關於TRTC(實時音視頻通話模式)在我司的實踐

TRTC

騰訊實時音視頻(Tencent Real-Time Communication,TRTC)將騰訊21年來在網絡與音視頻技術上的深度積累,以多人音視頻通話和低延時互動直播兩大場景化方案,經過騰訊雲服務向開發者開放,致力於幫助開發者快速搭建低成本、低延時、高品質的音視頻互動解決方案。git


TRTC流程圖

f3ba68fa7e39fe64af92ff99f56b77a

加入房間

建立流

this.client = TRTC.createClient({
    mode: 'videoCall',
    sdkAppId,
    userId,
    userSig
});
  • mode: 實時音視頻通話模式,設置爲‘videoCall’,互動直播模式,設置爲'live'
  • sdkAppId: 您從騰訊雲申請的 sdkAppId
  • userId: 用戶 ID,隨機生成,一個房間內不容許重複的userId
  • userSig: 用戶簽名,基於後臺算法生成,防盜刷

加入

this.client
    .join({ roomId })
    .catch(error => {
        console.error('進房失敗 ' + error);
    })
    .then(() => {
        console.log('進房成功');
    });
  • roomId:後臺生成的房間Id,不能重複

發佈本地流

本地推流

this.localStream = TRTC.createStream({ userId: this.userId, audio: true, video: true });
  • userId: 用戶 ID,隨機生成,一個房間內不容許重複的userId
  • audio: 是否從麥克風採集音頻
  • video: 是否從攝像頭採集視頻

初始化本地音視頻流

this.localStream
    .initialize()
    .catch(err => {
        console.error('初始化本地流失敗 ' + error);
    })
    .then((res) => {
        console.log('初始化本地流成功');
        this.localStream.play('localVideo');
    });
  • localVideo: 綁定的div id

發佈

this.client
    .publish(this.localStream)
    .catch(err => {
        console.error('本地流發佈失敗 ' + error);
    })
    .then((res) => {
        console.log('本地流發佈成功');
    });
  • 本地流發佈成功以後,能夠註冊本地推流函數,每三秒執行一次,處理異常狀況。

訂閱遠端流

遠端流增長

this.client.on('stream-added', event => {
    this.remoteStream = event.stream;
    //訂閱遠端流
    this.client.subscribe(this.remoteStream);
});

遠端流訂閱

this.client.on('stream-subscribed', event => {
    console.log('log', 'onRemoteStreamUpdate:' + event);
    this.remoteStream = event.stream;
    this.id = this.remoteStream.getId();
    const remoteVideoDom = document.querySelector('#remoteVideo');
    if(!document.querySelector(`#remoteStream-${this.id}`)) {
        const div = document.createElement('div');
        div.setAttribute('style', 'position: absolute; right: 0; left: 0; top: 0; width: 100%; height: 100%');
        div.setAttribute('id', `remoteStream-${this.id}`);
        remoteVideoDom.appendChild(div);
    }
    const videoLoading = document.querySelector('#video-loading');
    videoLoading.setAttribute('style', 'display: none;');
    // 播放遠端流
    this.remoteStream.play(`remoteStream-${this.id}`);
});
  • 能夠在遠端流監聽成功以後,註冊遠端流狀態變化函數,處理異常狀況。

退出

取消發佈本地流

this.client.unpublish(this.localStream)
    .catch((err) => {
        console.log('error', 'unpublish error:' + err);
    })
    .then((res) => {
        // 取消發佈本地流成功
        console.log('log', 'unpublish error:' + res);
    });

退出房間

this.client.leave();

異常處理

本地流監聽

// 每隔3秒獲取本地推流狀況
this.localTimer = setInterval(() => {
    this.client.getLocalVideoStats().then(stats => {
        for (let userId in stats) {
            console.log(new Date(), 'getLocalVideoStats', 'userId: ' + userId +
        'bytesSent: ' + stats[userId].bytesSent + 'local userId' + this.userId);
            if(this.userId == userId && stats[userId].bytesSent == 0) {
                this.onEvent('leave');
            }

            const bytesSentSR = (stats[userId].bytesSent - this.bytesSent) / 3000;

            if(this.userId == userId && bytesSentSR >= 20 && bytesSentSR <= 59) {
                
            }

            if(this.userId == userId) {
                this.bytesSent =  stats[userId].bytesSent;
            }
        }
    });
}, 3000);
  • 可在本地流發佈成功後,註冊本地推流變化函數,處理異常狀況
  • bytesSent: 若是發送單位爲0,則表示本地斷網
  • 公式: 目前發送字節數 - 上一次發送字節數 / 3000

