Просмотр исходного кода

处理自动播放状态下处理语音播放和自动切换逻辑

liyanbo 4 месяцев назад
Родитель
Сommit
8a90eb606b
1 измененных файлов с 79 добавлено и 63 удалено
  1. 79 63
      src/views/AIPage/aiGenerate/DialogContent.vue

+ 79 - 63
src/views/AIPage/aiGenerate/DialogContent.vue

@@ -19,7 +19,7 @@
           <el-icon class="arrow-icon"><CaretLeft /></el-icon>
         </div>
         <div class="arrow-icon-circle" @click="togglePlay">
-          <span class="play-text">{{ isPlaying ? '暂停' : '播放' }}</span>
+          <span class="play-text">{{ isPlaying ? '暂停' : '自动' }}</span>
         </div>
         <div class="arrow-icon-circle" @click="playNext" :class="{ 'disabled': currentSectionIndex === scriptData.sections.length - 1 && currentDialogueIndex === currentSection.dialogues.length - 1 }">
           <el-icon class="arrow-icon"><CaretRight /></el-icon>
@@ -297,7 +297,7 @@ const playBackgroundAudio = () => {
   }
 }
 
-const playDialogueAudio = () => {
+const playDialogueAudio = (isAutoPlay = false) => {
   // 停止之前的对话语音
   if (dialogueAudio.value) {
     dialogueAudio.value.pause()
@@ -306,41 +306,49 @@ const playDialogueAudio = () => {
   
   // 播放当前对话的语音
   if (currentDialogue.value?.voiceoverUrl) {
-    dialogueAudio.value = new Audio(currentDialogue.value.voiceoverUrl)
-    return new Promise((resolve) => {
-      // 最短3秒跳转
-      const minDelay = 3000
-      let audioEnded = false
-      
-      // 音频结束事件
-      dialogueAudio.value.onended = () => {
-        audioEnded = true
-        resolve()
+    const audio = new Audio(currentDialogue.value.voiceoverUrl)
+    dialogueAudio.value = audio
+    
+    // 音频结束事件
+    audio.onended = () => {
+      // 如果是自动播放状态,继续播放下一条
+      if (isAutoPlay && isPlaying.value) {
+        setTimeout(() => {
+          if (!playNext(true)) {
+            // 播放完毕
+            isPlaying.value = false
+            stopAllAudio()
+          }
+        }, 100)
       }
-      
-      // 播放音频
-      dialogueAudio.value.play().catch(e => {
-        console.error('对话语音播放失败:', e)
-        // 播放失败时,2秒后跳转
-        setTimeout(resolve, minDelay)
-      })
-      
-      // 检查音频时长
-      dialogueAudio.value.addEventListener('loadedmetadata', () => {
-        const duration = dialogueAudio.value.duration
-        // 如果音频时长小于2秒,2秒后跳转
-        if (duration < 2) {
-          setTimeout(() => {
-            if (!audioEnded) {
-              resolve()
-            }
-          }, minDelay)
-        }
-      })
+    }
+    
+    // 播放音频
+    audio.play().catch(e => {
+      console.error('对话语音播放失败:', e)
+      // 播放失败时,2秒后跳转(暂时注销,因为会导致user类型数字人回复播报跳转后语音播报报错,直接2秒跳转)
+      // if (isAutoPlay && isPlaying.value) {
+      //   setTimeout(() => {
+      //     if (!playNext(true)) {
+      //       // 播放完毕
+      //       isPlaying.value = false
+      //       stopAllAudio()
+      //     }
+      //   }, 2000)
+      // }
     })
+  } else {
+    // 如果没有语音文件,2秒后跳转
+    if (isAutoPlay && isPlaying.value && currentDialogue.value?.type !== 'user') {
+      setTimeout(() => {
+        if (!playNext(true)) {
+          // 播放完毕
+          isPlaying.value = false
+          stopAllAudio()
+        }
+      }, 2000)
+    }
   }
-  // 如果没有语音文件,2秒后跳转
-  return new Promise(resolve => setTimeout(resolve, 2000))
 }
 
 const togglePlay = () => {
@@ -356,26 +364,15 @@ const togglePlay = () => {
   }
 }
 
-const playSequence = async () => {
+// 自动播放序列
+const playSequence = () => {
   if (!isPlaying.value) return
 
   // 如果当前是用户输入卡片,暂停播放等待用户输入
-  if (currentDialogue.value?.type === 'user') {
-    return
-  }
-
-  // 播放当前对话语音
-  await playDialogueAudio()
+  if (currentDialogue.value?.type === 'user') return
 
-  // 播放下一个对话
-  if (!playNext()) {
-    // 播放完毕
-    isPlaying.value = false
-    // 停止所有音频,包括背景音
-    stopAllAudio()
-  } else {
-    playSequence()
-  }
+  // 播放当前对话语音,传递isAutoPlay参数
+  playDialogueAudio(true)
 }
 
 const playPrevious = () => {
@@ -384,7 +381,7 @@ const playPrevious = () => {
 
   // 如果正在进行数字人对话,调用stopStream清理
   recoverQuestDialogue()
-  stopPlayback()
+  stopPlayback(false) // 不触发回调
   if (conversationInProgress.value) {
     stopStream()
   }
@@ -400,10 +397,14 @@ const playPrevious = () => {
   // 播放背景音
   playBackgroundAudio()
   // 播放当前对话语音
-  playDialogueAudio()
+  if (isPlaying.value) {
+    playDialogueAudio(true)
+  } else {
+    playDialogueAudio()
+  }
 }
 
-const playNext = () => {
+const playNext = (isAutoPlay = false) => {
   // 停止当前对话语音
   if (dialogueAudio.value) {
     dialogueAudio.value.pause()
@@ -412,23 +413,31 @@ const playNext = () => {
   
   // 如果正在进行数字人对话,调用stopStream清理
   recoverQuestDialogue()
-  stopPlayback()
+  stopPlayback(false)
   if (conversationInProgress.value) {
     stopStream()
   }
 
   if (currentSection.value && currentDialogueIndex.value < currentSection.value.dialogues.length - 1) {
     currentDialogueIndex.value++
-    // 播放当前对话语音
-    playDialogueAudio()
+    // 根据是否为自动播放状态决定如何播放语音
+    if (isPlaying.value) {
+      playDialogueAudio(true)
+    } else {
+      playDialogueAudio()
+    }
     return true
   } else if (currentSectionIndex.value < props.scriptData.sections.length - 1) {
     currentSectionIndex.value++
     currentDialogueIndex.value = 0
     // 播放背景音
     playBackgroundAudio()
-    // 播放当前对话语音
-    playDialogueAudio()
+    // 根据是否为自动播放状态决定如何播放语音
+    if (isPlaying.value) {
+      playDialogueAudio(true)
+    } else {
+      playDialogueAudio()
+    }
     return true
   }
   return false
@@ -630,10 +639,17 @@ const handleAudioPlaybackComplete = () => {
   // AI回答完成后,如果之前是播放状态,继续播放
 
   stopAllAudio();
-  // // playNext()
-  // if (isPlaying.value) {
-  //   playNext()
-  // }
+  // 如果处于自动播放状态,继续播放下一条对话
+  if (isPlaying.value) {
+    if (playNext()) {
+      // 继续自动播放序列
+      playSequence();
+    } else {
+      // 播放完毕
+      isPlaying.value = false;
+      stopAllAudio();
+    }
+  }
 };
 
 // 组件挂载时添加键盘事件监听
@@ -651,7 +667,7 @@ onMounted(() => {
 onUnmounted(() => {
   window.removeEventListener('keydown', handleKeydown)
   stopAllAudio()
-  stopPlayback()
+  stopPlayback(false)
 })
 </script>