piixishstream 0.0.0-stage → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +124 -2
  2. package/dist/client/GatewayEvents.d.ts +30 -0
  3. package/dist/client/GatewayEvents.js +2 -0
  4. package/dist/client/GatewayEvents.js.map +1 -0
  5. package/dist/client/GatewayOpCodes.d.ts +40 -0
  6. package/dist/client/GatewayOpCodes.js +42 -0
  7. package/dist/client/GatewayOpCodes.js.map +1 -0
  8. package/dist/client/Streamer.d.ts +30 -0
  9. package/dist/client/Streamer.js +188 -0
  10. package/dist/client/Streamer.js.map +1 -0
  11. package/dist/client/index.d.ts +3 -0
  12. package/dist/client/index.js +4 -0
  13. package/dist/client/index.js.map +1 -0
  14. package/dist/client/processing/AnnexBBitstreamReaderWriter.d.ts +23 -0
  15. package/dist/client/processing/AnnexBBitstreamReaderWriter.js +149 -0
  16. package/dist/client/processing/AnnexBBitstreamReaderWriter.js.map +1 -0
  17. package/dist/client/processing/AnnexBHelper.d.ts +93 -0
  18. package/dist/client/processing/AnnexBHelper.js +127 -0
  19. package/dist/client/processing/AnnexBHelper.js.map +1 -0
  20. package/dist/client/processing/SPSVUIRewriter.d.ts +1 -0
  21. package/dist/client/processing/SPSVUIRewriter.js +297 -0
  22. package/dist/client/processing/SPSVUIRewriter.js.map +1 -0
  23. package/dist/client/voice/BaseMediaConnection.d.ts +80 -0
  24. package/dist/client/voice/BaseMediaConnection.js +552 -0
  25. package/dist/client/voice/BaseMediaConnection.js.map +1 -0
  26. package/dist/client/voice/CodecPayloadType.d.ts +59 -0
  27. package/dist/client/voice/CodecPayloadType.js +60 -0
  28. package/dist/client/voice/CodecPayloadType.js.map +1 -0
  29. package/dist/client/voice/StreamConnection.d.ts +11 -0
  30. package/dist/client/voice/StreamConnection.js +34 -0
  31. package/dist/client/voice/StreamConnection.js.map +1 -0
  32. package/dist/client/voice/VoiceConnection.d.ts +8 -0
  33. package/dist/client/voice/VoiceConnection.js +15 -0
  34. package/dist/client/voice/VoiceConnection.js.map +1 -0
  35. package/dist/client/voice/VoiceMessageTypes.d.ts +178 -0
  36. package/dist/client/voice/VoiceMessageTypes.js +2 -0
  37. package/dist/client/voice/VoiceMessageTypes.js.map +1 -0
  38. package/dist/client/voice/VoiceOpCodes.d.ts +35 -0
  39. package/dist/client/voice/VoiceOpCodes.js +38 -0
  40. package/dist/client/voice/VoiceOpCodes.js.map +1 -0
  41. package/dist/client/voice/WebRtcWrapper.d.ts +23 -0
  42. package/dist/client/voice/WebRtcWrapper.js +159 -0
  43. package/dist/client/voice/WebRtcWrapper.js.map +1 -0
  44. package/dist/client/voice/index.d.ts +4 -0
  45. package/dist/client/voice/index.js +6 -0
  46. package/dist/client/voice/index.js.map +1 -0
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.js +4 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/media/AudioStream.d.ts +7 -0
  51. package/dist/media/AudioStream.js +12 -0
  52. package/dist/media/AudioStream.js.map +1 -0
  53. package/dist/media/BaseMediaStream.d.ts +31 -0
  54. package/dist/media/BaseMediaStream.js +164 -0
  55. package/dist/media/BaseMediaStream.js.map +1 -0
  56. package/dist/media/LibavCodecId.d.ts +541 -0
  57. package/dist/media/LibavCodecId.js +553 -0
  58. package/dist/media/LibavCodecId.js.map +1 -0
  59. package/dist/media/LibavDecoder.d.ts +5 -0
  60. package/dist/media/LibavDecoder.js +43 -0
  61. package/dist/media/LibavDecoder.js.map +1 -0
  62. package/dist/media/LibavDemuxer.d.ts +44 -0
  63. package/dist/media/LibavDemuxer.js +231 -0
  64. package/dist/media/LibavDemuxer.js.map +1 -0
  65. package/dist/media/VideoStream.d.ts +7 -0
  66. package/dist/media/VideoStream.js +12 -0
  67. package/dist/media/VideoStream.js.map +1 -0
  68. package/dist/media/encoders/index.d.ts +26 -0
  69. package/dist/media/encoders/index.js +12 -0
  70. package/dist/media/encoders/index.js.map +1 -0
  71. package/dist/media/encoders/merge.d.ts +3 -0
  72. package/dist/media/encoders/merge.js +10 -0
  73. package/dist/media/encoders/merge.js.map +1 -0
  74. package/dist/media/encoders/nvenc.d.ts +10 -0
  75. package/dist/media/encoders/nvenc.js +23 -0
  76. package/dist/media/encoders/nvenc.js.map +1 -0
  77. package/dist/media/encoders/software.d.ts +17 -0
  78. package/dist/media/encoders/software.js +31 -0
  79. package/dist/media/encoders/software.js.map +1 -0
  80. package/dist/media/encoders/vaapi.d.ts +6 -0
  81. package/dist/media/encoders/vaapi.js +22 -0
  82. package/dist/media/encoders/vaapi.js.map +1 -0
  83. package/dist/media/index.d.ts +4 -0
  84. package/dist/media/index.js +5 -0
  85. package/dist/media/index.js.map +1 -0
  86. package/dist/media/newApi.d.ts +130 -0
  87. package/dist/media/newApi.js +409 -0
  88. package/dist/media/newApi.js.map +1 -0
  89. package/dist/utils.d.ts +25 -0
  90. package/dist/utils.js +65 -0
  91. package/dist/utils.js.map +1 -0
  92. package/package.json +82 -5
  93. package/src/client/GatewayEvents.ts +48 -0
  94. package/src/client/GatewayOpCodes.ts +40 -0
  95. package/src/client/Streamer.ts +259 -0
  96. package/src/client/index.ts +3 -0
  97. package/src/client/processing/AnnexBBitstreamReaderWriter.ts +148 -0
  98. package/src/client/processing/AnnexBHelper.ts +134 -0
  99. package/src/client/processing/SPSVUIRewriter.ts +332 -0
  100. package/src/client/voice/BaseMediaConnection.ts +639 -0
  101. package/src/client/voice/CodecPayloadType.ts +59 -0
  102. package/src/client/voice/MediaUdp.ts.bak +171 -0
  103. package/src/client/voice/StreamConnection.ts +38 -0
  104. package/src/client/voice/VoiceConnection.ts +19 -0
  105. package/src/client/voice/VoiceMessageTypes.ts +263 -0
  106. package/src/client/voice/VoiceOpCodes.ts +36 -0
  107. package/src/client/voice/WebRtcWrapper.ts +218 -0
  108. package/src/client/voice/index.ts +5 -0
  109. package/src/index.ts +3 -0
  110. package/src/media/AudioStream.ts +18 -0
  111. package/src/media/BaseMediaStream.ts +198 -0
  112. package/src/media/LibavCodecId.ts +564 -0
  113. package/src/media/LibavDecoder.ts +47 -0
  114. package/src/media/LibavDemuxer.ts +293 -0
  115. package/src/media/VideoStream.ts +17 -0
  116. package/src/media/encoders/index.ts +27 -0
  117. package/src/media/encoders/merge.ts +14 -0
  118. package/src/media/encoders/nvenc.ts +38 -0
  119. package/src/media/encoders/software.ts +76 -0
  120. package/src/media/encoders/vaapi.ts +29 -0
  121. package/src/media/index.ts +4 -0
  122. package/src/media/newApi.ts +642 -0
  123. package/src/utils.ts +101 -0
