webcodecs-node 0.5.0 → 0.5.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.
Files changed (188) hide show
  1. package/README.md +64 -184
  2. package/docs/api.md +1 -1
  3. package/docs/configuration.md +6 -17
  4. package/package.json +2 -2
  5. package/dist/AudioData.d.ts +0 -6
  6. package/dist/AudioData.d.ts.map +0 -1
  7. package/dist/AudioData.js +0 -6
  8. package/dist/AudioData.js.map +0 -1
  9. package/dist/AudioDecoder.d.ts +0 -6
  10. package/dist/AudioDecoder.d.ts.map +0 -1
  11. package/dist/AudioDecoder.js +0 -6
  12. package/dist/AudioDecoder.js.map +0 -1
  13. package/dist/AudioEncoder.d.ts +0 -6
  14. package/dist/AudioEncoder.d.ts.map +0 -1
  15. package/dist/AudioEncoder.js +0 -6
  16. package/dist/AudioEncoder.js.map +0 -1
  17. package/dist/EncodedAudioChunk.d.ts +0 -6
  18. package/dist/EncodedAudioChunk.d.ts.map +0 -1
  19. package/dist/EncodedAudioChunk.js +0 -6
  20. package/dist/EncodedAudioChunk.js.map +0 -1
  21. package/dist/EncodedVideoChunk.d.ts +0 -6
  22. package/dist/EncodedVideoChunk.d.ts.map +0 -1
  23. package/dist/EncodedVideoChunk.js +0 -6
  24. package/dist/EncodedVideoChunk.js.map +0 -1
  25. package/dist/FFmpegProcess.d.ts +0 -6
  26. package/dist/FFmpegProcess.d.ts.map +0 -1
  27. package/dist/FFmpegProcess.js +0 -6
  28. package/dist/FFmpegProcess.js.map +0 -1
  29. package/dist/HardwareAcceleration.d.ts +0 -6
  30. package/dist/HardwareAcceleration.d.ts.map +0 -1
  31. package/dist/HardwareAcceleration.js +0 -6
  32. package/dist/HardwareAcceleration.js.map +0 -1
  33. package/dist/ImageDecoder.d.ts +0 -6
  34. package/dist/ImageDecoder.d.ts.map +0 -1
  35. package/dist/ImageDecoder.js +0 -6
  36. package/dist/ImageDecoder.js.map +0 -1
  37. package/dist/Logger.d.ts +0 -6
  38. package/dist/Logger.d.ts.map +0 -1
  39. package/dist/Logger.js +0 -6
  40. package/dist/Logger.js.map +0 -1
  41. package/dist/MediaCapabilities.d.ts +0 -9
  42. package/dist/MediaCapabilities.d.ts.map +0 -1
  43. package/dist/MediaCapabilities.js +0 -8
  44. package/dist/MediaCapabilities.js.map +0 -1
  45. package/dist/VideoDecoder.d.ts +0 -6
  46. package/dist/VideoDecoder.d.ts.map +0 -1
  47. package/dist/VideoDecoder.js +0 -6
  48. package/dist/VideoDecoder.js.map +0 -1
  49. package/dist/VideoEncoder.d.ts +0 -6
  50. package/dist/VideoEncoder.d.ts.map +0 -1
  51. package/dist/VideoEncoder.js +0 -6
  52. package/dist/VideoEncoder.js.map +0 -1
  53. package/dist/VideoFrame.d.ts +0 -10
  54. package/dist/VideoFrame.d.ts.map +0 -1
  55. package/dist/VideoFrame.js +0 -9
  56. package/dist/VideoFrame.js.map +0 -1
  57. package/dist/__tests__/AudioData.test.d.ts +0 -5
  58. package/dist/__tests__/AudioData.test.d.ts.map +0 -1
  59. package/dist/__tests__/AudioData.test.js +0 -180
  60. package/dist/__tests__/AudioData.test.js.map +0 -1
  61. package/dist/__tests__/AudioDecoder.test.d.ts +0 -5
  62. package/dist/__tests__/AudioDecoder.test.d.ts.map +0 -1
  63. package/dist/__tests__/AudioDecoder.test.js +0 -733
  64. package/dist/__tests__/AudioDecoder.test.js.map +0 -1
  65. package/dist/__tests__/AudioEncoder.test.d.ts +0 -5
  66. package/dist/__tests__/AudioEncoder.test.d.ts.map +0 -1
  67. package/dist/__tests__/AudioEncoder.test.js +0 -247
  68. package/dist/__tests__/AudioEncoder.test.js.map +0 -1
  69. package/dist/__tests__/EncodedChunks.test.d.ts +0 -5
  70. package/dist/__tests__/EncodedChunks.test.d.ts.map +0 -1
  71. package/dist/__tests__/EncodedChunks.test.js +0 -100
  72. package/dist/__tests__/EncodedChunks.test.js.map +0 -1
  73. package/dist/__tests__/HardwareAcceleration.test.d.ts +0 -5
  74. package/dist/__tests__/HardwareAcceleration.test.d.ts.map +0 -1
  75. package/dist/__tests__/HardwareAcceleration.test.js +0 -85
  76. package/dist/__tests__/HardwareAcceleration.test.js.map +0 -1
  77. package/dist/__tests__/ImageDecoder.test.d.ts +0 -5
  78. package/dist/__tests__/ImageDecoder.test.d.ts.map +0 -1
  79. package/dist/__tests__/ImageDecoder.test.js +0 -558
  80. package/dist/__tests__/ImageDecoder.test.js.map +0 -1
  81. package/dist/__tests__/ImageDecoder.wpt.test.d.ts +0 -8
  82. package/dist/__tests__/ImageDecoder.wpt.test.d.ts.map +0 -1
  83. package/dist/__tests__/ImageDecoder.wpt.test.js +0 -135
  84. package/dist/__tests__/ImageDecoder.wpt.test.js.map +0 -1
  85. package/dist/__tests__/MediaCapabilities.test.d.ts +0 -5
  86. package/dist/__tests__/MediaCapabilities.test.d.ts.map +0 -1
  87. package/dist/__tests__/MediaCapabilities.test.js +0 -346
  88. package/dist/__tests__/MediaCapabilities.test.js.map +0 -1
  89. package/dist/__tests__/NodeAvDecoder.test.d.ts +0 -2
  90. package/dist/__tests__/NodeAvDecoder.test.d.ts.map +0 -1
  91. package/dist/__tests__/NodeAvDecoder.test.js +0 -206
  92. package/dist/__tests__/NodeAvDecoder.test.js.map +0 -1
  93. package/dist/__tests__/NodeAvEncoder.test.d.ts +0 -2
  94. package/dist/__tests__/NodeAvEncoder.test.d.ts.map +0 -1
  95. package/dist/__tests__/NodeAvEncoder.test.js +0 -176
  96. package/dist/__tests__/NodeAvEncoder.test.js.map +0 -1
  97. package/dist/__tests__/VideoDecoder.test.d.ts +0 -5
  98. package/dist/__tests__/VideoDecoder.test.d.ts.map +0 -1
  99. package/dist/__tests__/VideoDecoder.test.js +0 -675
  100. package/dist/__tests__/VideoDecoder.test.js.map +0 -1
  101. package/dist/__tests__/VideoEncoder.test.d.ts +0 -5
  102. package/dist/__tests__/VideoEncoder.test.d.ts.map +0 -1
  103. package/dist/__tests__/VideoEncoder.test.js +0 -468
  104. package/dist/__tests__/VideoEncoder.test.js.map +0 -1
  105. package/dist/__tests__/VideoFrame.test.d.ts +0 -5
  106. package/dist/__tests__/VideoFrame.test.d.ts.map +0 -1
  107. package/dist/__tests__/VideoFrame.test.js +0 -246
  108. package/dist/__tests__/VideoFrame.test.js.map +0 -1
  109. package/dist/__tests__/aac-utils.test.d.ts +0 -2
  110. package/dist/__tests__/aac-utils.test.d.ts.map +0 -1
  111. package/dist/__tests__/aac-utils.test.js +0 -37
  112. package/dist/__tests__/aac-utils.test.js.map +0 -1
  113. package/dist/__tests__/avc-utils.test.d.ts +0 -2
  114. package/dist/__tests__/avc-utils.test.d.ts.map +0 -1
  115. package/dist/__tests__/avc-utils.test.js +0 -63
  116. package/dist/__tests__/avc-utils.test.js.map +0 -1
  117. package/dist/__tests__/hevc-utils.test.d.ts +0 -2
  118. package/dist/__tests__/hevc-utils.test.d.ts.map +0 -1
  119. package/dist/__tests__/hevc-utils.test.js +0 -78
  120. package/dist/__tests__/hevc-utils.test.js.map +0 -1
  121. package/dist/demos/demo-conversion.d.ts +0 -13
  122. package/dist/demos/demo-conversion.d.ts.map +0 -1
  123. package/dist/demos/demo-conversion.js +0 -301
  124. package/dist/demos/demo-conversion.js.map +0 -1
  125. package/dist/demos/demo-hwaccel-conversion.d.ts +0 -8
  126. package/dist/demos/demo-hwaccel-conversion.d.ts.map +0 -1
  127. package/dist/demos/demo-hwaccel-conversion.js +0 -161
  128. package/dist/demos/demo-hwaccel-conversion.js.map +0 -1
  129. package/dist/demos/demo-mediabunny.d.ts +0 -7
  130. package/dist/demos/demo-mediabunny.d.ts.map +0 -1
  131. package/dist/demos/demo-mediabunny.js +0 -78
  132. package/dist/demos/demo-mediabunny.js.map +0 -1
  133. package/dist/ffmpeg/FFmpegProcess.d.ts +0 -111
  134. package/dist/ffmpeg/FFmpegProcess.d.ts.map +0 -1
  135. package/dist/ffmpeg/FFmpegProcess.js +0 -543
  136. package/dist/ffmpeg/FFmpegProcess.js.map +0 -1
  137. package/dist/ffmpeg/audio-codecs.d.ts +0 -59
  138. package/dist/ffmpeg/audio-codecs.d.ts.map +0 -1
  139. package/dist/ffmpeg/audio-codecs.js +0 -99
  140. package/dist/ffmpeg/audio-codecs.js.map +0 -1
  141. package/dist/ffmpeg/formats.d.ts +0 -42
  142. package/dist/ffmpeg/formats.d.ts.map +0 -1
  143. package/dist/ffmpeg/formats.js +0 -147
  144. package/dist/ffmpeg/formats.js.map +0 -1
  145. package/dist/ffmpeg/index.d.ts +0 -10
  146. package/dist/ffmpeg/index.d.ts.map +0 -1
  147. package/dist/ffmpeg/index.js +0 -13
  148. package/dist/ffmpeg/index.js.map +0 -1
  149. package/dist/ffmpeg/parsers/annexb.d.ts +0 -88
  150. package/dist/ffmpeg/parsers/annexb.d.ts.map +0 -1
  151. package/dist/ffmpeg/parsers/annexb.js +0 -201
  152. package/dist/ffmpeg/parsers/annexb.js.map +0 -1
  153. package/dist/ffmpeg/parsers/index.d.ts +0 -6
  154. package/dist/ffmpeg/parsers/index.d.ts.map +0 -1
  155. package/dist/ffmpeg/parsers/index.js +0 -8
  156. package/dist/ffmpeg/parsers/index.js.map +0 -1
  157. package/dist/ffmpeg/parsers/ivf.d.ts +0 -54
  158. package/dist/ffmpeg/parsers/ivf.d.ts.map +0 -1
  159. package/dist/ffmpeg/parsers/ivf.js +0 -109
  160. package/dist/ffmpeg/parsers/ivf.js.map +0 -1
  161. package/dist/ffmpeg/types.d.ts +0 -85
  162. package/dist/ffmpeg/types.d.ts.map +0 -1
  163. package/dist/ffmpeg/types.js +0 -8
  164. package/dist/ffmpeg/types.js.map +0 -1
  165. package/dist/mediabunny/FFmpegAudioDecoder.d.ts +0 -24
  166. package/dist/mediabunny/FFmpegAudioDecoder.d.ts.map +0 -1
  167. package/dist/mediabunny/FFmpegAudioDecoder.js +0 -126
  168. package/dist/mediabunny/FFmpegAudioDecoder.js.map +0 -1
  169. package/dist/mediabunny/FFmpegAudioEncoder.d.ts +0 -44
  170. package/dist/mediabunny/FFmpegAudioEncoder.d.ts.map +0 -1
  171. package/dist/mediabunny/FFmpegAudioEncoder.js +0 -221
  172. package/dist/mediabunny/FFmpegAudioEncoder.js.map +0 -1
  173. package/dist/mediabunny/FFmpegVideoDecoder.d.ts +0 -25
  174. package/dist/mediabunny/FFmpegVideoDecoder.d.ts.map +0 -1
  175. package/dist/mediabunny/FFmpegVideoDecoder.js +0 -122
  176. package/dist/mediabunny/FFmpegVideoDecoder.js.map +0 -1
  177. package/dist/mediabunny/FFmpegVideoEncoder.d.ts +0 -49
  178. package/dist/mediabunny/FFmpegVideoEncoder.d.ts.map +0 -1
  179. package/dist/mediabunny/FFmpegVideoEncoder.js +0 -264
  180. package/dist/mediabunny/FFmpegVideoEncoder.js.map +0 -1
  181. package/dist/mediabunny/index.d.ts +0 -21
  182. package/dist/mediabunny/index.d.ts.map +0 -1
  183. package/dist/mediabunny/index.js +0 -33
  184. package/dist/mediabunny/index.js.map +0 -1
  185. package/dist/types.d.ts +0 -6
  186. package/dist/types.d.ts.map +0 -1
  187. package/dist/types.js +0 -6
  188. package/dist/types.js.map +0 -1
