mirror of
https://github.com/tsightler/ring-mqtt.git
synced 2025-09-26 21:01:12 +08:00

* Use MQTT for start-stream debug messages * Fix ANSI colors * Refactor event URL management * Fix subscription detection * Improve event URL expiry handling by parsing Amazon S3 expire time * Convert to ESM/replace colors with chalk * Force colors for chalk * Migrate to ESM * Fix stop of keepalive stream * Add transcoded event selections * Update event URL on raw/trancoded toggle * Switch to per-camera livecall threads * Customized WebRTC functions Mostly copied from ring-client-api with port to pure Javascript, removal of unneeded features and additional debugging modified for use as worker thread with ring-mqtt. Allows easier testing with updated Werift versions. * Add nightlight enable/disable * Include nightlight state as attribute * Only pro versions have nightlight * Tweak battery level reporting for dual battery cameras * Release 5.1.0
97 lines
2.8 KiB
JavaScript
97 lines
2.8 KiB
JavaScript
// This code is largely copied from ring-client-api, but converted from Typescript
|
|
// to straight Javascript and some code not required for ring-mqtt removed.
|
|
// Much thanks to @dgreif for the original code which is the basis for this work.
|
|
|
|
import { WeriftPeerConnection } from './peer-connection.js'
|
|
import { Subscribed } from './subscribed.js'
|
|
import { fromEvent, ReplaySubject } from 'rxjs'
|
|
import { concatMap } from 'rxjs/operators'
|
|
|
|
export class StreamingConnectionBase extends Subscribed {
|
|
constructor(ws) {
|
|
super()
|
|
this.ws = ws
|
|
this.onCallAnswered = new ReplaySubject(1)
|
|
this.onCallEnded = new ReplaySubject(1)
|
|
this.onMessage = new ReplaySubject()
|
|
this.hasEnded = false
|
|
const pc = new WeriftPeerConnection()
|
|
this.pc = pc
|
|
this.onAudioRtp = pc.onAudioRtp
|
|
this.onVideoRtp = pc.onVideoRtp
|
|
this.onWsOpen = fromEvent(this.ws, 'open')
|
|
const onMessage = fromEvent(this.ws, 'message')
|
|
const onError = fromEvent(this.ws, 'error')
|
|
const onClose = fromEvent(this.ws, 'close')
|
|
|
|
this.addSubscriptions(
|
|
onMessage.pipe(concatMap((event) => {
|
|
const message = JSON.parse(event.data)
|
|
this.onMessage.next(message)
|
|
return this.handleMessage(message)
|
|
})).subscribe(),
|
|
|
|
onError.subscribe((e) => {
|
|
this.callEnded()
|
|
}),
|
|
|
|
onClose.subscribe(() => {
|
|
this.callEnded()
|
|
}),
|
|
|
|
this.pc.onConnectionState.subscribe((state) => {
|
|
if (state === 'failed') {
|
|
this.callEnded()
|
|
}
|
|
if (state === 'closed') {
|
|
this.callEnded()
|
|
}
|
|
})
|
|
)
|
|
}
|
|
|
|
activate() {
|
|
// the activate_session message is required to keep the stream alive longer than 70 seconds
|
|
this.sendSessionMessage('activate_session')
|
|
this.sendSessionMessage('stream_options', {
|
|
audio_enabled: true,
|
|
video_enabled: true,
|
|
})
|
|
}
|
|
|
|
sendMessage(message) {
|
|
if (this.hasEnded) {
|
|
return
|
|
}
|
|
this.ws.send(JSON.stringify(message))
|
|
}
|
|
|
|
callEnded() {
|
|
if (this.hasEnded) {
|
|
return
|
|
}
|
|
try {
|
|
this.sendMessage({
|
|
reason: { code: 0, text: '' },
|
|
method: 'close',
|
|
})
|
|
this.ws.close()
|
|
}
|
|
catch (_) {
|
|
// ignore any errors since we are stopping the call
|
|
}
|
|
this.hasEnded = true
|
|
this.unsubscribe()
|
|
this.onCallEnded.next()
|
|
this.pc.close()
|
|
}
|
|
|
|
stop() {
|
|
this.callEnded()
|
|
}
|
|
|
|
requestKeyFrame() {
|
|
this.pc.requestKeyFrame?.()
|
|
}
|
|
}
|