Explorar el Código

Merge branch 'muzi' of http://59.110.91.129:3000/zhangmengying/AIClass into wanzi

丸子 hace 1 mes
padre
commit
d5171a2248
Se han modificado 1 ficheros con 76 adiciones y 19 borrados
  1. 76 19
      src/components/ai/voice/VoiceInput2.vue

+ 76 - 19
src/components/ai/voice/VoiceInput2.vue

@@ -312,13 +312,17 @@ const toggleSpeechInput = async () => {
     
     // 停止音频处理
     if (scriptProcessor.value) {
-      scriptProcessor.value.disconnect()
+      // 对于AudioWorkletNode,需要先关闭端口
+      if (scriptProcessor.value.port) {
+        scriptProcessor.value.port.close();
+      }
+      scriptProcessor.value.disconnect();
     }
     if (mediaStreamSource.value) {
-      mediaStreamSource.value.disconnect()
+      mediaStreamSource.value.disconnect();
     }
     if (audioContext.value) {
-      audioContext.value.close()
+      audioContext.value.close();
     }
     
     // 释放媒体流资源
@@ -356,23 +360,72 @@ const toggleSpeechInput = async () => {
       // 使用Web Audio API捕获音频并转换为PCM格式
       audioContext.value = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 })
       mediaStreamSource.value = audioContext.value.createMediaStreamSource(stream)
-      scriptProcessor.value = audioContext.value.createScriptProcessor(4096, 1, 1)
-
-      // 处理音频数据
-      scriptProcessor.value.onaudioprocess = async (event) => {
-        const inputData = event.inputBuffer.getChannelData(0)
-        // 转换为16位PCM
-        const pcmData = new Int16Array(inputData.length)
-        for (let i = 0; i < inputData.length; i++) {
-          pcmData[i] = inputData[i] * 32768
+      
+      // 尝试使用AudioWorkletNode(现代浏览器推荐),如果不支持则回退到ScriptProcessorNode
+      if (audioContext.value.audioWorklet && window.AudioWorkletNode) {
+        try {
+          // 注册音频处理工作线程
+          await audioContext.value.audioWorklet.addModule('data:text/javascript,' + encodeURIComponent(`
+            class AudioProcessor extends AudioWorkletProcessor {
+              process(inputs, outputs, params) {
+                const input = inputs[0];
+                if (input.length > 0) {
+                  const channelData = input[0];
+                  const pcmData = new Int16Array(channelData.length);
+                  for (let i = 0; i < channelData.length; i++) {
+                    pcmData[i] = channelData[i] * 32768;
+                  }
+                  // 通过消息传递数据到主线程
+                  this.port.postMessage({ pcmData: pcmData.buffer }, [pcmData.buffer]);
+                }
+                return true;
+              }
+            }
+            registerProcessor('audio-processor', AudioProcessor);
+          `));
+          
+          // 创建AudioWorkletNode
+          scriptProcessor.value = new AudioWorkletNode(audioContext.value, 'audio-processor');
+          
+          // 处理来自工作线程的消息
+          scriptProcessor.value.port.onmessage = async (event) => {
+            if (event.data.pcmData) {
+              await sendAudioData(event.data.pcmData);
+            }
+          };
+        } catch (error) {
+          console.warn('AudioWorkletNode不支持,回退到ScriptProcessorNode:', error);
+          // 回退到ScriptProcessorNode
+          scriptProcessor.value = audioContext.value.createScriptProcessor(4096, 1, 1);
+          scriptProcessor.value.onaudioprocess = async (event) => {
+            const inputData = event.inputBuffer.getChannelData(0);
+            // 转换为16位PCM
+            const pcmData = new Int16Array(inputData.length);
+            for (let i = 0; i < inputData.length; i++) {
+              pcmData[i] = inputData[i] * 32768;
+            }
+            // 发送到后端
+            await sendAudioData(pcmData.buffer);
+          };
         }
-        // 发送到后端
-        await sendAudioData(pcmData.buffer)
+      } else {
+        // 使用传统的ScriptProcessorNode
+        scriptProcessor.value = audioContext.value.createScriptProcessor(4096, 1, 1);
+        scriptProcessor.value.onaudioprocess = async (event) => {
+          const inputData = event.inputBuffer.getChannelData(0);
+          // 转换为16位PCM
+          const pcmData = new Int16Array(inputData.length);
+          for (let i = 0; i < inputData.length; i++) {
+            pcmData[i] = inputData[i] * 32768;
+          }
+          // 发送到后端
+          await sendAudioData(pcmData.buffer);
+        };
       }
 
       // 连接音频节点
-      mediaStreamSource.value.connect(scriptProcessor.value)
-      scriptProcessor.value.connect(audioContext.value.destination)
+      mediaStreamSource.value.connect(scriptProcessor.value);
+      scriptProcessor.value.connect(audioContext.value.destination);
 
       // 先设置UI状态,让用户知道系统正在准备
       isRecording.value = true
@@ -393,13 +446,17 @@ const toggleSpeechInput = async () => {
             
             // 停止音频处理
             if (scriptProcessor.value) {
-              scriptProcessor.value.disconnect()
+              // 对于AudioWorkletNode,需要先关闭端口
+              if (scriptProcessor.value.port) {
+                scriptProcessor.value.port.close();
+              }
+              scriptProcessor.value.disconnect();
             }
             if (mediaStreamSource.value) {
-              mediaStreamSource.value.disconnect()
+              mediaStreamSource.value.disconnect();
             }
             if (audioContext.value) {
-              audioContext.value.close()
+              audioContext.value.close();
             }
             
             // 释放媒体流资源