Docs
Resources
Tools
News
to top

RCS

一对一通话

音视频呼叫回调注册

Mtc_CallCbSetIncoming(MtcCallCbIncoming);
Mtc_CallCbSetOutgoing(MtcCallCbOutgoing);
Mtc_CallCbSetAlerted(MtcCallCbAlerted);
Mtc_CallCbSetTalking(MtcCallCbTalking);
Mtc_CallCbSetTermed(MtcCallCbTermed);
Mtc_CallCbSetNetStaChanged(MtcCallCbNetStaChanged);

Mtc_CallCbSetAddVideoReq(MtcCallCbAddVideoReq);
Mtc_CallCbSetAddVideoOk(MtcCallCbAddVideoOk);
Mtc_CallCbSetAddVideoFailed(MtcCallCbAddVideoFailed);
Mtc_CallCbSetRmvVideoOk(MtcCallCbRmvVideoOk);
Mtc_CallCbSetRmvVideoFailed(MtcCallCbRmvVideoFailed);

Mtc_CallCbSetRtpConnectivity(MtcCallCbSetRtpConnectivity);
//创建本地和远端图像预览
void createVideoViews() {
    //添加远端图像预览
    if (!_remote) {
        _remote = [[ZmfView alloc] initWithFrame:self.view.bounds];
        _remote.backgroundColor = [UIColor clearColor];
        _remote.hidden = YES;
        [self.view insertSubview:_remote atIndex:0];
    }
    Zmf_VideoRenderStart((__bridge void *)(_remote), ZmfRenderViewFx);
    
    //添加本地图像预览
    if (!_preview) {
        _preview = [[ZmfView alloc] initWithFrame:self.view.bounds];
        _preview.backgroundColor = [UIColor clearColor];
        [self.view insertSubview:_preview atIndex:1];
    }
    Zmf_VideoRenderStart((__bridge void *)(_preview), ZmfRenderViewFx);
}

//关闭相关设备,关闭视频渲染
void destroyVideoViews() {
    //将这路视频通话从设备取消绑定
    Mtc_SessCameraDetach(mCurrentSessId);
    //停止所有视频设备的录制
    Zmf_VideoCaptureStopAll();
    if (_preview) {
        Zmf_VideoRenderRemoveAll((__bridge void *)_remote);
        Zmf_VideoRenderStop((__bridge void *)_remote);
        [_preview removeFromSuperview];
        _preview = nil;
    }
    
    if (_remote) {
        Zmf_VideoRenderRemoveAll((__bridge void *)_remote);
        Zmf_VideoRenderStop((__bridge void *)_remote);
        [_remote removeFromSuperview];
        _remote = nil;
    }
}


//设置扬声器方式
void MtcUtilSetSpeaker(bool mHasVideo) {
    AVAudioSession *session = [AVAudioSession sharedInstance];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                   [session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
                   if (mHasVideo) {
                        [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
                   } else {
                        [session overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
                   });
}


//是否存在耳麦
BOOL MtcUtilIsHeadSet()
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
        AVAudioSessionRouteDescription *des = [[AVAudioSession sharedInstance] currentRoute];
        NSArray *a = des.outputs;
        for (AVAudioSessionPortDescription *s in a) {
            if ([s.portType isEqualToString:AVAudioSessionPortHeadsetMic] || [s.portType isEqualToString:AVAudioSessionPortHeadphones]) {
                NSLog(@"耳机");
                return YES;
            }
        }
    } else {
        CFStringRef route;
        UInt32 propertySize = sizeof(CFStringRef);
        AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &route);
        if((route == NULL) || (CFStringGetLength(route) == 0)){
            // Silent Mode
            NSLog(@"AudioRoute: SILENT, do nothing!");
        } else {
            NSString* routeStr = (__bridge NSString*)route;
            NSLog(@"AudioRoute: %@", routeStr);
            /* Known values of route:
             * "Headset"
             * "Headphone"
             * "Speaker"
             * "SpeakerAndMicrophone"
             * "HeadphonesAndMicrophone"
             * "HeadsetInOut"
             * "ReceiverAndMicrophone"
             * "Lineout"
             */
            NSRange headphoneRange = [routeStr rangeOfString : @"Headphone"];
            NSRange headsetRange = [routeStr rangeOfString : @"Headset"];
            if (headphoneRange.location != NSNotFound) {
                return YES;
            } else if(headsetRange.location != NSNotFound) {
                return YES;
            }
        }
    }
    return NO;
}

