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
相关产品推荐
相关产品推荐

