<template> 
 | 
  <div class="demo"> 
 | 
    <div class="rtcBox"> 
 | 
      <div> 
 | 
        <div class="video-box"> 
 | 
          <video src="" id="rtcA" controls autoplay></video> 
 | 
          <h5>A</h5> 
 | 
        </div> 
 | 
        <div class="chat-box" v-show="!allowHangup && messageOpen"> 
 | 
          <h5>收消息</h5> 
 | 
          <p>{{ receiveText }}</p> 
 | 
        </div> 
 | 
      </div> 
 | 
      <div> 
 | 
        <div class="video-box"> 
 | 
          <video src="" id="rtcB" controls autoplay></video> 
 | 
          <h5>B</h5> 
 | 
          <button @click="call" :disabled="allowCall">发起连接</button> 
 | 
          <button @click="hangup" :disabled="allowHangup">hangup</button> 
 | 
        </div> 
 | 
        <div class="chat-box" v-show="!allowHangup && messageOpen"> 
 | 
          <h5>发消息</h5> 
 | 
          <textarea v-model="sendText"></textarea> 
 | 
          <br /> 
 | 
          <button @click="send">发送</button> 
 | 
        </div> 
 | 
      </div> 
 | 
    </div> 
 | 
  </div> 
 | 
</template> 
 | 
  
 | 
<script> 
 | 
