歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~
本篇文章的思維導圖騰訊視訊雲終端技術總監,rexchang(常青), 2008 年畢業加入騰訊,一直從事客戶端研發相關工作,先後參與過 PC QQ、手機QQ、QQ物聯 等產品專案,目前在騰訊視訊雲團隊負責音視訊終端解決方案的優化和落地工作,幫助客戶在可控的研發成本投入之下,獲得業內一流的音視訊解決方案,目前我們的產品線包括:互動直播、點播、短視訊、實時視訊通話,影像處理,AI 等等。
分開做一下介紹
小程式音視訊是什麼?
2017年騰訊視訊雲團隊跟微信團隊聯合,將視訊雲 SDK 跟微信小程式整合在一起,並通過 和 兩個標籤的形式開放內部的功能。通過這兩個標籤,開發者可以實現線上直播、低延時監控、雙人視訊通話以及多人視訊會議等功能。
那麼WebRTC又是什麼?
WebRTC(Web Real-Time Communication),是一個支援網頁瀏覽器進行實時語音對話或視訊對話的技術,是谷歌收購 GIPS 公司而獲得的一項技術,在 Chrome 瀏覽器上無需安裝外掛,通過 javascript 就可以編寫實時音視訊通話程式。
兩者區別在哪裡?
如果您跟我一樣是一個實用主義者,那我就簡單從實用主義角度說一下我的結論:小程式搞定了手機,WebRTC拿下了PC。
如果你對技術比較感興趣,那我們就可以從多個技術的角度去列舉兩者的區別,下面是一張詳細對比的表格:
- 實現原理: 小程式音視訊是將騰訊視訊雲的 liteavsdk 嵌入到微信內部實現的,然後通過 和 兩個標籤將 SDK 內部的音視訊能力開放出來。所以小程式的標籤起到了開發者 API 的作用,而內部的 SDK 則是真正用來實現音視訊功能。
WebRTC 由谷歌收購 GIPS 得來(這裡不得不提一下,我加入騰訊時所在的第一個團隊就是 QQ 團隊,當時 QQ 的音視訊還是購買的 GIPS 公司的產品,不過由於各種不靠譜,後來就轉為自研路線了)。所以其技術被完整的保留並且加入到了 Google 的 Chrome 瀏覽器核心當中。而且最近蘋果也已經開始在 Safari 瀏覽器中支援 WebRTC 的相關能力。
- 底層協議 小程式音視訊的主要協議是目前在直播領域最為常用的 RTMP 推流協議,以及 HTTP-FLV 播放協議,這兩種協議都已經有多年的沉澱而且在網際網路上的資料也是汗牛充棟。
WebRTC的底層則是使用RTP和RTCP兩種資料協議,其中RTP主要用於音視訊資料傳輸,而RTCP則一般用於控制。
- 移動端碎片化問題 小程式音視訊由於是微信統一實現的,而且微信團隊每個版本都儘量要求功能對齊,否則寧可不上,所以在碎片化問題上基本不存在。
WebRTC在這裡則要尷尬的多,一方面Android系統的碎片化本身讓WebRTC的具體表現呈現“百花齊放”的景象,同時,iOS 目前的內嵌WebView(也就是在微信等APP裡開啟的各種內嵌網頁)不支援WebRTC也還是個很麻煩的問題。
- 擴充套件性 小程式音視訊跟隨微信的版本釋出,有什麼問題一般是當前程式碼流修正,然後跟隨下一個版本釋出,所以一般一個功能點(比如給 pusher 加一個美顏的功能)或者一個問題點(比如不支援手勢放大)從確立到最終實現(或解決)僅需要一個月的時間,而且微信APP新版本的覆蓋速度也確實挺快。
相比之下,WebRTC則不是一個團隊或者一家公司的問題了,因為它現在已經走標準路線,所以每一個新特性都是先確定標準,然後再推動瀏覽器廠商(包括蘋果)進行跟隨。這裡面的故事就多了,時間也就更久了。
- 桌面瀏覽器 相信您已經發現,在前面幾個問題的分析上,我的觀點都傾向小程式音視訊。確實,在目前國內的移動領域裡,谷歌和蘋果都不能一家說了算,真正說了算的還是微信。
但是在桌面瀏覽器這個部分,Chrome目前在PC瀏覽器市場上留到地位的存在決定了 WebRTC 的優勢就很大了,開發者可以在不安裝外掛的情況下就可以實現自己想要的功能。
相比之下,由於沒有 Chrome 的原生支援,所以如果我們要在 PC 上對接小程式音視訊,就需要安裝瀏覽器外掛或者通過 wxlite://start 這樣的偽協議喚起本地 exe 應用程式(類似在網頁上開啟 QQ 聊天視窗)。
並非零和博弈
小程式音視訊和WebRTC支架並非零和博藝,雙方都有自己的優勢和不足,所以本著“打不過他們,就加入他們”的思路,騰訊視訊雲團隊在2018年春節回來後,就馬不停蹄地開始了小程式音視訊和WebRTC互通的相關工作。
目前,需要向各位開發者彙報的是,在最新版本的微信中,小程式音視訊已經可以跟WebRTC打通,目前在PC 的Chrome瀏覽器上就可以跟小程式進行實時音視訊互通。
// to-do
當然,如果您想知道這個功能是怎麼實現的,可以繼續看下去:
充分了解WebRTC
就像結婚一樣,既然你決定要選擇另一個人作為人生下半輩子的伴侶,那你肯定會先深入地瞭解一下TA這個人,比如性格,脾氣,愛好等各個方面。
同樣,我們要想很好的將小程式音視訊和WebRTC打通,那也必須要多瞭解一下WebRTC,這裡我就說一下我對 WebRTC 這個“人” 在性格上的一些理解。
首先,她雖然長得不太好看,但很有內涵。
說WebRTC長得不好看,只是我的一種比喻,我的意思是想說WebRTC的學習成本不低,雖然Google做了很多淺顯易懂的PPT來教你怎麼 Getting Start,但真要完整的學進去,還是需要靜下心來,慢慢地把她當成自己認可的目標去學下去。但是如果你是第一次戀愛(也就是第一次接觸實時音視訊),你會發現學習WebRTC的過程,本身就是了解一個實時音視訊技術細節的過程。
其次,她非常喜歡遷就別人,各種架構方案她都能支援到。
說WebRTC喜歡遷就比人,也是一種比喻,WebRTC所支援的後臺架構非常多(比如 Mixer, Mesh,Router),而且谷歌認為這些後臺實現都比較簡單,所以既沒有開放後臺相關的原始碼,也沒有提供統一的後臺解決方案。這種開放式的設計思路非常好,但副作用就是實現成本高。在真刀真槍的專案落地時,小規模的公司或者開發者就很容易被這種技術門檻擋在門外。尤其是想要將 WebRTC 真正應用到企業級解決方案中,面對錄製和存檔的剛性需求,就需要花費大量時間進行定製開發。
方案的確立
瞭解到 WebRTC 的這些特點後,我們的互通方案也就比較清晰了:
首先,小程式音視訊的特點是介面簡單,快速上手,這是小程式的優勢;而這一點恰恰是WebRTC的劣勢,所以我們沒有必要在小程式端為WebRTC暴露十幾個介面類,而是繼續採用小程式音視訊的 和 標籤來解決問題。
其次,WebRTC 的後臺沒有官方實現,那就意味著這裡有很大的發揮空間,騰訊視訊雲就可以實現一套WebRTC後臺並將其同小程式音視訊所使用RTMP後臺進行打通。簡單來說,騰訊視訊雲要在小程式音視訊和WebRTC之間充當紅娘(更確切的說,應該是翻譯員)的角色。
但是看過《新聞聯播》裡國家領導人之間談話鏡頭的人都知道,這種翻譯是會影響交流速度的。小程式音視訊和WebRTC之間互通,中間引入一個翻譯員,是不是通訊延時也就增加了?
其實不會,因為小程式音視訊和WebRTC的視訊編碼標準在常規應用場景中是一致的,都是H.264標準,這是音訊格式不同而已。這就意味著,翻譯員要做的事情很少,兩邊基本都能挺對對方在說什麼,所以延時不會增加太多。
成功的握手
下圖所展示的就是騰訊視訊雲在小程式音視訊和WebRTC互通問題上所採取的方案:
(1)首先,微信端的小程式通過騰訊視訊雲SDK將音視訊流推送到騰訊雲 RTMP 伺服器。
(2)其次,騰訊雲 RTMP 伺服器的會對音視訊資料進行初步的轉化處理,然後透傳給騰訊視訊雲的實時音視訊後臺叢集。
(3)再次,實時音視訊後臺會再次將資料交給一個叫做 WebRTC-Proxy 的模組,就在這裡, WebRTC-Proxy 要將來自小程式音視訊的音視訊資料翻譯成 WebRTC 理解的“語言”。
(4)最後,在PC上的Chrome瀏覽器,就可以通過瀏覽器內建的WebRTC模組跟 WebRTC-Proxy 通訊,進而看到小程式端的視訊影像。
(5)上面的四個過程倒過來,就可以實現雙向視訊通話;而將騰訊視訊雲作為星型結構的中心節點,多個端(不管是小程式還是Chrome瀏覽器)都接入進來,那就可以形成多人音視訊解決方案。
打通房間邏輯
僅僅完成了音視訊資料在小程式和WebRTC之間的握手還遠遠不夠,因為在一次成功的音視訊通話背後,不僅僅是把一端的音視訊資料傳遞到另一端這麼簡單,還有狀態的同步和成員間的狀態協同。
比如多人視訊通話中,涉及到呼叫和接通的流程,其中一方如果結束通話了,其他人要收到結束通話的通知。同時,如果有新的參與者加入,那麼其他人也要收到相應的通知。WebRTC 中有很多元件,比如 RTCPeerConnection 就在處理上訴林林種種的邏輯。但是 WebRTC 的介面中引入的新名詞非常多,對於初學者來說還是有一定的入門門檻,為了簡化這裡的邏輯,我們引入一個叫做“房間”的概念。
所謂房間(Room),就是把同時參與視訊通話的各方圈在一起的一個東西。比如雙人通話中,通話中的兩個人 A 和 B 就可以認為在一個房間中。再比如在多人通話中,通話中的五個人(A B C D E)也可以認為是在一個房間裡。
有了房間的概念,那我們就可以對剛才說的狀態協同用兩個簡單的動作描述一下:如果有一個人加入了視訊通話,那麼就可以理解為他/她已經進房(EnterRoom)了;如果有一個退出了視訊通話,那麼就可以理解為他/她已經離開房間(LeaveRoom)了。而房間的門板上始終寫著:“目前在房間裡有哪幾個人”。
有了房間的概念,我們就可以將小程式的兩個簡單的 和 標籤,同 WebRTC 那一套複雜的 API 進行功能上的對齊,我們甚至不需要修改我們在第一版中定義的介面,就可以達成這個目標:
(1) 的 url 介面不再傳遞 rtmp:// 協議的推流地址,而是傳遞 room:// 協議的推流地址。room:// 協議的使用方式可以參考我們的原理版文件 DOC。
(2) 標籤在 start 成功之後,就相當於成功進入一個 room,之後,您可以通過 onPushEvent (PUSH_EVT_ROOM_USERLIST = 1020) 事件,收到房間裡還有那些人的資訊。在視訊通話期間,房間內各個成員的進進出出,也都會通過這個事件通知給您的小程式程式碼。
(3)ROOM_USERLIST 裡每一項都是一個二元組(如果是 1v1 的視訊通話,ROOM_USERLIST 裡只會有一個人): userid 和 playurl。 userid 代表是哪個使用者, playurl 則是這個使用者遠端畫面的播放地址。您要做的只是使用 標籤播放這些遠端畫面的影像和聲音而已。
(4)在 WebRTC 這一端,您可以參考我們的 webrtc API,這套 API 相對於 WebRTC 原生的 API,更適合初學者使用。
如何快速接入?
如果您希望一天內就打通 webrtc 和 小程式音視訊 的互通,那麼我推薦您不要從零開始,因為那會耗費您太多時間去踩坑和 bugfix,推薦您直接使用我們封裝好的 ,這套方案既可以幫助您完成快速接入,又能滿足一定的定製需求。
另外,不要忘記在微信=>發現=>小程式=>騰訊雲視訊雲,體驗一下騰訊雲官方 Demo 中的 WebRTC 互通效果哦。
標籤說明
標籤是基於 和 實現的用於 WebRTC 互通的自定義元件。如果您希望直接使用 和 標籤完成對接,或者想要了解 的內部原理,可以參考 DOC。
版本要求
- 微信 6.6.6 版本開始支援。
效果演示
- PC 端 用 Chrome 瀏覽器開啟 體驗頁面 可以體驗桌面版 WebRTC 的效果。
- 微信端 發現=>小程式=>搜尋“騰訊視訊雲”,點選 WebRTC 功能卡,就可以體驗跟桌面版 Chrome 互通的效果了。
對接資料
對接資料 | 說明 | 下載連結 |
---|---|---|
小程式原始碼 | 包含的元件原始碼以及demo原始碼 | DOWNLOAD |
PC端原始碼 | 基於WebrtcAPI實現的Chrome版WebRTC接入原始碼(其中 component/WebRTCRoom.js 實現了一個簡單的房間管理功能,component/mainwindow.js包含了對 WebRTC API 的使用程式碼) | webrtc(Chrome).zip |
後臺原始碼 | 實現了一個簡單的房間列表功能,同時包含幾個所需引數的生成程式碼 | webrtc_server_list.zip |
標籤詳解
屬性定義
屬性 | 型別 | 值 | 說明 |
---|---|---|---|
template | String | '1v3' | 必要,標識元件使用的介面模版(使用者如果需要自定義介面,請看 介面定製) |
sdkAppID | String | ‘’ | 必要,開通 IM 服務所獲取到的 AppID |
userID | String | '' | 必要,使用者 ID |
userSig | String | ‘’ | 必要,身份簽名,相當於登入密碼的作用 |
roomID | Number | ‘’ | 必要,房間號 |
privateMapKey | String | ‘’ | 必要,房間許可權 key,相當於進入指定房間 roomID 的鑰匙 |
beauty | Number | 0~5 | 可選,預設 5, 美顏級別 0~5 |
muted | Boolean | true, false | 可選,預設 false,是否靜音 |
debug | Boolean | true, false | 可選,預設 false,是否列印推流 debug 資訊 |
bindRoomEvent | function | 必要,監聽 元件返回的事件 | |
enableIM | Boolean | true, false | 可選,預設false |
bindIMEvent | function | 當IM開啟時必要,監聽 IM 返回的事件 |
操作介面
元件包含如下操作介面,您需要先通過 selectComponent 獲取 標籤的引用,之後就可以進行相應的操作了。
函式名 | 說明 |
---|---|
start() | 啟動 |
pause() | 暫停 |
resume() | 恢復 |
stop() | 停止 |
switchCamera() | 切換攝像頭 |
var webrtcroom = this.selectComponent("#webrtcroomid")
webrtcroom.pause();
複製程式碼
事件通知
標籤通過 onRoomEvent 返回內部事件,通過 onIMEvent 返回 IM 訊息事件,事件引數格式如下
"detail": {
"tag": "事件tag標識,具有唯一性",
"code": "事件程式碼",
"detail": "對應事件的詳細引數"
}
複製程式碼
示例程式碼
// Page.wxml 檔案
<webrtc-room id="webrtcroom"
roomID="{{roomID}}"
userID="{{userID}}"
userSig="{{userSig}}"
sdkAppID="{{sdkAppID}}"
privateMapKey="{{privateMapKey}}"
template="1v3"
beauty="{{beauty}}"
muted="{{muted}}"
debug="{{debug}}"
bindRoomEvent="onRoomEvent"
enableIM="{{enableIM}}"
bindIMEvent="onIMEvent">
</webrtc-room>
// Page.js 檔案
Page({
data: {
//...
roomID: '',
userID: '',
userSig: '',
sdkAppID: '',
beauty: 3,
muted: false,
debug: false,
enableIM: false
},
onRoomEvent: function(e){
switch(e.detail.tag){
case 'error': {
//發生錯誤
var code = e.detail.code;
var detail = e.detail.detail;
break;
}
}
},
onIMEvent: function(e){
switch(e.detail.tag){
case 'big_group_msg_notify':
//收到群組訊息
console.debug( e.detail.detail )
break;
case 'login_event':
//登入事件通知
console.debug( e.detail.detail )
break;
case 'connection_event':
//連線狀態事件
console.debug( e.detail.detail )
break;
case 'join_group_event':
//進群事件通知
console.debug( e.detail.detail )
break;
}
},
onLoad: function (options) {
self.setData({
userID: self.data.userID,
userSig: self.data.userSig,
sdkAppID: self.data.sdkAppID,
roomID: self.data.roomID,
privateMapKey: res.data.privateMapKey
}, function() {
var webrtcroomCom = this.selectComponent('#webrtcroom');
if (webrtcroomCom) {
webrtcroomCom.start();
}
})
},
})
複製程式碼
使用指引
請確認已經參照 Demo部署 開通了相關服務和並正確的完成了配置。
step1: 下載自定義元件原始碼
並非微信小程式原生提供的標籤,而是一個自定義元件,所以您需要額外的程式碼來支援這個標籤。點選 小程式原始碼 下載原始碼包,您可以在 wxlite
資料夾下獲取到所需檔案。
step2: 在工程中引入元件
- 在 page 目錄下的 json 配置檔案內引用元件,這一步是必須的,因為 並非原生標籤。 "usingComponents": { "webrtc-room": "/pages/webrtc-room/webrtc-room" } 在 page 目錄下的 wxml 檔案中使用標籤
step3: 獲取 key 資訊
按照如下表格獲取關鍵的 key 資訊,這是使用騰訊雲互通直播服務所必須的幾個資訊:
KEY | 示例 | 作用 | 獲取方案 |
---|---|---|---|
sdkAppID | 1400087915 | 用於計費和業務區分 | step1 中獲取 |
userID | xiaoming | 使用者名稱 | 可以由您的伺服器指定,或者使用小程式的openid |
userSig | 加密字串 | 相當於 userid 對應的登入密碼 | 由您的伺服器簽發(PHP / JAVA) |
roomID | 12345 | 房間號 | 可以由您的伺服器指定 |
privateMapKey | 加密字串 | 進房票據:相當於是進入 roomid 的鑰匙 | 由您的伺服器簽發(PHP / JAVA) |
下載 sign_src.zip 可以獲得服務端簽發 userSig 和 privateMapKey 的計算程式碼(生成 userSig 和 privateMapKey 的簽名演算法是 ECDSA-SHA256)。
step4: 進入房間
self.setData({
userID: userID,
userSig: userSig,
sdkAppID: sdkAppID,
roomID: roomID,
privateMapKey: privateMapKey
}, function() {
var webrtcroomCom = this.selectComponent('#webrtcroomid');
if (webrtcroomCom) {
webrtcroomCom.start();
}
})
複製程式碼
介面定製
- 建立介面模版
//第一步:新建 /pages/templates/mytemplate 資料夾,並建立 mytemplate.wxml 和 mytemplate.wxss 檔案
//第二步:編寫 mytemplate.wxml 和 mytemplate.wxss 檔案
//mytemplate.wxml
<template name='mytemplate'>
<view class='videoview'>
<view class="pusher-box">
<live-pusher
id="rtcpusher"
autopush
mode="RTC"
url="{{pushURL}}"
aspect="{{aspect}}"
min-bitrate="{{minBitrate}}"
max-bitrate="{{maxBitrate}}"
audio-quality="high"
beauty="{{beauty}}"
muted="{{muted}}"
waiting-image="https://mc.qcloudimg.com/static/img/
daeed8616ac5df256c0591c22a65c4d3/pause_publish.jpg"
background-mute="{{true}}"
debug="{{debug}}"
bindstatechange="onPush"
binderror="onError">
<cover-image class='character' src="/pages/Resources/mask.png"></cover-image>
<cover-view class='character' style='padding: 0 5px;'>我</cover-view>
</live-pusher>
</view>
<view class="player-box" wx:for="{{members}}" wx:key="userID">
<view class='poster'>
<cover-image class='set'
src="https://miniprogram-1252463788.file.myqcloud.com/roomset_{{index + 2}}.png">
</cover-image>
</view>
<live-player
id="{{item.userID}}"
autoplay
mode="RTC"
wx:if="{{item.accelerateURL}}"
object-fit="fillCrop"
min-cache="0.1"
max-cache="0.3"
src="{{item.accelerateURL}}"
debug="{{debug}}"
background-mute="{{true}}"
bindstatechange="onPlay">
<cover-view class='loading' wx:if="{{item.loading}}">
<cover-image src="/pages/Resources/loading_image0.png"></cover-image>
</cover-view>
<cover-image class='character' src="/pages/Resources/mask.png"></cover-image>
<cover-view class='character' style='padding: 0 5px;'>{{item.userName}}</cover-view>
</live-player>
</view>
</view>
</template>
//mytemplate.wxss
.videoview {
background-repeat:no-repeat;
background-size: cover;
width: 100%;
height: 100%;
}
複製程式碼
- webrtc-room 元件引入模版
//為 <webrtc-room> 元件中的 webrtcroom.wxml 檔案新增自定義模版
<import src='/pages/templates/mytemplate/mytemplate.wxml'/>
<view class='conponent-box'>
<view styles="width:100%;height=100%;" wx:if="{{template=='1v3'}}">
<template is='mytemplate' data="{{pushURL, aspect,
minBitrate, maxBitrate, beauty, muted, debug, members}}"/>
</view>
</view>
//為 <webrtc-room> 元件中的 webrtcroom.wxss 檔案新增自定義樣式
@import "../templates/mytemplate/mytemplate.wxss";
複製程式碼
Chrome端對接
瞭解騰訊雲官網的 WebrtcAPI ,可以對接 Chrome 端的 H5 視訊通話,因為不是本文件的重點,此處不做贅述。
實時音視訊產品開通
想要嘗試這些接入,首先要開通騰訊雲實時音視訊,快來接入吧~
問答
相關閱讀
此文已由作者授權騰訊雲+社群釋出,更多原文請點選
搜尋關注公眾號「雲加社群」,第一時間獲取技術乾貨,關注後回覆1024 送你一份技術課程大禮包!
海量技術實踐經驗,盡在雲加社群!