diff --git a/public/js/detectSpeaking.js b/public/js/detectSpeaking.js index 9f2376ac..9df2906c 100644 --- a/public/js/detectSpeaking.js +++ b/public/js/detectSpeaking.js @@ -1,8 +1,9 @@ 'use strict'; -const bars = getSlALL('.volume-bar'); +const bars = document.querySelectorAll('.volume-bar'); -let scriptProcessor = null; +let audioContext = null; +let workletNode = null; /** * Check if audio context is supported @@ -18,37 +19,45 @@ function isAudioContextSupported() { */ async function getMicrophoneVolumeIndicator(stream) { if (isAudioContextSupported() && hasAudioTrack(stream)) { - stopMicrophoneProcessing(); - console.log('Start microphone volume indicator for audio track', stream.getAudioTracks()[0]); - const audioContext = new (window.AudioContext || window.webkitAudioContext)(); - const microphone = audioContext.createMediaStreamSource(stream); + try { + // Clean up any existing resources first + stopMicrophoneProcessing(); - // 创建并配置 AudioWorkletNode - await audioContext.audioWorklet.addModule('volume-processor.js'); - const workletNode = new AudioWorkletNode(audioContext, 'volume-processor', { - processorOptions: { - threshold: 10, // 音量阈值 - peerId: myPeerId, // 你的 peer ID - myAudioStatus: myAudioStatus, // 你的音频状态 - }, - }); + console.log('Start microphone volume indicator for audio track', stream.getAudioTracks()[0]); + audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const microphone = audioContext.createMediaStreamSource(stream); - // 监听处理器发送的消息 - workletNode.port.onmessage = (event) => { - const data = event.data; + // Create and configure AudioWorkletNode + await audioContext.audioWorklet.addModule('/js/volume-processor.js'); + workletNode = new AudioWorkletNode(audioContext, 'volume-processor', { + processorOptions: { + threshold: 10, // Volume threshold + peerId: myPeerId, // Your peer ID + myAudioStatus: myAudioStatus, // Your audio status + }, + }); - if (data.type === 'micVolume') { - // 发送数据到 DataChannel - sendToDataChannel(data); - handleMyVolume(data); // 自定义处理函数 - } else if (data.type === 'volumeIndicator') { - updateVolumeIndicator(data.volume); // 更新音量指示器 - } - }; + // Listen for messages from the processor + workletNode.port.onmessage = (event) => { + const data = event.data; - // 连接音频图 - microphone.connect(workletNode); - workletNode.connect(audioContext.destination); + if (data.type === 'micVolume') { + // Send data to DataChannel + sendToDataChannel(data); + handleMyVolume(data); // Custom handling function + } else if (data.type === 'volumeIndicator') { + updateVolumeIndicator(data.volume); // Update volume indicator + } + }; + + // Connect audio graph + microphone.connect(workletNode); + workletNode.connect(audioContext.destination); + } catch (error) { + console.error('Error initializing microphone volume indicator:', error); + // Clean up on error + stopMicrophoneProcessing(); + } } else { console.warn('Microphone volume indicator not supported for this browser'); } @@ -59,9 +68,27 @@ async function getMicrophoneVolumeIndicator(stream) { */ function stopMicrophoneProcessing() { console.log('Stop microphone volume indicator'); - if (scriptProcessor) { - scriptProcessor.disconnect(); - scriptProcessor = null; + + // Clean up workletNode + if (workletNode) { + try { + workletNode.disconnect(); + } catch (error) { + console.warn('Error disconnecting workletNode:', error); + } + workletNode = null; + } + + // Clean up audioContext + if (audioContext) { + try { + if (audioContext.state !== 'closed') { + audioContext.close(); + } + } catch (error) { + console.warn('Error closing audioContext:', error); + } + audioContext = null; } } diff --git a/public/js/volume-processor.js b/public/js/volume-processor.js index a4e2a58c..601226f6 100644 --- a/public/js/volume-processor.js +++ b/public/js/volume-processor.js @@ -8,16 +8,29 @@ class VolumeProcessor extends AudioWorkletProcessor { } process(inputs, outputs, parameters) { - const input = inputs[0][0]; // 获取输入音频数据 - let sum = 0; - for (let i = 0; i < input.length; i++) { - sum += input[i] * input[i]; + const input = inputs[0]; + + // Check if we have valid input + if (!input || input.length === 0) { + return true; } - const rms = Math.sqrt(sum / input.length); + + const inputData = input[0]; // Get input audio data + + // Check if inputData exists and has length + if (!inputData || inputData.length === 0) { + return true; + } + + let sum = 0; + for (let i = 0; i < inputData.length; i++) { + sum += inputData[i] * inputData[i]; + } + const rms = Math.sqrt(sum / inputData.length); const volume = Math.max(0, Math.min(1, rms * 10)); const finalVolume = Math.round(volume * 100); - // 只有当音量超过阈值且状态为 true 时才发送数据 + // Only send data when volume exceeds threshold and status is true if (this.myAudioStatus && finalVolume > this.threshold) { this.port.postMessage({ type: 'micVolume', @@ -26,7 +39,7 @@ class VolumeProcessor extends AudioWorkletProcessor { }); } - // 发送音量数据用于 UI 更新 + // Send volume data for UI updates this.port.postMessage({ type: 'volumeIndicator', volume: volume, @@ -36,4 +49,4 @@ class VolumeProcessor extends AudioWorkletProcessor { } } -registerProcessor('volume-processor', VolumeProcessor); \ No newline at end of file +registerProcessor('volume-processor', VolumeProcessor); diff --git a/public/views/client.html b/public/views/client.html index a9625726..bd1441d9 100755 --- a/public/views/client.html +++ b/public/views/client.html @@ -1174,8 +1174,9 @@ access to use this app. - + +