JavaScript 使用 mediaDevices API 選擇網路攝影機

來源:互聯網
上載者:User

標籤:img   做了   開啟   一個   hone   ntb   connect   nod   checkout   

大多數智能手機都有前置和後置網路攝影機,當你在建立視頻應用時你可能想要選擇或者切換前置、後置網路攝影機。

如果你開發的是一款聊天應用,你很可能會想調用自拍,但如果你開發的是一款拍照軟體,那麼你會更傾向於使用後置網路攝影機。在這篇文章中我們將探討如何通過 mediaDevices API 和 media constraints (媒體約束) 選擇或者切換網路攝影機。

準備工作

要跟著本文一起動手實踐你需要:

  • 一款擁有兩個可供測試的網路攝影機的 iOS 或 Android 裝置,如果你的電腦有兩個網路攝影機那也可以

  • ngrok 以便你能通過行動裝置輕鬆訪問到你的項目(也因為我覺得 ngrok 炒雞棒)

  • 這個 GitHub 庫 的代碼讓你起步

要擷取代碼,先把這個項目 clone 下來然後 checkout 到 initial-project tag 下。

git clone https://github.com/philnash/mediadevices-camera-selection.git -b initial-project

cd mediadevices-camera-selection

這個起步項目已經為你準備好了一些 HTML 和 CSS,所以我們就可以把注意集中到 JavaScript 上了。你可以直接開啟 index.html,但我建議你用一款 webserver 把這些檔案託管起來。我喜歡用 npm 的 serve 模組。我在這個庫裡已經引入了 serve,要使用它你需要先用 npm 安裝依賴然後啟動這個服務。

npm install

npm start

服務運行起來後,我們要用 ngrok 開啟一條隧道。serve 用 5000 連接埠託管檔案,要用 ngrok 開隧道通到這個連接埠,新開一個命令列視窗輸入以下命令:

`ngrok http 5000`

好了你現在可以公網訪問這個網站了,你可以在行動裝置上開啟這個網站,這樣接下來就可以測試啦。確保你開啟的是 HTTPS 的 URL,因為我們用的 API 只能在安全環境下使用。

網站看起來像這樣:

擷取 media stream

我們的第一個任務是從任意網路攝影機擷取視頻流顯示到螢幕上。完成這個之後我們再調研如何選擇特定網路攝影機。開啟 app.js , 我們以從 DOM 中選擇按鈕和 video 元素開始:

// app.js

const video = document.getElementById(‘video‘);

const button = document.getElementById(‘button‘);

當使用者點擊或觸摸按鈕時,我們要使用 mediaDevices API 請求網路攝影機許可權。要這樣做,我們要調用 navigator.mediaDevices.getUserMedia ,傳遞 media constraints 對象。讓我們從簡單的 constraints 開始,我們只需要視頻,因此我們把 video 設定為 true,audio 設定為 false。

getUserMedia 會返回一個 promise,當 resolve 的時候我們就可以訪問到網路攝影機的媒體流了。把媒體流賦值給 video 元素的 srcObj 屬性,我們就能從螢幕上看到視頻了。

button.addEventListener(‘click‘, event => {

  const constraints = {

    video: true,

    audio: false

  };

  navigator.mediaDevices

    .getUserMedia(constraints)

    .then(stream => {

      video.srcObject = stream;

    })

    .catch(error => {

      console.error(error);

    });

});

儲存檔案,重新載入頁面然後點擊按鈕。你應該能看到一個許可權對話方塊請求訪問你的網路攝影機,一旦授權螢幕上就應該會出現視頻。在你的電腦和手機上試一試,我在我的 iPhone 上試了,被選擇的是自拍。

如果你用的是一部 iPhone 手機,確認你在 Safari 裡嘗試,因為其他瀏覽器貌似並沒有效果。

可用網路攝影機

media Devices API 為我們提供了一種枚舉所有可用音頻和視頻輸入裝置的方式。我們要用 enumerateDevices 函數來為 框構建選項,這樣我們就能用它來選擇我們想看的網路攝影機了。再次開啟 app.js,從 DOM 中選出 元素:

const video = document.getElementById(‘video‘);

const button = document.getElementById(‘button‘);

const select = document.getElementById(‘select‘);

enumerateDevices 會返回一個 promise,所以讓我們寫一個用來接受 promise 結果的函數吧。這個函數接收一個 media device 數組作為參數。

