Firebase + WebRTC 程式碼研究室

1. 引言

在本程式碼研究室中,您將瞭解如何使用瀏覽器中的 WebRTC API 和 Cloud Firestore 建立簡易的視訊通訊應用程式。這個應用程式稱為 FirebaseRTC,可做為簡易範例,讓您瞭解如何建構支援 WebRTC 的應用程式。

課程內容

  • 使用 WebRTC 在網頁應用程式啟動視訊通話
  • 使用 Cloud Firestore 向遠端方進行訊號

軟硬體需求

開始進行這個程式碼研究室之前,請確認您已安裝下列項目:

  • 通常與 Node.js 搭配使用的 npm - 建議使用節點 LTS

2. 建立及設定 Firebase 專案

建立 Firebase 專案

  1. 在 Firebase 主控台中,按一下 [Add project] (新增專案),並為 Firebase 專案命名:FirebaseRTC。

記住 Firebase 專案的專案 ID。

  1. 按一下 [建立專案]。

您要建立的應用程式會使用兩種網路上提供的 Firebase 服務:

  • Cloud Firestore 可將結構化資料儲存至雲端,並在資料更新時立即取得通知
  • 使用 Firebase 託管功能來提供及提供靜態素材資源

在這個特定的程式碼研究室中,您已經在要複製的專案中設定 Firebase 託管。但在 Cloud Firestore 中,我們會逐步引導您使用 Firebase 主控台進行設定及啟用服務。

啟用 Cloud Firestore

這個應用程式使用 Cloud Firestore 儲存即時通訊訊息,並接收新的即時通訊訊息。

您必須啟用 Cloud Firestore:

  1. 在 Firebase 主控台選單中,按一下 [資料庫]。
  2. 按一下 Cloud Firestore 窗格中的 [Create database] (建立資料庫)
  3. 選取 [Start in test mode] (以測試模式啟動) 選項,閱讀安全性規則的免責聲明後,按一下 [Enable] (啟用)。

在測試模式下,您可以在開發期間自由寫入資料庫。在程式碼研究室中,我們會進一步確保資料庫的安全性。

3. 取得範例程式碼

從指令列複製 GitHub 存放區:

git clone https://github.com/webrtc/FirebaseRTC

範例程式碼應複製到 FirebaseRTC 目錄中。請確認您的指令列從現在開始執行:

cd FirebaseRTC

匯入啟動應用程式

在編輯器中開啟「FirebaseRTC」中的檔案,並按照以下操作說明進行變更。這個目錄包含程式碼研究室的開始程式碼,該程式碼是由尚未實際運作的 WebRTC 應用程式組成。我們會在這個程式碼研究室中讓程式碼順利運作。

4. 安裝 Firebase 指令列介面

Firebase 指令列介面 (CLI) 可讓您在本機端提供網路應用程式,並將網頁應用程式部署到 Firebase 託管。

  1. 執行下列指令來安裝 CLI:sh npm -g install firebase-tools
  1. 執行下列指令來確認 CLI 已正確安裝:sh firebase --version

請確認 Firebase CLI 版本為 6.7.1 以上版本。

  1. 執行下列指令來授權 Firebase CLI:sh firebase login

您已設定網頁應用程式範本,藉此提取 Firebase 的應用程式設定 從應用程式的本機目錄和檔案提取設定。但若要這麼做, 您必須為應用程式與 Firebase 專案建立關聯

  1. 執行下列指令來連結應用程式與 Firebase 專案: sh firebase use --add

  2. 系統顯示提示時,請選取您的專案 ID,並提供 Firebase 專案的別名。

如果您有多個環境 (實際工作環境、執行環境等),就很適合使用別名。不過,在這個程式碼研究室中,我們只是使用 default 的別名。

  1. 按照指令列中其餘的操作說明進行。

5. 執行本機伺服器

你現在可以開始透過我們的應用程式了!讓我們在本機執行應用程式!

  1. 執行下列 Firebase CLI 指令:sh firebase serve --only hosting

  2. 您的指令列應會顯示下列回應:hosting: Local server: http://localhost:5000

我們使用 Firebase 託管模擬器在本地提供應用程式。網頁應用程式現在應於 http://localhost:5000 提供。

  1. 在 http://localhost:5000 開啟您的應用程式。

您應該會看到已連結到 Firebase 專案的 FirebaseRTC 複本。

