[转载]使用GoEasy在uniapp下实现实时音视频通话附关键代码

发布时间 2023-12-21 18:01:54作者: maolangong

GRTC (GoEasy Real-Time Communication)是GoEasy推出的新功能,用于协助开发者在uniapp下轻松实现一对一和多人场景下的实时音视频通话功能。

集成步骤


1. 配置云厂商音视频服务
GRTC功能依赖于云厂商的音视频服务,目前已集成七牛云音视频服务(每月免费5000分钟),并计划未来支持更多云厂商。

具体请参考官网文档:https://docs.goeasy.io/2.x/rtc/qiniu/qiniu-rtc
【非常简单,几步搞定】


2. 下载依赖SDK和uniapp原生插件
GoEasy JS SDK下载:https://registry.npmjs.org/goeasy/-/goeasy-2.10.13.tgz
GRTC JS SDK下载:https://registry.npmjs.org/goeasy-rtc/-/goeasy-rtc-0.1.4.tgz
GRTC Uniapp原生插件下载:https://docs.goeasy.io/2.x/download/goeasy-rtc-uniapp-v0.1.0.zip

 

 

 3. 编码集成音视频通话接口
温馨提示:
1. GRTC 的初始化必须在建立连接之前完成,否则GRTC将无法正常工作。
2. 在建立GoEasy连接时,务必传入当前用户的ID和数据。缺少用户ID将无法作为发起拨打的用户,也无法作为明确的用户接收来电。
3. GoEasy使用了标签来实时呈现视频图像,由于标签是基于Uniapp原生插件实现的,因此仅限于在nvue页面中使用,无法在vue页面中应用。拨打、响铃和通话等界面通常都要求实时展示视频图像,因此建议相关页面统一采用nvue页面。
文章中提到的所有代码,均可以在官网demo源码处下载,包含vue2 和vue3两种语法哦,下载地址:https://gitee.com/goeasy-io/goeasy-rtc-demo


好了,接下来将具体说说代码层面您需要写哪些必要的代码:

1. 在uniapp的main.js中引入sdk并初始化GoEasy和GRTC,然后将其挂载为全局对象。

import App from './App';
import GoEasy from './lib/goeasy-2.10.13.esm.min.js';
import GRTC from './lib/goeasy-rtc-0.1.4.esm.min.js'

GoEasy.init({
    host:"hangzhou.goeasy.io",//应用所在的区域地址: 【hangzhou.goeasy.io或者singapore.goeasy.io】
    appkey:"您的appkey",// 如何获取appkey和每种key的说明参考:https://docs.goeasy.io/2.x/common/account/developer-account
    modules: ['im'],
    // true表示支持通知栏提醒,false则表示不需要通知栏提醒
    allowNotification: true //仅有效于app,小程序和H5将会被自动忽略
});
GRTC.init(GoEasy);

uni.$GoEasy = GoEasy;
uni.$GRTC = GRTC;


// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
  const app = createSSRApp(App)
  return {
    app
  }
}
// #endif

2. 建立GoEasy连接

const GoEasy = uni.$GoEasy;
const GRTC = uni.$GRTC;
onShow(() => {
     if (GoEasy.getConnectionStatus() === 'disconnected') {
      GoEasy.connect({
      id: 'User1',//必填
      data: {//必填,成员数据对象,可以任意定义属性
        name: 'Mattie',
        avatar: '/image/mattie.jpg'
      },
      onSuccess: () => {
        console.log('GoEasy connect successfully.')
      },
      onFailed: (error) => {
        console.log('Failed to connect GoEasy, code:' + error.code + ',error:' + error.content);
      },
      onProgress: (attempts) => {
        console.log('GoEasy is connecting', attempts);
      }
    });
   }
 });

用户data信息录入GoEasy小技巧:
前端只有建立GoEasy连接时才能传入data,如果用户修改头像后想要更新GoEasy这边的头像时,可以调用GoEasy提供的注册成员data的rest 接口:
方法: POST
URL: http://rest-hz.goeasy.io/v2/memberdata
请求头: Content-Type: application/json
请求体:

