You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter应用语音命令触发TTS重复问题的解决咨询

解决Flutter中语音命令触发TTS重复播放的问题

以下是几个针对性的解决方案,结合常见的语音识别与TTS库(如speech_to_text、flutter_tts)给出具体实现:

1. 确保语音监听真正终止

很多时候重复触发的原因是语音监听未正确停止,比如调用stopListening()时机不对,或未同步更新监听状态。

代码示例:

final SpeechToText _speech = SpeechToText();
bool _isListening = false;

void _onSpeechResult(SpeechRecognitionResult result) {
  // 收到结果后立即停止监听,避免后续重复回调
  if (_isListening) {
    _speech.stopListening();
    _isListening = false;
  }

  // 匹配朗读命令
  if (result.recognizedWords.toLowerCase().contains("朗读")) {
    _triggerTts("需要朗读的内容");
  }
}

void _startListening() async {
  // 仅在未监听状态下启动,防止重复开启
  if (!_isListening) {
    bool available = await _speech.initialize();
    if (available) {
      _isListening = true;
      // 关闭部分结果返回,避免中间识别结果触发重复逻辑
      _speech.listen(onResult: _onSpeechResult, partialResults: false);
    }
  }
}

2. 给TTS添加播放状态锁

通过全局变量标记TTS播放状态,触发前先判断是否正在播放,拦截重复请求。

代码示例:

final FlutterTts _tts = FlutterTts();
bool _isTtsPlaying = false;

void _triggerTts(String text) async {
  // 如果正在播放,直接返回
  if (_isTtsPlaying) return;

  _isTtsPlaying = true;
  await _tts.speak(text);
  
  // 监听播放完成事件,重置状态
  _tts.setCompletionHandler(() {
    _isTtsPlaying = false;
    // 如需恢复监听,可在此重新调用_startListening()
  });

  // 监听播放错误,同样重置状态
  _tts.setErrorHandler((msg) {
    _isTtsPlaying = false;
  });
}

3. 防止重复订阅语音识别事件

如果使用Stream形式接收语音结果,需确保只订阅一次,或在不需要时取消订阅,避免多次接收同一识别结果。

代码示例:

StreamSubscription<SpeechRecognitionResult>? _speechSubscription;

void _startListening() async {
  bool available = await _speech.initialize();
  if (available) {
    // 先取消之前的订阅,再重新订阅
    _speechSubscription?.cancel();
    _speechSubscription = _speech.listen(
      onResult: _onSpeechResult,
      partialResults: false
    ).listen((result) {
      // 处理识别结果
    });
  }
}

// 在页面销毁时取消订阅
@override
void dispose() {
  _speechSubscription?.cancel();
  _tts.stop();
  super.dispose();
}

4. 给命令匹配加防抖逻辑

如果语音识别短时间内返回多次相似命令,可设置时间窗口,同一命令仅执行一次。

代码示例:

DateTime? _lastCommandTime;
final Duration _debounceDuration = const Duration(seconds: 2);

void _onSpeechResult(SpeechRecognitionResult result) {
  if (_isListening) {
    _speech.stopListening();
    _isListening = false;
  }

  String command = result.recognizedWords.toLowerCase();
  if (command.contains("朗读")) {
    DateTime now = DateTime.now();
    // 判断距离上次执行是否超过防抖时间
    if (_lastCommandTime == null || now.difference(_lastCommandTime!) > _debounceDuration) {
      _triggerTts("需要朗读的内容");
      _lastCommandTime = now;
    }
  }
}

内容的提问来源于stack exchange,提问作者Uthpala Bandara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 00:50:29