@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,231 @@
1
+ import { BaseMediaPacketizer } from "./BaseMediaPacketizer.js";
2
+ import { H264Helpers, H265Helpers } from "../processing/AnnexBHelper.js";
3
+ import { extensions } from "../../utils.js";
4
+ import { splitNalu } from "../processing/AnnexBHelper.js";
5
+ import { CodecPayloadType } from "../voice/BaseMediaConnection.js";
6
+ /**
7
+ * Annex B format
8
+ *
9
+ * Packetizer for Annex B NAL. This method does NOT support aggregation packets
10
+ * where multiple NALs are sent as a single RTP payload. The supported payload
11
+ * type is Single NAL Unit Packet and Fragmentation Unit A (FU-A). The headers
12
+ * produced correspond to packetization-mode=1.
13
+
14
+ RTP Payload Format for H.264 Video:
15
+ https://tools.ietf.org/html/rfc6184
16
+
17
+ RTP Payload Format for HEVC Video:
18
+ https://tools.ietf.org/html/rfc7798
19
+
20
+ FFmpeg H264/HEVC RTP packetisation code:
21
+ https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/rtpenc_h264_hevc.c
22
+
23
+ When the payload size is less than or equal to max RTP payload, send as
24
+ Single NAL Unit Packet:
25
+ https://tools.ietf.org/html/rfc6184#section-5.6
26
+ https://tools.ietf.org/html/rfc7798#section-4.4.1
27
+
28
+ 0 1 2 3
29
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
30
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31
+ |F|NRI| Type | |
32
+ +-+-+-+-+-+-+-+-+ |
33
+ | |
34
+ | Bytes 2..n of a single NAL unit |
35
+ | |
36
+ | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37
+ | :...OPTIONAL RTP padding |
38
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39
+
40
+ Type = 24 for STAP-A (NOTE: this is the type of the RTP header
41
+ and NOT the NAL type).
42
+
43
+ When the payload size is greater than max RTP payload, send as
44
+ Fragmentation Unit A (FU-A):
45
+ https://tools.ietf.org/html/rfc6184#section-5.8
46
+ 0 1 2 3
47
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
48
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49
+ | FU indicator | FU header | |
50
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51
+ | Fragmentation Unit (FU) Payload
52
+ |
53
+ ...
54
+ */
55
+ class VideoPacketizerAnnexB extends BaseMediaPacketizer {
56
+ constructor(connection, ssrc, payloadType, nalFunctions) {
57
+ super(connection, ssrc, payloadType, true);
58
+ this._nalFunctions = nalFunctions;
59
+ }
60
+ /**
61
+ * Sends packets after partitioning the video frame into
62
+ * MTU-sized chunks
63
+ * @param frame Annex B video frame
64
+ */
65
+ async sendFrame(frame, frametime) {
66
+ super.sendFrame(frame, frametime);
67
+ const nalus = splitNalu(frame);
68
+ let packetsSent = 0;
69
+ let bytesSent = 0;
70
+ let index = 0;
71
+ for (const nalu of nalus) {
72
+ const isLastNal = index === nalus.length - 1;
73
+ if (nalu.length <= this.mtu) {
74
+ // Send as Single NAL Unit Packet.
75
+ const packetHeader = Buffer.concat([this.makeRtpHeader(isLastNal), this.createExtensionHeader(extensions)]);
76
+ const [ciphertext, nonceBuffer] = await this.encryptData(Buffer.concat([this.createExtensionPayload(extensions), nalu]), packetHeader);
77
+ const packet = Buffer.concat([
78
+ packetHeader, ciphertext,
79
+ nonceBuffer.subarray(0, 4),
80
+ ]);
81
+ this.mediaUdp.sendPacket(packet);
82
+ packetsSent++;
83
+ bytesSent += packet.length;
84
+ }
85
+ else {
86
+ const [naluHeader, naluData] = this._nalFunctions.splitHeader(nalu);
87
+ const data = this.partitionDataMTUSizedChunks(naluData);
88
+ const encryptedPackets = [];
89
+ // Send as Fragmentation Unit A (FU-A):
90
+ for (let i = 0; i < data.length; i++) {
91
+ const isFirstPacket = i === 0;
92
+ const isFinalPacket = i === data.length - 1;
93
+ const markerBit = isLastNal && isFinalPacket;
94
+ const packetHeader = Buffer.concat([this.makeRtpHeader(markerBit), this.createExtensionHeader(extensions)]);
95
+ const packetData = Buffer.concat([
96
+ this.createExtensionPayload(extensions),
97
+ this.makeFragmentationUnitHeader(isFirstPacket, isFinalPacket, naluHeader),
98
+ data[i]
99
+ ]);
100
+ encryptedPackets.push(this.encryptData(packetData, packetHeader)
101
+ .then(([ciphertext, nonceBuffer]) => Buffer.concat([
102
+ packetHeader,
103
+ ciphertext,
104
+ nonceBuffer.subarray(0, 4),
105
+ ])));
106
+ }
107
+ for (const packet of await Promise.all(encryptedPackets)) {
108
+ this.mediaUdp.sendPacket(packet);
109
+ packetsSent++;
110
+ bytesSent += packet.length;
111
+ }
112
+ }
113
+ index++;
114
+ }
115
+ await this.onFrameSent(packetsSent, bytesSent, frametime);
116
+ }
117
+ makeFragmentationUnitHeader(isFirstPacket, isLastPacket, naluHeader) {
118
+ throw new Error("Not implemented");
119
+ }
120
+ async onFrameSent(packetsSent, bytesSent, frametime) {
121
+ await super.onFrameSent(packetsSent, bytesSent, frametime);
122
+ // video RTP packet timestamp incremental value = 90,000Hz / fps
123
+ this.incrementTimestamp(90000 / 1000 * frametime);
124
+ }
125
+ }
126
+ export class VideoPacketizerH264 extends VideoPacketizerAnnexB {
127
+ constructor(connection, ssrc) {
128
+ super(connection, ssrc, CodecPayloadType.H264.payload_type, H264Helpers);
129
+ }
130
+ /**
131
+ * The FU indicator octet has the following format:
132
+
133
+ +---------------+
134
+ |0|1|2|3|4|5|6|7|
135
+ +-+-+-+-+-+-+-+-+
136
+ |F|NRI| Type |
137
+ +---------------+
138
+
139
+ F and NRI bits come from the NAL being transmitted.
140
+ Type = 28 for FU-A (NOTE: this is the type of the H264 RTP header
141
+ and NOT the NAL type).
142
+
143
+ The FU header has the following format:
144
+
145
+ +---------------+
146
+ |0|1|2|3|4|5|6|7|
147
+ +-+-+-+-+-+-+-+-+
148
+ |S|E|R| Type |
149
+ +---------------+
150
+
151
+ S: Set to 1 for the start of the NAL FU (i.e. first packet in frame).
152
+ E: Set to 1 for the end of the NAL FU (i.e. the last packet in the frame).
153
+ R: Reserved bit must be 0.
154
+ Type: The NAL unit payload type, comes from NAL packet (NOTE: this IS the type of the NAL message).
155
+ * @param isFirstPacket
156
+ * @param isLastPacket
157
+ * @param naluHeader
158
+ * @returns FU-A packets
159
+ */
160
+ makeFragmentationUnitHeader(isFirstPacket, isLastPacket, naluHeader) {
161
+ const nal0 = naluHeader[0];
162
+ const fuPayloadHeader = Buffer.alloc(2);
163
+ const nalType = H264Helpers.getUnitType(naluHeader);
164
+ const fnri = nal0 & 0xe0;
165
+ // set fu indicator
166
+ fuPayloadHeader[0] = 0x1c | fnri; // type 28 with fnri from original frame
167
+ // set fu header
168
+ if (isFirstPacket) {
169
+ fuPayloadHeader[1] = 0x80 | nalType; // set start bit
170
+ }
171
+ else if (isLastPacket) {
172
+ fuPayloadHeader[1] = 0x40 | nalType; // set last bit
173
+ }
174
+ else {
175
+ fuPayloadHeader[1] = nalType; // no start or end bit
176
+ }
177
+ return fuPayloadHeader;
178
+ }
179
+ }
180
+ export class VideoPacketizerH265 extends VideoPacketizerAnnexB {
181
+ constructor(connection, ssrc) {
182
+ super(connection, ssrc, CodecPayloadType.H265.payload_type, H265Helpers);
183
+ }
184
+ /**
185
+ * The FU indicator octet has the following format:
186
+
187
+ +---------------+---------------+
188
+ |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
189
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190
+ |F| Type | LayerId | TID |
191
+ +-------------+-----------------+
192
+
193
+ All other fields except Type come from the NAL being transmitted.
194
+ Type = 49 for FU-A (NOTE: this is the type of the H265 RTP header
195
+ and NOT the NAL type).
196
+
197
+ The FU header has the following format:
198
+
199
+ +---------------+
200
+ |0|1|2|3|4|5|6|7|
201
+ +-+-+-+-+-+-+-+-+
202
+ |S|E| Type |
203
+ +---------------+
204
+
205
+ S: Set to 1 for the start of the NAL FU (i.e. first packet in frame).
206
+ E: Set to 1 for the end of the NAL FU (i.e. the last packet in the frame).
207
+ Type: The NAL unit payload type, comes from NAL packet (NOTE: this IS the type of the NAL message).
208
+ * @param isFirstPacket
209
+ * @param isLastPacket
210
+ * @param naluHeader
211
+ * @returns FU-A packets
212
+ */
213
+ makeFragmentationUnitHeader(isFirstPacket, isLastPacket, naluHeader) {
214
+ const fuIndicatorHeader = Buffer.allocUnsafe(3);
215
+ naluHeader.copy(fuIndicatorHeader);
216
+ const nalType = H265Helpers.getUnitType(naluHeader);
217
+ // clear NAL type and set it to 49
218
+ fuIndicatorHeader[0] = (fuIndicatorHeader[0] & 0b10000001) | (49 << 1);
219
+ // set fu header
220
+ if (isFirstPacket) {
221
+ fuIndicatorHeader[2] = 0x80 | nalType; // set start bit
222
+ }
223
+ else if (isLastPacket) {
224
+ fuIndicatorHeader[2] = 0x40 | nalType; // set last bit
225
+ }
226
+ else {
227
+ fuIndicatorHeader[2] = nalType; // no start or end bit
228
+ }
229
+ return fuIndicatorHeader;
230
+ }
231
+ }
@@ -0,0 +1,15 @@
1
+ import type { MediaUdp } from "../voice/MediaUdp.js";
2
+ import { BaseMediaPacketizer } from "./BaseMediaPacketizer.js";
3
+ /**
4
+ * VP8 payload format
5
+ *
6
+ */
7
+ export declare class VideoPacketizerVP8 extends BaseMediaPacketizer {
8
+ private _pictureId;
9
+ constructor(connection: MediaUdp, ssrc: number);
10
+ private incrementPictureId;
11
+ sendFrame(frame: Buffer, frametime: number): Promise<void>;
12
+ createPacket(chunk: Buffer, isLastPacket?: boolean, isFirstPacket?: boolean): Promise<Buffer>;
13
+ onFrameSent(packetsSent: number, bytesSent: number, frametime: number): Promise<void>;
14
+ private makeChunk;
15
+ }
@@ -0,0 +1,56 @@
1
+ import { extensions, max_int16bit } from "../../utils.js";
2
+ import { BaseMediaPacketizer } from "./BaseMediaPacketizer.js";
3
+ import { CodecPayloadType } from "../voice/BaseMediaConnection.js";
4
+ /**
5
+ * VP8 payload format
6
+ *
7
+ */
8
+ export class VideoPacketizerVP8 extends BaseMediaPacketizer {
9
+ constructor(connection, ssrc) {
10
+ super(connection, ssrc, CodecPayloadType.VP8.payload_type, true);
11
+ this._pictureId = 0;
12
+ }
13
+ incrementPictureId() {
14
+ this._pictureId = (this._pictureId + 1) % max_int16bit;
15
+ }
16
+ async sendFrame(frame, frametime) {
17
+ super.sendFrame(frame, frametime);
18
+ const data = this.partitionDataMTUSizedChunks(frame);
19
+ let bytesSent = 0;
20
+ const encryptedPackets = data.map((chunk, i) => this.createPacket(chunk, i === (data.length - 1), i === 0));
21
+ for (const packet of await Promise.all(encryptedPackets)) {
22
+ this.mediaUdp.sendPacket(packet);
23
+ bytesSent += packet.length;
24
+ }
25
+ await this.onFrameSent(data.length, bytesSent, frametime);
26
+ }
27
+ async createPacket(chunk, isLastPacket = true, isFirstPacket = true) {
28
+ if (chunk.length > this.mtu)
29
+ throw Error('error packetizing video frame: frame is larger than mtu');
30
+ const packetHeader = Buffer.concat([this.makeRtpHeader(isLastPacket), this.createExtensionHeader(extensions)]);
31
+ const packetData = Buffer.concat([this.createExtensionPayload(extensions), this.makeChunk(chunk, isFirstPacket)]);
32
+ // nonce buffer used for encryption. 4 bytes are appended to end of packet
33
+ const [ciphertext, nonceBuffer] = await this.encryptData(packetData, packetHeader);
34
+ return Buffer.concat([packetHeader, ciphertext, nonceBuffer.subarray(0, 4)]);
35
+ }
36
+ async onFrameSent(packetsSent, bytesSent, frametime) {
37
+ await super.onFrameSent(packetsSent, bytesSent, frametime);
38
+ // video RTP packet timestamp incremental value = 90,000Hz / fps
39
+ this.incrementTimestamp(90000 / 1000 * frametime);
40
+ this.incrementPictureId();
41
+ }
42
+ makeChunk(frameData, isFirstPacket) {
43
+ // vp8 payload descriptor
44
+ const payloadDescriptorBuf = Buffer.alloc(2);
45
+ payloadDescriptorBuf[0] = 0x80;
46
+ payloadDescriptorBuf[1] = 0x80;
47
+ if (isFirstPacket) {
48
+ payloadDescriptorBuf[0] |= 0b00010000; // mark S bit, indicates start of frame
49
+ }
50
+ // vp8 pictureid payload extension
51
+ const pictureIdBuf = Buffer.alloc(2);
52
+ pictureIdBuf.writeUIntBE(this._pictureId, 0, 2);
53
+ pictureIdBuf[0] |= 0b10000000;
54
+ return Buffer.concat([payloadDescriptorBuf, pictureIdBuf, frameData]);
55
+ }
56
+ }
@@ -0,0 +1,4 @@
1
+ export * from './AudioPacketizer.js';
2
+ export * from './BaseMediaPacketizer.js';
3
+ export * from './VideoPacketizerVP8.js';
4
+ export * from './VideoPacketizerAnnexB.js';
@@ -0,0 +1,4 @@
1
+ export * from './AudioPacketizer.js';
2
+ export * from './BaseMediaPacketizer.js';
3
+ export * from './VideoPacketizerVP8.js';
4
+ export * from './VideoPacketizerAnnexB.js';
@@ -0,0 +1,93 @@
1
+ export declare enum H264NalUnitTypes {
2
+ Unspecified = 0,
3
+ CodedSliceNonIDR = 1,
4
+ CodedSlicePartitionA = 2,
5
+ CodedSlicePartitionB = 3,
6
+ CodedSlicePartitionC = 4,
7
+ CodedSliceIdr = 5,
8
+ SEI = 6,
9
+ SPS = 7,
10
+ PPS = 8,
11
+ AccessUnitDelimiter = 9,
12
+ EndOfSequence = 10,
13
+ EndOfStream = 11,
14
+ FillerData = 12,
15
+ SEIExtenstion = 13,
16
+ PrefixNalUnit = 14,
17
+ SubsetSPS = 15
18
+ }
19
+ export declare enum H265NalUnitTypes {
20
+ TRAIL_N = 0,
21
+ TRAIL_R = 1,
22
+ TSA_N = 2,
23
+ TSA_R = 3,
24
+ STSA_N = 4,
25
+ STSA_R = 5,
26
+ RADL_N = 6,
27
+ RADL_R = 7,
28
+ RASL_N = 8,
29
+ RASL_R = 9,
30
+ RSV_VCL_N10 = 10,
31
+ RSV_VCL_R11 = 11,
32
+ RSV_VCL_N12 = 12,
33
+ RSV_VCL_R13 = 13,
34
+ RSV_VCL_N14 = 14,
35
+ RSV_VCL_R15 = 15,
36
+ BLA_W_LP = 16,
37
+ BLA_W_RADL = 17,
38
+ BLA_N_LP = 18,
39
+ IDR_W_RADL = 19,
40
+ IDR_N_LP = 20,
41
+ CRA_NUT = 21,
42
+ RSV_IRAP_VCL22 = 22,
43
+ RSV_IRAP_VCL23 = 23,
44
+ RSV_VCL24 = 24,
45
+ RSV_VCL25 = 25,
46
+ RSV_VCL26 = 26,
47
+ RSV_VCL27 = 27,
48
+ RSV_VCL28 = 28,
49
+ RSV_VCL29 = 29,
50
+ RSV_VCL30 = 30,
51
+ RSV_VCL31 = 31,
52
+ VPS_NUT = 32,
53
+ SPS_NUT = 33,
54
+ PPS_NUT = 34,
55
+ AUD_NUT = 35,
56
+ EOS_NUT = 36,
57
+ EOB_NUT = 37,
58
+ FD_NUT = 38,
59
+ PREFIX_SEI_NUT = 39,
60
+ SUFFIX_SEI_NUT = 40,
61
+ RSV_NVCL41 = 41,
62
+ RSV_NVCL42 = 42,
63
+ RSV_NVCL43 = 43,
64
+ RSV_NVCL44 = 44,
65
+ RSV_NVCL45 = 45,
66
+ RSV_NVCL46 = 46,
67
+ RSV_NVCL47 = 47,
68
+ UNSPEC48 = 48,
69
+ UNSPEC49 = 49,
70
+ UNSPEC50 = 50,
71
+ UNSPEC51 = 51,
72
+ UNSPEC52 = 52,
73
+ UNSPEC53 = 53,
74
+ UNSPEC54 = 54,
75
+ UNSPEC55 = 55,
76
+ UNSPEC56 = 56,
77
+ UNSPEC57 = 57,
78
+ UNSPEC58 = 58,
79
+ UNSPEC59 = 59,
80
+ UNSPEC60 = 60,
81
+ UNSPEC61 = 61,
82
+ UNSPEC62 = 62,
83
+ UNSPEC63 = 63
84
+ }
85
+ export interface AnnexBHelpers {
86
+ getUnitType(frame: Buffer): number;
87
+ splitHeader(frame: Buffer): [Buffer, Buffer];
88
+ isAUD(unitType: number): boolean;
89
+ }
90
+ export declare const H264Helpers: AnnexBHelpers;
91
+ export declare const H265Helpers: AnnexBHelpers;
92
+ export declare function splitNalu(frame: Buffer): Buffer<ArrayBufferLike>[];
93
+ export declare function mergeNalu(nalus: Buffer[]): Buffer<ArrayBuffer>;
@@ -0,0 +1,132 @@
1
+ export var H264NalUnitTypes;
2
+ (function (H264NalUnitTypes) {
3
+ H264NalUnitTypes[H264NalUnitTypes["Unspecified"] = 0] = "Unspecified";
4
+ H264NalUnitTypes[H264NalUnitTypes["CodedSliceNonIDR"] = 1] = "CodedSliceNonIDR";
5
+ H264NalUnitTypes[H264NalUnitTypes["CodedSlicePartitionA"] = 2] = "CodedSlicePartitionA";
6
+ H264NalUnitTypes[H264NalUnitTypes["CodedSlicePartitionB"] = 3] = "CodedSlicePartitionB";
7
+ H264NalUnitTypes[H264NalUnitTypes["CodedSlicePartitionC"] = 4] = "CodedSlicePartitionC";
8
+ H264NalUnitTypes[H264NalUnitTypes["CodedSliceIdr"] = 5] = "CodedSliceIdr";
9
+ H264NalUnitTypes[H264NalUnitTypes["SEI"] = 6] = "SEI";
10
+ H264NalUnitTypes[H264NalUnitTypes["SPS"] = 7] = "SPS";
11
+ H264NalUnitTypes[H264NalUnitTypes["PPS"] = 8] = "PPS";
12
+ H264NalUnitTypes[H264NalUnitTypes["AccessUnitDelimiter"] = 9] = "AccessUnitDelimiter";
13
+ H264NalUnitTypes[H264NalUnitTypes["EndOfSequence"] = 10] = "EndOfSequence";
14
+ H264NalUnitTypes[H264NalUnitTypes["EndOfStream"] = 11] = "EndOfStream";
15
+ H264NalUnitTypes[H264NalUnitTypes["FillerData"] = 12] = "FillerData";
16
+ H264NalUnitTypes[H264NalUnitTypes["SEIExtenstion"] = 13] = "SEIExtenstion";
17
+ H264NalUnitTypes[H264NalUnitTypes["PrefixNalUnit"] = 14] = "PrefixNalUnit";
18
+ H264NalUnitTypes[H264NalUnitTypes["SubsetSPS"] = 15] = "SubsetSPS";
19
+ })(H264NalUnitTypes || (H264NalUnitTypes = {}));
20
+ export var H265NalUnitTypes;
21
+ (function (H265NalUnitTypes) {
22
+ H265NalUnitTypes[H265NalUnitTypes["TRAIL_N"] = 0] = "TRAIL_N";
23
+ H265NalUnitTypes[H265NalUnitTypes["TRAIL_R"] = 1] = "TRAIL_R";
24
+ H265NalUnitTypes[H265NalUnitTypes["TSA_N"] = 2] = "TSA_N";
25
+ H265NalUnitTypes[H265NalUnitTypes["TSA_R"] = 3] = "TSA_R";
26
+ H265NalUnitTypes[H265NalUnitTypes["STSA_N"] = 4] = "STSA_N";
27
+ H265NalUnitTypes[H265NalUnitTypes["STSA_R"] = 5] = "STSA_R";
28
+ H265NalUnitTypes[H265NalUnitTypes["RADL_N"] = 6] = "RADL_N";
29
+ H265NalUnitTypes[H265NalUnitTypes["RADL_R"] = 7] = "RADL_R";
30
+ H265NalUnitTypes[H265NalUnitTypes["RASL_N"] = 8] = "RASL_N";
31
+ H265NalUnitTypes[H265NalUnitTypes["RASL_R"] = 9] = "RASL_R";
32
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL_N10"] = 10] = "RSV_VCL_N10";
33
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL_R11"] = 11] = "RSV_VCL_R11";
34
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL_N12"] = 12] = "RSV_VCL_N12";
35
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL_R13"] = 13] = "RSV_VCL_R13";
36
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL_N14"] = 14] = "RSV_VCL_N14";
37
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL_R15"] = 15] = "RSV_VCL_R15";
38
+ H265NalUnitTypes[H265NalUnitTypes["BLA_W_LP"] = 16] = "BLA_W_LP";
39
+ H265NalUnitTypes[H265NalUnitTypes["BLA_W_RADL"] = 17] = "BLA_W_RADL";
40
+ H265NalUnitTypes[H265NalUnitTypes["BLA_N_LP"] = 18] = "BLA_N_LP";
41
+ H265NalUnitTypes[H265NalUnitTypes["IDR_W_RADL"] = 19] = "IDR_W_RADL";
42
+ H265NalUnitTypes[H265NalUnitTypes["IDR_N_LP"] = 20] = "IDR_N_LP";
43
+ H265NalUnitTypes[H265NalUnitTypes["CRA_NUT"] = 21] = "CRA_NUT";
44
+ H265NalUnitTypes[H265NalUnitTypes["RSV_IRAP_VCL22"] = 22] = "RSV_IRAP_VCL22";
45
+ H265NalUnitTypes[H265NalUnitTypes["RSV_IRAP_VCL23"] = 23] = "RSV_IRAP_VCL23";
46
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL24"] = 24] = "RSV_VCL24";
47
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL25"] = 25] = "RSV_VCL25";
48
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL26"] = 26] = "RSV_VCL26";
49
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL27"] = 27] = "RSV_VCL27";
50
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL28"] = 28] = "RSV_VCL28";
51
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL29"] = 29] = "RSV_VCL29";
52
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL30"] = 30] = "RSV_VCL30";
53
+ H265NalUnitTypes[H265NalUnitTypes["RSV_VCL31"] = 31] = "RSV_VCL31";
54
+ H265NalUnitTypes[H265NalUnitTypes["VPS_NUT"] = 32] = "VPS_NUT";
55
+ H265NalUnitTypes[H265NalUnitTypes["SPS_NUT"] = 33] = "SPS_NUT";
56
+ H265NalUnitTypes[H265NalUnitTypes["PPS_NUT"] = 34] = "PPS_NUT";
57
+ H265NalUnitTypes[H265NalUnitTypes["AUD_NUT"] = 35] = "AUD_NUT";
58
+ H265NalUnitTypes[H265NalUnitTypes["EOS_NUT"] = 36] = "EOS_NUT";
59
+ H265NalUnitTypes[H265NalUnitTypes["EOB_NUT"] = 37] = "EOB_NUT";
60
+ H265NalUnitTypes[H265NalUnitTypes["FD_NUT"] = 38] = "FD_NUT";
61
+ H265NalUnitTypes[H265NalUnitTypes["PREFIX_SEI_NUT"] = 39] = "PREFIX_SEI_NUT";
62
+ H265NalUnitTypes[H265NalUnitTypes["SUFFIX_SEI_NUT"] = 40] = "SUFFIX_SEI_NUT";
63
+ H265NalUnitTypes[H265NalUnitTypes["RSV_NVCL41"] = 41] = "RSV_NVCL41";
64
+ H265NalUnitTypes[H265NalUnitTypes["RSV_NVCL42"] = 42] = "RSV_NVCL42";
65
+ H265NalUnitTypes[H265NalUnitTypes["RSV_NVCL43"] = 43] = "RSV_NVCL43";
66
+ H265NalUnitTypes[H265NalUnitTypes["RSV_NVCL44"] = 44] = "RSV_NVCL44";
67
+ H265NalUnitTypes[H265NalUnitTypes["RSV_NVCL45"] = 45] = "RSV_NVCL45";
68
+ H265NalUnitTypes[H265NalUnitTypes["RSV_NVCL46"] = 46] = "RSV_NVCL46";
69
+ H265NalUnitTypes[H265NalUnitTypes["RSV_NVCL47"] = 47] = "RSV_NVCL47";
70
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC48"] = 48] = "UNSPEC48";
71
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC49"] = 49] = "UNSPEC49";
72
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC50"] = 50] = "UNSPEC50";
73
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC51"] = 51] = "UNSPEC51";
74
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC52"] = 52] = "UNSPEC52";
75
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC53"] = 53] = "UNSPEC53";
76
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC54"] = 54] = "UNSPEC54";
77
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC55"] = 55] = "UNSPEC55";
78
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC56"] = 56] = "UNSPEC56";
79
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC57"] = 57] = "UNSPEC57";
80
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC58"] = 58] = "UNSPEC58";
81
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC59"] = 59] = "UNSPEC59";
82
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC60"] = 60] = "UNSPEC60";
83
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC61"] = 61] = "UNSPEC61";
84
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC62"] = 62] = "UNSPEC62";
85
+ H265NalUnitTypes[H265NalUnitTypes["UNSPEC63"] = 63] = "UNSPEC63";
86
+ })(H265NalUnitTypes || (H265NalUnitTypes = {}));
87
+ ;
88
+ export const H264Helpers = {
89
+ getUnitType(frame) {
90
+ return frame[0] & 0x1f;
91
+ },
92
+ splitHeader(frame) {
93
+ return [frame.subarray(0, 1), frame.subarray(1)];
94
+ },
95
+ isAUD(unitType) {
96
+ return unitType === H264NalUnitTypes.AccessUnitDelimiter;
97
+ }
98
+ };
99
+ export const H265Helpers = {
100
+ getUnitType(frame) {
101
+ return (frame[0] >> 1) & 0x3f;
102
+ },
103
+ splitHeader(frame) {
104
+ return [frame.subarray(0, 2), frame.subarray(2)];
105
+ },
106
+ isAUD(unitType) {
107
+ return unitType === H265NalUnitTypes.AUD_NUT;
108
+ }
109
+ };
110
+ // Get individual NAL units from an AVPacket frame
111
+ export function splitNalu(frame) {
112
+ const nalus = [];
113
+ let offset = 0;
114
+ while (offset < frame.length) {
115
+ const naluSize = frame.readUInt32BE(offset);
116
+ offset += 4;
117
+ const nalu = frame.subarray(offset, offset + naluSize);
118
+ nalus.push(nalu);
119
+ offset += nalu.length;
120
+ }
121
+ return nalus;
122
+ }
123
+ // Merge NAL units into an AVPacket frame
124
+ export function mergeNalu(nalus) {
125
+ const chunks = [];
126
+ for (const nalu of nalus) {
127
+ const size = Buffer.allocUnsafe(4);
128
+ size.writeUInt32BE(nalu.length);
129
+ chunks.push(size, nalu);
130
+ }
131
+ return Buffer.concat(chunks);
132
+ }
@@ -0,0 +1,118 @@
1
+ import { MediaUdp } from "./MediaUdp.js";
2
+ import { type TransportEncryptor } from "../encryptor/TransportEncryptor.js";
3
+ import { SupportedEncryptionModes } from "../../utils.js";
4
+ import WebSocket from 'ws';
5
+ import EventEmitter from "node:events";
6
+ import type { Message, GatewayRequest } from "./VoiceMessageTypes.js";
7
+ import type { Streamer } from "../Streamer.js";
8
+ type VoiceConnectionStatus = {
9
+ hasSession: boolean;
10
+ hasToken: boolean;
11
+ started: boolean;
12
+ resuming: boolean;
13
+ };
14
+ type WebRtcParameters = {
15
+ address: string;
16
+ port: number;
17
+ audioSsrc: number;
18
+ videoSsrc: number;
19
+ rtxSsrc: number;
20
+ supportedEncryptionModes: SupportedEncryptionModes[];
21
+ };
22
+ export type VideoAttributes = {
23
+ width: number;
24
+ height: number;
25
+ fps: number;
26
+ };
27
+ export declare const CodecPayloadType: {
28
+ readonly opus: {
29
+ readonly name: "opus";
30
+ readonly type: "audio";
31
+ readonly priority: 1000;
32
+ readonly payload_type: 120;
33
+ };
34
+ readonly H264: {
35
+ readonly name: "H264";
36
+ readonly type: "video";
37
+ readonly priority: 1000;
38
+ readonly payload_type: 101;
39
+ readonly rtx_payload_type: 102;
40
+ readonly encode: true;
41
+ readonly decode: true;
42
+ };
43
+ readonly H265: {
44
+ readonly name: "H265";
45
+ readonly type: "video";
46
+ readonly priority: 1000;
47
+ readonly payload_type: 103;
48
+ readonly rtx_payload_type: 104;
49
+ readonly encode: true;
50
+ readonly decode: true;
51
+ };
52
+ readonly VP8: {
53
+ readonly name: "VP8";
54
+ readonly type: "video";
55
+ readonly priority: 1000;
56
+ readonly payload_type: 105;
57
+ readonly rtx_payload_type: 106;
58
+ readonly encode: true;
59
+ readonly decode: true;
60
+ };
61
+ readonly VP9: {
62
+ readonly name: "VP9";
63
+ readonly type: "video";
64
+ readonly priority: 1000;
65
+ readonly payload_type: 107;
66
+ readonly rtx_payload_type: 108;
67
+ readonly encode: true;
68
+ readonly decode: true;
69
+ };
70
+ readonly AV1: {
71
+ readonly name: "AV1";
72
+ readonly type: "video";
73
+ readonly priority: 1000;
74
+ readonly payload_type: 109;
75
+ readonly rtx_payload_type: 110;
76
+ readonly encode: true;
77
+ readonly decode: true;
78
+ };
79
+ };
80
+ export declare abstract class BaseMediaConnection extends EventEmitter {
81
+ private interval;
82
+ udp: MediaUdp;
83
+ guildId: string | null;
84
+ channelId: string;
85
+ botId: string;
86
+ ws: WebSocket | null;
87
+ ready: (udp: MediaUdp) => void;
88
+ status: VoiceConnectionStatus;
89
+ server: string | null;
90
+ token: string | null;
91
+ session_id: string | null;
92
+ webRtcParams: WebRtcParameters | null;
93
+ private _streamer;
94
+ private _transportEncryptor?;
95
+ private _sequenceNumber;
96
+ constructor(streamer: Streamer, guildId: string | null, botId: string, channelId: string, callback: (udp: MediaUdp) => void);
97
+ abstract get serverId(): string | null;
98
+ get type(): "guild" | "call";
99
+ get transportEncryptor(): TransportEncryptor | undefined;
100
+ get streamer(): Streamer;
101
+ stop(): void;
102
+ setSession(session_id: string): void;
103
+ setTokens(server: string, token: string): void;
104
+ start(): void;
105
+ handleReady(d: Message.Ready): void;
106
+ handleProtocolAck(d: Message.SelectProtocolAck): void;
107
+ setupEvents(): void;
108
+ setupHeartbeat(interval: number): void;
109
+ sendOpcode<T extends GatewayRequest>(code: T["op"], data: T["d"]): void;
110
+ identify(): void;
111
+ resume(): void;
112
+ private setProtocols;
113
+ setVideoAttributes(enabled: false): void;
114
+ setVideoAttributes(enabled: true, attr: VideoAttributes): void;
115
+ setSpeaking(speaking: boolean): void;
116
+ sendVoice(): Promise<void>;
117
+ }
118
+ export {};