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
    }
    

<<:  17 Liveview 练习

>>:  Day-20 堆叠(Stack)

[Lesson3] BMI

今天要来做一个计算BMI的简易App! activity_main.xml: 使用LinearLay...

[第十天]从0开始的UnityAR手机游戏开发-Vuforia多张图卡辨识

到Vuforia官网点击Develop→Target Manager→Add Target 新增其他...

Android Studio初学笔记-Day7-Button和Toast

Button和Toast 今天要介绍的是Button这个常在程序中能看到的元件,在Button的属性...

[Day7] 实作 - 敌人篇

如果你是熟悉RPG Maker的人 一定知道各式各样实作敌人的方式 其中当然包括使用引擎内建的UI来...

Day 30 : 第一个 MQTT 智慧装置

MQTT 通讯协定 最後一天就是要把大家领进门, 来把上回的智慧装置串接到 Home Assista...