@@ -1,733 +0,0 @@
1
- /**
2
- * Tests for AudioDecoder class
3
- */
4
- import { describe, it, expect } from 'vitest';
5
- import { AudioDecoder } from '../decoders/AudioDecoder.js';
6
- import { AudioEncoder } from '../encoders/AudioEncoder.js';
7
- import { AudioData } from '../core/AudioData.js';
8
- import { EncodedAudioChunk } from '../core/EncodedAudioChunk.js';
9
- describe('AudioDecoder', () => {
10
- describe('isConfigSupported', () => {
11
- it('should support Opus', async () => {
12
- const support = await AudioDecoder.isConfigSupported({
13
- codec: 'opus',
14
- sampleRate: 48000,
15
- numberOfChannels: 2,
16
- });
17
- expect(support.supported).toBe(true);
18
- });
19
- it('should support AAC', async () => {
20
- const support = await AudioDecoder.isConfigSupported({
21
- codec: 'mp4a.40.2',
22
- sampleRate: 44100,
23
- numberOfChannels: 2,
24
- });
25
- expect(support.supported).toBe(true);
26
- });
27
- it('should support MP3', async () => {
28
- const support = await AudioDecoder.isConfigSupported({
29
- codec: 'mp3',
30
- sampleRate: 44100,
31
- numberOfChannels: 2,
32
- });
33
- expect(support.supported).toBe(true);
34
- });
35
- it('should support FLAC', async () => {
36
- const support = await AudioDecoder.isConfigSupported({
37
- codec: 'flac',
38
- sampleRate: 48000,
39
- numberOfChannels: 2,
40
- });
41
- expect(support.supported).toBe(true);
42
- });
43
- it('should support Vorbis', async () => {
44
- const support = await AudioDecoder.isConfigSupported({
45
- codec: 'vorbis',
46
- sampleRate: 44100,
47
- numberOfChannels: 2,
48
- });
49
- expect(support.supported).toBe(true);
50
- });
51
- it('should not support missing codec', async () => {
52
- const support = await AudioDecoder.isConfigSupported({
53
- codec: '',
54
- sampleRate: 48000,
55
- numberOfChannels: 2,
56
- });
57
- expect(support.supported).toBe(false);
58
- });
59
- it('should not support missing sampleRate', async () => {
60
- const support = await AudioDecoder.isConfigSupported({
61
- codec: 'opus',
62
- sampleRate: 0,
63
- numberOfChannels: 2,
64
- });
65
- expect(support.supported).toBe(false);
66
- });
67
- });
68
- describe('constructor', () => {
69
- it('should create decoder with callbacks', () => {
70
- const output = jest.fn();
71
- const error = jest.fn();
72
- const decoder = new AudioDecoder({ output, error });
73
- expect(decoder.state).toBe('unconfigured');
74
- decoder.close();
75
- });
76
- it('should throw without output callback', () => {
77
- expect(() => new AudioDecoder({ output: null, error: () => { } })).toThrow();
78
- });
79
- it('should throw without error callback', () => {
80
- expect(() => new AudioDecoder({ output: () => { }, error: null })).toThrow();
81
- });
82
- });
83
- describe('configure', () => {
84
- it('should configure decoder', () => {
85
- const decoder = new AudioDecoder({
86
- output: () => { },
87
- error: () => { },
88
- });
89
- decoder.configure({
90
- codec: 'opus',
91
- sampleRate: 48000,
92
- numberOfChannels: 2,
93
- });
94
- expect(decoder.state).toBe('configured');
95
- decoder.close();
96
- });
97
- it('should throw without codec', () => {
98
- const decoder = new AudioDecoder({
99
- output: () => { },
100
- error: () => { },
101
- });
102
- expect(() => decoder.configure({
103
- codec: '',
104
- sampleRate: 48000,
105
- numberOfChannels: 2,
106
- })).toThrow();
107
- decoder.close();
108
- });
109
- it('should throw with invalid sampleRate', () => {
110
- const decoder = new AudioDecoder({
111
- output: () => { },
112
- error: () => { },
113
- });
114
- expect(() => decoder.configure({
115
- codec: 'opus',
116
- sampleRate: 0,
117
- numberOfChannels: 2,
118
- })).toThrow();
119
- decoder.close();
120
- });
121
- it('should throw with invalid numberOfChannels', () => {
122
- const decoder = new AudioDecoder({
123
- output: () => { },
124
- error: () => { },
125
- });
126
- expect(() => decoder.configure({
127
- codec: 'opus',
128
- sampleRate: 48000,
129
- numberOfChannels: 0,
130
- })).toThrow();
131
- decoder.close();
132
- });
133
- it('should throw on closed decoder', () => {
134
- const decoder = new AudioDecoder({
135
- output: () => { },
136
- error: () => { },
137
- });
138
- decoder.close();
139
- expect(() => decoder.configure({
140
- codec: 'opus',
141
- sampleRate: 48000,
142
- numberOfChannels: 2,
143
- })).toThrow();
144
- });
145
- it('should accept valid outputFormat', () => {
146
- const decoder = new AudioDecoder({
147
- output: () => { },
148
- error: () => { },
149
- });
150
- decoder.configure({
151
- codec: 'opus',
152
- sampleRate: 48000,
153
- numberOfChannels: 2,
154
- outputFormat: 's16',
155
- });
156
- expect(decoder.state).toBe('configured');
157
- decoder.close();
158
- });
159
- it('should throw with invalid outputFormat', () => {
160
- const decoder = new AudioDecoder({
161
- output: () => { },
162
- error: () => { },
163
- });
164
- expect(() => decoder.configure({
165
- codec: 'opus',
166
- sampleRate: 48000,
167
- numberOfChannels: 2,
168
- outputFormat: 'invalid',
169
- })).toThrow();
170
- decoder.close();
171
- });
172
- });
173
- describe('decode', () => {
174
- it('should throw when not configured', () => {
175
- const decoder = new AudioDecoder({
176
- output: () => { },
177
- error: () => { },
178
- });
179
- const chunk = new EncodedAudioChunk({
180
- type: 'key',
181
- timestamp: 0,
182
- data: new Uint8Array(100),
183
- });
184
- expect(() => decoder.decode(chunk)).toThrow();
185
- decoder.close();
186
- });
187
- it('should throw with invalid chunk', () => {
188
- const decoder = new AudioDecoder({
189
- output: () => { },
190
- error: () => { },
191
- });
192
- decoder.configure({
193
- codec: 'opus',
194
- sampleRate: 48000,
195
- numberOfChannels: 2,
196
- });
197
- expect(() => decoder.decode('invalid')).toThrow();
198
- decoder.close();
199
- });
200
- });
201
- describe('reset', () => {
202
- it('should reset decoder to unconfigured state', () => {
203
- const decoder = new AudioDecoder({
204
- output: () => { },
205
- error: () => { },
206
- });
207
- decoder.configure({
208
- codec: 'opus',
209
- sampleRate: 48000,
210
- numberOfChannels: 2,
211
- });
212
- expect(decoder.state).toBe('configured');
213
- decoder.reset();
214
- expect(decoder.state).toBe('unconfigured');
215
- decoder.close();
216
- });
217
- it('should throw on closed decoder', () => {
218
- const decoder = new AudioDecoder({
219
- output: () => { },
220
- error: () => { },
221
- });
222
- decoder.close();
223
- expect(() => decoder.reset()).toThrow();
224
- });
225
- });
226
- describe('close', () => {
227
- it('should close decoder', () => {
228
- const decoder = new AudioDecoder({
229
- output: () => { },
230
- error: () => { },
231
- });
232
- decoder.close();
233
- expect(decoder.state).toBe('closed');
234
- });
235
- it('should be idempotent', () => {
236
- const decoder = new AudioDecoder({
237
- output: () => { },
238
- error: () => { },
239
- });
240
- decoder.close();
241
- decoder.close(); // Should not throw
242
- expect(decoder.state).toBe('closed');
243
- });
244
- });
245
- describe('flush', () => {
246
- it('should throw when not configured', async () => {
247
- const decoder = new AudioDecoder({
248
- output: () => { },
249
- error: () => { },
250
- });
251
- await expect(decoder.flush()).rejects.toThrow();
252
- decoder.close();
253
- });
254
- });
255
- describe('decodeQueueSize', () => {
256
- it('should start at 0', () => {
257
- const decoder = new AudioDecoder({
258
- output: () => { },
259
- error: () => { },
260
- });
261
- expect(decoder.decodeQueueSize).toBe(0);
262
- decoder.close();
263
- });
264
- });
265
- });
266
- describe('AudioDecoder encode-decode roundtrip', () => {
267
- it('should decode Opus encoded audio', async () => {
268
- const sampleRate = 48000;
269
- const numberOfChannels = 2;
270
- const numberOfFrames = 960; // 20ms at 48kHz
271
- const chunkCount = 3;
272
- // Step 1: Encode audio
273
- const encodedChunks = [];
274
- const encoder = new AudioEncoder({
275
- output: (chunk) => encodedChunks.push(chunk),
276
- error: (err) => { throw err; },
277
- });
278
- encoder.configure({
279
- codec: 'opus',
280
- sampleRate,
281
- numberOfChannels,
282
- bitrate: 64000,
283
- });
284
- // Create and encode test audio (sine waves) - use interleaved f32 format
285
- for (let c = 0; c < chunkCount; c++) {
286
- const samples = new Float32Array(numberOfFrames * numberOfChannels);
287
- const frequency = 440 + c * 100; // Different frequency for each chunk
288
- for (let i = 0; i < numberOfFrames; i++) {
289
- const t = (c * numberOfFrames + i) / sampleRate;
290
- const value = Math.sin(2 * Math.PI * frequency * t);
291
- for (let ch = 0; ch < numberOfChannels; ch++) {
292
- samples[i * numberOfChannels + ch] = value;
293
- }
294
- }
295
- const audioData = new AudioData({
296
- format: 'f32', // Use interleaved format
297
- sampleRate,
298
- numberOfChannels,
299
- numberOfFrames,
300
- timestamp: c * (numberOfFrames * 1_000_000 / sampleRate),
301
- data: samples,
302
- });
303
- encoder.encode(audioData);
304
- audioData.close();
305
- }
306
- await encoder.flush();
307
- encoder.close();
308
- expect(encodedChunks.length).toBeGreaterThan(0);
309
- // Step 2: Decode audio
310
- const decodedAudio = [];
311
- const decoder = new AudioDecoder({
312
- output: (audio) => decodedAudio.push(audio),
313
- error: (err) => { throw err; },
314
- });
315
- decoder.configure({
316
- codec: 'opus',
317
- sampleRate,
318
- numberOfChannels,
319
- });
320
- for (const chunk of encodedChunks) {
321
- decoder.decode(chunk);
322
- }
323
- await decoder.flush();
324
- decoder.close();
325
- // Verify decoded audio
326
- expect(decodedAudio.length).toBeGreaterThan(0);
327
- let totalFrames = 0;
328
- for (const audio of decodedAudio) {
329
- expect(audio.sampleRate).toBe(sampleRate);
330
- expect(audio.numberOfChannels).toBe(numberOfChannels);
331
- totalFrames += audio.numberOfFrames;
332
- audio.close();
333
- }
334
- // Total decoded frames should be close to original
335
- const expectedFrames = numberOfFrames * chunkCount;
336
- expect(totalFrames).toBeGreaterThanOrEqual(expectedFrames * 0.9);
337
- }, 30000);
338
- it('should decode FLAC encoded audio', async () => {
339
- const sampleRate = 48000;
340
- const numberOfChannels = 2;
341
- const numberOfFrames = 4608; // FLAC minimum frame size
342
- const chunkCount = 2;
343
- // Step 1: Encode audio
344
- const encodedChunks = [];
345
- const encoder = new AudioEncoder({
346
- output: (chunk) => encodedChunks.push(chunk),
347
- error: (err) => { throw err; },
348
- });
349
- encoder.configure({
350
- codec: 'flac',
351
- sampleRate,
352
- numberOfChannels,
353
- });
354
- for (let c = 0; c < chunkCount; c++) {
355
- const samples = new Float32Array(numberOfFrames * numberOfChannels);
356
- for (let i = 0; i < numberOfFrames; i++) {
357
- const t = (c * numberOfFrames + i) / sampleRate;
358
- const value = Math.sin(2 * Math.PI * 880 * t) * 0.5;
359
- for (let ch = 0; ch < numberOfChannels; ch++) {
360
- samples[i * numberOfChannels + ch] = value;
361
- }
362
- }
363
- const audioData = new AudioData({
364
- format: 'f32', // Use interleaved format
365
- sampleRate,
366
- numberOfChannels,
367
- numberOfFrames,
368
- timestamp: c * (numberOfFrames * 1_000_000 / sampleRate),
369
- data: samples,
370
- });
371
- encoder.encode(audioData);
372
- audioData.close();
373
- }
374
- await encoder.flush();
375
- encoder.close();
376
- expect(encodedChunks.length).toBeGreaterThan(0);
377
- // Step 2: Decode audio
378
- const decodedAudio = [];
379
- const decoder = new AudioDecoder({
380
- output: (audio) => decodedAudio.push(audio),
381
- error: (err) => { throw err; },
382
- });
383
- decoder.configure({
384
- codec: 'flac',
385
- sampleRate,
386
- numberOfChannels,
387
- });
388
- for (const chunk of encodedChunks) {
389
- decoder.decode(chunk);
390
- }
391
- await decoder.flush();
392
- decoder.close();
393
- // Verify decoded audio
394
- expect(decodedAudio.length).toBeGreaterThan(0);
395
- for (const audio of decodedAudio) {
396
- expect(audio.sampleRate).toBe(sampleRate);
397
- expect(audio.numberOfChannels).toBe(numberOfChannels);
398
- audio.close();
399
- }
400
- }, 30000);
401
- it('should handle mono audio', async () => {
402
- const sampleRate = 48000; // libopus only supports specific rates: 48000, 24000, 16000, 12000, 8000
403
- const numberOfChannels = 1;
404
- const numberOfFrames = 960; // Opus frame size
405
- // Encode
406
- const encodedChunks = [];
407
- const encoder = new AudioEncoder({
408
- output: (chunk) => encodedChunks.push(chunk),
409
- error: (err) => { throw err; },
410
- });
411
- encoder.configure({
412
- codec: 'opus',
413
- sampleRate,
414
- numberOfChannels,
415
- bitrate: 32000,
416
- });
417
- const samples = new Float32Array(numberOfFrames);
418
- for (let i = 0; i < numberOfFrames; i++) {
419
- samples[i] = Math.sin(2 * Math.PI * 440 * i / sampleRate);
420
- }
421
- const audioData = new AudioData({
422
- format: 'f32', // Use interleaved format (same as planar for mono)
423
- sampleRate,
424
- numberOfChannels,
425
- numberOfFrames,
426
- timestamp: 0,
427
- data: samples,
428
- });
429
- encoder.encode(audioData);
430
- audioData.close();
431
- await encoder.flush();
432
- encoder.close();
433
- expect(encodedChunks.length).toBeGreaterThan(0);
434
- // Decode
435
- const decodedAudio = [];
436
- const decoder = new AudioDecoder({
437
- output: (audio) => decodedAudio.push(audio),
438
- error: (err) => { throw err; },
439
- });
440
- decoder.configure({
441
- codec: 'opus',
442
- sampleRate,
443
- numberOfChannels,
444
- });
445
- for (const chunk of encodedChunks) {
446
- decoder.decode(chunk);
447
- }
448
- await decoder.flush();
449
- decoder.close();
450
- expect(decodedAudio.length).toBeGreaterThan(0);
451
- for (const audio of decodedAudio) {
452
- expect(audio.numberOfChannels).toBe(numberOfChannels);
453
- audio.close();
454
- }
455
- }, 30000);
456
- });
457
- describe('AudioDecoder output formats', () => {
458
- // Helper to encode test audio for format tests
459
- async function encodeTestAudio() {
460
- const sampleRate = 48000;
461
- const numberOfChannels = 2;
462
- const numberOfFrames = 960;
463
- const encodedChunks = [];
464
- const encoder = new AudioEncoder({
465
- output: (chunk) => encodedChunks.push(chunk),
466
- error: (err) => { throw err; },
467
- });
468
- encoder.configure({
469
- codec: 'opus',
470
- sampleRate,
471
- numberOfChannels,
472
- bitrate: 64000,
473
- });
474
- // Create test audio - interleaved f32
475
- const samples = new Float32Array(numberOfFrames * numberOfChannels);
476
- for (let i = 0; i < numberOfFrames; i++) {
477
- const value = Math.sin(2 * Math.PI * 440 * i / sampleRate);
478
- samples[i * numberOfChannels] = value;
479
- samples[i * numberOfChannels + 1] = value;
480
- }
481
- const audioData = new AudioData({
482
- format: 'f32',
483
- sampleRate,
484
- numberOfChannels,
485
- numberOfFrames,
486
- timestamp: 0,
487
- data: samples,
488
- });
489
- encoder.encode(audioData);
490
- audioData.close();
491
- await encoder.flush();
492
- encoder.close();
493
- return encodedChunks;
494
- }
495
- it('should decode to s16 format', async () => {
496
- const encodedChunks = await encodeTestAudio();
497
- expect(encodedChunks.length).toBeGreaterThan(0);
498
- const decodedAudio = [];
499
- const decoder = new AudioDecoder({
500
- output: (audio) => decodedAudio.push(audio),
501
- error: (err) => { throw err; },
502
- });
503
- decoder.configure({
504
- codec: 'opus',
505
- sampleRate: 48000,
506
- numberOfChannels: 2,
507
- outputFormat: 's16',
508
- });
509
- for (const chunk of encodedChunks) {
510
- decoder.decode(chunk);
511
- }
512
- await decoder.flush();
513
- decoder.close();
514
- expect(decodedAudio.length).toBeGreaterThan(0);
515
- for (const audio of decodedAudio) {
516
- expect(audio.format).toBe('s16');
517
- expect(audio.numberOfChannels).toBe(2);
518
- audio.close();
519
- }
520
- }, 30000);
521
- it('should decode to s32 format', async () => {
522
- const encodedChunks = await encodeTestAudio();
523
- expect(encodedChunks.length).toBeGreaterThan(0);
524
- const decodedAudio = [];
525
- const decoder = new AudioDecoder({
526
- output: (audio) => decodedAudio.push(audio),
527
- error: (err) => { throw err; },
528
- });
529
- decoder.configure({
530
- codec: 'opus',
531
- sampleRate: 48000,
532
- numberOfChannels: 2,
533
- outputFormat: 's32',
534
- });
535
- for (const chunk of encodedChunks) {
536
- decoder.decode(chunk);
537
- }
538
- await decoder.flush();
539
- decoder.close();
540
- expect(decodedAudio.length).toBeGreaterThan(0);
541
- for (const audio of decodedAudio) {
542
- expect(audio.format).toBe('s32');
543
- audio.close();
544
- }
545
- }, 30000);
546
- it('should decode to u8 format', async () => {
547
- const encodedChunks = await encodeTestAudio();
548
- expect(encodedChunks.length).toBeGreaterThan(0);
549
- const decodedAudio = [];
550
- const decoder = new AudioDecoder({
551
- output: (audio) => decodedAudio.push(audio),
552
- error: (err) => { throw err; },
553
- });
554
- decoder.configure({
555
- codec: 'opus',
556
- sampleRate: 48000,
557
- numberOfChannels: 2,
558
- outputFormat: 'u8',
559
- });
560
- for (const chunk of encodedChunks) {
561
- decoder.decode(chunk);
562
- }
563
- await decoder.flush();
564
- decoder.close();
565
- expect(decodedAudio.length).toBeGreaterThan(0);
566
- for (const audio of decodedAudio) {
567
- expect(audio.format).toBe('u8');
568
- audio.close();
569
- }
570
- }, 30000);
571
- it('should decode to f32-planar format', async () => {
572
- const encodedChunks = await encodeTestAudio();
573
- expect(encodedChunks.length).toBeGreaterThan(0);
574
- const decodedAudio = [];
575
- const decoder = new AudioDecoder({
576
- output: (audio) => decodedAudio.push(audio),
577
- error: (err) => { throw err; },
578
- });
579
- decoder.configure({
580
- codec: 'opus',
581
- sampleRate: 48000,
582
- numberOfChannels: 2,
583
- outputFormat: 'f32-planar',
584
- });
585
- for (const chunk of encodedChunks) {
586
- decoder.decode(chunk);
587
- }
588
- await decoder.flush();
589
- decoder.close();
590
- expect(decodedAudio.length).toBeGreaterThan(0);
591
- for (const audio of decodedAudio) {
592
- expect(audio.format).toBe('f32-planar');
593
- expect(audio.numberOfChannels).toBe(2);
594
- audio.close();
595
- }
596
- }, 30000);
597
- it('should decode to s16-planar format', async () => {
598
- const encodedChunks = await encodeTestAudio();
599
- expect(encodedChunks.length).toBeGreaterThan(0);
600
- const decodedAudio = [];
601
- const decoder = new AudioDecoder({
602
- output: (audio) => decodedAudio.push(audio),
603
- error: (err) => { throw err; },
604
- });
605
- decoder.configure({
606
- codec: 'opus',
607
- sampleRate: 48000,
608
- numberOfChannels: 2,
609
- outputFormat: 's16-planar',
610
- });
611
- for (const chunk of encodedChunks) {
612
- decoder.decode(chunk);
613
- }
614
- await decoder.flush();
615
- decoder.close();
616
- expect(decodedAudio.length).toBeGreaterThan(0);
617
- for (const audio of decodedAudio) {
618
- expect(audio.format).toBe('s16-planar');
619
- audio.close();
620
- }
621
- }, 30000);
622
- });
623
- describe('AudioEncoder input formats', () => {
624
- it('should encode from s16 format', async () => {
625
- const sampleRate = 48000;
626
- const numberOfChannels = 2;
627
- const numberOfFrames = 960;
628
- const encodedChunks = [];
629
- const encoder = new AudioEncoder({
630
- output: (chunk) => encodedChunks.push(chunk),
631
- error: (err) => { throw err; },
632
- });
633
- encoder.configure({
634
- codec: 'opus',
635
- sampleRate,
636
- numberOfChannels,
637
- bitrate: 64000,
638
- });
639
- // Create s16 interleaved samples
640
- const samples = new Int16Array(numberOfFrames * numberOfChannels);
641
- for (let i = 0; i < numberOfFrames; i++) {
642
- const value = Math.round(Math.sin(2 * Math.PI * 440 * i / sampleRate) * 32767);
643
- samples[i * numberOfChannels] = value;
644
- samples[i * numberOfChannels + 1] = value;
645
- }
646
- const audioData = new AudioData({
647
- format: 's16',
648
- sampleRate,
649
- numberOfChannels,
650
- numberOfFrames,
651
- timestamp: 0,
652
- data: new Uint8Array(samples.buffer),
653
- });
654
- encoder.encode(audioData);
655
- audioData.close();
656
- await encoder.flush();
657
- encoder.close();
658
- expect(encodedChunks.length).toBeGreaterThan(0);
659
- }, 30000);
660
- it('should encode from f32-planar format', async () => {
661
- const sampleRate = 48000;
662
- const numberOfChannels = 2;
663
- const numberOfFrames = 960;
664
- const encodedChunks = [];
665
- const encoder = new AudioEncoder({
666
- output: (chunk) => encodedChunks.push(chunk),
667
- error: (err) => { throw err; },
668
- });
669
- encoder.configure({
670
- codec: 'opus',
671
- sampleRate,
672
- numberOfChannels,
673
- bitrate: 64000,
674
- });
675
- // Create f32-planar samples (channel 0 followed by channel 1)
676
- const samples = new Float32Array(numberOfFrames * numberOfChannels);
677
- for (let i = 0; i < numberOfFrames; i++) {
678
- const value = Math.sin(2 * Math.PI * 440 * i / sampleRate);
679
- samples[i] = value; // Channel 0
680
- samples[numberOfFrames + i] = value; // Channel 1
681
- }
682
- const audioData = new AudioData({
683
- format: 'f32-planar',
684
- sampleRate,
685
- numberOfChannels,
686
- numberOfFrames,
687
- timestamp: 0,
688
- data: new Uint8Array(samples.buffer),
689
- });
690
- encoder.encode(audioData);
691
- audioData.close();
692
- await encoder.flush();
693
- encoder.close();
694
- expect(encodedChunks.length).toBeGreaterThan(0);
695
- }, 30000);
696
- it('should encode from s16-planar format', async () => {
697
- const sampleRate = 48000;
698
- const numberOfChannels = 2;
699
- const numberOfFrames = 960;
700
- const encodedChunks = [];
701
- const encoder = new AudioEncoder({
702
- output: (chunk) => encodedChunks.push(chunk),
703
- error: (err) => { throw err; },
704
- });
705
- encoder.configure({
706
- codec: 'opus',
707
- sampleRate,
708
- numberOfChannels,
709
- bitrate: 64000,
710
- });
711
- // Create s16-planar samples
712
- const samples = new Int16Array(numberOfFrames * numberOfChannels);
713
- for (let i = 0; i < numberOfFrames; i++) {
714
- const value = Math.round(Math.sin(2 * Math.PI * 440 * i / sampleRate) * 32767);
715
- samples[i] = value; // Channel 0
716
- samples[numberOfFrames + i] = value; // Channel 1
717
- }
718
- const audioData = new AudioData({
719
- format: 's16-planar',
720
- sampleRate,
721
- numberOfChannels,
722
- numberOfFrames,
723
- timestamp: 0,
724
- data: new Uint8Array(samples.buffer),
725
- });
726
- encoder.encode(audioData);
727
- audioData.close();
728
- await encoder.flush();
729
- encoder.close();
730
- expect(encodedChunks.length).toBeGreaterThan(0);
731
- }, 30000);
732
- });
733
- //# sourceMappingURL=AudioDecoder.test.js.map