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)
      })
    }
複製代碼
相關文章
相關標籤/搜索