1、实时音视频开发说明

1.1、实时音频、实时视频均通过相同的接口进行调用,遵循相同的业务流程。不同的业务通过呼叫接口参数CallType进行区分,VIDEO视频、VOICE音频等。

1.2、接口逻辑:

接口调用是采取异步调用的方式。所有的呼叫相关接口的调用结果通过回调接口ECVoIPCallDelegate中的方法OnCallEvents来接受服务端返回的各种状态。

1.3、业务流程

(1)客户A呼叫客户B发起请求

(2)云通讯服务端收到A请求并把请求转发给B

(3)客户B收到请求并应答

(4)云通讯服务端收到B应答并转发A

(5)A收到应答,通话建立

2、代码示例

2.1、呼叫界面处理

✾ 音频呼叫 — 我们假设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)
 @return 消息数 -1:全部获取 0:不获取
 */
- (NSString*)onGetOfflineCallId {
    NSLog(@"推送 onGetOfflineCallId=%@", [AppDelegate shareInstance].callid);
    return [AppDelegate shareInstance].callid;
}
             
                    

✾ 有呼入时,用户需要处理的事件 — 被叫John接到Tony的呼叫,则SDK底层调用哪个John代理类中的onCallEvents方法,开发者可在此处理呼入的业务逻辑。

注意:在集成音视频通话的时候,当结束当前通话的时候,需要在处理回调事件的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 withType: CallType.Voice];
    if (ret == 0)
    {
        NSLog (@“被叫端拒绝呼叫成功”);
    }
    else
    {
        NSLog (@“被叫端拒绝呼叫失败”);
    }
    
                        

✾ 结束通话 — Tony和John的通话过程中,任何一方想结束呼叫,则都可以调用如下代码:

[[ECDevice ShareIntance].VoIPManager releaseCall:mCurrentID];
                
                    

3、辅助接口

(1)获取通话ID

