iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
Modern Web

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

Day17 [實作] RTCPeerConnection: 本機端模擬 P2P 的過程

上一篇我們通過簡單的例子了解 Offer / Answer 的機制,今天我們要加上視訊:

  • Bob 通過 addTrack 把自己的音視訊軌道加入 PeerConnection 中
  • Alice 可以透過 ontrack 來取得Bob 的影像
  1. index.html

    <html>
      <head>
        <title>WebRTC PeerConnection</title>
      </head>
    
      <body>
        <div>
          <div>
            <button id="start">Start</button>
            <button id="call" disabled>Call</button>
            <button id="hangup" disabled>HangUp</button>
          </div>
    
          <div>
            <div>
              <h2>Local:</h2>
              <video id="localvideo" autoplay playsinline></video>
            </div>
            <div>
              <h2>Remote:</h2>
              <video id="remotevideo" autoplay playsinline></video>
            </div>
          </div>
        </div>
    
        <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
        <script src="js/main.js"></script>
      </body>
    </html>
    
  2. main.js

    'use strict'
    
    const localVideo = document.querySelector('video#localVideo')
    const remoteVideo = document.querySelector('video#remoteVideo')
    const btnStart = document.querySelector('button#start')
    const btnCall = document.querySelector('button#call')
    const btnHangup = document.querySelector('button#hangup')
    
    let localStream
    let BobPC
    let AlicePC
    
    btnStart.onclick = start
    btnCall.onclick = call
    btnHangup.onclick = hangup
    
    function start() {
      const constraints = {
        video: true,
        audio: false,
      }
    
      if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
        return
      } else {
        navigator.mediaDevices.getUserMedia(constraints).then(gotMediaStream)
    
        btnStart.disabled = true
        btnCall.disabled = false
        btnHangup.disabled = true
      }
    }
    
    function gotMediaStream(stream) {
      localVideo.srcObject = stream
      localStream = stream
    }
    
    function call() {
      const offerOptions = {
        offerToReceiveAudio: 0,
        offerToReceiveVideo: 1,
      }
    
      BobPC = new RTCPeerConnection()
      AlicePC = new RTCPeerConnection()
    
      BobPC.onicecandidate = (e) => {
        AlicePC.addIceCandidate(e.candidate)
        console.log('BobPC ICE candidate:', e.candidate)
      }
    
      AlicePC.onicecandidate = (e) => {
        BobPC.addIceCandidate(e.candidate)
        console.log('AlicePC ICE candidate:', e.candidate)
      }
    
      AlicePC.ontrack = gotRemoteStream
    
      localStream.getTracks().forEach((track) => {
        BobPC.addTrack(track, localStream)
      })
    
      BobPC.createOffer(offerOptions).then(gotLocalDescription)
    
      btnCall.disabled = true
      btnHangup.disabled = false
    }
    
    function gotRemoteStream(e) {
      if (remoteVideo.srcObject !== e.streams[0]) {
        remoteVideo.srcObject = e.streams[0]
      }
    }
    
    function gotLocalDescription(desc) {
      BobPC.setLocalDescription(desc)
      // 2. 通過 Signaling server 將包含 Bob SDP 的offer 發送給 Alice
      // 3. Alice 收到 offer 後呼叫 setRemoteDescription 設定 Bob 的 SDP
      AlicePC.setRemoteDescription(desc)
      // 4. Alice 呼叫 RTCPeerConnection.createAnswer 建立一個 answer
      AlicePC.createAnswer().then(gotAnswerDescription)
    }
    
    function gotAnswerDescription(desc) {
      AlicePC.setLocalDescription(desc)
      // 5. 通過 Signaling server 將包含 Alice SDP 的 answer 發送給 Bob
      // 6. Bob 收到 answer  後呼叫 setRemoteDescription 設定 Alice 的SDP
      BobPC.setRemoteDescription(desc)
    }
    
    function hangup() {
      BobPC.close()
      AlicePC.close()
      BobPC = null
      AlicePC = null
    
      btnCall.disabled = false
      btnHangup.disabled = true
    }
    

上一篇
Day16 RTCPeerConnection: Offer / Answer
下一篇
Day18 使用 GCP 免費雲端主機測試 Turn server
系列文
後疫情時代的 WebRTC 微學習30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言