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)
})
}
複製代碼