refactor: Move getNode/canEnableFFmpegOptimizations into a lazy loaded 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>
This commit is contained in:
Jacob Morrison 2023-11-06 04:17:19 -05:00 committed by GitHub
parent ac645084f0
commit 637e1a4ddb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -101,10 +101,7 @@ 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.
@ -112,60 +109,11 @@ for (const streamType of Object.values(StreamType)) {
* @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 {
@ -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;
}
/**