Skip to content

Commit

Permalink
refactor: Move getNode/canEnableFFmpegOptimizations into a lazy l…
Browse files Browse the repository at this point in the history
…oaded call (#9918)

* Move the getNode/canEnableFFMPEGOptimizations into a lazy loaded call the first time it's actually ever referenced

* PR feedback: Make initializeNodes return a map then nullably assign NODES, this removes an extra variable and cleans up the code

* chore: lint suggestion

Co-authored-by: Aura Román <kyradiscord@gmail.com>

* Use local map instead of recursive

* Run prettier

* Fix lint

---------

Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com>
Co-authored-by: Aura Román <kyradiscord@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Nov 6, 2023
1 parent ac64508 commit 637e1a4
Showing 1 changed file with 71 additions and 65 deletions.
136 changes: 71 additions & 65 deletions packages/voice/src/audio/TransformerGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,71 +101,19 @@ export class Node {
}

// Create a node for each stream type
const NODES = new Map<StreamType, Node>();
for (const streamType of Object.values(StreamType)) {
NODES.set(streamType, new Node(streamType));
}
let NODES: Map<StreamType, Node> | null = null;

/**
* Gets a node from its stream type.
*
* @param type - The stream type of the target node
*/
export function getNode(type: StreamType) {
const node = NODES.get(type);
const node = (NODES ??= initializeNodes()).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: 48_000, channels: 2, frameSize: 960 }),
});

getNode(StreamType.Opus).addEdge({
type: TransformerType.OpusDecoder,
to: getNode(StreamType.Raw),
cost: 1.5,
transformer: () => new prism.opus.Decoder({ rate: 48_000, 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: Omit<Edge, 'from'> = {
type: TransformerType.FFmpegPCM,
to: getNode(StreamType.Raw),
cost: 2,
transformer: (input) =>
new prism.FFmpeg({
args: ['-i', typeof input === 'string' ? input : '-', ...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' }),
});

// Try to enable FFmpeg Ogg optimizations
function canEnableFFmpegOptimizations(): boolean {
try {
Expand All @@ -175,22 +123,80 @@ function canEnableFFmpegOptimizations(): boolean {
return false;
}

if (canEnableFFmpegOptimizations()) {
const FFMPEG_OGG_EDGE: Omit<Edge, 'from'> = {
type: TransformerType.FFmpegOgg,
to: getNode(StreamType.OggOpus),
function initializeNodes(): Map<StreamType, Node> {
const nodes = new Map<StreamType, Node>();
for (const streamType of Object.values(StreamType)) {
nodes.set(streamType, new Node(streamType));
}

nodes.get(StreamType.Raw)!.addEdge({
type: TransformerType.OpusEncoder,
to: nodes.get(StreamType.Opus)!,
cost: 1.5,
transformer: () => new prism.opus.Encoder({ rate: 48_000, channels: 2, frameSize: 960 }),
});

nodes.get(StreamType.Opus)!.addEdge({
type: TransformerType.OpusDecoder,
to: nodes.get(StreamType.Raw)!,
cost: 1.5,
transformer: () => new prism.opus.Decoder({ rate: 48_000, channels: 2, frameSize: 960 }),
});

nodes.get(StreamType.OggOpus)!.addEdge({
type: TransformerType.OggOpusDemuxer,
to: nodes.get(StreamType.Opus)!,
cost: 1,
transformer: () => new prism.opus.OggDemuxer(),
});

nodes.get(StreamType.WebmOpus)!.addEdge({
type: TransformerType.WebmOpusDemuxer,
to: nodes.get(StreamType.Opus)!,
cost: 1,
transformer: () => new prism.opus.WebmDemuxer(),
});

const FFMPEG_PCM_EDGE: Omit<Edge, 'from'> = {
type: TransformerType.FFmpegPCM,
to: nodes.get(StreamType.Raw)!,
cost: 2,
transformer: (input) =>
new prism.FFmpeg({
args: ['-i', typeof input === 'string' ? input : '-', ...FFMPEG_OPUS_ARGUMENTS],
args: ['-i', typeof input === 'string' ? input : '-', ...FFMPEG_PCM_ARGUMENTS],
}),
};
getNode(StreamType.Arbitrary).addEdge(FFMPEG_OGG_EDGE);
// Include Ogg and WebM as well in case they have different sampling rates or are mono instead of stereo
// at the moment, this will not do anything. However, if/when detection for correct Opus headers is
// implemented, this will help inform the voice engine that it is able to transcode the audio.
getNode(StreamType.OggOpus).addEdge(FFMPEG_OGG_EDGE);
getNode(StreamType.WebmOpus).addEdge(FFMPEG_OGG_EDGE);

nodes.get(StreamType.Arbitrary)!.addEdge(FFMPEG_PCM_EDGE);
nodes.get(StreamType.OggOpus)!.addEdge(FFMPEG_PCM_EDGE);
nodes.get(StreamType.WebmOpus)!.addEdge(FFMPEG_PCM_EDGE);

nodes.get(StreamType.Raw)!.addEdge({
type: TransformerType.InlineVolume,
to: nodes.get(StreamType.Raw)!,
cost: 0.5,
transformer: () => new prism.VolumeTransformer({ type: 's16le' }),
});

if (canEnableFFmpegOptimizations()) {
const FFMPEG_OGG_EDGE: Omit<Edge, 'from'> = {
type: TransformerType.FFmpegOgg,
to: nodes.get(StreamType.OggOpus)!,
cost: 2,
transformer: (input) =>
new prism.FFmpeg({
args: ['-i', typeof input === 'string' ? input : '-', ...FFMPEG_OPUS_ARGUMENTS],
}),
};
nodes.get(StreamType.Arbitrary)!.addEdge(FFMPEG_OGG_EDGE);
// Include Ogg and WebM as well in case they have different sampling rates or are mono instead of stereo
// at the moment, this will not do anything. However, if/when detection for correct Opus headers is
// implemented, this will help inform the voice engine that it is able to transcode the audio.
nodes.get(StreamType.OggOpus)!.addEdge(FFMPEG_OGG_EDGE);
nodes.get(StreamType.WebmOpus)!.addEdge(FFMPEG_OGG_EDGE);
}

return nodes;
}

/**
Expand Down

0 comments on commit 637e1a4

Please sign in to comment.