export default { 
 | 
  name: "local1", 
 | 
  data() { 
 | 
    return { 
 | 
      peerA: null, 
 | 
      peerB: null, 
 | 
      channelA: null, 
 | 
      channelB: null, 
 | 
      offerOption: { 
 | 
        offerToReceiveAudio: 1, 
 | 
        offerToReceiveVideo: 1, 
 | 
      }, 
 | 
      allowCall: true, 
 | 
      allowHangup: true, 
 | 
      messageOpen: false, 
 | 
      sendText: "", 
 | 
      receiveText: "", 
 | 
    }; 
 | 
  }, 
 | 
  methods: { 
 | 
    send() { 
 | 
      this.channelB.send(JSON.stringify({ name: this.sendText })); 
 | 
      this.sendText = ""; 
 | 
    }, 
 | 
    start() { 
 | 
      this.state = "2"; 
 | 
      this.newRecognition.start(); 
 | 
    }, 
 | 
    stop() { 
 | 
      this.state = "1"; 
 | 
      this.newRecognition.stop(); 
 | 
    }, 
 | 
    async call() { 
 | 
      if (!this.peerA || !this.peerB) { 
 | 
        // 判断是否有对应实例,没有就重新创建 
 | 
        this.initPeer(); 
 | 
      } 
 | 
      try { 
 | 
        let offer = await this.peerB.createOffer(this.offerOption); // 创建 offer 
 | 
        await this.onCreateOffer(offer); 
 | 
      } catch (e) { 
 | 
        console.log("createOffer: ", e); 
 | 
      } 
 | 
  
 | 
      this.allowCall = true; 
 | 
      this.allowHangup = false; 
 | 
    }, 
 | 
    hangup() { 
 | 
      this.peerA.close(); 
 | 
      this.peerB.close(); 
 | 
      this.channelA.close(); 
 | 
      this.channelB.close(); 
 | 
      this.peerA = null; 
 | 
      this.peerB = null; 
 | 
      this.channelA = null; 
 | 
      this.channelB = null; 
 | 
      this.sendText = ""; 
 | 
      this.receiveText = ""; 
 | 
      this.allowCall = false; 
 | 
      this.allowHangup = true; 
 | 
    }, 
 | 
    async onCreateOffer(desc) { 
 | 
      try { 
 | 
        await this.peerB.setLocalDescription(desc); // 呼叫端设置本地 offer 描述 
 | 
      } catch (e) { 
 | 
        console.log("Offer-setLocalDescription: ", e); 
 | 
      } 
 | 
      try { 
 | 
        await this.peerA.setRemoteDescription(desc); // 接收端设置远程 offer 描述 
 | 
      } catch (e) { 
 | 
        console.log("Offer-setRemoteDescription: ", e); 
 | 
      } 
 | 
      try { 
 | 
        let answer = await this.peerA.createAnswer(); // 接收端创建 answer 
 | 
        await this.onCreateAnswer(answer); 
 | 
      } catch (e) { 
 | 
        console.log("createAnswer: ", e); 
 | 
      } 
 | 
    }, 
 | 
    async onCreateAnswer(desc) { 
 | 
      try { 
 | 
        await this.peerA.setLocalDescription(desc); // 接收端设置本地 answer 描述 
 | 
      } catch (e) { 
 | 
        console.log("answer-setLocalDescription: ", e); 
 | 
      } 
 | 
      try { 
 | 
        await this.peerB.setRemoteDescription(desc); // 呼叫端设置远程 answer 描述 
 | 
      } catch (e) { 
 | 
        console.log("answer-setRemoteDescription: ", e); 
 | 
      } 
 | 
    }, 
 | 
    initPeer() { 
 | 
      // 创建输出端 PeerConnection 
 | 
      let PeerConnection = 
 | 
        window.RTCPeerConnection || 
 | 
        window.mozRTCPeerConnection || 
 | 
        window.webkitRTCPeerConnection; 
 | 
      this.peerA = new PeerConnection(); 
 | 
      this.peerA.addStream(this.localstream); // 添加本地流 
 | 
      // 监听 A 的ICE候选信息 
 | 
      // 如果收集到,就添加给 B 
 | 
      this.peerA.onicecandidate = (event) => { 
 | 
        if (event.candidate) { 
 | 
          this.peerB.addIceCandidate(event.candidate); 
 | 
        } 
 | 
      }; 
 | 
      this.peerA.ondatachannel = (event) => { 
 | 
        console.log(event); 
 | 
        this.channelA = event.channel; 
 | 
        this.channelA.binaryType = "arraybuffer"; 
 | 
        this.channelA.onopen = (e) => { 
 | 
          console.log("channelA onopen", e); 
 | 
        }; 
 | 
        this.channelA.onclose = (e) => { 
 | 
          console.log("channelA onclose", e); 
 | 
        }; 
 | 
        this.channelA.onmessage = (e) => { 
 | 
          this.receiveText = JSON.parse(e.data).name; 
 | 
          console.log("channelA onmessage", e.data); 
 | 
        }; 
 | 
      }; 
 | 
      //                this.channelA.send('Hi you!'); 
 | 
      // 创建呼叫端 
 | 
      this.peerB = new PeerConnection(); 
 | 
      this.peerB.onaddstream = (event) => { 
 | 
        // 监听是否有媒体流接入,如果有就赋值给 rtcB 的 src 
 | 
        console.log("event-stream", event); 
 | 
        let video = document.querySelector("#rtcB"); 
 | 
        video.srcObject = event.stream; 
 | 
      }; 
 | 
      this.channelB = this.peerB.createDataChannel("messagechannel"); 
 | 
      console.log("this.channelB", this.channelB); 
 | 
      this.channelB.binaryType = "arraybuffer"; 
 | 
      this.channelB.onopen = (event) => { 
 | 
        console.log(1); 
 | 
        console.log("channelB onopen", event); 
 | 
        this.messageOpen = true; 
 | 
      }; 
 | 
      this.channelB.onclose = function (event) { 
 | 
        console.log(1); 
 | 
        console.log("channelB onclose", event); 
 | 
      }; 
 | 
      // 监听 B 的ICE候选信息 
 | 
      // 如果收集到,就添加给 A 
 | 
      this.peerB.onicecandidate = (event) => { 
 | 
        if (event.candidate) { 
 | 
          this.peerA.addIceCandidate(event.candidate); 
 | 
        } 
 | 
      }; 
 | 
      this.allowCall = false; 
 | 
    }, 
 | 
    async createMedia() { 
 | 
      // 保存本地流到全局(视频音频都支持) 
 | 
      this.localstream = await navigator.mediaDevices.getUserMedia({ 
 | 
        audio: true, 
 | 
        video: true, 
 | 
      }); 
 | 
      console.log(this.localstream); 
 | 
      console.log( 
 | 
        this.localstream.getVideoTracks(), 
 | 
        this.localstream.getAudioTracks() 
 | 
      ); 
 | 
      let video = document.querySelector("#rtcA"); 
 | 
      video.srcObject = this.localstream; 
 | 
      this.initPeer(); // 获取到媒体流后,调用函数初始化 RTCPeerConnection 
 | 
    }, 
 | 
  }, 
 | 
  mounted() { 
 | 
    // 获取最新视图后获取本地流 
 | 
    this.$nextTick(() => { 
 | 
      // {mediaSource: 'screen'} 
 | 
      this.createMedia(); 
 | 
    }); 
 | 
  }, 
 | 
}; 
 | 
</script> 
 | 
  
 | 
<style lang="scss"> 
 | 
.rtcBox { 
 | 
  display: flex; 
 | 
  justify-content: center; 
 | 
  .video-box { 
 | 
    height: 380px; 
 | 
    border-bottom: 1px solid #1fbeca; 
 | 
    margin-bottom: 10px; 
 | 
  } 
 | 
  video { 
 | 
    width: 400px; 
 | 
    height: 300px; 
 | 
    margin-left: 20px; 
 | 
    background-color: #ddd; 
 | 
  } 
 | 
  .chat-box { 
 | 
    text-align: center; 
 | 
    h5 { 
 | 
      margin-bottom: 10px; 
 | 
    } 
 | 
    p, 
 | 
    textarea { 
 | 
      width: 240px; 
 | 
      height: 60px; 
 | 
      border: 1px solid #000; 
 | 
      display: inline-block; 
 | 
    } 
 | 
  } 
 | 
} 
 | 
</style> 
 |