互联网点对点音视频
1、点对点音视频开发说明
1.1、实时音频、实时视频均通过相同的接口进行调用,遵循相同的业务流程。不同的业务通过呼叫接口参数CallType进行区分,VIDEO视频、VOICE音频等。
1.2、接口逻辑
接口调用是采取异步调用的方式。所有的呼叫相关接口的调用结果通过回调接口ECVoIPCallDelegate中的方法OnCallEvents来接受服务端返回的各种状态。
1.3、业务流程
- 客户A呼叫客户B发起请求
- 云通讯服务端收到A请求并把请求转发给B
- 客户B收到请求并应答
- 云通讯服务端收到B应答并转发A
- A收到应答,通话建立
2、代码示例
音频呼叫
我们假设Tony音频呼叫John,则代码如下:
- self.callID = [[ECDevice sharedInstance].VoIPManager makeCallWithType:VOICE andCalled:@ "John的登录账号"];
- if (self.callid.length <= 0)//获取CallID失败,即拨打失败
- {
- }
- 说明:self.callID如果返回空则代表呼叫失败,可能是参数错误引起。否则返回是一串数字,是当前通话的标识。
视频呼叫
我们假设Tony视频呼叫John,此时代码和音频呼叫相同,区别是呼叫类型需要传VIDEO,并且在呼叫前需要设置本地和对方的视频view,代码如下:
- [[ECDevice sharedInstance].VoIPManager setVideoView:remoteVideoView andLocalView:localVideoView];
- self.callID = [[ECDevice sharedInstance].VoIPManager
- makeCallWithType:VIDEO andCalled: @ "John的登录号码"];
- if (self.callid.length <= 0)//获取CallID失败,即拨打失败
- {
- }
- 说明:self.callID如果返回空则代表呼叫失败,可能是参数错误引起。否则返回是一串数字,是当前通话的标识。视频时(包含点对点和会议),设置远端UIView的属性contentMode:(setVideoView:remoteVideoView)UIViewContentModeScaleToFill
- //view默认值,图像数据显示,填充view,但不等比例拉伸UIViewContentModeScaleAspectFit
- //图像等比例拉伸,完全显示内容UIViewContentModeScaleAspectFill
- //图像等比例拉伸,填充view,部分内容可能不显示
离线呼叫
我们假设Tony不在线,John呼叫Tony的音视频,需要在拿到远程推送的时候解析出callid并实现onGetOfflineCallId,代码如下:
- - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
- NSError *parseError = nil;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:userInfo
- options:NSJSONWritingPrettyPrinted error:&parseError];
- NSString *str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"推送内容"
- message:str
- delegate:nil
- cancelButtonTitle:NSLocalizedString(@"OK", @"OK")
- otherButtonTitles:nil];
- [alert show];
- NSLog(@"远程推送str:%@",str);
- NSLog(@"远程推送1:%@",userInfo);
- NSLog(@"远程推送r:%@",[userInfo objectForKey:@"r"]);
- NSLog(@"远程推送s:%@",[userInfo objectForKey:@"s"]);
- self.callid = nil;
- NSString *userdata = [userInfo objectForKey:@"c"];
- NSLog(@"远程推送userdata:%@",userdata);
- if (userdata) {
- NSDictionary*callidobj = [NSJSONSerialization JSONObjectWithData:[userdata dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableLeaves error:nil];
- NSLog(@"远程推送callidobj:%@",callidobj);
- if ([callidobj isKindOfClass:[NSDictionary class]]) {
- self.callid = [callidobj objectForKey:@"callid"];
- }
- }
- NSLog(@"远程推送 callid=%@",self.callid);}
- 然后需要实现
- /*
- @brief 需要获取的离线呼叫CallId (用于苹果推送下来的离线呼叫callid)
- */
- - (NSString*)onGetOfflineCallId {
- NSLog(@"推送 onGetOfflineCallId=%@", [AppDelegate shareInstance].callid);
- return [AppDelegate shareInstance].callid;
- }
有呼入时,用户需要处理的事件
被叫John接到Tony的呼叫,则SDK底层调用onIncomingCallReceived方法,开发者可在此处理呼入的业务逻辑。
注意:在集成音视频通话的时候,当结束当前通话的时候,需要在处理回调事件的onCallEvents中调用一下releaseCall方法,以保证当前通话占用的资源都释放了,避免在下次呼叫的时候出现线路被占用现象。(android、ios均需这样操作),Ios的调用地方,onCallEvents中的ECallEnd,代码如下:
- //有呼叫,调起对应的界面
- - (NSString*)onIncomingCallReceived:(NSString*)callid withCallerAccount:(NSString *)caller withCallerPhone:(NSString *)callerphone withCallerName:(NSString *)callername withCallType:(CallType)calltype;{
- //注意:如果Tony呼叫的是John的电话,则John的程序不会收到通知回调,而是直接
- //进入PSTN网络,和正常打电话一样
- if(CallType == VOICE)
- {
- NSlog(@“网络音频呼叫,调起音频呼叫的界面”);
- }
- else if(CallType == VIDEO)
- {
- NSLog (@“网络音频呼叫,调起视频呼叫的界面”);
- }
- }
- // 主叫端呼叫的时候,会有多种状态
- //呼叫事件的回调
- //(1)需要注册一个通知,告知外部呼叫的状态
- -(void)onCallEvents:(VoIPCall*)voipCall {
- [[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_onCallEvent object:voipCall];
- }
- //(2)外部成为观察者,并在通知里面监听呼叫的状态
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onCallEvents:) name:KNOTIFICATION_onCallEvent object:nil];
- //监听呼叫的状态
- -(void)onCallEvents:(NSNotification *)notification {VoIPCall* voipCall = notification.object;
- if (![self.callID isEqualToString:voipCall.callID])
- {
- return;
- }
- // 呼叫的状态
- ECallProceeding = 0, //外呼,服务器回100Tring
- ECallAlerting, //外呼对方振铃
- ECallFailed, //外呼失败
- ECallRing, //呼叫振铃
- ECallStreaming, //通话,外呼和来电
- ECallReleasing, //释放呼叫请求中
- ECallPaused, //呼叫保持
- ECallPausedByRemote, //呼叫被保持
- ECallResumed, //呼叫恢复
- ECallResumedByRemote, //呼叫被恢复
- ECallTransfered, //呼叫被转移
- ECallEnd //呼叫释放
- switch (voipCall.callStatus) {case ECallProceeding:
- {
- }
- break;
- case ECallStreaming:
- {
- }
- break;
- case ECallAlerting:
- {
- }
- break;
- case ECallEnd:
- {
- }
- break;
- case ECallRing:
- {
- }
- break;
- case ECallPaused:
- {
- }
- break;
- case ECallPausedByRemote:
- {
- }
- break;
- case ECallResumed:
- {
- }
- break;
- case ECallResumedByRemote:
- {
- }
- break;
- case ECallTransfered:
- {
- }
- break;
- case ECallFailed:
- {NSlog(@"Tony收到呼叫John失败的回调");
- if( voipCall.reason == ECErrorType_NoResponse){
- NSLog(@"网络不给力");
- }
- else if( voipCall.reason == ECErrorType_BadCredentials )
- {
- NSLog(@"鉴权失败");
- }
- else if ( voipCall.reason == ECErrorType_CallBusy || voipCall.reason == ECErrorType_Declined )
- {
- NSLog(@"您拨叫的用户正忙,请稍后再拨");
- }
- else if( voipCall.reason == ECErrorType_NoResponse)
- {
- NSLog(@"对方不在线");
- }
- else if( voipCall.reason == ECErrorType_CallMissed )
- {
- NSLog(@"呼叫超时");
- }
- else if( voipCall.reason == ECErrorType_NoNetwork )
- {
- NSLog(@"当前无网络");
- }
- else if( voipCall.reason == ECErrorType_SDKUnSupport)
- {
- NSLog(@"该版本不支持此功能");
- }
- else if( voipCall.reason == ECErrorType_CalleeSDKUnSupport )
- {
- NSLog(@"对方版本不支持音频");
- }
- else
- {
- NSLog(@"呼叫失败");}
- }
- break;
- case ECallEnd:
- {
- //无论是Tony还是John主动结束通话,双方都会进入到此回调
- NSLog(@"挂机");
- }
- break;
- default:
- break;
- }}
2.2、被叫端界面的处理
假设John侧调起来音频或者视频呼入的界面,界面上有“接受”和“拒绝”两个按钮:
- (1)John点击“接受”按钮,则调用的代码是
- //如果视频呼叫,则在接受呼叫之前,需要先设置视频通话显示的view
- [[ECDevice sharedInstance].VoIPManager setVideoView:remoteVideoView andLocalView:localVideoView];
- NSInteger ret = [[ECDevice ShareIntance].VoIPManager
- acceptCall:self.callID withType: VOICE(视频: VIDEO)];
- if (ret == 0)// 音频或视频通话界面
- {
- NSLog (@“被叫端接受呼叫成功”);
- }
- else
- {
- NSlog(@“被叫端接受呼叫失败”);
- }(2)John点击“拒绝”按钮,音视频拒绝的代码是一致的,调用的代码是:
- NSInteger ret = [[ECDevice ShareIntance].VoIPManager
- rejectCall:self.callID andReason: ECErrorType_CallBusy];
- if (ret == 0)
- {
- NSLog (@“被叫端拒绝呼叫成功”);
- }
- else
- {
- NSLog (@“被叫端拒绝呼叫失败”);
- }
结束通话
Tony和John的通话过程中,任何一方想结束呼叫,则都可以调用如下代码:
- [[ECDevice ShareIntance].VoIPManager releaseCall:mCurrentID];
3、辅助接口
获取通话ID
- [[ECDevice sharedInstance].VoIPManager getCurrentCall;
- 功能:获取当前通话的callid,
- 参数:无
- 返回值:当前通话id
发送DTMF
- [[ECDevice sharedInstance].VoIPManager sendDTMF:(NSString *)callid dtmf:(NSString *)dtmf;
- 功能:获取当前通话的callid,
- 参数:callid-通话id
- dtmf-键值-
- 返回值:当前通话id
设置扬声器状态
- [ECDevice sharedInstance] .VoIPManager enableLoudsSpeaker:(BOOL)enable;
- 功能:免提设置
- 参数:enable - NO:关闭 YES:打开
- 返回值:无
获取扬声器状态
- [ECDevice sharedInstance] .VoIPManager getLoudsSpeakerStatus;
- 功能:获取当前免提状态
- 参数:enable - NO:关闭 YES:打开
- 返回值:无
设置静音
- [ECDevice sharedInstance].VoIPManager setMute:(BOOL)on
- 功能:静音设置
- 参数:enable - NO:正常 YES:静音
- 返回值:无
获取静音的状态
- [ECDevice sharedInstance] .VoIPManager getMuteStatus
- 功能:获取当前静音状态
- 参数:enable - NO:正常 YES:静音
- 返回值:无
接近检测,通话时如果贴近听筒,关闭屏幕(暂缓提供)
- [ECDevice sharedInstance].VoIPManager enterVoipCallFlow:(BOOL)status
- 功能:是否抑制马赛克
- 参数:NO:关闭 YES:打开
- 返回值:无
设置视频通话显示的窗口
- [ECDevice sharedInstance] .VoIPManager setVideoView:(UIView*)viewandLocalView:(UIView*)localView
- 功能:视频通话显示的view
- 参数:view-对方显示视图和本地显示视图
- 返回值:无
获取手机摄像头参数
- [ECDevice sharedInstance].VoIPManager getCameraInfo
- 功能:获取摄像设备信息
- 参数:无
- 返回值: 摄像设备信息数组
切换前置和后置摄像头
- [[ECDevice sharedInstance].VoIPManager
- selectCamera:(NSInteger)cameraIndex capability:(NSInteger)capabilityIndex fps:(NSInteger)fps
- rotate:(ECRotate)rotate force:(BOOL)isForce scale:(CGFloat)scale]
- 功能:选择使用的摄像设备参数:cameraIndex-设备index
- capabilityIndex-能力index
- fps-帧率
- rotate-旋转的角度
- isForce 是否强制启动本SDK调用的摄像头,默认使用NO
- scale 编码缩放,正实数。默认1.0,小于1.0缩小,大于1.0放大返回值: 摄像设备信息数组
设置编码范式
- [ECDevice sharedInstance].VoIPManager
- setCodecEnabledWithCodec:(ECCodec) codec andEnabled:(BOOL) enabled
- 功能:设置支持的编解码方式
- 参数:codec-编解码类型
- enabled- NO:不支持 YES:支持返回值: 无
获取编解码方式是否支持
- [ECDevice sharedInstance].VoIPManager
- getCondecEnabelWithCodec:(ECCodec) codec
- 功能:获取编解码方式是否支持
- 参数:codec-编解码类型
- 返回值: NO:不支持 YES:支持
设置音频处理的类型和对用的处理模式
- [ECDevice sharedInstance].VoIPManager
- setAudioConfigEnabledWithType:(ECAudioType) type andEnabled:(BOOL) enabled andMode:(NSInteger) mode
- 功能:设置音频处理的开关
- 参数:type-音频处理类型
- enabled-YES:开启,NO:关闭
- mode-各自对应的模式: AUDIO_AgcMode、AUDIO_EcMode、AUDIO_NsMode.
- 返回值: 成功 0 失败 -1
获取音频处理的开关
- [ECDevice sharedInstance].VoIPManager
- getAudioConfigEnabelWithType:(ECAudioType) type
- 功能:获取音频处理的开关
- 参数:type-音频处理类型
- enabled-YES:开启,NO:关闭
- 返回值: 成功:音频属性结构 失败:nil
统计通话质量
- [ECDevice sharedInstance].VoIPManager
- getCallStatisticsWithCallid:(NSString*) digid andType:(CallType)type
- 功能:统计通话质量返回值: 返回丢包率等通话质量信息对象
获取通话的网络流量信息
- [ECDevice sharedInstance].VoIPManager
- getNetworkStatisticWithCallId:(NSString*) callid
- 功能:获取通话的网络流量信息
- 参数:callid :会话ID,会议类传入房间号
- 返回值:网络流量信息对象
设置视频通话码率
- [ECDevice sharedInstance].VoIPManager
- setVideoBitRates:(NSInteger)bitrates
- 功能:设置视频通话码率
- 参数:bitrates 视频码流,kb/s,范围30-300
- 返回值:无
获取服务器callSid
建议通话建立后获取。
- [[ECDevice sharedInstance].VoIPManager
- getServerIdFromCallId:callid
- 参数:callid-通话id
- 返回值:callSid