webSocked、webRtc(RTCPeerConnection)、getUserMedia 实现实时通信

websocked主要实现文本信息、二进制图片录音等消息通讯web

webRtc主要实现视频音频流的通讯浏览器

getUserMedia主要实现获取浏览器摄像头麦克风以及获取视频音频流socket

首先得创建一个webScoked对象,用webSocked几个经常使用的事件去监听webSocked的工做状态,在onopen事件中监听到webSocked链接成功,在须要的地方使用send方法发送消息,就能够在onmessage事件中监听通讯消息并处理,当发生意外错误或者须要关闭webSocked的时候就会调用oncloseide

部分代码
init() {
  if (this.brid) {
    let url = window.config.baseConfig.socketUrl + this.brid
    this.webSock = new WebSocket(url)
    this.webSock.onopen = this.webSockOpen
    this.webSock.onerror = this.webSocketError
    this.webSock.onmessage = this.webSocketMsg
    this.webSock.onclose = this.webSocketClose
  }
},
webSockOpen() {
  console.log('链接成功!')
},
webSocketMsg(evt) {
  try {
    let data = JSON.parse(evt.data), id = data.id, i = this.tempMsg[id]
    if (data.code === 1) {
      this.msgs[i].code = 1
    } else if (data.code === 2 && !i) {
      this.tempMsg[id] = true
      this.msgs.push(data)
      this.webSock.send(JSON.stringify({code: '3', id: id}))
    }
  } catch (e) {}
},
webSocketError(e) {
  console.error(e)
},
webSocketClose() {
  console.warn('关闭webSock')
},
send(val) {
  let id = this.brid + new Date().getTime(), data = {
    code: '0',
    id: id,
    from: this.brid,
    to: this.to,
    msg: this.value || val
  }
  this.webSock.send(JSON.stringify(data))
  this.$refs.input.innerHTML = ''
  this.value = ''
  this.tempMsg[id] = this.msgs.length
  this.msgs.push(data)
}
复制代码

接下来获取浏览器摄像头、麦克风以及获取数据流,须要注意的是浏览器兼容性this

navigator.mediaDevices.getUserMedia({
    //constraints
    video: true,
    audio: true
}).then(stream => {
    const video = document.querySelector('video');
    video.srcObject = stream;
}).catch(error => {
    alert('error: ', error)
})
复制代码

其中constraints 约束对象,咱们能够用来指定一些和媒体流有关的属性。好比指定是否获取某种流,指定视频流的宽高、帧率以及理想值,对于移动设备来讲,还能够指定获取前摄像头,或者后置摄像头。url

最后三者结合实现一个数据流的通讯,通讯大体流程以下:spa

一、发送方启动本地视频(获取浏览器摄像头、麦克风)并添加至通道中,发送视频邀请 {event: 'invite', to: '接收方id', type: '1'}code

二、如发送方在接收方以前取消电话,需通知对方已取消{event: 'cancle', to: '接收方id', type: '1'}视频

三、如接收方挂断了电话,需通知对方已经挂断电话{event: 'close', to: '接收方id', type: '1'}对象

四、若是接收方接听了电话,须要启动本地视频并添加至通道中(获取浏览器摄像头、麦克风)需回复发起方{event: 'reply', to: '接收方id', type: '1'}

5.当发起方收到reply后,发送iceCandidate,officeSdp

六、接收方会执行addIceCandidate(new RTCIceCandidate(JSON.parse(data.msg))),setRemoteDescription(new RTCSessionDescription(JSON.parse(data.msg))),而后在回复发起方answerSdp

七、发起方接收到answerSdp,执行setRemoteDescription(new RTCSessionDescription(JSON.parse(data.msg)))

部分实现代码

