一、前言
视频通话接通不难,难的是各种情况处理,且有点功能声网SDK是不提供的,如果要完整的视频通话,这代码量有点大,这篇文章仅以接通为目标
二、看下效果图(设计图)
video_calling.png video_call.png二、跟着我开始步骤
1、配置部分
在app下的build.gradle中配置
implementation 'io.agora.rtc:full-sdk:3.6.2'
2、拨打前或者加入频道前先询问权限
private fun checkPermission(isClickAcceptCallBack:(() -> Unit)?= null){
if (PermissionCheckUtil.checkPermissions(mContext,if (startCallBean.type == AUDIO_TYPE) PermissionAppUtils.Group.MICROPHONE else PermissionAppUtils.Group.CAMERA_RECORD)){
if (startCallBean.type == AUDIO_TYPE) isClickAcceptCallBack?.invoke()?:initAudioEngine() else isClickAcceptCallBack?.invoke()?:initVideoEngine()
} else {
DialogUtils.okAndCancel(
mContext,
if (startCallBean.type == AUDIO_TYPE) getString(R.string.audio_call_permission_tip) else getString(R.string.video_call_permission_tip),
ok = getString(R.string.go_open),
okListener = {
PermissionAppUtils.requestCombinedPermission(mContext,if (startCallBean.type == AUDIO_TYPE) PermissionAppUtils.Group.MICROPHONE else PermissionAppUtils.Group.CAMERA_RECORD) {
if (it.granted){
if (isClickAcceptCallBack != null){
if (startCallBean.type == AUDIO_TYPE) {
initAudioEngine()
isClickAcceptCallBack.invoke()
} else {
initVideoEngine()
isClickAcceptCallBack.invoke()
}
} else {
if (startCallBean.type == AUDIO_TYPE) initAudioEngine() else initVideoEngine()
}
} else {
if (it.shouldShowRequestPermissionRationale){
//禁止,不做操作,拨打方直接关闭界面,接听方在点接听时再询问一次
if (isCallOutGoing || isClickAcceptCallBack != null){
show(R.string.call_permission_empty_tip)
finish()
}
} else {
//永久禁止,需求说只弹前面的弹框,永久禁止就直接跳设置
//点接听时跳到设置,返回不处理,让它再点一次接听按钮
if (isClickAcceptCallBack == null){
isJumpAppSetting = true
CUtils.startAppSettings(mContext)
}
}
}
}
})
}
}
override fun onResume() {
super.onResume()
if (isJumpAppSetting){
isJumpAppSetting = false
when(startCallBean.type){
AUDIO_TYPE -> {
if (PermissionCheckUtil.checkPermissions(mContext,PermissionAppUtils.Group.MICROPHONE)){
initAudioEngine()
}
}
VIDEO_TYPE -> {
if (PermissionCheckUtil.checkPermissions(mContext,PermissionAppUtils.Group.CAMERA_RECORD)){
initVideoEngine()
}
}
else ->{
show(R.string.call_permission_empty_tip)
finish()
}
}
}
}
3、有了权限初始化声网引擎和加入频道(显示自己的视频画面)
initVideoEngine()代码如下:
private fun initVideoEngine(){
initializeAgoraEngine()
setupVideoProfile()
initVideoModule()
setupLocalVideo(startCallBean.closeCamera)
rtcEngine?.setVideoSource(RtcVideoConsumer())
if (isCallOutGoing && !startCallBean.isFloatBackCall){
joinChannel(startCallBean.token,startCallBean.channelName,SPUtil.getUserId())
}
}
我这个本地视频用了相芯美颜的,可参考它demo原来的代码。上面代码中token和channelName都是app服务器接口返回的
4、自己加入频道后通知对方
/**
* @desc : 自己加入频道成功回调
* @author : congge on 2022-03-24 15:07
**/
override fun onJoinChannelSuccess(channel: String, uid: Int, elapsed: Int) {
runOnUiThread {
LogUtils.i("mRtcEventHandler","onJoinChannelSuccess")
if (!isCallOutGoing){
dealViewShow(true)
dealCallTime(true)
mViewModel.postChatMediaAnswer(startCallBean.mediaId)
} else {
//拨打方加入频道后,邀请对方通话
if(disposableIntervalCall == null || disposableIntervalCall!!.isDisposed){
disposableIntervalCall = Observable.interval(0,5, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.take(55)
.subscribe {
//只有第一次邀请要通知栏
mViewModel.getChatMediaSendInvite(startCallBean.mediaId,it == 0L)
}
}
//自己加入频道后,给对方60s加入频道的时间
longTimeNoResponse(timeOutNoResponse)
}
}
}
注:onJoinChannelSuccess是加入频道成功后的回调,拨打方加入频道后,就通知对方。如果是接听方加入频道后就可以显示通话中界面了。声网是没有通知对方的api的,我项目是用融云IM通知对方的。
5、对方加入频道后(显示对方的视频画面)
/**
* @desc : 对方加入频道成功回调
* 此回调在以下任一情况下触发:
* 1、远程用户/主机通过调用joinChannel方法加入通道。
* 2、远程用户在加入通道后通过调用setClientRole方法将用户角色切换到主机。
* 3、网络中断后,远程用户/主机重新加入通道。
* 4、主机通过调用addInjectStreamUrl方法将在线媒体流注入频道。
* @author : congge on 2022-03-24 15:08
**/
override fun onUserJoined(uid: Int, elapsed: Int) {
runOnUiThread {
LogUtils.i("mRtcEventHandler","onUserJoined")
//stopRinging关闭声音要在dealViewShow前面,里面有关扬声器
CallRingingUtil.getInstance().stopRinging()
dealViewShow(false)
dealCallTime(true)
//10s内对方进入了频道
cancelLongTimeNoResponse()
if (startCallBean.type == VIDEO_TYPE){
videoUid = uid
setupRemoteVideo(uid)
}
}
}
private fun setupRemoteVideo(uid: Int,fl: FrameLayout? = mBinding.flVideoCallRemoteVideo,surfaceViewRemote1:SurfaceView? = null) {
if (isMBindingViewInitialised()){
fl?.let {
if (it.childCount >= 1) {
return
}
it.removeAllViews()
if (surfaceViewRemote1 == null){
surfaceViewRemote = RtcEngine.CreateRendererView(mContext)
it.addView(surfaceViewRemote)
// Initializes the video view of a remote user.
rtcEngine?.setupRemoteVideo(VideoCanvas(surfaceViewRemote, VideoCanvas.RENDER_MODE_HIDDEN, uid))
surfaceViewRemote!!.tag = uid // for mark purpose
} else {
surfaceViewRemote = surfaceViewRemote1
it.addView(surfaceViewRemote)
surfaceViewRemote!!.tag = uid
}
}
}
}
1、拨打方监听到接听方进入频道的回调
2、接听方进入频道后也会收到这回调
6、至此双方应该能互相看见对方了,最后就是挂断了
挂断就是退出频道
rtcEngine?.leaveChannel()
然后对方就会收到以下回调
override fun onUserOffline(uid: Int, reason: Int)
如果需要完整的声网音视频通话的代码,可私信我
网友评论