[[ECDevice sharedInstance].VoIPManager getCurrentCall;
功能:获取当前通话的callid,
参数:无
返回值:当前通话id

                    

(2)发送DTMF

[[ECDevice sharedInstance].VoIPManager sendDTMF:(NSString *)callid dtmf:(NSString *)dtmf;
功能:获取当前通话的callid,
参数:callid-通话id
      dtmf-键值
-	返回值:当前通话id

                    

(3)设置扬声器状态

[ECDevice sharedInstance] .VoIPManager enableLoudsSpeaker:(BOOL)enable;
功能:免提设置
参数:enable - NO:关闭 YES:打开
返回值:无

                    

(4)获取扬声器状态

[ECDevice sharedInstance].VoIPManager getLoudsSpeakerStatus;
功能:获取当前免提状态
参数:enable - NO:关闭 YES:打开
返回值:无

                    

(5)设置静音

[ECDevice sharedInstance].VoIPManager setMute:(BOOL)on
功能:静音设置
参数:enable - NO:正常 YES:静音
返回值:无

                    

(6)获取静音的状态

[ECDevice sharedInstance].VoIPManager getMuteStatus
功能:获取当前静音状态
参数:enable - NO:正常 YES:静音
返回值:无

                    

(7)接近检测,通话时如果贴近听筒,关闭屏幕(暂缓提供)

[ECDevice sharedInstance].VoIPManager enterVoipCallFlow:(BOOL)status
功能:是否抑制马赛克
参数:NO:关闭 YES:打开
返回值:无

                    

(8)设置视频通话显示的窗口

[ECDevice sharedInstance].VoIPManager setVideoView:(UIView*)view
andLocalView:(UIView*)localView
功能:视频通话显示的view,
参数:view-对方显示视图和本地显示视图
返回值:无

                    

(9)获取手机摄像头参数

[ECDevice sharedInstance].VoIPManager getCameraInfo
功能:获取摄像设备信息
参数:无
返回值: 摄像设备信息数组

                    

(10)切换前置和后置摄像头

  [[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放大
返回值: 摄像设备信息数组

                    

(11)设置编码范式

[ECDevice sharedInstance].VoIPManager  
setCodecEnabledWithCodec:(ECCodec) codec andEnabled:(BOOL) enabled
功能:设置支持的编解码方式
参数:codec-编解码类型
      enabled- NO:不支持 YES:支持
返回值: 无

                    

(12)获取编解码方式是否支持

[ECDevice sharedInstance].VoIPManager  
getCondecEnabelWithCodec:(ECCodec) codec
功能:获取编解码方式是否支持
参数:codec-编解码类型
返回值: NO:不支持 YES:支持

                    

(13)设置音频处理的类型和对用的处理模式

[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 

                    

(14)获取音频处理的开关

[ECDevice sharedInstance].VoIPManager  
getAudioConfigEnabelWithType:(ECAudioType) type
功能:获取音频处理的开关
参数:type-音频处理类型
enabled-YES:开启,NO:关闭
返回值: 成功:音频属性结构 失败:nil

                    

(15)统计通话质量

[ECDevice sharedInstance].VoIPManager 
getCallStatisticsWithCallid:(NSString*) digid andType:(CallType)type
功能:统计通话质量
返回值: 返回丢包率等通话质量信息对象

                    

(16)获取通话的网络流量信息

[ECDevice sharedInstance].VoIPManager  
getNetworkStatisticWithCallId:(NSString*) callid
获取通话的网络流量信息
参数:callid :会话ID,会议类传入房间号
返回值:网络流量信息对象

                    

(17)设置视频通话码率

[ECDevice sharedInstance].VoIPManager  
setVideoBitRates:(NSInteger)bitrates
设置视频通话码率
参数:bitrates  视频码流,kb/s,范围30-300
返回值:无 

                    

(18)获取服务器callSid,建议通话建立后获取。

[[ECDevice sharedInstance].VoIPManager 
getServerIdFromCallId:callid

参数:callid-通话id
返回值:callSid

                    

(19)获取用户在线状态

/**
 @brief 获取用户在线状态
 @brief userAccs 用户账号数组
 @param completion 执行结果回调block
 */
-(void)getUsersState:(NSArray *)userAccs 
completion:(void(^)(ECError* error, NSArray* usersState)) completion;

例:
userAccs = @”用户账号数组”;//每次最多获取50人
  [[ECDevice sharedInstance] getUsersState: userAccs completion:^(ECError* error, NSArray* usersState) {
            __strong __typeof(weakSelf)strongSelf = weakSelf;
            if ([strongSelf.sessionId isEqualToString:state.userAccs]) {// 判断是否是本次会话id
                if (state.isOnline) { //显示他人的在线状态
                    _stateLabel.text = [NSString stringWithFormat:@"%@-%@", 
                                       [strongSelf getDeviceWithType:state.deviceType], 
                                       [strongSelf getNetWorkWithType:state.network]];
                } else { //显示他人的不在线状态
                    _stateLabel.text = @"对方不在线";
                }
            }
        }];

                    

(20)单应用多证书

 /**
 @brief 多证书设置
 @param pushCerKey 推送证书标识,与服务器上传证书保持一致
 */
[[ECDevice sharedInstance] setPushCerKey:@"小余6位数字或字母"];
                    

(21)设置网络代理

/**
 @brief 设置网络代理,需要走代理时登录前设置,不支持ssl;socks5代理支持IM和点对点音视频(关闭p2p),http代理支持IM
 @param proxyHost 代理服务器地址,最大长度255。当设置空时,取消代理
 @param proxyPort 代理端口
 @param type 鉴权类型。 目前支持 0 不鉴权;2 用户名密码鉴权
 @param authName 用户名,最大长度255。authType=2时有效
 @param authPwd 用户名密码,最大长度255。authType=2时有效
 @param proxyType 代理类型。 目前支持 0 socks5代理;1 http代理
 @return 0成功,非0失败
 */
[[ECDevice sharedInstance] setNetworkProxy:(NSString*)proxyHost port:(NSInteger)proxyPort 
authType:(NSInteger)type name:(NSString*)authName pwd:(NSString*)authPwd ProxyType:(NSInteger)proxyType];
                    

文档更新时间:2017年12月4日