|
|
|
@ -26,6 +26,7 @@ import com.deep_voice.speech.tts.TtsEventListener |
|
|
|
import com.deep_voice.speech.tts.TtsEventType |
|
|
|
import com.deep_voice.bytedance_speech.BytedanceTTS |
|
|
|
import java.util.UUID |
|
|
|
import com.yunqiinnovation.agent_service.Utils |
|
|
|
|
|
|
|
/** |
|
|
|
* 代理服务事件监听接口 |
|
|
|
@ -571,7 +572,7 @@ object AgentService : CoroutineScope { |
|
|
|
/** |
|
|
|
* 停止AI流输出 |
|
|
|
*/ |
|
|
|
private fun stopAiStream() { |
|
|
|
fun stopAiStream() { |
|
|
|
if (isAiStreaming) { |
|
|
|
try { |
|
|
|
// 先更新状态,避免回调时的状态不一致 |
|
|
|
@ -580,7 +581,8 @@ object AgentService : CoroutineScope { |
|
|
|
// 取消当前AI生成任务 |
|
|
|
currentAiJob?.cancel() |
|
|
|
currentAiJob = null |
|
|
|
|
|
|
|
currsessionId = "" //取消会话 |
|
|
|
|
|
|
|
// 通知ChatAPI服务终止当前流式请求 |
|
|
|
chatApiService.cancelCurrentStream() |
|
|
|
|
|
|
|
@ -756,9 +758,6 @@ object AgentService : CoroutineScope { |
|
|
|
responseBuilder.append(token) |
|
|
|
if (speakResponse && broadcast) { |
|
|
|
ttsService?.speakStream(token) |
|
|
|
if (token.length > 0) { |
|
|
|
audioPlayer?.stopAudio() |
|
|
|
} |
|
|
|
} |
|
|
|
if (broadcast) { |
|
|
|
// 发送流式回复token |
|
|
|
@ -774,6 +773,7 @@ object AgentService : CoroutineScope { |
|
|
|
// 视情况决定是否朗读回复 |
|
|
|
if (speakResponse && broadcast && sessionid == currsessionId){ |
|
|
|
ttsService?.flushStream() |
|
|
|
audioPlayer?.stopAudio() |
|
|
|
} |
|
|
|
val response = responseBuilder.toString() |
|
|
|
// 发送完整回复,包含是否有图片的标记 |
|
|
|
@ -1164,6 +1164,22 @@ object AgentService : CoroutineScope { |
|
|
|
class AudioPlayer(private val context: Context) { |
|
|
|
private var mediaPlayer: MediaPlayer? = null |
|
|
|
private var isInitialized = false |
|
|
|
private val playbackLock = Object() // 添加同步锁 |
|
|
|
|
|
|
|
/** |
|
|
|
* 安全检查 MediaPlayer 是否正在播放 |
|
|
|
*/ |
|
|
|
private fun isMediaPlayerPlaying(): Boolean { |
|
|
|
return try { |
|
|
|
mediaPlayer?.isPlaying == true |
|
|
|
} catch (e: IllegalStateException) { |
|
|
|
Log.w(TAG, "MediaPlayer 状态异常,假定未播放: ${e.message}") |
|
|
|
false |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "检查播放状态时发生异常: ${e.message}") |
|
|
|
false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 播放音频资源 |
|
|
|
@ -1172,75 +1188,167 @@ object AgentService : CoroutineScope { |
|
|
|
* @param volume 音量大小,范围0.0-1.0,默认1.0 |
|
|
|
*/ |
|
|
|
fun playAudio(resId: Int, isLooping: Boolean = false, volume: Float = 1.0f) { |
|
|
|
try { |
|
|
|
// 释放之前的资源 |
|
|
|
release() |
|
|
|
synchronized(playbackLock) { |
|
|
|
try { |
|
|
|
// 强制停止并释放之前的资源 |
|
|
|
forceStop() |
|
|
|
|
|
|
|
// 创建播放器并设置资源 |
|
|
|
mediaPlayer = MediaPlayer().apply { |
|
|
|
// 设置资源 |
|
|
|
context.resources.openRawResourceFd(resId)?.use { fd -> |
|
|
|
setDataSource(fd.fileDescriptor, fd.startOffset, fd.length) |
|
|
|
} |
|
|
|
// 创建播放器并设置资源 |
|
|
|
mediaPlayer = MediaPlayer().apply { |
|
|
|
// 设置资源 |
|
|
|
context.resources.openRawResourceFd(resId)?.use { fd -> |
|
|
|
setDataSource(fd.fileDescriptor, fd.startOffset, fd.length) |
|
|
|
} |
|
|
|
|
|
|
|
this.isLooping = isLooping // 设置循环属性 |
|
|
|
setVolume(volume, volume) // 设置音量(左声道,右声道) |
|
|
|
this.isLooping = isLooping // 设置循环属性 |
|
|
|
setVolume(volume, volume) // 设置音量(左声道,右声道) |
|
|
|
|
|
|
|
setOnCompletionListener { |
|
|
|
if (!isLooping) { |
|
|
|
release() |
|
|
|
setOnCompletionListener { |
|
|
|
if (!isLooping) { |
|
|
|
release() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
setOnErrorListener { _, what, extra -> |
|
|
|
Log.e(TAG, "MediaPlayer 错误: what=$what, extra=$extra") |
|
|
|
forceRelease() |
|
|
|
true // 返回true表示错误已处理 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
prepare() |
|
|
|
start() |
|
|
|
prepare() |
|
|
|
start() |
|
|
|
Log.d(TAG, "开始播放音频资源: $resId, 循环: $isLooping") |
|
|
|
} |
|
|
|
isInitialized = true |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "播放音频资源异常: ${e.message}", e) |
|
|
|
forceRelease() |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "播放音频资源异常: ${e.message}", e) |
|
|
|
release() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 停止音频播放 |
|
|
|
*/ |
|
|
|
fun stopAudio() { |
|
|
|
try { |
|
|
|
mediaPlayer?.apply { |
|
|
|
when { |
|
|
|
isPlaying -> { |
|
|
|
synchronized(playbackLock) { |
|
|
|
try { |
|
|
|
mediaPlayer?.apply { |
|
|
|
if (isMediaPlayerPlaying()) { |
|
|
|
stop() |
|
|
|
Log.d(TAG, "音频已停止") |
|
|
|
} |
|
|
|
else -> { |
|
|
|
} else { |
|
|
|
Log.d(TAG, "音频未在播放状态,无需停止") |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e: IllegalStateException) { |
|
|
|
Log.e(TAG, "MediaPlayer 状态异常,无法停止: ${e.message}", e) |
|
|
|
forceRelease() |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "停止音频播放异常: ${e.message}", e) |
|
|
|
forceRelease() |
|
|
|
} |
|
|
|
} catch (e: IllegalStateException) { |
|
|
|
Log.e(TAG, "MediaPlayer 状态异常,无法停止: ${e.message}", e) |
|
|
|
// 重置 MediaPlayer |
|
|
|
release() |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "停止音频播放异常: ${e.message}", e) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 释放资源 |
|
|
|
* 强制停止播放(不释放资源) |
|
|
|
*/ |
|
|
|
fun release() { |
|
|
|
private fun forceStop() { |
|
|
|
try { |
|
|
|
mediaPlayer?.apply { |
|
|
|
if (isPlaying) { |
|
|
|
stop() |
|
|
|
if (isMediaPlayerPlaying()) { |
|
|
|
try { |
|
|
|
stop() |
|
|
|
Log.d(TAG, "强制停止音频播放") |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "强制停止时异常: ${e.message}") |
|
|
|
} |
|
|
|
} |
|
|
|
try { |
|
|
|
reset() |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "重置时异常: ${e.message}") |
|
|
|
} |
|
|
|
reset() |
|
|
|
release() |
|
|
|
} |
|
|
|
mediaPlayer = null |
|
|
|
isInitialized = false |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "释放音频资源异常: ${e.message}", e) |
|
|
|
mediaPlayer = null |
|
|
|
isInitialized = false |
|
|
|
Log.w(TAG, "强制停止过程中异常: ${e.message}") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 释放资源 |
|
|
|
*/ |
|
|
|
fun release() { |
|
|
|
synchronized(playbackLock) { |
|
|
|
try { |
|
|
|
mediaPlayer?.apply { |
|
|
|
// 安全停止播放 |
|
|
|
if (isMediaPlayerPlaying()) { |
|
|
|
try { |
|
|
|
stop() |
|
|
|
} catch (e: IllegalStateException) { |
|
|
|
Log.w(TAG, "停止播放时状态异常: ${e.message}") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 安全重置 |
|
|
|
try { |
|
|
|
reset() |
|
|
|
} catch (e: IllegalStateException) { |
|
|
|
Log.w(TAG, "重置 MediaPlayer 时状态异常: ${e.message}") |
|
|
|
} |
|
|
|
|
|
|
|
// 安全释放 - 修复递归调用问题 |
|
|
|
try { |
|
|
|
release() // 这里调用的是 MediaPlayer.release(),不是递归 |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "释放 MediaPlayer 时异常: ${e.message}") |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "释放音频资源异常: ${e.message}", e) |
|
|
|
} finally { |
|
|
|
// 确保变量被清理 |
|
|
|
mediaPlayer = null |
|
|
|
isInitialized = false |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 强制释放资源,不进行状态检查 |
|
|
|
*/ |
|
|
|
private fun forceRelease() { |
|
|
|
synchronized(playbackLock) { |
|
|
|
try { |
|
|
|
mediaPlayer?.apply { |
|
|
|
try { |
|
|
|
reset() |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "重置 MediaPlayer 失败: ${e.message}") |
|
|
|
} |
|
|
|
try { |
|
|
|
release() |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "释放 MediaPlayer 失败: ${e.message}") |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.w(TAG, "强制释放资源时发生异常: ${e.message}") |
|
|
|
} finally { |
|
|
|
mediaPlayer = null |
|
|
|
isInitialized = false |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 检查是否正在播放 |
|
|
|
*/ |
|
|
|
fun isPlaying(): Boolean { |
|
|
|
synchronized(playbackLock) { |
|
|
|
return isMediaPlayerPlaying() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|