By default The text to speech engine uses an async call, this causes the main Dart thread to go on with whatever line of code comes next, this leads up to another setstate() call after the TTS speak function which reverts the animation state from Speaking to Idle almost instantly.
is there any way to avoid this issue?
I want it to work as follows:
setstate(() => _animation = 'Speaking')
wait until the TTS is finished speaking
setstate(() => _animation = 'Idle')
If I'm misunderstanding something, could you please point it out? in case this is how Dart works then if you have any workarounds that'd be great.
Simplified code for inspection:
void _speak(String sentence) async {
updateRiveRoot(_animation = 'Speak');
setState(() => _isSpeaking = true);
if (!_isSpeaking) {
await tts.awaitSpeakCompletion(true);
tts.speak(sentence).then((result) {
if (result != null) {
print("getting here");// not being preinted out
setState(() => _isListening = false);
setState(() => _isSpeaking = false);
updateRiveRoot(_animation = 'Idle');
}
});
} else {
setState(() => _isSpeaking = true);
}
print("isSpeaking is $_isSpeaking and animation is $_animation");
}
I have scrolled through the TTS documentation but couldn't find useful information on the problem I'm currently facing.
try to use .then,
void _speak(String sentence) async {
if (!_isSpeaking) {
setState(() => _animation = 'Speak');
setState(() => _isSpeaking = true);
tts.speak(sentence).then((result) {
if (result != null) {
_isListening = false;
_isSpeaking = false;
setState((){});
}
});
}
} else {
setState(() => _isSpeaking = false);
}
}
Related
In my app I have a video running in the background.
I have a parameter page with a filepicker button which saves the path of the selected video in sharedpreferences
Future<File> _pickVideo() async {
final result = await FilePicker.platform.pickFiles(type: FileType.video);
File file = File(result!.files.single.path ?? '');
if (file != null) {
setState(() {
pickedVideo = file;
print('video $pickedVideo');
});
}
return file;}
In the video player page i retrieve the sharedpreferences path and I can display it in a Text widget
Text(selectedVideoValue ?? '',)
when I want to use it in the video player it doesn't work.
am i doing something wrong?
String? selectedVideoValue;
if (selectedVideoValue != null) {
controller = VideoPlayerController.file(File('{$selectedVideoValue}'))
..addListener(() => setState(() {}))
..initialize().then((_) {
controller.setVolume(0.0);
controller.play();
controller.setLooping(true);
setState(() {});
});
} else {
controller =
VideoPlayerController.asset("assets/movies/STYLEARCHIGRAPHIQUE.mp4")
..addListener(() => setState(() {}))
..initialize().then((_) {
controller.setVolume(0.0);
controller.play();
controller.setLooping(true);
setState(() {});
});
}
Thanks for your help
Below Code set into initState() may be working
controller = VideoPlayerController.file(File('{$selectedVideoValue}'))
..addListener(() => setState(() {}))
..initialize().then((_) {
controller.setVolume(0.0);
controller.play();
controller.setLooping(true);
setState(() {});
});
} else {
controller =
VideoPlayerController.asset("assets/movies/STYLEARCHIGRAPHIQUE.mp4")
..addListener(() => setState(() {}))
..initialize().then((_) {
controller.setVolume(0.0);
controller.play();
controller.setLooping(true);
setState(() {});
});
}```
I have provider that I build by learning from course, and there is set variables if I remove it nothing change and everything works fine but I'm afraid in future something will go error.
Here is my code:
class SimilarMovieProvider with ChangeNotifier {
List<SimilarMovieModel> _similarMovie = [];
bool _isLoading = true;
List<SimilarMovieModel> get similarMovie => _similarMovie;
bool get isLoading => _isLoading;
set similarMovie(List<SimilarMovieModel> _similarMovie) {
_similarMovie = similarMovie;
notifyListeners();
}
set isLoading(bool _isLoading) {
_isLoading = isLoading;
notifyListeners();
}
Future getSimilarMovie(movieId) async {
_isLoading = true;
try {
List<SimilarMovieModel> similarMovie =
await Http().getSimilarMovie(movieId);
_similarMovie = similarMovie;
_isLoading = false;
notifyListeners();
} catch (error) {
_isLoading = false;
notifyListeners();
print(error);
}
}
}
As far as I am concerned it doesn't change anything. You just switch from using a setter to using a method to update your instance.
So I was trying to organize my code and breaking it down into smaller functions when I discovered that a function is being skipped by Dart for some reason, if somebody is versed well with async programming; an explination for why this is happening would be appreciated.
The code:
void _converse(bool first_run) async {
first_run ? _speak("how may I help you?") : _speak("need anything else?");
sleep(Duration(seconds: 3));
await _listen();// the _listen function
sleep(Duration(seconds: 10));
first_run = false;
}
_listen() code:
Future _listen() async {
String _question = '-';
if (!_isListening) {
bool available = await _speech.initialize(
onStatus: (val) => print('onStatus: $val'),
onError: (val) => print('onError: $val'),
);
if (available) {
setState(() => _isListening = true);
_speech.listen(
onResult: (val) => setState(() {
_text = val.recognizedWords;
if (val.hasConfidenceRating && val.confidence > 0) {
_confidence = val.confidence;
}
}),
);
}
} else {
setState(() => _isListening = false);
// test placeholder
process_speech(_text);
_speech.stop();
}
}
The _listen() function which is supposed to take in speech input is being ignored.
Currently writing a flutter app using the flutter_tts library.
I have a list of sentences to read out, but currently having trouble waiting for the setCompletionHandler() to complete.
How can I wait for the setCompletionHandler() callback to complete before moving on to the next string? Currently, the TTS.speak() function finishes immediately with the while loop incrementing right away so it only reads out the last sentence in the list.
// code shortened for brevity
FlutterTts TTS;
TtsState ttsState = TtsState.stopped;
get isPlaying => ttsState == TtsState.playing;
get isStopped => ttsState == TtsState.stopped;
List<String> sentences = ['Hello, World', 'How are you?', 'The quick brown fox jumps over the lazy dog'];
#override
void initState() {
super.initState();
TTS = FlutterTts();
}
void readOutSentences(sentences) async {
int i = 0;
bool readCompleted = false;
while (i < sentences.length) {
readCompleted = await runSpeak(sentences[i].toString());
if (readCompleted)
i++;
}
}
Future<bool> runSpeak(String currentSentence) async {
TTS.setStartHandler(() {
setState(() {
ttsState = TtsState.playing;
});
});
TTS.setCompletionHandler(() {
setState(() {
ttsState = TtsState.stopped;
});
});
await TTS.speak(currentSentence);
return true;
}
readOutSentences(sentences);
Forgive about the setCompletionHandler)
You can use such async functions:
Future<void> _speak(String _text) async {
if (_text != null && _text.isNotEmpty) {
await flutterTts.awaitSpeakCompletion(true);
await flutterTts.speak(_text);
}
}
readAllSentencesList(List<String> allSentences) async {
for (int i=0; i<allSentences.length; i++){
await _speak(allSentences[i]);
}
}
Don't forget to use last flutter_tts library!
Set setCompletionHandler like following to speak all sentences of the list one by one.
List<String> sentences = ['Hello, World', 'How are you?', 'The quick brown fox jumps over the lazy dog']
int i = 0;
FlutterTts flutterTts = FlutterTts();
await flutterTts.speak(sentences[i]);
flutterTts.setCompletionHandler(() async {
if (i < sentences.length - 1) {
i++;
await flutterTts.speak(sentences[i]);
}
});
To wait for the callback use the await keyword:
await TTS.setCompletionHandler(() {
setState(() {
ttsState = TtsState.stopped;
});
});
when i run my app in debug mode it shows me the error "type 'future' is not a subtype of type 'function'" all over the screen and also in the debug console. Can someone help me? I imagine it's a problem with async functions "reset","rateoGet" and "rateoSave" but i can't find any solution.
P.S. I've deleted part of the code because it was useless for this question.
int plus;
int min;
int per;
int div;
double val;
int gameswon =0;
int moves;
static int mosse=15;
String win = "gioca";
int games=0;
double rateo=1;
String mode;
int flag;
var timer=30;
#override
void initState() {
super.initState();
reset();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:
MyButton(text: "$per" ,color: Colors.deepPurpleAccent, onTap: (){
setState(() {
val*=per;
});
if(widget.mode=="timermode" && flag==0){
timerceckresults();
}else if(widget.mode=="movesmode"){
checkResult();
}
},
MyBottomButton(text: "Reset",color: Colors.indigo,width:160, onTap: reset()),
),
}
checkResult() {
if(val == 101) {
print("hai vinto");
win="Hai Vinto";
setState(() {});
gameswon++;
Timer(Duration(seconds: 2), () {
reset();
});
} else {
print("ci sei quasi");
moves++;
mosse--;
win="$mosse moves left";
setState(() {});
if(moves>14){
print("hai perso coglione");
win="Hai Perso Coglione";
setState(() {});
Timer(Duration(seconds: 2), () {
reset();
});
}
}
}
timerceckresults(){
flag=1;
timer = 30;
Timer.periodic(Duration(seconds: 1), (t){
timer--;
setState(() {
win = "${timer.toString()}seconds left";
});
if(val==101){
timer=0;
}
if(timer == 0) {
t.cancel();
if(val == 101) {
win="Hai Vinto";
setState(() {});
gameswon++;
Timer(Duration(seconds: 2), () {
reset();
});
} else {
win="Hai Perso Coglione";
setState(() {});
Timer(Duration(seconds: 2), () {
reset();
});
}
}
});
static int randNum(x,y) {
var rng = new Random();
return rng.nextInt(y-x)+x;
}
reset() async{
timer=1;
plus = randNum(4, 9);
min = randNum(5, 19);
per = randNum(3, 9);
div = randNum(2, 5);
val = randNum(2, 11).toDouble();
moves = 0;
mosse=15;
if(widget.mode=="timermode"){
win="start playing";
}else{
win="$mosse moves left";
}
await rateoSave();
await rateoGet();
games++;
rateo=gameswon/(games-1);
await rateoSave();
flag=0;
setState(() {});
}
rateoSave() async {
SharedPreferences prefs=await SharedPreferences.getInstance();
await prefs.setInt("games",games);
await prefs.setInt("gameswon",gameswon);
}
rateoGet() async {
SharedPreferences prefs=await SharedPreferences.getInstance();
games=(prefs.getInt("games") ?? 0);
gameswon=(prefs.getInt("gameswon") ?? 0);
https://dart.dev/codelabs/async-await read this before you check the answer will help you alot
reset() async{
timer=1;
plus = randNum(4, 9);
min = randNum(5, 19);
per = randNum(3, 9);
div = randNum(2, 5);
val = randNum(2, 11).toDouble();
moves = 0;
mosse=15;
if(widget.mode=="timermode"){
win="start playing";
}else{
win="$mosse moves left";
}
await rateoSave();
await rateoGet();
games++;
rateo=gameswon/(games-1);
await rateoSave();
flag=0;
setState(() {});
}
Future<bool> rateoSave() {
SharedPreferences prefs= SharedPreferences.getInstance();
prefs.setInt("games",games);
prefs.setInt("gameswon",gameswon);
return true;
}
Future<bool> rateoGet() async {
SharedPreferences prefs= SharedPreferences.getInstance();
await games=(prefs.getInt("games") ?? 0);
await gameswon=(prefs.getInt("gameswon") ?? 0);
return true;
}
you are trying to get a variable from a method that returns a future. you need to add await just before you make the call to that function.
can you tell us in which line this error occurs ?
The most important thing to keep in mind is that if anything in your call-chain returns a Future, everything above it must deal with futures, either by returning the future itself (if no processing must be done), or await'ing and dealing with the returned value (but you'll still be returning a future).