{
  "appkey": "您的appkey", // 应用appkey
  "id": "User1", // 成员id
  "data": {"name": "Mattie", "avatar": "/images/Avatar-2.png"} //成员数据对象,可以任意定义属性
}

3. 一对一通话实现

3.1. 【拨打】发起一对一通话
GRTC.call({
          calleeId: 'User2',
          mediaType: 1,//0:音频通话 1:视频通话
        }).then(() => {//呼叫成功
          uni.navigateTo({//一般都是调转到拨打页面
            url: `./rtc/private/dial`,
          })
        }).catch((error)=>{//呼叫失败,会返回具体失败原因
          console.log("呼叫失败:", error);
          uni.showToast({
            icon: "none",
            title: "呼叫失败",
            duration: 2000
          })
        })
      },
      fail: (res) => {
        console.log(res.errMsg);
      }
    });
3.2. 【通话页面渲染】拨打、响铃、通话情况

通过调用GRTC.currentCall() 获取当前通话对象,以便在页面上呈现拨打方、接听方的信息、通话时长以及视频图像。

<template>
  <view class="call-view">
    <view class="nav-bar">
      <text class="duration">{{duration}}</text>
    </view>

    <!-- 音频通话 -->
    <view v-if="call.mediaType===0" class="profile">
      <image class="user-avatar" mode="widthFix" :src="friend.data.avatar"></image>
      <text class="user-name">{{friend.data.name}}</text>
    </view>

    <!-- 视频通话 -->
    <view v-if="call.mediaType === 1" class="content">
      <view class="container">
        <grtc-video :userId="mainVideoUserId" class="main-video"></grtc-video>
        <grtc-video :userId="miniVideoUserId" class="mini-video"></grtc-video>
      </view>
    </view>
    
</template>

<script setup>
  import {ref} from 'vue';
  import {onLoad, onUnload, onBackPress} from "@dcloudio/uni-app";
  const GRTC = uni.$GRTC;
  const call = GRTC.currentCall();//从currentCall中获取呼叫者的信息,然后进行相关信息的渲染
    // currentCall 对象的属性说明:
    // - id: 通话ID
    // - time: 拨打时间
    // - caller: 主叫用户信息
    // - callees: 被叫用户信息列表,数组对象,每个callee中都包含被呼叫人的id和data信息
    // - status: 通话状态 ('Dialing': 呼叫中, 'Ringing': 响铃中,'InCall': 通话中)
    // - groupId: 群id(可选)
    // - mediaType: 媒体类型(0: 音频, 1: 视频)
    // - getDuration(): 通话时长(秒)


  const currentUser = uni.$currentUser;
  const friend = currentUser.id === call.caller.id ? call.callees[0] : call.caller;
  const mainVideoUserId = ref(friend.id);
  const miniVideoUserId = ref(currentUser.id);

  const duration = ref(formattedDuration());

  const interval = setInterval(() => {
    duration.value = formattedDuration();
  }, 1000);

 function formattedDuration() {
    const seconds = call.getDuration();
    const minutes = Math.floor(seconds / 60);
    const formattedSeconds = String(seconds % 60).padStart(2, '0');
    const formattedMinutes = String(minutes).padStart(2, '0');
    return `${formattedMinutes}:${formattedSeconds}`; // mm:ss
  }

</script>

3.3. 来电事件监听

开发者可通过监听 GRTC.EVENT.RING 事件实现来监听来电。在监听到该事件时,即可触发页面跳转至来电提醒页面。
注意:
为确保不错过任何来电,务必在 APP 默认首页实现来电事件的监听。这样可以确保 APP 启动后立即执行监听代码,无论用户在访问任何页面时,只要有来电,都能及时监听到来电事件并成功跳转至来电页面。

onShow(() => {
     if (GoEasy.getConnectionStatus() === 'disconnected') {
      //建立GoEasy连接,代码省略,请参考上面的完整代码
      GoEasy.connect({...});
   }
   GRTC.on(GRTC.EVENT.RING, onRing); //监听来电事件  
  });
  function onRing() {
    const currentCall = GRTC.currentCall();
    console.log('onRing', currentCall);
        //TODO: 跳转到来电页面
    }
 }
3.4. 接听通话