應用程式已自動連結至您的 Firebase 專案。

6. 建立新聊天室

在這個應用程式中,每個視訊通訊工作階段都會稱為一個聊天室。使用者可按一下應用程式中的按鈕以建立新房間。這項操作會產生一個遠端方可用,用來加入同一間房間的 ID。此 ID 會用來當做每個房間的 Cloud Firestore 金鑰。

每個房間都會包含優惠和答案的 RTCSessionDescriptions,以及由雙方各自擁有 ICE 候選資料的兩個集合。

第一項工作是導入缺少的程式碼,以便透過呼叫者提供初始優惠來建立新房間。開啟 public/app.js 並找到註解 // Add code for creating a room here,然後加入下列程式碼:

const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);

const roomWithOffer = {
    offer: {
        type: offer.type,
        sdp: offer.sdp
    }
}
const roomRef = await db.collection('rooms').add(roomWithOffer);
const roomId = roomRef.id;
document.querySelector('#currentRoom').innerText = `Current room is ${roomId} - You are the caller!`

第一行會建立 RTCSessionDescription,用來代表呼叫者提供的優惠。這個欄位會設為本機說明,最後寫入 Cloud Firestore 中的新聊天室物件。

接下來,我們會監聽資料庫的變更,並偵測來電者是否已新增答案。

roomRef.onSnapshot(async snapshot -> {
    console.log('Got updated room:', snapshot.data());
    const data = snapshot.data();
    if (!peerConnection.currentRemoteDescription && data.answer) {
        console.log('Set remote description: ', data.answer);
        const answer = new RTCSessionDescription(data.answer)
        await peerConnection.setRemoteDescription(answer);
    }
});

這會等待呼叫者寫入 RTCSessionDescription 的答案,並將該值設為呼叫端 RTCPeerConnection 的遠端說明。

7. 加入聊天室

下一步是實作加入現有聊天室的邏輯。方法是按一下 [加入聊天室] 按鈕,然後輸入要加入的聊天室 ID。這項工作需要實作答案的 RTCSessionDescription,並視情況在資料庫中更新會議室。

const offer = roomSnapshot.data().offer;
await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);

const roomWithAnswer = {
    answer: {
        type: answer.type,
        sdp: answer.sdp
    }
}
await roomRef.update(roomWithAnswer);

在上述程式碼中,我們首先會從呼叫端擷取優惠,並建立設為遠端說明的 RTCSessionDescription。接著,建立答案,將其設為本機說明,然後更新資料庫。資料庫的更新會在呼叫端觸發 onSnapshot 回呼,然後根據呼叫者的答案設定遠端說明。這會完成呼叫者與呼叫者之間的 RTCSessionDescription 物件交換作業。

8. 收集 ICE 候選人

在呼叫端和來電者能夠彼此連線之前,他們也需要交換 ICE 候選項目,讓 WebRTC 知道如何連線至遠端對等端。下一個工作是導入程式碼來監聽 ICE 候選項目,並將其加入資料庫中的集合。尋找 collectIceCandidates 函式並新增下列程式碼:

async function collectIceCandidates(roomRef, peerConnection,
                                    localName, remoteName) {
    const candidatesCollection = roomRef.collection(localName);

    peerConnection.addEventListener('icecandidate', event -> {
        if (event.candidate) {
            const json = event.candidate.toJSON();
            candidatesCollection.add(json);
        }
    });

    roomRef.collection(remoteName).onSnapshot(snapshot -> {
        snapshot.docChanges().forEach(change -> {
            if (change.type === "added") {
                const candidate = new RTCIceCandidate(change.doc.data());
                peerConnection.addIceCandidate(candidate);
            }
        });
    })
}

這個函式可執行兩個動作。此程式會從 WebRTC API 收集 ICE 候選項目並將其新增至資料庫,並監聽來自遠端對等節點的 ICE 候選項目,並將其加入其 RTCPeerConnection 執行個體。監聽資料庫變更時,必須篩除所有未新增的新增項目,因為我們之後也會一次新增同一組 ICE 候選項目。

9. 結語

在這個程式碼研究室中,您已學會如何使用 Cloud Firestore 實作 WebRTC 信號,以及如何利用這項功能建立簡單的視訊通訊應用程式。

詳情請參閱下列資源:

  1. FirebaseRTC 原始碼
  2. WebRTC 範例
  3. Cloud Firestore