@siteed/audio-studio 3.2.0-beta.1 → 3.2.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.
- package/CHANGELOG.md +356 -5
- package/android/src/main/java/net/siteed/audiostudio/AudioStreamDecoder.kt +306 -94
- package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +39 -6
- package/build/cjs/errors/AudioStreamError.js +9 -0
- package/build/cjs/errors/AudioStreamError.js.map +1 -1
- package/build/cjs/errors/AudioStreamError.test.js +22 -1
- package/build/cjs/errors/AudioStreamError.test.js.map +1 -1
- package/build/cjs/streamAudioData.js +99 -32
- package/build/cjs/streamAudioData.js.map +1 -1
- package/build/cjs/utils/audioProcessing.js +14 -10
- package/build/cjs/utils/audioProcessing.js.map +1 -1
- package/build/esm/errors/AudioStreamError.js +9 -0
- package/build/esm/errors/AudioStreamError.js.map +1 -1
- package/build/esm/errors/AudioStreamError.test.js +22 -1
- package/build/esm/errors/AudioStreamError.test.js.map +1 -1
- package/build/esm/streamAudioData.js +99 -32
- package/build/esm/streamAudioData.js.map +1 -1
- package/build/esm/utils/audioProcessing.js +14 -10
- package/build/esm/utils/audioProcessing.js.map +1 -1
- package/build/types/errors/AudioStreamError.d.ts.map +1 -1
- package/build/types/streamAudioData.d.ts +5 -0
- package/build/types/streamAudioData.d.ts.map +1 -1
- package/build/types/utils/audioProcessing.d.ts +2 -2
- package/build/types/utils/audioProcessing.d.ts.map +1 -1
- package/ios/AudioStreamDecoder.swift +191 -100
- package/ios/AudioStudioModule.swift +48 -9
- package/package.json +163 -146
- package/scripts/README.md +58 -0
- package/src/errors/AudioStreamError.test.ts +29 -2
- package/src/errors/AudioStreamError.ts +14 -0
- package/src/streamAudioData.ts +146 -42
- package/src/utils/audioProcessing.ts +25 -14
- package/android/src/androidTest/assets/chorus.wav +0 -0
- package/android/src/androidTest/assets/jfk.wav +0 -0
- package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
- package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioFinalMetadataContractInstrumentedTest.kt +0 -190
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioProcessorInstrumentedTest.kt +0 -197
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderInstrumentedTest.kt +0 -487
- package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderPerformanceInstrumentedTest.kt +0 -250
- package/android/src/androidTest/java/net/siteed/audiostudio/OpusRangeDecodeRegressionInstrumentedTest.kt +0 -186
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/AudioFocusStrategyIntegrationTest.kt +0 -332
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/BufferDurationIntegrationTest.kt +0 -324
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/CompressedOnlyOutputTest.kt +0 -253
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/DeviceDisconnectionFallbackTest.kt +0 -218
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/EventEmissionIntervalTest.kt +0 -120
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/M4aFormatTest.kt +0 -345
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/OutputControlIntegrationTest.kt +0 -340
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/PcmStreamingDurationTest.kt +0 -252
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/README.md +0 -95
- package/android/src/androidTest/java/net/siteed/audiostudio/integration/run_integration_tests.sh +0 -43
- package/android/src/test/java/net/siteed/audiostudio/AndroidCallStateTest.kt +0 -37
- package/android/src/test/java/net/siteed/audiostudio/AndroidEventEmitterTest.kt +0 -28
- package/android/src/test/java/net/siteed/audiostudio/AudioFileHandlerTest.kt +0 -279
- package/android/src/test/java/net/siteed/audiostudio/AudioFocusStrategyTest.kt +0 -249
- package/android/src/test/java/net/siteed/audiostudio/AudioFormatTest.kt +0 -151
- package/android/src/test/java/net/siteed/audiostudio/AudioFormatUtilsTest.kt +0 -273
- package/android/src/test/java/net/siteed/audiostudio/DeviceDisconnectionFallbackUnitTest.kt +0 -140
- package/android/src/test/java/net/siteed/audiostudio/InterruptionAutoResumePolicyTest.kt +0 -49
- package/android/src/test/resources/chorus.wav +0 -0
- package/android/src/test/resources/generate_test_audio.py +0 -94
- package/android/src/test/resources/jfk.wav +0 -0
- package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
- package/android/src/test/resources/recorder_hello_world.wav +0 -0
- package/ios/AudioStudioTests/AudioFileHandlerTests.swift +0 -338
- package/ios/AudioStudioTests/AudioFormatUtilsTests.swift +0 -331
- package/ios/AudioStudioTests/AudioStreamDecoderTests.swift +0 -128
- package/ios/AudioStudioTests/AudioTestHelpers.swift +0 -130
- package/ios/AudioStudioTests/CompressedOnlyOutputTests.swift +0 -334
- package/ios/AudioStudioTests/EventEmissionIntervalTests.swift +0 -105
- package/ios/AudioStudioTests/Info.plist +0 -22
- package/ios/AudioStudioTests/README.md +0 -39
- package/ios/AudioStudioTests/SimpleAudioTest.swift +0 -98
- package/ios/AudioStudioTests/TestAudioGenerator.swift +0 -75
- package/ios/tests/README.md +0 -41
- package/ios/tests/integration/buffer_and_fallback_test.swift +0 -178
- package/ios/tests/integration/buffer_duration_test.swift +0 -185
- package/ios/tests/integration/compressed_only_output_test.swift +0 -271
- package/ios/tests/integration/output_control_test.swift +0 -322
- package/ios/tests/integration/run_integration_tests.sh +0 -37
- package/ios/tests/opus_support_test_macos.swift +0 -154
- package/ios/tests/standalone/audio_processing_test.swift +0 -144
- package/ios/tests/standalone/audio_recording_test.swift +0 -277
- package/ios/tests/standalone/audio_streaming_test.swift +0 -249
- package/ios/tests/standalone/standalone_test.swift +0 -144
|
@@ -41,10 +41,12 @@ function toFloat32(samples) {
|
|
|
41
41
|
}
|
|
42
42
|
if (typeof samples === 'string') {
|
|
43
43
|
const bytes = base64ToBytes(samples);
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
const floatLength = Math.floor(bytes.byteLength / 4);
|
|
45
|
+
if (bytes.byteOffset % 4 === 0) {
|
|
46
|
+
return new Float32Array(bytes.buffer, bytes.byteOffset, floatLength);
|
|
47
|
+
}
|
|
48
|
+
const sliced = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
49
|
+
return new Float32Array(sliced, 0, Math.floor(sliced.byteLength / 4));
|
|
48
50
|
}
|
|
49
51
|
if (samples && typeof samples === 'object' && 'length' in samples) {
|
|
50
52
|
// ArrayLike fallback
|
|
@@ -73,31 +75,50 @@ function base64ToBytes(input) {
|
|
|
73
75
|
out[i] = bin.charCodeAt(i);
|
|
74
76
|
return out;
|
|
75
77
|
}
|
|
78
|
+
function rejectInvalidRange(message) {
|
|
79
|
+
throw new AudioStreamError({
|
|
80
|
+
code: 'ERR_AUDIO_STREAM_INVALID_RANGE',
|
|
81
|
+
message,
|
|
82
|
+
recoverable: false,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function assertPositiveFiniteOption(value, name, integer = false) {
|
|
86
|
+
if (value === undefined)
|
|
87
|
+
return;
|
|
88
|
+
if (!Number.isFinite(value) ||
|
|
89
|
+
value <= 0 ||
|
|
90
|
+
(integer && !Number.isInteger(value))) {
|
|
91
|
+
rejectInvalidRange(`${name} must be a positive${integer ? ' integer' : ''}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
76
94
|
function validateOptions(options) {
|
|
77
95
|
if (!options.fileUri) {
|
|
78
|
-
|
|
79
|
-
code: 'ERR_AUDIO_STREAM_INVALID_RANGE',
|
|
80
|
-
message: 'fileUri is required',
|
|
81
|
-
recoverable: false,
|
|
82
|
-
});
|
|
96
|
+
rejectInvalidRange('fileUri is required');
|
|
83
97
|
}
|
|
84
98
|
if (options.startTimeMs !== undefined &&
|
|
85
99
|
options.endTimeMs !== undefined &&
|
|
86
100
|
options.startTimeMs >= options.endTimeMs) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
rejectInvalidRange('startTimeMs must be < endTimeMs');
|
|
102
|
+
}
|
|
103
|
+
if (options.endTimeMs !== undefined && options.endTimeMs <= 0) {
|
|
104
|
+
rejectInvalidRange('endTimeMs must be > 0');
|
|
105
|
+
}
|
|
106
|
+
if (options.startTimeMs !== undefined && options.startTimeMs < 0) {
|
|
107
|
+
rejectInvalidRange('startTimeMs must be >= 0');
|
|
92
108
|
}
|
|
93
109
|
if (options.chunkDurationMs !== undefined &&
|
|
94
110
|
(options.chunkDurationMs < 10 || options.chunkDurationMs > 60000)) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
111
|
+
rejectInvalidRange('chunkDurationMs must be in [10, 60000]');
|
|
112
|
+
}
|
|
113
|
+
if (options.backpressureTimeoutMs !== undefined &&
|
|
114
|
+
options.backpressureTimeoutMs < 0) {
|
|
115
|
+
rejectInvalidRange('backpressureTimeoutMs must be >= 0');
|
|
100
116
|
}
|
|
117
|
+
assertPositiveFiniteOption(options.targetSampleRate, 'targetSampleRate');
|
|
118
|
+
assertPositiveFiniteOption(options.sampleRate, 'sampleRate');
|
|
119
|
+
assertPositiveFiniteOption(options.channels, 'channels', true);
|
|
120
|
+
assertPositiveFiniteOption(options.maxBufferedChunks, 'maxBufferedChunks', true);
|
|
121
|
+
assertPositiveFiniteOption(options.maxChunkBytes, 'maxChunkBytes', true);
|
|
101
122
|
if (options.streamFormat !== undefined &&
|
|
102
123
|
options.streamFormat !== 'float32') {
|
|
103
124
|
throw new AudioStreamError({
|
|
@@ -182,6 +203,7 @@ async function streamAudioDataNative(options, callbacks) {
|
|
|
182
203
|
let processingChain = Promise.resolve();
|
|
183
204
|
let settled = false;
|
|
184
205
|
let abortListener = null;
|
|
206
|
+
let lastProgress = null;
|
|
185
207
|
const finalize = () => {
|
|
186
208
|
for (const sub of subs) {
|
|
187
209
|
try {
|
|
@@ -256,6 +278,7 @@ async function streamAudioDataNative(options, callbacks) {
|
|
|
256
278
|
const evt = raw;
|
|
257
279
|
if (evt.requestId !== requestId)
|
|
258
280
|
return;
|
|
281
|
+
lastProgress = evt;
|
|
259
282
|
callbacks.onProgress(evt);
|
|
260
283
|
}));
|
|
261
284
|
}
|
|
@@ -268,7 +291,9 @@ async function streamAudioDataNative(options, callbacks) {
|
|
|
268
291
|
.then(() => {
|
|
269
292
|
settle(() => { }, 'resolve', {
|
|
270
293
|
requestId,
|
|
271
|
-
durationMs: evt.durationMs
|
|
294
|
+
durationMs: evt.durationMs > 0
|
|
295
|
+
? evt.durationMs
|
|
296
|
+
: (lastProgress?.durationMs ?? 0),
|
|
272
297
|
sampleRate: evt.sampleRate,
|
|
273
298
|
channels: evt.channels,
|
|
274
299
|
chunks: evt.chunks ?? chunkCount,
|
|
@@ -288,7 +313,7 @@ async function streamAudioDataNative(options, callbacks) {
|
|
|
288
313
|
.then(() => {
|
|
289
314
|
settle(() => { }, 'resolve', {
|
|
290
315
|
requestId,
|
|
291
|
-
durationMs: 0,
|
|
316
|
+
durationMs: lastProgress?.durationMs ?? 0,
|
|
292
317
|
sampleRate: options.targetSampleRate ??
|
|
293
318
|
options.sampleRate ??
|
|
294
319
|
0,
|
|
@@ -314,7 +339,7 @@ async function streamAudioDataNative(options, callbacks) {
|
|
|
314
339
|
if (options.signal.aborted) {
|
|
315
340
|
settle(() => { }, 'resolve', {
|
|
316
341
|
requestId,
|
|
317
|
-
durationMs: 0,
|
|
342
|
+
durationMs: lastProgress?.durationMs ?? 0,
|
|
318
343
|
sampleRate: options.targetSampleRate ?? options.sampleRate ?? 0,
|
|
319
344
|
channels: options.channels ?? 1,
|
|
320
345
|
chunks: 0,
|
|
@@ -361,8 +386,8 @@ async function streamAudioDataWeb(options, callbacks) {
|
|
|
361
386
|
try {
|
|
362
387
|
const processed = await processAudioBuffer({
|
|
363
388
|
fileUri: options.fileUri,
|
|
364
|
-
targetSampleRate: options.targetSampleRate
|
|
365
|
-
targetChannels: options.channels
|
|
389
|
+
targetSampleRate: options.targetSampleRate,
|
|
390
|
+
targetChannels: options.channels,
|
|
366
391
|
normalizeAudio: options.normalizeAudio ?? true,
|
|
367
392
|
startTimeMs: options.startTimeMs,
|
|
368
393
|
endTimeMs: options.endTimeMs,
|
|
@@ -371,12 +396,21 @@ async function streamAudioDataWeb(options, callbacks) {
|
|
|
371
396
|
const channels = processed.channels;
|
|
372
397
|
const durationMs = processed.durationMs;
|
|
373
398
|
const chunkDurationMs = options.chunkDurationMs ?? 1000;
|
|
374
|
-
let samplesPerChunk = Math.max(
|
|
399
|
+
let samplesPerChunk = Math.max(channels, Math.floor((chunkDurationMs / 1000) * sampleRate) * channels);
|
|
375
400
|
if (options.maxChunkBytes) {
|
|
376
|
-
|
|
377
|
-
|
|
401
|
+
// Round down to a multiple of `channels` so we never split an
|
|
402
|
+
// interleaved frame across two chunks (that would produce a
|
|
403
|
+
// fractional `startSample` for the next chunk).
|
|
404
|
+
const rawMax = Math.floor(options.maxChunkBytes / 4);
|
|
405
|
+
const maxSamples = Math.max(channels, Math.floor(rawMax / channels) * channels);
|
|
406
|
+
samplesPerChunk = Math.max(channels, Math.min(samplesPerChunk, maxSamples));
|
|
378
407
|
}
|
|
379
|
-
const all = sanitizeFloat32(processed.
|
|
408
|
+
const all = sanitizeFloat32(interleaveBuffer(processed.buffer, channels), options.normalizeAudio ?? true);
|
|
409
|
+
// Chunk timestamps are absolute (range start + offset) on every
|
|
410
|
+
// platform; progress is *elapsed within the range* so the
|
|
411
|
+
// `processedMs / durationMs` fraction stays in [0, 1] regardless of
|
|
412
|
+
// `startTimeMs`. The native decoders use the same split.
|
|
413
|
+
const rangeStartMs = options.startTimeMs ?? 0;
|
|
380
414
|
let chunkIndex = 0;
|
|
381
415
|
let emittedSamples = 0;
|
|
382
416
|
for (let off = 0; off < all.length; off += samplesPerChunk) {
|
|
@@ -395,11 +429,13 @@ async function streamAudioDataWeb(options, callbacks) {
|
|
|
395
429
|
const slice = all.slice(off, end);
|
|
396
430
|
const startSample = off / channels;
|
|
397
431
|
const endSample = end / channels;
|
|
432
|
+
const startMs = Math.round((startSample / sampleRate) * 1000) + rangeStartMs;
|
|
433
|
+
const endMs = Math.round((endSample / sampleRate) * 1000) + rangeStartMs;
|
|
398
434
|
const chunk = {
|
|
399
435
|
requestId,
|
|
400
436
|
chunkIndex,
|
|
401
|
-
startTimeMs:
|
|
402
|
-
endTimeMs:
|
|
437
|
+
startTimeMs: startMs,
|
|
438
|
+
endTimeMs: endMs,
|
|
403
439
|
durationMs: Math.round(((endSample - startSample) / sampleRate) * 1000),
|
|
404
440
|
startSample,
|
|
405
441
|
sampleCount: slice.length,
|
|
@@ -409,11 +445,22 @@ async function streamAudioDataWeb(options, callbacks) {
|
|
|
409
445
|
isFinal: end >= all.length,
|
|
410
446
|
};
|
|
411
447
|
await callbacks.onChunk(chunk);
|
|
448
|
+
// Resample rounding (Math.ceil in processAudioBuffer) can push
|
|
449
|
+
// elapsed past the source-rate-derived range duration on the tail
|
|
450
|
+
// chunk. Cap so onProgress consumers always see a [0, 1] ratio,
|
|
451
|
+
// matching the native `coerceIn(0, 1)` / `min(1, max(0, …))`
|
|
452
|
+
// clamp.
|
|
453
|
+
const rawElapsedMs = Math.round((endSample / sampleRate) * 1000);
|
|
454
|
+
const elapsedMs = durationMs > 0
|
|
455
|
+
? Math.min(rawElapsedMs, durationMs)
|
|
456
|
+
: rawElapsedMs;
|
|
412
457
|
callbacks.onProgress?.({
|
|
413
458
|
requestId,
|
|
414
|
-
processedMs:
|
|
459
|
+
processedMs: elapsedMs,
|
|
415
460
|
durationMs,
|
|
416
|
-
progress: durationMs > 0
|
|
461
|
+
progress: durationMs > 0
|
|
462
|
+
? Math.min(1, Math.max(0, elapsedMs / durationMs))
|
|
463
|
+
: 1,
|
|
417
464
|
emittedChunks: chunkIndex + 1,
|
|
418
465
|
});
|
|
419
466
|
chunkIndex += 1;
|
|
@@ -433,6 +480,26 @@ async function streamAudioDataWeb(options, callbacks) {
|
|
|
433
480
|
throw mapStreamError(err, options.fileUri, 'web');
|
|
434
481
|
}
|
|
435
482
|
}
|
|
483
|
+
function interleaveBuffer(buffer, channels) {
|
|
484
|
+
const numCh = Math.max(1, Math.min(channels, buffer.numberOfChannels));
|
|
485
|
+
const framesPerCh = buffer.length;
|
|
486
|
+
if (numCh === 1) {
|
|
487
|
+
// Cheap path: clone channel 0 so downstream mutation doesn't touch the
|
|
488
|
+
// underlying AudioBuffer storage.
|
|
489
|
+
return new Float32Array(buffer.getChannelData(0));
|
|
490
|
+
}
|
|
491
|
+
const out = new Float32Array(framesPerCh * numCh);
|
|
492
|
+
const channelData = [];
|
|
493
|
+
for (let c = 0; c < numCh; c++) {
|
|
494
|
+
channelData.push(buffer.getChannelData(c));
|
|
495
|
+
}
|
|
496
|
+
for (let f = 0; f < framesPerCh; f++) {
|
|
497
|
+
for (let c = 0; c < numCh; c++) {
|
|
498
|
+
out[f * numCh + c] = channelData[c][f];
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return out;
|
|
502
|
+
}
|
|
436
503
|
function sanitizeFloat32(input, clamp) {
|
|
437
504
|
if (!clamp) {
|
|
438
505
|
// still need NaN/Inf sanitation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamAudioData.js","sourceRoot":"","sources":["../../src/streamAudioData.ts"],"names":[],"mappings":"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","sourcesContent":["import { LegacyEventEmitter, type EventSubscription } from 'expo-modules-core'\n\nimport AudioStudioModule from './AudioStudioModule'\nimport { isWeb } from './constants'\nimport {\n AudioStreamError,\n AudioStreamErrorCode,\n mapStreamError,\n} from './errors/AudioStreamError'\nimport { processAudioBuffer } from './utils/audioProcessing'\n\n/**\n * High-level API: stream decoded audio from a stored file as bounded Float32\n * chunks without materializing the full PCM range in memory.\n *\n * See `docs/STREAM_AUDIO_DATA.md` for the full contract and rollout notes.\n */\nexport interface StreamAudioDataOptions {\n /** URI of the audio file to decode. */\n fileUri: string\n /** Start time in milliseconds (default: 0). */\n startTimeMs?: number\n /** End time in milliseconds (default: end-of-file). */\n endTimeMs?: number\n /**\n * Source sample rate hint. Ignored if `targetSampleRate` is set; native\n * decoders read the actual rate from the file.\n */\n sampleRate?: number\n /** Output sample rate. Native resamples when this differs from the file. */\n targetSampleRate?: number\n /** Output channel count (1 = mono downmix, 2 = stereo passthrough). */\n channels?: number\n /** Clamp samples to [-1, 1] and replace non-finite values with 0. */\n normalizeAudio?: boolean\n /** Target chunk duration in ms (default: 1000, min: 10, max: 60000). */\n chunkDurationMs?: number\n /** Soft cap on chunk size in bytes (Float32 = 4 bytes/sample). */\n maxChunkBytes?: number\n /** Max chunks queued in native before JS ack pauses decode (default: 4). */\n maxBufferedChunks?: number\n /** Output PCM format; only `'float32'` supported today. */\n streamFormat?: 'float32'\n /** Abort the in-flight request. Resolves promise with `cancelled: true`. */\n signal?: AbortSignal\n}\n\nexport interface StreamAudioDataChunk {\n /** Native request id; constant across all chunks of one call. */\n requestId: string\n /** Zero-based monotonic chunk index. */\n chunkIndex: number\n /** Start time in output-rate ms (rounded to nearest sample). */\n startTimeMs: number\n /** End time in output-rate ms. */\n endTimeMs: number\n /** Duration in ms (`endTimeMs - startTimeMs`). */\n durationMs: number\n /** First sample index in the output timeline. */\n startSample: number\n /** Sample count in `samples` (interleaved if channels > 1). */\n sampleCount: number\n /** Output sample rate. */\n sampleRate: number\n /** Output channel count. */\n channels: number\n /** Interleaved Float32 samples in [-1, 1]. */\n samples: Float32Array\n /** True for the last chunk of a non-cancelled run. */\n isFinal: boolean\n}\n\nexport interface StreamAudioDataProgress {\n requestId: string\n processedMs: number\n durationMs: number\n progress: number\n emittedChunks: number\n bufferedChunks?: number\n}\n\nexport interface StreamAudioDataResult {\n requestId: string\n durationMs: number\n sampleRate: number\n channels: number\n chunks: number\n samples: number\n cancelled: boolean\n}\n\nexport interface StreamAudioDataCallbacks {\n /**\n * Called with each decoded chunk. If this returns a Promise, native decode\n * pauses until it resolves (backpressure). Throwing aborts the stream with\n * `ERR_AUDIO_STREAM_DECODE_FAILED`.\n */\n onChunk: (chunk: StreamAudioDataChunk) => void | Promise<void>\n /** Called whenever native reports progress. */\n onProgress?: (progress: StreamAudioDataProgress) => void\n}\n\nexport interface AudioDecodeCapabilities {\n platform: 'ios' | 'android' | 'web'\n supportedInputFormats: string[]\n supportedOutputFormats: Array<'float32'>\n supportsCancellation: boolean\n supportsBackpressure: boolean\n supportsTimeRange: boolean\n supportsTargetSampleRate: boolean\n supportsChannelMixing: boolean\n knownLimitations?: string[]\n}\n\nconst CHUNK_EVENT = 'AudioDataStreamChunk'\nconst PROGRESS_EVENT = 'AudioDataStreamProgress'\nconst COMPLETE_EVENT = 'AudioDataStreamComplete'\nconst ERROR_EVENT = 'AudioDataStreamError'\n\nlet cachedEmitter: LegacyEventEmitter | null = null\nfunction getEmitter(): LegacyEventEmitter {\n if (!cachedEmitter) {\n cachedEmitter = new LegacyEventEmitter(AudioStudioModule)\n }\n return cachedEmitter\n}\n\nfunction generateRequestId(): string {\n const g = globalThis as { crypto?: { randomUUID?: () => string } }\n if (typeof g.crypto?.randomUUID === 'function') {\n try {\n return g.crypto.randomUUID()\n } catch {\n // fall through\n }\n }\n return `asd_${Date.now().toString(36)}_${Math.random()\n .toString(36)\n .slice(2, 10)}`\n}\n\nfunction toFloat32(samples: unknown): Float32Array {\n if (samples instanceof Float32Array) return samples\n if (Array.isArray(samples)) {\n const out = new Float32Array(samples.length)\n for (let i = 0; i < samples.length; i++) {\n const v = Number(samples[i])\n out[i] = Number.isFinite(v) ? v : 0\n }\n return out\n }\n if (typeof samples === 'string') {\n const bytes = base64ToBytes(samples)\n const aligned =\n bytes.byteOffset % 4 === 0\n ? new Float32Array(\n bytes.buffer,\n bytes.byteOffset,\n bytes.byteLength / 4\n )\n : new Float32Array(bytes.buffer.slice(bytes.byteOffset))\n return new Float32Array(aligned)\n }\n if (samples && typeof samples === 'object' && 'length' in samples) {\n // ArrayLike fallback\n const arr = samples as ArrayLike<number>\n const out = new Float32Array(arr.length)\n for (let i = 0; i < arr.length; i++) {\n const v = Number(arr[i])\n out[i] = Number.isFinite(v) ? v : 0\n }\n return out\n }\n return new Float32Array(0)\n}\n\nfunction base64ToBytes(input: string): Uint8Array {\n const g = globalThis as { atob?: (s: string) => string }\n if (typeof g.atob !== 'function') {\n // Buffer path for environments without atob; React Native has atob.\n const Buf = (globalThis as { Buffer?: { from: Function } }).Buffer\n if (Buf) return new Uint8Array(Buf.from(input, 'base64'))\n return new Uint8Array(0)\n }\n const bin = g.atob(input)\n const out = new Uint8Array(bin.length)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nfunction validateOptions(options: StreamAudioDataOptions): void {\n if (!options.fileUri) {\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_INVALID_RANGE',\n message: 'fileUri is required',\n recoverable: false,\n })\n }\n if (\n options.startTimeMs !== undefined &&\n options.endTimeMs !== undefined &&\n options.startTimeMs >= options.endTimeMs\n ) {\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_INVALID_RANGE',\n message: 'startTimeMs must be < endTimeMs',\n recoverable: false,\n })\n }\n if (\n options.chunkDurationMs !== undefined &&\n (options.chunkDurationMs < 10 || options.chunkDurationMs > 60000)\n ) {\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_INVALID_RANGE',\n message: 'chunkDurationMs must be in [10, 60000]',\n recoverable: false,\n })\n }\n if (\n options.streamFormat !== undefined &&\n options.streamFormat !== 'float32'\n ) {\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_UNSUPPORTED_FORMAT',\n message: `Unsupported streamFormat: ${options.streamFormat}`,\n recoverable: false,\n })\n }\n}\n\n/**\n * Stream decoded audio from a stored file as bounded Float32 PCM chunks.\n *\n * Memory bound:\n * `chunkDurationMs * sampleRate * channels * 4 * maxBufferedChunks` +\n * native decoder buffers.\n *\n * Cancellation: pass `options.signal` and call `abort()`. The returned promise\n * resolves with `cancelled: true` (it does not reject) when cancellation wins.\n *\n * Backpressure: if `onChunk` returns a Promise, native decode is paused until\n * it resolves; if it throws, the stream is aborted with a `decode_failed` error.\n */\nexport async function streamAudioData(\n options: StreamAudioDataOptions,\n callbacks: StreamAudioDataCallbacks\n): Promise<StreamAudioDataResult> {\n validateOptions(options)\n\n if (isWeb) {\n return streamAudioDataWeb(options, callbacks)\n }\n\n return streamAudioDataNative(options, callbacks)\n}\n\n/** Discover what the running platform supports. */\nexport async function getAudioDecodeCapabilities(): Promise<AudioDecodeCapabilities> {\n if (isWeb) {\n return {\n platform: 'web',\n supportedInputFormats: [\n 'audio/wav',\n 'audio/mpeg',\n 'audio/mp4',\n 'audio/aac',\n 'audio/ogg',\n 'audio/webm',\n ],\n supportedOutputFormats: ['float32'],\n supportsCancellation: true,\n supportsBackpressure: true,\n supportsTimeRange: true,\n supportsTargetSampleRate: true,\n supportsChannelMixing: true,\n knownLimitations: [\n 'Web decodes the entire file via AudioContext.decodeAudioData before chunking; very long files may exceed browser memory.',\n ],\n }\n }\n if (typeof AudioStudioModule.getAudioDecodeCapabilities === 'function') {\n try {\n const caps = await AudioStudioModule.getAudioDecodeCapabilities()\n return caps as AudioDecodeCapabilities\n } catch (err) {\n throw mapStreamError(err, undefined, 'native')\n }\n }\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_NATIVE_UNAVAILABLE',\n message: 'getAudioDecodeCapabilities is not available on this build',\n recoverable: false,\n })\n}\n\nasync function streamAudioDataNative(\n options: StreamAudioDataOptions,\n callbacks: StreamAudioDataCallbacks\n): Promise<StreamAudioDataResult> {\n if (typeof AudioStudioModule.streamAudioData !== 'function') {\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_NATIVE_UNAVAILABLE',\n message:\n 'streamAudioData native method missing — rebuild the host app with the latest @siteed/audio-studio.',\n recoverable: false,\n })\n }\n\n const requestId = generateRequestId()\n const emitter = getEmitter()\n const subs: EventSubscription[] = []\n let chunkCount = 0\n let sampleCount = 0\n let processingChain: Promise<void> = Promise.resolve()\n let settled = false\n let abortListener: (() => void) | null = null\n\n const finalize = () => {\n for (const sub of subs) {\n try {\n sub.remove()\n } catch {\n /* noop */\n }\n }\n subs.length = 0\n if (abortListener && options.signal) {\n options.signal.removeEventListener('abort', abortListener)\n }\n }\n\n return new Promise<StreamAudioDataResult>((resolve, reject) => {\n const settle = (\n fn: () => void,\n mode: 'resolve' | 'reject',\n value: unknown\n ) => {\n if (settled) return\n settled = true\n finalize()\n fn()\n if (mode === 'resolve') {\n resolve(value as StreamAudioDataResult)\n } else {\n reject(value as Error)\n }\n }\n\n const handleError = (err: unknown) => {\n settle(\n () => {\n try {\n AudioStudioModule.cancelStreamAudioData?.(requestId)\n } catch {\n /* noop */\n }\n },\n 'reject',\n mapStreamError(err, options.fileUri, 'native')\n )\n }\n\n subs.push(\n emitter.addListener(CHUNK_EVENT, (raw: unknown) => {\n const evt = raw as {\n requestId: string\n chunkIndex: number\n startTimeMs: number\n endTimeMs: number\n startSample: number\n sampleCount: number\n sampleRate: number\n channels: number\n samples: Float32Array | number[] | string\n isFinal: boolean\n }\n if (evt.requestId !== requestId) return\n const chunk: StreamAudioDataChunk = {\n requestId: evt.requestId,\n chunkIndex: evt.chunkIndex,\n startTimeMs: evt.startTimeMs,\n endTimeMs: evt.endTimeMs,\n durationMs: evt.endTimeMs - evt.startTimeMs,\n startSample: evt.startSample,\n sampleCount: evt.sampleCount,\n sampleRate: evt.sampleRate,\n channels: evt.channels,\n samples: toFloat32(evt.samples),\n isFinal: evt.isFinal,\n }\n chunkCount += 1\n sampleCount += chunk.sampleCount\n\n processingChain = processingChain\n .then(async () => {\n await callbacks.onChunk(chunk)\n try {\n AudioStudioModule.acknowledgeStreamAudioChunk?.(\n requestId,\n chunk.chunkIndex\n )\n } catch {\n /* noop */\n }\n })\n .catch(handleError)\n })\n )\n\n if (callbacks.onProgress) {\n subs.push(\n emitter.addListener(PROGRESS_EVENT, (raw: unknown) => {\n const evt = raw as StreamAudioDataProgress\n if (evt.requestId !== requestId) return\n callbacks.onProgress!(evt)\n })\n )\n }\n\n subs.push(\n emitter.addListener(COMPLETE_EVENT, (raw: unknown) => {\n const evt = raw as {\n requestId: string\n durationMs: number\n sampleRate: number\n channels: number\n chunks?: number\n samples?: number\n cancelled: boolean\n }\n if (evt.requestId !== requestId) return\n // Wait for in-flight onChunk callbacks before resolving.\n processingChain\n .then(() => {\n settle(() => {}, 'resolve', {\n requestId,\n durationMs: evt.durationMs,\n sampleRate: evt.sampleRate,\n channels: evt.channels,\n chunks: evt.chunks ?? chunkCount,\n samples: evt.samples ?? sampleCount,\n cancelled: evt.cancelled,\n } satisfies StreamAudioDataResult)\n })\n .catch(handleError)\n })\n )\n\n subs.push(\n emitter.addListener(ERROR_EVENT, (raw: unknown) => {\n const evt = raw as {\n requestId: string\n code?: string\n message?: string\n nativeMessage?: string\n }\n if (evt.requestId !== requestId) return\n if (evt.code === 'ERR_AUDIO_STREAM_CANCELLED') {\n processingChain\n .catch(() => {})\n .then(() => {\n settle(() => {}, 'resolve', {\n requestId,\n durationMs: 0,\n sampleRate:\n options.targetSampleRate ??\n options.sampleRate ??\n 0,\n channels: options.channels ?? 1,\n chunks: chunkCount,\n samples: sampleCount,\n cancelled: true,\n } satisfies StreamAudioDataResult)\n })\n return\n }\n handleError(\n new AudioStreamError({\n code:\n (evt.code as AudioStreamErrorCode) ??\n 'ERR_AUDIO_STREAM_UNKNOWN',\n message: evt.message ?? 'native stream error',\n nativeMessage: evt.nativeMessage,\n fileUri: options.fileUri,\n platform: 'native',\n recoverable: false,\n })\n )\n })\n )\n\n if (options.signal) {\n if (options.signal.aborted) {\n settle(() => {}, 'resolve', {\n requestId,\n durationMs: 0,\n sampleRate:\n options.targetSampleRate ?? options.sampleRate ?? 0,\n channels: options.channels ?? 1,\n chunks: 0,\n samples: 0,\n cancelled: true,\n } satisfies StreamAudioDataResult)\n return\n }\n abortListener = () => {\n try {\n AudioStudioModule.cancelStreamAudioData?.(requestId)\n } catch {\n /* noop */\n }\n }\n options.signal.addEventListener('abort', abortListener)\n }\n\n const { signal: _signal, ...nativeOptions } = options\n AudioStudioModule.streamAudioData({\n ...nativeOptions,\n requestId,\n streamFormat: options.streamFormat ?? 'float32',\n chunkDurationMs: options.chunkDurationMs ?? 1000,\n maxBufferedChunks: options.maxBufferedChunks ?? 4,\n normalizeAudio: options.normalizeAudio ?? true,\n }).catch(handleError)\n })\n}\n\nasync function streamAudioDataWeb(\n options: StreamAudioDataOptions,\n callbacks: StreamAudioDataCallbacks\n): Promise<StreamAudioDataResult> {\n const requestId = generateRequestId()\n const cancelled = () => options.signal?.aborted === true\n if (cancelled()) {\n return {\n requestId,\n durationMs: 0,\n sampleRate: options.targetSampleRate ?? options.sampleRate ?? 0,\n channels: options.channels ?? 1,\n chunks: 0,\n samples: 0,\n cancelled: true,\n }\n }\n\n try {\n const processed = await processAudioBuffer({\n fileUri: options.fileUri,\n targetSampleRate: options.targetSampleRate ?? 16000,\n targetChannels: options.channels ?? 1,\n normalizeAudio: options.normalizeAudio ?? true,\n startTimeMs: options.startTimeMs,\n endTimeMs: options.endTimeMs,\n })\n\n const sampleRate = processed.sampleRate\n const channels = processed.channels\n const durationMs = processed.durationMs\n const chunkDurationMs = options.chunkDurationMs ?? 1000\n let samplesPerChunk = Math.max(\n 1,\n Math.floor((chunkDurationMs / 1000) * sampleRate) * channels\n )\n if (options.maxChunkBytes) {\n const maxSamples = Math.floor(options.maxChunkBytes / 4)\n samplesPerChunk = Math.min(samplesPerChunk, maxSamples)\n }\n\n const all = sanitizeFloat32(processed.channelData, options.normalizeAudio ?? true)\n\n let chunkIndex = 0\n let emittedSamples = 0\n for (let off = 0; off < all.length; off += samplesPerChunk) {\n if (cancelled()) {\n return {\n requestId,\n durationMs,\n sampleRate,\n channels,\n chunks: chunkIndex,\n samples: emittedSamples,\n cancelled: true,\n }\n }\n const end = Math.min(off + samplesPerChunk, all.length)\n const slice = all.slice(off, end)\n const startSample = off / channels\n const endSample = end / channels\n const chunk: StreamAudioDataChunk = {\n requestId,\n chunkIndex,\n startTimeMs: Math.round((startSample / sampleRate) * 1000),\n endTimeMs: Math.round((endSample / sampleRate) * 1000),\n durationMs: Math.round(\n ((endSample - startSample) / sampleRate) * 1000\n ),\n startSample,\n sampleCount: slice.length,\n sampleRate,\n channels,\n samples: slice,\n isFinal: end >= all.length,\n }\n await callbacks.onChunk(chunk)\n callbacks.onProgress?.({\n requestId,\n processedMs: chunk.endTimeMs,\n durationMs,\n progress: durationMs > 0 ? chunk.endTimeMs / durationMs : 1,\n emittedChunks: chunkIndex + 1,\n })\n chunkIndex += 1\n emittedSamples += slice.length\n }\n\n return {\n requestId,\n durationMs,\n sampleRate,\n channels,\n chunks: chunkIndex,\n samples: emittedSamples,\n cancelled: false,\n }\n } catch (err) {\n throw mapStreamError(err, options.fileUri, 'web')\n }\n}\n\nfunction sanitizeFloat32(\n input: Float32Array,\n clamp: boolean\n): Float32Array {\n if (!clamp) {\n // still need NaN/Inf sanitation\n for (let i = 0; i < input.length; i++) {\n const v = input[i]\n if (!Number.isFinite(v)) input[i] = 0\n }\n return input\n }\n for (let i = 0; i < input.length; i++) {\n const v = input[i]\n if (!Number.isFinite(v)) {\n input[i] = 0\n } else if (v > 1) {\n input[i] = 1\n } else if (v < -1) {\n input[i] = -1\n }\n }\n return input\n}\n"]}
|
|
1
|
+
{"version":3,"file":"streamAudioData.js","sourceRoot":"","sources":["../../src/streamAudioData.ts"],"names":[],"mappings":"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","sourcesContent":["import { LegacyEventEmitter, type EventSubscription } from 'expo-modules-core'\n\nimport AudioStudioModule from './AudioStudioModule'\nimport { isWeb } from './constants'\nimport {\n AudioStreamError,\n AudioStreamErrorCode,\n mapStreamError,\n} from './errors/AudioStreamError'\nimport { processAudioBuffer } from './utils/audioProcessing'\n\n/**\n * High-level API: stream decoded audio from a stored file as bounded Float32\n * chunks without materializing the full PCM range in memory.\n *\n * See `docs/STREAM_AUDIO_DATA.md` for the full contract and rollout notes.\n */\nexport interface StreamAudioDataOptions {\n /** URI of the audio file to decode. */\n fileUri: string\n /** Start time in milliseconds (default: 0). */\n startTimeMs?: number\n /** End time in milliseconds (default: end-of-file). */\n endTimeMs?: number\n /**\n * Source sample rate hint. Ignored if `targetSampleRate` is set; native\n * decoders read the actual rate from the file.\n */\n sampleRate?: number\n /** Output sample rate. Native resamples when this differs from the file. */\n targetSampleRate?: number\n /** Output channel count (1 = mono downmix, 2 = stereo passthrough). */\n channels?: number\n /** Clamp samples to [-1, 1] and replace non-finite values with 0. */\n normalizeAudio?: boolean\n /** Target chunk duration in ms (default: 1000, min: 10, max: 60000). */\n chunkDurationMs?: number\n /** Soft cap on chunk size in bytes (Float32 = 4 bytes/sample). */\n maxChunkBytes?: number\n /** Max chunks queued in native before JS ack pauses decode (default: 4). */\n maxBufferedChunks?: number\n /**\n * Optional timeout for a chunk acknowledgement while backpressure is active.\n * Undefined/0 disables timeout so long transcription callbacks can run.\n */\n backpressureTimeoutMs?: number\n /** Output PCM format; only `'float32'` supported today. */\n streamFormat?: 'float32'\n /** Abort the in-flight request. Resolves promise with `cancelled: true`. */\n signal?: AbortSignal\n}\n\nexport interface StreamAudioDataChunk {\n /** Native request id; constant across all chunks of one call. */\n requestId: string\n /** Zero-based monotonic chunk index. */\n chunkIndex: number\n /** Start time in output-rate ms (rounded to nearest sample). */\n startTimeMs: number\n /** End time in output-rate ms. */\n endTimeMs: number\n /** Duration in ms (`endTimeMs - startTimeMs`). */\n durationMs: number\n /** First sample index in the output timeline. */\n startSample: number\n /** Sample count in `samples` (interleaved if channels > 1). */\n sampleCount: number\n /** Output sample rate. */\n sampleRate: number\n /** Output channel count. */\n channels: number\n /** Interleaved Float32 samples in [-1, 1]. */\n samples: Float32Array\n /** True for the last chunk of a non-cancelled run. */\n isFinal: boolean\n}\n\nexport interface StreamAudioDataProgress {\n requestId: string\n processedMs: number\n durationMs: number\n progress: number\n emittedChunks: number\n bufferedChunks?: number\n}\n\nexport interface StreamAudioDataResult {\n requestId: string\n durationMs: number\n sampleRate: number\n channels: number\n chunks: number\n samples: number\n cancelled: boolean\n}\n\nexport interface StreamAudioDataCallbacks {\n /**\n * Called with each decoded chunk. If this returns a Promise, native decode\n * pauses until it resolves (backpressure). Throwing aborts the stream with\n * `ERR_AUDIO_STREAM_DECODE_FAILED`.\n */\n onChunk: (chunk: StreamAudioDataChunk) => void | Promise<void>\n /** Called whenever native reports progress. */\n onProgress?: (progress: StreamAudioDataProgress) => void\n}\n\nexport interface AudioDecodeCapabilities {\n platform: 'ios' | 'android' | 'web'\n supportedInputFormats: string[]\n supportedOutputFormats: Array<'float32'>\n supportsCancellation: boolean\n supportsBackpressure: boolean\n supportsTimeRange: boolean\n supportsTargetSampleRate: boolean\n supportsChannelMixing: boolean\n knownLimitations?: string[]\n}\n\nconst CHUNK_EVENT = 'AudioDataStreamChunk'\nconst PROGRESS_EVENT = 'AudioDataStreamProgress'\nconst COMPLETE_EVENT = 'AudioDataStreamComplete'\nconst ERROR_EVENT = 'AudioDataStreamError'\n\nlet cachedEmitter: LegacyEventEmitter | null = null\nfunction getEmitter(): LegacyEventEmitter {\n if (!cachedEmitter) {\n cachedEmitter = new LegacyEventEmitter(AudioStudioModule)\n }\n return cachedEmitter\n}\n\nfunction generateRequestId(): string {\n const g = globalThis as { crypto?: { randomUUID?: () => string } }\n if (typeof g.crypto?.randomUUID === 'function') {\n try {\n return g.crypto.randomUUID()\n } catch {\n // fall through\n }\n }\n return `asd_${Date.now().toString(36)}_${Math.random()\n .toString(36)\n .slice(2, 10)}`\n}\n\nfunction toFloat32(samples: unknown): Float32Array {\n if (samples instanceof Float32Array) return samples\n if (Array.isArray(samples)) {\n const out = new Float32Array(samples.length)\n for (let i = 0; i < samples.length; i++) {\n const v = Number(samples[i])\n out[i] = Number.isFinite(v) ? v : 0\n }\n return out\n }\n if (typeof samples === 'string') {\n const bytes = base64ToBytes(samples)\n const floatLength = Math.floor(bytes.byteLength / 4)\n if (bytes.byteOffset % 4 === 0) {\n return new Float32Array(bytes.buffer, bytes.byteOffset, floatLength)\n }\n const sliced = bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n )\n return new Float32Array(sliced, 0, Math.floor(sliced.byteLength / 4))\n }\n if (samples && typeof samples === 'object' && 'length' in samples) {\n // ArrayLike fallback\n const arr = samples as ArrayLike<number>\n const out = new Float32Array(arr.length)\n for (let i = 0; i < arr.length; i++) {\n const v = Number(arr[i])\n out[i] = Number.isFinite(v) ? v : 0\n }\n return out\n }\n return new Float32Array(0)\n}\n\nfunction base64ToBytes(input: string): Uint8Array {\n const g = globalThis as { atob?: (s: string) => string }\n if (typeof g.atob !== 'function') {\n // Buffer path for environments without atob; React Native has atob.\n const Buf = (\n globalThis as {\n Buffer?: {\n from: (input: string, encoding: string) => Uint8Array\n }\n }\n ).Buffer\n if (Buf) return new Uint8Array(Buf.from(input, 'base64'))\n return new Uint8Array(0)\n }\n const bin = g.atob(input)\n const out = new Uint8Array(bin.length)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nfunction rejectInvalidRange(message: string): never {\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_INVALID_RANGE',\n message,\n recoverable: false,\n })\n}\n\nfunction assertPositiveFiniteOption(\n value: number | undefined,\n name: string,\n integer = false\n): void {\n if (value === undefined) return\n if (\n !Number.isFinite(value) ||\n value <= 0 ||\n (integer && !Number.isInteger(value))\n ) {\n rejectInvalidRange(\n `${name} must be a positive${integer ? ' integer' : ''}`\n )\n }\n}\n\nfunction validateOptions(options: StreamAudioDataOptions): void {\n if (!options.fileUri) {\n rejectInvalidRange('fileUri is required')\n }\n if (\n options.startTimeMs !== undefined &&\n options.endTimeMs !== undefined &&\n options.startTimeMs >= options.endTimeMs\n ) {\n rejectInvalidRange('startTimeMs must be < endTimeMs')\n }\n if (options.endTimeMs !== undefined && options.endTimeMs <= 0) {\n rejectInvalidRange('endTimeMs must be > 0')\n }\n if (options.startTimeMs !== undefined && options.startTimeMs < 0) {\n rejectInvalidRange('startTimeMs must be >= 0')\n }\n if (\n options.chunkDurationMs !== undefined &&\n (options.chunkDurationMs < 10 || options.chunkDurationMs > 60000)\n ) {\n rejectInvalidRange('chunkDurationMs must be in [10, 60000]')\n }\n if (\n options.backpressureTimeoutMs !== undefined &&\n options.backpressureTimeoutMs < 0\n ) {\n rejectInvalidRange('backpressureTimeoutMs must be >= 0')\n }\n assertPositiveFiniteOption(options.targetSampleRate, 'targetSampleRate')\n assertPositiveFiniteOption(options.sampleRate, 'sampleRate')\n assertPositiveFiniteOption(options.channels, 'channels', true)\n assertPositiveFiniteOption(\n options.maxBufferedChunks,\n 'maxBufferedChunks',\n true\n )\n assertPositiveFiniteOption(options.maxChunkBytes, 'maxChunkBytes', true)\n\n if (\n options.streamFormat !== undefined &&\n options.streamFormat !== 'float32'\n ) {\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_UNSUPPORTED_FORMAT',\n message: `Unsupported streamFormat: ${options.streamFormat}`,\n recoverable: false,\n })\n }\n}\n\n/**\n * Stream decoded audio from a stored file as bounded Float32 PCM chunks.\n *\n * Memory bound:\n * `chunkDurationMs * sampleRate * channels * 4 * maxBufferedChunks` +\n * native decoder buffers.\n *\n * Cancellation: pass `options.signal` and call `abort()`. The returned promise\n * resolves with `cancelled: true` (it does not reject) when cancellation wins.\n *\n * Backpressure: if `onChunk` returns a Promise, native decode is paused until\n * it resolves; if it throws, the stream is aborted with a `decode_failed` error.\n */\nexport async function streamAudioData(\n options: StreamAudioDataOptions,\n callbacks: StreamAudioDataCallbacks\n): Promise<StreamAudioDataResult> {\n validateOptions(options)\n\n if (isWeb) {\n return streamAudioDataWeb(options, callbacks)\n }\n\n return streamAudioDataNative(options, callbacks)\n}\n\n/** Discover what the running platform supports. */\nexport async function getAudioDecodeCapabilities(): Promise<AudioDecodeCapabilities> {\n if (isWeb) {\n return {\n platform: 'web',\n supportedInputFormats: [\n 'audio/wav',\n 'audio/mpeg',\n 'audio/mp4',\n 'audio/aac',\n 'audio/ogg',\n 'audio/webm',\n ],\n supportedOutputFormats: ['float32'],\n supportsCancellation: true,\n supportsBackpressure: true,\n supportsTimeRange: true,\n supportsTargetSampleRate: true,\n supportsChannelMixing: true,\n knownLimitations: [\n 'Web decodes the entire file via AudioContext.decodeAudioData before chunking; very long files may exceed browser memory.',\n ],\n }\n }\n if (typeof AudioStudioModule.getAudioDecodeCapabilities === 'function') {\n try {\n const caps = await AudioStudioModule.getAudioDecodeCapabilities()\n return caps as AudioDecodeCapabilities\n } catch (err) {\n throw mapStreamError(err, undefined, 'native')\n }\n }\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_NATIVE_UNAVAILABLE',\n message: 'getAudioDecodeCapabilities is not available on this build',\n recoverable: false,\n })\n}\n\nasync function streamAudioDataNative(\n options: StreamAudioDataOptions,\n callbacks: StreamAudioDataCallbacks\n): Promise<StreamAudioDataResult> {\n if (typeof AudioStudioModule.streamAudioData !== 'function') {\n throw new AudioStreamError({\n code: 'ERR_AUDIO_STREAM_NATIVE_UNAVAILABLE',\n message:\n 'streamAudioData native method missing — rebuild the host app with the latest @siteed/audio-studio.',\n recoverable: false,\n })\n }\n\n const requestId = generateRequestId()\n const emitter = getEmitter()\n const subs: EventSubscription[] = []\n let chunkCount = 0\n let sampleCount = 0\n let processingChain: Promise<void> = Promise.resolve()\n let settled = false\n let abortListener: (() => void) | null = null\n let lastProgress: StreamAudioDataProgress | null = null\n\n const finalize = () => {\n for (const sub of subs) {\n try {\n sub.remove()\n } catch {\n /* noop */\n }\n }\n subs.length = 0\n if (abortListener && options.signal) {\n options.signal.removeEventListener('abort', abortListener)\n }\n }\n\n return new Promise<StreamAudioDataResult>((resolve, reject) => {\n const settle = (\n fn: () => void,\n mode: 'resolve' | 'reject',\n value: unknown\n ) => {\n if (settled) return\n settled = true\n finalize()\n fn()\n if (mode === 'resolve') {\n resolve(value as StreamAudioDataResult)\n } else {\n reject(value as Error)\n }\n }\n\n const handleError = (err: unknown) => {\n settle(\n () => {\n try {\n AudioStudioModule.cancelStreamAudioData?.(requestId)\n } catch {\n /* noop */\n }\n },\n 'reject',\n mapStreamError(err, options.fileUri, 'native')\n )\n }\n\n subs.push(\n emitter.addListener(CHUNK_EVENT, (raw: unknown) => {\n const evt = raw as {\n requestId: string\n chunkIndex: number\n startTimeMs: number\n endTimeMs: number\n startSample: number\n sampleCount: number\n sampleRate: number\n channels: number\n samples: Float32Array | number[] | string\n isFinal: boolean\n }\n if (evt.requestId !== requestId) return\n const chunk: StreamAudioDataChunk = {\n requestId: evt.requestId,\n chunkIndex: evt.chunkIndex,\n startTimeMs: evt.startTimeMs,\n endTimeMs: evt.endTimeMs,\n durationMs: evt.endTimeMs - evt.startTimeMs,\n startSample: evt.startSample,\n sampleCount: evt.sampleCount,\n sampleRate: evt.sampleRate,\n channels: evt.channels,\n samples: toFloat32(evt.samples),\n isFinal: evt.isFinal,\n }\n chunkCount += 1\n sampleCount += chunk.sampleCount\n\n processingChain = processingChain\n .then(async () => {\n await callbacks.onChunk(chunk)\n try {\n AudioStudioModule.acknowledgeStreamAudioChunk?.(\n requestId,\n chunk.chunkIndex\n )\n } catch {\n /* noop */\n }\n })\n .catch(handleError)\n })\n )\n\n if (callbacks.onProgress) {\n subs.push(\n emitter.addListener(PROGRESS_EVENT, (raw: unknown) => {\n const evt = raw as StreamAudioDataProgress\n if (evt.requestId !== requestId) return\n lastProgress = evt\n callbacks.onProgress!(evt)\n })\n )\n }\n\n subs.push(\n emitter.addListener(COMPLETE_EVENT, (raw: unknown) => {\n const evt = raw as {\n requestId: string\n durationMs: number\n sampleRate: number\n channels: number\n chunks?: number\n samples?: number\n cancelled: boolean\n }\n if (evt.requestId !== requestId) return\n // Wait for in-flight onChunk callbacks before resolving.\n processingChain\n .then(() => {\n settle(() => {}, 'resolve', {\n requestId,\n durationMs:\n evt.durationMs > 0\n ? evt.durationMs\n : (lastProgress?.durationMs ?? 0),\n sampleRate: evt.sampleRate,\n channels: evt.channels,\n chunks: evt.chunks ?? chunkCount,\n samples: evt.samples ?? sampleCount,\n cancelled: evt.cancelled,\n } satisfies StreamAudioDataResult)\n })\n .catch(handleError)\n })\n )\n\n subs.push(\n emitter.addListener(ERROR_EVENT, (raw: unknown) => {\n const evt = raw as {\n requestId: string\n code?: string\n message?: string\n nativeMessage?: string\n }\n if (evt.requestId !== requestId) return\n if (evt.code === 'ERR_AUDIO_STREAM_CANCELLED') {\n processingChain\n .catch(() => {})\n .then(() => {\n settle(() => {}, 'resolve', {\n requestId,\n durationMs: lastProgress?.durationMs ?? 0,\n sampleRate:\n options.targetSampleRate ??\n options.sampleRate ??\n 0,\n channels: options.channels ?? 1,\n chunks: chunkCount,\n samples: sampleCount,\n cancelled: true,\n } satisfies StreamAudioDataResult)\n })\n return\n }\n handleError(\n new AudioStreamError({\n code:\n (evt.code as AudioStreamErrorCode) ??\n 'ERR_AUDIO_STREAM_UNKNOWN',\n message: evt.message ?? 'native stream error',\n nativeMessage: evt.nativeMessage,\n fileUri: options.fileUri,\n platform: 'native',\n recoverable: false,\n })\n )\n })\n )\n\n if (options.signal) {\n if (options.signal.aborted) {\n settle(() => {}, 'resolve', {\n requestId,\n durationMs: lastProgress?.durationMs ?? 0,\n sampleRate:\n options.targetSampleRate ?? options.sampleRate ?? 0,\n channels: options.channels ?? 1,\n chunks: 0,\n samples: 0,\n cancelled: true,\n } satisfies StreamAudioDataResult)\n return\n }\n abortListener = () => {\n try {\n AudioStudioModule.cancelStreamAudioData?.(requestId)\n } catch {\n /* noop */\n }\n }\n options.signal.addEventListener('abort', abortListener)\n }\n\n const { signal: _signal, ...nativeOptions } = options\n AudioStudioModule.streamAudioData({\n ...nativeOptions,\n requestId,\n streamFormat: options.streamFormat ?? 'float32',\n chunkDurationMs: options.chunkDurationMs ?? 1000,\n maxBufferedChunks: options.maxBufferedChunks ?? 4,\n normalizeAudio: options.normalizeAudio ?? true,\n }).catch(handleError)\n })\n}\n\nasync function streamAudioDataWeb(\n options: StreamAudioDataOptions,\n callbacks: StreamAudioDataCallbacks\n): Promise<StreamAudioDataResult> {\n const requestId = generateRequestId()\n const cancelled = () => options.signal?.aborted === true\n if (cancelled()) {\n return {\n requestId,\n durationMs: 0,\n sampleRate: options.targetSampleRate ?? options.sampleRate ?? 0,\n channels: options.channels ?? 1,\n chunks: 0,\n samples: 0,\n cancelled: true,\n }\n }\n\n try {\n const processed = await processAudioBuffer({\n fileUri: options.fileUri,\n targetSampleRate: options.targetSampleRate,\n targetChannels: options.channels,\n normalizeAudio: options.normalizeAudio ?? true,\n startTimeMs: options.startTimeMs,\n endTimeMs: options.endTimeMs,\n })\n\n const sampleRate = processed.sampleRate\n const channels = processed.channels\n const durationMs = processed.durationMs\n const chunkDurationMs = options.chunkDurationMs ?? 1000\n let samplesPerChunk = Math.max(\n channels,\n Math.floor((chunkDurationMs / 1000) * sampleRate) * channels\n )\n if (options.maxChunkBytes) {\n // Round down to a multiple of `channels` so we never split an\n // interleaved frame across two chunks (that would produce a\n // fractional `startSample` for the next chunk).\n const rawMax = Math.floor(options.maxChunkBytes / 4)\n const maxSamples = Math.max(\n channels,\n Math.floor(rawMax / channels) * channels\n )\n samplesPerChunk = Math.max(\n channels,\n Math.min(samplesPerChunk, maxSamples)\n )\n }\n\n const all = sanitizeFloat32(\n interleaveBuffer(processed.buffer, channels),\n options.normalizeAudio ?? true\n )\n\n // Chunk timestamps are absolute (range start + offset) on every\n // platform; progress is *elapsed within the range* so the\n // `processedMs / durationMs` fraction stays in [0, 1] regardless of\n // `startTimeMs`. The native decoders use the same split.\n const rangeStartMs = options.startTimeMs ?? 0\n let chunkIndex = 0\n let emittedSamples = 0\n for (let off = 0; off < all.length; off += samplesPerChunk) {\n if (cancelled()) {\n return {\n requestId,\n durationMs,\n sampleRate,\n channels,\n chunks: chunkIndex,\n samples: emittedSamples,\n cancelled: true,\n }\n }\n const end = Math.min(off + samplesPerChunk, all.length)\n const slice = all.slice(off, end)\n const startSample = off / channels\n const endSample = end / channels\n const startMs =\n Math.round((startSample / sampleRate) * 1000) + rangeStartMs\n const endMs =\n Math.round((endSample / sampleRate) * 1000) + rangeStartMs\n const chunk: StreamAudioDataChunk = {\n requestId,\n chunkIndex,\n startTimeMs: startMs,\n endTimeMs: endMs,\n durationMs: Math.round(\n ((endSample - startSample) / sampleRate) * 1000\n ),\n startSample,\n sampleCount: slice.length,\n sampleRate,\n channels,\n samples: slice,\n isFinal: end >= all.length,\n }\n await callbacks.onChunk(chunk)\n // Resample rounding (Math.ceil in processAudioBuffer) can push\n // elapsed past the source-rate-derived range duration on the tail\n // chunk. Cap so onProgress consumers always see a [0, 1] ratio,\n // matching the native `coerceIn(0, 1)` / `min(1, max(0, …))`\n // clamp.\n const rawElapsedMs = Math.round((endSample / sampleRate) * 1000)\n const elapsedMs =\n durationMs > 0\n ? Math.min(rawElapsedMs, durationMs)\n : rawElapsedMs\n callbacks.onProgress?.({\n requestId,\n processedMs: elapsedMs,\n durationMs,\n progress:\n durationMs > 0\n ? Math.min(1, Math.max(0, elapsedMs / durationMs))\n : 1,\n emittedChunks: chunkIndex + 1,\n })\n chunkIndex += 1\n emittedSamples += slice.length\n }\n\n return {\n requestId,\n durationMs,\n sampleRate,\n channels,\n chunks: chunkIndex,\n samples: emittedSamples,\n cancelled: false,\n }\n } catch (err) {\n throw mapStreamError(err, options.fileUri, 'web')\n }\n}\n\nfunction interleaveBuffer(buffer: AudioBuffer, channels: number): Float32Array {\n const numCh = Math.max(1, Math.min(channels, buffer.numberOfChannels))\n const framesPerCh = buffer.length\n if (numCh === 1) {\n // Cheap path: clone channel 0 so downstream mutation doesn't touch the\n // underlying AudioBuffer storage.\n return new Float32Array(buffer.getChannelData(0))\n }\n const out = new Float32Array(framesPerCh * numCh)\n const channelData: Float32Array[] = []\n for (let c = 0; c < numCh; c++) {\n channelData.push(buffer.getChannelData(c))\n }\n for (let f = 0; f < framesPerCh; f++) {\n for (let c = 0; c < numCh; c++) {\n out[f * numCh + c] = channelData[c][f]\n }\n }\n return out\n}\n\nfunction sanitizeFloat32(input: Float32Array, clamp: boolean): Float32Array {\n if (!clamp) {\n // still need NaN/Inf sanitation\n for (let i = 0; i < input.length; i++) {\n const v = input[i]\n if (!Number.isFinite(v)) input[i] = 0\n }\n return input\n }\n for (let i = 0; i < input.length; i++) {\n const v = input[i]\n if (!Number.isFinite(v)) {\n input[i] = 0\n } else if (v > 1) {\n input[i] = 1\n } else if (v < -1) {\n input[i] = -1\n }\n }\n return input\n}\n"]}
|
|
@@ -41,8 +41,11 @@ export async function processAudioBuffer({ arrayBuffer, fileUri, targetSampleRat
|
|
|
41
41
|
// Create context at original sample rate first
|
|
42
42
|
ctx =
|
|
43
43
|
audioContext ||
|
|
44
|
-
new (window.AudioContext ||
|
|
44
|
+
new (window.AudioContext ||
|
|
45
|
+
window.webkitAudioContext)();
|
|
45
46
|
buffer = await ctx.decodeAudioData(audioData);
|
|
47
|
+
const effectiveTargetSampleRate = targetSampleRate ?? buffer.sampleRate;
|
|
48
|
+
const effectiveTargetChannels = targetChannels ?? buffer.numberOfChannels;
|
|
46
49
|
logger?.debug('Decoded audio buffer:', {
|
|
47
50
|
originalChannels: buffer.numberOfChannels,
|
|
48
51
|
originalSampleRate: buffer.sampleRate,
|
|
@@ -60,21 +63,22 @@ export async function processAudioBuffer({ arrayBuffer, fileUri, targetSampleRat
|
|
|
60
63
|
const bytesPerSample = 2; // 16-bit audio = 2 bytes per sample
|
|
61
64
|
const adjustedStartSample = position !== undefined
|
|
62
65
|
? Math.floor((position / bytesPerSample) *
|
|
63
|
-
(buffer.sampleRate /
|
|
66
|
+
(buffer.sampleRate / effectiveTargetSampleRate))
|
|
64
67
|
: startSample;
|
|
65
68
|
const samplesNeeded = length !== undefined
|
|
66
69
|
? Math.floor((length / bytesPerSample) *
|
|
67
|
-
(buffer.sampleRate /
|
|
68
|
-
: endTimeMs !== undefined
|
|
69
|
-
? Math.floor(((endTimeMs - startTimeMs) / 1000) *
|
|
70
|
+
(buffer.sampleRate / effectiveTargetSampleRate))
|
|
71
|
+
: endTimeMs !== undefined
|
|
72
|
+
? Math.floor(((endTimeMs - (startTimeMs ?? 0)) / 1000) *
|
|
73
|
+
buffer.sampleRate)
|
|
70
74
|
: buffer.length - adjustedStartSample;
|
|
71
75
|
logger?.debug('Sample calculations (adjusted):', {
|
|
72
76
|
originalStartSample: startSample,
|
|
73
77
|
adjustedStartSample,
|
|
74
78
|
samplesNeeded,
|
|
75
79
|
originalSampleRate: buffer.sampleRate,
|
|
76
|
-
targetSampleRate,
|
|
77
|
-
conversionRatio: buffer.sampleRate /
|
|
80
|
+
targetSampleRate: effectiveTargetSampleRate,
|
|
81
|
+
conversionRatio: buffer.sampleRate / effectiveTargetSampleRate,
|
|
78
82
|
expectedDurationMs: (samplesNeeded / buffer.sampleRate) * 1000,
|
|
79
83
|
});
|
|
80
84
|
// Create temporary buffer for the segment
|
|
@@ -88,7 +92,7 @@ export async function processAudioBuffer({ arrayBuffer, fileUri, targetSampleRat
|
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
// Create offline context for resampling
|
|
91
|
-
const offlineCtx = new OfflineAudioContext(
|
|
95
|
+
const offlineCtx = new OfflineAudioContext(effectiveTargetChannels, Math.ceil((samplesNeeded * effectiveTargetSampleRate) / buffer.sampleRate), effectiveTargetSampleRate);
|
|
92
96
|
// Create source and connect
|
|
93
97
|
const source = offlineCtx.createBufferSource();
|
|
94
98
|
source.buffer = segmentBuffer;
|
|
@@ -101,7 +105,7 @@ export async function processAudioBuffer({ arrayBuffer, fileUri, targetSampleRat
|
|
|
101
105
|
const durationMs = Math.round((samplesNeeded / buffer.sampleRate) * 1000);
|
|
102
106
|
logger?.debug('Final processed audio:', {
|
|
103
107
|
outputSamples: channelData.length,
|
|
104
|
-
outputSampleRate:
|
|
108
|
+
outputSampleRate: effectiveTargetSampleRate,
|
|
105
109
|
durationMs,
|
|
106
110
|
});
|
|
107
111
|
return {
|
|
@@ -109,7 +113,7 @@ export async function processAudioBuffer({ arrayBuffer, fileUri, targetSampleRat
|
|
|
109
113
|
channelData,
|
|
110
114
|
samples: channelData.length,
|
|
111
115
|
durationMs,
|
|
112
|
-
sampleRate:
|
|
116
|
+
sampleRate: effectiveTargetSampleRate,
|
|
113
117
|
channels: processedBuffer.numberOfChannels,
|
|
114
118
|
};
|
|
115
119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audioProcessing.js","sourceRoot":"","sources":["../../../src/utils/audioProcessing.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/audio-studio/src/utils/audioProcessing.ts\nimport { Platform } from 'react-native'\n\nimport { ConsoleLike } from '../AudioStudio.types'\n\nexport interface ProcessAudioBufferOptions {\n arrayBuffer?: ArrayBuffer\n fileUri?: string\n targetSampleRate: number\n targetChannels: number\n normalizeAudio: boolean\n startTimeMs?: number\n endTimeMs?: number\n position?: number\n length?: number\n audioContext?: AudioContext\n logger?: ConsoleLike\n}\n\nexport interface ProcessedAudioData {\n channelData: Float32Array\n samples: number\n durationMs: number\n sampleRate: number\n channels: number\n buffer: AudioBuffer\n}\n\nexport async function processAudioBuffer({\n arrayBuffer,\n fileUri,\n targetSampleRate,\n targetChannels,\n normalizeAudio,\n startTimeMs,\n endTimeMs,\n position,\n length,\n audioContext,\n logger,\n}: ProcessAudioBufferOptions): Promise<ProcessedAudioData> {\n if (Platform.OS !== 'web') {\n throw new Error('processAudioBuffer is only supported on web')\n }\n\n let ctx: AudioContext | undefined\n let buffer: AudioBuffer | undefined\n\n try {\n // Log initial parameters\n logger?.debug('Process audio buffer - Initial params:', {\n hasArrayBuffer: !!arrayBuffer,\n fileUri,\n targetSampleRate,\n targetChannels,\n normalizeAudio,\n startTimeMs,\n endTimeMs,\n position,\n length,\n })\n\n // Get the audio data\n let audioData: ArrayBuffer\n if (arrayBuffer) {\n audioData = arrayBuffer\n } else if (fileUri) {\n const response = await fetch(fileUri)\n if (!response.ok) {\n throw new Error(\n `Failed to fetch fileUri: ${response.statusText}`\n )\n }\n audioData = await response.arrayBuffer()\n } else {\n throw new Error('Either arrayBuffer or fileUri must be provided')\n }\n\n logger?.debug('Audio data loaded:', {\n byteLength: audioData.byteLength,\n firstBytes: Array.from(new Uint8Array(audioData.slice(0, 16))),\n })\n\n // Create context at original sample rate first\n ctx =\n audioContext ||\n new (window.AudioContext || (window as any).webkitAudioContext)()\n buffer = await ctx.decodeAudioData(audioData)\n\n logger?.debug('Decoded audio buffer:', {\n originalChannels: buffer.numberOfChannels,\n originalSampleRate: buffer.sampleRate,\n originalDuration: buffer.duration,\n originalLength: buffer.length,\n })\n\n // Calculate time range\n const startSample =\n startTimeMs !== undefined\n ? Math.floor((startTimeMs / 1000) * buffer.sampleRate)\n : position !== undefined\n ? Math.floor(position / 2)\n : 0\n\n // Fix: Adjust position calculation based on original sample rate\n // When position is provided in bytes, we need to account for the original sample rate\n const bytesPerSample = 2 // 16-bit audio = 2 bytes per sample\n const adjustedStartSample =\n position !== undefined\n ? Math.floor(\n (position / bytesPerSample) *\n (buffer.sampleRate / targetSampleRate)\n )\n : startSample\n\n const samplesNeeded =\n length !== undefined\n ? Math.floor(\n (length / bytesPerSample) *\n (buffer.sampleRate / targetSampleRate)\n )\n : endTimeMs !== undefined && startTimeMs !== undefined\n ? Math.floor(\n ((endTimeMs - startTimeMs) / 1000) * buffer.sampleRate\n )\n : buffer.length - adjustedStartSample\n\n logger?.debug('Sample calculations (adjusted):', {\n originalStartSample: startSample,\n adjustedStartSample,\n samplesNeeded,\n originalSampleRate: buffer.sampleRate,\n targetSampleRate,\n conversionRatio: buffer.sampleRate / targetSampleRate,\n expectedDurationMs: (samplesNeeded / buffer.sampleRate) * 1000,\n })\n\n // Create temporary buffer for the segment\n const segmentBuffer = ctx.createBuffer(\n buffer.numberOfChannels,\n samplesNeeded,\n buffer.sampleRate\n )\n\n // Copy the segment\n for (let channel = 0; channel < buffer.numberOfChannels; channel++) {\n const channelData = buffer.getChannelData(channel)\n const segmentData = segmentBuffer.getChannelData(channel)\n for (let i = 0; i < samplesNeeded; i++) {\n segmentData[i] = channelData[adjustedStartSample + i]\n }\n }\n\n // Create offline context for resampling\n const offlineCtx = new OfflineAudioContext(\n targetChannels,\n Math.ceil((samplesNeeded * targetSampleRate) / buffer.sampleRate),\n targetSampleRate\n )\n\n // Create source and connect\n const source = offlineCtx.createBufferSource()\n source.buffer = segmentBuffer\n source.connect(offlineCtx.destination)\n\n // Render at new sample rate\n source.start()\n const processedBuffer = await offlineCtx.startRendering()\n\n // Get the final audio data\n const channelData = processedBuffer.getChannelData(0)\n const durationMs = Math.round(\n (samplesNeeded / buffer.sampleRate) * 1000\n )\n\n logger?.debug('Final processed audio:', {\n outputSamples: channelData.length,\n outputSampleRate: targetSampleRate,\n durationMs,\n })\n\n return {\n buffer: processedBuffer,\n channelData,\n samples: channelData.length,\n durationMs,\n sampleRate: targetSampleRate,\n channels: processedBuffer.numberOfChannels,\n }\n } catch (error) {\n logger?.error('Failed to process audio buffer:', {\n error,\n position,\n length,\n startTimeMs,\n endTimeMs,\n bufferLength: buffer?.length,\n })\n throw error\n } finally {\n if (!audioContext && ctx) {\n await ctx.close()\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"audioProcessing.js","sourceRoot":"","sources":["../../../src/utils/audioProcessing.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/audio-studio/src/utils/audioProcessing.ts\nimport { Platform } from 'react-native'\n\nimport { ConsoleLike } from '../AudioStudio.types'\n\nexport interface ProcessAudioBufferOptions {\n arrayBuffer?: ArrayBuffer\n fileUri?: string\n targetSampleRate?: number\n targetChannels?: number\n normalizeAudio: boolean\n startTimeMs?: number\n endTimeMs?: number\n position?: number\n length?: number\n audioContext?: AudioContext\n logger?: ConsoleLike\n}\n\nexport interface ProcessedAudioData {\n channelData: Float32Array\n samples: number\n durationMs: number\n sampleRate: number\n channels: number\n buffer: AudioBuffer\n}\n\nexport async function processAudioBuffer({\n arrayBuffer,\n fileUri,\n targetSampleRate,\n targetChannels,\n normalizeAudio,\n startTimeMs,\n endTimeMs,\n position,\n length,\n audioContext,\n logger,\n}: ProcessAudioBufferOptions): Promise<ProcessedAudioData> {\n if (Platform.OS !== 'web') {\n throw new Error('processAudioBuffer is only supported on web')\n }\n\n let ctx: AudioContext | undefined\n let buffer: AudioBuffer | undefined\n\n try {\n // Log initial parameters\n logger?.debug('Process audio buffer - Initial params:', {\n hasArrayBuffer: !!arrayBuffer,\n fileUri,\n targetSampleRate,\n targetChannels,\n normalizeAudio,\n startTimeMs,\n endTimeMs,\n position,\n length,\n })\n\n // Get the audio data\n let audioData: ArrayBuffer\n if (arrayBuffer) {\n audioData = arrayBuffer\n } else if (fileUri) {\n const response = await fetch(fileUri)\n if (!response.ok) {\n throw new Error(\n `Failed to fetch fileUri: ${response.statusText}`\n )\n }\n audioData = await response.arrayBuffer()\n } else {\n throw new Error('Either arrayBuffer or fileUri must be provided')\n }\n\n logger?.debug('Audio data loaded:', {\n byteLength: audioData.byteLength,\n firstBytes: Array.from(new Uint8Array(audioData.slice(0, 16))),\n })\n\n // Create context at original sample rate first\n ctx =\n audioContext ||\n new (window.AudioContext ||\n (\n window as unknown as {\n webkitAudioContext?: typeof AudioContext\n }\n ).webkitAudioContext)()\n buffer = await ctx.decodeAudioData(audioData)\n\n const effectiveTargetSampleRate = targetSampleRate ?? buffer.sampleRate\n const effectiveTargetChannels = targetChannels ?? buffer.numberOfChannels\n\n logger?.debug('Decoded audio buffer:', {\n originalChannels: buffer.numberOfChannels,\n originalSampleRate: buffer.sampleRate,\n originalDuration: buffer.duration,\n originalLength: buffer.length,\n })\n\n // Calculate time range\n const startSample =\n startTimeMs !== undefined\n ? Math.floor((startTimeMs / 1000) * buffer.sampleRate)\n : position !== undefined\n ? Math.floor(position / 2)\n : 0\n\n // Fix: Adjust position calculation based on original sample rate\n // When position is provided in bytes, we need to account for the original sample rate\n const bytesPerSample = 2 // 16-bit audio = 2 bytes per sample\n const adjustedStartSample =\n position !== undefined\n ? Math.floor(\n (position / bytesPerSample) *\n (buffer.sampleRate / effectiveTargetSampleRate)\n )\n : startSample\n\n const samplesNeeded =\n length !== undefined\n ? Math.floor(\n (length / bytesPerSample) *\n (buffer.sampleRate / effectiveTargetSampleRate)\n )\n : endTimeMs !== undefined\n ? Math.floor(\n ((endTimeMs - (startTimeMs ?? 0)) / 1000) *\n buffer.sampleRate\n )\n : buffer.length - adjustedStartSample\n\n logger?.debug('Sample calculations (adjusted):', {\n originalStartSample: startSample,\n adjustedStartSample,\n samplesNeeded,\n originalSampleRate: buffer.sampleRate,\n targetSampleRate: effectiveTargetSampleRate,\n conversionRatio: buffer.sampleRate / effectiveTargetSampleRate,\n expectedDurationMs: (samplesNeeded / buffer.sampleRate) * 1000,\n })\n\n // Create temporary buffer for the segment\n const segmentBuffer = ctx.createBuffer(\n buffer.numberOfChannels,\n samplesNeeded,\n buffer.sampleRate\n )\n\n // Copy the segment\n for (let channel = 0; channel < buffer.numberOfChannels; channel++) {\n const channelData = buffer.getChannelData(channel)\n const segmentData = segmentBuffer.getChannelData(channel)\n for (let i = 0; i < samplesNeeded; i++) {\n segmentData[i] = channelData[adjustedStartSample + i]\n }\n }\n\n // Create offline context for resampling\n const offlineCtx = new OfflineAudioContext(\n effectiveTargetChannels,\n Math.ceil(\n (samplesNeeded * effectiveTargetSampleRate) / buffer.sampleRate\n ),\n effectiveTargetSampleRate\n )\n\n // Create source and connect\n const source = offlineCtx.createBufferSource()\n source.buffer = segmentBuffer\n source.connect(offlineCtx.destination)\n\n // Render at new sample rate\n source.start()\n const processedBuffer = await offlineCtx.startRendering()\n\n // Get the final audio data\n const channelData = processedBuffer.getChannelData(0)\n const durationMs = Math.round(\n (samplesNeeded / buffer.sampleRate) * 1000\n )\n\n logger?.debug('Final processed audio:', {\n outputSamples: channelData.length,\n outputSampleRate: effectiveTargetSampleRate,\n durationMs,\n })\n\n return {\n buffer: processedBuffer,\n channelData,\n samples: channelData.length,\n durationMs,\n sampleRate: effectiveTargetSampleRate,\n channels: processedBuffer.numberOfChannels,\n }\n } catch (error) {\n logger?.error('Failed to process audio buffer:', {\n error,\n position,\n length,\n startTimeMs,\n endTimeMs,\n bufferLength: buffer?.length,\n })\n throw error\n } finally {\n if (!audioContext && ctx) {\n await ctx.close()\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioStreamError.d.ts","sourceRoot":"","sources":["../../../src/errors/AudioStreamError.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAC1B,qCAAqC,GACrC,gCAAgC,GAChC,gCAAgC,GAChC,4BAA4B,GAC5B,oCAAoC,GACpC,iCAAiC,GACjC,uCAAuC,GACvC,qCAAqC,GACrC,uBAAuB,GACvB,0BAA0B,CAAA;AAEhC,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,oBAAoB,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB;AASD,qBAAa,gBAAiB,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAA;IACnC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;gBAEnB,OAAO,EAAE,uBAAuB;IAW5C,MAAM,IAAI,uBAAuB;CAWpC;
|
|
1
|
+
{"version":3,"file":"AudioStreamError.d.ts","sourceRoot":"","sources":["../../../src/errors/AudioStreamError.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAC1B,qCAAqC,GACrC,gCAAgC,GAChC,gCAAgC,GAChC,4BAA4B,GAC5B,oCAAoC,GACpC,iCAAiC,GACjC,uCAAuC,GACvC,qCAAqC,GACrC,uBAAuB,GACvB,0BAA0B,CAAA;AAEhC,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,oBAAoB,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB;AASD,qBAAa,gBAAiB,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAA;IACnC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;gBAEnB,OAAO,EAAE,uBAAuB;IAW5C,MAAM,IAAI,uBAAuB;CAWpC;AAwFD,wBAAgB,cAAc,CAC1B,GAAG,EAAE,OAAO,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAClB,gBAAgB,CA4ClB"}
|
|
@@ -28,6 +28,11 @@ export interface StreamAudioDataOptions {
|
|
|
28
28
|
maxChunkBytes?: number;
|
|
29
29
|
/** Max chunks queued in native before JS ack pauses decode (default: 4). */
|
|
30
30
|
maxBufferedChunks?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Optional timeout for a chunk acknowledgement while backpressure is active.
|
|
33
|
+
* Undefined/0 disables timeout so long transcription callbacks can run.
|
|
34
|
+
*/
|
|
35
|
+
backpressureTimeoutMs?: number;
|
|
31
36
|
/** Output PCM format; only `'float32'` supported today. */
|
|
32
37
|
streamFormat?: 'float32';
|
|
33
38
|
/** Abort the in-flight request. Resolves promise with `cancelled: true`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamAudioData.d.ts","sourceRoot":"","sources":["../../src/streamAudioData.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACnC,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAA;IACf,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,4EAA4E;IAC5E,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,WAAW,CAAA;CACvB;AAED,MAAM,WAAW,oBAAoB;IACjC,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAA;IACjB,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAA;IAClB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAA;IACnB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAA;IACnB,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,8CAA8C;IAC9C,OAAO,EAAE,YAAY,CAAA;IACrB,sDAAsD;IACtD,OAAO,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,uBAAuB;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,qBAAqB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,wBAAwB;IACrC;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,+CAA+C;IAC/C,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,IAAI,CAAA;CAC3D;AAED,MAAM,WAAW,uBAAuB;IACpC,QAAQ,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,CAAA;IACnC,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,sBAAsB,EAAE,KAAK,CAAC,SAAS,CAAC,CAAA;IACxC,oBAAoB,EAAE,OAAO,CAAA;IAC7B,oBAAoB,EAAE,OAAO,CAAA;IAC7B,iBAAiB,EAAE,OAAO,CAAA;IAC1B,wBAAwB,EAAE,OAAO,CAAA;IACjC,qBAAqB,EAAE,OAAO,CAAA;IAC9B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC9B;
|
|
1
|
+
{"version":3,"file":"streamAudioData.d.ts","sourceRoot":"","sources":["../../src/streamAudioData.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { ConsoleLike } from '../AudioStudio.types';
|
|
|
2
2
|
export interface ProcessAudioBufferOptions {
|
|
3
3
|
arrayBuffer?: ArrayBuffer;
|
|
4
4
|
fileUri?: string;
|
|
5
|
-
targetSampleRate
|
|
6
|
-
targetChannels
|
|
5
|
+
targetSampleRate?: number;
|
|
6
|
+
targetChannels?: number;
|
|
7
7
|
normalizeAudio: boolean;
|
|
8
8
|
startTimeMs?: number;
|
|
9
9
|
endTimeMs?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audioProcessing.d.ts","sourceRoot":"","sources":["../../../src/utils/audioProcessing.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAElD,MAAM,WAAW,yBAAyB;IACtC,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gBAAgB,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"audioProcessing.d.ts","sourceRoot":"","sources":["../../../src/utils/audioProcessing.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAElD,MAAM,WAAW,yBAAyB;IACtC,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,cAAc,EAAE,OAAO,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAA;CACvB;AAED,MAAM,WAAW,kBAAkB;IAC/B,WAAW,EAAE,YAAY,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,WAAW,CAAA;CACtB;AAED,wBAAsB,kBAAkB,CAAC,EACrC,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,WAAW,EACX,SAAS,EACT,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,MAAM,GACT,EAAE,yBAAyB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA+KzD"}
|