Day11 [实作] 如何在 WebRTC 中切换设备

建立开发环境

  1. 我们需要一个 http server,安装 http-server ,安装方式如文档

  2. 建立一个资料夹 WebRTC ,里面包含一个 index.html

    <!DOCTYPE html>
      <head>
        <title>WebRTC</title>
      </head>
      <body>
    		测试 http server
      </body>
    </html>
    
  3. 打开终端机 cd到 WebRTC 资料夹内并输入 http-server

    https://ithelp.ithome.com.tw/upload/images/20210925/20130062qjQAw2dmI1.png

透过WebRTC samples 学习检查并切换设备

WebRTC samples 有非常多用於展示 WebRTC API 的 sample code ,是学习 WebRTC 很好的教材,今天我们透过一个切换设备的范例来看看如何学习。

  1. 在 WebRTC 资料夹内建立以下文件

    https://ithelp.ithome.com.tw/upload/images/20210925/20130062sAERZkyMbp.png

  2. index.html 修改为:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title>WebRTC</title>
      </head>
      <body>
        <div>
          <label>音讯输入装置:</label>
          <select id="audioSource"></select>
        </div>
    
        <div>
          <label>音讯输出装置:</label>
          <select id="audioOutput"></select>
        </div>
    
        <div>
          <label>视讯输入装置:</label>
          <select id="videoSource"></select>
        </div>
    
        <video autoplay playsinline id="player"></video>
        <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
    
        <script src="./js/main.js"></script>
      </body>
    </html>
    
  3. main.js 修改为:

    /*
     *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
     *
     *  Use of this source code is governed by a BSD-style license
     *  that can be found in the LICENSE file in the root of the source
     *  tree.
     */
    
    'use strict'
    
    // 取得标签
    const videoElement = document.querySelector('video')
    const audioInputSelect = document.querySelector('select#audioSource')
    const audioOutputSelect = document.querySelector('select#audioOutput')
    const videoSelect = document.querySelector('select#videoSource')
    const selectors = [audioInputSelect, audioOutputSelect, videoSelect]
    
    audioOutputSelect.disabled = !('sinkId' in HTMLMediaElement.prototype)
    
    // 将读取到的设备加入到 select 标签中
    function gotDevices(deviceInfos) {
      // Handles being called several times to update labels. Preserve values.
      const values = selectors.map((select) => select.value)
      selectors.forEach((select) => {
        while (select.firstChild) {
          select.removeChild(select.firstChild)
        }
      })
      for (let i = 0; i !== deviceInfos.length; ++i) {
        const deviceInfo = deviceInfos[i]
        const option = document.createElement('option')
        option.value = deviceInfo.deviceId
        if (deviceInfo.kind === 'audioinput') {
          option.text =
            deviceInfo.label || `microphone ${audioInputSelect.length + 1}`
          audioInputSelect.appendChild(option)
        } else if (deviceInfo.kind === 'audiooutput') {
          option.text =
            deviceInfo.label || `speaker ${audioOutputSelect.length + 1}`
          audioOutputSelect.appendChild(option)
        } else if (deviceInfo.kind === 'videoinput') {
          option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`
          videoSelect.appendChild(option)
        } else {
          console.log('Some other kind of source/device: ', deviceInfo)
        }
      }
      selectors.forEach((select, selectorIndex) => {
        if (
          Array.prototype.slice
            .call(select.childNodes)
            .some((n) => n.value === values[selectorIndex])
        ) {
          select.value = values[selectorIndex]
        }
      })
    }
    
    // 读取设备
    navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError)
    
    // 手动修改音讯的输出 例如预设耳机切换成喇叭
    function attachSinkId(element, sinkId) {
      if (typeof element.sinkId !== 'undefined') {
        element
          .setSinkId(sinkId)
          .then(() => {
            console.log(`Success, audio output device attached: ${sinkId}`)
          })
          .catch((error) => {
            let errorMessage = error
            if (error.name === 'SecurityError') {
              errorMessage = `You need to use HTTPS for selecting audio output device: ${error}`
            }
            console.error(errorMessage)
            // Jump back to first output device in the list as it's the default.
            audioOutputSelect.selectedIndex = 0
          })
      } else {
        console.warn('Browser does not support output device selection.')
      }
    }
    
    // 处理音讯改变的方法
    function changeAudioDestination() {
      const audioDestination = audioOutputSelect.value
      attachSinkId(videoElement, audioDestination)
    }
    
    // 将视讯显示在 video 标签上
    function gotStream(stream) {
      videoElement.srcObject = stream
    
      return navigator.mediaDevices.enumerateDevices()
    }
    
    // 错误处理
    function handleError(error) {
      console.log(
        'navigator.MediaDevices.getUserMedia error: ',
        error.message,
        error.name,
      )
    }
    
    // 播放自己的视讯
    function start() {
      if (window.stream) {
        window.stream.getTracks().forEach((track) => {
          track.stop()
        })
      }
      const audioSource = audioInputSelect.value
      const videoSource = videoSelect.value
      const constraints = {
        audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
        video: { deviceId: videoSource ? { exact: videoSource } : undefined },
      }
      navigator.mediaDevices
        .getUserMedia(constraints)
        .then(gotStream)
        .then(gotDevices)
        .catch(handleError)
    }
    
    audioInputSelect.onchange = start
    audioOutputSelect.onchange = changeAudioDestination
    
    videoSelect.onchange = start
    
    start()
    
  4. 打开终端机 cd到资料夹内并输入 http-server ,使用浏览器开启 http://localhost:8080/允许使用权限,就可以尝试切换设备。


<<:  Day10 - [丰收款] 安全无虞後,开始建立订单:ATM虚拟帐号篇 (2)

>>:  DAY13 - 第二个小范例 : 台股爬虫

Day 09:今天又想不出标题了!tmux plugin 和 mouse mode

我把从第一天到现在每天的 Home 目录都放上 GitHub 了,README.md 里面有说明 ...

Chapter5 终於要来从零打造-Canvas网页游戏-之行前说明书

前言 其实我算蛮容易分心的,说好要搞流程图,结果都在打code;说好要做游戏,结果都在搞动画;虽然列...

DAY16:Pytorch transforms(上)

torchvision.transforms transforms可以用来改变样本的多样性,例如:旋...

SuiteScript - Entry Point

Schedule Script execute Map/Reduce Script getInput...

[Day 15] Sass - Loop

Hi 终於来到第15天了(一半了!!!) 今天要写的是关於Sass-Loop回圈,回圈很常与前几天介...