/* 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 { clContext as nodenCLContext, OpenCLBuffer } from 'nodencl' import { MacadamConsumerFactory } from './macadamConsumer' import { ScreenConsumerFactory } from './screenConsumer' import { FFmpegConsumerFactory } from './ffmpegConsumer' import { RedioPipe, RedioEnd } from 'redioactive' import { Frame } from 'beamcoder' import { Channel } from '../channel' import { ConfigParams, VideoFormat, DeviceConfig, ConsumerConfig } from '../config' import { ClJobs } from '../clJobQueue' export interface Consumer { initialise(): Promise connect(mixAudio: RedioPipe, mixVideo: RedioPipe): void } export interface ConsumerFactory { createConsumer( chanID: string, params: ConfigParams, format: VideoFormat, device: DeviceConfig, clJobs: ClJobs ): T } export class ConsumerRegistry { private readonly consumerFactories: Map> private readonly consumers: Map private readonly chanIDs: Map private readonly formats: Map private consumerIndex = 0 constructor(clContext: nodenCLContext) { this.consumerFactories = new Map() this.consumerFactories.set('decklink', new MacadamConsumerFactory(clContext)) this.consumerFactories.set('screen', new ScreenConsumerFactory(clContext)) this.consumerFactories.set('ffmpeg', new FFmpegConsumerFactory(clContext)) this.consumers = new Map() this.chanIDs = new Map() this.formats = new Map() } createConsumer( chanNum: number, consumerIndex: number, params: ConfigParams, device: DeviceConfig, clJobs: ClJobs ): Consumer { if (this.consumers.get(consumerIndex)) throw new Error( `${device.name} consumer device ${device.deviceIndex} consumerIndex ${consumerIndex} is already registered` ) if (consumerIndex === -1) consumerIndex = this.consumerIndex++ const factory = this.consumerFactories.get(device.name.toLowerCase()) if (!factory) throw new Error(`device name '${device.name}' not recognised`) const chanID = this.chanIDs.get(chanNum) if (!chanID) throw new Error(`channel ID not registered`) const format = this.formats.get(chanNum) if (!format) throw new Error(`channel format not registered`) const consumer = factory.createConsumer( chanID, params, format, { name: device.name.toLowerCase(), deviceIndex: device.deviceIndex }, clJobs ) this.consumers.set(consumerIndex, consumer) return consumer } removeConsumer( chanNum: number, _channel: Channel, consumerIndex: number, params: ConfigParams ): void { const chanID = this.chanIDs.get(chanNum) if (!chanID) throw new Error(`Failed to remove consumer from channel ${chanNum} - channel not found`) const consumer = this.consumers.get(consumerIndex) if (consumer) { // channel.removeConsumer(consumer) // this.consumers.delete(consumerIndex) throw new Error(`Remove consumer not implemented`) } else if (Object.keys(params).length > 0) { console.log('Remove consumer with options', params) throw new Error(`Remove consumer by matching params not implemented`) } else throw new Error(`Failed to remove consumer - no consumerIndex and no parameters`) } createConsumers( chanNum: number, chanID: string, config: ConsumerConfig, clJobs: ClJobs ): Consumer[] { this.chanIDs.set(chanNum, chanID) this.formats.set(chanNum, config.format) return config.devices.map((device) => this.createConsumer(chanNum, this.consumerIndex++, {}, device, clJobs) ) } }