在监听到来电响铃事件后,可通过调用 GRTC.accept() 方法来接听通话。在接听成功后,可跳转至通话页面,实现通话功能。没有来电时,调用该方法将无效。

<view class="action-item" @click="accept()">
    <view class="accept-background">
       <image class="action-icon rotate" src="/static/images/phoneEnd.png"></image>
     </view>
     <text class="action-text">接听</text>
 </view>
 function accept() {
    GRTC.accept().then(() => {
      uni.redirectTo({//调转到接听页面
        url: './call'
      });
    }).catch((e) => {
      console.log('e', e);
    })
  }
3.5. 结束通话

若当前存在进行中的通话,随时可通过调用 GRTC.end() 方法来结束通话。在通话拨打时调用,表示取消通话;来电响铃时调用,则是拒接来电;而在通话中调用,则意味着挂断通话。

<view class="action-item" @click="end()">
  <view class="end-background">
       <image class="action-icon" src="/static/images/phoneEnd.png"></image>
    </view>
     <text class="action-text">拒绝</text>
 </view>
      
 function end() {
    GRTC.end();
  }
3.6. 监听通话结束事件

任何一方的退出都意味着通话的结束。由于用户退出事件对象包含退出的具体原因,包括用户主动取消拨打、拒绝来电、或结束正在进行的通话,同时也可能由于网络异常导致通话中断。此外,响铃超时和多设备同步同样会引发该事件。

onLoad(() => {
    GRTC.on(GRTC.EVENT.USER_QUIT, onUserQuit);
  })
  function onUserQuit(event) {
  console.log('onUserQuit', event);
  // event属性说明:
        // - user: 
        //   - id: 用户ID
        //   - data: 用户data
        // - reason: 退出原因,可能的取值包括:
        //   - NO_ANSWER: 本端响铃达到XX秒,本方未接听
        //   - CANCELLED: 本端取消
        //   - REJECTED: 本端拒绝
        //   - HUNG_UP: 本端挂断
        //   - RTC_DISCONNECTED: 本端RTC网络断开
        //   - GOEASY_DISCONNECTED: 本端GoEasy网络断开
        //   - HANDLED_ON_ANOTHER_DEVICE: 已经被同一个用户在其他设备接听或者拒绝
    clearInterval(interval);
    const username = event.user.id === currentUser.id ? '' : event.user.data.name;
    let message = '';
    switch (event.reason) {
      case 'GOEASY_DISCONNECTED':
        message = `${username}网络异常`;
        break;
      case 'HUNG_UP':
        message = `${username}已挂断`;
        break;
    }
    plus.nativeUI.toast(message);
    uni.navigateBack();
  }

 

3.7. 监听用户已响铃事件

在发起通话时,若对方已成功接收来电并开始响铃,将触发该事件。该事件可用于模拟传统电话中不同声音代表不同拨打状态的效果,同时还可通过页面展示每个用户的响铃状态。

GRTC.on(GRTC.EVENT.USER_RANG, onUserRang);
function onUserRang(event) {
    console.log('onUserRang', event);
    // event属性说明:
        // - user: 
        //   - id: 用户ID
        //   - data: 用户data
    plus.nativeUI.toast(event.user.data.name+"已响铃");
  }
3.8. 监听用户接听成功事件

只要有用户接听成功,该事件都会被触发。

GRTC.on(GRTC.EVENT.USER_ACCEPTED, onUserAccepted);
function onUserAccepted(event) {
        console.log('onUserAccepted', event);
        // event属性说明:
        // - user: 
        //   - id: 用户ID
        //   - data: 用户data
        
    plus.nativeUI.toast(event.user.data.name+"已接听");
    uni.redirectTo({
      url: './call'
    });
  }

4. 多人通话实现

GRTC多人通话功能支持最多9人同时进行通话,其中包括一个发起通话的拨打方和最多8个同时参与通话的接听方。

4.1. 【拨打】发起多人通话
 GRTC.groupCall({
          groupId: 'group001',//群id
          calleeIds: ['user1','user2','user3'], //接听方用户id数组,最多不可以超过8个,
          mediaType: 1,//0:音频通话 1:视频通话
        }).then(() => {
          hideCheckbox();
          uni.navigateTo({
            url: `./rtc/group/dial`,
          })
        }).catch((error)=>{
          console.log("error:",error)
          hideCheckbox();
          uni.showToast({
            icon: "error",
            title: "呼叫失败",
            duration: 2000
          })
        })
      },
      fail: (res) => {
        console.log(res.errMsg);
      }
    });
