// 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; };