发起音视频呼叫

if (isVideo) {
   createVideoViews();
}

NSString *dialablePhone = ContactsGetPhoneWithCountryCode(phone);
ZCHAR *uri = Mtc_UriFormatX((ZCHAR *)[dialablePhone UTF8String], ZFALSE);
Mtc_SessCall(uri, 0, ZTRUE, isVideo);

Zmf_AudioInputStart(ZmfAudioDeviceVoice, 0, 0, ZmfAudioDeviceVoice ? ZmfAecOn : ZmfAecOff, ZmfAgcOn);
Zmf_AudioOutputStart(ZmfAudioDeviceVoice, 0, 0);

注:isVideo 判断是否是视频呼叫i。

呼叫成功后会依次触发以下回调:

static ZVOID MtcCallCbOutgoing(ZULONG dwSessId) {
    //通话记录插入数据库
    //设置扬声器方式
    MtcUtilSetSpeaker(mHasVideo);
    if (mHasVideo) {
        //设置长度、宽度、帧速率
        Zmf_VideoCaptureStart(ZmfVideoCaptureFront, 1280, 720, 30);
        //若为视频呼叫,则开启本地视频预览
        Zmf_VideoRenderAdd((__bridge void *)_preview, ZmfVideoCaptureFront, 0, ZmfRenderFullScreen);
        //将这路视频通话绑定到设备
        Mtc_SessCameraAttach(dwSessId, ZmfVideoCaptureFront);
    }
}
	

static ZVOID MtcCallCbAlerted(ZULONG dwSessId, ZULONG dwAlertType){
	//开始响铃,界面显示振铃中
}

音视频呼叫来电

当接到电话时,会触发以下回调:

static ZVOID MtcCallCbIncoming(ZULONG dwSessId) {
    // 获取来电号码,插入数据库
    ZCHAR *pcParptId = ZNULL;
    ZBOOL bHasVideo;
    Mtc_SessGetPeerId(dwSessId, ZNULL, &pcParptId);
    NSString *peerNumber = [NSString stringWithUTF8String:Mtc_UriGetUserPart(pcParptId)];
    
    /* not support multi peer to peer call, if incoming while calling, return */
    if ([self isCalling] || [self isTalking]) {
        Mtc_SessTerm(dwSessId, EN_MTC_CALL_TERM_REASON_BUSY);
        return;
    }
    
    BOOL mHasVideo = Mtc_SessPeerOfferVideo(dwSessId);
    //界面刷新显示来电,并开始响铃,若为视频通话,则开启本地预览
    if (mHasVideo) {
        createVideoViews();
        
        //设置长度、宽度、帧速率
        Zmf_VideoCaptureStart(ZmfVideoCaptureFront, 1280, 720, 30);
        //若为视频呼叫,则开启本地视频预览
        Zmf_VideoRenderAdd((__bridge void *)_preview, ZmfVideoCaptureFront, 0, ZmfRenderFullScreen);
        //将这路视频通话绑定到设备
        Mtc_SessCameraAttach(dwSessId, ZmfVideoCaptureFront);
    }
}

接听音视频呼叫

Mtc_SessAnswer(dwSessId, 0, ZTRUE, isVideo);

Zmf_AudioInputStart(ZmfAudioDeviceVoice, 0, 0, ZmfAudioDeviceVoice ? ZmfAecOn : ZmfAecOff, ZmfAgcOn);
Zmf_AudioOutputStart(ZmfAudioDeviceVoice, 0, 0);

对方触发以下回调

static ZVOID MtcCallCbTalking(ZULONG dwSessId) {
    //callId是数据库自增Id
    NSInteger callId = [[MtcCallManager sharedInstance] getCallIdWithConfId:dwSessId];
    
    Mvc_ResumeAllStrm();
    Mvd_ResumeAllStrm();
    //根据CallId,更新数据库状态并通知界面刷新,若为视频通话,则开启本端以及对端视频
    if (Mtc_SessHasVideo(dwSessId)) {
        //设置扬声器
        MtcUtilSetSpeaker(!MtcUtilIsHeadSet());
        
        Mvd_ResumeAllStrm();
        Mtc_SessVideoStart(dwSessId);
        //开始远端图像预览
        Zmf_VideoRenderAdd((__bridge void *)_remote, Mtc_SessGetName(dwSessId), 0, ZmfRenderFullScreen);
    }
}

取消音视频呼叫

