@harmonia-audio/codec 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,425 @@
1
+ import { Transform, TransformCallback } from 'node:stream';
2
+
3
+ /**
4
+ * Opus application modes.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const encoder = new OpusEncoder({
9
+ * sampleRate: 48000,
10
+ * channels: 2,
11
+ * application: 'audio',
12
+ * });
13
+ * ```
14
+ */
15
+ type OpusApplication = "voip" | "audio" | "restricted_lowdelay";
16
+ /**
17
+ * Opus signal type hints.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * encoder.setSignal('music');
22
+ * ```
23
+ */
24
+ type OpusSignalType = "voice" | "music";
25
+ /**
26
+ * Configuration options for creating an Opus encoder.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const options: OpusEncoderOptions = {
31
+ * sampleRate: 48000,
32
+ * channels: 2,
33
+ * application: 'audio',
34
+ * bitrate: 128000,
35
+ * };
36
+ * ```
37
+ */
38
+ interface OpusEncoderOptions {
39
+ readonly sampleRate: (typeof OPUS_SAMPLE_RATES)[number];
40
+ readonly channels: (typeof OPUS_CHANNELS)[number];
41
+ readonly application: OpusApplication;
42
+ readonly bitrate?: number;
43
+ readonly complexity?: number;
44
+ readonly fec?: boolean;
45
+ readonly packetLossPercent?: number;
46
+ readonly dtx?: boolean;
47
+ readonly vbr?: boolean;
48
+ readonly signal?: OpusSignalType;
49
+ }
50
+ /**
51
+ * Configuration options for creating an Opus decoder.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const decoder = new OpusDecoder({ sampleRate: 48000, channels: 2 });
56
+ * ```
57
+ */
58
+ interface OpusDecoderOptions {
59
+ readonly sampleRate: (typeof OPUS_SAMPLE_RATES)[number];
60
+ readonly channels: (typeof OPUS_CHANNELS)[number];
61
+ }
62
+ /** Valid Opus sample rates. */
63
+ declare const OPUS_SAMPLE_RATES: readonly [8000, 12000, 16000, 24000, 48000];
64
+ /** Valid Opus channel counts. */
65
+ declare const OPUS_CHANNELS: readonly [1, 2];
66
+ /** Valid Opus frame durations in milliseconds. */
67
+ declare const OPUS_FRAME_DURATIONS: readonly [2.5, 5, 10, 20, 40, 60];
68
+ /** Discord's required Opus sample rate. */
69
+ declare const DISCORD_OPUS_SAMPLE_RATE: 48000;
70
+ /** Discord's required Opus channel count (stereo). */
71
+ declare const DISCORD_OPUS_CHANNELS: 2;
72
+ /** Discord's standard Opus frame duration in milliseconds. */
73
+ declare const DISCORD_OPUS_FRAME_DURATION: 20;
74
+ /** Discord Opus frame size in samples per channel. */
75
+ declare const DISCORD_OPUS_FRAME_SIZE: 960;
76
+
77
+ /**
78
+ * High-performance Opus encoder backed by native Rust bindings.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import { OpusEncoder } from '@harmonia/codec';
83
+ *
84
+ * const encoder = new OpusEncoder({
85
+ * sampleRate: 48000,
86
+ * channels: 2,
87
+ * application: 'audio',
88
+ * });
89
+ *
90
+ * const encoded = encoder.encode(pcmBuffer);
91
+ * ```
92
+ */
93
+ declare class OpusEncoder {
94
+ private readonly native;
95
+ private readonly _sampleRate;
96
+ private readonly _channels;
97
+ private readonly _application;
98
+ constructor(options: OpusEncoderOptions);
99
+ /**
100
+ * Encode 16-bit PCM audio to Opus.
101
+ *
102
+ * @param pcm - Buffer containing interleaved 16-bit signed integer PCM samples
103
+ * @returns Encoded Opus packet
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * const opus = encoder.encode(pcmBuffer);
108
+ * ```
109
+ */
110
+ encode(pcm: Buffer): Buffer;
111
+ /**
112
+ * Encode 32-bit float PCM audio to Opus.
113
+ *
114
+ * @param pcm - Buffer containing interleaved 32-bit float PCM samples
115
+ * @returns Encoded Opus packet
116
+ *
117
+ * @example
118
+ * ```ts
119
+ * const opus = encoder.encodeFloat(floatPcmBuffer);
120
+ * ```
121
+ */
122
+ encodeFloat(pcm: Buffer): Buffer;
123
+ /**
124
+ * Set the encoder bitrate in bits per second.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * encoder.setBitrate(128000);
129
+ * ```
130
+ */
131
+ setBitrate(bitrate: number): void;
132
+ /**
133
+ * Get the current encoder bitrate.
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * const bitrate = encoder.getBitrate();
138
+ * ```
139
+ */
140
+ getBitrate(): number;
141
+ /**
142
+ * Set encoding complexity (0-10, higher = better quality but slower).
143
+ *
144
+ * @example
145
+ * ```ts
146
+ * encoder.setComplexity(10);
147
+ * ```
148
+ */
149
+ setComplexity(complexity: number): void;
150
+ /**
151
+ * Get the current encoding complexity.
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * const complexity = encoder.getComplexity();
156
+ * ```
157
+ */
158
+ getComplexity(): number;
159
+ /**
160
+ * Enable or disable forward error correction.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * encoder.setFec(true);
165
+ * ```
166
+ */
167
+ setFec(enabled: boolean): void;
168
+ /**
169
+ * Check if FEC is enabled.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * const fecEnabled = encoder.getFec();
174
+ * ```
175
+ */
176
+ getFec(): boolean;
177
+ /**
178
+ * Set expected packet loss percentage for FEC optimization.
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * encoder.setPacketLossPercent(10);
183
+ * ```
184
+ */
185
+ setPacketLossPercent(percent: number): void;
186
+ /**
187
+ * Enable or disable discontinuous transmission.
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * encoder.setDtx(true);
192
+ * ```
193
+ */
194
+ setDtx(enabled: boolean): void;
195
+ /**
196
+ * Enable or disable variable bitrate.
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * encoder.setVbr(true);
201
+ * ```
202
+ */
203
+ setVbr(enabled: boolean): void;
204
+ /**
205
+ * Set the signal type hint.
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * encoder.setSignal('music');
210
+ * ```
211
+ */
212
+ setSignal(signal: OpusSignalType): void;
213
+ /**
214
+ * Reset the encoder state.
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * encoder.reset();
219
+ * ```
220
+ */
221
+ reset(): void;
222
+ /** The sample rate this encoder operates at. */
223
+ get sampleRate(): number;
224
+ /** The number of channels this encoder operates with. */
225
+ get channels(): number;
226
+ /** The application mode this encoder was configured with. */
227
+ get application(): OpusApplication;
228
+ }
229
+
230
+ /**
231
+ * High-performance Opus decoder backed by native Rust bindings.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * import { OpusDecoder } from '@harmonia/codec';
236
+ *
237
+ * const decoder = new OpusDecoder({ sampleRate: 48000, channels: 2 });
238
+ * const pcm = decoder.decode(opusPacket);
239
+ * ```
240
+ */
241
+ declare class OpusDecoder {
242
+ private readonly native;
243
+ private readonly _sampleRate;
244
+ private readonly _channels;
245
+ constructor(options: OpusDecoderOptions);
246
+ /**
247
+ * Decode an Opus packet to 16-bit PCM.
248
+ *
249
+ * @param opusData - The Opus-encoded packet
250
+ * @returns Buffer containing decoded 16-bit PCM samples
251
+ *
252
+ * @example
253
+ * ```ts
254
+ * const pcm = decoder.decode(opusPacket);
255
+ * ```
256
+ */
257
+ decode(opusData: Buffer): Buffer;
258
+ /**
259
+ * Decode an Opus packet to 32-bit float PCM.
260
+ *
261
+ * @param opusData - The Opus-encoded packet
262
+ * @returns Buffer containing decoded 32-bit float PCM samples
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * const pcm = decoder.decodeFloat(opusPacket);
267
+ * ```
268
+ */
269
+ decodeFloat(opusData: Buffer): Buffer;
270
+ /**
271
+ * Decode with forward error correction from a previous packet.
272
+ *
273
+ * @param opusData - The Opus packet to attempt FEC recovery from
274
+ * @param frameSize - Number of samples per channel expected
275
+ * @returns Buffer containing recovered PCM
276
+ *
277
+ * @example
278
+ * ```ts
279
+ * const recovered = decoder.decodeFec(previousPacket, 960);
280
+ * ```
281
+ */
282
+ decodeFec(opusData: Buffer, frameSize: number): Buffer;
283
+ /**
284
+ * Perform packet loss concealment (no input packet available).
285
+ *
286
+ * @param frameSize - Number of samples per channel to generate
287
+ * @returns Buffer containing concealed PCM
288
+ *
289
+ * @example
290
+ * ```ts
291
+ * const concealed = decoder.decodePlc(960);
292
+ * ```
293
+ */
294
+ decodePlc(frameSize: number): Buffer;
295
+ /**
296
+ * Reset the decoder state.
297
+ *
298
+ * @example
299
+ * ```ts
300
+ * decoder.reset();
301
+ * ```
302
+ */
303
+ reset(): void;
304
+ /** The sample rate this decoder operates at. */
305
+ get sampleRate(): number;
306
+ /** The number of channels this decoder produces. */
307
+ get channels(): number;
308
+ }
309
+
310
+ /**
311
+ * Transform stream that encodes PCM to Opus.
312
+ *
313
+ * @example
314
+ * ```ts
315
+ * import { OpusEncoderStream } from '@harmonia/codec';
316
+ *
317
+ * const stream = new OpusEncoderStream({
318
+ * sampleRate: 48000,
319
+ * channels: 2,
320
+ * application: 'audio',
321
+ * });
322
+ *
323
+ * pcmSource.pipe(stream).on('data', (opusPacket) => {
324
+ * // handle encoded packet
325
+ * });
326
+ * ```
327
+ */
328
+ declare class OpusEncoderStream extends Transform {
329
+ private readonly encoder;
330
+ private readonly frameSize;
331
+ private readonly frameSizeBytes;
332
+ private pendingBuffer;
333
+ constructor(options: OpusEncoderOptions);
334
+ _transform(chunk: Buffer, _encoding: BufferEncoding, callback: TransformCallback): void;
335
+ _flush(callback: TransformCallback): void;
336
+ }
337
+ /**
338
+ * Transform stream that decodes Opus to PCM.
339
+ *
340
+ * @example
341
+ * ```ts
342
+ * import { OpusDecoderStream } from '@harmonia/codec';
343
+ *
344
+ * const stream = new OpusDecoderStream({ sampleRate: 48000, channels: 2 });
345
+ *
346
+ * opusSource.pipe(stream).on('data', (pcm) => {
347
+ * // handle decoded PCM
348
+ * });
349
+ * ```
350
+ */
351
+ declare class OpusDecoderStream extends Transform {
352
+ private readonly decoder;
353
+ constructor(options: OpusDecoderOptions);
354
+ _transform(chunk: Buffer, _encoding: BufferEncoding, callback: TransformCallback): void;
355
+ }
356
+
357
+ /**
358
+ * Utilities for inspecting Opus packets without decoding.
359
+ *
360
+ * @example
361
+ * ```ts
362
+ * import { OpusPacket } from '@harmonia/codec';
363
+ *
364
+ * const channels = OpusPacket.getChannels(opusData);
365
+ * const frames = OpusPacket.getFrameCount(opusData);
366
+ * ```
367
+ */
368
+ declare class OpusPacket {
369
+ /**
370
+ * Get the number of channels from an Opus packet header.
371
+ *
372
+ * @example
373
+ * ```ts
374
+ * const channels = OpusPacket.getChannels(opusPacket);
375
+ * ```
376
+ */
377
+ static getChannels(packet: Buffer): number;
378
+ /**
379
+ * Get the number of frames in an Opus packet.
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * const frameCount = OpusPacket.getFrameCount(opusPacket);
384
+ * ```
385
+ */
386
+ static getFrameCount(packet: Buffer): number;
387
+ /**
388
+ * Get samples per frame for a given sample rate.
389
+ *
390
+ * @example
391
+ * ```ts
392
+ * const spf = OpusPacket.getSamplesPerFrame(opusPacket, 48000);
393
+ * ```
394
+ */
395
+ static getSamplesPerFrame(packet: Buffer, sampleRate: number): number;
396
+ private constructor();
397
+ }
398
+
399
+ /**
400
+ * Error thrown by Opus codec operations.
401
+ *
402
+ * @example
403
+ * ```ts
404
+ * try {
405
+ * encoder.encode(buffer);
406
+ * } catch (error) {
407
+ * if (error instanceof HarmoniaCodecError) {
408
+ * console.error(error.code, error.message);
409
+ * }
410
+ * }
411
+ * ```
412
+ */
413
+ declare class HarmoniaCodecError extends Error {
414
+ /**
415
+ * Machine-readable error code.
416
+ */
417
+ readonly code: string;
418
+ /**
419
+ * Additional context about the error.
420
+ */
421
+ readonly context: Record<string, unknown>;
422
+ constructor(code: string, message: string, context?: Record<string, unknown>);
423
+ }
424
+
425
+ export { DISCORD_OPUS_CHANNELS, DISCORD_OPUS_FRAME_DURATION, DISCORD_OPUS_FRAME_SIZE, DISCORD_OPUS_SAMPLE_RATE, HarmoniaCodecError, OPUS_CHANNELS, OPUS_FRAME_DURATIONS, OPUS_SAMPLE_RATES, type OpusApplication, OpusDecoder, type OpusDecoderOptions, OpusDecoderStream, OpusEncoder, type OpusEncoderOptions, OpusEncoderStream, OpusPacket, type OpusSignalType };