首先要做的是清空 現有的任何選項,然後插入一個空的 。接著迴圈遍曆所有裝置,過濾掉非 “videoinput”類型的裝置。然後我們建立一個  元素,用裝置識別碼 當作 option value,裝置 label 當作 option text。我們還要處理一種情況,如果一個裝置沒有 label 存在,產生一個簡單的 “Camera n” 作為標籤。 const video = document.getElementById(‘video‘); const button = document.getElementById(‘button‘); const select = document.getElementById(‘select‘);  function gotDevices(mediaDevices) {   select.innerHTML = ‘‘;   select.appendChild(document.createElement(‘option‘));   let count = 1;   mediaDevices.forEach(mediaDevice => {     if (mediaDevice.kind === ‘videoinput‘) {       const option = document.createElement(‘option‘);       option.value = mediaDevice.deviceId;       const label = mediaDevice.label || `Camera ${count++}`;       const textNode = document.createTextNode(label);       option.appendChild(textNode);       select.appendChild(option);     }   }); } 在 app.js 末尾調用一下 enumerateDevices。 `navigator.mediaDevices.enumerateDevices().then(gotDevices);` 重新整理頁面,看一下按鈕旁邊的下拉選擇框。如果你用的是 Android ,或者使用 Chrome 或 Firefox,你就能看到可用的網路攝影機名稱了。 然而在 iPhone 上,你將看到我們函數產生的通用名字 “Camera 1” 和 “Camera 2”。在 iOS 上只有你授權至少一個網路攝影機給網站,你才能看到網路攝影機的名字。這讓在我們的介面上選擇網路攝影機變得更不方便,因為儘管你能擷取到裝置識別碼,你還是不能分辨哪個網路攝影機是哪個。  目前我們還沒有處理下拉選擇框來改變網路攝影機。在這之前,讓我們來看另一種能改變哪個網路攝影機被使用的方法。 FacingMode FacingMode 約束是一個可以用來選擇網路攝影機的替代方法。這個方法比起通過 enumerateDevices 函數擷取 ID 來說更不那麼精確,但在行動裝置上效果非常好。對於這個約束,一共有四種選項可供你選擇:使用者(user),環境(environment),左(left),右(right)。MDN 上的文檔對這個約束做了詳細介紹, 以本文的目的我們將使用使用者和環境模式,在行動裝置上它們正好對應到前置和後置網路攝影機。 要使用 facingMode 約束我們需要修改調用 getUserMedia 時使用的 constraints 對象。對於 video 我們需要一個對象來控制具體的約束,而不是給一個 true 值。像這樣修改代碼來使用自拍: button.addEventListener(‘click‘, event => {   const videoConstraints = {     facingMode: ‘user‘   };   const constraints = {     video: videoConstraints,     audio: false   }; 現在可以用你的手機測試。你應該能看到自拍被使用。更改 facingMode 為 environment 再試一次, 使用的應該是後置網路攝影機。讓我們把這些代碼和上面通過 enumerateDevices 擷取到的結果放到一塊兒,只要我們獲得了讀取網路攝影機資料的許可權,就能構建一個網路攝影機切換器了。 切換網路攝影機 現在我們有在首次選擇時挑選使用者或環境網路攝影機的代碼了,但如果我們要切換網路攝影機那還有一丟丟額外的工作要做。 首先,我們應該保留對當前流的引用,這樣當我們切換到另一個流時就能停止當前流。在 app.js 的最前面添加一個額外的變數和輔助函數來停止流中的軌。 const video = document.getElementById(‘video‘); const button = document.getElementById(‘button‘); const select = document.getElementById(‘select‘); let currentStream;  function stopMediaTracks(stream) {   stream.getTracks().forEach(track => {     track.stop();   }); } 函數 stopMediaTracks 接收一個媒體流,迴圈遍曆流中的每一個媒體軌道,調用 stop 方法停止媒體軌。 我們要在點擊同一個按鈕時改變網路攝影機,所以我們需要更新一下按鈕的事件監聽器了。如果當前有媒體流,我們應該先停止掉它。然後我們要檢查 元素看是否選擇了特定的裝置,然後基於此構造 media constraints 對象。

這樣修改按鈕的點擊處理函數和 video constraints:

button.addEventListener(‘click‘, event => {

  if (typeof currentStream !== ‘undefined‘) {

    stopMediaTracks(currentStream);

  }

  const videoConstraints = {};

  if (select.value === ‘‘) {

    videoConstraints.facingMode = ‘environment‘;

  } else {

    videoConstraints.deviceId = { exact: select.value };

  }

  const constraints = {

    video: videoConstraints,

    audio: false

  };

當我們想通過 deviceId 來選擇裝置時,使用 exact 約束。 可是對於 facingMode,我們沒有使用 exact 約束, 否則在一個無法識別有沒有使用者或環境模式的裝置上將會失敗,導致我們什麼媒體裝置也拿不到。

當我們獲得使用視頻的許可權時,在點擊處理函數內,我們還要修改一些別的東西。把傳遞給函數的新流賦值給 currentStream 以便後續調用 stop,觸發另一次 enumerateDevices 的調用。

enumerateDevices 返回一個 promise,所以在我們的 then 函數中可以直接返回它,然後鏈式建立一個新的 then 把結果傳遞給 gotDevices 函數處理。

用以下代碼替換現有的 getUserMedia 調用:

button.addEventListener(‘click‘, event => {

  if (typeof currentStream !== ‘undefined‘) {

    stopMediaTracks(currentStream);

  }

  const videoConstraints = {};

  if (select.value === ‘‘) {

    videoConstraints.facingMode = ‘environment‘;

  } else {

    videoConstraints.deviceId = { exact: select.value };

  }

  const constraints = {

    video: videoConstraints,

    audio: false

  };

 

  navigator.mediaDevices

    .getUserMedia(constraints)

    .then(stream => {

      currentStream = stream;

      video.srcObject = stream;

      return navigator.mediaDevices.enumerateDevices();

    })

    .then(gotDevices)

    .catch(error => {

      console.error(error);

    });

});

當你添加完所有的代碼,你的 app.js 應該看起來像這個檔案一樣。重新整理頁面然後你就能愉快地選擇和改變網路攝影機了。這個頁面在行動裝置和電腦上都有效。

下一步

我們已經看到如何通過使用 facingMode 和 deviceId 約束來選擇使用者的網路攝影機。記住,在你有許可權使用網路攝影機之前,facingMode 更可靠,但是選擇 deviceId 更加精確。你可以從 GitHub 倉庫 中得到所有本文中的代碼,你也可以從這裡嘗試線上版的應用。

如果你正在使用 Twilio Video 構建視頻應用,你可以在調用 connect 或者 createLocalVideoTrack的時候使用這些 constraints。

對於視訊交談來說,選擇和切換網路攝影機是非常有用的功能,允許使用者在你的應用介面準確地選擇他們想用的網路攝影機,並且還能做到在視訊通話時分享你的螢幕。

JavaScript 使用 mediaDevices API 選擇網路攝影機

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.