@discordjs/voice 0.6.0 → 0.7.0

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 (60) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +41 -18
  3. package/dist/index.d.ts +155 -89
  4. package/dist/index.js +10 -26
  5. package/dist/index.js.map +7 -1
  6. package/dist/index.mjs +10 -0
  7. package/dist/index.mjs.map +7 -0
  8. package/package.json +67 -96
  9. package/dist/DataStore.js +0 -151
  10. package/dist/DataStore.js.map +0 -1
  11. package/dist/VoiceConnection.js +0 -529
  12. package/dist/VoiceConnection.js.map +0 -1
  13. package/dist/audio/AudioPlayer.js +0 -449
  14. package/dist/audio/AudioPlayer.js.map +0 -1
  15. package/dist/audio/AudioPlayerError.js +0 -17
  16. package/dist/audio/AudioPlayerError.js.map +0 -1
  17. package/dist/audio/AudioResource.js +0 -162
  18. package/dist/audio/AudioResource.js.map +0 -1
  19. package/dist/audio/PlayerSubscription.js +0 -23
  20. package/dist/audio/PlayerSubscription.js.map +0 -1
  21. package/dist/audio/TransformerGraph.js +0 -233
  22. package/dist/audio/TransformerGraph.js.map +0 -1
  23. package/dist/audio/index.js +0 -18
  24. package/dist/audio/index.js.map +0 -1
  25. package/dist/joinVoiceChannel.js +0 -24
  26. package/dist/joinVoiceChannel.js.map +0 -1
  27. package/dist/networking/Networking.js +0 -457
  28. package/dist/networking/Networking.js.map +0 -1
  29. package/dist/networking/VoiceUDPSocket.js +0 -145
  30. package/dist/networking/VoiceUDPSocket.js.map +0 -1
  31. package/dist/networking/VoiceWebSocket.js +0 -129
  32. package/dist/networking/VoiceWebSocket.js.map +0 -1
  33. package/dist/networking/index.js +0 -16
  34. package/dist/networking/index.js.map +0 -1
  35. package/dist/receive/AudioReceiveStream.js +0 -64
  36. package/dist/receive/AudioReceiveStream.js.map +0 -1
  37. package/dist/receive/SSRCMap.js +0 -69
  38. package/dist/receive/SSRCMap.js.map +0 -1
  39. package/dist/receive/SpeakingMap.js +0 -38
  40. package/dist/receive/SpeakingMap.js.map +0 -1
  41. package/dist/receive/VoiceReceiver.js +0 -149
  42. package/dist/receive/VoiceReceiver.js.map +0 -1
  43. package/dist/receive/index.js +0 -16
  44. package/dist/receive/index.js.map +0 -1
  45. package/dist/util/Secretbox.js +0 -50
  46. package/dist/util/Secretbox.js.map +0 -1
  47. package/dist/util/abortAfter.js +0 -15
  48. package/dist/util/abortAfter.js.map +0 -1
  49. package/dist/util/adapter.js +0 -3
  50. package/dist/util/adapter.js.map +0 -1
  51. package/dist/util/demuxProbe.js +0 -90
  52. package/dist/util/demuxProbe.js.map +0 -1
  53. package/dist/util/entersState.js +0 -26
  54. package/dist/util/entersState.js.map +0 -1
  55. package/dist/util/generateDependencyReport.js +0 -82
  56. package/dist/util/generateDependencyReport.js.map +0 -1
  57. package/dist/util/index.js +0 -17
  58. package/dist/util/index.js.map +0 -1
  59. package/dist/util/util.js +0 -7
  60. package/dist/util/util.js.map +0 -1
