2020年6月11(webrtc篇)


熟悉webrtc

WebRTC用来协助建立p2p通讯的。主要用于协商双方通讯过程,传递基本信息,如:会话控制信息,用来开始和结束通话,即开始视频、结束视频这些操作指令;处理错误的消息;元数据,如各自的音视频解码方式、带宽;网络数据,对方的公网IP、端口、内网IP及端口。但是WebRTC的API并没有实现信令通信机制,所以使用者需要自己去实现。常见的信令交互图如下

image-20200611185906328

image-20200611185906328

  • Amy、Bob均实例化一个RTCPeerConnection(以下简称rpcA和rpcB),调用rpcA的createOffer()方法建立一个offer信令,并且拿到A的SDP
  • 通过rpcA的setLocalDescription()方法设置A机器的本地描述
  • A通过服务器将offer信令发给B
  • B接收到A的offer信令,通过rpcB的setRemoteDescription()方法设置远程机器(即A)的描述
  • B调用rpcB的createAnswer()方法建立一个answer信令,并且拿到B的SDP
  • 通过rpcB的setLocalDescription()方法设置B机器的本地描述
  • B通过服务器将answer信令发送给A
  • A接收到B的answer信令,通过rpcA的setRemoteDescription()方法设置远程机器B的描述

sdp(Session Description Protocol)是一种会话描述协议,属于文本协议,即WebRTC中常说的信令(Signalling),是WebRTC用来协助建立p2p通讯的。主要用于协商双方通讯过程,传递基本信息,如:会话控制信息,用来开始和结束通话,即开始视频、结束视频这些操作指令;处理错误的消息;元数据,如各自的音视频解码方式、带宽;网络数据,对方的公网IP、端口、内网IP及端口。但是WebRTC的API并没有实现信令通信机制,所以使用者需要自己去实现。常见的信令交

现在看一个关于屏幕分享的小案例

案例展示

image-20200611185906328

用到的是vue-webrtc

代码展示(父组件)

<template>
  <div class="container">
    <div class="row">
      <div class="col-md-12 my-3">
        <h2>Room</h2>
        <input v-model="roomId" />
      </div>
    </div>
    <div class="row">
      <div class="col-md-12">
        <div class>
          <vue-webrtc
            ref="webrtc"
            width="100%"
            :roomId="roomId"
            v-on:joined-room="logEvent"
            v-on:left-room="logEvent"
            v-on:opened-room="logEvent"
            v-on:share-started="logEvent"
            v-on:share-stopped="logEvent"
            @error="onError"
          />
        </div>
        <div class="row">
          <div class="col-md-12 my-3">
            <button type="button" class="btn btn-primary" @click="onJoin">Join</button>
            <button type="button" class="btn btn-primary" @click="onLeave">Leave</button>
            <button type="button" class="btn btn-primary" @click="onCapture">Capture Photo</button>
            <button type="button" class="btn btn-primary" @click="onShareScreen">Share Screen</button>
          </div>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="col-md-12">
        <h2>Captured Image</h2>
        <figure class="figure">
          <img :src="img" class="img-responsive" />
        </figure>
      </div>
    </div>
  </div>
</template>

<script>
import Vue from 'vue'
import { WebRTC } from 'plugin';
import { find, head } from 'lodash';

Vue.component(WebRTC.name, WebRTC);

export default {
  name: 'app',
  components: {
  },
  data () {
    return {
      img: null,
      roomId: "public-room"
    };
  },
  computed: {
  },
  watch: {
  },
  methods: {
    onCapture () {
      this.img = this.$refs.webrtc.capture();
    },
    onJoin () {
      this.$refs.webrtc.join();
    },
    onLeave () {
      this.$refs.webrtc.leave();
    },
    onShareScreen () {
      this.img = this.$refs.webrtc.shareScreen();
    },
    onError (error, stream) {
      console.log('On Error Event', error, stream);
    },
    logEvent (event) {
      console.log('Event : ', event);
    },
  }
};
</script>

子组件接收

image-20200611190125454

点击分享按钮

shareScreen () {
    var that = this;
    if (navigator.getDisplayMedia || navigator.mediaDevices.getDisplayMedia) {
      function addStreamStopListener (stream, callback) {
        console.log(stream, 'stream')
        var streamEndedEvent = 'ended';
        if ('oninactive' in stream) {
          streamEndedEvent = 'inactive';
        }
        stream.addEventListener(streamEndedEvent, function () {
          callback();
          callback = function () { };
        }, false);
      }

      function onGettingSteam (stream) {
        that.rtcmConnection.addStream(stream);
        that.$emit('share-started', stream.streamid);

        addStreamStopListener(stream, function () {
          that.rtcmConnection.removeStream(stream.streamid);
          that.$emit('share-stopped', stream.streamid);
        });
      }

      function getDisplayMediaError (error) {
        console.log('Media error: ' + JSON.stringify(error));
      }
      // 出现弹框
      if (navigator.mediaDevices.getDisplayMedia) {
        // 异步请求
        navigator.mediaDevices.getDisplayMedia({ video: true, audio: false }).then(stream => {
          onGettingSteam(stream);
        }, getDisplayMediaError).catch(getDisplayMediaError);
      }
      else if (navigator.getDisplayMedia) {
        debugger
        navigator.getDisplayMedia({ video: true }).then(stream => {
          onGettingSteam(stream);
        }, getDisplayMediaError).catch(getDisplayMediaError);
      }
    }
  }

Author: wxy
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source wxy !
  TOC