互联网点对点音视频

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