// src/services/audioUtils.js
// This file should not import React or use any hooks.
export const stopAllPlayingAudio = (playingSourcesRef, audioContextRef, playbackTimeRef) => {
if (audioContextRef.current) {
playingSourcesRef.current.forEach((source) => {
try {
source.stop();
} catch (e) {
// Ignore errors from stopping already stopped sources
}
});
playingSourcesRef.current = [];
playbackTimeRef.current = audioContextRef.current.currentTime;
console.log("All playing audio has been stopped.");
}
};
export const stopAllMediaStreams = (vadStreamRef, mediaRecorderRef, scriptProcessorRef, streamRef) => {
if (vadStreamRef.current) {
vadStreamRef.current.getTracks().forEach((track) => track.stop());
vadStreamRef.current = null;
}
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
mediaRecorderRef.current.stop();
}
if (scriptProcessorRef.current) {
scriptProcessorRef.current.disconnect();
scriptProcessorRef.current = null;
}
if (streamRef.current) {
streamRef.current.getTracks().forEach(track => track.stop());
streamRef.current = null;
}
console.log("All audio streams and timers have been stopped.");
};
export const resampleBuffer = (buffer, srcRate, dstRate) => {
if (srcRate === dstRate) return buffer;
const ratio = srcRate / dstRate;
const newLength = Math.round(buffer.length / ratio);
const resampled = new Float32Array(newLength);
for (let i = 0; i < newLength; i++) {
const srcIndex = i * ratio;
const srcIndexFloor = Math.floor(srcIndex);
const srcIndexCeil = Math.min(srcIndexFloor + 1, buffer.length - 1);
const weight = srcIndex - srcIndexFloor;
resampled[i] =
buffer[srcIndexFloor] * (1 - weight) + buffer[srcIndexCeil] * weight;
}
return resampled;
};
export const convertPcmToFloat32 = (pcmBytes) => {
const int16Array = new Int16Array(
pcmBytes.buffer,
pcmBytes.byteOffset,
pcmBytes.byteLength / 2
);
const float32Array = new Float32Array(int16Array.length);
for (let i = 0; i < int16Array.length; i++) {
float32Array[i] = int16Array[i] / 32768;
}
return float32Array;
};