遠端流監聽

this.remoteTimer = setInterval(() => {
    this.client.getRemoteVideoStats().then(stats => {
        for (let userId in stats) {
            console.log('getRemoteVideoStats', 'userId: ' + userId +
        ' bytesReceived: ' + stats[userId].bytesReceived +
        ' packetsReceived: ' + stats[userId].packetsReceived +
        ' packetsLost: ' + stats[userId].packetsLost);
            // const bytesReceived = (stats[userId].bytesReceived - this.bytesReceived) / 3000;
            // let title = '';

            // if(this.agentId == userId && bytesReceived >= 120) {
            //     title = '當前通話,對方網絡良好';
            // }

            // if(this.agentId == userId && bytesReceived >= 60 && bytesReceived <= 119) {
            //     title = '當前通話,對方網絡通常';
            // }

            // if(this.agentId == userId && bytesReceived >= 20 && bytesReceived <= 59) {
            //     title = '當前通話,對方網絡不佳';
            // }

            // if(this.agentId == userId) {
            //     Taro.showToast({
            //         title,
            //         icon: 'none',
            //         duration: 1000
            //     });
            //     this.bytesReceived =  stats[userId].bytesReceived;
            // }
        }
    });
}, 3000);
  • bytesReceived: 若是接受單位爲0,則表示對方斷網
  • 可在遠端流監聽成功以後,註冊遠端流狀態變化函數,處理異常狀況
  • 公式: 目前接收字節數 - 上一次接收字節數 / 3000

目前經過TRTC的事件通知,搭配Socket,能作到對異常處理有較好的支持。github

TRTC兼容性

Android(H5)

  • Android攝像頭不匹配,好比,華爲手機三個後置加一個前置,調用TRTC的獲取攝像頭接口,返回的倒是6個,而且沒有Label標註那個是後置,那個是前置,廠商問題,須要特殊適配。
  • Android上必須使用微信遊覽器打開H5頁面,其餘遊覽器會偶爾崩潰以及其餘問題(猜想微信遊覽器作了適配)。
  • 華爲P30部分機型,存在微信遊覽器環境下沒有默認打開騰訊X5內核,須要進行特殊處理。打開方案:一、能夠在手機設置、應用管理、微信、麥克風和攝像頭權限從新開啓。二、經過掃描X5內核開啓二維碼,引導開啓。不然會發布流失敗,由於X5內核關閉,致使沒有權限獲取。
  • TRTC對大部分機型可以有較好的支持。

iOS(H5)

  • 必須使用Safari遊覽器,其餘遊覽器會出現各類問題。
  • 須要用戶手動觸發播放,這時候須要在video組件上加上autoplay、muted、playsinline、controls(SDK,4.0.0版本如下)
<Video
    id="remoteVideo"
    autoplay
    muted
    playsinline
    controls
/>
  • 切換先後置攝像頭須要根據Label標籤進行區分,獲取先後置攝像頭的deviceId,切換流程以下:算法

    一、獲取攝像頭json

    TRTC.getCameras().then(devices => {
            this.cameras = devices;
        });

    二、選擇攝像頭小程序

    this.localStream.switchDevice('video', deviceId)
        .catch(err => {
            console.log('error', 'switchDevice error:' + err);
        })
        .then((res) => {
            console.log('log', 'switchDevice success' + res);
        });

小程序

  • 小程序的異常機制比較難作,由於沒有成員離開事件通知,目前咱們的解決方案是判斷當前房間人數,咱們房間只會有兩我的。

    TRTC Issue回答微信

  • React技術棧(我只使用了Taro)可以支持視頻播放,但推薦更好的Vue技術棧,由於Vue有官方封裝的組件。
  • 手機兼容性比較好,微信環境加持。

雲端混流

request({
    url: `http://fcgi.video.qcloud.com/common_access?appid=${liveSign.appId}&interface=Mix_StreamV2&t=${liveSign.t}&sign=${liveSign.liveSign}`,
    method: 'POST',
    headers: {
        'content-type': 'application/json',
    },
    body: JSON.stringify(params)
}, (error, response, body) => {
    res.send({errCode: 0});
});

經過http://fcgi.video.qcloud.com/common_access接口,咱們可以完美的監聽房間內發生的狀況,錄製好的視頻,會上傳到騰訊的雲點播平臺,同時也支持客戶自行導出。網絡

相關文章
相關標籤/搜索