保姆級教程!基於聲網 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 下載

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