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.
-
+
+