creatRTCPreeConnection() {
      // let iceServer = {iceServer: {'iceServers': [{'url': 'turn:172.16.113.146:3478', 'username': 'daiyao', 'credential': 'daiyao'}]}}
      let iceServer = {'iceServers': [{'url': 'stun:stun.voiparound.com'}]}
      this.cn = new RTCPeerConnection(iceServer)
      console.log(this.cn)
      this.cn.onaddstream = (event) => {
        if (this.isVideo) {
          document.getElementById('remoteVideo').srcObject = event.stream
        } else {
          document.getElementById('remoteAudio').srcObject = event.stream
        }
      }
    },
    video() {
      this.showTh = true
      let thObj = {
        event: 'invite',
        to: '2815718',
        // to: '4223',
        type: '1',
        tips: '发送视频邀请'
      }
      this.sendth(thObj)
    },
    sendth(val) {
      console.log(val)
      this.webSock.send(JSON.stringify(val))
    },
    dealVideoMsg(data) {
      if (data.event === 'invite') {
        this.isShow.invite = data.event
        this.showTh = true
        if (data.kind === 'audio') {
          this.isShow.media = 'video'
          this.isVideo = false
        }
        if (this.isOpen) {
          this.creatRTCPreeConnection()
          this.GetUserMedia(data.from, false)
          let thObj = {
            type: '1',
            event: 'reply',
            to: data.from,
            tips: '接收到' + data.from + '视频邀约,回复能够通话'
          }
          this.sendth(thObj)
          this.isShow.invite = null
          this.isShow.all = 'all'
        }
      } else if (data.event === 'reply') {
        this.isShow.reply = data.event
        this.creatRTCPreeConnection()
        this.sendCandidate(data.from)
        this.GetUserMedia(data.from, true)
      } else if (data.event === 'candidate') {
        this.cn.addIceCandidate(new RTCIceCandidate(JSON.parse(data.msg)))
      } else if (data.event === 'offerSdp') {
        this.cn.setRemoteDescription(new RTCSessionDescription(JSON.parse(data.msg)))
        this.createAnswer(data.from)
      } else if (data.event === 'answerSdp') {
        this.cn.setRemoteDescription(new RTCSessionDescription(JSON.parse(data.msg)))
      }
    },
    GetUserMedia(toUserId, isCaller) {
      navigator.webkitGetUserMedia({'audio': this.isAudio, 'video': this.isVideo},
        (stream) => {
          console.log(this.isVideo)
          if (this.isVideo) {
            console.log(this.isVideo)
            document.getElementById('localVideo').srcObject = stream
          } else {
            document.getElementById('localAudio').srcObject = stream
          }
          this.cn.addStream(stream)
          if (isCaller) {
            this.creatOf(toUserId)
          }
        }, (error) => {
          console.log('getUserMedia error: ' + error)
        }
      )
    },
    sendCandidate(toUserId) {
      console.log(this.cn)
      console.log(this.cn.onicecandidate)
      this.cn.onicecandidate = (event) => {
        console.log(event.candidate)
        if (event.candidate !== null) {
          var thObj = {
            type: '1',
            event: 'candidate',
            msg: event.candidate,
            to: toUserId,
            tips: '发送rtc候选人信息,进入可连线视频列表'
          }
          this.sendth(thObj)
        }
      }
    },
    creatOf(toUserId) {
      this.cn.createOffer((offerSdp) => {
        console.log('1')
        this.cn.setLocalDescription(offerSdp)
        var thObj = {
          type: '1',
          msg: offerSdp,
          event: 'offerSdp',
          to: toUserId,
          tips: 'offerSdp'
        }
        console.log('111')
        this.sendth(thObj)
      }, (error) => {
        console.log('Failure callback:' + error)
      })
    },
    createAnswer(toUserId) {
      this.cn.createAnswer((answerSdp) => {
        this.cn.setLocalDescription(answerSdp)
        var thObj = {
          type: '1',
          msg: answerSdp,
          event: 'answerSdp',
          to: toUserId,
          tips: 'answerSdp'
        }
        this.sendth(thObj)
      }, (error) => {
        console.log('Failure callback:' + error)
      })
    }
复制代码
相关文章
相关标签/搜索