iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
2
Software Development

30天之即時網路影音開發攻略(小白本)系列 第 7

30-07之Web 如何進行語音與影像採集 ?

黑色好看版 - 傳送門


https://ithelp.ithome.com.tw/upload/images/20181022/20089358r4NEMQ5UbJ.png

正文開始


前面幾篇咱們已經學習了聲音與影像的採集相關知識,那接下咱們來學習一下如何在 Web 上進行聲音與影像的採集。

如何在 Web 上進行聲音與影像的採集 ? ( 其它平台的別問我 )

這篇文章中,咱們將會用到一個東東叫做WebRTC,接下來會以它為主,將之分成以下三個章節:

  • WebRTC 是啥 ?
  • 使用 WebRTC 來採集聲音與影像
  • 將採集到的聲音儲放成一個檔案

WebRTC 是啥 ?


讓瀏覽器不需加裝任何套件就可以進行即時文字、語音與影像對話的 API 。

WebRTC 全名為 Web Real-Time Communication,中文為網頁即時通訊,這東東用途就是讓咱們的瀏覽器不用裝認何啥套件就可以進行和其它瀏覽器進行即時文字、語音與影像對話。

它在 2011 年時進入了 W3C 的推薦表準,並且到了現在(2018),大部份的瀏覽器都有支援 (IE 例外)。

它主要有三種類型的 API:

  • getUserMedia:用來處理音視串流採集。 (採集聲音或影像)。
  • RTCPeerConnection:用來建立兩個瀏覽器之間的直接通訊。 (建立與管理 p2p 連線)
  • RTCDataChannel:負責用來傳送資料。(操作那條 p2p 連線)

基本上在這篇文章中只會用到第一個 getUserMedia 其它的 API 在後面文章會詳細的進行說明。

備註

當前(2018)支援各平台的狀態請參考以下連結:

WiKI: WebRTC Support

使用 WebRTC 來採集聲音與影像


事實上就是如此的簡單,下面程式碼中,我們使用 getUserMedia 來採集聲音與影像,而 stream 就是咱們所採集到的聲音與影像,它們都是 raw data,也就是說聲音是 PCM 編碼,而影像就是單純的一堆連續的圖片編碼。

const constraints = { audio: true, video: true }
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
    // stream 就是咱們的聲音與影像
})
.catch((err) => {
    // 錯誤處理
})

上面的程式碼中有幾個重點要注意一下:

getUserMedia 回傳的是一個 Promise

這也代表你可以將程式碼改成如下,記得要 try catch 不然錯誤會無法捕捉到的。

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

try {
    const stream = await navigator.mediaDevices.getUserMedia(constraints) 
} catch (error) {
    // 錯誤處理
}

getUserMedia 進行 resolve 時,是回傳 MediaStream

MediaStream 之後會詳細說明。

錯誤時可能會回傳下列錯誤

  • AbortError:硬件有問題,例如麥克風 G 了。
  • NotAllowedError:用戶拒絕使用麥克風。
  • NotFoundError:找不到你的 constraints 裡設置的媒體類型。
  • NotReadableError:用戶允許使用媒體設備,但是去讀取時發現無法使用媒體設備。
  • OverConstrainedError:表示無法滿足你所設置的 constraints。
  • SecurityError:偏好設定中可能有禁止使用媒體設備。
  • TypeError:constraints 怪怪的。

constraints 是用來設置 audio 或 video 的限制

詳細的參數請參考此篇文章這裡只簡單的說明有那些用法。

例如你可限制只使用 audio:

{ audio: true }

例如你可以限制 video 的長與寬:

{ video: { width: 1280, height: 720 } }

例如你可以限制影像的幀率(FPS):

之前的文章有提到幀率這東西,它就是一秒鐘的影像有幾個圖片,如果現在是屬於低頻寬的網路環境,咱們可以將他調低,如下面所示,它就變成一秒鐘的影像只有 10 張圖片(正常應該是 20 ~ 30)。

