保姆級教程!基於聲網 Web SDK實現音視訊通話及螢幕共享

語言: CN / TW / HK

前言

大家好,我是 @小曾同學,小夥伴們也可以叫我小曾~

如果你想實現一對一音視訊通話和螢幕共享功能,不妨來看看這篇文章,保姆級教程,不需要從零實現,直接整合聲網 SDK 即可輕鬆上手。

本文也分享了我在實踐過程中遇到的一些問題,幫助小夥伴們避坑。如果文章知識點有錯誤的地方,還請大家指正,讓我們一起學習,一起進步~


01 背景介紹

聲網提供了各端豐富的音視訊 SDK,本文將要使用的是 Web 端 SDK。

本篇文章主要給小夥伴們分享如何使用聲網 SDK 實現 Web 端音視訊通話及螢幕共享功能,其中也會涵蓋在實踐過程中遇到的一些問題,以此記錄防止小夥伴們踩坑,同時也希望通過從 0 到 1 實戰的分享,能夠幫助更多的小夥伴。

02 前期準備

在實戰之前,需要有以下準備條件:

  • Npm & Node.js
  • 前端開發基礎,如 html & CSS & JavaScript
  • 註冊聲網賬號,申請聲網APPID、臨時Token ,詳見開始使用聲網平臺

如果你還沒有聲網賬號,可以通過這裡免費註冊,每個賬戶每月都有10000分鐘免費額度。如果是個人學習/除錯,時長完全夠用。

我個人的開發環境,具體資訊如下:

  • MacBook Pro
  • Visual Studio Code:v1.75.1
  • Npm:v8.19.3
  • Node.js:v16.19.0
  • 聲網 SDK:v4.2.1 ,sdk的下載可檢視這裡
  • Google Chrome :v110.0.5481.177

03 實戰環節

通過[前期準備],我們已經完成了相關配置,已經擁有了 App ID、Channel、臨時 Token、聲網 SDK,在本次實戰中,主要詳細講解兩個 demo,分別是音視訊通話及螢幕共享連麥。

3.1 實現音視訊通話

在開始實戰之前,先宣告下 Demo 組成架構,

建立一個資料夾名為 Agora_VideoCall,資料夾中包含五個檔案,分別是:

  • index.html:用於設計 Web 應用的使用者介面
  • index.css:用於設計網頁樣式
  • basicVideoCall.js:實現音視訊通話邏輯程式碼,主要通過 AgoraRTCClient 實現
  • AgoraRTC_N-4.2.1.js:聲網音視訊SDK
  • assets:第三方庫,主要用於設計使用者介面

在 index.html 檔案中匯入聲網SDK,具體內容可檢視詳細程式碼,接下來主要詳細講解音視訊通話及螢幕共享實現邏輯。

<script src="./AgoraRTC-N-4.2.1.js"></script>

3.1.1 實現音視訊通話邏輯

以下程式碼均在 basicVideoCall.js 文字中寫入

1)首先呼叫 AgoraRTC.createClient 方法建立一個 client 物件,也就是建立客戶端物件

var client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });

2)定義變數 App ID,Token、Channel、User ID,並使用箭頭函式實現當頁面被呼叫時用於加入音視訊通話通道。

var options = {
  appid: null,
  channel: null,
  uid: null,
  token: null
};

$(() => {
  var urlParams = new URL(location.href).searchParams;
  options.appid = urlParams.get("appid");
  options.channel = urlParams.get("channel");
  options.token = urlParams.get("token");
  options.uid = urlParams.get("uid");
  if (options.appid && options.channel) {
    $("#uid").val(options.uid);
    $("#appid").val(options.appid);
    $("#token").val(options.token);
    $("#channel").val(options.channel);
    $("#join-form").submit();
  }
})

3)加入頻道

