@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
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { NativeDiagnosticEvent, NativeStreamInfo } from '../native.js';
|
|
2
|
+
/** Lifecycle state of a playback pipeline, independent of its voice transport state. */
|
|
3
|
+
export type PlaybackState = 'idle' | 'starting' | 'playing' | 'pausing' | 'resuming' | 'paused' | 'stopping' | 'stopped' | 'completed' | 'failed';
|
|
4
|
+
/** Discord transport lifecycle state, including credential negotiation and recovery. */
|
|
5
|
+
export type VoiceConnectionState = 'connecting' | 'negotiatingDave' | 'connected' | 'reconnecting' | 'disconnecting' | 'disconnected' | 'failed';
|
|
6
|
+
/** Metadata and format information for the selected audio stream; unavailable measurements are null. */
|
|
7
|
+
export interface AudioStreamInfo {
|
|
8
|
+
/** Zero-based index of the selected audio stream in the media container. */
|
|
9
|
+
streamIndex: number;
|
|
10
|
+
/** Codec name reported by the selected audio stream. */
|
|
11
|
+
codec: string;
|
|
12
|
+
/** Encoded stream sample rate in Hz, or null when unknown; playback output is normalized separately. */
|
|
13
|
+
sampleRate: number | null;
|
|
14
|
+
/** Encoded stream channel count, or null when unknown. */
|
|
15
|
+
channels: number | null;
|
|
16
|
+
/** Encoded stream channel layout description, or null when unknown. */
|
|
17
|
+
channelLayout: string | null;
|
|
18
|
+
/** Source duration in milliseconds, or null when unknown. */
|
|
19
|
+
durationMs: number | null;
|
|
20
|
+
/** Stream bit rate in bits per second, or null when unknown. */
|
|
21
|
+
bitRate: number | null;
|
|
22
|
+
/** Container or stream metadata keyed by native tag name. */
|
|
23
|
+
metadata: Readonly<Record<string, string>>;
|
|
24
|
+
}
|
|
25
|
+
/** Source and output timeline measurements in milliseconds; unsupported measurements are null. */
|
|
26
|
+
export interface PlaybackPosition {
|
|
27
|
+
/** Original media timeline associated with the latest submitted PCM block. */
|
|
28
|
+
mediaMs: number | null;
|
|
29
|
+
/** `timestamp` when derived from source PTS, `estimated` when inferred, or null. */
|
|
30
|
+
mediaPositionAccuracy: 'timestamp' | 'estimated' | null;
|
|
31
|
+
/**
|
|
32
|
+
* Duration of audio submitted to the output in milliseconds; may differ from source position after filtering.
|
|
33
|
+
*/
|
|
34
|
+
submittedMs: number;
|
|
35
|
+
/** Output-reported played duration in milliseconds, or null when the output does not provide it. */
|
|
36
|
+
playedMs: number | null;
|
|
37
|
+
}
|
|
38
|
+
/** Severity of a structured native tracing event. */
|
|
39
|
+
export type DiagnosticSeverity = 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
40
|
+
/** Typed diagnostic value; integers remain decimal strings to preserve precision in JavaScript. */
|
|
41
|
+
export type DiagnosticFieldValue = {
|
|
42
|
+
/** Discriminant describing the representation of the diagnostic field. */
|
|
43
|
+
kind: 'string' | 'debug';
|
|
44
|
+
/** Diagnostic field value in the representation selected by kind. */
|
|
45
|
+
value: string;
|
|
46
|
+
} | {
|
|
47
|
+
/** Discriminant describing the representation of the diagnostic field. */
|
|
48
|
+
kind: 'integer';
|
|
49
|
+
/** Diagnostic field value in the representation selected by kind. */
|
|
50
|
+
value: string;
|
|
51
|
+
} | {
|
|
52
|
+
/** Discriminant describing the representation of the diagnostic field. */
|
|
53
|
+
kind: 'boolean';
|
|
54
|
+
/** Diagnostic field value in the representation selected by kind. */
|
|
55
|
+
value: boolean;
|
|
56
|
+
} | {
|
|
57
|
+
/** Discriminant describing the representation of the diagnostic field. */
|
|
58
|
+
kind: 'number';
|
|
59
|
+
/** Diagnostic field value in the representation selected by kind. */
|
|
60
|
+
value: number;
|
|
61
|
+
};
|
|
62
|
+
/** Structured native diagnostic event forwarded through the bounded diagnostic queues. */
|
|
63
|
+
export interface DiagnosticEvent {
|
|
64
|
+
/** Unix timestamp of the diagnostic event in milliseconds. */
|
|
65
|
+
timestamp: number;
|
|
66
|
+
/** Native tracing severity associated with the event. */
|
|
67
|
+
severity: DiagnosticSeverity;
|
|
68
|
+
/** Native tracing target or module that emitted the diagnostic. */
|
|
69
|
+
target: string;
|
|
70
|
+
/** Server or diagnostic event name. */
|
|
71
|
+
event: string;
|
|
72
|
+
/** Human-readable diagnostic or failure description. */
|
|
73
|
+
message: string | null;
|
|
74
|
+
/** Native playback identity, or null for diagnostics without playback context. */
|
|
75
|
+
playbackId: string | null;
|
|
76
|
+
/** Native voice connection identity, or null for diagnostics without voice context. */
|
|
77
|
+
voiceConnectionId: string | null;
|
|
78
|
+
/** Typed structured diagnostic fields; integers are represented as decimal strings. */
|
|
79
|
+
fields: Readonly<Record<string, DiagnosticFieldValue>>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Callback receiving a structured native diagnostic event.
|
|
83
|
+
* @param event - Structured native diagnostic delivered by the bounded event queue.
|
|
84
|
+
*/
|
|
85
|
+
export type DebugListener = (event: DiagnosticEvent) => void;
|
|
86
|
+
/**
|
|
87
|
+
* Normalize native optional stream metadata into explicit nullable public fields.
|
|
88
|
+
* @param info - Native stream metadata to normalize into the public nullable representation.
|
|
89
|
+
* @returns Stream metadata using the public AudioStreamInfo representation.
|
|
90
|
+
*/
|
|
91
|
+
export declare function toStreamInfo(info: NativeStreamInfo): AudioStreamInfo;
|
|
92
|
+
/**
|
|
93
|
+
* Normalize a structured native diagnostic; invalid severity or field representations throw.
|
|
94
|
+
* @param event - Event name identifying the typed notification or Gateway voice dispatch.
|
|
95
|
+
* @returns A diagnostic event with typed field values.
|
|
96
|
+
*/
|
|
97
|
+
export declare function toDiagnosticEvent(event: NativeDiagnosticEvent): DiagnosticEvent;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize native optional stream metadata into explicit nullable public fields.
|
|
3
|
+
* @param info - Native stream metadata to normalize into the public nullable representation.
|
|
4
|
+
* @returns Stream metadata using the public AudioStreamInfo representation.
|
|
5
|
+
*/
|
|
6
|
+
export function toStreamInfo(info) {
|
|
7
|
+
return {
|
|
8
|
+
streamIndex: info.streamIndex,
|
|
9
|
+
codec: info.codec,
|
|
10
|
+
sampleRate: info.sampleRate ?? null,
|
|
11
|
+
channels: info.channels ?? null,
|
|
12
|
+
channelLayout: info.channelLayout ?? null,
|
|
13
|
+
durationMs: info.durationMs ?? null,
|
|
14
|
+
bitRate: info.bitRate ?? null,
|
|
15
|
+
metadata: info.metadata,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Normalize a structured native diagnostic; invalid severity or field representations throw.
|
|
20
|
+
* @param event - Event name identifying the typed notification or Gateway voice dispatch.
|
|
21
|
+
* @returns A diagnostic event with typed field values.
|
|
22
|
+
*/
|
|
23
|
+
export function toDiagnosticEvent(event) {
|
|
24
|
+
const severity = event.severity;
|
|
25
|
+
if (!isDiagnosticSeverity(severity)) {
|
|
26
|
+
throw new Error(`Unknown native diagnostic severity: ${severity}`);
|
|
27
|
+
}
|
|
28
|
+
const fields = {};
|
|
29
|
+
for (const [key, field] of Object.entries(event.fields)) {
|
|
30
|
+
if (field.kind === 'string' || field.kind === 'debug') {
|
|
31
|
+
if (field.stringValue === undefined) {
|
|
32
|
+
throw new Error(`Invalid native diagnostic field: ${key}`);
|
|
33
|
+
}
|
|
34
|
+
fields[key] = { kind: field.kind, value: field.stringValue };
|
|
35
|
+
}
|
|
36
|
+
else if (field.kind === 'integer') {
|
|
37
|
+
if (field.stringValue === undefined) {
|
|
38
|
+
throw new Error(`Invalid native diagnostic field: ${key}`);
|
|
39
|
+
}
|
|
40
|
+
fields[key] = { kind: 'integer', value: field.stringValue };
|
|
41
|
+
}
|
|
42
|
+
else if (field.kind === 'boolean') {
|
|
43
|
+
if (field.boolValue === undefined) {
|
|
44
|
+
throw new Error(`Invalid native diagnostic field: ${key}`);
|
|
45
|
+
}
|
|
46
|
+
fields[key] = { kind: 'boolean', value: field.boolValue };
|
|
47
|
+
}
|
|
48
|
+
else if (field.kind === 'number') {
|
|
49
|
+
if (field.numberValue === undefined) {
|
|
50
|
+
throw new Error(`Invalid native diagnostic field: ${key}`);
|
|
51
|
+
}
|
|
52
|
+
fields[key] = { kind: 'number', value: field.numberValue };
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
throw new Error(`Unknown native diagnostic field kind: ${field.kind}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
timestamp: event.timestamp,
|
|
60
|
+
severity,
|
|
61
|
+
target: event.target,
|
|
62
|
+
event: event.event,
|
|
63
|
+
message: event.message ?? null,
|
|
64
|
+
playbackId: event.playbackId ?? null,
|
|
65
|
+
voiceConnectionId: event.voiceConnectionId ?? null,
|
|
66
|
+
fields,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function isDiagnosticSeverity(value) {
|
|
70
|
+
return (value === 'trace' ||
|
|
71
|
+
value === 'debug' ||
|
|
72
|
+
value === 'info' ||
|
|
73
|
+
value === 'warn' ||
|
|
74
|
+
value === 'error');
|
|
75
|
+
}
|
package/native.d.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/* auto-generated by NAPI-RS */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Which binding artifact the generated loader actually loaded: `'native'` for
|
|
6
|
+
* a native addon, otherwise the `platformArchABI` of the WASI flavor. Every
|
|
7
|
+
* flavor napi-rs can build is listed, because `NAPI_RS_NATIVE_LIBRARY_PATH`
|
|
8
|
+
* can point the loader at a WASI artifact this package does not build itself.
|
|
9
|
+
*/
|
|
10
|
+
export declare const __napiBindingTarget: 'native' | 'wasm32-wasi' | 'wasm32-wasip1'
|
|
11
|
+
|
|
12
|
+
export declare class NativeRemedia {
|
|
13
|
+
/** Forward this context's bounded diagnostic queue to one JavaScript callback. */
|
|
14
|
+
setDebugCallback(callback: (arg: NativeDiagnosticEvent) => void): void
|
|
15
|
+
/** Number of events discarded by the observability queue or full N-API callback queue. */
|
|
16
|
+
get droppedDebugEvents(): number
|
|
17
|
+
/** Open a Discord voice transport using session data collected by the caller's Gateway client. */
|
|
18
|
+
connectVoice(options: NativeVoiceOptions): Promise<NativeVoiceSessionIds>
|
|
19
|
+
/**
|
|
20
|
+
* Replace only the Discord transport while retaining the existing
|
|
21
|
+
* playback decoder, filters, volume, pause state, and output timeline.
|
|
22
|
+
*/
|
|
23
|
+
replaceVoice(voiceId: string, generation: number, options: NativeVoiceOptions): Promise<void>
|
|
24
|
+
/**
|
|
25
|
+
* Invalidate an in-flight transport replacement before newer Gateway
|
|
26
|
+
* credentials are used. This does not touch the active playback session.
|
|
27
|
+
*/
|
|
28
|
+
invalidateVoiceRecovery(voiceId: string, generation: number): void
|
|
29
|
+
/** Close the old Discord transport while leaving the playback session parked for recovery. */
|
|
30
|
+
suspendVoice(voiceId: string, generation: number): Promise<void>
|
|
31
|
+
/** Terminate a playback parked during voice recovery after retries fail. */
|
|
32
|
+
failVoiceRecovery(voiceId: string, message: string): void
|
|
33
|
+
/** Current transport state for one voice session. */
|
|
34
|
+
voiceState(voiceId: string): string
|
|
35
|
+
/** Return the latest transport failure for one voice session. */
|
|
36
|
+
voiceError(voiceId: string): string | null
|
|
37
|
+
/** Stop playback and release the associated voice transport. */
|
|
38
|
+
disconnectVoice(voiceId: string): Promise<void>
|
|
39
|
+
/** Forget a voice session after its transport has been disconnected. */
|
|
40
|
+
releaseVoiceSession(voiceId: string): void
|
|
41
|
+
/** Create a bounded native byte input for one Node.js Readable producer. */
|
|
42
|
+
createByteStream(): string
|
|
43
|
+
/**
|
|
44
|
+
* Copy one Node buffer into the native-owned bounded input, applying
|
|
45
|
+
* backpressure when the decoder has not consumed enough pending bytes.
|
|
46
|
+
*/
|
|
47
|
+
writeByteStream(streamId: string, chunk: Buffer): Promise<void>
|
|
48
|
+
/**
|
|
49
|
+
* Signal a clean producer EOF. The stream handle remains valid until it is
|
|
50
|
+
* cancelled so playback can resolve its source if EOF arrives quickly.
|
|
51
|
+
*/
|
|
52
|
+
finishByteStream(streamId: string): Promise<void>
|
|
53
|
+
/** Propagate a JavaScript Readable error through FFmpeg to playback state. */
|
|
54
|
+
failByteStream(streamId: string, message: string): Promise<void>
|
|
55
|
+
/**
|
|
56
|
+
* Cancel an input and wake any native readers or writers blocked by its
|
|
57
|
+
* bounded queue. Repeated calls are harmless.
|
|
58
|
+
*/
|
|
59
|
+
cancelByteStream(streamId: string): void
|
|
60
|
+
/** Create an isolated, diagnostics-only Remedia context from environment configuration. */
|
|
61
|
+
static create(): Promise<NativeRemedia>
|
|
62
|
+
/**
|
|
63
|
+
* Stop all playback, disconnect all voice transports, flush telemetry, and close the context.
|
|
64
|
+
* This method is safe to call repeatedly.
|
|
65
|
+
*/
|
|
66
|
+
close(): Promise<void>
|
|
67
|
+
/** Create a decoder-only session that consumes frames into a no-op output. */
|
|
68
|
+
createPlaybackSession(): string
|
|
69
|
+
/** Start decoding into the null output or the associated Discord Opus sender. */
|
|
70
|
+
play(playbackId: string, source: NativeMediaSource): Promise<NativeStreamInfo>
|
|
71
|
+
/** Request playback pause at the current output frame boundary. */
|
|
72
|
+
pause(playbackId: string): Promise<void>
|
|
73
|
+
/** Resume a paused playback session. */
|
|
74
|
+
resume(playbackId: string): Promise<void>
|
|
75
|
+
/** Seek to a media position in milliseconds. */
|
|
76
|
+
seek(playbackId: string, positionMs: number): Promise<void>
|
|
77
|
+
/** Validate and replace the trusted native FFmpeg audio filtergraph. */
|
|
78
|
+
playbackSetFilterGraph(playbackId: string, graph: string): Promise<void>
|
|
79
|
+
/** Clear the current native audio filtergraph. */
|
|
80
|
+
playbackClearFilterGraph(playbackId: string): Promise<void>
|
|
81
|
+
/** Current configured raw FFmpeg filtergraph, if any. */
|
|
82
|
+
playbackFilterGraph(playbackId: string): string | null
|
|
83
|
+
/** Set normalized linear master gain in the inclusive range 0.0 through 2.0. */
|
|
84
|
+
playbackSetVolume(playbackId: string, gain: number): Promise<void>
|
|
85
|
+
/** Current normalized linear master gain. */
|
|
86
|
+
playbackVolume(playbackId: string): number
|
|
87
|
+
/** Validate a filtergraph before a Discord voice session has a native playback object. */
|
|
88
|
+
validateFilterGraph(graph: string): Promise<void>
|
|
89
|
+
/** Stop playback without disconnecting its Discord voice transport. */
|
|
90
|
+
stop(playbackId: string): Promise<void>
|
|
91
|
+
/** Capture the source generation before an asynchronous wait is scheduled. */
|
|
92
|
+
playbackGeneration(playbackId: string): string
|
|
93
|
+
/** Wait for a generation captured synchronously by the JavaScript wrapper. */
|
|
94
|
+
wait(playbackId: string, generation: string): Promise<string>
|
|
95
|
+
/** Current playback lifecycle state. */
|
|
96
|
+
playbackState(playbackId: string): string
|
|
97
|
+
/** Source media, filtered output submission, and output-reported played positions. */
|
|
98
|
+
playbackPosition(playbackId: string): NativePlaybackPosition
|
|
99
|
+
/** Known media duration in milliseconds. */
|
|
100
|
+
playbackDurationMs(playbackId: string): number | null
|
|
101
|
+
/** Latest decoder, resampler, output, or worker failure. */
|
|
102
|
+
playbackError(playbackId: string): string | null
|
|
103
|
+
/** Stop and forget a standalone playback session. Voice sessions remain connected. */
|
|
104
|
+
disposePlaybackSession(playbackId: string): Promise<void>
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface NativeDiagnosticEvent {
|
|
108
|
+
timestamp: number
|
|
109
|
+
severity: string
|
|
110
|
+
target: string
|
|
111
|
+
event: string
|
|
112
|
+
message?: string
|
|
113
|
+
playbackId?: string
|
|
114
|
+
voiceConnectionId?: string
|
|
115
|
+
fields: Record<string, NativeDiagnosticField>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface NativeDiagnosticField {
|
|
119
|
+
kind: string
|
|
120
|
+
stringValue?: string
|
|
121
|
+
boolValue?: boolean
|
|
122
|
+
numberValue?: number
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface NativeMediaSource {
|
|
126
|
+
/** Explicitly `file`, `url`, `buffer`, or `stream`. */
|
|
127
|
+
kind: string
|
|
128
|
+
value?: string
|
|
129
|
+
bytes?: Buffer
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface NativePlaybackPosition {
|
|
133
|
+
mediaMs?: number
|
|
134
|
+
mediaPositionAccuracy?: string
|
|
135
|
+
submittedMs: number
|
|
136
|
+
playedMs?: number
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface NativeStreamInfo {
|
|
140
|
+
streamIndex: number
|
|
141
|
+
codec: string
|
|
142
|
+
sampleRate?: number
|
|
143
|
+
channels?: number
|
|
144
|
+
channelLayout?: string
|
|
145
|
+
durationMs?: number
|
|
146
|
+
bitRate?: number
|
|
147
|
+
metadata: Record<string, string>
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface NativeVoiceOptions {
|
|
151
|
+
guildId: string
|
|
152
|
+
channelId: string
|
|
153
|
+
userId: string
|
|
154
|
+
sessionId: string
|
|
155
|
+
token: string
|
|
156
|
+
endpoint: string
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface NativeVoiceSessionIds {
|
|
160
|
+
voiceId: string
|
|
161
|
+
playbackId: string
|
|
162
|
+
}
|