{ video: { frameRate: 10 }

例如你可以調整聲音的採樣率與採樣大小:

{ audio: true, sampleSize: 8 (bit), sampleRate: 40000 (40kHz) }

不過 stack overflow 這裡看到好像有說就算調整了也沒啥用,不過這裡我只是要讓你知道,是有這兩種屬性的。

使用 WebRTC 來採集聲音並且儲放成 .wav 檔


下面的範例中,我們有用到 getUserMedia 來進行聲音的採集,同時我們有用到 recorderjs 這個套件來將採集來的聲音記錄下來,最後結束時,會將聲音輸出成 wav。最下面附件有全部程式碼,可以直接的複製到 html 檔案後,然後再用瀏覽器開啟,最後等個 10 秒鐘,你就會看到多了聲音控制畫面與下載的連結了。

在這段程式碼中有一個東西叫AudioContext,它也是原生的 API,你可以想成它是一個聲音的容器,然後我們將聲音串流丟到它的裡面,接下來咱們就可以針對這個容器內的聲音做些事情,像記錄或加工都可以。

navigator.mediaDevices.getUserMedia({ audio: true })
    .then((stream) => {
      const audioContext = new AudioContext;
      const audioInput = audioContext.createMediaStreamSource(stream);

      const rec = new Recorder(audioInput);
      // 這個聲音串流一開時,就開始進行錄製。
      rec.record()

      setTimeout(function () {
        // 然後在 10 秒後結束錄製,並產生個語音控制項與下載連結。
        rec.stop();
        createAudioController(rec);
        createDownloadLink(rec);
      }, 10000);
    })
    .catch((err) => {
      console.log('nonono ~~~ !!');
    })

接下來 10 秒過後,我們會停止錄製,並且會產生兩個東西,如下圖,有點醜我知道,因為我懶改。

https://ithelp.ithome.com.tw/upload/images/20181022/20089358wfYfovYtkm.png

首先第一個是畫面上會有個 audio 的控制項,讓你可以直接聽你剛剛錄的歌,下面為這段程式碼。

 function createAudioController(rec) {
    rec && rec.exportWAV((blob) => {
      const url = URL.createObjectURL(blob);
      const audio = document.createElement('audio');
      audio.controls = true;
      audio.src = url;

      main.appendChild(audio);
    });
}

第二個是畫面上會有個 link 連結,點下去就可以下載你剛剛錄的聲音 wav 檔,這個檔案前一篇中文章30-06之聲音與影像的封裝有提到,它是儲放聲音的一種容器,通常他就是用來專門儲放 raw data (PCM) 的格式(容器)。

 function createAudioController(rec) {
    rec && rec.exportWAV((blob) => {
      const url = URL.createObjectURL(blob);
      const audio = document.createElement('audio');
      audio.controls = true;
      audio.src = url;

      main.appendChild(audio);
    });
}

所有程式碼請拉到最下面備註。

結論


這篇文章中我們簡單的學習到以下幾個重點:

  • WebRTC 是啥 ? 它就是讓瀏覽器不需加裝任何套件就可以進行即時文字、語音與影像對話的 API。
  • 如何的使用 WebRTC 來採集聲音與影像。
  • 如何的將採集到的聲音儲放到容器中。

這篇文章中我們說明了如何在 Web 上進行聲音的採集,但這只是直播開發用戶端的其中一部份,其它的 Android、ios、mac、windows 平台如何的去進行採集,那就要請各位自已去探討囉,這裡就只針對我熟悉的 Web 部份來研究。

參考資料


備註


<html>

<div id="main"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/recorderjs/0.1.0/recorder.js"></script>
<script>

  navigator.mediaDevices.getUserMedia({ audio: true })
    .then((stream) => {
      const audioContext = new AudioContext;
      const audioInput = audioContext.createMediaStreamSource(stream);
      const rec = new Recorder(audioInput);
      // 這個聲音串流一開時,就開始進行錄製。
      rec.record()

      setTimeout(function () {
        // 然後在 10 秒後結束錄製,並產生個下載連結。
        rec.stop();
        createAudioController(rec);
        createDownloadLink(rec);
      }, 10000);
    })
    .catch((err) => {
      console.log('nonono ~~~ !!');
    })

  function createDownloadLink(rec) {
    rec && rec.exportWAV((blob) => {
      const url = URL.createObjectURL(blob);
      const hf = document.createElement('a');

      hf.href = url;
      hf.download = 'test.wav';
      hf.innerHTML = hf.download;
      main.appendChild(hf);
    });
  }

  function createAudioController(rec) {
    rec && rec.exportWAV((blob) => {
      const url = URL.createObjectURL(blob);
      const audio = document.createElement('audio');
      audio.controls = true;
      audio.src = url;

      main.appendChild(audio);
    });
  }

</script>

</html>

上一篇
30-06之聲音與影像的封裝
下一篇
30-08之 WebRTC 採集的詳細說明與聲音的加工
系列文
30天之即時網路影音開發攻略(小白本)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言