@@ -0,0 +1,130 @@
1
+ import ffmpeg from "fluent-ffmpeg";
2
+ import { PassThrough, type Readable } from "node:stream";
3
+ import type { SupportedVideoCodec } from "../utils.js";
4
+ import type { Streamer } from "../client/index.js";
5
+ import type { EncoderSettingsGetter } from "./encoders/index.js";
6
+ import type { VideoStreamInfo } from "./LibavDemuxer.js";
7
+ export type PrepareStreamOptions = {
8
+ /**
9
+ * Disable video transcoding
10
+ * If enabled, all video related settings have no effects, and the input
11
+ * video stream is used as-is.
12
+ *
13
+ * You need to ensure that the video stream has the right properties
14
+ * (keyframe every 1s, B-frames disabled). Failure to do so will result in
15
+ * a glitchy stream, or degraded performance
16
+ */
17
+ noTranscoding: boolean;
18
+ /**
19
+ * Video width
20
+ */
21
+ width: number;
22
+ /**
23
+ * Video height
24
+ */
25
+ height: number;
26
+ /**
27
+ * Video frame rate
28
+ */
29
+ frameRate?: number;
30
+ /**
31
+ * Video codec
32
+ */
33
+ videoCodec: SupportedVideoCodec;
34
+ /**
35
+ * Video average bitrate in kbps
36
+ */
37
+ bitrateVideo: number;
38
+ /**
39
+ * Video max bitrate in kbps
40
+ */
41
+ bitrateVideoMax: number;
42
+ /**
43
+ * Audio bitrate in kbps
44
+ */
45
+ bitrateAudio: number;
46
+ /**
47
+ * Enable audio output
48
+ */
49
+ includeAudio: boolean;
50
+ /**
51
+ * Functions to get encoder settings
52
+ * This function will receive the average and max bitrate as the input, and
53
+ * returns an object containing encoder settings for the supported codecs
54
+ */
55
+ encoder: EncoderSettingsGetter;
56
+ /**
57
+ * Enable hardware accelerated decoding
58
+ */
59
+ hardwareAcceleratedDecoding: boolean;
60
+ /**
61
+ * Add some options to minimize latency
62
+ */
63
+ minimizeLatency: boolean;
64
+ /**
65
+ * Custom headers for HTTP requests
66
+ */
67
+ customHeaders: Record<string, string>;
68
+ /**
69
+ * Custom input options to pass directly to ffmpeg
70
+ * These will be added to the command before other options
71
+ */
72
+ customInputOptions: string[];
73
+ /**
74
+ * Custom ffmpeg flags/options to pass directly to ffmpeg
75
+ * These will be added to the command after other options
76
+ */
77
+ customFfmpegFlags: string[];
78
+ };
79
+ export type Controller = {
80
+ volume: number;
81
+ setVolume(newVolume: number): Promise<boolean>;
82
+ };
83
+ export declare function prepareStream(input: string | Readable, options?: Partial<PrepareStreamOptions>, cancelSignal?: AbortSignal): {
84
+ command: ffmpeg.FfmpegCommand;
85
+ output: PassThrough;
86
+ promise: Promise<void>;
87
+ controller: {
88
+ readonly volume: number;
89
+ setVolume(newVolume: number): Promise<boolean>;
90
+ };
91
+ };
92
+ export type PlayStreamOptions = {
93
+ /**
94
+ * Set stream type as "Go Live" or camera stream
95
+ */
96
+ type: "go-live" | "camera";
97
+ /**
98
+ * Set format of the stream
99
+ */
100
+ format: "matroska" | "nut";
101
+ /**
102
+ * Override video width sent to Discord.
103
+ *
104
+ * DO NOT SPECIFY UNLESS YOU KNOW WHAT YOU'RE DOING!
105
+ */
106
+ width: number | ((v: VideoStreamInfo) => number);
107
+ /**
108
+ * Override video height sent to Discord.
109
+ *
110
+ * DO NOT SPECIFY UNLESS YOU KNOW WHAT YOU'RE DOING!
111
+ */
112
+ height: number | ((v: VideoStreamInfo) => number);
113
+ /**
114
+ * Override video frame rate sent to Discord.
115
+ *
116
+ * DO NOT SPECIFY UNLESS YOU KNOW WHAT YOU'RE DOING!
117
+ */
118
+ frameRate: number | ((v: VideoStreamInfo) => number);
119
+ /**
120
+ * Same as ffmpeg's `readrate_initial_burst` command line flag
121
+ *
122
+ * See https://ffmpeg.org/ffmpeg.html#:~:text=%2Dreadrate_initial_burst
123
+ */
124
+ readrateInitialBurst: number | undefined;
125
+ /**
126
+ * Enable stream preview from input stream (experimental)
127
+ */
128
+ streamPreview: boolean;
129
+ };
130
+ export declare function playStream(input: Readable, streamer: Streamer, options?: Partial<PlayStreamOptions>, cancelSignal?: AbortSignal): Promise<void>;
@@ -0,0 +1,409 @@
1
+ import ffmpeg from "fluent-ffmpeg";
2
+ import pDebounce from "p-debounce";
3
+ import sharp from "sharp";
4
+ import Log from "debug-level";
5
+ import { AV_PKT_FLAG_KEY } from "node-av";
6
+ import { PassThrough } from "node:stream";
7
+ import { demux } from "./LibavDemuxer.js";
8
+ import { VideoStream } from "./VideoStream.js";
9
+ import { AudioStream } from "./AudioStream.js";
10
+ import { isBun, isDeno, isFiniteNonZero } from "../utils.js";
11
+ import { AVCodecID } from "./LibavCodecId.js";
12
+ import { createDecoder } from "./LibavDecoder.js";
13
+ import { Encoders } from "./encoders/index.js";
14
+ export function prepareStream(input, options = {}, cancelSignal) {
15
+ cancelSignal?.throwIfAborted();
16
+ const defaultOptions = {
17
+ noTranscoding: false,
18
+ // negative values = resize by aspect ratio, see https://trac.ffmpeg.org/wiki/Scaling
19
+ width: -2,
20
+ height: -2,
21
+ frameRate: undefined,
22
+ videoCodec: "H264",
23
+ bitrateVideo: 5000,
24
+ bitrateVideoMax: 7000,
25
+ bitrateAudio: 128,
26
+ includeAudio: true,
27
+ encoder: Encoders.software(),
28
+ hardwareAcceleratedDecoding: false,
29
+ minimizeLatency: false,
30
+ customHeaders: {
31
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.3",
32
+ Connection: "keep-alive",
33
+ },
34
+ customInputOptions: [],
35
+ customFfmpegFlags: [],
36
+ };
37
+ function mergeOptions(opts) {
38
+ return {
39
+ noTranscoding: opts.noTranscoding ?? defaultOptions.noTranscoding,
40
+ width: isFiniteNonZero(opts.width)
41
+ ? Math.round(opts.width)
42
+ : defaultOptions.width,
43
+ height: isFiniteNonZero(opts.height)
44
+ ? Math.round(opts.height)
45
+ : defaultOptions.height,
46
+ frameRate: isFiniteNonZero(opts.frameRate) && opts.frameRate > 0
47
+ ? opts.frameRate
48
+ : defaultOptions.frameRate,
49
+ videoCodec: opts.videoCodec ?? defaultOptions.videoCodec,
50
+ bitrateVideo: isFiniteNonZero(opts.bitrateVideo) && opts.bitrateVideo > 0
51
+ ? Math.round(opts.bitrateVideo)
52
+ : defaultOptions.bitrateVideo,
53
+ bitrateVideoMax: isFiniteNonZero(opts.bitrateVideoMax) && opts.bitrateVideoMax > 0
54
+ ? Math.round(opts.bitrateVideoMax)
55
+ : defaultOptions.bitrateVideoMax,
56
+ bitrateAudio: isFiniteNonZero(opts.bitrateAudio) && opts.bitrateAudio > 0
57
+ ? Math.round(opts.bitrateAudio)
58
+ : defaultOptions.bitrateAudio,
59
+ encoder: opts.encoder ?? defaultOptions.encoder,
60
+ includeAudio: opts.includeAudio ?? defaultOptions.includeAudio,
61
+ hardwareAcceleratedDecoding: opts.hardwareAcceleratedDecoding ??
62
+ defaultOptions.hardwareAcceleratedDecoding,
63
+ minimizeLatency: opts.minimizeLatency ?? defaultOptions.minimizeLatency,
64
+ customHeaders: {
65
+ ...defaultOptions.customHeaders,
66
+ ...opts.customHeaders,
67
+ },
68
+ customInputOptions: opts.customInputOptions ?? defaultOptions.customInputOptions,
69
+ customFfmpegFlags: opts.customFfmpegFlags ?? defaultOptions.customFfmpegFlags,
70
+ };
71
+ }
72
+ const mergedOptions = mergeOptions(options);
73
+ let isHttpUrl = false;
74
+ let isHls = false;
75
+ let isSrt = false;
76
+ if (typeof input === "string") {
77
+ isHttpUrl = input.startsWith("http") || input.startsWith("https");
78
+ isHls = input.includes("m3u");
79
+ isSrt = input.startsWith("srt://");
80
+ }
81
+ const output = new PassThrough();
82
+ // command creation
83
+ const command = ffmpeg(input);
84
+ // input options
85
+ if (mergedOptions.customInputOptions &&
86
+ mergedOptions.customInputOptions.length > 0) {
87
+ command.inputOptions(mergedOptions.customInputOptions);
88
+ }
89
+ const { hardwareAcceleratedDecoding, minimizeLatency, customHeaders } = mergedOptions;
90
+ if (hardwareAcceleratedDecoding)
91
+ command.inputOption("-hwaccel", "auto");
92
+ if (minimizeLatency) {
93
+ command.addOptions(["-fflags nobuffer", "-analyzeduration 0"]);
94
+ }
95
+ if (isHttpUrl) {
96
+ command.inputOption("-headers", Object.entries(customHeaders)
97
+ .map(([k, v]) => `${k}: ${v}`)
98
+ .join("\r\n"));
99
+ if (!isHls) {
100
+ command.inputOptions([
101
+ "-reconnect 1",
102
+ "-reconnect_at_eof 1",
103
+ "-reconnect_streamed 1",
104
+ "-reconnect_delay_max 4294",
105
+ ]);
106
+ }
107
+ }
108
+ if (isSrt) {
109
+ command.inputOption("-scan_all_pmts 0");
110
+ }
111
+ // general output options
112
+ command.output(output).outputFormat("nut");
113
+ // video setup
114
+ const { noTranscoding, width, height, frameRate, bitrateVideo, bitrateVideoMax, videoCodec, encoder, } = mergedOptions;
115
+ command.addOutputOption("-map 0:v");
116
+ if (noTranscoding) {
117
+ command.videoCodec("copy");
118
+ }
119
+ else {
120
+ command.videoFilter(`scale=${width}:${height}`);
121
+ if (frameRate)
122
+ command.fpsOutput(frameRate);
123
+ command.addOutputOption([
124
+ "-b:v",
125
+ `${bitrateVideo}k`,
126
+ "-maxrate:v",
127
+ `${bitrateVideoMax}k`,
128
+ "-bufsize:v",
129
+ `${Math.round(bitrateVideo / 2)}k`,
130
+ "-bf",
131
+ "0",
132
+ "-pix_fmt",
133
+ "yuv420p",
134
+ "-force_key_frames",
135
+ "expr:gte(t,n_forced*1)",
136
+ ]);
137
+ const encoderSettings = encoder(bitrateVideo, bitrateVideoMax)[videoCodec];
138
+ if (!encoderSettings)
139
+ throw new Error(`Encoder settings not specified for ${videoCodec}`);
140
+ command
141
+ .videoCodec(encoderSettings.name)
142
+ .videoFilter(encoderSettings.outFilters ?? [])
143
+ .outputOptions(encoderSettings.options)
144
+ .outputOptions(encoderSettings.globalOptions ?? []);
145
+ }
146
+ // audio setup
147
+ const { includeAudio, bitrateAudio } = mergedOptions;
148
+ if (includeAudio)
149
+ command
150
+ .addOutputOption("-map 0:a:0?")
151
+ .audioChannels(2)
152
+ /*
153
+ * I don't have much surround sound material to test this with,
154
+ * if you do and you have better settings for this, feel free to
155
+ * contribute!
156
+ */
157
+ .addOutputOption("-lfe_mix_level 1")
158
+ .audioFrequency(48000)
159
+ .audioCodec("libopus")
160
+ .audioBitrate(`${bitrateAudio}k`)
161
+ .audioFilters("volume@internal_lib=1.0");
162
+ // Add custom ffmpeg flags
163
+ if (mergedOptions.customFfmpegFlags &&
164
+ mergedOptions.customFfmpegFlags.length > 0) {
165
+ command.addOptions(mergedOptions.customFfmpegFlags);
166
+ }
167
+ // exit handling
168
+ const promise = new Promise((resolve, reject) => {
169
+ command.on("error", (err) => {
170
+ if (cancelSignal?.aborted)
171
+ /**
172
+ * fluent-ffmpeg might throw an error when SIGTERM is sent to
173
+ * the process, so we check if the abort signal is triggered
174
+ * and throw that instead
175
+ */
176
+ reject(cancelSignal.reason);
177
+ else
178
+ reject(err);
179
+ });
180
+ command.on("end", () => resolve());
181
+ });
182
+ promise.catch(() => { });
183
+ cancelSignal?.addEventListener("abort", () => command.kill("SIGTERM"), {
184
+ once: true,
185
+ });
186
+ // realtime control mechanism
187
+ let currentVolume = 1;
188
+ let zmqClientPromise;
189
+ if (includeAudio && !isBun() && !isDeno()) {
190
+ function randomInclusive(start, end) {
191
+ return Math.floor(Math.random() * (end - start + 1)) + start;
192
+ }
193
+ // Last octet is from 2 to 254 to avoid WSL2 shenanigans
194
+ const loopbackIp = [
195
+ 127,
196
+ randomInclusive(0, 255),
197
+ randomInclusive(0, 255),
198
+ randomInclusive(2, 254),
199
+ ].join(".");
200
+ const zmqEndpoint = `tcp://${loopbackIp}:42069`;
201
+ command.audioFilters(`azmq=b=${zmqEndpoint.replaceAll(":", "\\\\:")}`);
202
+ zmqClientPromise = import("zeromq").then((zmq) => {
203
+ const client = new zmq.Request({
204
+ sendTimeout: 5000,
205
+ receiveTimeout: 5000,
206
+ });
207
+ client.connect(zmqEndpoint);
208
+ promise.catch(() => { }).finally(() => client.disconnect(zmqEndpoint));
209
+ return client;
210
+ });
211
+ }
212
+ command.run();
213
+ return {
214
+ command,
215
+ output,
216
+ promise,
217
+ controller: {
218
+ get volume() {
219
+ return currentVolume;
220
+ },
221
+ async setVolume(newVolume) {
222
+ if (newVolume < 0)
223
+ return false;
224
+ try {
225
+ if (!zmqClientPromise)
226
+ return false;
227
+ const client = await zmqClientPromise;
228
+ await client.send(`volume@internal_lib volume ${newVolume}`);
229
+ const [res] = await client.receive();
230
+ if (res.toString("utf-8").split(" ")[0] !== "0")
231
+ return false;
232
+ currentVolume = newVolume;
233
+ return true;
234
+ }
235
+ catch {
236
+ return false;
237
+ }
238
+ },
239
+ },
240
+ };
241
+ }
242
+ export async function playStream(input, streamer, options = {}, cancelSignal) {
243
+ const logger = new Log("playStream");
244
+ cancelSignal?.throwIfAborted();
245
+ if (!streamer.voiceConnection)
246
+ throw new Error("Bot is not connected to a voice channel");
247
+ const defaultOptions = {
248
+ type: "go-live",
249
+ format: "nut",
250
+ width: (video) => video.width,
251
+ height: (video) => video.height,
252
+ frameRate: (video) => video.framerate_num / video.framerate_den,
253
+ readrateInitialBurst: undefined,
254
+ streamPreview: false,
255
+ };
256
+ function mergeOptions(opts) {
257
+ return {
258
+ type: opts.type ?? defaultOptions.type,
259
+ format: opts.format ?? defaultOptions.format,
260
+ width: typeof opts.width === "function" ||
261
+ (isFiniteNonZero(opts.width) && opts.width > 0)
262
+ ? opts.width
263
+ : defaultOptions.width,
264
+ height: typeof opts.height === "function" ||
265
+ (isFiniteNonZero(opts.height) && opts.height > 0)
266
+ ? opts.height
267
+ : defaultOptions.height,
268
+ frameRate: typeof opts.frameRate === "function" ||
269
+ (isFiniteNonZero(opts.frameRate) && opts.frameRate > 0)
270
+ ? opts.frameRate
271
+ : defaultOptions.frameRate,
272
+ readrateInitialBurst: isFiniteNonZero(opts.readrateInitialBurst) &&
273
+ opts.readrateInitialBurst > 0
274
+ ? opts.readrateInitialBurst
275
+ : defaultOptions.readrateInitialBurst,
276
+ streamPreview: opts.streamPreview ?? defaultOptions.streamPreview,
277
+ };
278
+ }
279
+ const mergedOptions = mergeOptions(options);
280
+ logger.debug({ options: mergedOptions }, "Merged options");
281
+ logger.debug("Initializing demuxer");
282
+ const { video, audio } = await demux(input, {
283
+ format: mergedOptions.format,
284
+ });
285
+ cancelSignal?.throwIfAborted();
286
+ if (!video)
287
+ throw new Error("No video stream in media");
288
+ const cleanupFuncs = [];
289
+ const videoCodecMap = {
290
+ [AVCodecID.AV_CODEC_ID_H264]: "H264",
291
+ [AVCodecID.AV_CODEC_ID_H265]: "H265",
292
+ [AVCodecID.AV_CODEC_ID_VP8]: "VP8",
293
+ [AVCodecID.AV_CODEC_ID_VP9]: "VP9",
294
+ [AVCodecID.AV_CODEC_ID_AV1]: "AV1",
295
+ };
296
+ let conn;
297
+ let stopStream;
298
+ if (mergedOptions.type === "go-live") {
299
+ conn = await streamer.createStream();
300
+ stopStream = () => streamer.stopStream();
301
+ }
302
+ else {
303
+ conn = streamer.voiceConnection.webRtcConn;
304
+ streamer.signalVideo(true);
305
+ stopStream = () => streamer.signalVideo(false);
306
+ }
307
+ conn.setPacketizer(videoCodecMap[video.codec]);
308
+ conn.mediaConnection.setSpeaking(true);
309
+ const { width, height, frameRate } = mergedOptions;
310
+ conn.mediaConnection.setVideoAttributes(true, {
311
+ width: Math.round(typeof width === "function" ? width(video) : width),
312
+ height: Math.round(typeof height === "function" ? height(video) : height),
313
+ fps: Math.round(typeof frameRate === "function" ? frameRate(video) : frameRate),
314
+ });
315
+ const vStream = new VideoStream(conn);
316
+ video.stream.pipe(vStream);
317
+ if (audio) {
318
+ const aStream = new AudioStream(conn);
319
+ audio.stream.pipe(aStream);
320
+ // vStream.syncStream = aStream;
321
+ const burstTime = mergedOptions.readrateInitialBurst;
322
+ if (typeof burstTime === "number") {
323
+ vStream.sync = false;
324
+ vStream.noSleep = aStream.noSleep = true;
325
+ const stopBurst = (pts) => {
326
+ if (pts < burstTime * 1000)
327
+ return;
328
+ vStream.sync = true;
329
+ vStream.noSleep = aStream.noSleep = false;
330
+ vStream.off("pts", stopBurst);
331
+ };
332
+ vStream.on("pts", stopBurst);
333
+ }
334
+ }
335
+ if (mergedOptions.streamPreview && mergedOptions.type === "go-live") {
336
+ (async () => {
337
+ const logger = new Log("playStream:preview");
338
+ logger.debug("Initializing decoder for stream preview");
339
+ const decoder = await createDecoder(video.avStream);
340
+ if (!decoder) {
341
+ logger.warn("Failed to initialize decoder. Stream preview will be disabled");
342
+ return;
343
+ }
344
+ cleanupFuncs.push(() => {
345
+ logger.debug("Freeing decoder");
346
+ decoder.free();
347
+ });
348
+ const updatePreview = pDebounce.promise(async (packet) => {
349
+ if (!(packet.flags !== undefined && packet.flags & AV_PKT_FLAG_KEY))
350
+ return;
351
+ const decodeStart = performance.now();
352
+ const frames = await decoder.decode(packet).catch((e) => {
353
+ logger.error(e, "Failed to decode the frame");
354
+ return [];
355
+ });
356
+ if (!frames.length)
357
+ return;
358
+ const decodeEnd = performance.now();
359
+ logger.debug(`Decoding a frame took ${decodeEnd - decodeStart}ms`);
360
+ const frame = frames[0];
361
+ return sharp(frame.toBuffer(), {
362
+ raw: {
363
+ width: frame.width ?? 0,
364
+ height: frame.height ?? 0,
365
+ channels: 4,
366
+ },
367
+ })
368
+ .resize(1024, 576, { fit: "inside" })
369
+ .jpeg()
370
+ .toBuffer()
371
+ .then((image) => streamer.setStreamPreview(image))
372
+ .catch(() => { })
373
+ .finally(() => {
374
+ frames.forEach((frame) => {
375
+ frame.free();
376
+ });
377
+ });
378
+ });
379
+ video.stream.on("data", updatePreview);
380
+ cleanupFuncs.push(() => video.stream.off("data", updatePreview));
381
+ })();
382
+ }
383
+ return new Promise((resolve, reject) => {
384
+ cleanupFuncs.push(() => {
385
+ stopStream();
386
+ conn.mediaConnection.setSpeaking(false);
387
+ conn.mediaConnection.setVideoAttributes(false);
388
+ });
389
+ let cleanedUp = false;
390
+ const cleanup = () => {
391
+ if (cleanedUp)
392
+ return;
393
+ cleanedUp = true;
394
+ for (const f of cleanupFuncs)
395
+ f();
396
+ };
397
+ cancelSignal?.addEventListener("abort", () => {
398
+ cleanup();
399
+ reject(cancelSignal.reason);
400
+ }, { once: true });
401
+ vStream.once("finish", () => {
402
+ if (cancelSignal?.aborted)
403
+ return;
404
+ cleanup();
405
+ resolve();
406
+ });
407
+ }).catch(() => { });
408
+ }
409
+ //# sourceMappingURL=newApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"newApi.js","sourceRoot":"","sources":["../../src/media/newApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { AnyChannel, DMChannel, GroupDMChannel, VoiceBasedChannel } from "discord.js-selfbot-v13";
2
+ export declare function normalizeVideoCodec(codec: string): "H264" | "H265" | "VP8" | "VP9" | "AV1";
3
+ export declare const STREAMS_SIMULCAST: {
4
+ type: string;
5
+ rid: string;
6
+ quality: number;
7
+ }[];
8
+ export declare enum SupportedEncryptionModes {
9
+ AES256 = "aead_aes256_gcm_rtpsize",
10
+ XCHACHA20 = "aead_xchacha20_poly1305_rtpsize"
11
+ }
12
+ export type SupportedVideoCodec = "H264" | "H265" | "VP8" | "VP9" | "AV1";
13
+ export declare const max_int16bit: number;
14
+ export declare const max_int32bit: number;
15
+ export declare function isFiniteNonZero(n: unknown): n is number;
16
+ export declare function parseStreamKey(streamKey: string): {
17
+ type: "guild" | "call";
18
+ channelId: string;
19
+ guildId: string | null;
20
+ userId: string;
21
+ };
22
+ export declare function generateStreamKey(type: "guild" | "call", guildId: string | null, channelId: string, userId: string): string;
23
+ export declare function isVoiceChannel(channel: AnyChannel): channel is DMChannel | GroupDMChannel | VoiceBasedChannel;
24
+ export declare function isDeno(): boolean;
25
+ export declare function isBun(): boolean;
package/dist/utils.js ADDED
@@ -0,0 +1,65 @@
1
+ export function normalizeVideoCodec(codec) {
2
+ if (/H\.?264|AVC/i.test(codec))
3
+ return "H264";
4
+ if (/H\.?265|HEVC/i.test(codec))
5
+ return "H265";
6
+ if (/VP(8|9)/i.test(codec))
7
+ return codec.toUpperCase();
8
+ if (/AV1/i.test(codec))
9
+ return "AV1";
10
+ throw new Error(`Unknown codec: ${codec}`);
11
+ }
12
+ // The available video streams are sent by client on connection to voice gateway using OpCode Identify (0)
13
+ // The server then replies with the ssrc and rtxssrc for each available stream using OpCode Ready (2)
14
+ // RID is used specifically to distinguish between different simulcast streams of the same video source,
15
+ // but we don't really care about sending multiple quality streams, so we hardcode a single one
16
+ export const STREAMS_SIMULCAST = [{ type: "screen", rid: "100", quality: 100 }];
17
+ export var SupportedEncryptionModes;
18
+ (function (SupportedEncryptionModes) {
19
+ SupportedEncryptionModes["AES256"] = "aead_aes256_gcm_rtpsize";
20
+ SupportedEncryptionModes["XCHACHA20"] = "aead_xchacha20_poly1305_rtpsize";
21
+ })(SupportedEncryptionModes || (SupportedEncryptionModes = {}));
22
+ export const max_int16bit = 2 ** 16;
23
+ export const max_int32bit = 2 ** 32;
24
+ export function isFiniteNonZero(n) {
25
+ return !!n && Number.isFinite(n);
26
+ }
27
+ export function parseStreamKey(streamKey) {
28
+ const streamKeyArray = streamKey.split(":");
29
+ const type = streamKeyArray.shift();
30
+ if (type !== "guild" && type !== "call") {
31
+ throw new Error(`Invalid stream key type: ${type}`);
32
+ }
33
+ if ((type === "guild" && streamKeyArray.length < 3) ||
34
+ (type === "call" && streamKey.length < 2))
35
+ throw new Error(`Invalid stream key: ${streamKey}`); // invalid stream key
36
+ let guildId = null;
37
+ if (type === "guild") {
38
+ guildId = streamKeyArray.shift() ?? null;
39
+ }
40
+ const channelId = streamKeyArray.shift();
41
+ const userId = streamKeyArray.shift();
42
+ if (!channelId || !userId) {
43
+ throw new Error(`Invalid stream key: ${streamKey}`);
44
+ }
45
+ return { type, channelId, guildId, userId };
46
+ }
47
+ export function generateStreamKey(type, guildId, channelId, userId) {
48
+ const streamKey = `${type}${type === "guild" ? `:${guildId}` : ""}:${channelId}:${userId}`;
49
+ return streamKey;
50
+ }
51
+ export function isVoiceChannel(channel) {
52
+ return (channel.type === "DM" ||
53
+ channel.type === "GROUP_DM" ||
54
+ channel.type === "GUILD_STAGE_VOICE" ||
55
+ channel.type === "GUILD_VOICE");
56
+ }
57
+ export function isDeno() {
58
+ // @ts-expect-error
59
+ return typeof Deno !== "undefined";
60
+ }
61
+ export function isBun() {
62
+ // @ts-expect-error
63
+ return typeof Bun !== "undefined";
64
+ }
65
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}