fix: mute audio output during System Audio and Mic capture to prevent echo
Insert a zero-gain GainNode between ScriptProcessorNode and audioContext.destination. The processor stays in the graph (so onaudioprocess fires on all browsers) but zero volume reaches the speakers, eliminating the echo/feedback loop during live capture.
This commit is contained in:
parent
f637ab10a5
commit
80af17a255
|
|
@ -28,6 +28,7 @@ export function useMediaStreamASR({ wsUrl }: UseMediaStreamASRProps): UseMediaSt
|
|||
const wsRef = useRef<WebSocket | null>(null)
|
||||
const audioContextRef = useRef<AudioContext | null>(null)
|
||||
const processorRef = useRef<ScriptProcessorNode | null>(null)
|
||||
const gainNodeRef = useRef<GainNode | null>(null)
|
||||
const sourceRef = useRef<MediaStreamAudioSourceNode | null>(null)
|
||||
const streamRef = useRef<MediaStream | null>(null)
|
||||
const isStreamingRef = useRef(false)
|
||||
|
|
@ -63,8 +64,10 @@ export function useMediaStreamASR({ wsUrl }: UseMediaStreamASRProps): UseMediaSt
|
|||
}
|
||||
|
||||
processorRef.current?.disconnect()
|
||||
gainNodeRef.current?.disconnect()
|
||||
sourceRef.current?.disconnect()
|
||||
processorRef.current = null
|
||||
gainNodeRef.current = null
|
||||
sourceRef.current = null
|
||||
|
||||
if (wsRef.current) {
|
||||
|
|
@ -114,18 +117,22 @@ export function useMediaStreamASR({ wsUrl }: UseMediaStreamASRProps): UseMediaSt
|
|||
const processor = audioContext.createScriptProcessor(4096, 1, 1)
|
||||
processorRef.current = processor
|
||||
|
||||
// onaudioprocess — mirrors useVideoASR lines 126-132 exactly
|
||||
// Zero-gain node mutes audio output to prevent echo/feedback. The processor
|
||||
// must remain in the graph (connected to destination) so onaudioprocess fires.
|
||||
const zeroGain = audioContext.createGain()
|
||||
zeroGain.gain.value = 0
|
||||
gainNodeRef.current = zeroGain
|
||||
|
||||
processor.onaudioprocess = (e) => {
|
||||
const float32Data = e.inputBuffer.getChannelData(0)
|
||||
const outputData = e.outputBuffer.getChannelData(0)
|
||||
outputData.set(float32Data)
|
||||
if (!isStreamingRef.current) return
|
||||
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) return
|
||||
wsRef.current.send(float32Data.buffer)
|
||||
}
|
||||
|
||||
source.connect(processor)
|
||||
processor.connect(audioContext.destination)
|
||||
processor.connect(zeroGain)
|
||||
zeroGain.connect(audioContext.destination)
|
||||
|
||||
const ws = new WebSocket(wsUrl)
|
||||
wsRef.current = ws
|
||||
|
|
@ -181,6 +188,7 @@ export function useMediaStreamASR({ wsUrl }: UseMediaStreamASRProps): UseMediaSt
|
|||
})
|
||||
}
|
||||
processorRef.current?.disconnect()
|
||||
gainNodeRef.current?.disconnect()
|
||||
sourceRef.current?.disconnect()
|
||||
wsRef.current?.close()
|
||||
audioContextRef.current?.close()
|
||||
|
|
|
|||
Loading…
Reference in New Issue