//主动挂断
//第二个参数,主动挂断的状态码只能选择以下三种之一:
//EN_MTC_CALL_TERM_STATUS_NORMAL    正常挂断
//EN_MTC_CALL_TERM_STATUS_BUSY      正忙
//EN_MTC_CALL_TERM_STATUS_DECLINE   拒接
Mtc_SessTerm(dwSessId, MTC_CALL_TERM_NORMAL);

对方收到回调:

public void mtcCallCbTermed(int dwSessId, int dwStatCode) {
    // dwStatCode为结束通话的状态码,根据 dwStatCode 判断终止原因,更新数据库状态
    //  MTC_CALL_TERM_BYE  /**< @brief Terminated by bye. */
    //  MTC_CALL_TERM_CANCEL  /**< @brief Terminated by cancel. */
    //  MTC_CALL_TERM_TIMEOUT  /**< @brief Terminated by timeout. */
    //  MTC_CALL_TERM_BUSY /**< @brief Terminated by busy. */
    //  MTC_CALL_TERM_DECLINE  /**< @brief Terminated by decline. */
    //  MTC_CALL_TERM_TRSFED  /**< @brief Terminated by transfered. */
    //  MTC_CALL_TERM_REDIRECT  /**< @brief Terminated by redirect. */
    //  MTC_CALL_TERM_REPLACE  /**< @brief Terminated by replace. */
    
    //  EN_MTC_CALL_TERM_REASON_NORMAL      对方正常通话中挂断
    //  EN_MTC_CALL_TERM_REASON_BUSY        对方正忙
    //  EN_MTC_CALL_TERM_REASON_DECLINE     对方拒接
    //  EN_MTC_CALL_TERM_REASON_NOT_AVAILABLE     暂时不可用
    
    destroyVideoViews();
    
    [[AVAudioSession sharedInstance] setActive:NO error:nil];
    
    Zmf_AudioInputStopAll();
    Zmf_AudioOutputStopAll();
}

监听视频图像开始渲染的回调

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(videoRenderStarted:)
                                                 name:ZmfVideoRenderDidStart
                                               object:nil];
}

/**
 *  outgoing或者incoming ,显示本地和对方的视频,会通知2次
 *
 *  @param notification
 */
- (void)videoRenderStarted:(NSNotification *)notification
{
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(videoRenderStarted:) withObject:notification waitUntilDone:NO];
        return;
    }
    void *pWnd = (void *)[[notification.userInfo valueForKey:ZmfWindow] longValue];
    
    if (pWnd == (__bridge void *)_remote) {
        if (_remote && _remote.hidden) {
            _remote.hidden = NO;
            //把预览缩小
            if (_preview) {
                
                ZUINT localWidth, localHeight;
                Mtc_SessGetVideoLocalSize(mCurSessId, &localHeight, &localWidth);
                CGSize localSize = MtcVideoCalcLocalSize(localWidth, localHeight, [[UIScreen mainScreen] bounds].size);
                CGSize previewSize = _preview.bounds.size;
                if (CGSizeEqualToSize(localSize, previewSize)) {
                    return;
                }
                
                [UIView animateWithDuration:0.3
                                 animations:^{
                                     _preview.frame = CGRectMake(10, 10, localSize.width, localSize.height);
                                 }
                                 completion:^(BOOL finished) {
                                     _preview.layer.masksToBounds = YES;
                                     _preview.layer.borderColor = [[UIColor whiteColor] CGColor];
                                     _preview.layer.borderWidth = 1.0f;
                                 }
                ];
            }
        }
    }
}

监听音视频通话信号回调

static ZVOID MtcCallCbNetStaChanged(ZULONG dwSessId, ZBOOL bVideo, ZBOOL bSend, ZINT iType)
{
    // 如果信号断开,则主动结束通话
    if (iType == EN_MTC_NET_STATUS_DISCONNECTED) {
        Mtc_SessTerm(dwSessId, EN_MTC_CALL_TERM_REASON_NORMAL);
    }
}

监听音视频通话RTP流回调

static ZVOID MtcCallCbSetRtpConnectivity(ZULONG dwSessId, ZBOOL bConnected)
{
    // 如果RTP流已断开,则主动结束通话
    if (mCurSessId == dwSessId && !bConnected) {
        Mtc_SessTerm(dwSessId, EN_MTC_CALL_TERM_REASON_NORMAL);
    }
}
Juphoon © 2015 中文(简体)
关于我们 JusTalk 开发人员 招聘 隐私政策