diff --git a/backend/bin.mjs b/backend/bin.mjs index 1289135..7ecbb63 100755 --- a/backend/bin.mjs +++ b/backend/bin.mjs @@ -12,13 +12,15 @@ async function main () { port: 3030, host: '0.0.0.0', input: 'alsa:default', - output: 'alsa:default' + output: 'alsa:default', + dev: false }, alias: { p: 'port', h: 'host', i: 'input', - o: 'output' + o: 'output', + d: 'dev' } }) diff --git a/backend/darkice.mjs b/backend/darkice.mjs index 2c93395..2df007a 100644 --- a/backend/darkice.mjs +++ b/backend/darkice.mjs @@ -11,8 +11,8 @@ import { action, STREAM_STATUS, LOG_MESSAGE } from './state.mjs' export class Darkice { constructor (opts = {}) { this.command = opts.command || 'darkice' - this.config = opts.config || p.join(__dirname, 'etc', '..', 'darkice.cfg') - this.logLevel = 5 + this.config = opts.config || p.join(__dirname, '..', 'etc', 'darkice.cfg') + this.logLevel = 8 this.stream = new Readable() this.log = [] this.stream.on('data', row => this.log.push(row)) diff --git a/backend/ices2.mjs b/backend/ices2.mjs new file mode 100644 index 0000000..7a0661e --- /dev/null +++ b/backend/ices2.mjs @@ -0,0 +1,61 @@ +import p from 'path' +import split2 from 'split2' +import { Readable } from 'streamx' +import { spawn } from 'child_process' +import { fileURLToPath } from 'url'; + +const __dirname = p.dirname(fileURLToPath(import.meta.url)) + +import { action, STREAM_STATUS, LOG_MESSAGE } from './state.mjs' + +export class Darkice { + constructor (opts = {}) { + this.command = opts.command || 'ices2' + this.config = opts.config || p.join(__dirname, '..', 'etc', 'ices2.xml') + this.logLevel = 8 + this.stream = new Readable() + this.log = [] + this.stream.on('data', row => this.log.push(row)) + this.id = 'darkice' + this.url = 'https://stream.rdl.de/rdl_ob1.ogg' + } + + restart () { + if (!this.process) return this.start() + this.process.once('close', () => { + process.nextTick(() => { + this.start() + }) + }) + this.stop() + } + + stop () { + this.process.kill() + } + + start () { + if (this.process) return + const args = [this.config] + this.process = spawn(this.command, args) + this.process.stdout.pipe(split2()).on('data', message => { + this.stream.push(action(LOG_MESSAGE, { id: this.id, type: 'stdout', message })) + // this.stream.push({ type: 'stdout', data }) + }) + this.process.stderr.pipe(split2()).on('data', message => { + this.stream.push(action(LOG_MESSAGE, { id: this.id, type: 'stdout', message })) + // this.stream.push({ type: 'stderr', data }) + }) + + this.process.on('close', () => { + this.stream.push(action(STREAM_STATUS, { id: this.id, status: 'stopped', url: this.url })) + this.process = null + }) + + this.stream.push(action(STREAM_STATUS, { id: this.id, status: 'started', url: this.url })) + + return new Promise((resolve, reject) => { + resolve() + }) + } +} diff --git a/backend/package.json b/backend/package.json index e3188b8..40b0f84 100644 --- a/backend/package.json +++ b/backend/package.json @@ -6,17 +6,21 @@ "license": "MIT", "bin": "bin.mjs", "scripts": { - "start": "node bin.mjs" + "start": "node bin.mjs", + "dev": "node bin.mjs --dev" }, "dependencies": { "baresip-wrapper": "^1.0.10", "debug": "^4.3.1", + "es-main": "^1.0.2", "fastify": "^3.15.1", "fastify-cors": "^6.0.1", + "fastify-http-proxy": "^6.2.0", "fastify-sse-v2": "^2.0.4", "fastify-static": "^4.0.1", "is-online": "^9.0.0", "minimist": "^1.2.5", + "node-jsonrpc-client": "^1.0.4", "split2": "^3.2.2", "streamx": "^2.10.3" }, diff --git a/backend/server.mjs b/backend/server.mjs index 90cc187..37e7f18 100644 --- a/backend/server.mjs +++ b/backend/server.mjs @@ -9,8 +9,10 @@ import { Transform, Readable } from 'streamx' import fastifyStatic from 'fastify-static' import fastifyCors from 'fastify-cors' import fastifySSE from 'fastify-sse-v2' +import fastifyProxy from 'fastify-http-proxy' -import { Darkice } from './darkice.mjs' +//import { Darkice } from './darkice.mjs' +import { Darkice } from './ices2.mjs' import { Baresip } from './baresip.mjs' import { AlsaMeter } from './lib/ffmpeg-meter.mjs' import { ConnectivityCheck } from './lib/is-online.mjs' @@ -26,7 +28,9 @@ function deviceToFFMPEG (device) { export async function run (config = {}) { const app = fastify() const darkice = new Darkice() - const baresip = new Baresip() + const baresip = new Baresip({ + destination: 901 + }) const isOnline = new ConnectivityCheck() const meter = new AlsaMeter({ @@ -57,10 +61,18 @@ export async function run (config = {}) { // const state = new StateContainer(reducer, INITIAL_STATE) // state.ingestActionStream(actions) - app.register(fastifyStatic, { - root: p.join(__dirname, '..', 'frontend', 'dist'), - prefix: '/' - }) + + if (config.dev) { + app.register(fastifyProxy, { + upstream: 'http://localhost:3000', + prefix: '/' + }) + } else { + app.register(fastifyStatic, { + root: p.join(__dirname, '..', 'frontend', 'dist'), + prefix: '/' + }) + } app.register(fastifyCors, { origin: '*' diff --git a/common/state.mjs b/common/state.mjs index 6aae066..084befb 100644 --- a/common/state.mjs +++ b/common/state.mjs @@ -17,7 +17,7 @@ export const INITIAL_STATE = { pings: 0, meter: {}, connectionState: { connected: false, error: null }, - connectivity: { internet: false } + connectivity: { internet: false }, } export function reducer (state, event) { @@ -32,14 +32,15 @@ export function reducer (state, event) { } } if (action === STREAM_STATUS) { - const { id, status } = data + const { id, status, url } = data return { ...state, streams: { ...(state.streams || {}), [id]: { ...state.streams[id], - status + status, + url } } } diff --git a/frontend/src/app.jsx b/frontend/src/app.jsx index 99ca391..38d2a68 100644 --- a/frontend/src/app.jsx +++ b/frontend/src/app.jsx @@ -14,7 +14,7 @@ function App () {
{url}}
+