Browse Source

优化按住说话

weicu
fdp 1 year ago
parent
commit
3082a0df1c
  1. 4
      lib/data/services/music_manager.dart
  2. 88
      lib/modules/agent/controllers/agent_controller.dart
  3. 12
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  4. 18
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt
  5. 2
      local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt
  6. 6
      local_plugins/music_service/lib/music_service.dart

4
lib/data/services/music_manager.dart

@ -105,7 +105,7 @@ class MusicManager extends GetxService {
required Function() onPrevious, required Function() onPrevious,
required Function(int) onSeekTo, required Function(int) onSeekTo,
required Function() onStop, required Function() onStop,
required Function(int, int, int, double) onStop1, required Function(int, int, int, double) onProgress,
}) async { }) async {
try { try {
await _musicService.setMediaSessionCallbacks( await _musicService.setMediaSessionCallbacks(
@ -115,7 +115,7 @@ class MusicManager extends GetxService {
onPrevious: onPrevious, onPrevious: onPrevious,
onSeekTo: onSeekTo, onSeekTo: onSeekTo,
onStop: onStop, onStop: onStop,
onStop1: onStop1, onProgress: onProgress,
); );
} catch (e) { } catch (e) {
Logger.d('MusicManager', '设置媒体会话回调失败: $e'); Logger.d('MusicManager', '设置媒体会话回调失败: $e');

88
lib/modules/agent/controllers/agent_controller.dart

@ -165,7 +165,7 @@ class AgentController extends GetxController {
onPrevious: onMediaSessionPrevious, onPrevious: onMediaSessionPrevious,
onSeekTo: onMediaSessionSeekTo, onSeekTo: onMediaSessionSeekTo,
onStop: onMediaSessionStop, onStop: onMediaSessionStop,
onStop1: onMediaSessionSeekTo1, onProgress: onMediaSessionProgress,
); );
Logger.d('AgentController', '媒体会话回调设置完成'); Logger.d('AgentController', '媒体会话回调设置完成');
} catch (e) { } catch (e) {
@ -1307,7 +1307,6 @@ class AgentController extends GetxController {
// 设置按住说话状态 // 设置按住说话状态
isPushToTalkActive.value = true; isPushToTalkActive.value = true;
print("开始按住说话,状态已设置为true");
// 开始语音识别 // 开始语音识别
await AgentService.audioContinue(); await AgentService.audioContinue();
// await startVoiceInput(); // await startVoiceInput();
@ -1406,9 +1405,6 @@ class AgentController extends GetxController {
await _updateMediaSessionMetadata(musicData); await _updateMediaSessionMetadata(musicData);
await _updateMediaSessionPlaybackState(true); await _updateMediaSessionPlaybackState(true);
// 启动进度定时器
_startProgressTimer();
Logger.d(TAG, '音乐播放启动成功'); Logger.d(TAG, '音乐播放启动成功');
} catch (e) { } catch (e) {
Logger.e(TAG, '播放音乐失败: $e'); Logger.e(TAG, '播放音乐失败: $e');
@ -1439,7 +1435,6 @@ class AgentController extends GetxController {
Logger.d('AgentController', '恢复播放音乐'); Logger.d('AgentController', '恢复播放音乐');
await _musiceManager.resume(); await _musiceManager.resume();
isPlaying.value = true; isPlaying.value = true;
_startProgressTimer();
// 更新媒体会话播放状态 // 更新媒体会话播放状态
await _updateMediaSessionPlaybackState(true); await _updateMediaSessionPlaybackState(true);
@ -1451,23 +1446,6 @@ class AgentController extends GetxController {
} }
} }
// 启动进度更新定时器
void _startProgressTimer() {
_stopProgressTimer(); // 先停止现有定时器
Logger.d('AgentController', '启动播放进度定时器');
_progressTimer = Timer.periodic(const Duration(milliseconds: 500), (timer) {
if (isPlaying.value && currentId.value != 0) {
updateMusicProgress();
} else if (!isPlaying.value) {
// 如果不在播放状态,停止定时器
timer.cancel();
_progressTimer = null;
Logger.d('AgentController', '播放已停止,取消进度定时器');
}
});
}
// 停止进度更新定时器 // 停止进度更新定时器
void _stopProgressTimer() { void _stopProgressTimer() {
if (_progressTimer != null) { if (_progressTimer != null) {
@ -1478,45 +1456,7 @@ class AgentController extends GetxController {
} }
// 获取播放进度 // 获取播放进度
Future<void> updateMusicProgress() async { Future<void> updateMusicProgress(int currentIdInternal, int newPosition,
try {
if (!isPlaying.value || currentId.value == 0) {
return; // 如果没有在播放,直接返回
}
// var progressInfo = await _musiceManager.getProgress();
// final newPosition = progressInfo['currentPosition'] ?? 0;
// final newDuration = progressInfo['duration'] ?? 0;
// final newProgress = progressInfo['progress'] ?? 0.0;
// bool hasUpdate = false;
// // 只有当值发生变化时才更新,避免不必要的UI刷新
// if (currentPosition.value != newPosition) {
// currentPosition.value = newPosition;
// hasUpdate = true;
// }
// if (duration.value != newDuration) {
// duration.value = newDuration;
// hasUpdate = true;
// }
// if ((progress.value - newProgress).abs() > 0.001) {
// // 避免浮点数精度问题
// progress.value = newProgress;
// hasUpdate = true;
// }
// 如果有进度更新,通知系统媒体会话更新进度信息
// if (hasUpdate) {
// await _updateMediaSessionProgress();
// }
} catch (e) {
Logger.e('AgentController', '获取播放进度失败: $e');
}
}
// 获取播放进度
Future<void> updateMusicProgress1(int currentIdInternal, int newPosition,
int newDuration, double newProgress) async { int newDuration, double newProgress) async {
try { try {
if (currentIdInternal != 0) { if (currentIdInternal != 0) {
@ -1524,12 +1464,6 @@ class AgentController extends GetxController {
// return; // 如果没有在播放,直接返回 // return; // 如果没有在播放,直接返回
} }
// // var progressInfo = await _musiceManager.getProgress();
// final newPosition = progressInfo['currentPosition'] ?? 0;
// final newDuration = progressInfo['duration'] ?? 0;
// final newProgress = progressInfo['progress'] ?? 0.0;
// print(
// "updateMusicProgress1:currentIdInternal:$currentIdInternal newPosition:$newPosition newDuration:$newDuration newProgress:$newProgress");
bool hasUpdate = false; bool hasUpdate = false;
if (currentId.value != currentIdInternal) { if (currentId.value != currentIdInternal) {
currentId.value = currentIdInternal; currentId.value = currentIdInternal;
@ -1597,20 +1531,17 @@ class AgentController extends GetxController {
Future<void> seekToPosition(int positionMs) async { Future<void> seekToPosition(int positionMs) async {
try { try {
await _musiceManager.seekTo(positionMs); await _musiceManager.seekTo(positionMs);
// 立即更新进度状态
// await updateMusicProgress();
} catch (e) { } catch (e) {
Logger.e('AgentController', '跳转播放位置失败: $e'); Logger.e('AgentController', '跳转播放位置失败: $e');
} }
} }
// 跳转到指定位置 // 跳转到指定位置
Future<void> seekToPosition1(int currentIdInternal, int newPosition, Future<void> seekToProgress(int currentIdInternal, int newPosition,
int newDuration, double newProgress) async { int newDuration, double newProgress) async {
try { try {
//await _musiceManager.seekTo(positionMs);
// 立即更新进度状态 // 立即更新进度状态
await updateMusicProgress1( await updateMusicProgress(
currentIdInternal, newPosition, newDuration, newProgress); currentIdInternal, newPosition, newDuration, newProgress);
} catch (e) { } catch (e) {
Logger.e('AgentController', '跳转播放位置失败: $e'); Logger.e('AgentController', '跳转播放位置失败: $e');
@ -1700,9 +1631,6 @@ class AgentController extends GetxController {
currentId.value = formattedPlaylist[0]['id'] ?? 0; currentId.value = formattedPlaylist[0]['id'] ?? 0;
} }
// 启动进度定时器
_startProgressTimer();
Logger.d(TAG, '音乐列表播放启动成功'); Logger.d(TAG, '音乐列表播放启动成功');
} catch (e) { } catch (e) {
Logger.e(TAG, '播放音乐列表失败: $e'); Logger.e(TAG, '播放音乐列表失败: $e');
@ -1831,12 +1759,12 @@ class AgentController extends GetxController {
_stopProgressTimer(); _stopProgressTimer();
} }
/// 处理来自系统通知栏的跳转操作 /// 处理来自系统进度条
Future<void> onMediaSessionSeekTo1(int currentIdInternal, int newPosition, Future<void> onMediaSessionProgress(int currentIdInternal, int newPosition,
int newDuration, double newProgress) async { int newDuration, double newProgress) async {
// print( // print(
// "onMediaSessionSeekTo1 currentIdInternal :$currentIdInternal ,newPosition:$newPosition newDuration:$newDuration newProgress:$newProgress"); // "onMediaSessionProgress currentIdInternal :$currentIdInternal ,newPosition:$newPosition newDuration:$newDuration newProgress:$newProgress");
await seekToPosition1( await seekToProgress(
currentIdInternal, newPosition, newDuration, newProgress); currentIdInternal, newPosition, newDuration, newProgress);
} }
} }

12
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt

@ -352,7 +352,6 @@ object AgentService : CoroutineScope {
*/ */
private fun startIdleCheck() { private fun startIdleCheck() {
stopIdleCheck() // 先停止现有的检查 stopIdleCheck() // 先停止现有的检查
Log.d(TAG, "启动空闲检测: ${isRecognitionActive}")
if (!isRecognitionActive) return if (!isRecognitionActive) return
idleCheckJob = launch { idleCheckJob = launch {
@ -360,7 +359,6 @@ object AgentService : CoroutineScope {
delay(maxIdleSeconds * 1000L) delay(maxIdleSeconds * 1000L)
if (isActive && isRecognitionActive && !hasSpeechDetected && !isTtsSpeaking && !isAiStreaming) { if (isActive && isRecognitionActive && !hasSpeechDetected && !isTtsSpeaking && !isAiStreaming) {
Log.d(TAG, "启动空闲检测: stopRecognition")
//stopRecognition() //stopRecognition()
sendEvent("auto_stop", mapOf("reason" to "idle_timeout", "seconds" to maxIdleSeconds)) sendEvent("auto_stop", mapOf("reason" to "idle_timeout", "seconds" to maxIdleSeconds))
} }
@ -398,14 +396,12 @@ object AgentService : CoroutineScope {
Log.d(TAG, "服务未初始化") Log.d(TAG, "服务未初始化")
return false return false
} }
Log.d(TAG, "麦克风音频未暂停,无法设置${azureAsrHelper!!.isPaused},$isExternalActive")
if(!(azureAsrHelper!!.isPaused)&&isExternalActive) if(!(azureAsrHelper!!.isPaused)&&isExternalActive)
{ {
Log.d(TAG, "麦克风音频未暂停,无法设置") Log.d(TAG, "麦克风音频未暂停,无法设置")
BleService.closeCodec() BleService.closeCodec()
return false return false
} }
Log.d(TAG, "开始语音识别")
if (isRecognitionActive) return true if (isRecognitionActive) return true
// 检查录音权限 // 检查录音权限
@ -499,14 +495,13 @@ object AgentService : CoroutineScope {
_isRecognitionActive.set(false) _isRecognitionActive.set(false)
stopIdleCheck() stopIdleCheck()
Log.d(TAG, "onSessionStopped")
audioPlayer?.playAudio(R.raw.stop) audioPlayer?.playAudio(R.raw.stop)
} }
override fun onCanceled(reason: String, errorDetails: String) { override fun onCanceled(reason: String, errorDetails: String) {
_isRecognitionActive.set(false) _isRecognitionActive.set(false)
stopIdleCheck() stopIdleCheck()
Log.d(TAG, "recognition_canceled")
BleService.closeCodec() BleService.closeCodec()
sendEvent("recognition_canceled", mapOf( sendEvent("recognition_canceled", mapOf(
"reason" to reason, "reason" to reason,
@ -517,7 +512,7 @@ object AgentService : CoroutineScope {
override fun onError(error: String) { override fun onError(error: String) {
_isRecognitionActive.set(false) _isRecognitionActive.set(false)
stopIdleCheck() stopIdleCheck()
Log.d(TAG, "error")
BleService.closeCodec() BleService.closeCodec()
Log.e(TAG, "语音识别错误: $error") Log.e(TAG, "语音识别错误: $error")
sendEvent("error", mapOf( sendEvent("error", mapOf(
@ -549,7 +544,6 @@ object AgentService : CoroutineScope {
try { try {
azureAsrHelper?.stopContinuousRecognition() azureAsrHelper?.stopContinuousRecognition()
Log.d(TAG, "停止语音识别")
BleService.closeCodec() BleService.closeCodec()
_isRecognitionActive.set(false) _isRecognitionActive.set(false)
stopIdleCheck() stopIdleCheck()
@ -569,7 +563,7 @@ object AgentService : CoroutineScope {
try { try {
if(audioSourceType== AzureAsrHelper.AudioSourceType.EXTERNAL) if(audioSourceType== AzureAsrHelper.AudioSourceType.EXTERNAL)
{ {
Log.d(TAG, "当前是什么输入:$audioSourceType")
BleService.closeCodec() BleService.closeCodec()
stopRecognition() stopRecognition()
startRecognition(false) startRecognition(false)

18
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt

@ -458,9 +458,12 @@ class AzureAsrHelper(private val context: Context) {
EventHandler<SessionEventArgs> { _, _ -> EventHandler<SessionEventArgs> { _, _ ->
// 直接在当前线程调用回调 // 直接在当前线程调用回调
Log.d(tag, "会话结束事件") Log.d(tag, "会话结束事件")
if (audioSourceType == AudioSourceType.EXTERNAL) {
callback.onSessionStopped() callback.onSessionStopped()
isContinuousRecognitionActive = false isContinuousRecognitionActive = false
stopAudioProcessing() stopAudioProcessing()
}
} }
) )
@ -633,7 +636,12 @@ class AzureAsrHelper(private val context: Context) {
Log.d(tag, "关闭麦克风stopAudioPause: ") Log.d(tag, "关闭麦克风stopAudioPause: ")
// 清理旧的识别器 // 清理旧的识别器
isPaused = true isPaused = true
// 如果正在进行连续识别,先停止
if (isContinuousRecognitionActive) {
// 直接停止,不等待结果
recognizer?.stopContinuousRecognitionAsync()
isContinuousRecognitionActive = false
}
} }
@ -642,9 +650,15 @@ class AzureAsrHelper(private val context: Context) {
*/ */
fun audioContinue() { fun audioContinue() {
Log.d(tag, "继续麦克风stopAudioPause: ") Log.d(tag, "继续麦克风stopAudioPause: ")
// 如果正在进行连续识别,先停止
if (!isContinuousRecognitionActive) {
// 直接停止,不等待结果
recognizer?.startContinuousRecognitionAsync()
isContinuousRecognitionActive = true
}
// 开始连续识别 // 开始连续识别
isPaused = false isPaused = false
} }
/** /**

2
local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt

@ -216,7 +216,7 @@ private fun updateProgress() {
// 更新媒体会话进度 // 更新媒体会话进度
// 通知Flutter层 // 通知Flutter层
flutterChannel?.invokeMethod("onMediaSessionSeekTo1", mapOf( flutterChannel?.invokeMethod("onMediaSessionProgress", mapOf(
"currentIdInternal" to currentIdInternal, "currentIdInternal" to currentIdInternal,
"currentPosition" to currentPosition, "currentPosition" to currentPosition,
"duration" to duration, "duration" to duration,

6
local_plugins/music_service/lib/music_service.dart

@ -103,7 +103,7 @@ class MusicService {
required Function() onPrevious, required Function() onPrevious,
required Function(int) onSeekTo, required Function(int) onSeekTo,
required Function() onStop, required Function() onStop,
required Function(int, int, int, double) onStop1, required Function(int, int, int, double) onProgress,
}) async { }) async {
// 设置方法调用处理器来处理来自原生平台的回调 // 设置方法调用处理器来处理来自原生平台的回调
_methodChannel.setMethodCallHandler((call) async { _methodChannel.setMethodCallHandler((call) async {
@ -127,12 +127,12 @@ class MusicService {
case 'onMediaSessionStop': case 'onMediaSessionStop':
onStop(); onStop();
break; break;
case 'onMediaSessionSeekTo1': case 'onMediaSessionProgress':
final currentIdInternal = call.arguments['currentIdInternal'] as int; final currentIdInternal = call.arguments['currentIdInternal'] as int;
final currentPosition = call.arguments['currentPosition'] as int; final currentPosition = call.arguments['currentPosition'] as int;
final duration = call.arguments['duration'] as int; final duration = call.arguments['duration'] as int;
final progress = call.arguments['progress'] as double; final progress = call.arguments['progress'] as double;
onStop1(currentIdInternal, currentPosition, duration, progress); onProgress(currentIdInternal, currentPosition, duration, progress);
break; break;
} }
}); });

Loading…
Cancel
Save