@fluxerjs/voice 1.0.3
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/README.md +24 -0
- package/dist/index.d.mts +140 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.js +925 -0
- package/dist/index.mjs +892 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @fluxerjs/voice
|
|
2
|
+
|
|
3
|
+
Voice for Fluxer bots. Join channels and play WebM/Opus audio.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @fluxerjs/voice @fluxerjs/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { getVoiceManager } from '@fluxerjs/voice';
|
|
15
|
+
|
|
16
|
+
const voiceManager = getVoiceManager(client);
|
|
17
|
+
const connection = await voiceManager.join(channel);
|
|
18
|
+
await connection.play(streamUrl);
|
|
19
|
+
|
|
20
|
+
connection.stop();
|
|
21
|
+
voiceManager.leave(guildId);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Use yt-dlp to get stream URLs from YouTube. For LiveKit, listen for `serverLeave` to reconnect.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Client, VoiceChannel } from '@fluxerjs/core';
|
|
3
|
+
import { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData } from '@fluxerjs/types';
|
|
4
|
+
|
|
5
|
+
interface VoiceConnectionEvents {
|
|
6
|
+
ready: [];
|
|
7
|
+
error: [err: Error];
|
|
8
|
+
disconnect: [];
|
|
9
|
+
}
|
|
10
|
+
declare class VoiceConnection extends EventEmitter {
|
|
11
|
+
readonly client: Client;
|
|
12
|
+
readonly channel: VoiceChannel;
|
|
13
|
+
readonly guildId: string;
|
|
14
|
+
private _sessionId;
|
|
15
|
+
private _token;
|
|
16
|
+
private _endpoint;
|
|
17
|
+
private _userId;
|
|
18
|
+
private voiceWs;
|
|
19
|
+
private udpSocket;
|
|
20
|
+
private ssrc;
|
|
21
|
+
private secretKey;
|
|
22
|
+
private heartbeatInterval;
|
|
23
|
+
private sequence;
|
|
24
|
+
private timestamp;
|
|
25
|
+
private _playing;
|
|
26
|
+
private _destroyed;
|
|
27
|
+
private currentStream;
|
|
28
|
+
private remoteUdpAddress;
|
|
29
|
+
private remoteUdpPort;
|
|
30
|
+
private audioPacketQueue;
|
|
31
|
+
private pacingInterval;
|
|
32
|
+
constructor(client: Client, channel: VoiceChannel, userId: string);
|
|
33
|
+
get sessionId(): string | null;
|
|
34
|
+
get playing(): boolean;
|
|
35
|
+
/** Called when we have both server update and state update. */
|
|
36
|
+
connect(server: GatewayVoiceServerUpdateDispatchData, state: GatewayVoiceStateUpdateDispatchData): Promise<void>;
|
|
37
|
+
private getWebSocketConstructor;
|
|
38
|
+
private sendVoiceOp;
|
|
39
|
+
private setupUDP;
|
|
40
|
+
/**
|
|
41
|
+
* Play a stream of raw Opus packets
|
|
42
|
+
* Uses the same queue and 20ms pacing as play(). Use this for local files (MP3 → PCM → Opus) or other Opus sources.
|
|
43
|
+
*/
|
|
44
|
+
playOpus(stream: NodeJS.ReadableStream): void;
|
|
45
|
+
/**
|
|
46
|
+
* Play a direct WebM/Opus URL or stream. Fetches the URL (if string), demuxes with prism-media WebmDemuxer,
|
|
47
|
+
* and sends Opus packets to the voice connection. No FFmpeg or encoding; input must be WebM with Opus.
|
|
48
|
+
*/
|
|
49
|
+
play(urlOrStream: string | NodeJS.ReadableStream): Promise<void>;
|
|
50
|
+
private sendAudioFrame;
|
|
51
|
+
stop(): void;
|
|
52
|
+
disconnect(): void;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** LiveKit-specific: emitted when server sends leave (token expiry, server policy, etc.). Emitted before disconnect. */
|
|
57
|
+
type LiveKitRtcConnectionEvents = VoiceConnectionEvents & {
|
|
58
|
+
serverLeave: [];
|
|
59
|
+
};
|
|
60
|
+
declare class LiveKitRtcConnection extends EventEmitter {
|
|
61
|
+
readonly client: Client;
|
|
62
|
+
readonly channel: VoiceChannel;
|
|
63
|
+
readonly guildId: string;
|
|
64
|
+
private _playing;
|
|
65
|
+
private _destroyed;
|
|
66
|
+
private room;
|
|
67
|
+
private audioSource;
|
|
68
|
+
private audioTrack;
|
|
69
|
+
private currentStream;
|
|
70
|
+
private lastServerEndpoint;
|
|
71
|
+
private lastServerToken;
|
|
72
|
+
private _disconnectEmitted;
|
|
73
|
+
constructor(client: Client, channel: VoiceChannel, _userId: string);
|
|
74
|
+
get playing(): boolean;
|
|
75
|
+
private debug;
|
|
76
|
+
private audioDebug;
|
|
77
|
+
private emitDisconnect;
|
|
78
|
+
/** Returns true if the LiveKit room is connected and not destroyed. */
|
|
79
|
+
isConnected(): boolean;
|
|
80
|
+
/** Returns true if we're already connected to the given server (skip migration). */
|
|
81
|
+
isSameServer(endpoint: string | null, token: string): boolean;
|
|
82
|
+
playOpus(_stream: NodeJS.ReadableStream): void;
|
|
83
|
+
connect(server: GatewayVoiceServerUpdateDispatchData, _state: GatewayVoiceStateUpdateDispatchData): Promise<void>;
|
|
84
|
+
play(urlOrStream: string | NodeJS.ReadableStream): Promise<void>;
|
|
85
|
+
stop(): void;
|
|
86
|
+
disconnect(): void;
|
|
87
|
+
destroy(): void;
|
|
88
|
+
}
|
|
89
|
+
declare module 'events' {
|
|
90
|
+
interface LiveKitRtcConnection {
|
|
91
|
+
on<E extends keyof LiveKitRtcConnectionEvents>(event: E, listener: (...args: LiveKitRtcConnectionEvents[E]) => void): this;
|
|
92
|
+
emit<E extends keyof LiveKitRtcConnectionEvents>(event: E, ...args: LiveKitRtcConnectionEvents[E]): boolean;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Maps guild_id -> user_id -> channel_id (null if not in voice). */
|
|
97
|
+
type VoiceStateMap = Map<string, Map<string, string | null>>;
|
|
98
|
+
interface VoiceManagerOptions {
|
|
99
|
+
/** Gateway shard ID to use for voice (default 0). */
|
|
100
|
+
shardId?: number;
|
|
101
|
+
}
|
|
102
|
+
declare class VoiceManager extends EventEmitter {
|
|
103
|
+
readonly client: Client;
|
|
104
|
+
private readonly connections;
|
|
105
|
+
/** guild_id -> user_id -> channel_id */
|
|
106
|
+
readonly voiceStates: VoiceStateMap;
|
|
107
|
+
private readonly pending;
|
|
108
|
+
private readonly shardId;
|
|
109
|
+
constructor(client: Client, options?: VoiceManagerOptions);
|
|
110
|
+
private handleVoiceStatesSync;
|
|
111
|
+
/** Get the voice channel ID the user is in, or null. */
|
|
112
|
+
getVoiceChannelId(guildId: string, userId: string): string | null;
|
|
113
|
+
private handleVoiceStateUpdate;
|
|
114
|
+
private handleVoiceServerUpdate;
|
|
115
|
+
private registerConnection;
|
|
116
|
+
private tryCompletePending;
|
|
117
|
+
/** Join a voice channel. Resolves when the connection is ready. */
|
|
118
|
+
join(channel: VoiceChannel): Promise<VoiceConnection | LiveKitRtcConnection>;
|
|
119
|
+
/** Leave a guild's voice channel. */
|
|
120
|
+
leave(guildId: string): void;
|
|
121
|
+
getConnection(guildId: string): VoiceConnection | LiveKitRtcConnection | undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Union of connection types (Discord-style or LiveKit). */
|
|
125
|
+
type VoiceConnectionLike = VoiceConnection | LiveKitRtcConnection;
|
|
126
|
+
/**
|
|
127
|
+
* Create a voice manager and join a channel in one call.
|
|
128
|
+
* Uses the default shard (0).
|
|
129
|
+
*/
|
|
130
|
+
declare function joinVoiceChannel(client: Client, channel: VoiceChannel, options?: {
|
|
131
|
+
shardId?: number;
|
|
132
|
+
}): Promise<VoiceConnectionLike>;
|
|
133
|
+
/**
|
|
134
|
+
* Get or create the VoiceManager for this client.
|
|
135
|
+
*/
|
|
136
|
+
declare function getVoiceManager(client: Client, options?: {
|
|
137
|
+
shardId?: number;
|
|
138
|
+
}): VoiceManager;
|
|
139
|
+
|
|
140
|
+
export { LiveKitRtcConnection, type LiveKitRtcConnectionEvents, VoiceConnection, type VoiceConnectionEvents, type VoiceConnectionLike, VoiceManager, type VoiceManagerOptions, type VoiceStateMap, getVoiceManager, joinVoiceChannel };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Client, VoiceChannel } from '@fluxerjs/core';
|
|
3
|
+
import { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData } from '@fluxerjs/types';
|
|
4
|
+
|
|
5
|
+
interface VoiceConnectionEvents {
|
|
6
|
+
ready: [];
|
|
7
|
+
error: [err: Error];
|
|
8
|
+
disconnect: [];
|
|
9
|
+
}
|
|
10
|
+
declare class VoiceConnection extends EventEmitter {
|
|
11
|
+
readonly client: Client;
|
|
12
|
+
readonly channel: VoiceChannel;
|
|
13
|
+
readonly guildId: string;
|
|
14
|
+
private _sessionId;
|
|
15
|
+
private _token;
|
|
16
|
+
private _endpoint;
|
|
17
|
+
private _userId;
|
|
18
|
+
private voiceWs;
|
|
19
|
+
private udpSocket;
|
|
20
|
+
private ssrc;
|
|
21
|
+
private secretKey;
|
|
22
|
+
private heartbeatInterval;
|
|
23
|
+
private sequence;
|
|
24
|
+
private timestamp;
|
|
25
|
+
private _playing;
|
|
26
|
+
private _destroyed;
|
|
27
|
+
private currentStream;
|
|
28
|
+
private remoteUdpAddress;
|
|
29
|
+
private remoteUdpPort;
|
|
30
|
+
private audioPacketQueue;
|
|
31
|
+
private pacingInterval;
|
|
32
|
+
constructor(client: Client, channel: VoiceChannel, userId: string);
|
|
33
|
+
get sessionId(): string | null;
|
|
34
|
+
get playing(): boolean;
|
|
35
|
+
/** Called when we have both server update and state update. */
|
|
36
|
+
connect(server: GatewayVoiceServerUpdateDispatchData, state: GatewayVoiceStateUpdateDispatchData): Promise<void>;
|
|
37
|
+
private getWebSocketConstructor;
|
|
38
|
+
private sendVoiceOp;
|
|
39
|
+
private setupUDP;
|
|
40
|
+
/**
|
|
41
|
+
* Play a stream of raw Opus packets
|
|
42
|
+
* Uses the same queue and 20ms pacing as play(). Use this for local files (MP3 → PCM → Opus) or other Opus sources.
|
|
43
|
+
*/
|
|
44
|
+
playOpus(stream: NodeJS.ReadableStream): void;
|
|
45
|
+
/**
|
|
46
|
+
* Play a direct WebM/Opus URL or stream. Fetches the URL (if string), demuxes with prism-media WebmDemuxer,
|
|
47
|
+
* and sends Opus packets to the voice connection. No FFmpeg or encoding; input must be WebM with Opus.
|
|
48
|
+
*/
|
|
49
|
+
play(urlOrStream: string | NodeJS.ReadableStream): Promise<void>;
|
|
50
|
+
private sendAudioFrame;
|
|
51
|
+
stop(): void;
|
|
52
|
+
disconnect(): void;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** LiveKit-specific: emitted when server sends leave (token expiry, server policy, etc.). Emitted before disconnect. */
|
|
57
|
+
type LiveKitRtcConnectionEvents = VoiceConnectionEvents & {
|
|
58
|
+
serverLeave: [];
|
|
59
|
+
};
|
|
60
|
+
declare class LiveKitRtcConnection extends EventEmitter {
|
|
61
|
+
readonly client: Client;
|
|
62
|
+
readonly channel: VoiceChannel;
|
|
63
|
+
readonly guildId: string;
|
|
64
|
+
private _playing;
|
|
65
|
+
private _destroyed;
|
|
66
|
+
private room;
|
|
67
|
+
private audioSource;
|
|
68
|
+
private audioTrack;
|
|
69
|
+
private currentStream;
|
|
70
|
+
private lastServerEndpoint;
|
|
71
|
+
private lastServerToken;
|
|
72
|
+
private _disconnectEmitted;
|
|
73
|
+
constructor(client: Client, channel: VoiceChannel, _userId: string);
|
|
74
|
+
get playing(): boolean;
|
|
75
|
+
private debug;
|
|
76
|
+
private audioDebug;
|
|
77
|
+
private emitDisconnect;
|
|
78
|
+
/** Returns true if the LiveKit room is connected and not destroyed. */
|
|
79
|
+
isConnected(): boolean;
|
|
80
|
+
/** Returns true if we're already connected to the given server (skip migration). */
|
|
81
|
+
isSameServer(endpoint: string | null, token: string): boolean;
|
|
82
|
+
playOpus(_stream: NodeJS.ReadableStream): void;
|
|
83
|
+
connect(server: GatewayVoiceServerUpdateDispatchData, _state: GatewayVoiceStateUpdateDispatchData): Promise<void>;
|
|
84
|
+
play(urlOrStream: string | NodeJS.ReadableStream): Promise<void>;
|
|
85
|
+
stop(): void;
|
|
86
|
+
disconnect(): void;
|
|
87
|
+
destroy(): void;
|
|
88
|
+
}
|
|
89
|
+
declare module 'events' {
|
|
90
|
+
interface LiveKitRtcConnection {
|
|
91
|
+
on<E extends keyof LiveKitRtcConnectionEvents>(event: E, listener: (...args: LiveKitRtcConnectionEvents[E]) => void): this;
|
|
92
|
+
emit<E extends keyof LiveKitRtcConnectionEvents>(event: E, ...args: LiveKitRtcConnectionEvents[E]): boolean;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Maps guild_id -> user_id -> channel_id (null if not in voice). */
|
|
97
|
+
type VoiceStateMap = Map<string, Map<string, string | null>>;
|
|
98
|
+
interface VoiceManagerOptions {
|
|
99
|
+
/** Gateway shard ID to use for voice (default 0). */
|
|
100
|
+
shardId?: number;
|
|
101
|
+
}
|
|
102
|
+
declare class VoiceManager extends EventEmitter {
|
|
103
|
+
readonly client: Client;
|
|
104
|
+
private readonly connections;
|
|
105
|
+
/** guild_id -> user_id -> channel_id */
|
|
106
|
+
readonly voiceStates: VoiceStateMap;
|
|
107
|
+
private readonly pending;
|
|
108
|
+
private readonly shardId;
|
|
109
|
+
constructor(client: Client, options?: VoiceManagerOptions);
|
|
110
|
+
private handleVoiceStatesSync;
|
|
111
|
+
/** Get the voice channel ID the user is in, or null. */
|
|
112
|
+
getVoiceChannelId(guildId: string, userId: string): string | null;
|
|
113
|
+
private handleVoiceStateUpdate;
|
|
114
|
+
private handleVoiceServerUpdate;
|
|
115
|
+
private registerConnection;
|
|
116
|
+
private tryCompletePending;
|
|
117
|
+
/** Join a voice channel. Resolves when the connection is ready. */
|
|
118
|
+
join(channel: VoiceChannel): Promise<VoiceConnection | LiveKitRtcConnection>;
|
|
119
|
+
/** Leave a guild's voice channel. */
|
|
120
|
+
leave(guildId: string): void;
|
|
121
|
+
getConnection(guildId: string): VoiceConnection | LiveKitRtcConnection | undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Union of connection types (Discord-style or LiveKit). */
|
|
125
|
+
type VoiceConnectionLike = VoiceConnection | LiveKitRtcConnection;
|
|
126
|
+
/**
|
|
127
|
+
* Create a voice manager and join a channel in one call.
|
|
128
|
+
* Uses the default shard (0).
|
|
129
|
+
*/
|
|
130
|
+
declare function joinVoiceChannel(client: Client, channel: VoiceChannel, options?: {
|
|
131
|
+
shardId?: number;
|
|
132
|
+
}): Promise<VoiceConnectionLike>;
|
|
133
|
+
/**
|
|
134
|
+
* Get or create the VoiceManager for this client.
|
|
135
|
+
*/
|
|
136
|
+
declare function getVoiceManager(client: Client, options?: {
|
|
137
|
+
shardId?: number;
|
|
138
|
+
}): VoiceManager;
|
|
139
|
+
|
|
140
|
+
export { LiveKitRtcConnection, type LiveKitRtcConnectionEvents, VoiceConnection, type VoiceConnectionEvents, type VoiceConnectionLike, VoiceManager, type VoiceManagerOptions, type VoiceStateMap, getVoiceManager, joinVoiceChannel };
|