@discordjs/voice 0.5.6 → 0.7.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.
- package/LICENSE +190 -21
- package/README.md +41 -18
- package/dist/index.d.ts +356 -215
- package/dist/index.js +10 -26
- package/dist/index.js.map +7 -1
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +7 -0
- package/package.json +67 -93
- package/dist/DataStore.js +0 -151
- package/dist/DataStore.js.map +0 -1
- package/dist/VoiceConnection.js +0 -494
- package/dist/VoiceConnection.js.map +0 -1
- package/dist/audio/AudioPlayer.js +0 -449
- package/dist/audio/AudioPlayer.js.map +0 -1
- package/dist/audio/AudioPlayerError.js +0 -17
- package/dist/audio/AudioPlayerError.js.map +0 -1
- package/dist/audio/AudioResource.js +0 -164
- package/dist/audio/AudioResource.js.map +0 -1
- package/dist/audio/PlayerSubscription.js +0 -23
- package/dist/audio/PlayerSubscription.js.map +0 -1
- package/dist/audio/TransformerGraph.js +0 -233
- package/dist/audio/TransformerGraph.js.map +0 -1
- package/dist/audio/index.js +0 -18
- package/dist/audio/index.js.map +0 -1
- package/dist/joinVoiceChannel.js +0 -24
- package/dist/joinVoiceChannel.js.map +0 -1
- package/dist/networking/Networking.js +0 -457
- package/dist/networking/Networking.js.map +0 -1
- package/dist/networking/VoiceUDPSocket.js +0 -145
- package/dist/networking/VoiceUDPSocket.js.map +0 -1
- package/dist/networking/VoiceWebSocket.js +0 -129
- package/dist/networking/VoiceWebSocket.js.map +0 -1
- package/dist/networking/index.js +0 -16
- package/dist/networking/index.js.map +0 -1
- package/dist/receive/AudioReceiveStream.js +0 -20
- package/dist/receive/AudioReceiveStream.js.map +0 -1
- package/dist/receive/SSRCMap.js +0 -67
- package/dist/receive/SSRCMap.js.map +0 -1
- package/dist/receive/VoiceReceiver.js +0 -215
- package/dist/receive/VoiceReceiver.js.map +0 -1
- package/dist/receive/index.js +0 -16
- package/dist/receive/index.js.map +0 -1
- package/dist/util/Secretbox.js +0 -50
- package/dist/util/Secretbox.js.map +0 -1
- package/dist/util/adapter.js +0 -3
- package/dist/util/adapter.js.map +0 -1
- package/dist/util/demuxProbe.js +0 -90
- package/dist/util/demuxProbe.js.map +0 -1
- package/dist/util/entersState.js +0 -30
- package/dist/util/entersState.js.map +0 -1
- package/dist/util/generateDependencyReport.js +0 -82
- package/dist/util/generateDependencyReport.js.map +0 -1
- package/dist/util/index.js +0 -17
- package/dist/util/index.js.map +0 -1
- package/dist/util/util.js +0 -7
- package/dist/util/util.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceUDPSocket.js","sourceRoot":"","sources":["../../src/networking/VoiceUDPSocket.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSocket, Socket } from 'dgram';\nimport { isIPv4 } from 'net';\nimport { TypedEmitter } from 'tiny-typed-emitter';\nimport { Awaited } from '../util/util';\n\n/**\n * Stores an IP address and port. Used to store socket details for the local client as well as\n * for Discord.\n */\nexport interface SocketConfig {\n\tip: string;\n\tport: number;\n}\n\ninterface KeepAlive {\n\tvalue: number;\n\ttimestamp: number;\n}\n\nexport interface VoiceUDPSocketEvents {\n\terror: (error: Error) => Awaited<void>;\n\tclose: () => Awaited<void>;\n\tdebug: (message: string) => Awaited<void>;\n\tmessage: (message: Buffer) => Awaited<void>;\n}\n\n/**\n * The interval in milliseconds at which keep alive datagrams are sent\n */\nconst KEEP_ALIVE_INTERVAL = 5e3;\n\n/**\n * The maximum number of keep alive packets which can be missed\n */\nconst KEEP_ALIVE_LIMIT = 12;\n\n/**\n * The maximum value of the keep alive counter\n */\nconst MAX_COUNTER_VALUE = 2 ** 32 - 1;\n\n/**\n * Manages the UDP networking for a voice connection.\n */\nexport class VoiceUDPSocket extends TypedEmitter<VoiceUDPSocketEvents> {\n\t/**\n\t * The underlying network Socket for the VoiceUDPSocket.\n\t */\n\tprivate readonly socket: Socket;\n\n\t/**\n\t * The socket details for Discord (remote).\n\t */\n\tprivate readonly remote: SocketConfig;\n\n\t/**\n\t * A list of keep alives that are waiting to be acknowledged.\n\t */\n\tprivate readonly keepAlives: KeepAlive[];\n\n\t/**\n\t * The counter used in the keep alive mechanism\n\t */\n\tprivate keepAliveCounter = 0;\n\n\t/**\n\t * The buffer used to write the keep alive counter into\n\t */\n\tprivate readonly keepAliveBuffer: Buffer;\n\n\t/**\n\t * The Node.js interval for the keep-alive mechanism\n\t */\n\tprivate readonly keepAliveInterval: NodeJS.Timeout;\n\n\t/**\n\t * The time taken to receive a response to keep alive messages\n\t */\n\tpublic ping?: number;\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 VoiceUDPSocket.\n\t *\n\t * @param remote - Details of the remote socket\n\t */\n\tpublic constructor(remote: SocketConfig, debug = false) {\n\t\tsuper();\n\t\tthis.socket = createSocket('udp4');\n\t\tthis.socket.on('error', (error: Error) => this.emit('error', error));\n\t\tthis.socket.on('message', (buffer: Buffer) => this.onMessage(buffer));\n\t\tthis.socket.on('close', () => this.emit('close'));\n\t\tthis.remote = remote;\n\t\tthis.keepAlives = [];\n\t\tthis.keepAliveBuffer = Buffer.alloc(8);\n\t\tthis.keepAliveInterval = setInterval(() => this.keepAlive(), KEEP_ALIVE_INTERVAL);\n\t\tsetImmediate(() => this.keepAlive());\n\n\t\tthis.debug = debug ? (message: string) => this.emit('debug', message) : null;\n\t}\n\n\t/**\n\t * Called when a message is received on the UDP socket\n\t * @param buffer The received buffer\n\t */\n\tprivate onMessage(buffer: Buffer): void {\n\t\t// Handle keep alive message\n\t\tif (buffer.length === 8) {\n\t\t\tconst counter = buffer.readUInt32LE(0);\n\t\t\tconst index = this.keepAlives.findIndex(({ value }) => value === counter);\n\t\t\tif (index === -1) return;\n\t\t\tthis.ping = Date.now() - this.keepAlives[index].timestamp;\n\t\t\t// Delete all keep alives up to and including the received one\n\t\t\tthis.keepAlives.splice(0, index);\n\t\t}\n\t\t// Propagate the message\n\t\tthis.emit('message', buffer);\n\t}\n\n\t/**\n\t * Called at a regular interval to check whether we are still able to send datagrams to Discord\n\t */\n\tprivate keepAlive() {\n\t\tif (this.keepAlives.length >= KEEP_ALIVE_LIMIT) {\n\t\t\tthis.debug?.('UDP socket has not received enough responses from Discord - closing socket');\n\t\t\tthis.destroy();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.keepAliveBuffer.writeUInt32LE(this.keepAliveCounter, 0);\n\t\tthis.send(this.keepAliveBuffer);\n\t\tthis.keepAlives.push({\n\t\t\tvalue: this.keepAliveCounter,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\t\tthis.keepAliveCounter++;\n\t\tif (this.keepAliveCounter > MAX_COUNTER_VALUE) {\n\t\t\tthis.keepAliveCounter = 0;\n\t\t}\n\t}\n\n\t/**\n\t * Sends a buffer to Discord.\n\t *\n\t * @param buffer - The buffer to send\n\t */\n\tpublic send(buffer: Buffer) {\n\t\treturn this.socket.send(buffer, this.remote.port, this.remote.ip);\n\t}\n\n\t/**\n\t * Closes the socket, the instance will not be able to be reused.\n\t */\n\tpublic destroy() {\n\t\ttry {\n\t\t\tthis.socket.close();\n\t\t} catch {}\n\t\tclearInterval(this.keepAliveInterval);\n\t}\n\n\t/**\n\t * Performs IP discovery to discover the local address and port to be used for the voice connection.\n\t *\n\t * @param ssrc - The SSRC received from Discord\n\t */\n\tpublic performIPDiscovery(ssrc: number): Promise<SocketConfig> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst listener = (message: Buffer) => {\n\t\t\t\ttry {\n\t\t\t\t\tif (message.readUInt16BE(0) !== 2) return;\n\t\t\t\t\tconst packet = parseLocalPacket(message);\n\t\t\t\t\tthis.socket.off('message', listener);\n\t\t\t\t\tresolve(packet);\n\t\t\t\t} catch {}\n\t\t\t};\n\n\t\t\tthis.socket.on('message', listener);\n\t\t\tthis.socket.once('close', () => reject(new Error('Cannot perform IP discovery - socket closed')));\n\n\t\t\tconst discoveryBuffer = Buffer.alloc(74);\n\n\t\t\tdiscoveryBuffer.writeUInt16BE(1, 0);\n\t\t\tdiscoveryBuffer.writeUInt16BE(70, 2);\n\t\t\tdiscoveryBuffer.writeUInt32BE(ssrc, 4);\n\t\t\tthis.send(discoveryBuffer);\n\t\t});\n\t}\n}\n\n/**\n * Parses the response from Discord to aid with local IP discovery.\n *\n * @param message - The received message\n */\nexport function parseLocalPacket(message: Buffer): SocketConfig {\n\tconst packet = Buffer.from(message);\n\n\tconst ip = packet.slice(8, packet.indexOf(0, 8)).toString('utf-8');\n\n\tif (!isIPv4(ip)) {\n\t\tthrow new Error('Malformed IP address');\n\t}\n\n\tconst port = packet.readUInt16BE(packet.length - 2);\n\n\treturn { ip, port };\n}\n"]}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.VoiceWebSocket = void 0;
|
|
7
|
-
const ws_1 = __importDefault(require("ws"));
|
|
8
|
-
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
|
|
9
|
-
/**
|
|
10
|
-
* An extension of the WebSocket class to provide helper functionality when interacting
|
|
11
|
-
* with the Discord Voice gateway.
|
|
12
|
-
*/
|
|
13
|
-
class VoiceWebSocket extends tiny_typed_emitter_1.TypedEmitter {
|
|
14
|
-
/**
|
|
15
|
-
* Creates a new VoiceWebSocket
|
|
16
|
-
*
|
|
17
|
-
* @param address - The address to connect to
|
|
18
|
-
*/
|
|
19
|
-
constructor(address, debug) {
|
|
20
|
-
super();
|
|
21
|
-
/**
|
|
22
|
-
* The number of consecutively missed heartbeats.
|
|
23
|
-
*/
|
|
24
|
-
this.missedHeartbeats = 0;
|
|
25
|
-
this.ws = new ws_1.default(address);
|
|
26
|
-
this.ws.onmessage = (e) => this.onMessage(e);
|
|
27
|
-
this.ws.onopen = (e) => this.emit('open', e);
|
|
28
|
-
this.ws.onerror = (e) => this.emit('error', e instanceof Error ? e : e.error);
|
|
29
|
-
this.ws.onclose = (e) => this.emit('close', e);
|
|
30
|
-
this.lastHeartbeatAck = 0;
|
|
31
|
-
this.lastHeatbeatSend = 0;
|
|
32
|
-
this.debug = debug ? (message) => this.emit('debug', message) : null;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Destroys the VoiceWebSocket. The heartbeat interval is cleared, and the connection is closed.
|
|
36
|
-
*/
|
|
37
|
-
destroy() {
|
|
38
|
-
var _a;
|
|
39
|
-
try {
|
|
40
|
-
(_a = this.debug) === null || _a === void 0 ? void 0 : _a.call(this, 'destroyed');
|
|
41
|
-
this.setHeartbeatInterval(-1);
|
|
42
|
-
this.ws.close(1000);
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
this.emit('error', error);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Handles message events on the WebSocket. Attempts to JSON parse the messages and emit them
|
|
50
|
-
* as packets.
|
|
51
|
-
*
|
|
52
|
-
* @param event - The message event
|
|
53
|
-
*/
|
|
54
|
-
onMessage(event) {
|
|
55
|
-
var _a;
|
|
56
|
-
if (typeof event.data !== 'string')
|
|
57
|
-
return;
|
|
58
|
-
(_a = this.debug) === null || _a === void 0 ? void 0 : _a.call(this, `<< ${event.data}`);
|
|
59
|
-
let packet;
|
|
60
|
-
try {
|
|
61
|
-
packet = JSON.parse(event.data);
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
this.emit('error', error);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (packet.op === 6 /* HeartbeatAck */) {
|
|
68
|
-
this.lastHeartbeatAck = Date.now();
|
|
69
|
-
this.missedHeartbeats = 0;
|
|
70
|
-
this.ping = this.lastHeartbeatAck - this.lastHeatbeatSend;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Packet event.
|
|
74
|
-
*
|
|
75
|
-
* @event VoiceWebSocket#packet
|
|
76
|
-
* @type {any}
|
|
77
|
-
*/
|
|
78
|
-
this.emit('packet', packet);
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Sends a JSON-stringifiable packet over the WebSocket
|
|
82
|
-
*
|
|
83
|
-
* @param packet - The packet to send
|
|
84
|
-
*/
|
|
85
|
-
sendPacket(packet) {
|
|
86
|
-
var _a;
|
|
87
|
-
try {
|
|
88
|
-
const stringified = JSON.stringify(packet);
|
|
89
|
-
(_a = this.debug) === null || _a === void 0 ? void 0 : _a.call(this, `>> ${stringified}`);
|
|
90
|
-
return this.ws.send(stringified);
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
this.emit('error', error);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Sends a heartbeat over the WebSocket
|
|
98
|
-
*/
|
|
99
|
-
sendHeartbeat() {
|
|
100
|
-
this.lastHeatbeatSend = Date.now();
|
|
101
|
-
this.missedHeartbeats++;
|
|
102
|
-
const nonce = this.lastHeatbeatSend;
|
|
103
|
-
return this.sendPacket({
|
|
104
|
-
op: 3 /* Heartbeat */,
|
|
105
|
-
d: nonce,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Sets/clears an interval to send heartbeats over the WebSocket
|
|
110
|
-
*
|
|
111
|
-
* @param ms - The interval in milliseconds. If negative, the interval will be unset.
|
|
112
|
-
*/
|
|
113
|
-
setHeartbeatInterval(ms) {
|
|
114
|
-
if (typeof this.heartbeatInterval !== 'undefined')
|
|
115
|
-
clearInterval(this.heartbeatInterval);
|
|
116
|
-
if (ms > 0) {
|
|
117
|
-
this.heartbeatInterval = setInterval(() => {
|
|
118
|
-
if (this.lastHeatbeatSend !== 0 && this.missedHeartbeats >= 3) {
|
|
119
|
-
// Missed too many heartbeats - disconnect
|
|
120
|
-
this.ws.close();
|
|
121
|
-
this.setHeartbeatInterval(-1);
|
|
122
|
-
}
|
|
123
|
-
this.sendHeartbeat();
|
|
124
|
-
}, ms);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
exports.VoiceWebSocket = VoiceWebSocket;
|
|
129
|
-
//# sourceMappingURL=VoiceWebSocket.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceWebSocket.js","sourceRoot":"","sources":["../../src/networking/VoiceWebSocket.ts"],"names":[],"mappings":"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","sourcesContent":["import { VoiceOpcodes } from 'discord-api-types/voice/v4';\nimport WebSocket, { MessageEvent } from 'ws';\nimport { TypedEmitter } from 'tiny-typed-emitter';\nimport { Awaited } from '../util/util';\n\n/**\n * Debug event for VoiceWebSocket.\n *\n * @event VoiceWebSocket#debug\n * @type {string}\n */\n\nexport interface VoiceWebSocketEvents {\n\terror: (error: Error) => Awaited<void>;\n\topen: (event: WebSocket.OpenEvent) => Awaited<void>;\n\tclose: (event: WebSocket.CloseEvent) => Awaited<void>;\n\tdebug: (message: string) => Awaited<void>;\n\tpacket: (packet: any) => Awaited<void>;\n}\n\n/**\n * An extension of the WebSocket class to provide helper functionality when interacting\n * with the Discord Voice gateway.\n */\nexport class VoiceWebSocket extends TypedEmitter<VoiceWebSocketEvents> {\n\t/**\n\t * The current heartbeat interval, if any\n\t */\n\tprivate heartbeatInterval?: NodeJS.Timeout;\n\n\t/**\n\t * The time (milliseconds since UNIX epoch) that the last heartbeat acknowledgement packet was received.\n\t * This is set to 0 if an acknowledgement packet hasn't been received yet.\n\t */\n\tprivate lastHeartbeatAck: number;\n\n\t/**\n\t * The time (milliseconds since UNIX epoch) that the last heartbeat was sent. This is set to 0 if a heartbeat\n\t * hasn't been sent yet.\n\t */\n\tprivate lastHeatbeatSend: number;\n\n\t/**\n\t * The number of consecutively missed heartbeats.\n\t */\n\tprivate missedHeartbeats = 0;\n\n\t/**\n\t * The last recorded ping.\n\t */\n\tpublic ping?: number;\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 * The underlying WebSocket of this wrapper\n\t */\n\tprivate readonly ws: WebSocket;\n\n\t/**\n\t * Creates a new VoiceWebSocket\n\t *\n\t * @param address - The address to connect to\n\t */\n\tpublic constructor(address: string, debug: boolean) {\n\t\tsuper();\n\t\tthis.ws = new WebSocket(address);\n\t\tthis.ws.onmessage = (e) => this.onMessage(e);\n\t\tthis.ws.onopen = (e) => this.emit('open', e);\n\t\tthis.ws.onerror = (e: Error | WebSocket.ErrorEvent) => this.emit('error', e instanceof Error ? e : e.error);\n\t\tthis.ws.onclose = (e) => this.emit('close', e);\n\n\t\tthis.lastHeartbeatAck = 0;\n\t\tthis.lastHeatbeatSend = 0;\n\n\t\tthis.debug = debug ? (message: string) => this.emit('debug', message) : null;\n\t}\n\n\t/**\n\t * Destroys the VoiceWebSocket. The heartbeat interval is cleared, and the connection is closed.\n\t */\n\tpublic destroy() {\n\t\ttry {\n\t\t\tthis.debug?.('destroyed');\n\t\t\tthis.setHeartbeatInterval(-1);\n\t\t\tthis.ws.close(1000);\n\t\t} catch (error) {\n\t\t\tthis.emit('error', error);\n\t\t}\n\t}\n\n\t/**\n\t * Handles message events on the WebSocket. Attempts to JSON parse the messages and emit them\n\t * as packets.\n\t *\n\t * @param event - The message event\n\t */\n\tpublic onMessage(event: MessageEvent) {\n\t\tif (typeof event.data !== 'string') return;\n\n\t\tthis.debug?.(`<< ${event.data}`);\n\n\t\tlet packet: any;\n\t\ttry {\n\t\t\tpacket = JSON.parse(event.data);\n\t\t} catch (error) {\n\t\t\tthis.emit('error', error);\n\t\t\treturn;\n\t\t}\n\n\t\tif (packet.op === VoiceOpcodes.HeartbeatAck) {\n\t\t\tthis.lastHeartbeatAck = Date.now();\n\t\t\tthis.missedHeartbeats = 0;\n\t\t\tthis.ping = this.lastHeartbeatAck - this.lastHeatbeatSend;\n\t\t}\n\n\t\t/**\n\t\t * Packet event.\n\t\t *\n\t\t * @event VoiceWebSocket#packet\n\t\t * @type {any}\n\t\t */\n\t\tthis.emit('packet', packet);\n\t}\n\n\t/**\n\t * Sends a JSON-stringifiable packet over the WebSocket\n\t *\n\t * @param packet - The packet to send\n\t */\n\tpublic sendPacket(packet: any) {\n\t\ttry {\n\t\t\tconst stringified = JSON.stringify(packet);\n\t\t\tthis.debug?.(`>> ${stringified}`);\n\t\t\treturn this.ws.send(stringified);\n\t\t} catch (error) {\n\t\t\tthis.emit('error', error);\n\t\t}\n\t}\n\n\t/**\n\t * Sends a heartbeat over the WebSocket\n\t */\n\tprivate sendHeartbeat() {\n\t\tthis.lastHeatbeatSend = Date.now();\n\t\tthis.missedHeartbeats++;\n\t\tconst nonce = this.lastHeatbeatSend;\n\t\treturn this.sendPacket({\n\t\t\top: VoiceOpcodes.Heartbeat,\n\t\t\td: nonce,\n\t\t});\n\t}\n\n\t/**\n\t * Sets/clears an interval to send heartbeats over the WebSocket\n\t *\n\t * @param ms - The interval in milliseconds. If negative, the interval will be unset.\n\t */\n\tpublic setHeartbeatInterval(ms: number) {\n\t\tif (typeof this.heartbeatInterval !== 'undefined') clearInterval(this.heartbeatInterval);\n\t\tif (ms > 0) {\n\t\t\tthis.heartbeatInterval = setInterval(() => {\n\t\t\t\tif (this.lastHeatbeatSend !== 0 && this.missedHeartbeats >= 3) {\n\t\t\t\t\t// Missed too many heartbeats - disconnect\n\t\t\t\t\tthis.ws.close();\n\t\t\t\t\tthis.setHeartbeatInterval(-1);\n\t\t\t\t}\n\t\t\t\tthis.sendHeartbeat();\n\t\t\t}, ms);\n\t\t}\n\t}\n}\n"]}
|
package/dist/networking/index.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
-
};
|
|
12
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
__exportStar(require("./Networking"), exports);
|
|
14
|
-
__exportStar(require("./VoiceUDPSocket"), exports);
|
|
15
|
-
__exportStar(require("./VoiceWebSocket"), exports);
|
|
16
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/networking/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,+CAA6B;AAC7B,mDAAiC;AACjC,mDAAiC","sourcesContent":["export * from './Networking';\nexport * from './VoiceUDPSocket';\nexport * from './VoiceWebSocket';\n"]}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AudioReceiveStream = void 0;
|
|
4
|
-
const stream_1 = require("stream");
|
|
5
|
-
/**
|
|
6
|
-
* A readable stream of Opus packets received from a specific entity
|
|
7
|
-
* in a Discord voice connection.
|
|
8
|
-
*/
|
|
9
|
-
class AudioReceiveStream extends stream_1.Readable {
|
|
10
|
-
constructor(options) {
|
|
11
|
-
super({
|
|
12
|
-
...options,
|
|
13
|
-
objectMode: true,
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
17
|
-
_read() { }
|
|
18
|
-
}
|
|
19
|
-
exports.AudioReceiveStream = AudioReceiveStream;
|
|
20
|
-
//# sourceMappingURL=AudioReceiveStream.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AudioReceiveStream.js","sourceRoot":"","sources":["../../src/receive/AudioReceiveStream.ts"],"names":[],"mappings":";;;AAAA,mCAAmD;AAEnD;;;GAGG;AACH,MAAa,kBAAmB,SAAQ,iBAAQ;IAC/C,YAAmB,OAAyB;QAC3C,KAAK,CAAC;YACL,GAAG,OAAO;YACV,UAAU,EAAE,IAAI;SAChB,CAAC,CAAC;IACJ,CAAC;IAED,gEAAgE;IACzD,KAAK,KAAI,CAAC;CACjB;AAVD,gDAUC","sourcesContent":["import { Readable, ReadableOptions } from 'stream';\n\n/**\n * A readable stream of Opus packets received from a specific entity\n * in a Discord voice connection.\n */\nexport class AudioReceiveStream extends Readable {\n\tpublic constructor(options?: ReadableOptions) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tobjectMode: true,\n\t\t});\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-empty-function\n\tpublic _read() {}\n}\n"]}
|
package/dist/receive/SSRCMap.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SSRCMap = void 0;
|
|
4
|
-
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
|
|
5
|
-
/**
|
|
6
|
-
* Maps audio SSRCs to data of users in voice connections.
|
|
7
|
-
*/
|
|
8
|
-
class SSRCMap extends tiny_typed_emitter_1.TypedEmitter {
|
|
9
|
-
constructor() {
|
|
10
|
-
super();
|
|
11
|
-
this.map = new Map();
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Updates the map with new user data
|
|
15
|
-
*
|
|
16
|
-
* @param data The data to update with
|
|
17
|
-
*/
|
|
18
|
-
update(data) {
|
|
19
|
-
const existing = this.map.get(data.audioSSRC);
|
|
20
|
-
const newValue = {
|
|
21
|
-
...this.map.get(data.audioSSRC),
|
|
22
|
-
...data,
|
|
23
|
-
};
|
|
24
|
-
this.map.set(data.audioSSRC, newValue);
|
|
25
|
-
this.emit('update', existing, newValue);
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Gets the stored voice data of a user.
|
|
29
|
-
*
|
|
30
|
-
* @param target The target, either their user ID or audio SSRC
|
|
31
|
-
*/
|
|
32
|
-
get(target) {
|
|
33
|
-
if (typeof target === 'number') {
|
|
34
|
-
return this.map.get(target);
|
|
35
|
-
}
|
|
36
|
-
for (const data of this.map.values()) {
|
|
37
|
-
if (data.userId === target) {
|
|
38
|
-
return data;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Deletes the stored voice data about a user.
|
|
44
|
-
*
|
|
45
|
-
* @param target The target of the delete operation, either their audio SSRC or user ID
|
|
46
|
-
* @returns The data that was deleted, if any
|
|
47
|
-
*/
|
|
48
|
-
delete(target) {
|
|
49
|
-
if (typeof target === 'number') {
|
|
50
|
-
const existing = this.map.get(target);
|
|
51
|
-
if (existing) {
|
|
52
|
-
this.map.delete(target);
|
|
53
|
-
this.emit('delete', existing);
|
|
54
|
-
}
|
|
55
|
-
return existing;
|
|
56
|
-
}
|
|
57
|
-
for (const [audioSSRC, data] of this.map.entries()) {
|
|
58
|
-
if (data.userId === target) {
|
|
59
|
-
this.map.delete(audioSSRC);
|
|
60
|
-
this.emit('delete', data);
|
|
61
|
-
return data;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
exports.SSRCMap = SSRCMap;
|
|
67
|
-
//# sourceMappingURL=SSRCMap.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SSRCMap.js","sourceRoot":"","sources":["../../src/receive/SSRCMap.ts"],"names":[],"mappings":";;;AAAA,2DAAkD;AA8BlD;;GAEG;AACH,MAAa,OAAQ,SAAQ,iCAA2B;IAMvD;QACC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,IAAmB;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAE9C,MAAM,QAAQ,GAAG;YAChB,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;YAC/B,GAAG,IAAI;SACP,CAAC;QAEF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACI,GAAG,CAAC,MAAuB;QACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;SAC5B;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE;YACrC,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE;gBAC3B,OAAO,IAAI,CAAC;aACZ;SACD;IACF,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,MAAuB;QACpC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,QAAQ,EAAE;gBACb,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACxB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;aAC9B;YACD,OAAO,QAAQ,CAAC;SAChB;QACD,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE;YACnD,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE;gBAC3B,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC1B,OAAO,IAAI,CAAC;aACZ;SACD;IACF,CAAC;CACD;AAnED,0BAmEC","sourcesContent":["import { TypedEmitter } from 'tiny-typed-emitter';\nimport { Awaited } from '../util/util';\n\n/**\n * The known data for a user in a Discord voice connection\n */\nexport interface VoiceUserData {\n\t/**\n\t * The SSRC of the user's audio stream\n\t */\n\taudioSSRC: number;\n\t/**\n\t * The SSRC of the user's video stream (if one exists).\n\t * Cannot be 0. If undefined, the user has no video stream.\n\t */\n\tvideoSSRC?: number;\n\t/**\n\t * The Discord user ID of the user\n\t */\n\tuserId: string;\n}\n\n/**\n * The events that an SSRCMap may emit.\n */\nexport interface SSRCMapEvents {\n\tupdate: (oldData: VoiceUserData | undefined, newData: VoiceUserData) => Awaited<void>;\n\tdelete: (deletedData: VoiceUserData) => Awaited<void>;\n}\n\n/**\n * Maps audio SSRCs to data of users in voice connections.\n */\nexport class SSRCMap extends TypedEmitter<SSRCMapEvents> {\n\t/**\n\t * The underlying map\n\t */\n\tprivate readonly map: Map<number, VoiceUserData>;\n\n\tpublic constructor() {\n\t\tsuper();\n\t\tthis.map = new Map();\n\t}\n\n\t/**\n\t * Updates the map with new user data\n\t *\n\t * @param data The data to update with\n\t */\n\tpublic update(data: VoiceUserData) {\n\t\tconst existing = this.map.get(data.audioSSRC);\n\n\t\tconst newValue = {\n\t\t\t...this.map.get(data.audioSSRC),\n\t\t\t...data,\n\t\t};\n\n\t\tthis.map.set(data.audioSSRC, newValue);\n\t\tthis.emit('update', existing, newValue);\n\t}\n\n\t/**\n\t * Gets the stored voice data of a user.\n\t *\n\t * @param target The target, either their user ID or audio SSRC\n\t */\n\tpublic get(target: number | string) {\n\t\tif (typeof target === 'number') {\n\t\t\treturn this.map.get(target);\n\t\t}\n\t\tfor (const data of this.map.values()) {\n\t\t\tif (data.userId === target) {\n\t\t\t\treturn data;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Deletes the stored voice data about a user.\n\t *\n\t * @param target The target of the delete operation, either their audio SSRC or user ID\n\t * @returns The data that was deleted, if any\n\t */\n\tpublic delete(target: number | string) {\n\t\tif (typeof target === 'number') {\n\t\t\tconst existing = this.map.get(target);\n\t\t\tif (existing) {\n\t\t\t\tthis.map.delete(target);\n\t\t\t\tthis.emit('delete', existing);\n\t\t\t}\n\t\t\treturn existing;\n\t\t}\n\t\tfor (const [audioSSRC, data] of this.map.entries()) {\n\t\t\tif (data.userId === target) {\n\t\t\t\tthis.map.delete(audioSSRC);\n\t\t\t\tthis.emit('delete', data);\n\t\t\t\treturn data;\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createVoiceReceiver = exports.VoiceReceiver = void 0;
|
|
4
|
-
const AudioPlayer_1 = require("../audio/AudioPlayer");
|
|
5
|
-
const Secretbox_1 = require("../util/Secretbox");
|
|
6
|
-
const AudioReceiveStream_1 = require("./AudioReceiveStream");
|
|
7
|
-
const SSRCMap_1 = require("./SSRCMap");
|
|
8
|
-
/**
|
|
9
|
-
* Attaches to a VoiceConnection, allowing you to receive audio packets from other
|
|
10
|
-
* users that are speaking.
|
|
11
|
-
*
|
|
12
|
-
* @beta
|
|
13
|
-
*/
|
|
14
|
-
class VoiceReceiver {
|
|
15
|
-
constructor(voiceConnection) {
|
|
16
|
-
this.voiceConnection = voiceConnection;
|
|
17
|
-
this.ssrcMap = new SSRCMap_1.SSRCMap();
|
|
18
|
-
this.subscriptions = new Map();
|
|
19
|
-
this.connectionData = {};
|
|
20
|
-
const onWsPacket = (packet) => this.onWsPacket(packet);
|
|
21
|
-
const onUdpMessage = (msg) => this.onUdpMessage(msg);
|
|
22
|
-
const applyConnectionData = (connectionData) => {
|
|
23
|
-
this.connectionData = {
|
|
24
|
-
...this.connectionData,
|
|
25
|
-
...connectionData,
|
|
26
|
-
};
|
|
27
|
-
if (connectionData.packetsPlayed === 0) {
|
|
28
|
-
this.voiceConnection.playOpusPacket(AudioPlayer_1.SILENCE_FRAME);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
// Bind listeners for updates
|
|
32
|
-
const onNetworkingChange = (oldState, newState) => {
|
|
33
|
-
const oldWs = Reflect.get(oldState, 'ws');
|
|
34
|
-
const oldUdp = Reflect.get(oldState, 'udp');
|
|
35
|
-
const newWs = Reflect.get(newState, 'ws');
|
|
36
|
-
const newUdp = Reflect.get(newState, 'udp');
|
|
37
|
-
const connectionData = Reflect.get(newState, 'connectionData');
|
|
38
|
-
if (connectionData)
|
|
39
|
-
applyConnectionData(connectionData);
|
|
40
|
-
if (newWs !== oldWs) {
|
|
41
|
-
oldWs === null || oldWs === void 0 ? void 0 : oldWs.off('packet', onWsPacket);
|
|
42
|
-
newWs === null || newWs === void 0 ? void 0 : newWs.on('packet', onWsPacket);
|
|
43
|
-
}
|
|
44
|
-
if (newUdp !== oldUdp) {
|
|
45
|
-
oldUdp === null || oldUdp === void 0 ? void 0 : oldUdp.off('message', onUdpMessage);
|
|
46
|
-
newUdp === null || newUdp === void 0 ? void 0 : newUdp.on('message', onUdpMessage);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
this.voiceConnection.on('stateChange', (oldState, newState) => {
|
|
50
|
-
const oldNetworking = Reflect.get(oldState, 'networking');
|
|
51
|
-
const newNetworking = Reflect.get(newState, 'networking');
|
|
52
|
-
if (newNetworking !== oldNetworking) {
|
|
53
|
-
oldNetworking === null || oldNetworking === void 0 ? void 0 : oldNetworking.off('stateChange', onNetworkingChange);
|
|
54
|
-
newNetworking === null || newNetworking === void 0 ? void 0 : newNetworking.on('stateChange', onNetworkingChange);
|
|
55
|
-
if (newNetworking) {
|
|
56
|
-
const ws = Reflect.get(newNetworking.state, 'ws');
|
|
57
|
-
const udp = Reflect.get(newNetworking.state, 'udp');
|
|
58
|
-
const connectionData = Reflect.get(newNetworking.state, 'connectionData');
|
|
59
|
-
ws === null || ws === void 0 ? void 0 : ws.on('packet', onWsPacket);
|
|
60
|
-
udp === null || udp === void 0 ? void 0 : udp.on('message', onUdpMessage);
|
|
61
|
-
if (connectionData)
|
|
62
|
-
applyConnectionData(connectionData);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
// Bind listeners for the existing state
|
|
67
|
-
const networking = Reflect.get(voiceConnection.state, 'networking');
|
|
68
|
-
if (networking) {
|
|
69
|
-
const ws = Reflect.get(networking.state, 'ws');
|
|
70
|
-
const udp = Reflect.get(networking.state, 'udp');
|
|
71
|
-
const connectionData = Reflect.get(networking.state, 'connectionData');
|
|
72
|
-
ws === null || ws === void 0 ? void 0 : ws.on('packet', onWsPacket);
|
|
73
|
-
udp === null || udp === void 0 ? void 0 : udp.on('message', onUdpMessage);
|
|
74
|
-
if (connectionData)
|
|
75
|
-
applyConnectionData(connectionData);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Called when a packet is received on the attached connection's WebSocket.
|
|
80
|
-
*
|
|
81
|
-
* @param packet The received packet
|
|
82
|
-
*/
|
|
83
|
-
onWsPacket(packet) {
|
|
84
|
-
var _a, _b, _c, _d, _e;
|
|
85
|
-
if (packet.op === 13 /* ClientDisconnect */ && typeof ((_a = packet.d) === null || _a === void 0 ? void 0 : _a.user_id) === 'string') {
|
|
86
|
-
this.ssrcMap.delete(packet.d.user_id);
|
|
87
|
-
}
|
|
88
|
-
else if (packet.op === 5 /* Speaking */ &&
|
|
89
|
-
typeof ((_b = packet.d) === null || _b === void 0 ? void 0 : _b.user_id) === 'string' &&
|
|
90
|
-
typeof ((_c = packet.d) === null || _c === void 0 ? void 0 : _c.ssrc) === 'number') {
|
|
91
|
-
this.ssrcMap.update({ userId: packet.d.user_id, audioSSRC: packet.d.ssrc });
|
|
92
|
-
}
|
|
93
|
-
else if (packet.op === 12 /* ClientConnect */ &&
|
|
94
|
-
typeof ((_d = packet.d) === null || _d === void 0 ? void 0 : _d.user_id) === 'string' &&
|
|
95
|
-
typeof ((_e = packet.d) === null || _e === void 0 ? void 0 : _e.audio_ssrc) === 'number') {
|
|
96
|
-
this.ssrcMap.update({
|
|
97
|
-
userId: packet.d.user_id,
|
|
98
|
-
audioSSRC: packet.d.audio_ssrc,
|
|
99
|
-
videoSSRC: packet.d.video_ssrc === 0 ? undefined : packet.d.video_ssrc,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
decrypt(buffer, mode, nonce, secretKey) {
|
|
104
|
-
// Choose correct nonce depending on encryption
|
|
105
|
-
let end;
|
|
106
|
-
if (mode === 'xsalsa20_poly1305_lite') {
|
|
107
|
-
buffer.copy(nonce, 0, buffer.length - 4);
|
|
108
|
-
end = buffer.length - 4;
|
|
109
|
-
}
|
|
110
|
-
else if (mode === 'xsalsa20_poly1305_suffix') {
|
|
111
|
-
buffer.copy(nonce, 0, buffer.length - 24);
|
|
112
|
-
end = buffer.length - 24;
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
buffer.copy(nonce, 0, 0, 12);
|
|
116
|
-
}
|
|
117
|
-
// Open packet
|
|
118
|
-
const decrypted = Secretbox_1.methods.open(buffer.slice(12, end), nonce, secretKey);
|
|
119
|
-
if (!decrypted)
|
|
120
|
-
return;
|
|
121
|
-
return Buffer.from(decrypted);
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Parses an audio packet, decrypting it to yield an Opus packet.
|
|
125
|
-
*
|
|
126
|
-
* @param buffer The buffer to parse
|
|
127
|
-
* @param mode The encryption mode
|
|
128
|
-
* @param nonce The nonce buffer used by the connection for encryption
|
|
129
|
-
* @param secretKey The secret key used by the connection for encryption
|
|
130
|
-
* @returns The parsed Opus packet
|
|
131
|
-
*/
|
|
132
|
-
parsePacket(buffer, mode, nonce, secretKey) {
|
|
133
|
-
let packet = this.decrypt(buffer, mode, nonce, secretKey);
|
|
134
|
-
if (!packet)
|
|
135
|
-
return;
|
|
136
|
-
// Strip RTP Header Extensions (one-byte only)
|
|
137
|
-
if (packet[0] === 0xbe && packet[1] === 0xde && packet.length > 4) {
|
|
138
|
-
const headerExtensionLength = packet.readUInt16BE(2);
|
|
139
|
-
let offset = 4;
|
|
140
|
-
for (let i = 0; i < headerExtensionLength; i++) {
|
|
141
|
-
const byte = packet[offset];
|
|
142
|
-
offset++;
|
|
143
|
-
if (byte === 0)
|
|
144
|
-
continue;
|
|
145
|
-
offset += 1 + (byte >> 4);
|
|
146
|
-
}
|
|
147
|
-
// Skip over undocumented Discord byte (if present)
|
|
148
|
-
const byte = packet.readUInt8(offset);
|
|
149
|
-
if (byte === 0x00 || byte === 0x02)
|
|
150
|
-
offset++;
|
|
151
|
-
packet = packet.slice(offset);
|
|
152
|
-
}
|
|
153
|
-
return packet;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Called when the UDP socket of the attached connection receives a message.
|
|
157
|
-
*
|
|
158
|
-
* @param msg The received message
|
|
159
|
-
*/
|
|
160
|
-
onUdpMessage(msg) {
|
|
161
|
-
if (msg.length <= 8)
|
|
162
|
-
return;
|
|
163
|
-
const ssrc = msg.readUInt32BE(8);
|
|
164
|
-
const stream = this.subscriptions.get(ssrc);
|
|
165
|
-
if (!stream)
|
|
166
|
-
return;
|
|
167
|
-
const userData = this.ssrcMap.get(ssrc);
|
|
168
|
-
if (!userData)
|
|
169
|
-
return;
|
|
170
|
-
if (this.connectionData.encryptionMode && this.connectionData.nonceBuffer && this.connectionData.secretKey) {
|
|
171
|
-
const packet = this.parsePacket(msg, this.connectionData.encryptionMode, this.connectionData.nonceBuffer, this.connectionData.secretKey);
|
|
172
|
-
if (packet) {
|
|
173
|
-
stream.push(packet);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
stream.destroy(new Error('Failed to parse packet'));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Creates a subscription for the given target, specified either by their SSRC or user ID.
|
|
182
|
-
*
|
|
183
|
-
* @param target The audio SSRC or user ID to subscribe to
|
|
184
|
-
* @returns A readable stream of Opus packets received from the target
|
|
185
|
-
*/
|
|
186
|
-
subscribe(target) {
|
|
187
|
-
var _a;
|
|
188
|
-
const ssrc = (_a = this.ssrcMap.get(target)) === null || _a === void 0 ? void 0 : _a.audioSSRC;
|
|
189
|
-
if (!ssrc) {
|
|
190
|
-
throw new Error(`No known SSRC for ${target}`);
|
|
191
|
-
}
|
|
192
|
-
const existing = this.subscriptions.get(ssrc);
|
|
193
|
-
if (existing)
|
|
194
|
-
return existing;
|
|
195
|
-
const stream = new AudioReceiveStream_1.AudioReceiveStream();
|
|
196
|
-
stream.once('close', () => this.subscriptions.delete(ssrc));
|
|
197
|
-
this.subscriptions.set(ssrc, stream);
|
|
198
|
-
return stream;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
exports.VoiceReceiver = VoiceReceiver;
|
|
202
|
-
/**
|
|
203
|
-
* Creates a new voice receiver for the given voice connection.
|
|
204
|
-
*
|
|
205
|
-
* @param voiceConnection The voice connection to attach to
|
|
206
|
-
* @beta
|
|
207
|
-
* @remarks
|
|
208
|
-
* Voice receive is an undocumented part of the Discord API - voice receive is not guaranteed
|
|
209
|
-
* to be stable and may break without notice.
|
|
210
|
-
*/
|
|
211
|
-
function createVoiceReceiver(voiceConnection) {
|
|
212
|
-
return new VoiceReceiver(voiceConnection);
|
|
213
|
-
}
|
|
214
|
-
exports.createVoiceReceiver = createVoiceReceiver;
|
|
215
|
-
//# sourceMappingURL=VoiceReceiver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceReceiver.js","sourceRoot":"","sources":["../../src/receive/VoiceReceiver.ts"],"names":[],"mappings":"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","sourcesContent":["import { VoiceOpcodes } from 'discord-api-types/voice/v4';\nimport { SILENCE_FRAME } from '../audio/AudioPlayer';\nimport { ConnectionData, Networking, NetworkingState } from '../networking/Networking';\nimport { VoiceUDPSocket } from '../networking/VoiceUDPSocket';\nimport { VoiceWebSocket } from '../networking/VoiceWebSocket';\nimport { methods } from '../util/Secretbox';\nimport type { VoiceConnection } from '../VoiceConnection';\nimport { AudioReceiveStream } from './AudioReceiveStream';\nimport { SSRCMap } from './SSRCMap';\n\n/**\n * Attaches to a VoiceConnection, allowing you to receive audio packets from other\n * users that are speaking.\n *\n * @beta\n */\nexport class VoiceReceiver {\n\t/**\n\t * The attached connection of this receiver.\n\t */\n\tpublic readonly voiceConnection;\n\n\t/**\n\t * Maps SSRCs to Discord user IDs.\n\t */\n\tpublic readonly ssrcMap: SSRCMap;\n\n\t/**\n\t * The current audio subscriptions of this receiver.\n\t */\n\tpublic readonly subscriptions: Map<number, AudioReceiveStream>;\n\n\t/**\n\t * The connection information for this receiver. Used to decrypt incoming packets.\n\t */\n\tprivate connectionData: Partial<ConnectionData>;\n\n\tpublic constructor(voiceConnection: VoiceConnection) {\n\t\tthis.voiceConnection = voiceConnection;\n\t\tthis.ssrcMap = new SSRCMap();\n\t\tthis.subscriptions = new Map();\n\t\tthis.connectionData = {};\n\n\t\tconst onWsPacket = (packet: any) => this.onWsPacket(packet);\n\t\tconst onUdpMessage = (msg: Buffer) => this.onUdpMessage(msg);\n\n\t\tconst applyConnectionData = (connectionData: Partial<ConnectionData>) => {\n\t\t\tthis.connectionData = {\n\t\t\t\t...this.connectionData,\n\t\t\t\t...connectionData,\n\t\t\t};\n\t\t\tif (connectionData.packetsPlayed === 0) {\n\t\t\t\tthis.voiceConnection.playOpusPacket(SILENCE_FRAME);\n\t\t\t}\n\t\t};\n\n\t\t// Bind listeners for updates\n\t\tconst onNetworkingChange = (oldState: NetworkingState, newState: NetworkingState) => {\n\t\t\tconst oldWs = Reflect.get(oldState, 'ws') as VoiceWebSocket | undefined;\n\t\t\tconst oldUdp = Reflect.get(oldState, 'udp') as VoiceUDPSocket | undefined;\n\t\t\tconst newWs = Reflect.get(newState, 'ws') as VoiceWebSocket | undefined;\n\t\t\tconst newUdp = Reflect.get(newState, 'udp') as VoiceUDPSocket | undefined;\n\n\t\t\tconst connectionData = Reflect.get(newState, 'connectionData') as Partial<ConnectionData> | undefined;\n\t\t\tif (connectionData) applyConnectionData(connectionData);\n\n\t\t\tif (newWs !== oldWs) {\n\t\t\t\toldWs?.off('packet', onWsPacket);\n\t\t\t\tnewWs?.on('packet', onWsPacket);\n\t\t\t}\n\n\t\t\tif (newUdp !== oldUdp) {\n\t\t\t\toldUdp?.off('message', onUdpMessage);\n\t\t\t\tnewUdp?.on('message', onUdpMessage);\n\t\t\t}\n\t\t};\n\n\t\tthis.voiceConnection.on('stateChange', (oldState, newState) => {\n\t\t\tconst oldNetworking: Networking | undefined = Reflect.get(oldState, 'networking');\n\t\t\tconst newNetworking: Networking | undefined = Reflect.get(newState, 'networking');\n\n\t\t\tif (newNetworking !== oldNetworking) {\n\t\t\t\toldNetworking?.off('stateChange', onNetworkingChange);\n\t\t\t\tnewNetworking?.on('stateChange', onNetworkingChange);\n\t\t\t\tif (newNetworking) {\n\t\t\t\t\tconst ws = Reflect.get(newNetworking.state, 'ws') as VoiceWebSocket | undefined;\n\t\t\t\t\tconst udp = Reflect.get(newNetworking.state, 'udp') as VoiceUDPSocket | undefined;\n\t\t\t\t\tconst connectionData = Reflect.get(newNetworking.state, 'connectionData') as\n\t\t\t\t\t\t| Partial<ConnectionData>\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tws?.on('packet', onWsPacket);\n\t\t\t\t\tudp?.on('message', onUdpMessage);\n\t\t\t\t\tif (connectionData) applyConnectionData(connectionData);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// Bind listeners for the existing state\n\t\tconst networking: Networking | undefined = Reflect.get(voiceConnection.state, 'networking');\n\t\tif (networking) {\n\t\t\tconst ws = Reflect.get(networking.state, 'ws') as VoiceWebSocket | undefined;\n\t\t\tconst udp = Reflect.get(networking.state, 'udp') as VoiceUDPSocket | undefined;\n\t\t\tconst connectionData = Reflect.get(networking.state, 'connectionData') as Partial<ConnectionData> | undefined;\n\t\t\tws?.on('packet', onWsPacket);\n\t\t\tudp?.on('message', onUdpMessage);\n\t\t\tif (connectionData) applyConnectionData(connectionData);\n\t\t}\n\t}\n\n\t/**\n\t * Called when a packet is received on the attached connection's WebSocket.\n\t *\n\t * @param packet The received packet\n\t */\n\tprivate onWsPacket(packet: any) {\n\t\tif (packet.op === VoiceOpcodes.ClientDisconnect && typeof packet.d?.user_id === 'string') {\n\t\t\tthis.ssrcMap.delete(packet.d.user_id);\n\t\t} else if (\n\t\t\tpacket.op === VoiceOpcodes.Speaking &&\n\t\t\ttypeof packet.d?.user_id === 'string' &&\n\t\t\ttypeof packet.d?.ssrc === 'number'\n\t\t) {\n\t\t\tthis.ssrcMap.update({ userId: packet.d.user_id, audioSSRC: packet.d.ssrc });\n\t\t} else if (\n\t\t\tpacket.op === VoiceOpcodes.ClientConnect &&\n\t\t\ttypeof packet.d?.user_id === 'string' &&\n\t\t\ttypeof packet.d?.audio_ssrc === 'number'\n\t\t) {\n\t\t\tthis.ssrcMap.update({\n\t\t\t\tuserId: packet.d.user_id,\n\t\t\t\taudioSSRC: packet.d.audio_ssrc,\n\t\t\t\tvideoSSRC: packet.d.video_ssrc === 0 ? undefined : packet.d.video_ssrc,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate decrypt(buffer: Buffer, mode: string, nonce: Buffer, secretKey: Uint8Array) {\n\t\t// Choose correct nonce depending on encryption\n\t\tlet end;\n\t\tif (mode === 'xsalsa20_poly1305_lite') {\n\t\t\tbuffer.copy(nonce, 0, buffer.length - 4);\n\t\t\tend = buffer.length - 4;\n\t\t} else if (mode === 'xsalsa20_poly1305_suffix') {\n\t\t\tbuffer.copy(nonce, 0, buffer.length - 24);\n\t\t\tend = buffer.length - 24;\n\t\t} else {\n\t\t\tbuffer.copy(nonce, 0, 0, 12);\n\t\t}\n\n\t\t// Open packet\n\t\tconst decrypted = methods.open(buffer.slice(12, end), nonce, secretKey);\n\t\tif (!decrypted) return;\n\t\treturn Buffer.from(decrypted);\n\t}\n\n\t/**\n\t * Parses an audio packet, decrypting it to yield an Opus packet.\n\t *\n\t * @param buffer The buffer to parse\n\t * @param mode The encryption mode\n\t * @param nonce The nonce buffer used by the connection for encryption\n\t * @param secretKey The secret key used by the connection for encryption\n\t * @returns The parsed Opus packet\n\t */\n\tprivate parsePacket(buffer: Buffer, mode: string, nonce: Buffer, secretKey: Uint8Array) {\n\t\tlet packet = this.decrypt(buffer, mode, nonce, secretKey);\n\t\tif (!packet) return;\n\n\t\t// Strip RTP Header Extensions (one-byte only)\n\t\tif (packet[0] === 0xbe && packet[1] === 0xde && packet.length > 4) {\n\t\t\tconst headerExtensionLength = packet.readUInt16BE(2);\n\t\t\tlet offset = 4;\n\t\t\tfor (let i = 0; i < headerExtensionLength; i++) {\n\t\t\t\tconst byte = packet[offset];\n\t\t\t\toffset++;\n\t\t\t\tif (byte === 0) continue;\n\t\t\t\toffset += 1 + (byte >> 4);\n\t\t\t}\n\t\t\t// Skip over undocumented Discord byte (if present)\n\t\t\tconst byte = packet.readUInt8(offset);\n\t\t\tif (byte === 0x00 || byte === 0x02) offset++;\n\n\t\t\tpacket = packet.slice(offset);\n\t\t}\n\n\t\treturn packet;\n\t}\n\n\t/**\n\t * Called when the UDP socket of the attached connection receives a message.\n\t *\n\t * @param msg The received message\n\t */\n\tprivate onUdpMessage(msg: Buffer) {\n\t\tif (msg.length <= 8) return;\n\t\tconst ssrc = msg.readUInt32BE(8);\n\t\tconst stream = this.subscriptions.get(ssrc);\n\t\tif (!stream) return;\n\n\t\tconst userData = this.ssrcMap.get(ssrc);\n\t\tif (!userData) return;\n\n\t\tif (this.connectionData.encryptionMode && this.connectionData.nonceBuffer && this.connectionData.secretKey) {\n\t\t\tconst packet = this.parsePacket(\n\t\t\t\tmsg,\n\t\t\t\tthis.connectionData.encryptionMode,\n\t\t\t\tthis.connectionData.nonceBuffer,\n\t\t\t\tthis.connectionData.secretKey,\n\t\t\t);\n\t\t\tif (packet) {\n\t\t\t\tstream.push(packet);\n\t\t\t} else {\n\t\t\t\tstream.destroy(new Error('Failed to parse packet'));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates a subscription for the given target, specified either by their SSRC or user ID.\n\t *\n\t * @param target The audio SSRC or user ID to subscribe to\n\t * @returns A readable stream of Opus packets received from the target\n\t */\n\tpublic subscribe(target: string | number) {\n\t\tconst ssrc = this.ssrcMap.get(target)?.audioSSRC;\n\t\tif (!ssrc) {\n\t\t\tthrow new Error(`No known SSRC for ${target}`);\n\t\t}\n\n\t\tconst existing = this.subscriptions.get(ssrc);\n\t\tif (existing) return existing;\n\n\t\tconst stream = new AudioReceiveStream();\n\t\tstream.once('close', () => this.subscriptions.delete(ssrc));\n\t\tthis.subscriptions.set(ssrc, stream);\n\t\treturn stream;\n\t}\n}\n\n/**\n * Creates a new voice receiver for the given voice connection.\n *\n * @param voiceConnection The voice connection to attach to\n * @beta\n * @remarks\n * Voice receive is an undocumented part of the Discord API - voice receive is not guaranteed\n * to be stable and may break without notice.\n */\nexport function createVoiceReceiver(voiceConnection: VoiceConnection) {\n\treturn new VoiceReceiver(voiceConnection);\n}\n"]}
|
package/dist/receive/index.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
-
};
|
|
12
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
__exportStar(require("./VoiceReceiver"), exports);
|
|
14
|
-
__exportStar(require("./SSRCMap"), exports);
|
|
15
|
-
__exportStar(require("./AudioReceiveStream"), exports);
|
|
16
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/receive/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,kDAAgC;AAChC,4CAA0B;AAC1B,uDAAqC","sourcesContent":["export * from './VoiceReceiver';\nexport * from './SSRCMap';\nexport * from './AudioReceiveStream';\n"]}
|
package/dist/util/Secretbox.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.methods = void 0;
|
|
4
|
-
const libs = {
|
|
5
|
-
sodium: (sodium) => ({
|
|
6
|
-
open: sodium.api.crypto_secretbox_open_easy,
|
|
7
|
-
close: sodium.api.crypto_secretbox_easy,
|
|
8
|
-
random: (n, buffer) => {
|
|
9
|
-
if (!buffer)
|
|
10
|
-
buffer = Buffer.allocUnsafe(n);
|
|
11
|
-
sodium.api.randombytes_buf(buffer);
|
|
12
|
-
return buffer;
|
|
13
|
-
},
|
|
14
|
-
}),
|
|
15
|
-
'libsodium-wrappers': (sodium) => ({
|
|
16
|
-
open: sodium.crypto_secretbox_open_easy,
|
|
17
|
-
close: sodium.crypto_secretbox_easy,
|
|
18
|
-
random: (n) => sodium.randombytes_buf(n),
|
|
19
|
-
}),
|
|
20
|
-
tweetnacl: (tweetnacl) => ({
|
|
21
|
-
open: tweetnacl.secretbox.open,
|
|
22
|
-
close: tweetnacl.secretbox,
|
|
23
|
-
random: (n) => tweetnacl.randomBytes(n),
|
|
24
|
-
}),
|
|
25
|
-
};
|
|
26
|
-
const fallbackError = () => {
|
|
27
|
-
throw new Error(`Cannot play audio as no valid encryption package is installed.
|
|
28
|
-
- Install sodium, libsodium-wrappers, or tweetnacl.
|
|
29
|
-
- Use the generateDependencyReport() function for more information.\n`);
|
|
30
|
-
};
|
|
31
|
-
const methods = {
|
|
32
|
-
open: fallbackError,
|
|
33
|
-
close: fallbackError,
|
|
34
|
-
random: fallbackError,
|
|
35
|
-
};
|
|
36
|
-
exports.methods = methods;
|
|
37
|
-
void (async () => {
|
|
38
|
-
for (const libName of Object.keys(libs)) {
|
|
39
|
-
try {
|
|
40
|
-
// eslint-disable-next-line
|
|
41
|
-
const lib = require(libName);
|
|
42
|
-
if (libName === 'libsodium-wrappers' && lib.ready)
|
|
43
|
-
await lib.ready; // eslint-disable-line no-await-in-loop
|
|
44
|
-
Object.assign(methods, libs[libName](lib));
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
catch { } // eslint-disable-line no-empty
|
|
48
|
-
}
|
|
49
|
-
})();
|
|
50
|
-
//# sourceMappingURL=Secretbox.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Secretbox.js","sourceRoot":"","sources":["../../src/util/Secretbox.ts"],"names":[],"mappings":";;;AAMA,MAAM,IAAI,GAAG;IACZ,MAAM,EAAE,CAAC,MAAW,EAAW,EAAE,CAAC,CAAC;QAClC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,0BAA0B;QAC3C,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,qBAAqB;QACvC,MAAM,EAAE,CAAC,CAAM,EAAE,MAAe,EAAE,EAAE;YACnC,IAAI,CAAC,MAAM;gBAAE,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YACnC,OAAO,MAAM,CAAC;QACf,CAAC;KACD,CAAC;IACF,oBAAoB,EAAE,CAAC,MAAW,EAAW,EAAE,CAAC,CAAC;QAChD,IAAI,EAAE,MAAM,CAAC,0BAA0B;QACvC,KAAK,EAAE,MAAM,CAAC,qBAAqB;QACnC,MAAM,EAAE,CAAC,CAAM,EAAE,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;KAC7C,CAAC;IACF,SAAS,EAAE,CAAC,SAAc,EAAW,EAAE,CAAC,CAAC;QACxC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,IAAI;QAC9B,KAAK,EAAE,SAAS,CAAC,SAAS;QAC1B,MAAM,EAAE,CAAC,CAAM,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;KAC5C,CAAC;CACO,CAAC;AAEX,MAAM,aAAa,GAAG,GAAG,EAAE;IAC1B,MAAM,IAAI,KAAK,CACd;;sEAEoE,CACpE,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,OAAO,GAAY;IACxB,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,aAAa;IACpB,MAAM,EAAE,aAAa;CACrB,CAAC;AAcO,0BAAO;AAZhB,KAAK,CAAC,KAAK,IAAI,EAAE;IAChB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAA0B,EAAE;QACjE,IAAI;YACH,2BAA2B;YAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YAC7B,IAAI,OAAO,KAAK,oBAAoB,IAAI,GAAG,CAAC,KAAK;gBAAE,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,uCAAuC;YAC3G,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,MAAM;SACN;QAAC,MAAM,GAAE,CAAC,+BAA+B;KAC1C;AACF,CAAC,CAAC,EAAE,CAAC","sourcesContent":["interface Methods {\n\topen(buffer: Buffer, nonce: Buffer, secretKey: Uint8Array): Buffer | null;\n\tclose(opusPacket: Buffer, nonce: Buffer, secretKey: Uint8Array): Buffer;\n\trandom(bytes: number, nonce: Buffer): Buffer;\n}\n\nconst libs = {\n\tsodium: (sodium: any): Methods => ({\n\t\topen: sodium.api.crypto_secretbox_open_easy,\n\t\tclose: sodium.api.crypto_secretbox_easy,\n\t\trandom: (n: any, buffer?: Buffer) => {\n\t\t\tif (!buffer) buffer = Buffer.allocUnsafe(n);\n\t\t\tsodium.api.randombytes_buf(buffer);\n\t\t\treturn buffer;\n\t\t},\n\t}),\n\t'libsodium-wrappers': (sodium: any): Methods => ({\n\t\topen: sodium.crypto_secretbox_open_easy,\n\t\tclose: sodium.crypto_secretbox_easy,\n\t\trandom: (n: any) => sodium.randombytes_buf(n),\n\t}),\n\ttweetnacl: (tweetnacl: any): Methods => ({\n\t\topen: tweetnacl.secretbox.open,\n\t\tclose: tweetnacl.secretbox,\n\t\trandom: (n: any) => tweetnacl.randomBytes(n),\n\t}),\n} as const;\n\nconst fallbackError = () => {\n\tthrow new Error(\n\t\t`Cannot play audio as no valid encryption package is installed.\n- Install sodium, libsodium-wrappers, or tweetnacl.\n- Use the generateDependencyReport() function for more information.\\n`,\n\t);\n};\n\nconst methods: Methods = {\n\topen: fallbackError,\n\tclose: fallbackError,\n\trandom: fallbackError,\n};\n\nvoid (async () => {\n\tfor (const libName of Object.keys(libs) as (keyof typeof libs)[]) {\n\t\ttry {\n\t\t\t// eslint-disable-next-line\n\t\t\tconst lib = require(libName);\n\t\t\tif (libName === 'libsodium-wrappers' && lib.ready) await lib.ready; // eslint-disable-line no-await-in-loop\n\t\t\tObject.assign(methods, libs[libName](lib));\n\t\t\tbreak;\n\t\t} catch {} // eslint-disable-line no-empty\n\t}\n})();\n\nexport { methods };\n"]}
|
package/dist/util/adapter.js
DELETED
package/dist/util/adapter.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/util/adapter.ts"],"names":[],"mappings":"","sourcesContent":["import { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData } from 'discord-api-types/v9';\n\n/**\n * Methods that are provided by the @discordjs/voice library to implementations of\n * Discord gateway DiscordGatewayAdapters.\n */\nexport interface DiscordGatewayAdapterLibraryMethods {\n\t/**\n\t * Call this when you receive a VOICE_SERVER_UPDATE payload that is relevant to the adapter.\n\t *\n\t * @param data - The inner data of the VOICE_SERVER_UPDATE payload\n\t */\n\tonVoiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): void;\n\t/**\n\t * Call this when you receive a VOICE_STATE_UPDATE payload that is relevant to the adapter.\n\t *\n\t * @param data - The inner data of the VOICE_STATE_UPDATE payload\n\t */\n\tonVoiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): void;\n\t/**\n\t * Call this when the adapter can no longer be used (e.g. due to a disconnect from the main gateway)\n\t */\n\tdestroy(): void;\n}\n\n/**\n * Methods that are provided by the implementer of a Discord gateway DiscordGatewayAdapter.\n */\nexport interface DiscordGatewayAdapterImplementerMethods {\n\t/**\n\t * Implement this method such that the given payload is sent to the main Discord gateway connection.\n\t *\n\t * @param payload - The payload to send to the main Discord gateway connection\n\t * @returns false if the payload definitely failed to send - in this case, the voice connection disconnects.\n\t */\n\tsendPayload(payload: any): boolean;\n\t/**\n\t * This will be called by @discordjs/voice when the adapter can safely be destroyed as it will no\n\t * longer be used.\n\t */\n\tdestroy(): void;\n}\n\n/**\n * A function used to build adapters. It accepts a methods parameter that contains functions that\n * can be called by the implementer when new data is received on its gateway connection. In return,\n * the implementer will return some methods that the library can call - e.g. to send messages on\n * the gateway, or to signal that the adapter can be removed.\n */\nexport type DiscordGatewayAdapterCreator = (\n\tmethods: DiscordGatewayAdapterLibraryMethods,\n) => DiscordGatewayAdapterImplementerMethods;\n"]}
|