/*
Phaneron - Clustered, accelerated and cloud-fit video server, pre-assembled and in kit form.
Copyright (C) 2020 Streampunk Media Ltd.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
https://www.streampunk.media/ mailto:furnace@streampunk.media
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
*/
import { ProducerFactory, Producer, InvalidProducerError } from './producer'
import { chanLayerFromString } from '../chanLayer'
import { channels } from '../index'
import { RedioPipe, RedioEnd, isValue, Valve } from 'redioactive'
import { clContext as nodenCLContext, OpenCLBuffer } from 'nodencl'
import { Frame } from 'beamcoder'
import { ClJobs } from '../clJobQueue'
import { LoadParams } from '../chanLayer'
import { VideoFormat } from '../config'
import { Mixer } from './mixer'
import { SourcePipes } from '../routeSource'
export class RouteProducer implements Producer {
private readonly sourceID: string
private readonly params: LoadParams
private readonly clContext: nodenCLContext
private readonly clJobs: ClJobs
private readonly consumerFormat: VideoFormat
private readonly mixer: Mixer
private audSource: RedioPipe | undefined
private vidSource: RedioPipe | undefined
private srcFormat: VideoFormat | undefined
private numForks = 0
constructor(
id: number,
params: LoadParams,
context: nodenCLContext,
clJobs: ClJobs,
consumerFormat: VideoFormat
) {
this.sourceID = `P${id} ${params.url} L${params.layer}`
this.params = params
this.clContext = context
this.clJobs = clJobs
this.consumerFormat = consumerFormat
this.mixer = new Mixer(this.clContext, this.consumerFormat, this.clJobs)
if (this.params.url.slice(0, 5) !== 'ROUTE')
throw new InvalidProducerError('Route producer supports route command')
}
async initialise(): Promise {
const routeIndex = this.params.url.indexOf('://')
if (routeIndex < 0) throw new Error('Route producer failed to find route source in parameters')
const chanLayer = chanLayerFromString(this.params.url.substr(routeIndex + 3))
if (!chanLayer.valid)
throw new Error(
`Route producer failed to parse channel and layer from params ${this.params.url.substr(
routeIndex + 3
)}`
)
const channel = channels[chanLayer.channel - 1]
if (!channel)
throw new Error(`Route producer failed to find source of channel ${chanLayer.channel}`)
const srcPipes = await channel.getRoutePipes(chanLayer.layer)
this.audSource = srcPipes.audio
const vidForkRef: Valve = async (frame) => {
if (isValue(frame)) {
for (let f = 0; f < this.numForks; ++f) frame.addRef()
return frame
} else {
return frame
}
}
this.vidSource = srcPipes.video.valve(vidForkRef)
this.srcFormat = srcPipes.format
await this.mixer.init(
this.sourceID,
this.audSource.fork(),
this.vidSource.fork(),
this.srcFormat
)
console.log(`Created Route producer from channel ${chanLayer.channel}`)
}
async getSourcePipes(): Promise {
if (!(this.audSource && this.vidSource && this.srcFormat))
throw new Error(`Route producer failed to find source pipes for route`)
this.numForks++
return Promise.resolve({
audio: this.audSource.fork(),
video: this.vidSource.fork(),
format: this.srcFormat
})
}
getMixer(): Mixer {
return this.mixer
}
setPaused(pause: boolean): void {
this.mixer.setPaused(pause)
}
release(): void {
this.mixer.release()
}
}
export class RouteProducerFactory implements ProducerFactory {
private clContext: nodenCLContext
constructor(clContext: nodenCLContext) {
this.clContext = clContext
}
createProducer(
id: number,
params: LoadParams,
clJobs: ClJobs,
consumerFormat: VideoFormat
): RouteProducer {
return new RouteProducer(id, params, this.clContext, clJobs, consumerFormat)
}
}