anyRTC Web SDK 实现音视频呼叫功能
阅读原文时间:2022年04月03日阅读:1

前言

大家好,今天小编带给大家一个基于 anyRTC Web SDK 实现音视频呼叫的功能(本项目采用vue开发)。

前提条件

在开始写代码之前还需要做一些准备工作,如果你之前没有使用过 anyRTC Web SDK 这里还需要花几分钟时间准备一下, 详见:开发前期准备

操作流程

下载并引入项目依赖

npm i ar-rtm-sdk -S
npm i ar-rtc-sdk -S


import ArRTM from 'ar-rtm-sdk';
import ArRTC from 'ar-rtc-sdk';
import config from '../config';

config.js

export default {
    appid: '', // anyRTC 控制台生成的 appid (详见前提条件)
    uid: 'web' + Math.floor(Math.random() * 10000000) // 随机生成本地uid
}

data 初始数据

data() {
    return {
        localInvitation: null, // 通过 ArRTMClient.createLocalInvitation 创建的实例
        ArRTMClient: null,     // 通过 ArRTM.createInstance 创建的RTM客户端实例
        ArRTCClient: null,     // 通过 ArRTC.createClient 创建的客户端对象
        audioTrack: null,      // 本地音频轨道
        videoTrack: null,      // 本地视频轨道
        audioDevices: [],      // 本地音频设备列表
        videoDevices: []       // 本地视频设备列表
        remoteUid: ''          // 远端用户的 uid
    }
}

mounted

mounted() {
    this.getRemoteUid(); // 获取远程用户 uid
    this.getDevices();   // 获取音视频设备
    this.createTrack();  // 创建本地音视频轨道
},

methods

// 获取远端用户 uid (这一步可以用输入框代替)
getRemoteUid() {
    const remoteUid = this.$route.query.uid;
    if (remoteUid) {
        this.remoteUid = remoteUid;
        this.createClient();
    }
},

// 获取音视频设备
async getDevices() {
    const [ videoDevices, audioDevices ] = await Promise.all([
        ArRTC.getCameras(),
        ArRTC.getMicrophones(),
    ]);
    this.videoDevices = videoDevices;
    this.audioDevices = audioDevices;
},

// 创建本地音视频轨道
async createTrack() {
    this.audioTrack = await ArRTC.createMicrophoneAudioTrack();
    // 如果没有摄像头设备就不创建视频轨道
    if (this.videoDevices.length) {
        this.videoTrack = await ArRTC.createCameraVideoTrack();
    }
},

// 创建 RTM 和 RTC 客户端对象
createClient() {
    this.ArRTMClient = ArRTM.createInstance(config.appid);
    this.ArRTCClient = ArRTC.createClient({ mode: 'rtc', codec: 'h264' });
    // 监听远端用户发布音视频流
    this.listenUserPublished();
    // 监听点对点消息
    this.listenMessageFromPeer();
    // 登录 RTM
    this.ArRTMClient.login({ uid: config.uid }).then(() => {
        // 监听远端用户上下线
        this.listenPeersOnlineStatusChanged();
        // 订阅人员上下线
        this.subscribePeersOnlineStatus();
    }).catch((err) => {
        console.log(err);
    });
},

// 监听点对点消息 (这里主要的作用就是远端通过rtm消息,告诉我们他的一些状态)
listenMessageFromPeer() {
    this.ArRTMClient.on('MessageFromPeer',  message => {
        // 状态码自己约定
        if (message.text === '100') {
             // 对方正在通话中
        } else if (message.text === '200') {
            // 对方挂断 我们也要离开房间
            this.handleLeave();
        }
    });
},

// 监听远端用户发布音视频流
listenUserPublished() {
    this.ArRTCClient.on("user-published", async (user, mediaType) => {
        await this.ArRTCClient.subscribe(user, mediaType);
        this.inTheCall = true;
        if (mediaType === 'video') {
            // 播放远端视频 (传入一个dom元素id)
            user.videoTrack.play('#remote_video');
        } else if (mediaType === 'audio') {
            // 播放远端音频 (音频不需要元素)
            user.audioTrack.play();
        }
    });
},

// 监听远端用户上下线
listenPeersOnlineStatusChanged() {
    this.ArRTMClient.on('PeersOnlineStatusChanged', (status) => {
        const ONLINE = status[this.remoteUid] === 'ONLINE';
        // 如果对方在线 就发送呼叫邀请
        ONLINE && this.callRemote(this.remoteUid);
    });
},

// 监听 localInvitation 状态
localInvitationListen() {
    // 被叫已接受呼叫邀请时触发
    this.localInvitation.on('LocalInvitationAccepted', (response) => {
        // 对方同意接听 本地加入频道
        this.joinChannel();
        console.log(response, '被叫已接受呼叫邀请时触发')
    });
},

// 加入频道
joinChannel() {
    this.ArRTCClient.join(config.appid, config.uid, null, config.uid).then(() => {
        this.videoTrack && this.videoTrack.play('local_video');
        // 发布本地音视频
        this.audioTrack && this.ArRTCClient.publish(this.audioTrack);
        this.videoTrack && this.ArRTCClient.publish(this.videoTrack);
    }).catch((err) => {
        console.log(err);
    });
},

// 订阅人员上下线
subscribePeersOnlineStatus() {
    this.ArRTMClient.subscribePeersOnlineStatus([this.remoteUid]);
},

// 呼叫远端用户
callRemote() {
    // 创建一个 LocalInvitation 实例
    this.localInvitation = this.ArRTMClient.createLocalInvitation(this.remoteUid);
    // 监听 localInvitation 状态
    this.localInvitationListen();
    // 发起呼叫
    this.localInvitation.send();
},

// 挂断
handleLeave() {
    // 离开频道
    this.ArRTCClient.leave();
    // 取消已发送的呼叫邀请
    this.localInvitation.cancel();
},

HTML

<!-- 挂断 -->
<div class='hangUp' @click='handleLeave'>
    <img src="../assets/images/hangUp.png" alt="">
</div>

<!-- 重新呼叫 -->
<div class='replay' @click='callRemote'>
    <div>
        <img src="../assets/images/replay.png" alt="">
    </div>
    <p>重新呼叫</p>
</div>

<!-- 本地视频容器 -->
<div id='local_video'></div>
<!-- 远端视频容器 -->
<div id='remote_video'></div>

CSS

<style lang='less' scoped>
#call {
    position: fixed;
    z-index: 90;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    .hangUp {
        position: fixed;
        z-index: 999;
        left: 0;
        right: 0;
        bottom: 100px;
        margin: auto;
        width: 78px;
        height: 78px;
        cursor: pointer;
    }
    .replay {
        position: fixed;
        z-index: 999;
        left: 0;
        right: 0;
        bottom: 100px;
        margin: auto;
        display: flex;
        flex-direction: column;
        align-items: center;
        div {
            width: 78px;
            height: 78px;
            cursor: pointer;
        }
        p {
            margin-top: 17px;
            font-size: 16px;
            font-family: PingFang, PingFang-Regular;
            font-weight: 400;
            color: #fff;
        }
    }
    #local_video {
        position: fixed;
        z-index: 300;
        top: 38px;
        left: 32px;
        width: 297px;
        height: 167px;
    }
    #remote_video {
        position: fixed;
        z-index: 200;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
    }
}
</style>