iT邦幫忙

2021 iThome 鐵人賽

DAY 25
0
Modern Web

後疫情時代的 WebRTC 微學習系列 第 25

Day25 [實作] 一對一視訊通話(5): 切換設備

如果我們的電腦有兩個攝影機,就會有切換裝置的需求,今天我們就來加入這個功能

  1. 在 index.html 增加兩個 select 用來選擇設備

    <div>
      <label>切換麥克風:</label>
      <select id="audioSource"></select>
    </div>
    
    <div>
      <label>切換攝影機:</label>
      <select id="videoSource"></select>
    </div>
    
  2. 在 main.js 增加切換設備會使用到的標籤

    // 切換設備
    const audioInputSelect = document.querySelector('select#audioSource')
    const videoSelect = document.querySelector('select#videoSource')
    const selectors = [audioInputSelect, videoSelect]
    
  3. 讀取設備並將設備加入 select 的選項中

    // 將讀取到的設備加入到 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 === '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((err) => {
        console.error('Error happens:', err)
      })
    
  4. 選取設備後切換標籤並將切換後的媒體傳送給對方,這邊使用 replaceTrack 去替換 track 不需要重新做協商

    audioInputSelect.onchange = () => {
      switchDevice(true)
    }
    videoSelect.onchange = () => {
      switchDevice(false)
    }
    
    async function switchDevice(isAudio) {
      if (!peerConn) return
      const audioSource = audioInputSelect.value
      const videoSource = videoSelect.value
      const constraints = {
        audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
        video: { deviceId: videoSource ? { exact: videoSource } : undefined },
      }
      const stream = await navigator.mediaDevices.getUserMedia(constraints)
      let track = stream[isAudio ? 'getAudioTracks' : 'getVideoTracks']()[0]
      let sender = peerConn.getSenders().find(function (s) {
        return s.track.kind == track.kind
      })
      console.log('found sender:', sender)
      sender.replaceTrack(track)
    
      localStream = stream
      localVideo.srcObject = stream
    }
    

上一篇
Day24 [實作] 一對一視訊通話(4): 加入通話及掛斷機制
下一篇
Day26 [實作] 一對一視訊通話(6): 關閉鏡頭或麥克風
系列文
後疫情時代的 WebRTC 微學習30

尚未有邦友留言

立即登入留言