@remedia/node 0.0.0-stage → 0.1.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +144 -2
- package/THIRD_PARTY_LICENSES.txt +15655 -0
- package/THIRD_PARTY_NOTICES.md +126 -0
- package/dist/discord.d.ts +149 -0
- package/dist/discord.js +1168 -0
- package/dist/events.d.ts +21 -0
- package/dist/events.js +28 -0
- package/dist/filters.d.ts +22 -0
- package/dist/filters.js +52 -0
- package/dist/gateway.d.ts +88 -0
- package/dist/gateway.js +100 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +4 -0
- package/dist/input.d.ts +46 -0
- package/dist/input.js +135 -0
- package/dist/lifecycle.d.ts +315 -0
- package/dist/lifecycle.js +109 -0
- package/dist/playback.d.ts +73 -0
- package/dist/playback.js +445 -0
- package/dist/remedia.d.ts +51 -0
- package/dist/remedia.js +150 -0
- package/dist/types.d.ts +97 -0
- package/dist/types.js +75 -0
- package/native.d.ts +162 -0
- package/native.js +778 -0
- package/package.json +86 -3
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import type { MediaSource } from './input.js';
|
|
2
|
+
import type { AudioStreamInfo, PlaybackPosition, PlaybackState } from './types.js';
|
|
3
|
+
/** Stable names for playback/session event subscriptions and emission. */
|
|
4
|
+
export declare const PlaybackSessionEvents: {
|
|
5
|
+
/** Emitted after a source starts and its stream information is available. */
|
|
6
|
+
readonly playbackStarted: "playbackStarted";
|
|
7
|
+
/** Emitted when a source generation reaches natural end-of-stream. */
|
|
8
|
+
readonly playbackCompleted: "playbackCompleted";
|
|
9
|
+
/** Emitted when a source generation is explicitly stopped or cancelled. */
|
|
10
|
+
readonly playbackStopped: "playbackStopped";
|
|
11
|
+
/** Emitted when a source generation fails to open, decode, process, or deliver output. */
|
|
12
|
+
readonly playbackFailed: "playbackFailed";
|
|
13
|
+
/** Emitted when playback is paused without replacing its source generation. */
|
|
14
|
+
readonly playbackPaused: "playbackPaused";
|
|
15
|
+
/** Emitted when paused playback resumes. */
|
|
16
|
+
readonly playbackResumed: "playbackResumed";
|
|
17
|
+
/** Emitted after seeking to a source timeline position. */
|
|
18
|
+
readonly playbackSeeked: "playbackSeeked";
|
|
19
|
+
/** Emitted when the configured session filtergraph changes. */
|
|
20
|
+
readonly filterChanged: "filterChanged";
|
|
21
|
+
/** Emitted when the configured session linear gain changes. */
|
|
22
|
+
readonly volumeChanged: "volumeChanged";
|
|
23
|
+
/** Emitted when a session is unregistered and its owned resources are released. */
|
|
24
|
+
readonly sessionDisposed: "sessionDisposed";
|
|
25
|
+
};
|
|
26
|
+
/** Union of the stable event names defined by PlaybackSessionEvents. */
|
|
27
|
+
export type PlaybackSessionEvents = (typeof PlaybackSessionEvents)[keyof typeof PlaybackSessionEvents];
|
|
28
|
+
/** Stable event names for typed VoiceSessionEvents subscriptions. */
|
|
29
|
+
export declare const VoiceSessionEvents: {
|
|
30
|
+
/** Emitted when the Discord transport lifecycle state changes. */
|
|
31
|
+
readonly voiceStateChanged: "voiceStateChanged";
|
|
32
|
+
/** Emitted when voice connection or recovery fails. */
|
|
33
|
+
readonly voiceFailed: "voiceFailed";
|
|
34
|
+
};
|
|
35
|
+
/** Union of the stable event names defined by VoiceSessionEvents. */
|
|
36
|
+
export type VoiceSessionEvents = (typeof VoiceSessionEvents)[keyof typeof VoiceSessionEvents];
|
|
37
|
+
/** Stable event names for typed RemediaEvents subscriptions. */
|
|
38
|
+
export declare const RemediaEvents: {
|
|
39
|
+
/** Emitted for a structured native diagnostic event. */
|
|
40
|
+
readonly debug: "debug";
|
|
41
|
+
/** Emitted when the Discord transport lifecycle state changes. */
|
|
42
|
+
readonly voiceStateChanged: "voiceStateChanged";
|
|
43
|
+
/** Emitted when voice connection or recovery fails. */
|
|
44
|
+
readonly voiceFailed: "voiceFailed";
|
|
45
|
+
/** Emitted after a source starts and its stream information is available. */
|
|
46
|
+
readonly playbackStarted: "playbackStarted";
|
|
47
|
+
/** Emitted when a source generation reaches natural end-of-stream. */
|
|
48
|
+
readonly playbackCompleted: "playbackCompleted";
|
|
49
|
+
/** Emitted when a source generation is explicitly stopped or cancelled. */
|
|
50
|
+
readonly playbackStopped: "playbackStopped";
|
|
51
|
+
/** Emitted when a source generation fails to open, decode, process, or deliver output. */
|
|
52
|
+
readonly playbackFailed: "playbackFailed";
|
|
53
|
+
/** Emitted when playback is paused without replacing its source generation. */
|
|
54
|
+
readonly playbackPaused: "playbackPaused";
|
|
55
|
+
/** Emitted when paused playback resumes. */
|
|
56
|
+
readonly playbackResumed: "playbackResumed";
|
|
57
|
+
/** Emitted after seeking to a source timeline position. */
|
|
58
|
+
readonly playbackSeeked: "playbackSeeked";
|
|
59
|
+
/** Emitted when the configured session filtergraph changes. */
|
|
60
|
+
readonly filterChanged: "filterChanged";
|
|
61
|
+
/** Emitted when the configured session linear gain changes. */
|
|
62
|
+
readonly volumeChanged: "volumeChanged";
|
|
63
|
+
/** Emitted when a session is unregistered and its owned resources are released. */
|
|
64
|
+
readonly sessionDisposed: "sessionDisposed";
|
|
65
|
+
};
|
|
66
|
+
/** Union of the stable event names defined by RemediaEvents. */
|
|
67
|
+
export type RemediaEvents = (typeof RemediaEvents)[keyof typeof RemediaEvents];
|
|
68
|
+
/**
|
|
69
|
+
* Correlation fields identifying the session and source generation that produced a playback event.
|
|
70
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
71
|
+
*/
|
|
72
|
+
export interface PlaybackEventIdentity<Metadata = unknown> {
|
|
73
|
+
/** Opaque Remedia session identity used to correlate events; distinct from the Discord bot user ID. */
|
|
74
|
+
sessionId: string;
|
|
75
|
+
/** Discord guild snowflake as a decimal string; unique within the owning client. */
|
|
76
|
+
guildId?: string;
|
|
77
|
+
/** Node identifier; embedded session events use null. */
|
|
78
|
+
nodeId: string | null;
|
|
79
|
+
/** Source generation used to correlate playback events; independent of transport replacement generations. */
|
|
80
|
+
generation: number;
|
|
81
|
+
/** Application-owned metadata retained locally for the source generation and attached to its events. */
|
|
82
|
+
customMetadata?: Metadata;
|
|
83
|
+
/** True only when a terminal event was reconstructed from an authoritative remote snapshot. */
|
|
84
|
+
reconstructed?: boolean;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Typed argument tuples for playback lifecycle notifications.
|
|
88
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
89
|
+
*/
|
|
90
|
+
export type PlaybackLifecycleEvents<Metadata = unknown> = {
|
|
91
|
+
/** Emitted after a source starts and its stream information is available. */
|
|
92
|
+
[PlaybackSessionEvents.playbackStarted]: [
|
|
93
|
+
PlaybackEventIdentity<Metadata> & {
|
|
94
|
+
/** Current playback lifecycle state. */
|
|
95
|
+
state: 'playing';
|
|
96
|
+
/** Metadata for the audio stream that started playback. */
|
|
97
|
+
info: AudioStreamInfo;
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
/** Emitted when a source generation reaches natural end-of-stream. */
|
|
101
|
+
[PlaybackSessionEvents.playbackCompleted]: [
|
|
102
|
+
PlaybackEventIdentity<Metadata> & {
|
|
103
|
+
/** Current playback lifecycle state. */
|
|
104
|
+
state: 'completed';
|
|
105
|
+
/** Latest source and output timeline measurements in milliseconds. */
|
|
106
|
+
position: PlaybackPosition;
|
|
107
|
+
}
|
|
108
|
+
];
|
|
109
|
+
/** Emitted when a source generation is explicitly stopped or cancelled. */
|
|
110
|
+
[PlaybackSessionEvents.playbackStopped]: [
|
|
111
|
+
PlaybackEventIdentity<Metadata> & {
|
|
112
|
+
/** Current playback lifecycle state. */
|
|
113
|
+
state: 'stopped';
|
|
114
|
+
/** Optional explanation for cancellation or a terminal playback event. */
|
|
115
|
+
reason?: string;
|
|
116
|
+
}
|
|
117
|
+
];
|
|
118
|
+
/** Emitted when a source generation fails to open, decode, process, or deliver output. */
|
|
119
|
+
[PlaybackSessionEvents.playbackFailed]: [
|
|
120
|
+
PlaybackEventIdentity<Metadata> & {
|
|
121
|
+
/** Current playback lifecycle state. */
|
|
122
|
+
state: 'failed';
|
|
123
|
+
/** Error object describing the operation or source failure. */
|
|
124
|
+
error: Error;
|
|
125
|
+
}
|
|
126
|
+
];
|
|
127
|
+
/** Emitted when playback is paused without replacing its source generation. */
|
|
128
|
+
[PlaybackSessionEvents.playbackPaused]: [
|
|
129
|
+
PlaybackEventIdentity<Metadata> & {
|
|
130
|
+
/** Playback or transport lifecycle state before this transition. */
|
|
131
|
+
previousState: PlaybackState;
|
|
132
|
+
/** Current playback lifecycle state. */
|
|
133
|
+
state: 'paused';
|
|
134
|
+
}
|
|
135
|
+
];
|
|
136
|
+
/** Emitted when paused playback resumes. */
|
|
137
|
+
[PlaybackSessionEvents.playbackResumed]: [
|
|
138
|
+
PlaybackEventIdentity<Metadata> & {
|
|
139
|
+
/** Playback or transport lifecycle state before this transition. */
|
|
140
|
+
previousState: PlaybackState;
|
|
141
|
+
/** Current playback lifecycle state. */
|
|
142
|
+
state: 'playing';
|
|
143
|
+
}
|
|
144
|
+
];
|
|
145
|
+
/** Emitted after seeking to a source timeline position. */
|
|
146
|
+
[PlaybackSessionEvents.playbackSeeked]: [
|
|
147
|
+
PlaybackEventIdentity<Metadata> & {
|
|
148
|
+
/** Requested source timeline position in milliseconds. */
|
|
149
|
+
positionMs: number;
|
|
150
|
+
/** Source timeline position before seeking, in milliseconds, or null when unknown. */
|
|
151
|
+
previousPositionMs: number | null;
|
|
152
|
+
}
|
|
153
|
+
];
|
|
154
|
+
/** Emitted when the configured session filtergraph changes. */
|
|
155
|
+
[PlaybackSessionEvents.filterChanged]: [
|
|
156
|
+
PlaybackEventIdentity<Metadata> & {
|
|
157
|
+
/** Filtergraph active before this change, or null when filtering was disabled. */
|
|
158
|
+
previousGraph: string | null;
|
|
159
|
+
/** Current raw FFmpeg audio filtergraph, or null when filtering is disabled. */
|
|
160
|
+
graph: string | null;
|
|
161
|
+
}
|
|
162
|
+
];
|
|
163
|
+
/** Emitted when the configured session linear gain changes. */
|
|
164
|
+
[PlaybackSessionEvents.volumeChanged]: [
|
|
165
|
+
PlaybackEventIdentity<Metadata> & {
|
|
166
|
+
/** Linear master gain before this change. */
|
|
167
|
+
previousVolume: number;
|
|
168
|
+
/** Session master linear gain from 0 through 2, independent of filtergraph processing; defaults to 1. */
|
|
169
|
+
volume: number;
|
|
170
|
+
}
|
|
171
|
+
];
|
|
172
|
+
};
|
|
173
|
+
/** Correlation fields identifying the session that produced a voice transport event. */
|
|
174
|
+
export interface VoiceEventIdentity {
|
|
175
|
+
/** Opaque Remedia session identity used to correlate events; distinct from the Discord bot user ID. */
|
|
176
|
+
sessionId: string;
|
|
177
|
+
/** Discord guild snowflake as a decimal string; unique within the owning client. */
|
|
178
|
+
guildId: string;
|
|
179
|
+
/** Node identifier; embedded session events use null. */
|
|
180
|
+
nodeId: string | null;
|
|
181
|
+
}
|
|
182
|
+
/** Normalized voice lifecycle state used in events; DAVE negotiation uses negotiating_dave. */
|
|
183
|
+
export type LifecycleVoiceState = 'connecting' | 'negotiating_dave' | 'connected' | 'reconnecting' | 'disconnecting' | 'disconnected' | 'failed';
|
|
184
|
+
/** Typed argument tuples for voice transport notifications, independent of playback generation. */
|
|
185
|
+
export type VoiceLifecycleEvents = {
|
|
186
|
+
/** Emitted when the Discord transport lifecycle state changes. */
|
|
187
|
+
[VoiceSessionEvents.voiceStateChanged]: [
|
|
188
|
+
VoiceEventIdentity & {
|
|
189
|
+
/** Playback or transport lifecycle state before this transition. */
|
|
190
|
+
previousState: LifecycleVoiceState;
|
|
191
|
+
/** Current playback lifecycle state. */
|
|
192
|
+
state: LifecycleVoiceState;
|
|
193
|
+
}
|
|
194
|
+
];
|
|
195
|
+
/** Emitted when voice connection or recovery fails. */
|
|
196
|
+
[VoiceSessionEvents.voiceFailed]: [
|
|
197
|
+
VoiceEventIdentity & {
|
|
198
|
+
/** Current playback lifecycle state. */
|
|
199
|
+
state: 'failed';
|
|
200
|
+
/** Error object describing the operation or source failure. */
|
|
201
|
+
error: Error;
|
|
202
|
+
}
|
|
203
|
+
];
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Combined playback, voice, and disposal event arguments for a session.
|
|
207
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
208
|
+
*/
|
|
209
|
+
export type SessionLifecycleEvents<Metadata = unknown> = PlaybackLifecycleEvents<Metadata> & VoiceLifecycleEvents & {
|
|
210
|
+
/** Emitted when a session is unregistered and its owned resources are released. */
|
|
211
|
+
[PlaybackSessionEvents.sessionDisposed]: [
|
|
212
|
+
{
|
|
213
|
+
/** Opaque Remedia session identity used to correlate events; distinct from the Discord bot user ID. */
|
|
214
|
+
sessionId: string;
|
|
215
|
+
/** Discord guild snowflake as a decimal string; unique within the owning client. */
|
|
216
|
+
guildId?: string;
|
|
217
|
+
/** Node identifier; embedded session events use null. */
|
|
218
|
+
nodeId: string | null;
|
|
219
|
+
/** Source generation used to correlate playback events; independent of transport replacement generations. */
|
|
220
|
+
generation: number;
|
|
221
|
+
}
|
|
222
|
+
];
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Playback and disposal event arguments emitted by an embedded playback wrapper.
|
|
226
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
227
|
+
*/
|
|
228
|
+
export type PlaybackSessionEventMap<Metadata = unknown> = PlaybackLifecycleEvents<Metadata> & {
|
|
229
|
+
/** Emitted when a session is unregistered and its owned resources are released. */
|
|
230
|
+
[PlaybackSessionEvents.sessionDisposed]: [
|
|
231
|
+
{
|
|
232
|
+
/** Opaque Remedia session identity used to correlate events; distinct from the Discord bot user ID. */
|
|
233
|
+
sessionId: string;
|
|
234
|
+
/** Discord guild snowflake as a decimal string; unique within the owning client. */
|
|
235
|
+
guildId?: string;
|
|
236
|
+
/** Node identifier; embedded session events use null. */
|
|
237
|
+
nodeId: string | null;
|
|
238
|
+
/** Source generation used to correlate playback events; independent of transport replacement generations. */
|
|
239
|
+
generation: number;
|
|
240
|
+
}
|
|
241
|
+
];
|
|
242
|
+
};
|
|
243
|
+
/** Session lifecycle events and native diagnostic notifications forwarded by the embedded engine. */
|
|
244
|
+
export interface RemediaLifecycleEvents extends SessionLifecycleEvents<unknown> {
|
|
245
|
+
/** Emitted for a structured native diagnostic event. */
|
|
246
|
+
[RemediaEvents.debug]: [import('./types.js').DiagnosticEvent];
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Local metadata and cancellation options for one playback generation; session configuration persists across generations.
|
|
250
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
251
|
+
*/
|
|
252
|
+
export interface PlayOptions<Metadata = unknown> {
|
|
253
|
+
/** Application-owned metadata retained locally for the source generation and attached to its events. */
|
|
254
|
+
customMetadata?: Metadata;
|
|
255
|
+
/**
|
|
256
|
+
* Optional cancellation signal; cancellation before startup prevents playback, and cancellation after startup stops that generation.
|
|
257
|
+
*/
|
|
258
|
+
signal?: AbortSignal;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Caller-owned media input, metadata, and cancellation signal supplied to each awaited pre-play hook.
|
|
262
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
263
|
+
*/
|
|
264
|
+
export interface BeforePlayContext<Metadata = unknown> {
|
|
265
|
+
/** Caller-owned encoded input that the hooks inspect before the decoder opens it. */
|
|
266
|
+
readonly source: MediaSource;
|
|
267
|
+
/** Application-owned metadata retained locally for the source generation and attached to its events. */
|
|
268
|
+
readonly customMetadata: Metadata | undefined;
|
|
269
|
+
/** Cancellation signal for this hook invocation; check it before performing asynchronous work. */
|
|
270
|
+
readonly signal: AbortSignal;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Hook result: return nothing to continue, or cancel with an optional explanation to reject playback with AbortError.
|
|
274
|
+
*/
|
|
275
|
+
export type BeforePlayResult = void | {
|
|
276
|
+
/** Return true from a pre-play hook to reject playback before opening the source. */
|
|
277
|
+
cancel: true;
|
|
278
|
+
/** Optional explanation for cancellation or a terminal playback event. */
|
|
279
|
+
reason?: string;
|
|
280
|
+
};
|
|
281
|
+
/**
|
|
282
|
+
* Awaited local callback run before a source opens; rejection or cancellation prevents that source from starting.
|
|
283
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
284
|
+
* @param context - Source, local metadata, and cancellation signal supplied to the awaited hooks.
|
|
285
|
+
* @returns Nothing to continue, or a cancellation result; a promise is awaited before source opening.
|
|
286
|
+
*/
|
|
287
|
+
export type BeforePlayHook<Metadata = unknown> = (context: BeforePlayContext<Metadata>) => BeforePlayResult | Promise<BeforePlayResult>;
|
|
288
|
+
/**
|
|
289
|
+
* Ordered, awaited local middleware. It is not a server authorization mechanism.
|
|
290
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
291
|
+
*/
|
|
292
|
+
export declare class PlaybackHooks<Metadata = unknown> {
|
|
293
|
+
#private;
|
|
294
|
+
/**
|
|
295
|
+
* Append an awaited pre-play hook. Hooks run in registration order before a source opens.
|
|
296
|
+
* @param hook - Local callback to await before opening each source; returning cancel rejects playback.
|
|
297
|
+
* @returns An idempotent function that removes this hook registration.
|
|
298
|
+
*/
|
|
299
|
+
beforePlay(hook: BeforePlayHook<Metadata>): () => void;
|
|
300
|
+
/**
|
|
301
|
+
* Run registered pre-play hooks in order and reject on cancellation or hook failure.
|
|
302
|
+
* @param context - Source, local metadata, and cancellation signal supplied to the awaited hooks.
|
|
303
|
+
* @returns Resolves when every hook permits playback; cancellation rejects with AbortError.
|
|
304
|
+
*/
|
|
305
|
+
runBeforePlay(context: BeforePlayContext<Metadata>): Promise<void>;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Create playback event correlation fields for one local source generation.
|
|
309
|
+
* @param generation - Native source generation associated with the lifecycle notification.
|
|
310
|
+
* @param customMetadata - Application-owned metadata associated with this source generation.
|
|
311
|
+
* @returns Identity fields with metadata included only when provided.
|
|
312
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
313
|
+
* @param sessionId - Opaque Remedia session identity used for event correlation.
|
|
314
|
+
*/
|
|
315
|
+
export declare function lifecycleContext<Metadata>(sessionId: string, generation: number, customMetadata: Metadata | undefined): PlaybackEventIdentity<Metadata>;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/** Stable names for playback/session event subscriptions and emission. */
|
|
2
|
+
export const PlaybackSessionEvents = {
|
|
3
|
+
/** Emitted after a source starts and its stream information is available. */
|
|
4
|
+
playbackStarted: 'playbackStarted',
|
|
5
|
+
/** Emitted when a source generation reaches natural end-of-stream. */
|
|
6
|
+
playbackCompleted: 'playbackCompleted',
|
|
7
|
+
/** Emitted when a source generation is explicitly stopped or cancelled. */
|
|
8
|
+
playbackStopped: 'playbackStopped',
|
|
9
|
+
/** Emitted when a source generation fails to open, decode, process, or deliver output. */
|
|
10
|
+
playbackFailed: 'playbackFailed',
|
|
11
|
+
/** Emitted when playback is paused without replacing its source generation. */
|
|
12
|
+
playbackPaused: 'playbackPaused',
|
|
13
|
+
/** Emitted when paused playback resumes. */
|
|
14
|
+
playbackResumed: 'playbackResumed',
|
|
15
|
+
/** Emitted after seeking to a source timeline position. */
|
|
16
|
+
playbackSeeked: 'playbackSeeked',
|
|
17
|
+
/** Emitted when the configured session filtergraph changes. */
|
|
18
|
+
filterChanged: 'filterChanged',
|
|
19
|
+
/** Emitted when the configured session linear gain changes. */
|
|
20
|
+
volumeChanged: 'volumeChanged',
|
|
21
|
+
/** Emitted when a session is unregistered and its owned resources are released. */
|
|
22
|
+
sessionDisposed: 'sessionDisposed',
|
|
23
|
+
};
|
|
24
|
+
/** Stable event names for typed VoiceSessionEvents subscriptions. */
|
|
25
|
+
export const VoiceSessionEvents = {
|
|
26
|
+
/** Emitted when the Discord transport lifecycle state changes. */
|
|
27
|
+
voiceStateChanged: 'voiceStateChanged',
|
|
28
|
+
/** Emitted when voice connection or recovery fails. */
|
|
29
|
+
voiceFailed: 'voiceFailed',
|
|
30
|
+
};
|
|
31
|
+
/** Stable event names for typed RemediaEvents subscriptions. */
|
|
32
|
+
export const RemediaEvents = {
|
|
33
|
+
...PlaybackSessionEvents,
|
|
34
|
+
...VoiceSessionEvents,
|
|
35
|
+
/** Emitted for a structured native diagnostic event. */
|
|
36
|
+
debug: 'debug',
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Ordered, awaited local middleware. It is not a server authorization mechanism.
|
|
40
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
41
|
+
*/
|
|
42
|
+
export class PlaybackHooks {
|
|
43
|
+
#beforePlay = [];
|
|
44
|
+
/**
|
|
45
|
+
* Append an awaited pre-play hook. Hooks run in registration order before a source opens.
|
|
46
|
+
* @param hook - Local callback to await before opening each source; returning cancel rejects playback.
|
|
47
|
+
* @returns An idempotent function that removes this hook registration.
|
|
48
|
+
*/
|
|
49
|
+
beforePlay(hook) {
|
|
50
|
+
if (typeof hook !== 'function')
|
|
51
|
+
throw new TypeError('beforePlay hook must be a function');
|
|
52
|
+
this.#beforePlay.push(hook);
|
|
53
|
+
return () => {
|
|
54
|
+
const index = this.#beforePlay.indexOf(hook);
|
|
55
|
+
if (index >= 0)
|
|
56
|
+
this.#beforePlay.splice(index, 1);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run registered pre-play hooks in order and reject on cancellation or hook failure.
|
|
61
|
+
* @param context - Source, local metadata, and cancellation signal supplied to the awaited hooks.
|
|
62
|
+
* @returns Resolves when every hook permits playback; cancellation rejects with AbortError.
|
|
63
|
+
*/
|
|
64
|
+
async runBeforePlay(context) {
|
|
65
|
+
for (const hook of [...this.#beforePlay]) {
|
|
66
|
+
if (context.signal.aborted)
|
|
67
|
+
throw abortError(context.signal.reason);
|
|
68
|
+
const result = await raceAbort(Promise.resolve().then(() => hook(context)), context.signal);
|
|
69
|
+
if (context.signal.aborted)
|
|
70
|
+
throw abortError(context.signal.reason);
|
|
71
|
+
if (result?.cancel) {
|
|
72
|
+
const error = new Error(result.reason ?? 'playback was cancelled by a beforePlay hook');
|
|
73
|
+
error.name = 'AbortError';
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** @internal Release application hook references when the owning session is disposed. */
|
|
79
|
+
clear() {
|
|
80
|
+
this.#beforePlay.length = 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create playback event correlation fields for one local source generation.
|
|
85
|
+
* @param generation - Native source generation associated with the lifecycle notification.
|
|
86
|
+
* @param customMetadata - Application-owned metadata associated with this source generation.
|
|
87
|
+
* @returns Identity fields with metadata included only when provided.
|
|
88
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
89
|
+
* @param sessionId - Opaque Remedia session identity used for event correlation.
|
|
90
|
+
*/
|
|
91
|
+
export function lifecycleContext(sessionId, generation, customMetadata) {
|
|
92
|
+
return customMetadata === undefined
|
|
93
|
+
? { sessionId, nodeId: null, generation }
|
|
94
|
+
: { sessionId, nodeId: null, generation, customMetadata };
|
|
95
|
+
}
|
|
96
|
+
function abortError(reason) {
|
|
97
|
+
const error = new Error(reason instanceof Error ? reason.message : 'playback was cancelled');
|
|
98
|
+
error.name = 'AbortError';
|
|
99
|
+
return error;
|
|
100
|
+
}
|
|
101
|
+
function raceAbort(operation, signal) {
|
|
102
|
+
if (signal.aborted)
|
|
103
|
+
return Promise.reject(abortError(signal.reason));
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const onAbort = () => reject(abortError(signal.reason));
|
|
106
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
107
|
+
operation.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort));
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { RemediaEventEmitter } from './events.js';
|
|
2
|
+
import { type MediaSource } from './input.js';
|
|
3
|
+
import { PlaybackHooks, type PlayOptions, type PlaybackSessionEventMap } from './lifecycle.js';
|
|
4
|
+
import { type AudioStreamInfo, type PlaybackPosition, type PlaybackState } from './types.js';
|
|
5
|
+
import { FilterControls } from './filters.js';
|
|
6
|
+
/**
|
|
7
|
+
* Controls one playback session. Local sessions decode into a no-op output.
|
|
8
|
+
* @typeParam Metadata - Application-owned metadata attached to playback generations.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PlaybackSession<Metadata = unknown> extends RemediaEventEmitter<PlaybackSessionEventMap<Metadata>> {
|
|
11
|
+
#private;
|
|
12
|
+
/** Ordered, awaited local pre-play hooks; listeners are separate from hooks. */
|
|
13
|
+
readonly hooks: PlaybackHooks<Metadata>;
|
|
14
|
+
/** Persistent raw FFmpeg filtergraph controls for this session. */
|
|
15
|
+
readonly filters: FilterControls;
|
|
16
|
+
/** Stable opaque identity for this wrapper, suitable for correlating lifecycle events. */
|
|
17
|
+
get sessionId(): string;
|
|
18
|
+
/** Current playback lifecycle state. */
|
|
19
|
+
get state(): PlaybackState;
|
|
20
|
+
/** Latest source and output timeline measurements in milliseconds. */
|
|
21
|
+
get position(): PlaybackPosition;
|
|
22
|
+
/** Source duration in milliseconds, or null when unknown. */
|
|
23
|
+
get durationMs(): number | null;
|
|
24
|
+
/** Most recent playback or voice failure message, or null when no error is available. */
|
|
25
|
+
get error(): string | null;
|
|
26
|
+
/** Current normalized linear master gain, from 0.0 (mute) through 2.0. */
|
|
27
|
+
get volume(): number;
|
|
28
|
+
/**
|
|
29
|
+
* Set master gain independently of the raw filtergraph.
|
|
30
|
+
* @param gain - Finite linear master gain from 0 through 2; 1 leaves amplitude unchanged.
|
|
31
|
+
* @returns Resolves after the gain is stored or applied; rejects for non-finite gain or values outside 0 through 2.
|
|
32
|
+
* @throws {RangeError} If gain is non-finite or outside the inclusive range 0 through 2.
|
|
33
|
+
*/
|
|
34
|
+
setVolume(gain: number): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Open one media source and begin a new playback generation using the persistent session configuration. Stop active playback before starting another source.
|
|
37
|
+
* @param source - Encoded media input; Buffer and caller-owned binary Readable inputs require embedded mode.
|
|
38
|
+
* @param options - Optional metadata for this generation and a cancellation signal.
|
|
39
|
+
* @returns Selected stream metadata once startup succeeds; rejects if hooks, input opening, or playback startup fail.
|
|
40
|
+
*/
|
|
41
|
+
play(source: MediaSource, options?: PlayOptions<Metadata>): Promise<AudioStreamInfo>;
|
|
42
|
+
/**
|
|
43
|
+
* Pause the current playback without replacing its decoder or source generation.
|
|
44
|
+
* @returns Resolves when the backend accepts the pause request.
|
|
45
|
+
*/
|
|
46
|
+
pause(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Resume paused playback on its existing source generation.
|
|
49
|
+
* @returns Resolves when the backend accepts the resume request.
|
|
50
|
+
*/
|
|
51
|
+
resume(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Seek on the original media timeline; non-seekable and one-shot sources may reject.
|
|
54
|
+
* @param positionMs - Non-negative finite position on the original media timeline, in milliseconds.
|
|
55
|
+
* @returns Resolves after the backend accepts the seek; rejects for invalid positions or unsupported inputs.
|
|
56
|
+
*/
|
|
57
|
+
seek(positionMs: number): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Stop the active playback generation and release its input without leaving the voice channel.
|
|
60
|
+
* @returns Resolves after the backend stops the active source.
|
|
61
|
+
*/
|
|
62
|
+
stop(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Wait for the current playback generation to reach a terminal state.
|
|
65
|
+
* @returns The terminal playback state for the generation captured by this wait.
|
|
66
|
+
*/
|
|
67
|
+
wait(): Promise<PlaybackState>;
|
|
68
|
+
/**
|
|
69
|
+
* Stop and release this standalone playback session.
|
|
70
|
+
* @returns Resolves after disposal; rejects if resource cleanup fails.
|
|
71
|
+
*/
|
|
72
|
+
dispose(): Promise<void>;
|
|
73
|
+
}
|