4.2. 【通话页面渲染】拨打、响铃、通话情况

通过调用GRTC.currentCall() 获取当前通话对象,以便在页面上呈现拨打方、接听方的信息、通话时长以及视频图像。

<template>
  <view class="call-view">
    <cover-view class="profile">
      <image class="caller-avatar" mode="widthFix" :src="call.caller.data.avatar"></image>
      <text class="caller-name">{{call.caller.data.name}}</text>
    </cover-view>
    <view class="status-box">
      <text class="status-notice">邀请你加入多人通话</text>
      <image src="/static/images/load.gif" class="loading"></image>
    </view>

    <view class="callee-info">
      <text class="callee-text">参与通话的还有:</text>
      <view class="callee-list">
        <view v-for="(callee, index) in callees" :key="index" >
          <image class="callee-avatar" :src="callee.data.avatar" mode="widthFix"></image>
        </view>
      </view>
    </view>
  </view>
</template>

<script setup>
  import {ref} from 'vue';
  import {onLoad,onUnload,onBackPress} from "@dcloudio/uni-app";
   const GRTC = uni.$GRTC;

  const mediaType = GRTC.currentCall().mediaType;
  const currentUser = uni.$currentUser;

  const members = ref(sortedMembers());
  const duration = ref(formattedDuration());

  const interval = setInterval(() => {
    duration.value = formattedDuration();
  }, 1000);

  onBackPress((event) => {
    return event.from === 'backbutton';  // 禁止安卓侧滑返回
  });

  function sortedMembers() {
    const call = GRTC.currentCall();
    const allMembers = [...call.callees, call.caller].filter(member => member.status !== 'Quit');
    const sortedMembers = allMembers.sort((a, b) => {
      if (a.id === currentUser.id) return 1;
      if (b.id === currentUser.id) return -1;
      return 0;
    });
    return sortedMembers;
  }

  function formattedDuration() {
    const call = GRTC.currentCall();
    const seconds = call.getDuration();
    const minutes = Math.floor(seconds / 60);
    const formattedSeconds = String(seconds % 60).padStart(2, '0');
    const formattedMinutes = String(minutes).padStart(2, '0');
    return `${formattedMinutes}:${formattedSeconds}`; // mm:ss
  }
</script>

4.3. 来电事件监听 (代码同一对一通话)

开发者可通过监听 GRTC.EVENT.RING 事件实现来监听来电。在监听到该事件时,即可触发页面跳转至来电提醒页面。

注意:
为确保不错过任何来电,务必在 APP 默认首页实现来电事件的监听。这样可以确保 APP 启动后立即执行监听代码,无论用户在访问任何页面时,只要有来电,都能及时监听到来电事件并成功跳转至来电页面。

onShow(() => {
     if (GoEasy.getConnectionStatus() === 'disconnected') {
      //建立GoEasy连接,代码省略,请参考上面的完整代码
      GoEasy.connect({...});
   }
   GRTC.on(GRTC.EVENT.RING, onRing); //监听来电事件  
  });
  function onRing() {
    const currentCall = GRTC.currentCall();
    console.log('onRing', currentCall);
        //TODO: 跳转到来电页面
    }
 }
4.4. 接听通话(代码同一对一通话)

在监听到来电响铃事件后,可通过调用 GRTC.accept() 方法来接听通话。在接听成功后,可跳转至通话页面,实现通话功能。没有来电时,调用该方法将无效。

<view class="action-item" @click="accept()">
    <view class="accept-background">
       <image class="action-icon rotate" src="/static/images/phoneEnd.png"></image>
     </view>
     <text class="action-text">接听</text>
 </view>
 function accept() {
    GRTC.accept().then(() => {
      uni.redirectTo({//调转到接听页面
        url: './call'
      });
    }).catch((e) => {
      console.log('e', e);
    })
  }
4.5. 结束通话(代码同一对一通话)

