視訊通話 - 時信魔方教程

時信魔方發表於2020-12-28

時信魔方能幫助開發者快速構建視訊通訊程式,從點到點的視訊通訊到 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月28日

郵箱:xujiangwei@spap.com, hermit86@163.com

 

相關文章