一对一通话
音视频呼叫回调注册
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MtcCallCb.setCallback(this); ZmfVideo.addCallback(this); } @Override protected void onDestroy() { super.onDestroy(); MtcCallCb.setCallback(null); ZmfVideo.removeCallback(this); }
//创建本地和远端图像预览 private void createVideoViews() { if (mRemoteView != null) return; Context context = getApplicationContext(); FrameLayout.LayoutParams flp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); //添加远端图像预览 mRemoteView = ZmfVideo.renderNew(context); mRemoteView.setLayoutParams(flp); mViewMain.addView(mRemoteView, 0); ZmfVideo.renderStart(mRemoteView); //添加本地图像预览 mLocalView = ZmfVideo.renderNew(context); mLocalView.setLayoutParams(flp); mLocalView.setZOrderMediaOverlay(true); mViewMain.addView(mLocalView, 1); ZmfVideo.renderStart(mLocalView); mLocalView.setVisibility(View.GONE); } //关闭相关设备,关闭视频渲染 private void destroyVideoViews() { //将这路视频通话从设备取消绑定 MtcCall.Mtc_SessCameraDetach(dwSessId); //停止所有视频设备的录制 ZmfVideo.captureStopAll(); if (mLocalView != null) { ZmfVideo.renderRemoveAll(mLocalView); ZmfVideo.renderStop(mLocalView); mViewMain.removeView(mLocalView); mLocalView = null; } if (mRemoteView != null) { ZmfVideo.renderRemoveAll(mRemoteView); ZmfVideo.renderStop(mRemoteView); mViewMain.removeView(mRemoteView); mRemoteView = null; } } //设置音频模式 private void setCallMode() { if (mCallMode) return; mCallMode = true; //SDK根据设备寻找最适合的音频模式 int mode = MtcMedia.Mtc_MdmGetAndroidAudioMode(); if (mode != mAudioManager.getMode()) { mAudioManager.setMode(mode); } mAudioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN); new AsyncTask() { @Override protected Void doInBackground(Void... params) { synchronized (CallActivity.this) { if (CallActivity.this.isCalling()) { ZmfAudio.inputStart(MtcMedia.Mtc_MdmGetAndroidAudioInputDevice()/*获取录音设备*/, 0, 0, MtcMedia.Mtc_MdmGetOsAec() ? ZmfAudio.AEC_ON : ZmfAudio.AEC_OFF, MtcMedia.Mtc_MdmGetOsAgc() ? ZmfAudio.AGC_ON : ZmfAudio.AGC_OFF); ZmfAudio.outputStart(MtcMedia.Mtc_MdmGetAndroidAudioOutputDevice(), 0, 0); } } return null; } }.execute(); } //清除通话相关设置 private void clearCallMode() { mCallMode = false; if (mAudioManager == null) { return; } synchronized (this) { ZmfAudio.inputStopAll(); ZmfAudio.outputStopAll(); } mAudioManager.abandonAudioFocus(null); if (AudioManager.MODE_NORMAL != mAudioManager.getMode()) { mAudioManager.setMode(AudioManager.MODE_NORMAL); } } //设置扬声器方式 private void setSpeakerphoneOn(bool mHasVideo) { AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mAudioManager.setSpeakerphoneOn(mHasVideo); }
发起音视频呼叫
if (isVideo) { createVideoViews(); } setCallMode(); String phoneNumbwe = "+8618605745829"; String uri = MtcUri.Mtc_UriFormatX(phoneNumber, false); MtcCall.Mtc_SessCall(uri, 0, true, isVideo);
注:isVideo 判断是否是视频呼叫。
呼叫成功后会依次触发以下回调:
public void mtcCallCbOutgoing(int dwSessId) { //通话记录插入数据库 //设置扬声器方式 setSpeakerphoneOn(mHasVideo); if (mHasVideo) { //若为视频呼叫,则开启本地视频预览 MtcNumber width = new MtcNumber(); MtcNumber height = new MtcNumber(); MtcNumber framerate = new MtcNumber(); //通过菊风MDM模块获取适合的长度、宽度、帧速率 MtcMedia.Mtc_MdmGetCaptureParms(width, height, framerate); ZmfVideo.captureStart(mCapture, width.getValue(), height.getValue(), framerat.getValue()); mLocalView.setVisibility(View.VISIBLE); ZmfVideo.renderAdd(mLocalView, ZmfVideo.CaptureFront, 0, ZmfVideo.RENDER_FULL_SCREEN); //将这路视频通话绑定到设备 MtcCall.Mtc_SessCameraAttach(mCurSessId, ZmfVideo.CaptureFront); } } public void mtcCallCbAlerted(int dwSessId, int dwAlertType) { //开始响铃,界面显示振铃中 }
音视频呼叫来电
当接到电话时,会触发以下回调:
public void mtcCallCbIncoming(int dwSessId) { //获取来电号码,插入数据库 MtcString ppcDispName = new MtcString(); MtcString ppcUri = new MtcString(); MtcCall.Mtc_SessGetPeerId(dwSessId, ppcDispName, ppcUri); String number = MtcUri.Mtc_UriGetUserPart(ppcUri.getValue()); //判断来电是否为视频通话 boolean mHasVideo = MtcCall.Mtc_SessPeerOfferVideo(dwSessId); //界面刷新显示来电,并开始响铃,若为视频通话,则开启本地预览 if (mHasVideo) { createVideoViews(); //若为视频呼叫,则开启本地视频预览 MtcNumber width = new MtcNumber(); MtcNumber height = new MtcNumber(); MtcNumber framerate = new MtcNumber(); //通过菊风MDM模块获取适合的长度、宽度、帧速率 MtcMedia.Mtc_MdmGetCaptureParms(width, height, framerate); ZmfVideo.captureStart(mCapture, width.getValue(), height.getValue(), framerat.getValue()); mLocalView.setVisibility(View.VISIBLE); //开始本地图像预览 ZmfVideo.renderAdd(mLocalView, ZmfVideo.CaptureFront, 0, ZmfVideo.RENDER_FULL_SCREEN); //将这路视频通话绑定到设备 MtcCall.Mtc_SessCameraAttach(mCurSessId, ZmfVideo.CaptureFront); } }
接听音视频呼叫
setCallMode(); MtcCall.Mtc_SessAnswer(dwSessId, 0, true, isVideo);
双方触发以下回调:
public void mtcCallCbTalking(int dwSessId) { // 更新数据库状态 // 判断来电是否为视频通话 if (MtcCall.Mtc_SessHasVideo(dwSessId)) { MtcCall.Mtc_SessVideoStart(dwSessId); //开始远端图像预览 ZmfVideo.renderAdd(mRemoteView, MtcCall.Mtc_SessGetName(dwSessId), 0, ZmfVideo.RENDER_AUTO); } }
取消音视频呼叫
//主动挂断 //第二个参数(定义于 MtcConstants),主动挂断的状态码只能选择以下三种之一: //EN_MTC_CALL_TERM_STATUS_NORMAL 正常挂断 //EN_MTC_CALL_TERM_STATUS_BUSY 正忙 //EN_MTC_CALL_TERM_STATUS_DECLINE 拒接 MtcCall.Mtc_SessTerm(dwSessId, MtcCallConstants.MTC_CALL_TERM_NORMAL);
对方收到回调:
public void mtcCallCbTermed(int dwSessId, int dwStatCode) { // dwStatCode为结束通话的状态码,根据 dwStatCode 判断终止原因,更新数据库状态 // MTC_CALL_TERM_BYE = (0xE200+21); /**< @brief Terminated by bye. */ // MTC_CALL_TERM_CANCEL = (0xE200+22); /**< @brief Terminated by cancel. */ // MTC_CALL_TERM_TIMEOUT = (0xE200+23); /**< @brief Terminated by timeout. */ // MTC_CALL_TERM_BUSY = (0xE200+24); /**< @brief Terminated by busy. */ // MTC_CALL_TERM_DECLINE = (0xE200+25); /**< @brief Terminated by decline. */ // MTC_CALL_TERM_TRSFED = (0xE200+26); /**< @brief Terminated by transfered. */ // MTC_CALL_TERM_REDIRECT = (0xE200+27); /**< @brief Terminated by redirect. */ // MTC_CALL_TERM_REPLACE = (0xE200+28); /**< @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(); clearCallMode(); }
监听视频图像开始渲染的回调
@Override public void renderDidStart(SurfaceView zView, int iSource, String iRender, int iWidth, int iHeight) { // 检测本地或远端图像是否开始渲染 if (zView == mLocalView) { } else if (zView == mRemoteView) { // 样例,如果远端视频开始渲染,则缩小本地图像预览 MtcNumber localWidth = new MtcNumber(); MtcNumber localHeight = new MtcNumber(); MtcCall.Mtc_SessGetVideoLocalSize(mCurSessId, localHeight, localWidth); if (mLocalView.getWidth() == localWidth.getValue() && mLocalView.getHeight() == localHeight.getValue()) { return; } int screenWidth = mViewMain.getWidth(); int screenHeight = mViewMain.getHeight(); //计算本地预览图像等比例缩小后的尺寸 ST_MTC_RECT localRect = MtcVideo.calcLocalRect(localWidth.getValue(), localHeight.getValue(), screenWidth, screenHeight); MtcVideo.setViewRect(mLocalView, localRect); } }
监听音视频通话信号回调
public void mtcCallCbNetStaChanged(int dwSessId, boolean bVideo, boolean bSend, int iType) { // 如果信号断开,则主动结束通话 if (iType == MtcCallConstants.EN_MTC_NET_STATUS_DISCONNECTED) { MtcCall.Mtc_SessTerm(dwSessId, MtcCall.EN_MTC_CALL_TERM_REASON_NORMAL); } }
监听音视频通话RTP流回调
public void mtcCallCbSetRtpConnectivity(int dwSessId, boolean bConnected) { // 如果RTP流已断开,则主动结束通话 if (mCurSessId == dwSessId && !bConnected) { MtcCall.Mtc_SessTerm(dwSessId, MtcCall.EN_MTC_CALL_TERM_REASON_NORMAL); } }