iT邦幫忙

2021 iThome 鐵人賽

DAY 9
0
Software Development

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

Day 09 - 應用篇 - 使用者音視訊控制(2)

上一篇我們學會使用getUserMedia方法,來取得使用者音視訊並呈現於網頁,而本篇要介紹傳入getUserMedia方法的約束條件有哪些屬性,並做到更進階的媒體設備控制。

MediaStreamConstraints

約束條件是一個MediaStreamConstraints類型的物件,它擁有audio、video兩種屬性,使用時必須指定一種或兩種屬性,如果瀏覽器無法取得對應屬性的媒體設備,就會出現找不到相關裝置的錯誤,而最簡單的使用方式就是直接對指定的屬性給予true

const constraints = {
    audio: true, 
    video: true
}

取得特定解析度與幀率

除了直接取得對應的媒體設備之外,我們也能對音訊或視訊媒體指定條件,例如:指定特定的解析度與幀率。以下的程式碼會讓瀏覽器盡可能選擇開發者所設定的解析度與幀率,即1280x720與30fps,如果攝影機不支援如此高的解析度與幀率,則會自動選擇適合的值。

const constraints = {
    audio: true,
    video: { width: 1280, height: 720, frameRate: 30 }
}

如果希望影像的解析度可以在指定的範圍,可以給予min、max、idea、exact等屬性。

  • min:解析度最小值,若攝影機不支援則發生錯誤。
  • max:解析度最大值,若攝影機不支援則發生錯誤。
  • idea:解析度理想值,瀏覽器會盡可能取得該數值的解析度,若攝影機不支援則選擇誤差最小的。
  • exact:解析度精確值,瀏覽器必定取得該數值的解析度,若攝影機不支援則發生錯誤。
const constraints = {
  audio: true,
  video: {
    width: { min: 640, ideal: 1280, max: 1920 },
    height: { min: 480, ideal: 720, max: 1080 },
    frameRate: { min: 20, ideal: 24, max: 30 }
  }
}

取得特定硬體裝置

有時候攝影機或麥克風不只一個,我們可能會外接其他的設備,或是在行動裝置上會有前置與後置鏡頭,如果希望取得前或後鏡頭,可以給予facingMode屬性,該屬性有user、environment兩種值。

  • user:前置鏡頭。
  • environment:後置鏡頭。
const constraints = { 
    audio: true, 
    video: { facingMode: "user" }
}

但這樣似乎有點曖昧,如果想要明確的表白就應該直接一點,跟瀏覽器表明想要取得的裝置ID。

const constraints = { 
    audio: true, 
    video: { deviceId: preferredCameraDeviceId } 
}

這時候就有個疑問了,我要怎麼知道裝置的ID?又不是寫在臉上...,別擔心!開發者可以透過MediaDevices的enumerateDevices方法取得所有裝置的ID哦!

navigator.mediaDevices.enumerateDevices()
    .then(devices => {
        console.log(devices);
    })
    .catch(msg => console.log(msg));

使用enumerateDevices方法需要注意兩件事情,(1)必須在取得權限後使用(2)必須使用安全的外網連線,即不可在本地端測試,否則裝置ID會是空字串哦!

執行成功後,會回傳MediaDeviceInfo類型的陣列。

[
    {
        "deviceId": "default",
        "kind": "audioinput",
        "label": "預設 - Microphone Array (Intel® 智慧型音效技術)",
        "groupId": "0b9675d1957038d3b48280ef56bffbb3c4561dc25d011b530c18900eaa5daebb"
    },
    {
        "deviceId": "a097c5d24544be3a0cad7c3efaa2808eb7193d95854d12b1e04ad5b3a36f7891",
        "kind": "audioinput",
        "label": "Microphone Array (Intel® 智慧型音效技術)",
        "groupId": "0b9675d1957038d3b48280ef56bffbb3c4561dc25d011b530c18900eaa5daebb"
    },
    {
        "deviceId": "e40a3f1b1a3f0495e17f007b3c68d737c8f4d6d91c67922b592334094395cefd",
        "kind": "videoinput",
        "label": "HD User Facing (1bcf:2cb0)",
        "groupId": "a2ca4634a1c7993687bbb2b6f975f70fdcbd3002052d03655baca10e9d35a69e"
    },
    {
        "deviceId": "default",
        "kind": "audiooutput",
        "label": "預設 - Speakers (Realtek(R) Audio)",
        "groupId": "6f4713a15d5931983d7d6120a32b622798425ee61d30f5f5eaf656b80c73124d"
    },
    {
        "deviceId": "9577b42ee12be9612ff8c3b9eadb378a6898a76cae1a7676c69cf489009b4942",
        "kind": "audiooutput",
        "label": "Speakers (Realtek(R) Audio)",
        "groupId": "6f4713a15d5931983d7d6120a32b622798425ee61d30f5f5eaf656b80c73124d"
    }
]

專案開發

本節會延續Day8的程式專案,並修改一下index.js檔案的程式碼,來實作進階的條件約束,以取得不同解析度的影像。

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

function getMedia() {
    const constraints = {};
    constraints.audio = true;
    //要求視訊符合1920x1080解析度
    constraints.video = {
        width: { exact: 1920 },
        height: { exact: 1080 }
    };

    navigator.mediaDevices
        .getUserMedia(constraints)
        .then(stream => {
            const video_local = document.getElementById('localVideo');
            video_local.autoplay = true;
            video_local.srcObject = stream;
        })
        .catch(msg => console.log(msg));
}

getMedia();

請大家特別注意自己使用的攝影機可支援的解析度,並在程式碼撰寫符合的數值,通常攝影機上會標明是SD、HD、FHD或480p、720p、1080p等。

執行結果

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

影像解析度比較

把兩種解析度的影像放在一起比較看看,在螢幕前的你能分出480p與1080p嗎?

答案是左邊為480p,右邊為1080p(抱歉,圖太小可能很難看出來,如果你看的出來,我給予你像素眼的稱號)。

條件約束失敗

若攝影機不支援所設定的解析度,程式會執行失敗。我們可以按下鍵盤的F12開啟 DevTools 開發者工具,並選擇 Console 後,看到以下的錯誤訊息。

OverconstrainedError {name: "OverconstrainedError", message: "", constraint: "width"}

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

尚未有邦友留言

立即登入留言