一对一通话
音视频呼叫回调注册
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); } }