@@ -1,449 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createAudioPlayer = exports.AudioPlayer = exports.AudioPlayerStatus = exports.NoSubscriberBehavior = exports.SILENCE_FRAME = void 0;
4
- const DataStore_1 = require("../DataStore");
5
- const util_1 = require("../util/util");
6
- const VoiceConnection_1 = require("../VoiceConnection");
7
- const AudioPlayerError_1 = require("./AudioPlayerError");
8
- const PlayerSubscription_1 = require("./PlayerSubscription");
9
- const tiny_typed_emitter_1 = require("tiny-typed-emitter");
10
- // The Opus "silent" frame
11
- exports.SILENCE_FRAME = Buffer.from([0xf8, 0xff, 0xfe]);
12
- /**
13
- * Describes the behavior of the player when an audio packet is played but there are no available
14
- * voice connections to play to.
15
- */
16
- var NoSubscriberBehavior;
17
- (function (NoSubscriberBehavior) {
18
- /**
19
- * Pauses playing the stream until a voice connection becomes available
20
- */
21
- NoSubscriberBehavior["Pause"] = "pause";
22
- /**
23
- * Continues to play through the resource regardless
24
- */
25
- NoSubscriberBehavior["Play"] = "play";
26
- /**
27
- * The player stops and enters the Idle state
28
- */
29
- NoSubscriberBehavior["Stop"] = "stop";
30
- })(NoSubscriberBehavior = exports.NoSubscriberBehavior || (exports.NoSubscriberBehavior = {}));
31
- var AudioPlayerStatus;
32
- (function (AudioPlayerStatus) {
33
- /**
34
- * When there is currently no resource for the player to be playing
35
- */
36
- AudioPlayerStatus["Idle"] = "idle";
37
- /**
38
- * When the player is waiting for an audio resource to become readable before transitioning to Playing
39
- */
40
- AudioPlayerStatus["Buffering"] = "buffering";
41
- /**
42
- * When the player has been manually paused
43
- */
44
- AudioPlayerStatus["Paused"] = "paused";
45
- /**
46
- * When the player is actively playing an audio resource
47
- */
48
- AudioPlayerStatus["Playing"] = "playing";
49
- /**
50
- * When the player has paused itself. Only possible with the "pause" no subscriber behavior.
51
- */
52
- AudioPlayerStatus["AutoPaused"] = "autopaused";
53
- })(AudioPlayerStatus = exports.AudioPlayerStatus || (exports.AudioPlayerStatus = {}));
54
- /**
55
- * Used to play audio resources (i.e. tracks, streams) to voice connections.
56
- *
57
- * @remarks
58
- * Audio players are designed to be re-used - even if a resource has finished playing, the player itself
59
- * can still be used.
60
- *
61
- * The AudioPlayer drives the timing of playback, and therefore is unaffected by voice connections
62
- * becoming unavailable. Its behavior in these scenarios can be configured.
63
- */
64
- class AudioPlayer extends tiny_typed_emitter_1.TypedEmitter {
65
- /**
66
- * Creates a new AudioPlayer
67
- */
68
- constructor(options = {}) {
69
- super();
70
- /**
71
- * A list of VoiceConnections that are registered to this AudioPlayer. The player will attempt to play audio
72
- * to the streams in this list.
73
- */
74
- this.subscribers = [];
75
- this._state = { status: AudioPlayerStatus.Idle };
76
- this.behaviors = {
77
- noSubscriber: NoSubscriberBehavior.Pause,
78
- maxMissedFrames: 5,
79
- ...options.behaviors,
80
- };
81
- this.debug = options.debug === false ? null : (message) => this.emit('debug', message);
82
- }
83
- /**
84
- * A list of subscribed voice connections that can currently receive audio to play
85
- */
86
- get playable() {
87
- return this.subscribers
88
- .filter(({ connection }) => connection.state.status === VoiceConnection_1.VoiceConnectionStatus.Ready)
89
- .map(({ connection }) => connection);
90
- }
91
- /**
92
- * Subscribes a VoiceConnection to the audio player's play list. If the VoiceConnection is already subscribed,
93
- * then the existing subscription is used.
94
- *
95
- * @remarks
96
- * This method should not be directly called. Instead, use VoiceConnection#subscribe.
97
- *
98
- * @param connection - The connection to subscribe
99
- * @returns The new subscription if the voice connection is not yet subscribed, otherwise the existing subscription.
100
- */
101
- subscribe(connection) {
102
- const existingSubscription = this.subscribers.find((subscription) => subscription.connection === connection);
103
- if (!existingSubscription) {
104
- const subscription = new PlayerSubscription_1.PlayerSubscription(connection, this);
105
- this.subscribers.push(subscription);
106
- setImmediate(() => this.emit('subscribe', subscription));
107
- return subscription;
108
- }
109
- return existingSubscription;
110
- }
111
- /**
112
- * Unsubscribes a subscription - i.e. removes a voice connection from the play list of the audio player.
113
- *
114
- * @remarks
115
- * This method should not be directly called. Instead, use PlayerSubscription#unsubscribe.
116
- *
117
- * @param subscription - The subscription to remove
118
- * @returns Whether or not the subscription existed on the player and was removed.
119
- */
120
- unsubscribe(subscription) {
121
- const index = this.subscribers.indexOf(subscription);
122
- const exists = index !== -1;
123
- if (exists) {
124
- this.subscribers.splice(index, 1);
125
- subscription.connection.setSpeaking(false);
126
- this.emit('unsubscribe', subscription);
127
- }
128
- return exists;
129
- }
130
- /**
131
- * The state that the player is in.
132
- */
133
- get state() {
134
- return this._state;
135
- }
136
- /**
137
- * Sets a new state for the player, performing clean-up operations where necessary.
138
- */
139
- set state(newState) {
140
- var _a;
141
- const oldState = this._state;
142
- const newResource = Reflect.get(newState, 'resource');
143
- if (oldState.status !== AudioPlayerStatus.Idle && oldState.resource !== newResource) {
144
- oldState.resource.playStream.on('error', util_1.noop);
145
- oldState.resource.playStream.off('error', oldState.onStreamError);
146
- oldState.resource.audioPlayer = undefined;
147
- oldState.resource.playStream.destroy();
148
- oldState.resource.playStream.read(); // required to ensure buffered data is drained, prevents memory leak
149
- }
150
- // When leaving the Buffering state (or buffering a new resource), then remove the event listeners from it
151
- if (oldState.status === AudioPlayerStatus.Buffering &&
152
- (newState.status !== AudioPlayerStatus.Buffering || newState.resource !== oldState.resource)) {
153
- oldState.resource.playStream.off('end', oldState.onFailureCallback);
154
- oldState.resource.playStream.off('close', oldState.onFailureCallback);
155
- oldState.resource.playStream.off('finish', oldState.onFailureCallback);
156
- oldState.resource.playStream.off('readable', oldState.onReadableCallback);
157
- }
158
- // transitioning into an idle should ensure that connections stop speaking
159
- if (newState.status === AudioPlayerStatus.Idle) {
160
- this._signalStopSpeaking();
161
- DataStore_1.deleteAudioPlayer(this);
162
- }
163
- // attach to the global audio player timer
164
- if (newResource) {
165
- DataStore_1.addAudioPlayer(this);
166
- }
167
- // playing -> playing state changes should still transition if a resource changed (seems like it would be useful!)
168
- const didChangeResources = oldState.status !== AudioPlayerStatus.Idle &&
169
- newState.status === AudioPlayerStatus.Playing &&
170
- oldState.resource !== newState.resource;
171
- this._state = newState;
172
- this.emit('stateChange', oldState, this._state);
173
- if (oldState.status !== newState.status || didChangeResources) {
174
- this.emit(newState.status, oldState, this._state);
175
- }
176
- (_a = this.debug) === null || _a === void 0 ? void 0 : _a.call(this, `state change:\nfrom ${stringifyState(oldState)}\nto ${stringifyState(newState)}`);
177
- }
178
- /**
179
- * Plays a new resource on the player. If the player is already playing a resource, the existing resource is destroyed
180
- * (it cannot be reused, even in another player) and is replaced with the new resource.
181
- *
182
- * @remarks
183
- * The player will transition to the Playing state once playback begins, and will return to the Idle state once
184
- * playback is ended.
185
- *
186
- * If the player was previously playing a resource and this method is called, the player will not transition to the
187
- * Idle state during the swap over.
188
- *
189
- * @param resource - The resource to play
190
- * @throws Will throw if attempting to play an audio resource that has already ended, or is being played by another player.
191
- */
192
- play(resource) {
193
- if (resource.ended) {
194
- throw new Error('Cannot play a resource that has already ended.');
195
- }
196
- if (resource.audioPlayer) {
197
- if (resource.audioPlayer === this) {
198
- return;
199
- }
200
- throw new Error('Resource is already being played by another audio player.');
201
- }
202
- resource.audioPlayer = this;
203
- // Attach error listeners to the stream that will propagate the error and then return to the Idle
204
- // state if the resource is still being used.
205
- const onStreamError = (error) => {
206
- if (this.state.status !== AudioPlayerStatus.Idle) {
207
- /**
208
- * Emitted when there is an error emitted from the audio resource played by the audio player
209
- *
210
- * @event AudioPlayer#error
211
- * @type {AudioPlayerError}
212
- */
213
- this.emit('error', new AudioPlayerError_1.AudioPlayerError(error, this.state.resource));
214
- }
215
- if (this.state.status !== AudioPlayerStatus.Idle && this.state.resource === resource) {
216
- this.state = {
217
- status: AudioPlayerStatus.Idle,
218
- };
219
- }
220
- };
221
- resource.playStream.once('error', onStreamError);
222
- if (resource.started) {
223
- this.state = {
224
- status: AudioPlayerStatus.Playing,
225
- missedFrames: 0,
226
- playbackDuration: 0,
227
- resource,
228
- onStreamError,
229
- };
230
- }
231
- else {
232
- const onReadableCallback = () => {
233
- if (this.state.status === AudioPlayerStatus.Buffering && this.state.resource === resource) {
234
- this.state = {
235
- status: AudioPlayerStatus.Playing,
236
- missedFrames: 0,
237
- playbackDuration: 0,
238
- resource,
239
- onStreamError,
240
- };
241
- }
242
- };
243
- const onFailureCallback = () => {
244
- if (this.state.status === AudioPlayerStatus.Buffering && this.state.resource === resource) {
245
- this.state = {
246
- status: AudioPlayerStatus.Idle,
247
- };
248
- }
249
- };
250
- resource.playStream.once('readable', onReadableCallback);
251
- resource.playStream.once('end', onFailureCallback);
252
- resource.playStream.once('close', onFailureCallback);
253
- resource.playStream.once('finish', onFailureCallback);
254
- this.state = {
255
- status: AudioPlayerStatus.Buffering,
256
- resource,
257
- onReadableCallback,
258
- onFailureCallback,
259
- onStreamError,
260
- };
261
- }
262
- }
263
- /**
264
- * Pauses playback of the current resource, if any.
265
- *
266
- * @param interpolateSilence - If true, the player will play 5 packets of silence after pausing to prevent audio glitches.
267
- * @returns true if the player was successfully paused, otherwise false.
268
- */
269
- pause(interpolateSilence = true) {
270
- if (this.state.status !== AudioPlayerStatus.Playing)
271
- return false;
272
- this.state = {
273
- ...this.state,
274
- status: AudioPlayerStatus.Paused,
275
- silencePacketsRemaining: interpolateSilence ? 5 : 0,
276
- };
277
- return true;
278
- }
279
- /**
280
- * Unpauses playback of the current resource, if any.
281
- *
282
- * @returns true if the player was successfully unpaused, otherwise false.
283
- */
284
- unpause() {
285
- if (this.state.status !== AudioPlayerStatus.Paused)
286
- return false;
287
- this.state = {
288
- ...this.state,
289
- status: AudioPlayerStatus.Playing,
290
- missedFrames: 0,
291
- };
292
- return true;
293
- }
294
- /**
295
- * Stops playback of the current resource and destroys the resource. The player will either transition to the Idle state,
296
- * or remain in its current state until the silence padding frames of the resource have been played.
297
- *
298
- * @param force - If true, will force the player to enter the Idle state even if the resource has silence padding frames.
299
- * @returns true if the player will come to a stop, otherwise false.
300
- */
301
- stop(force = false) {
302
- if (this.state.status === AudioPlayerStatus.Idle)
303
- return false;
304
- if (force || this.state.resource.silencePaddingFrames === 0) {
305
- this.state = {
306
- status: AudioPlayerStatus.Idle,
307
- };
308
- }
309
- else if (this.state.resource.silenceRemaining === -1) {
310
- this.state.resource.silenceRemaining = this.state.resource.silencePaddingFrames;
311
- }
312
- return true;
313
- }
314
- /**
315
- * Checks whether the underlying resource (if any) is playable (readable).
316
- *
317
- * @returns true if the resource is playable, false otherwise.
318
- */
319
- checkPlayable() {
320
- const state = this._state;
321
- if (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering)
322
- return false;
323
- // If the stream has been destroyed or is no longer readable, then transition to the Idle state.
324
- if (!state.resource.readable) {
325
- this.state = {
326
- status: AudioPlayerStatus.Idle,
327
- };
328
- return false;
329
- }
330
- return true;
331
- }
332
- /**
333
- * Called roughly every 20ms by the global audio player timer. Dispatches any audio packets that are buffered
334
- * by the active connections of this audio player.
335
- */
336
- _stepDispatch() {
337
- const state = this._state;
338
- // Guard against the Idle state
339
- if (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering)
340
- return;
341
- // Dispatch any audio packets that were prepared in the previous cycle
342
- this.playable.forEach((connection) => connection.dispatchAudio());
343
- }
344
- /**
345
- * Called roughly every 20ms by the global audio player timer. Attempts to read an audio packet from the
346
- * underlying resource of the stream, and then has all the active connections of the audio player prepare it
347
- * (encrypt it, append header data) so that it is ready to play at the start of the next cycle.
348
- */
349
- _stepPrepare() {
350
- const state = this._state;
351
- // Guard against the Idle state
352
- if (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering)
353
- return;
354
- // List of connections that can receive the packet
355
- const playable = this.playable;
356
- /* If the player was previously in the AutoPaused state, check to see whether there are newly available
357
- connections, allowing us to transition out of the AutoPaused state back into the Playing state */
358
- if (state.status === AudioPlayerStatus.AutoPaused && playable.length > 0) {
359
- this.state = {
360
- ...state,
361
- status: AudioPlayerStatus.Playing,
362
- missedFrames: 0,
363
- };
364
- }
365
- /* If the player is (auto)paused, check to see whether silence packets should be played and
366
- set a timeout to begin the next cycle, ending the current cycle here. */
367
- if (state.status === AudioPlayerStatus.Paused || state.status === AudioPlayerStatus.AutoPaused) {
368
- if (state.silencePacketsRemaining > 0) {
369
- state.silencePacketsRemaining--;
370
- this._preparePacket(exports.SILENCE_FRAME, playable, state);
371
- if (state.silencePacketsRemaining === 0) {
372
- this._signalStopSpeaking();
373
- }
374
- }
375
- return;
376
- }
377
- // If there are no available connections in this cycle, observe the configured "no subscriber" behavior.
378
- if (playable.length === 0) {
379
- if (this.behaviors.noSubscriber === NoSubscriberBehavior.Pause) {
380
- this.state = {
381
- ...state,
382
- status: AudioPlayerStatus.AutoPaused,
383
- silencePacketsRemaining: 5,
384
- };
385
- return;
386
- }
387
- else if (this.behaviors.noSubscriber === NoSubscriberBehavior.Stop) {
388
- this.stop(true);
389
- }
390
- }
391
- /* Attempt to read an Opus packet from the resource. If there isn't an available packet,
392
- play a silence packet. If there are 5 consecutive cycles with failed reads, then the
393
- playback will end. */
394
- const packet = state.resource.read();
395
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
396
- if (state.status === AudioPlayerStatus.Playing) {
397
- if (packet) {
398
- this._preparePacket(packet, playable, state);
399
- state.missedFrames = 0;
400
- }
401
- else {
402
- this._preparePacket(exports.SILENCE_FRAME, playable, state);
403
- state.missedFrames++;
404
- if (state.missedFrames >= this.behaviors.maxMissedFrames) {
405
- this.stop();
406
- }
407
- }
408
- }
409
- }
410
- /**
411
- * Signals to all the subscribed connections that they should send a packet to Discord indicating
412
- * they are no longer speaking. Called once playback of a resource ends.
413
- */
414
- _signalStopSpeaking() {
415
- return this.subscribers.forEach(({ connection }) => connection.setSpeaking(false));
416
- }
417
- /**
418
- * Instructs the given connections to each prepare this packet to be played at the start of the
419
- * next cycle.
420
- *
421
- * @param packet - The Opus packet to be prepared by each receiver
422
- * @param receivers - The connections that should play this packet
423
- */
424
- _preparePacket(packet, receivers, state) {
425
- state.playbackDuration += 20;
426
- receivers.forEach((connection) => connection.prepareAudioPacket(packet));
427
- }
428
- }
429
- exports.AudioPlayer = AudioPlayer;
430
- /**
431
- * Stringifies an AudioPlayerState instance
432
- *
433
- * @param state - The state to stringify
434
- */
435
- function stringifyState(state) {
436
- return JSON.stringify({
437
- ...state,
438
- resource: Reflect.has(state, 'resource'),
439
- stepTimeout: Reflect.has(state, 'stepTimeout'),
440
- });
441
- }
442
- /**
443
- * Creates a new AudioPlayer to be used
444
- */
445
- function createAudioPlayer(options) {
446
- return new AudioPlayer(options);
447
- }
448
- exports.createAudioPlayer = createAudioPlayer;
449
- //# sourceMappingURL=AudioPlayer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AudioPlayer.js","sourceRoot":"","sources":["../../src/audio/AudioPlayer.ts"],"names":[],"mappings":"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","sourcesContent":["import { addAudioPlayer, deleteAudioPlayer } from '../DataStore';\nimport { Awaited, noop } from '../util/util';\nimport { VoiceConnection, VoiceConnectionStatus } from '../VoiceConnection';\nimport { AudioPlayerError } from './AudioPlayerError';\nimport { AudioResource } from './AudioResource';\nimport { PlayerSubscription } from './PlayerSubscription';\nimport { TypedEmitter } from 'tiny-typed-emitter';\n\n// The Opus \"silent\" frame\nexport const SILENCE_FRAME = Buffer.from([0xf8, 0xff, 0xfe]);\n\n/**\n * Describes the behavior of the player when an audio packet is played but there are no available\n * voice connections to play to.\n */\nexport enum NoSubscriberBehavior {\n\t/**\n\t * Pauses playing the stream until a voice connection becomes available\n\t */\n\tPause = 'pause',\n\t/**\n\t * Continues to play through the resource regardless\n\t */\n\tPlay = 'play',\n\t/**\n\t * The player stops and enters the Idle state\n\t */\n\tStop = 'stop',\n}\n\nexport enum AudioPlayerStatus {\n\t/**\n\t * When there is currently no resource for the player to be playing\n\t */\n\tIdle = 'idle',\n\t/**\n\t * When the player is waiting for an audio resource to become readable before transitioning to Playing\n\t */\n\tBuffering = 'buffering',\n\t/**\n\t * When the player has been manually paused\n\t */\n\tPaused = 'paused',\n\t/**\n\t * When the player is actively playing an audio resource\n\t */\n\tPlaying = 'playing',\n\t/**\n\t * When the player has paused itself. Only possible with the \"pause\" no subscriber behavior.\n\t */\n\tAutoPaused = 'autopaused',\n}\n\n/**\n * Options that can be passed when creating an audio player, used to specify its behavior.\n */\nexport interface CreateAudioPlayerOptions {\n\tdebug?: boolean;\n\tbehaviors?: {\n\t\tnoSubscriber?: NoSubscriberBehavior;\n\t\tmaxMissedFrames?: number;\n\t};\n}\n\n/**\n * The state that an AudioPlayer is in when it has no resource to play. This is the starting state.\n */\nexport interface AudioPlayerIdleState {\n\tstatus: AudioPlayerStatus.Idle;\n}\n\n/**\n * The state that an AudioPlayer is in when it is waiting for a resource to become readable. Once this\n * happens, the AudioPlayer will enter the Playing state. If the resource ends/errors before this, then\n * it will re-enter the Idle state.\n */\nexport interface AudioPlayerBufferingState {\n\tstatus: AudioPlayerStatus.Buffering;\n\t/**\n\t * The resource that the AudioPlayer is waiting for\n\t */\n\tresource: AudioResource;\n\tonReadableCallback: () => void;\n\tonFailureCallback: () => void;\n\tonStreamError: (error: Error) => void;\n}\n\n/**\n * The state that an AudioPlayer is in when it is actively playing an AudioResource. When playback ends,\n * it will enter the Idle state.\n */\nexport interface AudioPlayerPlayingState {\n\tstatus: AudioPlayerStatus.Playing;\n\t/**\n\t * The number of consecutive times that the audio resource has been unable to provide an Opus frame.\n\t */\n\tmissedFrames: number;\n\t/**\n\t * The playback duration in milliseconds of the current audio resource. This includes filler silence packets\n\t * that have been played when the resource was buffering.\n\t */\n\tplaybackDuration: number;\n\t/**\n\t * The resource that is being played\n\t */\n\tresource: AudioResource;\n\tonStreamError: (error: Error) => void;\n}\n\n/**\n * The state that an AudioPlayer is in when it has either been explicitly paused by the user, or done\n * automatically by the AudioPlayer itself if there are no available subscribers.\n */\nexport interface AudioPlayerPausedState {\n\tstatus: AudioPlayerStatus.Paused | AudioPlayerStatus.AutoPaused;\n\t/**\n\t * How many silence packets still need to be played to avoid audio interpolation due to the stream suddenly pausing\n\t */\n\tsilencePacketsRemaining: number;\n\t/**\n\t * The playback duration in milliseconds of the current audio resource. This includes filler silence packets\n\t * that have been played when the resource was buffering.\n\t */\n\tplaybackDuration: number;\n\t/**\n\t * The current resource of the audio player\n\t */\n\tresource: AudioResource;\n\tonStreamError: (error: Error) => void;\n}\n\n/**\n * The various states that the player can be in.\n */\nexport type AudioPlayerState =\n\t| AudioPlayerIdleState\n\t| AudioPlayerBufferingState\n\t| AudioPlayerPlayingState\n\t| AudioPlayerPausedState;\n\nexport type AudioPlayerEvents = {\n\terror: (error: AudioPlayerError) => Awaited<void>;\n\tdebug: (message: string) => Awaited<void>;\n\tstateChange: (oldState: AudioPlayerState, newState: AudioPlayerState) => Awaited<void>;\n\tsubscribe: (subscription: PlayerSubscription) => Awaited<void>;\n\tunsubscribe: (subscription: PlayerSubscription) => Awaited<void>;\n} & {\n\t[status in AudioPlayerStatus]: (\n\t\toldState: AudioPlayerState,\n\t\tnewState: AudioPlayerState & { status: status },\n\t) => Awaited<void>;\n};\n\n/**\n * Used to play audio resources (i.e. tracks, streams) to voice connections.\n *\n * @remarks\n * Audio players are designed to be re-used - even if a resource has finished playing, the player itself\n * can still be used.\n *\n * The AudioPlayer drives the timing of playback, and therefore is unaffected by voice connections\n * becoming unavailable. Its behavior in these scenarios can be configured.\n */\nexport class AudioPlayer extends TypedEmitter<AudioPlayerEvents> {\n\t/**\n\t * The state that the AudioPlayer is in\n\t */\n\tprivate _state: AudioPlayerState;\n\n\t/**\n\t * A list of VoiceConnections that are registered to this AudioPlayer. The player will attempt to play audio\n\t * to the streams in this list.\n\t */\n\tprivate readonly subscribers: PlayerSubscription[] = [];\n\n\t/**\n\t * The behavior that the player should follow when it enters certain situations.\n\t */\n\tprivate readonly behaviors: {\n\t\tnoSubscriber: NoSubscriberBehavior;\n\t\tmaxMissedFrames: number;\n\t};\n\n\t/**\n\t * The debug logger function, if debugging is enabled.\n\t */\n\tprivate readonly debug: null | ((message: string) => void);\n\n\t/**\n\t * Creates a new AudioPlayer\n\t */\n\tpublic constructor(options: CreateAudioPlayerOptions = {}) {\n\t\tsuper();\n\t\tthis._state = { status: AudioPlayerStatus.Idle };\n\t\tthis.behaviors = {\n\t\t\tnoSubscriber: NoSubscriberBehavior.Pause,\n\t\t\tmaxMissedFrames: 5,\n\t\t\t...options.behaviors,\n\t\t};\n\t\tthis.debug = options.debug === false ? null : (message: string) => this.emit('debug', message);\n\t}\n\n\t/**\n\t * A list of subscribed voice connections that can currently receive audio to play\n\t */\n\tpublic get playable() {\n\t\treturn this.subscribers\n\t\t\t.filter(({ connection }) => connection.state.status === VoiceConnectionStatus.Ready)\n\t\t\t.map(({ connection }) => connection);\n\t}\n\n\t/**\n\t * Subscribes a VoiceConnection to the audio player's play list. If the VoiceConnection is already subscribed,\n\t * then the existing subscription is used.\n\t *\n\t * @remarks\n\t * This method should not be directly called. Instead, use VoiceConnection#subscribe.\n\t *\n\t * @param connection - The connection to subscribe\n\t * @returns The new subscription if the voice connection is not yet subscribed, otherwise the existing subscription.\n\t */\n\tprivate subscribe(connection: VoiceConnection) {\n\t\tconst existingSubscription = this.subscribers.find((subscription) => subscription.connection === connection);\n\t\tif (!existingSubscription) {\n\t\t\tconst subscription = new PlayerSubscription(connection, this);\n\t\t\tthis.subscribers.push(subscription);\n\t\t\tsetImmediate(() => this.emit('subscribe', subscription));\n\t\t\treturn subscription;\n\t\t}\n\t\treturn existingSubscription;\n\t}\n\n\t/**\n\t * Unsubscribes a subscription - i.e. removes a voice connection from the play list of the audio player.\n\t *\n\t * @remarks\n\t * This method should not be directly called. Instead, use PlayerSubscription#unsubscribe.\n\t *\n\t * @param subscription - The subscription to remove\n\t * @returns Whether or not the subscription existed on the player and was removed.\n\t */\n\tprivate unsubscribe(subscription: PlayerSubscription) {\n\t\tconst index = this.subscribers.indexOf(subscription);\n\t\tconst exists = index !== -1;\n\t\tif (exists) {\n\t\t\tthis.subscribers.splice(index, 1);\n\t\t\tsubscription.connection.setSpeaking(false);\n\t\t\tthis.emit('unsubscribe', subscription);\n\t\t}\n\t\treturn exists;\n\t}\n\n\t/**\n\t * The state that the player is in.\n\t */\n\tpublic get state() {\n\t\treturn this._state;\n\t}\n\n\t/**\n\t * Sets a new state for the player, performing clean-up operations where necessary.\n\t */\n\tpublic set state(newState: AudioPlayerState) {\n\t\tconst oldState = this._state;\n\t\tconst newResource = Reflect.get(newState, 'resource') as AudioResource | undefined;\n\n\t\tif (oldState.status !== AudioPlayerStatus.Idle && oldState.resource !== newResource) {\n\t\t\toldState.resource.playStream.on('error', noop);\n\t\t\toldState.resource.playStream.off('error', oldState.onStreamError);\n\t\t\toldState.resource.audioPlayer = undefined;\n\t\t\toldState.resource.playStream.destroy();\n\t\t\toldState.resource.playStream.read(); // required to ensure buffered data is drained, prevents memory leak\n\t\t}\n\n\t\t// When leaving the Buffering state (or buffering a new resource), then remove the event listeners from it\n\t\tif (\n\t\t\toldState.status === AudioPlayerStatus.Buffering &&\n\t\t\t(newState.status !== AudioPlayerStatus.Buffering || newState.resource !== oldState.resource)\n\t\t) {\n\t\t\toldState.resource.playStream.off('end', oldState.onFailureCallback);\n\t\t\toldState.resource.playStream.off('close', oldState.onFailureCallback);\n\t\t\toldState.resource.playStream.off('finish', oldState.onFailureCallback);\n\t\t\toldState.resource.playStream.off('readable', oldState.onReadableCallback);\n\t\t}\n\n\t\t// transitioning into an idle should ensure that connections stop speaking\n\t\tif (newState.status === AudioPlayerStatus.Idle) {\n\t\t\tthis._signalStopSpeaking();\n\t\t\tdeleteAudioPlayer(this);\n\t\t}\n\n\t\t// attach to the global audio player timer\n\t\tif (newResource) {\n\t\t\taddAudioPlayer(this);\n\t\t}\n\n\t\t// playing -> playing state changes should still transition if a resource changed (seems like it would be useful!)\n\t\tconst didChangeResources =\n\t\t\toldState.status !== AudioPlayerStatus.Idle &&\n\t\t\tnewState.status === AudioPlayerStatus.Playing &&\n\t\t\toldState.resource !== newState.resource;\n\n\t\tthis._state = newState;\n\n\t\tthis.emit('stateChange', oldState, this._state);\n\t\tif (oldState.status !== newState.status || didChangeResources) {\n\t\t\tthis.emit(newState.status, oldState, this._state as any);\n\t\t}\n\t\tthis.debug?.(`state change:\\nfrom ${stringifyState(oldState)}\\nto ${stringifyState(newState)}`);\n\t}\n\n\t/**\n\t * Plays a new resource on the player. If the player is already playing a resource, the existing resource is destroyed\n\t * (it cannot be reused, even in another player) and is replaced with the new resource.\n\t *\n\t * @remarks\n\t * The player will transition to the Playing state once playback begins, and will return to the Idle state once\n\t * playback is ended.\n\t *\n\t * If the player was previously playing a resource and this method is called, the player will not transition to the\n\t * Idle state during the swap over.\n\t *\n\t * @param resource - The resource to play\n\t * @throws Will throw if attempting to play an audio resource that has already ended, or is being played by another player.\n\t */\n\tpublic play<T>(resource: AudioResource<T>) {\n\t\tif (resource.ended) {\n\t\t\tthrow new Error('Cannot play a resource that has already ended.');\n\t\t}\n\n\t\tif (resource.audioPlayer) {\n\t\t\tif (resource.audioPlayer === this) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error('Resource is already being played by another audio player.');\n\t\t}\n\t\tresource.audioPlayer = this;\n\n\t\t// Attach error listeners to the stream that will propagate the error and then return to the Idle\n\t\t// state if the resource is still being used.\n\t\tconst onStreamError = (error: Error) => {\n\t\t\tif (this.state.status !== AudioPlayerStatus.Idle) {\n\t\t\t\t/**\n\t\t\t\t * Emitted when there is an error emitted from the audio resource played by the audio player\n\t\t\t\t *\n\t\t\t\t * @event AudioPlayer#error\n\t\t\t\t * @type {AudioPlayerError}\n\t\t\t\t */\n\t\t\t\tthis.emit('error', new AudioPlayerError(error, this.state.resource));\n\t\t\t}\n\n\t\t\tif (this.state.status !== AudioPlayerStatus.Idle && this.state.resource === resource) {\n\t\t\t\tthis.state = {\n\t\t\t\t\tstatus: AudioPlayerStatus.Idle,\n\t\t\t\t};\n\t\t\t}\n\t\t};\n\n\t\tresource.playStream.once('error', onStreamError);\n\n\t\tif (resource.started) {\n\t\t\tthis.state = {\n\t\t\t\tstatus: AudioPlayerStatus.Playing,\n\t\t\t\tmissedFrames: 0,\n\t\t\t\tplaybackDuration: 0,\n\t\t\t\tresource,\n\t\t\t\tonStreamError,\n\t\t\t};\n\t\t} else {\n\t\t\tconst onReadableCallback = () => {\n\t\t\t\tif (this.state.status === AudioPlayerStatus.Buffering && this.state.resource === resource) {\n\t\t\t\t\tthis.state = {\n\t\t\t\t\t\tstatus: AudioPlayerStatus.Playing,\n\t\t\t\t\t\tmissedFrames: 0,\n\t\t\t\t\t\tplaybackDuration: 0,\n\t\t\t\t\t\tresource,\n\t\t\t\t\t\tonStreamError,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst onFailureCallback = () => {\n\t\t\t\tif (this.state.status === AudioPlayerStatus.Buffering && this.state.resource === resource) {\n\t\t\t\t\tthis.state = {\n\t\t\t\t\t\tstatus: AudioPlayerStatus.Idle,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tresource.playStream.once('readable', onReadableCallback);\n\n\t\t\tresource.playStream.once('end', onFailureCallback);\n\t\t\tresource.playStream.once('close', onFailureCallback);\n\t\t\tresource.playStream.once('finish', onFailureCallback);\n\n\t\t\tthis.state = {\n\t\t\t\tstatus: AudioPlayerStatus.Buffering,\n\t\t\t\tresource,\n\t\t\t\tonReadableCallback,\n\t\t\t\tonFailureCallback,\n\t\t\t\tonStreamError,\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Pauses playback of the current resource, if any.\n\t *\n\t * @param interpolateSilence - If true, the player will play 5 packets of silence after pausing to prevent audio glitches.\n\t * @returns true if the player was successfully paused, otherwise false.\n\t */\n\tpublic pause(interpolateSilence = true) {\n\t\tif (this.state.status !== AudioPlayerStatus.Playing) return false;\n\t\tthis.state = {\n\t\t\t...this.state,\n\t\t\tstatus: AudioPlayerStatus.Paused,\n\t\t\tsilencePacketsRemaining: interpolateSilence ? 5 : 0,\n\t\t};\n\t\treturn true;\n\t}\n\n\t/**\n\t * Unpauses playback of the current resource, if any.\n\t *\n\t * @returns true if the player was successfully unpaused, otherwise false.\n\t */\n\tpublic unpause() {\n\t\tif (this.state.status !== AudioPlayerStatus.Paused) return false;\n\t\tthis.state = {\n\t\t\t...this.state,\n\t\t\tstatus: AudioPlayerStatus.Playing,\n\t\t\tmissedFrames: 0,\n\t\t};\n\t\treturn true;\n\t}\n\n\t/**\n\t * Stops playback of the current resource and destroys the resource. The player will either transition to the Idle state,\n\t * or remain in its current state until the silence padding frames of the resource have been played.\n\t *\n\t * @param force - If true, will force the player to enter the Idle state even if the resource has silence padding frames.\n\t * @returns true if the player will come to a stop, otherwise false.\n\t */\n\tpublic stop(force = false) {\n\t\tif (this.state.status === AudioPlayerStatus.Idle) return false;\n\t\tif (force || this.state.resource.silencePaddingFrames === 0) {\n\t\t\tthis.state = {\n\t\t\t\tstatus: AudioPlayerStatus.Idle,\n\t\t\t};\n\t\t} else if (this.state.resource.silenceRemaining === -1) {\n\t\t\tthis.state.resource.silenceRemaining = this.state.resource.silencePaddingFrames;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether the underlying resource (if any) is playable (readable).\n\t *\n\t * @returns true if the resource is playable, false otherwise.\n\t */\n\tpublic checkPlayable() {\n\t\tconst state = this._state;\n\t\tif (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering) return false;\n\n\t\t// If the stream has been destroyed or is no longer readable, then transition to the Idle state.\n\t\tif (!state.resource.readable) {\n\t\t\tthis.state = {\n\t\t\t\tstatus: AudioPlayerStatus.Idle,\n\t\t\t};\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Called roughly every 20ms by the global audio player timer. Dispatches any audio packets that are buffered\n\t * by the active connections of this audio player.\n\t */\n\tprivate _stepDispatch() {\n\t\tconst state = this._state;\n\n\t\t// Guard against the Idle state\n\t\tif (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering) return;\n\n\t\t// Dispatch any audio packets that were prepared in the previous cycle\n\t\tthis.playable.forEach((connection) => connection.dispatchAudio());\n\t}\n\n\t/**\n\t * Called roughly every 20ms by the global audio player timer. Attempts to read an audio packet from the\n\t * underlying resource of the stream, and then has all the active connections of the audio player prepare it\n\t * (encrypt it, append header data) so that it is ready to play at the start of the next cycle.\n\t */\n\tprivate _stepPrepare() {\n\t\tconst state = this._state;\n\n\t\t// Guard against the Idle state\n\t\tif (state.status === AudioPlayerStatus.Idle || state.status === AudioPlayerStatus.Buffering) return;\n\n\t\t// List of connections that can receive the packet\n\t\tconst playable = this.playable;\n\n\t\t/* If the player was previously in the AutoPaused state, check to see whether there are newly available\n\t\t connections, allowing us to transition out of the AutoPaused state back into the Playing state */\n\t\tif (state.status === AudioPlayerStatus.AutoPaused && playable.length > 0) {\n\t\t\tthis.state = {\n\t\t\t\t...state,\n\t\t\t\tstatus: AudioPlayerStatus.Playing,\n\t\t\t\tmissedFrames: 0,\n\t\t\t};\n\t\t}\n\n\t\t/* If the player is (auto)paused, check to see whether silence packets should be played and\n\t\t set a timeout to begin the next cycle, ending the current cycle here. */\n\t\tif (state.status === AudioPlayerStatus.Paused || state.status === AudioPlayerStatus.AutoPaused) {\n\t\t\tif (state.silencePacketsRemaining > 0) {\n\t\t\t\tstate.silencePacketsRemaining--;\n\t\t\t\tthis._preparePacket(SILENCE_FRAME, playable, state);\n\t\t\t\tif (state.silencePacketsRemaining === 0) {\n\t\t\t\t\tthis._signalStopSpeaking();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are no available connections in this cycle, observe the configured \"no subscriber\" behavior.\n\t\tif (playable.length === 0) {\n\t\t\tif (this.behaviors.noSubscriber === NoSubscriberBehavior.Pause) {\n\t\t\t\tthis.state = {\n\t\t\t\t\t...state,\n\t\t\t\t\tstatus: AudioPlayerStatus.AutoPaused,\n\t\t\t\t\tsilencePacketsRemaining: 5,\n\t\t\t\t};\n\t\t\t\treturn;\n\t\t\t} else if (this.behaviors.noSubscriber === NoSubscriberBehavior.Stop) {\n\t\t\t\tthis.stop(true);\n\t\t\t}\n\t\t}\n\n\t\t/* Attempt to read an Opus packet from the resource. If there isn't an available packet,\n\t\t\t play a silence packet. If there are 5 consecutive cycles with failed reads, then the\n\t\t\t playback will end. */\n\t\tconst packet: Buffer | null = state.resource.read();\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n\t\tif (state.status === AudioPlayerStatus.Playing) {\n\t\t\tif (packet) {\n\t\t\t\tthis._preparePacket(packet, playable, state);\n\t\t\t\tstate.missedFrames = 0;\n\t\t\t} else {\n\t\t\t\tthis._preparePacket(SILENCE_FRAME, playable, state);\n\t\t\t\tstate.missedFrames++;\n\t\t\t\tif (state.missedFrames >= this.behaviors.maxMissedFrames) {\n\t\t\t\t\tthis.stop();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Signals to all the subscribed connections that they should send a packet to Discord indicating\n\t * they are no longer speaking. Called once playback of a resource ends.\n\t */\n\tprivate _signalStopSpeaking() {\n\t\treturn this.subscribers.forEach(({ connection }) => connection.setSpeaking(false));\n\t}\n\n\t/**\n\t * Instructs the given connections to each prepare this packet to be played at the start of the\n\t * next cycle.\n\t *\n\t * @param packet - The Opus packet to be prepared by each receiver\n\t * @param receivers - The connections that should play this packet\n\t */\n\tprivate _preparePacket(\n\t\tpacket: Buffer,\n\t\treceivers: VoiceConnection[],\n\t\tstate: AudioPlayerPlayingState | AudioPlayerPausedState,\n\t) {\n\t\tstate.playbackDuration += 20;\n\t\treceivers.forEach((connection) => connection.prepareAudioPacket(packet));\n\t}\n}\n\n/**\n * Stringifies an AudioPlayerState instance\n *\n * @param state - The state to stringify\n */\nfunction stringifyState(state: AudioPlayerState) {\n\treturn JSON.stringify({\n\t\t...state,\n\t\tresource: Reflect.has(state, 'resource'),\n\t\tstepTimeout: Reflect.has(state, 'stepTimeout'),\n\t});\n}\n\n/**\n * Creates a new AudioPlayer to be used\n */\nexport function createAudioPlayer(options?: CreateAudioPlayerOptions) {\n\treturn new AudioPlayer(options);\n}\n"]}
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AudioPlayerError = void 0;
4
- /**
5
- * An error emitted by an AudioPlayer. Contains an attached resource to aid with
6
- * debugging and identifying where the error came from.
7
- */
8
- class AudioPlayerError extends Error {
9
- constructor(error, resource) {
10
- super(error.message);
11
- this.resource = resource;
12
- this.name = error.name;
13
- this.stack = error.stack;
14
- }
15
- }
16
- exports.AudioPlayerError = AudioPlayerError;
17
- //# sourceMappingURL=AudioPlayerError.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AudioPlayerError.js","sourceRoot":"","sources":["../../src/audio/AudioPlayerError.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACH,MAAa,gBAAiB,SAAQ,KAAK;IAK1C,YAAmB,KAAY,EAAE,QAAuB;QACvD,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,CAAC;CACD;AAXD,4CAWC","sourcesContent":["import type { AudioResource } from './AudioResource';\n\n/**\n * An error emitted by an AudioPlayer. Contains an attached resource to aid with\n * debugging and identifying where the error came from.\n */\nexport class AudioPlayerError extends Error {\n\t/**\n\t * The resource associated with the audio player at the time the error was thrown.\n\t */\n\tpublic readonly resource: AudioResource;\n\tpublic constructor(error: Error, resource: AudioResource) {\n\t\tsuper(error.message);\n\t\tthis.resource = resource;\n\t\tthis.name = error.name;\n\t\tthis.stack = error.stack;\n\t}\n}\n"]}