写点什么

uni-app 技术分享|开源 demo 视频呼叫 arcall uni-app 端技术实现

发布于: 2021 年 09 月 02 日

介绍

基本

uniapp_arcall 是通过 uniapp 实现的语音通话、视频通话以及相关配套的呼叫邀请。解决向指定用户发起呼叫通知,对方接受后进行通话的场景需求。

呼叫邀请基本流程

graph TDA[主叫] -->|发起呼叫|B{被叫收到呼叫}    A -->|收到被叫接听|C[主叫执行 RTC]    A -->|收到被叫拒绝|G[相关逻辑]    B  -->D[被叫接听]    B  -->E[被叫拒绝]    D -->|通知主叫接听|A    D -->F[被叫执行 RTC]    E -->|通知主叫拒绝|A    B -->H[60s 无操作邀请自动失败]
复制代码

通话基本流程

graph LRA[初始化 RTC 实例] -->|采集音视频|B[加入房间]    B -->|本地采集音视频| C[发布并渲染音视频]    B -->|通过回调获取远端音视频| D[渲染远端音视频]
复制代码

arcall 具体实现

demo 源码 地址

呼叫邀请相关逻辑

引入呼叫邀请所需插件


// rtm 实时消息引入const rtmModule = uni.requireNativePlugin('AR-RtmModule');
复制代码

呼叫邀请初始化

uniapp_arcall 的是项目启动就登陆 RTM,因此写在 onLaunch中,调试时会发生以下错误


Error: [JS Framework] Failed to receiveTasks, instance (1) is not available.
复制代码


原因是多次将 RTM 实例初始化,会影响到 RTM 相关的使用请将程序杀死后在进行调试


// 初始化回调await rtmModule.setCallBack(res => {      switch (res.rtmEvent) {      // SDK 与 RTM 系统的连接状态发生改变回调。      case 'onConnectionStateChanged':        break;        // 收到点对点消息回调      case 'onPeerMessageReceived':              break;        // 被订阅用户在线状态改变      case 'onPeersOnlineStatusChanged':                break;        // 返回给主叫:被叫已接受呼叫邀请      case 'onLocalInvitationAccepted':                break;        // 返回给主叫:呼叫邀请已被取消      case 'onLocalInvitationCanceled':                break;        // 返回给主叫:呼叫邀请进程失败      case 'onLocalInvitationFailure':                break;        // 返回给主叫:被叫已收到呼叫邀请      case 'onLocalInvitationReceivedByPeer':                break;        // 返回给主叫:被叫已拒绝呼叫邀请      case 'onLocalInvitationRefused':              break;        // 返回给被叫:接受呼叫邀请成功      case 'onRemoteInvitationAccepted':              break;        // 返回给被叫:主叫已取消呼叫邀请      case 'onRemoteInvitationCanceled':                break;        // 返回给被叫:来自主叫的呼叫邀请进程失败      case 'onRemoteInvitationFailure':                break;        // 返回给被叫:收到一个呼叫邀请      case 'onRemoteInvitationReceived':              break;        // 返回给被叫:拒绝呼叫邀请成功      case 'onRemoteInvitationRefused':                break;      default:        break;    }  })// 初始化实例await rtmModule.createInstance({    "appId": "你的 appid"  }, res => {    console.log(res);  })// 登录 RTM 系统await rtmModule.login({  "token": "",  "userId": "本地用户标识"}, (res) => {  console.log("登录 RTM 系统", res);})// // 使用 RTM 呼叫邀请(设置邀请呼叫实例的监听器)await rtmModule.setCallEventListener();
复制代码

主叫

  • 查询呼叫用户是否在线


  rtmModule.queryPeersOnlineStatus({        "peerIds": ["呼叫用户"]      }, (res) => {        console.log(res);      })