定義 join 函式主要是將本地音視訊 track 加入一個 RTC 頻道,此時需要在函式中傳入 App ID,Token、Channel、User ID。加入房間後,需要釋出音視訊track,所以還需要建立音視訊 track,並呼叫 publish 方法將這些本地音視訊track物件當作引數釋出到頻道中。

注意注意,在建立音視訊 track 時需要先呼叫 createMicrophoneAudioTrack :通過麥克風採集的音訊建立本地音訊軌道物件;再呼叫 createCameraVideoTrack :通過攝像頭採集的視訊建立本地視訊軌道物件。(如果先呼叫createCameraVideoTrack ,那麼頁面中將不會顯示本地視訊預覽畫面)

建立之後即可呼叫 play 方法展示本地預覽,並呼叫 publish 方法釋出到 RTC 頻道中。注意 play 和 publish 方法的使用沒有先後順序,誰在前在後沒有什麼影響。

async function join() {
  
  [ options.uid, localTracks.audioTrack, localTracks.videoTrack ] = await Promise.all([
    // 加入頻道
    client.join(options.appid, options.channel, options.token || null, options.uid || null),
    // 建立本地音視訊track
    //AgoraRTC.createCameraVideoTrack(),
    AgoraRTC.createMicrophoneAudioTrack(),
    AgoraRTC.createCameraVideoTrack()
  ]);

  localTracks.videoTrack.play("local-player");
  $("#local-player-name").text(`localVideo(${options.uid})`);

  await client.publish(Object.values(localTracks));
  console.log("publish success");
}

4)在頻道中新增或移除遠端使用者邏輯

實現將同頻道的遠端使用者新增到本地介面,當遠端使用者取消釋出時,則從本地將使用者移除。

function handleUserPublished(user, mediaType) {
  const id = user.uid;
  remoteUsers[id] = user;
  subscribe(user, mediaType);
}

function handleUserUnpublished(user, mediaType) {
  if (mediaType === 'video') {
    const id = user.uid;
    delete remoteUsers[id];
    $(`#player-wrapper-${id}`).remove();

  }
}

5)訂閱遠端音視訊邏輯

當遠端使用者釋出音視訊時,本地使用者需要對其訂閱,從而實現音視訊通話,在 subscribe 函式中需要傳入兩個引數,分別是同頻道遠端使用者 user id 和遠端 mediaType,並呼叫 play 方法,播放遠端使用者音視訊,從而實現一對一連麥。

async function subscribe(user, mediaType) {
  const uid = user.uid;
  // 訂閱遠端使用者
  await client.subscribe(user, mediaType);
  console.log("subscribe success");
  if (mediaType === 'video') {
    const player = $(`
      <div id="player-wrapper-${uid}">
        <p class="player-name">remoteUser(${uid})</p>
        <div id="player-${uid}" class="player"></div>
      </div>
    `);
    $("#remote-playerlist").append(player);
    user.videoTrack.play(`player-${uid}`);
  }
  if (mediaType === 'audio') {
    user.audioTrack.play();
  }
}

6)監聽事件

當遠端使用者釋出或者取消釋出音視訊 track 時,本地還需要對其監聽,在 join 函式中,監聽 client.on("user-published", handleUserPublished) 事件和 client.on("user-unpublished", handleUserUnpublished) 事件,具體如下

client.on("user-published", handleUserPublished);
client.on("user-unpublished", handleUserUnpublished);

7)離開頻道

當用戶點選 leave 按鈕時,則將 stop 本地和遠端音視訊 track。

