@m7mdxzx1/discord-video-strem 0.0.1

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 (89) hide show
  1. package/README.md +294 -0
  2. package/dist/client/GatewayEvents.d.ts +27 -0
  3. package/dist/client/GatewayEvents.js +1 -0
  4. package/dist/client/GatewayOpCodes.d.ts +40 -0
  5. package/dist/client/GatewayOpCodes.js +41 -0
  6. package/dist/client/Streamer.d.ts +41 -0
  7. package/dist/client/Streamer.js +189 -0
  8. package/dist/client/encryptor/TransportEncryptor.d.ts +16 -0
  9. package/dist/client/encryptor/TransportEncryptor.js +38 -0
  10. package/dist/client/index.d.ts +4 -0
  11. package/dist/client/index.js +4 -0
  12. package/dist/client/packet/AudioPacketizer.d.ts +8 -0
  13. package/dist/client/packet/AudioPacketizer.js +22 -0
  14. package/dist/client/packet/BaseMediaPacketizer.d.ts +109 -0
  15. package/dist/client/packet/BaseMediaPacketizer.js +243 -0
  16. package/dist/client/packet/VideoPacketizerAnnexB.d.ts +132 -0
  17. package/dist/client/packet/VideoPacketizerAnnexB.js +231 -0
  18. package/dist/client/packet/VideoPacketizerVP8.d.ts +15 -0
  19. package/dist/client/packet/VideoPacketizerVP8.js +56 -0
  20. package/dist/client/packet/index.d.ts +4 -0
  21. package/dist/client/packet/index.js +4 -0
  22. package/dist/client/processing/AnnexBHelper.d.ts +93 -0
  23. package/dist/client/processing/AnnexBHelper.js +132 -0
  24. package/dist/client/voice/BaseMediaConnection.d.ts +118 -0
  25. package/dist/client/voice/BaseMediaConnection.js +319 -0
  26. package/dist/client/voice/MediaUdp.d.ts +26 -0
  27. package/dist/client/voice/MediaUdp.js +140 -0
  28. package/dist/client/voice/StreamConnection.d.ts +10 -0
  29. package/dist/client/voice/StreamConnection.js +30 -0
  30. package/dist/client/voice/VoiceConnection.d.ts +7 -0
  31. package/dist/client/voice/VoiceConnection.js +10 -0
  32. package/dist/client/voice/VoiceMessageTypes.d.ts +136 -0
  33. package/dist/client/voice/VoiceMessageTypes.js +1 -0
  34. package/dist/client/voice/VoiceOpCodes.d.ts +21 -0
  35. package/dist/client/voice/VoiceOpCodes.js +22 -0
  36. package/dist/client/voice/index.d.ts +5 -0
  37. package/dist/client/voice/index.js +5 -0
  38. package/dist/index.d.ts +5 -0
  39. package/dist/index.js +5 -0
  40. package/dist/media/AudioStream.d.ts +25 -0
  41. package/dist/media/AudioStream.js +63 -0
  42. package/dist/media/BaseMediaStream.d.ts +31 -0
  43. package/dist/media/BaseMediaStream.js +145 -0
  44. package/dist/media/LibavCodecId.d.ts +541 -0
  45. package/dist/media/LibavCodecId.js +552 -0
  46. package/dist/media/LibavDecoder.d.ts +5 -0
  47. package/dist/media/LibavDecoder.js +63 -0
  48. package/dist/media/LibavDemuxer.d.ts +23 -0
  49. package/dist/media/LibavDemuxer.js +295 -0
  50. package/dist/media/VideoStream.d.ts +7 -0
  51. package/dist/media/VideoStream.js +10 -0
  52. package/dist/media/index.d.ts +1 -0
  53. package/dist/media/index.js +1 -0
  54. package/dist/media/newApi.d.ts +126 -0
  55. package/dist/media/newApi.js +387 -0
  56. package/dist/media/utils.d.ts +1 -0
  57. package/dist/media/utils.js +4 -0
  58. package/dist/utils.d.ts +28 -0
  59. package/dist/utils.js +54 -0
  60. package/package.json +69 -0
  61. package/src/client/GatewayEvents.ts +41 -0
  62. package/src/client/GatewayOpCodes.ts +40 -0
  63. package/src/client/Streamer.ts +279 -0
  64. package/src/client/encryptor/TransportEncryptor.ts +62 -0
  65. package/src/client/index.ts +4 -0
  66. package/src/client/packet/AudioPacketizer.ts +28 -0
  67. package/src/client/packet/BaseMediaPacketizer.ts +307 -0
  68. package/src/client/packet/VideoPacketizerAnnexB.ts +263 -0
  69. package/src/client/packet/VideoPacketizerVP8.ts +73 -0
  70. package/src/client/packet/index.ts +4 -0
  71. package/src/client/processing/AnnexBHelper.ts +142 -0
  72. package/src/client/voice/BaseMediaConnection.ts +407 -0
  73. package/src/client/voice/MediaUdp.ts +171 -0
  74. package/src/client/voice/StreamConnection.ts +33 -0
  75. package/src/client/voice/VoiceConnection.ts +15 -0
  76. package/src/client/voice/VoiceMessageTypes.ts +164 -0
  77. package/src/client/voice/VoiceOpCodes.ts +21 -0
  78. package/src/client/voice/index.ts +5 -0
  79. package/src/index.ts +5 -0
  80. package/src/media/AudioStream.ts +81 -0
  81. package/src/media/BaseMediaStream.ts +173 -0
  82. package/src/media/LibavCodecId.ts +566 -0
  83. package/src/media/LibavDecoder.ts +82 -0
  84. package/src/media/LibavDemuxer.ts +348 -0
  85. package/src/media/VideoStream.ts +15 -0
  86. package/src/media/index.ts +1 -0
  87. package/src/media/newApi.ts +618 -0
  88. package/src/media/utils.ts +6 -0
  89. package/src/utils.ts +77 -0
