import type { Readable } from 'node:stream' ; import prism from 'prism-media' ; /**
 * This module creates a Transformer Graph to figure out what the most efficient way
 * of transforming the input stream into something playable would be.
 */ const FFMPEG_PCM_ARGUMENTS = [ '-analyzeduration' , '0' , '-loglevel' , '0' , '-f' , 's16le' , '-ar' , '48000' , '-ac' , '2' ] ; const FFMPEG_OPUS_ARGUMENTS = [ '-analyzeduration' , '0' , '-loglevel' , '0' , '-acodec' , 'libopus' , '-f' , 'opus' , '-ar' , '48000' , '-ac' , '2' , ] ; remarks export enum StreamType { Arbitrary = 'arbitrary' , Raw = 'raw' , OggOpus = 'ogg/opus' , WebmOpus = 'webm/opus' , Opus = 'opus' } /**
 * The different types of transformers that can exist within the pipeline.
 */ export enum TransformerType { FFmpegPCM = 'ffmpeg pcm' , FFmpegOgg = 'ffmpeg ogg' , OpusEncoder = 'opus encoder' , OpusDecoder = 'opus decoder' , OggOpusDemuxer = 'ogg/opus demuxer' , WebmOpusDemuxer = 'webm/opus demuxer' , InlineVolume = 'volume transformer' } /**
 * Represents a pathway from one stream type to another using a transformer.
 */ export interface Edge { from : Node ; to : Node ; cost : number ; transformer : ( input : string | Readable ) => Readable ; type : TransformerType ; } /**
 * Represents a type of stream within the graph, e.g. an Opus stream, or a stream of raw audio.
 */ export class Node { /**
     * The outbound edges from this node.
     */ public readonly edges : Edge [ ] = [ ] ; /**
     * The type of stream for this node.
     */ public readonly type : StreamType ; public constructor ( type ) { this . type = type ; } param edge public addEdge ( edge ) { this . edges . push ( { ... edge , from : this } ) ; } } const NODES = new Map < StreamType , Node > ( ) ; for ( const streamType of Object . values ( StreamType ) ) { NODES . set ( streamType , new Node ( streamType ) ) ; } param type export function getNode ( type ) { const node = NODES . get ( type ) ; if ( ! node ) throw new Error ( `Node type '${ type }' does not exist!` ) ; return node ; } getNode ( StreamType . Raw ) . addEdge ( { type : TransformerType . OpusEncoder , to : getNode ( StreamType . Opus ) , cost : 1.5 , transformer : ( ) => new prism . opus . Encoder ( { rate : 48000 , channels : 2 , frameSize : 960 } ) , } ) ; getNode ( StreamType . Opus ) . addEdge ( { type : TransformerType . OpusDecoder , to : getNode ( StreamType . Raw ) , cost : 1.5 , transformer : ( ) => new prism . opus . Decoder ( { rate : 48000 , channels : 2 , frameSize : 960 } ) , } ) ; getNode ( StreamType . OggOpus ) . addEdge ( { type : TransformerType . OggOpusDemuxer , to : getNode ( StreamType . Opus ) , cost : 1 , transformer : ( ) => new prism . opus . OggDemuxer ( ) , } ) ; getNode ( StreamType . WebmOpus ) . addEdge ( { type : TransformerType . WebmOpusDemuxer , to : getNode ( StreamType . Opus ) , cost : 1 , transformer : ( ) => new prism . opus . WebmDemuxer ( ) , } ) ; const FFMPEG_PCM_EDGE = { type : TransformerType . FFmpegPCM , to : getNode ( StreamType . Raw ) , cost : 2 , transformer : ( input ) => new prism . FFmpeg ( { args : typeof input === 'string' ? [ '-i' , input , ... FFMPEG_PCM_ARGUMENTS ] : FFMPEG_PCM_ARGUMENTS , } ) , } ; getNode ( StreamType . Arbitrary ) . addEdge ( FFMPEG_PCM_EDGE ) ; getNode ( StreamType . OggOpus ) . addEdge ( FFMPEG_PCM_EDGE ) ; getNode ( StreamType . WebmOpus ) . addEdge ( FFMPEG_PCM_EDGE ) ; getNode ( StreamType . Raw ) . addEdge ( { type : TransformerType . InlineVolume , to : getNode ( StreamType . Raw ) , cost : 0.5 , transformer : ( ) => new prism . VolumeTransformer ( { type : 's16le' } ) , } ) ; function canEnableFFmpegOptimizations ( ) { try { return prism . FFmpeg . getInfo ( ) . output . includes ( '--enable-libopus' ) ; } catch { } return false ; } if ( canEnableFFmpegOptimizations ( ) ) { const FFMPEG_OGG_EDGE = { type : TransformerType . FFmpegOgg , to : getNode ( StreamType . OggOpus ) , cost : 2 , transformer : ( input ) => new prism . FFmpeg ( { args : typeof input === 'string' ? [ '-i' , input , ... FFMPEG_OPUS_ARGUMENTS ] : FFMPEG_OPUS_ARGUMENTS , } ) , } ; getNode ( StreamType . Arbitrary ) . addEdge ( FFMPEG_OGG_EDGE ) ; getNode ( StreamType . OggOpus ) . addEdge ( FFMPEG_OGG_EDGE ) ; getNode ( StreamType . WebmOpus ) . addEdge ( FFMPEG_OGG_EDGE ) ; } /**
 * Represents a step in the path from node A to node B.
 */ interface Step { /**
     * The next step.
     */ next ? : Step ; /**
     * The cost of the steps after this step.
     */ cost : number ; /**
     * The edge associated with this step.
     */ edge ? : Edge ; } param from param constraints param goal param path param depth function findPath ( from , constraints , goal = getNode ( StreamType . Opus ) , path = [ ] , depth = 5 ) { if ( from === goal && constraints ( path ) ) { return { cost : 0 } ; } else if ( depth === 0 ) { return { cost : Infinity } ; } let currentBest = undefined ; for ( const edge of from . edges ) { if ( currentBest && edge . cost > currentBest . cost ) continue ; const next = findPath ( edge . to , constraints , goal , [ ... path , edge ] , depth - 1 ) ; const cost = edge . cost + next . cost ; if ( ! currentBest || cost < currentBest . cost ) { currentBest = { cost , edge , next } ; } } return currentBest ?? { cost : Infinity } ; } param step function constructPipeline ( step ) { const edges = [ ] ; let current = step ; while ( current ?. edge ) { edges . push ( current . edge ) ; current = current . next ; } return edges ; } param from param constraint export function findPipeline ( from , constraint ) { return constructPipeline ( findPath ( getNode ( from ) , constraint ) ) ; }