82 lines
2.0 KiB
Dart
82 lines
2.0 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter_tts/flutter_tts.dart';
|
|
import 'package:mymuseum_visitapp/Services/Glasses/engines/tts_engine.dart';
|
|
|
|
/// TTS on-device via Google (Android) / AVSpeechSynthesizer (iOS).
|
|
/// Gratuit, pas de latence réseau, supporte FR/NL/EN/DE.
|
|
class FlutterTtsEngine implements TtsEngine {
|
|
final FlutterTts _tts = FlutterTts();
|
|
bool _speaking = false;
|
|
String? _lastText;
|
|
String? _lastLang;
|
|
Completer<void>? _completer;
|
|
|
|
FlutterTtsEngine() {
|
|
_tts.setStartHandler(() {
|
|
_speaking = true;
|
|
});
|
|
_tts.setCompletionHandler(() {
|
|
_speaking = false;
|
|
_completer?.complete();
|
|
_completer = null;
|
|
});
|
|
_tts.setCancelHandler(() {
|
|
_speaking = false;
|
|
_completer?.complete();
|
|
_completer = null;
|
|
});
|
|
_tts.setErrorHandler((msg) {
|
|
_speaking = false;
|
|
_completer?.completeError(msg);
|
|
_completer = null;
|
|
});
|
|
}
|
|
|
|
@override
|
|
bool get isSpeaking => _speaking;
|
|
|
|
@override
|
|
Future<void> speak(String text, {String languageCode = 'fr-FR'}) async {
|
|
if (text.isEmpty) return;
|
|
_lastText = text;
|
|
_lastLang = languageCode;
|
|
|
|
try {
|
|
await _tts.stop();
|
|
await _tts.setLanguage(languageCode);
|
|
await _tts.setSpeechRate(0.45);
|
|
await _tts.setVolume(1.0);
|
|
await _tts.setPitch(1.0);
|
|
|
|
_completer = Completer<void>();
|
|
await _tts.speak(text);
|
|
|
|
// Attend la vraie fin de la synthèse
|
|
await _completer!.future.timeout(
|
|
const Duration(seconds: 30),
|
|
onTimeout: () {},
|
|
);
|
|
} catch (e) {
|
|
debugPrint('[FlutterTtsEngine] speak error: $e');
|
|
} finally {
|
|
_speaking = false;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> stop() async {
|
|
await _tts.stop();
|
|
_speaking = false;
|
|
_completer?.complete();
|
|
_completer = null;
|
|
}
|
|
|
|
@override
|
|
Future<void> replay() async {
|
|
if (_lastText != null) {
|
|
await speak(_lastText!, languageCode: _lastLang ?? 'fr-FR');
|
|
}
|
|
}
|
|
}
|