feat: Updating WebRTC with camera-streamer signaling protocol (#1417)
This commit is contained in:
parent
9c3c56bd56
commit
b94840736f
@ -62,50 +62,15 @@ export default class WebrtcCameraStreamer extends Mixins(BaseMixin) {
|
|||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
get streamConfig() {
|
|
||||||
let config: any = {
|
|
||||||
sdpSemantics: 'unified-plan',
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.useStun) {
|
|
||||||
config.iceServers = [{ urls: ['stun:stun.l.google.com:19302'] }]
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
startStream() {
|
startStream() {
|
||||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
|
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
|
||||||
|
const requestIceServers = this.useStun ? [{ urls: ['stun:stun.l.google.com:19302'] }] : null
|
||||||
|
|
||||||
this.pc = new RTCPeerConnection(this.streamConfig)
|
// This WebRTC signaling pattern is designed for camera-streamer, a common webcam server the supports WebRTC.
|
||||||
this.pc.addTransceiver('video', { direction: 'recvonly' })
|
|
||||||
|
|
||||||
this.pc.addEventListener(
|
|
||||||
'track',
|
|
||||||
(evt) => {
|
|
||||||
if (evt.track.kind == 'video' && this.$refs.stream) {
|
|
||||||
// @ts-ignore
|
|
||||||
this.$refs.stream.srcObject = evt.streams[0]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
this.pc.addEventListener('connectionstatechange', () => {
|
|
||||||
this.status = (this.pc?.connectionState ?? '').toString()
|
|
||||||
|
|
||||||
if (['failed', 'disconnected'].includes(this.status)) {
|
|
||||||
setTimeout(async () => {
|
|
||||||
await this.pc?.close()
|
|
||||||
this.startStream()
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
fetch(this.url, {
|
fetch(this.url, {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
type: 'request',
|
type: 'request',
|
||||||
//res: params.res
|
iceServers: requestIceServers,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@ -114,25 +79,58 @@ export default class WebrtcCameraStreamer extends Mixins(BaseMixin) {
|
|||||||
})
|
})
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((answer) => {
|
.then((answer) => {
|
||||||
|
let peerConnectionConfig: any = {
|
||||||
|
sdpSemantics: 'unified-plan',
|
||||||
|
}
|
||||||
|
// It's important to set any ICE servers returned, which could include servers we requested or servers
|
||||||
|
// setup by the server. But note that older versions of camera-streamer won't return this property.
|
||||||
|
if (answer.iceServers) {
|
||||||
|
peerConnectionConfig.iceServers = answer.iceServers
|
||||||
|
}
|
||||||
|
this.pc = new RTCPeerConnection(peerConnectionConfig)
|
||||||
|
this.pc.addTransceiver('video', { direction: 'recvonly' })
|
||||||
|
this.pc.addEventListener(
|
||||||
|
'track',
|
||||||
|
(evt) => {
|
||||||
|
if (evt.track.kind == 'video' && this.$refs.stream) {
|
||||||
|
// @ts-ignore
|
||||||
|
this.$refs.stream.srcObject = evt.streams[0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false
|
||||||
|
)
|
||||||
|
this.pc.addEventListener('connectionstatechange', () => {
|
||||||
|
this.status = (this.pc?.connectionState ?? '').toString()
|
||||||
|
if (['failed', 'disconnected'].includes(this.status)) {
|
||||||
|
setTimeout(async () => {
|
||||||
|
await this.pc?.close()
|
||||||
|
this.startStream()
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.pc.addEventListener('icecandidate', (e) => {
|
||||||
|
if (e.candidate) {
|
||||||
|
return fetch(this.url, {
|
||||||
|
body: JSON.stringify({
|
||||||
|
type: 'remote_candidate',
|
||||||
|
id: this.remote_pc_id,
|
||||||
|
candidates: [e.candidate],
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
}).catch(function (error) {
|
||||||
|
window.console.error(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
this.remote_pc_id = answer.id
|
this.remote_pc_id = answer.id
|
||||||
return this.pc?.setRemoteDescription(answer)
|
return this.pc?.setRemoteDescription(answer)
|
||||||
})
|
})
|
||||||
.then(() => this.pc?.createAnswer())
|
.then(() => this.pc?.createAnswer())
|
||||||
.then((answer) => this.pc?.setLocalDescription(answer))
|
.then((answer) => this.pc?.setLocalDescription(answer))
|
||||||
.then(() => {
|
|
||||||
// wait for ICE gathering to complete
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const checkState = () => {
|
|
||||||
if (this.pc?.iceGatheringState === 'complete') {
|
|
||||||
this.pc?.removeEventListener('icegatheringstatechange', checkState)
|
|
||||||
resolve(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.pc?.iceGatheringState === 'complete') resolve(true)
|
|
||||||
else this.pc?.addEventListener('icegatheringstatechange', checkState)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const offer = this.pc?.localDescription
|
const offer = this.pc?.localDescription
|
||||||
return fetch(this.url, {
|
return fetch(this.url, {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user