若当前存在进行中的通话,随时可通过调用 GRTC.end() 方法来结束通话。在通话拨打时调用,表示取消通话;来电响铃时调用,则是拒接来电;而在通话中调用,则意味着挂断通话。

<view class="action-item" @click="end()">
  <view class="end-background">
       <image class="action-icon" src="/static/images/phoneEnd.png"></image>
    </view>
     <text class="action-text">拒绝</text>
 </view>
      
 function end() {
    GRTC.end();
  }
4.6. 监听通话结束事件和单个用户退出聊天事件

当多人通话的倒数第二个用户结束了通话意味着整个多人通话的结束。
可以通过一下代码进行监听。

onLoad(() => {
    GRTC.on(GRTC.EVENT.CALL_ENDED, onCallEnded);
 })
 function onCallEnded() {
    clearInterval(interval);
    uni.navigateBack();
  }

任何用户退出通话,都可以通过监听USER_QUIT事件来监听用户的退出通话的行为。 可用于展示具体的退出原因或更新页面上的用户列表。

由于用户退出事件对象包含退出的具体原因,包括用户主动取消拨打、拒绝来电、或结束正在进行的通话,同时也可能由于网络异常导致通话中断。此外,响铃超时和多设备同步同样会引发该事件。

onLoad(() => {
    GRTC.on(GRTC.EVENT.USER_QUIT, onUserQuit);
  })
  function onUserQuit(event) {
    callees.value = GRTC.currentCall() ? GRTC.currentCall().callees : [];
    const username = event.user.data.name;
    let message = '';
    switch (event.reason) {
      case 'DIAL_TIMEOUT':
        message = `拨打超时`;
        break;
      case 'CANCELLED':
        message = `已取消`;
        break;
      case 'REJECTED':
        message = `${username}已拒绝`;
        break;
      case 'GOEASY_DISCONNECTED':
        message = `${username}网络异常`;
        break;
    }
    plus.nativeUI.toast(message);
  }
4.7. 监听用户已响铃事件

在发起通话时,被拨打者开始响铃,将触发该事件。 在多人通话场景下,此事件将被多次触发,每当有用户响铃时都会被触发。

GRTC.on(GRTC.EVENT.USER_RANG, onUserRang);
function onUserRang(event) {
    console.log('onUserRang', event);
    // event属性说明:
        // - user: 
        //   - id: 用户ID
        //   - data: 用户data
    plus.nativeUI.toast(event.user.data.name+"已响铃");
  }
4.8. 监听用户接听成功事件

在多人通话场景下,此事件将被多次触发,每当有用户接听成功时都会触发。

GRTC.on(GRTC.EVENT.USER_ACCEPTED, onUserAccepted);
function onUserAccepted(event) {
        console.log('onUserAccepted', event);
        // event属性说明:
        // - user: 
        //   - id: 用户ID
        //   - data: 用户data
        
    plus.nativeUI.toast(event.user.data.name+"已接听");
    uni.redirectTo({
      url: './call'
    });
  }

4. 离线通话推送和自定义铃声设置

在音视频实时通话功能的开发中,当发起通话请求时,对方的应用可能处于后台或锁屏状态。为了及时提醒用户有新的来电,我们可以通过推送来实现,并通过自定义铃声进行响铃。
4.1. 推送和自定义铃声

要实现来电推送和自定义铃声,首先需要集成GoEasy Uniapp通知推送和添加自定义铃声。 然后,在发起通话时,添加notification属性,对方即可收到来电提醒。

        let promise = GRTC.call({
            calleeId: 'User1', //接听方用户id
            mediaType: 0,
            notification: {
                title: 'Jack',  //通知标题
                body: '邀请您语音通话', //通知内容
                sound: 'ring', //铃声
                badge: '+1' //角标
            },
        });

4.2. 厂商通道和厂商消息分类接入

为了确保即使在应用进程杀掉后,仍能及时接收到推送,需要接入各手机品牌的厂商通道。此外,为了防止来电推送被手机厂商判为运营消息而被过滤,还需进行厂商消息分类的接入。

有什么问题,上GoEasy官网找在线客服。

————————————————
版权声明:本文为CSDN博主「GoEasy消息推送」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44720122/article/details/135094419