async function leave() {
  for (trackName in localTracks) {
    var track = localTracks[trackName];
    if(track) {
      track.stop();
      track.close();
      localTracks[trackName] = undefined;
    }
  }

3.1.2 Demo展示

接下來可以執行我們的 Demo 啦,輸入 APPID、Token、Channel、Userid,點選 join,即可看到自己本地的畫面,如果想和別人連麥,可以再複製一下網址,輸入相同的 APPID、Token、Channel,即可實現連麥,趕快試試吧。

3.2 螢幕共享連麥

螢幕共享就是將本地使用者的螢幕內容,以視訊畫面的方式分享給其他遠端使用者觀看。其工作原理實際上是通過 createScreenVideoTrack 建立一個螢幕共享的視訊軌道物件來實現。採集螢幕的過程中瀏覽器會詢問需要共享哪些螢幕,根據終端使用者的選擇去獲取螢幕資訊。

在上述音視訊 demo 的基礎上實現螢幕共享功能。

3.2.1 新增螢幕共享UI

在 index.html 頁面中新增螢幕共享(ScreenShare)button

3.2.2 螢幕共享實現邏輯

以下程式碼均在 basicVideoCall.js 文字中寫入

1)實現 share 函式

和上述 join 函式功能類似,主要用於開啟螢幕共享,使用 createScreenVideoTrack 建立螢幕共享的視訊軌道物件,同時也可以對視訊編碼進行一些簡單的配置。函式中同樣也需要新增監聽事件。

async function share() {

  client.on("user-published", handleUserPublished);
  client.on("user-unpublished", handleUserUnpublished);
  let screenTrack;

      [options.uid, localTracks.audioTrack, screenTrack] = await Promise.all([
    
    client.join(options.appid, options.channel, options.token || null, options.uid || null),
    AgoraRTC.createMicrophoneAudioTrack(),
    AgoraRTC.createScreenVideoTrack({
      encoderConfig: {
        framerate: 15,
        height: 720,
        width: 1280
      }
    }, "auto")
  ]);

2)新增螢幕共享音視訊軌道,並呼叫 play 方法播放本地螢幕共享的視訊。

if(screenTrack instanceof Array){
    localTracks.screenVideoTrack = screenTrack[0]
    localTracks.screenAudioTrack = screenTrack[1]
  }
  else{
    localTracks.screenVideoTrack = screenTrack
  }

  localTracks.screenVideoTrack.play("local-player");
  $("#local-player-name").text(`localVideo(${options.uid})`);

3)釋出螢幕共享

釋出本地音訊和螢幕共享畫面至 RTC 頻道中。

if(localTracks.screenAudioTrack == null){
    await client.publish([localTracks.screenVideoTrack, localTracks.audioTrack]);
  }
  else{
    await client.publish([localTracks.screenVideoTrack, localTracks.audioTrack, localTracks.screenAudioTrack]);
  }

4)在 share 函式實現邏輯中需要繫結 "track-ended" 事件,當螢幕共享停止時,會有一個警報通知終端使用者。

localTracks.screenVideoTrack.on("track-ended", () => {
    alert(`Screen-share track ended, stop sharing screen ` + localTracks.screenVideoTrack.getTrackId());
    localTracks.screenVideoTrack && localTracks.screenVideoTrack.close();
    localTracks.screenAudioTrack && localTracks.screenAudioTrack.close();
    localTracks.audioTrack && localTracks.audioTrack.close();
  });

3.2.3 Demo 展示

當點選 ScreenShare 時,會提示使用者選擇哪一個 page 進行分享,同時也有一個預設音訊選項,點選分享之後,即可釋出螢幕共享。

04 小結

如果你想實現音視訊和螢幕共享的 Web 應用,完全可以借鑑本篇文章 + 聲網SDK,如果不是很熟悉的話,可以先看聲網給出的「快速開始 - 實現音視訊通話」。

在實踐過程中需要注意的是:在建立音視訊 track 時需要先呼叫 createMicrophoneAudioTrack ,再呼叫 createCameraVideoTrack ,如果先呼叫 createCameraVideoTrack 那麼頁面中將不會顯示本地視訊預覽畫面。

Generally,本篇文章給出的 demo 比較簡單,如果想要新增其他的功能比如,虛擬背景、AI降噪等,可以在此基礎上繼續新增功能。

(正文完)


參考資料

註冊聲網賬號

相關 SDK 下載

快速開始 - 實現音視訊通話