iT邦幫忙

2021 iThome 鐵人賽

DAY 8
2
Software Development

新手也能打造網路電話系統-WebRTC入門與活用系列 第 8

Day 08 - 應用篇 - 使用者音視訊控制(1)

本篇要來實作如何取得使用者音視訊,因為這是進行通話的必要事項,若沒有音訊也沒有視訊,那就不會有聲音也不會有畫面。

取得使用者音視訊

透過MediaDevices的getUserMedia方法可取得使用者的媒體流,getUserMedia內需要傳入MediaStreamConstraints類型的物件,該物件是一種約束條件,即約束使用者的設備應回傳符合條件的媒體流。

//建立約束條件
const constraints = {};
constraints.audio = true; //要求音訊
constraints.video = true; //要求視訊

//向使用者取得媒體設備的權限
navigator.mediaDevices
    .getUserMedia(constraints)
    .then(stream => {
        stream; //符合約束條件的媒體流
    })
    .catch(msg => console.log(msg));

播放使用者音視訊

我們可將取得的媒體流交由網頁中的video元件來播放。

const video_local = document.getElementById('localVideo'); //取得網頁中的元件
video_local.autoplay = true; //當video元件被指定媒體流時,便會自動開始播放
video_local.srcObject = stream; //將媒體流指定給video元件

開發工具與專案架構

我會以Web的形式教學,並著重於本系列文章的主題,因此硬體設備、開發工具的安裝與程式語法不會特別著墨,今後的文章會以相同的硬體設備、開發工具進行教學。

硬體設備

以下設備擇一即可。

  • 內建攝影機與麥克風的筆電
  • 桌機搭配網路攝影機與網路麥克風

開發工具

本文章採用的開發工具如下,讀者可以選擇自己擅長的工具,若是Web初學者或未接觸過程式設計的人,可以選擇本文的開發工具。

  • 開發環境:VSCode
  • 瀏覽器:Chrome
  • 網頁程式:HTML、CSS、JavaScript

專案架構

本文章專案架構如下,大家可以建立一個資料夾並新增以下的檔案。

專案開發

介面設計

首先,開啟index.html檔案,並撰寫以下程式碼。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport"
        content="width=device-width, initial-scale=1, user-scalable=0, minimum-scale=1, maximum-scale=1">
    <title>Day8</title>
    <!-- 匯入CSS檔案 -->
    <link rel="stylesheet" type="text/css" href="main.css">
</head>

<body>
    <!-- 建立div區塊,內部包含一個video元件 -->
    <div id="videos">
        <video id="localVideo"></video>
    </div>
    <!-- 匯入JavaScript程式碼 -->
    <script src="index.js"></script>
</body>

</html>

接著,開啟main.css檔案,並撰寫以下程式碼。

/* 調整元件id為localVideo的高度與寬度 */
#localVideo {
    height: 100%;
    width: 100%;
}

程式設計

接著,開啟index.js檔案,並撰寫以下程式碼。

//Step1:定義用於取得媒體資料流的方法
function getMedia() {
    //Step2:宣告媒體設備約束條件的變數
    const constraints = {};
    constraints.audio = true; //要求音訊
    constraints.video = true; //要求視訊

    //Step3:向使用者取得媒體設備的權限
    navigator.mediaDevices
        .getUserMedia(constraints)
        .then(stream => {
            //Step4:將媒體資料流指派給video元件,並使其播放媒體
            const video_local = document.getElementById('localVideo');
            video_local.autoplay = true;
            video_local.srcObject = stream;
        })
        .catch(msg => console.log(msg));
}

//Step5:執行getMedia方法
getMedia();
  • Step1:先建立一個方法,其內部功能為向使用者要求權限,並呈現媒體資料於使用者介面。
  • Step2:宣告一個物件變數,其內部為媒體設備的約束條件,這裡我們要求取得audio、video的媒體資料,而約束條件的詳細參數會於下一篇文章進行說明。
  • Step3:使用getUserMedia方法並傳入Step2的變數,以取得使用者媒體設備的資料。執行後會顯示權限請求的視窗,讓使用者選擇是否允許權限,若使用者允許權限,則回傳Promise物件,我們可以使用then方法來取得媒體資料流,若使用者不允許權限,則拋出例外,這邊我們先用console log把它顯示出來。
  • Step4:將媒體資料流指派給video元件並播放它,此時就可以看到影像與聽到聲音囉!
  • Step5:執行getMedia方法,以查看上述的程式結果。

執行結果

程式碼撰寫完成後,我們可以用Chrome開啟index.html檔案。以下將各種情況的執行結果列出來,大家可以看看自己是不是也做到了!

向使用者請求權限

向使用者請求權限後,瀏覽器會顯示是否允許的視窗。

允許權限後

允許權限後,即可看到攝影機的畫面與聽到周遭的聲音。

不允許權限

若不允許權限,程式會執行失敗。我們可以按下鍵盤的F12開啟 DevTools 開發者工具,並選擇 Console 後,看到以下的錯誤訊息。

DOMException: Permission denied

無相關硬體設備

若沒有攝影機或麥克風等相關硬體設備,程式會執行失敗。可以按下鍵盤的F12開啟 DevTools 開發者工具,並選擇 Console 後,看到以下的錯誤訊息。

DOMException: Requested device not found

額外練習

本節會介紹將上述程式碼優化的方法,並不會影響本系列文章的學習,有興趣的讀者可以閱讀。

Async、Await

由於getUserMedia方法會回傳Promise物件,所以我們可以用 ES7 的 Async、Await 讓程式碼變得更好閱讀,以避免 Callback Hell。

index.jsgetMedia方法改寫後的結果如下:

async function getMedia() {
    const constraints = {};
    constraints.audio = true;
    constraints.video = true;

    const stream = await navigator.mediaDevices
        .getUserMedia(constraints)
        .catch(msg => {
            console.log(msg);
            return;
        });

    const video_local = document.querySelector('#localVideo');
    video_local.autoplay = true;
    video_local.srcObject = stream;
}

Video play event

如果想監聽視訊開始播放的時機,可以加入onplay的event。

video_local.onplay = () => {
    console.log('視訊開始播放');
};

靜音功能

如果不希望聽到自己的聲音,可以加上muted,以達到靜音的效果。

video_local.muted = true;

HTML屬性

如果希望一開始就是自動播放與靜音,可以直接在index.html的video元件加上autoplay、muted屬性,這樣就不用在index.js撰寫相關程式碼。

<video id="localVideo" autoplay muted></video>

上一篇
Day 07 - 觀念篇 - WebRTC API
下一篇
Day 09 - 應用篇 - 使用者音視訊控制(2)
系列文
新手也能打造網路電話系統-WebRTC入門與活用30

尚未有邦友留言

立即登入留言