remove baresip for now, use ices2
This commit is contained in:
parent
3409fb8ab8
commit
333146a182
10 changed files with 123 additions and 20 deletions
|
|
@ -12,13 +12,15 @@ async function main () {
|
||||||
port: 3030,
|
port: 3030,
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
input: 'alsa:default',
|
input: 'alsa:default',
|
||||||
output: 'alsa:default'
|
output: 'alsa:default',
|
||||||
|
dev: false
|
||||||
},
|
},
|
||||||
alias: {
|
alias: {
|
||||||
p: 'port',
|
p: 'port',
|
||||||
h: 'host',
|
h: 'host',
|
||||||
i: 'input',
|
i: 'input',
|
||||||
o: 'output'
|
o: 'output',
|
||||||
|
d: 'dev'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import { action, STREAM_STATUS, LOG_MESSAGE } from './state.mjs'
|
||||||
export class Darkice {
|
export class Darkice {
|
||||||
constructor (opts = {}) {
|
constructor (opts = {}) {
|
||||||
this.command = opts.command || 'darkice'
|
this.command = opts.command || 'darkice'
|
||||||
this.config = opts.config || p.join(__dirname, 'etc', '..', 'darkice.cfg')
|
this.config = opts.config || p.join(__dirname, '..', 'etc', 'darkice.cfg')
|
||||||
this.logLevel = 5
|
this.logLevel = 8
|
||||||
this.stream = new Readable()
|
this.stream = new Readable()
|
||||||
this.log = []
|
this.log = []
|
||||||
this.stream.on('data', row => this.log.push(row))
|
this.stream.on('data', row => this.log.push(row))
|
||||||
|
|
|
||||||
61
backend/ices2.mjs
Normal file
61
backend/ices2.mjs
Normal file
|
|
@ -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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,17 +6,21 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": "bin.mjs",
|
"bin": "bin.mjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node bin.mjs"
|
"start": "node bin.mjs",
|
||||||
|
"dev": "node bin.mjs --dev"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baresip-wrapper": "^1.0.10",
|
"baresip-wrapper": "^1.0.10",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
|
"es-main": "^1.0.2",
|
||||||
"fastify": "^3.15.1",
|
"fastify": "^3.15.1",
|
||||||
"fastify-cors": "^6.0.1",
|
"fastify-cors": "^6.0.1",
|
||||||
|
"fastify-http-proxy": "^6.2.0",
|
||||||
"fastify-sse-v2": "^2.0.4",
|
"fastify-sse-v2": "^2.0.4",
|
||||||
"fastify-static": "^4.0.1",
|
"fastify-static": "^4.0.1",
|
||||||
"is-online": "^9.0.0",
|
"is-online": "^9.0.0",
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
|
"node-jsonrpc-client": "^1.0.4",
|
||||||
"split2": "^3.2.2",
|
"split2": "^3.2.2",
|
||||||
"streamx": "^2.10.3"
|
"streamx": "^2.10.3"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,10 @@ import { Transform, Readable } from 'streamx'
|
||||||
import fastifyStatic from 'fastify-static'
|
import fastifyStatic from 'fastify-static'
|
||||||
import fastifyCors from 'fastify-cors'
|
import fastifyCors from 'fastify-cors'
|
||||||
import fastifySSE from 'fastify-sse-v2'
|
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 { Baresip } from './baresip.mjs'
|
||||||
import { AlsaMeter } from './lib/ffmpeg-meter.mjs'
|
import { AlsaMeter } from './lib/ffmpeg-meter.mjs'
|
||||||
import { ConnectivityCheck } from './lib/is-online.mjs'
|
import { ConnectivityCheck } from './lib/is-online.mjs'
|
||||||
|
|
@ -26,7 +28,9 @@ function deviceToFFMPEG (device) {
|
||||||
export async function run (config = {}) {
|
export async function run (config = {}) {
|
||||||
const app = fastify()
|
const app = fastify()
|
||||||
const darkice = new Darkice()
|
const darkice = new Darkice()
|
||||||
const baresip = new Baresip()
|
const baresip = new Baresip({
|
||||||
|
destination: 901
|
||||||
|
})
|
||||||
const isOnline = new ConnectivityCheck()
|
const isOnline = new ConnectivityCheck()
|
||||||
|
|
||||||
const meter = new AlsaMeter({
|
const meter = new AlsaMeter({
|
||||||
|
|
@ -57,10 +61,18 @@ export async function run (config = {}) {
|
||||||
// const state = new StateContainer(reducer, INITIAL_STATE)
|
// const state = new StateContainer(reducer, INITIAL_STATE)
|
||||||
// state.ingestActionStream(actions)
|
// state.ingestActionStream(actions)
|
||||||
|
|
||||||
app.register(fastifyStatic, {
|
|
||||||
root: p.join(__dirname, '..', 'frontend', 'dist'),
|
if (config.dev) {
|
||||||
prefix: '/'
|
app.register(fastifyProxy, {
|
||||||
})
|
upstream: 'http://localhost:3000',
|
||||||
|
prefix: '/'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
app.register(fastifyStatic, {
|
||||||
|
root: p.join(__dirname, '..', 'frontend', 'dist'),
|
||||||
|
prefix: '/'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
app.register(fastifyCors, {
|
app.register(fastifyCors, {
|
||||||
origin: '*'
|
origin: '*'
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export const INITIAL_STATE = {
|
||||||
pings: 0,
|
pings: 0,
|
||||||
meter: {},
|
meter: {},
|
||||||
connectionState: { connected: false, error: null },
|
connectionState: { connected: false, error: null },
|
||||||
connectivity: { internet: false }
|
connectivity: { internet: false },
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reducer (state, event) {
|
export function reducer (state, event) {
|
||||||
|
|
@ -32,14 +32,15 @@ export function reducer (state, event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (action === STREAM_STATUS) {
|
if (action === STREAM_STATUS) {
|
||||||
const { id, status } = data
|
const { id, status, url } = data
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
streams: {
|
streams: {
|
||||||
...(state.streams || {}),
|
...(state.streams || {}),
|
||||||
[id]: {
|
[id]: {
|
||||||
...state.streams[id],
|
...state.streams[id],
|
||||||
status
|
status,
|
||||||
|
url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ function App () {
|
||||||
</div>
|
</div>
|
||||||
<div className='App-main'>
|
<div className='App-main'>
|
||||||
<StreamControl id='darkice' state={state} />
|
<StreamControl id='darkice' state={state} />
|
||||||
<StreamControl id='baresip' state={state} />
|
{/* <StreamControl id='baresip' state={state} /> */}
|
||||||
</div>
|
</div>
|
||||||
<div className='App-side'>
|
<div className='App-side'>
|
||||||
<Meters value={state.meter} />
|
<Meters value={state.meter} />
|
||||||
|
|
@ -69,7 +69,9 @@ function Meters (props) {
|
||||||
function StreamControl (props = {}) {
|
function StreamControl (props = {}) {
|
||||||
const { id = 'darkice', state = {} } = props
|
const { id = 'darkice', state = {} } = props
|
||||||
const command = useCommand()
|
const command = useCommand()
|
||||||
const status = (state && state.streams && state.streams[id]) ? state.streams[id].status : 'stopped'
|
const stream = state && state.streams && state.streams[id]
|
||||||
|
const status = (stream && stream.status) || 'stopped'
|
||||||
|
const url = (stream && stream.url) || JSON.stringify(stream)
|
||||||
const disabled = command.pending || status === 'unknown'
|
const disabled = command.pending || status === 'unknown'
|
||||||
let label
|
let label
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
|
@ -84,6 +86,10 @@ function StreamControl (props = {}) {
|
||||||
<ToggleButton active={active} disabled={disabled} onClick={onClick}>
|
<ToggleButton active={active} disabled={disabled} onClick={onClick}>
|
||||||
{label}
|
{label}
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
|
<div className='StreamControl-url'>
|
||||||
|
<h4>Stream address</h4>
|
||||||
|
{url && <code>{url}</code>}
|
||||||
|
</div>
|
||||||
<Log messages={state.log[id]} />
|
<Log messages={state.log[id]} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,14 @@
|
||||||
.StreamControl {
|
.StreamControl {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
/* width: 200px; */
|
//width: 250px;
|
||||||
|
width: 100%;
|
||||||
|
.StreamControl-url {
|
||||||
|
code {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.Meters {
|
.Meters {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
@ -94,6 +101,7 @@
|
||||||
|
|
||||||
.StatusBar {
|
.StatusBar {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
padding: 1rem;
|
||||||
> * {
|
> * {
|
||||||
display: block;
|
display: block;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ export function useRemoteState (opts = {}) {
|
||||||
dispatch(action)
|
dispatch(action)
|
||||||
}
|
}
|
||||||
eventSource.onerror = () => {
|
eventSource.onerror = () => {
|
||||||
console.log('ONERROR!!')
|
|
||||||
dispatch(action(CONNECTION_STATE, { error: `Failed to connect to backend` }))
|
dispatch(action(CONNECTION_STATE, { error: `Failed to connect to backend` }))
|
||||||
if (retryInterval) setTimeout(reconnect, retryInterval)
|
if (retryInterval) setTimeout(reconnect, retryInterval)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
package.json
14
package.json
|
|
@ -1,8 +1,18 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": ["backend", "frontend", "common"],
|
"workspaces": [
|
||||||
|
"backend",
|
||||||
|
"frontend",
|
||||||
|
"common"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cd frontend && yarn build",
|
"build": "cd frontend && yarn build",
|
||||||
"start": "cd backend && yarn start"
|
"start": "cd backend && yarn start",
|
||||||
|
"dev": "concurrently npm:dev:*",
|
||||||
|
"dev:backend": "cd backend && yarn dev",
|
||||||
|
"dev:frontend": "cd frontend && yarn dev"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"concurrently": "^6.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue