快速实现视频通话

原创
2020/12/28 10:45
阅读数 200

时信魔方能帮助开发者快速构建视频通讯程序,从点到点的视频通讯到 MCU 融屏视频通讯都可以轻松使用时信魔方实现:

多人会议截屏

 

本节中我们将使用时信魔方实现两个账号之间进行视频通话,实现的效果截图如下所示:

主叫方 被叫方
主叫方截图 被叫方截图

 

预备知识

在开始写代码前,先简单介绍一下时信魔方的 MultipointComm 模块和服务单元,这是实现音视频通讯的基本模块。如果是实现多方在线会议,则需要使用 ConferenceService 模块和服务单元,这在后面的章节将有介绍。

一个典型的音视频通讯场景入下图所示:

场景

客户端需要通过信令服务器交换信令与对端协商通讯参数,通讯双方需要协商使用什么视频编解码器,音频编解码以及通讯端口等等信息。之后依据协商的参数,在媒体流服务器上进行音视频数据流的发送和接收。

这里我们使用 MultipointCommRTCDevice 来开发视频通话,RTCDevice 使用的是 WebRTC 实现。这节的示例程序将通过 ICE 穿透的方式进行媒体流交换,因此不需要使用 cube-media-unit 来进行转码和混码。

> 关于如何使用 cube-server 可查看我们之前的文章《快速启动服务器》

MultipointComm 将 RTC 媒体流分为两类:

  • Outbound stream 出站流 - 设备上行发送的 RTC 音频或视频流。
  • Inbound stream 入站流 - 设备下行接收的 RTC 音频或视频流。

通讯请求就是建立“通话”的过程:

  • makeCall 发起通话邀请
  • answerCall 应答通话邀请
  • followCall 请求入站邀约
  • revokeCall 停止入站邀约
  • hangupCall 挂断当前通话

因此,使用 MultipointComm 实现音视频通讯,就是一个操作“通话” API 的过程。接下来我们将在浏览器里实现一个简单的点到点的视频通话程序。

 

程序界面

除了在界面里放置“呼叫”、“应答”和“挂断”按钮,为了显示两个画面,我们还需要放置两个 video 标签来容纳我们自己的摄像头视频画面和对端的摄像头视频画面。界面结构如下图所示:

界面示例

 

准备工作

在进行通话前,我们需要启动 MultipointComm 模块,并监听相关的通讯事件,例如:收到来自其他终端的通话邀请等。

启动 MultipointComm 模块:

JavaScript 代码:

cube.mpComm.start();

 

监听事件:

JavaScript 代码:

cube.mpComm.on(CallEvent.InProgress, onInProgress);
cube.mpComm.on(CallEvent.Ringing, onRinging);
cube.mpComm.on(CallEvent.NewCall, onNewCall);
cube.mpComm.on(CallEvent.Connected, onConnected);
cube.mpComm.on(CallEvent.Bye, onBye);
cube.mpComm.on(CallEvent.Timeout, onTimeout);
cube.mpComm.on(CallEvent.CallFailed, onCallFailed);

 

发起通话

点击“呼叫”按钮是发起对指定 ID 的呼叫。

JavaScript 代码:

function makeCall() {
    // 设置视频标签元素
    cube.mpComm.setRemoteVideoElement(peerVideo);
    cube.mpComm.setLocalVideoElement(myVideo);

    if (peerIdInput.value.length < 3) {
        stateLabel.innerHTML = '<span class="warning">请输入“对端 ID”</span>';
        return;
    }

    cube.contact.getContact(peerIdInput.value, function(contact) {
        let mediaConstraint = new MediaConstraint(true, true);

        cube.mpComm.makeCall(contact, mediaConstraint, function() {
            stateLabel.innerHTML = '呼叫 ' + contact.getId();
            hangupCallButton.removeAttribute('disabled');
        }, function(error) {
            stateLabel.innerHTML = '发生呼叫错误 ' + error;
        });
    });
}

这里我们还使用了 ContactService 模块来获取指定 ID 的联系人,在获取到对应的 Contact 实例后,再执行 MultipointCommmakeCall() 方法。

 

应答邀请

当收到其他终端的通话邀请时,点击“应答”来接通通话:

JavaScript 代码:

function answerCall() {
    // 设置视频标签元素
    cube.mpComm.setRemoteVideoElement(peerVideo);
    cube.mpComm.setLocalVideoElement(myVideo);

    let mediaConstraint = new MediaConstraint(true, true);
    cube.mpComm.answerCall(mediaConstraint, function(record) {
        stateLabel.innerHTML = '应答 ' + record.getPeer().getId();
    }, function(error) {
        stateLabel.innerHTML = '应答错误:' + error;
    });
}

 

结束通话

通话结束时,点击“挂断”按钮来停止通话,关闭摄像头和麦克风。

JavaScript 代码:

function hangupCall() {
    cube.mpComm.hangupCall();
}

 

事件处理

这里我们主要关注 NewCall 事件,NewCall 事件的回调函数代码如下:

function onNewCall(event) {
    // 当前的通话记录
    let record = event.getData();
    stateLabel.innerHTML = '收到来自 ' + record.getCaller().getId() + ' 通话邀请';
    hangupCallButton.removeAttribute('disabled');
    answerCallButton.removeAttribute('disabled');

    ...
}

在收到该事件时,需要提示用户有对端在邀请你通话,也就是“有来电”,从而让用户选择是否接听。

通常的,移动端程序并不总在前台运行,因此是否有来电与 SHM 链路是否连通没有关联,即便没有和服务器连接,移动端也可以在通话邀请等待(默认是30秒)期间回到前台应答通话。

 

处理摄像头和麦克风调用权限

首次运行程序时,浏览器会提示你是否允许程序调用你的摄像头和麦克风,这时需要你选择允许,以便程序能顺利获取到视频流和音频流。

Chrome 浏览器的媒体设备管理窗口在浏览器地址栏右侧:

Chrome

 

Firefox 浏览器的媒体设备管理窗口在地址栏左侧:

Firefox

 

 

> > 作者:徐江威 > > 日期:2020年12月24日 > > 邮箱:xujiangwei@spap.com, hermit86@163.com >

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部