引言
隨著社會(huì)的發(fā)展呕童,人們對(duì)實(shí)時(shí)音視頻的需求越來(lái)越多崔赌。在線會(huì)議意蛀,電商直播,在線教育等相關(guān)產(chǎn)品不斷涌現(xiàn)健芭。但是對(duì)于個(gè)人開(kāi)發(fā)者或者小團(tuán)隊(duì)來(lái)說(shuō)县钥,自己實(shí)現(xiàn)一個(gè)實(shí)時(shí)音視頻服務(wù)并且要保障服務(wù)穩(wěn)定,滿足低延時(shí)等要求慈迈,難度非常大魁蒜。為此我們需要尋找一個(gè)合適的解決方案。功能強(qiáng)大且可靠的聲網(wǎng)Agora就成為了極佳的選擇吩翻。
今年聲網(wǎng)推出了下一代 Agora Web SDK (Agora Web SDK NG)兜看,基于 TypeScript 開(kāi)發(fā),使用 Promise 來(lái)管理異步操作狭瞎,靈活易用细移。今天我就來(lái)分享一下如何快速接入該SDK并實(shí)現(xiàn)一些簡(jiǎn)單的實(shí)時(shí)音視頻通話。
前期準(zhǔn)備
首先我們需要注冊(cè)一個(gè)聲網(wǎng)賬號(hào)(注冊(cè)地址)熊锭,注冊(cè)成功后會(huì)進(jìn)入控制臺(tái)弧轧,完成實(shí)名認(rèn)證雪侥,在左側(cè)進(jìn)入項(xiàng)目管理頁(yè)面,開(kāi)始創(chuàng)建項(xiàng)目:
輸入項(xiàng)目名稱精绎,選擇鑒權(quán)機(jī)制速缨。為了項(xiàng)目安全性考慮,這里推薦使用安全模式代乃。提交后進(jìn)入項(xiàng)目信息頁(yè)面旬牲,記錄一下AppID和證書我們之后在代碼中會(huì)用到。由于我們選擇了安全模式搁吓,在使用SDK時(shí)我們需要生成token原茅,在本地開(kāi)發(fā)調(diào)試時(shí)可以在項(xiàng)目信息頁(yè)面下方點(diǎn)擊生成臨時(shí)token,然后拷貝到代碼中使用堕仔。
在項(xiàng)目發(fā)布時(shí)擂橘,可以參考文檔和官方倉(cāng)庫(kù)編寫對(duì)應(yīng)的token生成代碼,部署到自己的服務(wù)器上通過(guò)調(diào)用接口的形式來(lái)獲取token摩骨。
新建項(xiàng)目并集成SDK
前期準(zhǔn)備工作已經(jīng)完成通贞,大家根據(jù)自己的實(shí)際情況來(lái)新建一個(gè)web項(xiàng)目,完成后恼五,我們開(kāi)始通過(guò)npm安裝SDK昌罩。
npm install agora-rtc-sdk-ng --save
你也可以通過(guò)script標(biāo)簽的形式引入SDK。
<script src="https://download.agora.io/sdk/web/AgoraRTC_N-4.1.0.js"></script>
<!-- or -->
<script src="./AgoraRTC_N-4.1.0.js"></script>
之后我們只需要在項(xiàng)目代碼中引入agora-rtc-sdk-ng就可以直接使用了唤冈。
import AgoraRTC from "agora-rtc-sdk-ng";
實(shí)現(xiàn)基礎(chǔ)的1對(duì)1視頻通話
現(xiàn)在我們開(kāi)始來(lái)按步驟實(shí)現(xiàn)基礎(chǔ)的1對(duì)1視頻通話。
1. 創(chuàng)建本地客戶端對(duì)象
首先我們需要?jiǎng)?chuàng)建一個(gè)本地客戶端對(duì)象银伟,由于我們不是直播你虹,mode我們選擇rtc,編碼有H.264和VP8兩種彤避,我這里沒(méi)有兼容性要求傅物,所以選用推薦的VP8,參考官方文檔琉预。
const rtcClient = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
2. 加入頻道
加入頻道這里需要傳入4個(gè)參數(shù):聲網(wǎng)的項(xiàng)目appid董饰,頻道名稱,如果鑒權(quán)開(kāi)啟了安全模式需要傳入token圆米,最后傳入uid卒暂,uid為null時(shí)SDK會(huì)自動(dòng)生成一個(gè)uid返回給你。
如果你是用app證書通過(guò)自己的代碼生成token娄帖,需要保證頻道名稱和uid與生成token時(shí)保持一致也祠,否則加入頻道會(huì)失敗。
const uid = await rtcClient.join(<appid>, <channel name>, <token>, <uid>);
3. 創(chuàng)建本地音視頻軌道
加入完頻道我們開(kāi)始創(chuàng)建本地音視頻軌道近速,調(diào)用createMicrophoneAudioTrack()通過(guò)本地麥克風(fēng)采集的音頻創(chuàng)建音頻軌道對(duì)象诈嘿,調(diào)用
createCameraVideoTrack()通過(guò)本地?cái)z像頭采集的視頻創(chuàng)建視頻軌道對(duì)象堪旧。你也可以在調(diào)用時(shí)傳入?yún)?shù)來(lái)調(diào)整編碼、前置\后置攝像頭等配置奖亚。同時(shí)這里還需要注意瀏覽器提示或相關(guān)的設(shè)置淳梦,允許瀏覽器訪問(wèn)攝像頭、麥克風(fēng)等設(shè)備昔字,必要時(shí)對(duì)用戶進(jìn)行引導(dǎo)和提示爆袍。
const localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
const localVideoTrack = await AgoraRTC.createCameraVideoTrack();
4. 播放本地音視頻軌道
創(chuàng)建完本地音視頻軌道對(duì)象后,我們可以調(diào)用play()進(jìn)行播放李滴,預(yù)覽一下音頻和視頻螃宙。播放音頻軌道時(shí)不需要傳入任何參數(shù),播放視頻軌道時(shí)需要指定一個(gè)DOM元素所坯,你可以傳入一個(gè)元素對(duì)象谆扎,也可以傳入元素的id值。之后SDK會(huì)自動(dòng)在該元素內(nèi)部生成一個(gè)video元素播放視頻軌道芹助。
<div id="video-container"></div>
// 播放視頻軌道
localVideoTrack.play(document.getElementById('video-container'));
// or
localVideoTrack.play('video-container');
// 播放音頻軌道
localAudioTrack.play();
效果如圖:
5. 發(fā)布本地音視頻軌道
現(xiàn)在我們需要調(diào)用publish()將我們本地的音視頻軌道發(fā)布到頻道中堂湖,一個(gè)本地客戶端對(duì)象可以發(fā)布多個(gè)音頻軌道,比如:背景音樂(lè)状土、麥克風(fēng)聲音等无蜂,SDK會(huì)自動(dòng)將其合并為一個(gè)音頻軌道發(fā)布到頻道中去,但是一個(gè)本地客戶端對(duì)象只能發(fā)布一個(gè)視頻軌道蒙谓,如果有發(fā)布多個(gè)視頻軌道的需求斥季,你可以創(chuàng)建多個(gè)本地客戶端對(duì)象加入同一個(gè)頻道,然后發(fā)布不同的視頻軌道累驮,但是需要注意區(qū)分2個(gè)client使用的uid酣倾,并在本地訂閱時(shí)過(guò)濾掉,防止重復(fù)訂閱谤专,參考文檔躁锡。
await rtcClient.publish([
localAudioTrack,
localVideoTrack
]);
6. 訂閱遠(yuǎn)端用戶并播放遠(yuǎn)端音視頻
現(xiàn)在我們需要監(jiān)聽(tīng)user-published事件,當(dāng)同一頻道的其他用戶調(diào)用publish()發(fā)布音視頻軌道時(shí)置侍,SDK會(huì)觸發(fā)該事件映之,我們需要監(jiān)聽(tīng)這個(gè)事件并在回調(diào)中訂閱其他用戶發(fā)布的音視頻軌道,并調(diào)用play()進(jìn)行播放
<div id="remote-user"></div>
rtcClient.on("user-published", async (user, mediaType) => {
await rtcClient.subscribe(user, mediaType);
if (mediaType === "video") {
console.log("subscribe video success", user);
user.videoTrack.play(document.getElementById('remote-user'));
}
if (mediaType === "audio") {
console.log("subscribe audio success");
user.audioTrack.play();
}
});
效果如下圖蜡坊,上方是我們本地的攝像頭畫面杠输,下方為遠(yuǎn)端的攝像頭畫面,到這里為止一個(gè)基礎(chǔ)的1對(duì)1視頻通話已經(jīng)完成了秕衙!
通話質(zhì)量監(jiān)測(cè)
對(duì)于實(shí)時(shí)音視頻來(lái)說(shuō)抬伺,保障通話質(zhì)量是很重要的一環(huán),在SDK中提供了相關(guān)的api供我們查詢當(dāng)前的通話質(zhì)量灾梦,文檔峡钓,通過(guò)使用這些api妓笙,客戶端可以及時(shí)采取措施,給予用戶及時(shí)的提示和反饋能岩。避免影響用戶的使用體驗(yàn)创南。
聲網(wǎng)控制臺(tái)還有水晶球面板递沪,里面提供了豐富的通話質(zhì)量數(shù)據(jù)查詢功能,開(kāi)發(fā)者可以使用這個(gè)工具更全面的掌握通話質(zhì)量狀況。
小拓展
多個(gè)音頻軌道
上文中有提到忆谓,一個(gè)客戶端對(duì)象可以發(fā)布多個(gè)音頻軌道舰始,沒(méi)有先后順序闸衫,可以多次通過(guò)調(diào)用publish()進(jìn)行發(fā)布屹蚊,SDK會(huì)自動(dòng)合并為一個(gè)音頻軌道發(fā)布到頻道中。下面我們就通過(guò)自定義音頻采集以及MediaStreamTrack API往通話中播放一個(gè)本地音頻文件作為背景音樂(lè)坝辫。
1. 創(chuàng)建HTMLAudioElement
我們?cè)谇懊婊A(chǔ)音視頻通話代碼的基礎(chǔ)上進(jìn)行修改篷就,首先創(chuàng)建一個(gè)button確保用戶,讓用戶點(diǎn)擊后再播放音頻文件近忙,確保用戶與頁(yè)面有一個(gè)交互行為竭业。并監(jiān)聽(tīng)對(duì)應(yīng)的點(diǎn)擊事件。
<button id="addMusic">添加音樂(lè)</button>
document.getElementById("addMusic").addEventListener("click", () => {
const audio = new Audio("./music.ogg");
audio.play();
});
2. 獲取音頻軌道并發(fā)布
調(diào)用captureStream()獲取MediaStream對(duì)象及舍,監(jiān)聽(tīng)addtrack事件未辆,觸發(fā)時(shí)調(diào)用getAudioTracks()獲取MediaStreamTrack對(duì)象的集合,由于我的音頻文件只有一個(gè)音軌锯玛,所以這里直接取第1個(gè)元素咐柜。使用createCustomAudioTrack()將獲取到的MediaStreamTrack轉(zhuǎn)換為一個(gè)可以用于SDK的音頻軌道,最后使用客戶端對(duì)象的publish()發(fā)布攘残。結(jié)合之前的音視頻通話拙友,此時(shí)在遠(yuǎn)端已經(jīng)能正常收聽(tīng)到2個(gè)音軌的聲音了(麥克風(fēng)和音樂(lè)文件)。
document.getElementById("addMusic").addEventListener("click", () => {
const audio = new Audio("./music.ogg");
audio.play();
const musicStream = audio.captureStream();
const musicStream.onaddtrack = async () => {
const musicMediaStreamTrack = musicStream.getAudioTracks()[0];
const musicCustomAudioTrack = AgoraRTC.createCustomAudioTrack({
mediaStreamTrack: musicMediaStreamTrack
});
await rtClient.publish([musicCustomAudioTrack])
};
});
自定義視頻采集
和音頻一樣肯腕,SDK也支持你使用自定義的視頻軌道來(lái)實(shí)現(xiàn)如屏幕錄制献宫,播放本地視頻文件等功能钥平。屏幕錄制在官方文檔中有介紹实撒,這里我分享一下如何獲取并發(fā)布一個(gè)本地視頻文件的視頻軌道。
一個(gè)客戶端對(duì)象只支持發(fā)布一個(gè)視頻軌道涉瘾,同時(shí)發(fā)布多個(gè)(比如錄屏+攝像頭畫面)需要?jiǎng)?chuàng)建2個(gè)客戶端對(duì)象分別進(jìn)行發(fā)布知态。
1. 創(chuàng)建video元素
首先我們創(chuàng)建一個(gè)video元素用于播放視頻文件,并獲取到HTMLVideoElement對(duì)象立叛。
<video id="videoFile" src="./video.mp4" control>
const video = document.getElementById('video');
2. 獲取并發(fā)布視頻文件的媒體流
這一步和獲取音頻文件媒體流類似负敏,我們分別發(fā)布了視頻和音頻軌道后的效果如圖。畫面上方的A端播放的視頻文件秘蛇,畫面下方是B端的攝像頭畫面
視頻文件包含視頻軌道和音頻軌道其做,我們需要分別獲取對(duì)應(yīng)的軌道進(jìn)行發(fā)布顶考,如果只發(fā)布了視頻軌道會(huì)導(dǎo)致遠(yuǎn)端沒(méi)有視頻聲音
const stream = video.captureStream();
stream.onaddtrack = async () => {
const videoMediaStreamTrack = stream.getVideoTracks()[0];
const audioMediaStreamTrack = stream.getAudioTracks()[0];
const videoTrack = AgoraRTC.createCustomVideoTrack({
mediaStreamTrack: videoMediaStreamTrack
});
const audioTrack = AgoraRTC.createCustomAudioTrack({
mediaStreamTrack: audioMediaStreamTrack
});
await this.rtc.client!.publish([videoTrack,audioTrack]);
};
結(jié)尾
聲網(wǎng)的Agora Web SDK NG 版接入是十分便捷的,簡(jiǎn)單易上手妖泄,功能強(qiáng)大驹沿,文檔清晰。SDK也在github上開(kāi)源蹈胡。每個(gè)月還有10000分鐘的免費(fèi)額度渊季,他們也會(huì)不定期舉辦一些套餐包優(yōu)惠活動(dòng)。通話質(zhì)量也有可靠的保障罚渐。對(duì)于個(gè)人或小團(tuán)隊(duì)來(lái)說(shuō)實(shí)現(xiàn)音視頻通話不再是很困難的一件事了却汉。總結(jié)一下就是:真香荷并。如果你和你的團(tuán)隊(duì)有這方面的需求合砂,不妨也來(lái)試試使用聲網(wǎng)。
「本文為個(gè)人原創(chuàng)璧坟,首發(fā)于聲網(wǎng)開(kāi)發(fā)者社區(qū)」