复制代码


  • 呼叫用户在线时发起呼叫并订阅

  • 发起呼叫把本地创建的频道房间发送过去


  rtmModule.sendLocalInvitation({        "calleeId": calleeId, // 被呼叫者的 user ID        "content": JSON.stringify(info) // 邀请内容      }, (res) => {        resolve(res.code);      })
复制代码


  • 订阅(获取对方在线状态)当结束通话或结束邀请时记得取消订阅


  rtmModule.subscribePeersOnlineStatus({      "peerIds": ["对方 uid"]    }, (res) => {      //smething      console.log("订阅指定单个或多个用户的在线状态", res);    })
复制代码


  • 主叫取消呼叫


  rtmModule.cancelLocalInvitation({      "calleeId": calleeId, // 被呼叫者的 user ID      "content": JSON.stringify(info) // 邀请内容    }, (res) => {      console.log("取消给对方的呼叫邀请", res);    });
复制代码

被叫

通过回调 onRemoteInvitationReceived 收到主叫


  • 拒绝呼叫


rtmModule.refuseRemoteInvitation({      "calleeId": userId,      "response": JSON.stringify(info) /邀请内容    }, (res) => {    });
复制代码


  • 接受呼叫


rtmModule.acceptRemoteInvitation({      "calleeId": calleeId, // 供被叫获取主叫的用户 ID      "response": info ? JSON.stringify(info) : "" // 邀请响应    }, (res) => {    });// 订阅对方在线状态...
复制代码

相关提示

相关的提示、逻辑都可通过回调来进行操作

通话相关逻辑

视频组件必须实在 nvue 页面


<AR-CanvasView ref="location" style="flex: 1;" />
复制代码


不管是主叫还是被叫,收到接听的回调后就可以进入 RTC 的相关逻辑


  • 引入插件


const rtcModule = uni.requireNativePlugin('AR-RtcModule');
复制代码


  • 初始化


// 初始化回调 await rtcModule.setCallBack(res => {    switch (res.engineEvent) {      case "onConnectionLost":        console.log("onConnectionLost", res);        break;        // 网络连接状态已改变回调      case "onConnectionStateChanged":        console.log("网络连接状态已改变回调", res);        break;        // 发生警告回调      case "onWarning":                break;        // 发生错误回调      case "onError":                break;        // 加入频道成功回调      case "onJoinChannelSuccess":        // 本地渲染              break;        // 远端用户加入当前频道回调      case "onUserJoined":              break;        // 远端用户离开当前频道回调      case "onUserOffline":        console.log("远端用户离开当前频道回调", res);              break;        // 网络连接状态已改变回调      case "onConnectionStateChanged":              break;        // 已显示远端视频首帧回调      case "onFirstRemoteVideoFrame":        break;      case "onFirstRemoteVideoDecoded":              break;        // 远端用户视频状态发生已变化回调(当频道内的用户超过 17 时,该回调可能不准确)      case "onRemoteVideoStateChanged":              break;        //   // 本地网络类型发生改变回调        // case "onNetworkTypeChanged":        //   break;        //   // 网络连接中断        // case "onConnectionLost":        //   break;
// // 远端音频状态发生改变回调 // case "onRemoteAudioStateChanged": // break; // // 本地音频状态发生改变回调 // case "onLocalAudioStateChanged": // break; // // 本地视频状态发生改变回调 // case "onLocalVideoStateChanged": // break; // // 重新加入频道回调 // case "onRejoinChannelSuccess": // break; // // 离开频道回调 // case "onLeaveChannel": // break; // 已发送本地音频首帧回调 // case "onFirstLocalAudioFrame": // break; // // 已显示本地视频首帧回调 // case "onFirstLocalVideoFrame": // break; // // Token 服务即将过期回调 // case "onTokenPrivilegeWillExpire": // break; // // Token 过期回调 // case "onRequestToken": // break; // // 用户角色已切换回调(直播场景下) // case "onClientRoleChanged": // break; // // 本地或远端视频大小或旋转信息发生改变回调 // case "onVideoSizeChanged": // break; // // 通话中远端音频流的统计信息回调 // case "onRemoteAudioStats": // break; // // 当前通话统计回调。 该回调在通话中每两秒触发一次 // case "onRtcStats": // break; // // 通话中每个用户的网络上下行 last mile 质量报告回调 // case "onNetworkQuality": // break; // // 通话中本地视频流的统计信息回调 // case "onLocalVideoStats": // break; // // 通话中本地音频流的统计信息回调 // case "onLocalAudioStats": // break; // // 通话中远端视频流的统计信息回调 // case "onRemoteVideoStats": // break; } });// 初始化实例await rtcModule.create({ "appId": '你的 appid'}, res => { console.log('初始化实例 rtc', res);});// 开启智能降噪await rtcModule.setParameters({ Cmd: 'SetAudioAiNoise', Enable: 1 }, (res) => { console.log('私人定制', res); });
复制代码


  • 采集音视频如果是语音通话可以不执行下列代码


// 设置视频编码属性await rtcModule.setVideoEncoderConfiguration({},res) => {console.log('RTC 设置视频编码属性 setVideoEncoderConfiguration 方法调用', res.code ===0 ? '成功' :'失败:' + res);});// 启用视频await rtcModule.enableVideo((res) => {console.log('RTC 启用视频 enableVideo 方法调用', res.code === 0 ? '成功' : '失败:' +res);});
复制代码


  • 加入房间


rtcModule.joinChannel({      "token": '',      "channelId": 本地创建的频道/通过呼叫邀请传递过来的频道,      "uid": 本地的userid,    }, (res) => {      console.log('RTC joinChannel 方法调用', res.code === 0 ? '成功' : '失败:' + res);    });
复制代码


  • 本地视频渲染


  <AR-CanvasView ref="location" style="flex: 1;" />
复制代码


获取容器


  // 请确保可以获取到容器  Store.location = this.$refs.location;  console.log(Store.location);  // 打印后 类似这种  {    "ref": "68",    "type": "AR-CanvasView",    "attr": {      "@styleScope": "data-v-39c12bd0"    },    "style": {      "flex": "1"    }  }
复制代码


   // 渲染视频    await Store.location.setupLocalVideo({      "renderMode": 1,      "channelId": 加入的频道房间      "uid": 本地的userid      "mirrorMode": 0    }, (res) => {      console.log('渲染视频', res);    });    // 本地预览    await Store.location.startPreview((res) => {      console.log('本地预览', res);    })
复制代码


  • 远端视频渲染通过回调 onFirstRemoteVideoDecoded 获取远端用户发布视频 Store.remote 与 Store.location 类似


  await Store.remote.setupRemoteVideo({      "renderMode": 1,      "channelId": 加入的频道      "uid": res.uid      "mirrorMode": 0    }, (res) => {      console.log('渲染远端视频', res);    })    // 本地预览    await Store.remote.startPreview((res) => {      console.log('远端本地预览', res);    })
复制代码


  • 挂断


    // 销毁实例      rtcModule.destroyRtc((res) => {        console.log("销毁实例", res);      });
复制代码

总结

当前逻辑基本实现呼叫邀请+通话需要更详细,更具体,更全面的代码请前往 demo 源码 地址


  • 注意事项

  • RTM 初始化、RTC 初始化都只需要执行一次,多次执行请杀掉程序

  • RTM 可以在 vue 页面, RTC 视频容器必须在 nvue 页面

发布于: 2021 年 09 月 02 日阅读数: 9
用户头像

实时交互,万物互联! 2020.08.10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
uni-app技术分享|开源demo视频呼叫arcall uni-app端技术实现