Files
ring-mqtt/lib/go2rtc.js
tsightler b8338e30de Release 5.1.0 (#537)
* 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
2023-02-02 20:59:09 -05:00

109 lines
4.1 KiB
JavaScript

import chalk from 'chalk'
import utils from './utils.js'
import { spawn } from 'child_process'
import readline from 'readline'
import yaml from 'js-yaml'
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import writeFileAtomic from 'write-file-atomic'
import debugModule from 'debug'
const debug = debugModule('ring-rtsp')
export default new class Go2RTC {
constructor() {
this.started = false
this.go2rtcProcess = false
}
async init(cameras) {
this.started = true
debug(chalk.green('-'.repeat(90)))
debug('Creating go2rtc configuration and starting go2rtc process...')
const configFile = (process.env.RUNMODE === 'standard')
? dirname(fileURLToPath(new URL('.', import.meta.url)))+'/config/go2rtc.yaml'
: '/data/go2rtc.yaml'
let config = {
log: {
level: "debug"
},
api: {
listen: ""
},
srtp: {
listen: ""
},
rtsp: {
listen: ":8554",
...(utils.config().livestream_user && utils.config().livestream_pass)
? {
username: utils.config().livestream_user,
password: utils.config().livestream_pass
} : {},
default_query: "video=h264&audio=aac&audio=opus"
}
}
if (cameras) {
config.streams = {}
for (const camera of cameras) {
config.streams[`${camera.deviceId}_live`] =
`exec:${dirname(fileURLToPath(new URL('.', import.meta.url)))}/scripts/start-stream.sh ${camera.deviceId} live ${camera.deviceTopic} {output}`
config.streams[`${camera.deviceId}_event`] =
`exec:${dirname(fileURLToPath(new URL('.', import.meta.url)))}/scripts/start-stream.sh ${camera.deviceId} event ${camera.deviceTopic} {output}`
}
try {
await writeFileAtomic(configFile, yaml.dump(config, { lineWidth: -1 }))
debug('Successfully wrote go2rtc configuration file: '+configFile)
} catch (err) {
debug(chalk.red('Failed to write go2rtc configuration file: '+configFile))
debug(err.message)
}
}
this.go2rtcProcess = spawn('go2rtc', ['-config', configFile], {
env: process.env, // set env vars
cwd: '.', // set cwd
stdio: 'pipe' // forward stdio options
})
this.go2rtcProcess.on('spawn', async () => {
debug('The go2rtc process was started successfully')
await utils.sleep(2) // Give the process a second to start the API server
debug(chalk.green('-'.repeat(90)))
})
this.go2rtcProcess.on('close', async () => {
await utils.sleep(1) // Delay to avoid spurious messages if shutting down
if (this.started !== 'shutdown') {
debug('The go2rtc process exited unexpectedly, will restart in 5 seconds...')
this.go2rtcProcess.kill(9) // Sometimes rtsp-simple-server crashes and doesn't exit completely, try to force kill it
await utils.sleep(5)
this.init()
}
})
const stdoutLine = readline.createInterface({ input: this.go2rtcProcess.stdout })
stdoutLine.on('line', (line) => {
// Replace time in go2rtc log messages with tag
debug(line.replace(/^.*\d{2}:\d{2}:\d{2}\.\d{3}([^\s]+) /, chalk.green('[go2rtc] ')))
})
const stderrLine = readline.createInterface({ input: this.go2rtcProcess.stderr })
stderrLine.on('line', (line) => {
// Replace time in go2rtc log messages with tag
debug(line.replace(/^.*\d{2}:\d{2}:\d{2}\.\d{3}([^\s]+) /, '[go2rtc] '))
})
}
shutdown() {
this.started = 'shutdown'
if (this.go2rtcProcess) {
this.go2rtcProcess.kill()
this.go2rtcProcess = false
}
return
}
}