@@ -0,0 +1,21 @@
1
+ export declare enum VoiceOpCodes {
2
+ IDENTIFY = 0,
3
+ SELECT_PROTOCOL = 1,
4
+ READY = 2,
5
+ HEARTBEAT = 3,
6
+ SELECT_PROTOCOL_ACK = 4,
7
+ SPEAKING = 5,
8
+ HEARTBEAT_ACK = 6,
9
+ RESUME = 7,
10
+ HELLO = 8,
11
+ RESUMED = 9,
12
+ VIDEO = 12,
13
+ CLIENT_DISCONNECT = 13,
14
+ SESSION_UPDATE = 14,
15
+ MEDIA_SINK_WANTS = 15,
16
+ VOICE_BACKEND_VERSION = 16,
17
+ CHANNEL_OPTIONS_UPDATE = 17,
18
+ FLAGS = 18,
19
+ SPEED_TEST = 19,
20
+ PLATFORM = 20
21
+ }
@@ -0,0 +1,22 @@
1
+ export var VoiceOpCodes;
2
+ (function (VoiceOpCodes) {
3
+ VoiceOpCodes[VoiceOpCodes["IDENTIFY"] = 0] = "IDENTIFY";
4
+ VoiceOpCodes[VoiceOpCodes["SELECT_PROTOCOL"] = 1] = "SELECT_PROTOCOL";
5
+ VoiceOpCodes[VoiceOpCodes["READY"] = 2] = "READY";
6
+ VoiceOpCodes[VoiceOpCodes["HEARTBEAT"] = 3] = "HEARTBEAT";
7
+ VoiceOpCodes[VoiceOpCodes["SELECT_PROTOCOL_ACK"] = 4] = "SELECT_PROTOCOL_ACK";
8
+ VoiceOpCodes[VoiceOpCodes["SPEAKING"] = 5] = "SPEAKING";
9
+ VoiceOpCodes[VoiceOpCodes["HEARTBEAT_ACK"] = 6] = "HEARTBEAT_ACK";
10
+ VoiceOpCodes[VoiceOpCodes["RESUME"] = 7] = "RESUME";
11
+ VoiceOpCodes[VoiceOpCodes["HELLO"] = 8] = "HELLO";
12
+ VoiceOpCodes[VoiceOpCodes["RESUMED"] = 9] = "RESUMED";
13
+ VoiceOpCodes[VoiceOpCodes["VIDEO"] = 12] = "VIDEO";
14
+ VoiceOpCodes[VoiceOpCodes["CLIENT_DISCONNECT"] = 13] = "CLIENT_DISCONNECT";
15
+ VoiceOpCodes[VoiceOpCodes["SESSION_UPDATE"] = 14] = "SESSION_UPDATE";
16
+ VoiceOpCodes[VoiceOpCodes["MEDIA_SINK_WANTS"] = 15] = "MEDIA_SINK_WANTS";
17
+ VoiceOpCodes[VoiceOpCodes["VOICE_BACKEND_VERSION"] = 16] = "VOICE_BACKEND_VERSION";
18
+ VoiceOpCodes[VoiceOpCodes["CHANNEL_OPTIONS_UPDATE"] = 17] = "CHANNEL_OPTIONS_UPDATE";
19
+ VoiceOpCodes[VoiceOpCodes["FLAGS"] = 18] = "FLAGS";
20
+ VoiceOpCodes[VoiceOpCodes["SPEED_TEST"] = 19] = "SPEED_TEST";
21
+ VoiceOpCodes[VoiceOpCodes["PLATFORM"] = 20] = "PLATFORM";
22
+ })(VoiceOpCodes || (VoiceOpCodes = {}));
@@ -0,0 +1,5 @@
1
+ export * from './VoiceConnection.js';
2
+ export * from './VoiceOpCodes.js';
3
+ export * from './MediaUdp.js';
4
+ export * from './StreamConnection.js';
5
+ export * from './BaseMediaConnection.js';
@@ -0,0 +1,5 @@
1
+ export * from './VoiceConnection.js';
2
+ export * from './VoiceOpCodes.js';
3
+ export * from './MediaUdp.js';
4
+ export * from './StreamConnection.js';
5
+ export * from './BaseMediaConnection.js';
@@ -0,0 +1,5 @@
1
+ export * from './client/index.js';
2
+ export * from './media/index.js';
3
+ export * from './media/newApi.js';
4
+ export * as NewApi from './media/newApi.js';
5
+ export * as Utils from './utils.js';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './client/index.js';
2
+ export * from './media/index.js';
3
+ export * from './media/newApi.js';
4
+ export * as NewApi from './media/newApi.js';
5
+ export * as Utils from './utils.js';
@@ -0,0 +1,25 @@
1
+ import type { MediaUdp } from "../client/voice/MediaUdp.js";
2
+ import { BaseMediaStream } from "./BaseMediaStream.js";
3
+ export declare class AudioStream extends BaseMediaStream {
4
+ udp: MediaUdp;
5
+ private _isMuted;
6
+ private _volume;
7
+ private _opusEncoder;
8
+ constructor(udp: MediaUdp, noSleep?: boolean, initialMuted?: boolean);
9
+ /**
10
+ * Mutes the audio stream. No audio frames will be sent.
11
+ */
12
+ mute(): void;
13
+ /**
14
+ * Unmutes the audio stream. Audio frames will resume sending.
15
+ */
16
+ unmute(): void;
17
+ /**
18
+ * Checks if the audio stream is currently muted.
19
+ * @returns True if muted, false otherwise.
20
+ */
21
+ isMuted(): boolean;
22
+ setVolume(volume: number): void;
23
+ getVolume(): number;
24
+ protected _sendFrame(frame: Buffer, frametime: number): Promise<void>;
25
+ }
@@ -0,0 +1,63 @@
1
+ import OpusScript from "opusscript";
2
+ import { BaseMediaStream } from "./BaseMediaStream.js";
3
+ export class AudioStream extends BaseMediaStream {
4
+ constructor(udp, noSleep = false, initialMuted = false) {
5
+ super("audio", noSleep);
6
+ this._volume = 1.0;
7
+ this.udp = udp;
8
+ this._isMuted = initialMuted; // Initialize mute state
9
+ this._opusEncoder = new OpusScript(48000, 2, 2048);
10
+ }
11
+ /**
12
+ * Mutes the audio stream. No audio frames will be sent.
13
+ */
14
+ mute() {
15
+ this._isMuted = true;
16
+ }
17
+ /**
18
+ * Unmutes the audio stream. Audio frames will resume sending.
19
+ */
20
+ unmute() {
21
+ this._isMuted = false;
22
+ }
23
+ /**
24
+ * Checks if the audio stream is currently muted.
25
+ * @returns True if muted, false otherwise.
26
+ */
27
+ isMuted() {
28
+ return this._isMuted;
29
+ }
30
+ setVolume(volume) {
31
+ if (volume < 0) {
32
+ this._volume = 0;
33
+ }
34
+ else {
35
+ this._volume = Math.min(volume, 2.0);
36
+ }
37
+ }
38
+ getVolume() {
39
+ return this._volume;
40
+ }
41
+ async _sendFrame(frame, frametime) {
42
+ if (this._isMuted) {
43
+ return;
44
+ }
45
+ let processedFrame = frame;
46
+ if (this._volume !== 1.0) {
47
+ try {
48
+ const pcmData = this._opusEncoder.decode(frame);
49
+ for (let i = 0; i < pcmData.length; i += 2) {
50
+ const sample = pcmData.readInt16LE(i);
51
+ const newSample = Math.max(-32768, Math.min(32767, Math.floor(sample * this._volume)));
52
+ pcmData.writeInt16LE(newSample, i);
53
+ }
54
+ processedFrame = this._opusEncoder.encode(pcmData, 960);
55
+ }
56
+ catch (error) {
57
+ console.error("[AudioStream] Error processing audio frame:", error);
58
+ processedFrame = frame;
59
+ }
60
+ }
61
+ await this.udp.sendAudioFrame(processedFrame, frametime);
62
+ }
63
+ }
@@ -0,0 +1,31 @@
1
+ import { Writable } from "node:stream";
2
+ import type { Packet } from "@lng2004/libav.js-variant-webcodecs-avf-with-decoders";
3
+ export declare class BaseMediaStream extends Writable {
4
+ private _pts?;
5
+ private _syncTolerance;
6
+ private _loggerSend;
7
+ private _loggerSync;
8
+ private _loggerSleep;
9
+ private _noSleep;
10
+ private _startTime?;
11
+ private _startPts?;
12
+ private _sync;
13
+ private _syncStream?;
14
+ constructor(type: string, noSleep?: boolean);
15
+ get sync(): boolean;
16
+ set sync(val: boolean);
17
+ get syncStream(): BaseMediaStream | undefined;
18
+ set syncStream(stream: BaseMediaStream | undefined);
19
+ get noSleep(): boolean;
20
+ set noSleep(val: boolean);
21
+ get pts(): number | undefined;
22
+ get syncTolerance(): number;
23
+ set syncTolerance(n: number);
24
+ protected _sendFrame(frame: Buffer, frametime: number): Promise<void>;
25
+ private ptsDelta;
26
+ private isAhead;
27
+ private isBehind;
28
+ private resetTimingCompensation;
29
+ _write(frame: Packet, _: BufferEncoding, callback: (error?: Error | null) => void): Promise<void>;
30
+ _destroy(error: Error | null, callback: (error?: Error | null) => void): void;
31
+ }
@@ -0,0 +1,145 @@
1
+ import { Log } from "debug-level";
2
+ import { setTimeout } from "node:timers/promises";
3
+ import { Writable } from "node:stream";
4
+ import { combineLoHi } from "./utils.js";
5
+ export class BaseMediaStream extends Writable {
6
+ constructor(type, noSleep = false) {
7
+ super({ objectMode: true, highWaterMark: 0 });
8
+ this._syncTolerance = 20;
9
+ this._sync = true;
10
+ this._loggerSend = new Log(`stream:${type}:send`);
11
+ this._loggerSync = new Log(`stream:${type}:sync`);
12
+ this._loggerSleep = new Log(`stream:${type}:sleep`);
13
+ this._noSleep = noSleep;
14
+ }
15
+ get sync() {
16
+ return this._sync;
17
+ }
18
+ set sync(val) {
19
+ this._sync = val;
20
+ if (val)
21
+ this._loggerSync.debug("Sync enabled");
22
+ else
23
+ this._loggerSync.debug("Sync disabled");
24
+ }
25
+ get syncStream() {
26
+ return this._syncStream;
27
+ }
28
+ set syncStream(stream) {
29
+ if (stream === this)
30
+ throw new Error("A stream cannot sync with itself");
31
+ this._syncStream = stream;
32
+ }
33
+ get noSleep() {
34
+ return this._noSleep;
35
+ }
36
+ set noSleep(val) {
37
+ this._noSleep = val;
38
+ if (!val)
39
+ this.resetTimingCompensation();
40
+ }
41
+ get pts() {
42
+ return this._pts;
43
+ }
44
+ get syncTolerance() {
45
+ return this._syncTolerance;
46
+ }
47
+ set syncTolerance(n) {
48
+ if (n < 0)
49
+ return;
50
+ this._syncTolerance = n;
51
+ }
52
+ async _sendFrame(frame, frametime) {
53
+ throw new Error("Not implemented");
54
+ }
55
+ ptsDelta() {
56
+ if (this.pts !== undefined && this.syncStream?.pts !== undefined)
57
+ return this.pts - this.syncStream.pts;
58
+ return undefined;
59
+ }
60
+ isAhead() {
61
+ const delta = this.ptsDelta();
62
+ return this.syncStream?.writableEnded === false && delta !== undefined && delta > this.syncTolerance;
63
+ }
64
+ isBehind() {
65
+ const delta = this.ptsDelta();
66
+ return this.syncStream?.writableEnded === false && delta !== undefined && delta < -this.syncTolerance;
67
+ }
68
+ resetTimingCompensation() {
69
+ this._startTime = this._startPts = undefined;
70
+ }
71
+ async _write(frame, _, callback) {
72
+ const { data, ptshi, pts, durationhi, duration, time_base_num, time_base_den } = frame;
73
+ // biome-ignore lint/style/noNonNullAssertion: this will never happen with our media stream
74
+ const frametime = combineLoHi(durationhi, duration) / time_base_den * time_base_num * 1000;
75
+ const start_sendFrame = performance.now();
76
+ await this._sendFrame(Buffer.from(data), frametime);
77
+ const end_sendFrame = performance.now();
78
+ // biome-ignore lint/style/noNonNullAssertion: this will never happen with our media stream
79
+ this._pts = combineLoHi(ptshi, pts) / time_base_den * time_base_num * 1000;
80
+ this.emit("pts", this._pts);
81
+ const sendTime = end_sendFrame - start_sendFrame;
82
+ const ratio = sendTime / frametime;
83
+ this._loggerSend.debug({
84
+ stats: {
85
+ pts: this._pts,
86
+ frame_size: data.length,
87
+ duration: sendTime,
88
+ frametime
89
+ }
90
+ }, `Frame sent in ${sendTime.toFixed(2)}ms (${(ratio * 100).toFixed(2)}% frametime)`);
91
+ if (ratio > 1) {
92
+ this._loggerSend.warn({
93
+ frame_size: data.length,
94
+ duration: sendTime,
95
+ frametime
96
+ }, `Frame takes too long to send (${(ratio * 100).toFixed(2)}% frametime)`);
97
+ }
98
+ this._startTime ??= start_sendFrame;
99
+ this._startPts ??= this._pts;
100
+ const sleep = Math.max(0, this._pts - this._startPts + frametime - (end_sendFrame - this._startTime));
101
+ if (this._noSleep || sleep === 0) {
102
+ callback(null);
103
+ }
104
+ else if (this.sync && this.isBehind()) {
105
+ this._loggerSync.debug({
106
+ stats: {
107
+ pts: this.pts,
108
+ pts_other: this.syncStream?.pts
109
+ }
110
+ }, "Stream is behind. Not sleeping for this frame");
111
+ this.resetTimingCompensation();
112
+ callback(null);
113
+ }
114
+ else if (this.sync && this.isAhead()) {
115
+ do {
116
+ this._loggerSync.debug({
117
+ stats: {
118
+ pts: this.pts,
119
+ pts_other: this.syncStream?.pts,
120
+ frametime
121
+ }
122
+ }, `Stream is ahead. Waiting for ${frametime}ms`);
123
+ await setTimeout(frametime);
124
+ } while (this.sync && this.isAhead());
125
+ this.resetTimingCompensation();
126
+ callback(null);
127
+ }
128
+ else {
129
+ this._loggerSleep.debug({
130
+ stats: {
131
+ pts: this._pts,
132
+ startPts: this._startPts,
133
+ time: end_sendFrame,
134
+ startTime: this._startTime,
135
+ frametime
136
+ }
137
+ }, `Sleeping for ${sleep}ms`);
138
+ setTimeout(sleep).then(() => callback(null));
139
+ }
140
+ }
141
+ _destroy(error, callback) {
142
+ super._destroy(error, callback);
143
+ this.syncStream = undefined;
144
+ }
145
+ }