From 02593af32bce208db878d60b9f48d5486c05fa86 Mon Sep 17 00:00:00 2001 From: Ievgenii Kovtun Date: Mon, 19 Jun 2023 02:20:20 +0200 Subject: [PATCH 1/5] Add setPauseFor method for late setup --- speech_to_text/lib/speech_to_text.dart | 12 +++++ speech_to_text/test/speech_to_text_test.dart | 54 ++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/speech_to_text/lib/speech_to_text.dart b/speech_to_text/lib/speech_to_text.dart index f1d1f3de..646dfe77 100644 --- a/speech_to_text/lib/speech_to_text.dart +++ b/speech_to_text/lib/speech_to_text.dart @@ -435,6 +435,16 @@ class SpeechToText { throw ListenFailedException(e.message, e.details, e.stacktrace); } } + void setPauseFor(Duration pauseFor) { + //Setup new pauseFor only if listen is active and pauseFor is different + if ((_listenTimer?.isActive ?? false) && (_pauseFor == null || _pauseFor!.compareTo(pauseFor) != 0)) { + _listenTimer?.cancel(); + _listenTimer = null; + _setupListenAndPause(pauseFor, _listenFor); + } else { + throw ListenNotStartedException(); + } + } void _setupListenAndPause( Duration? initialPauseFor, Duration? initialListenFor) { @@ -658,3 +668,5 @@ class ListenFailedException implements Exception { final String? stackTrace; ListenFailedException(this.message, [this.details, this.stackTrace]); } + +class ListenNotStartedException implements Exception {} diff --git a/speech_to_text/test/speech_to_text_test.dart b/speech_to_text/test/speech_to_text_test.dart index b2bf4698..fd741a9d 100644 --- a/speech_to_text/test/speech_to_text_test.dart +++ b/speech_to_text/test/speech_to_text_test.dart @@ -187,6 +187,60 @@ void main() { expect(speech.isListening, isTrue); }); }); + test('trows on setPauseFor when not listening', () async { + fakeAsync((fa) { + speech.initialize(); + fa.flushMicrotasks(); + testPlatform.onStatus!(SpeechToText.notListeningStatus); + fa.flushMicrotasks(); + expect(speech.isListening, isFalse); + try { + speech.setPauseFor(Duration(seconds: 5)); + fail('Should have thrown'); + } on ListenNotStartedException { + // This is a good result + } catch (wrongE) { + fail('Should have been ListenNotStartedException'); + } + }); + }); + test('stops listen after late setPauseFor with no speech', () async { + fakeAsync((fa) { + speech.initialize(); + fa.flushMicrotasks(); + speech.listen(pauseFor: Duration(seconds: 2)); + testPlatform.onStatus!(SpeechToText.listeningStatus); + fa.flushMicrotasks(); + expect(speech.isListening, isTrue); + fa.elapse(Duration(seconds: 1)); + speech.setPauseFor(Duration(seconds: 5)); + fa.flushMicrotasks(); + fa.elapse(Duration(seconds: 3)); + expect(speech.isListening, isTrue); + fa.elapse(Duration(seconds: 2)); + expect(speech.isListening, isFalse); + }); + }); + test('keeps listening after late setPauseFor with speech event', () async { + fakeAsync((fa) { + speech.initialize(); + fa.flushMicrotasks(); + speech.listen(pauseFor: Duration(seconds: 2)); + testPlatform.onStatus!(SpeechToText.listeningStatus); + fa.flushMicrotasks(); + fa.elapse(Duration(seconds: 1)); + expect(speech.isListening, isTrue); + speech.setPauseFor(Duration(seconds: 5)); + fa.flushMicrotasks(); + fa.elapse(Duration(seconds: 3)); + expect(speech.isListening, isTrue); + testPlatform + .onTextRecognition!(TestSpeechChannelHandler.firstRecognizedJson); + fa.flushMicrotasks(); + fa.elapse(Duration(seconds: 3)); + expect(speech.isListening, isTrue); + }); + }); test('creates finalResult true if none provided', () async { fakeAsync((fa) { speech.initialize(finalTimeout: Duration(milliseconds: 100)); From 3085ade1159bf133c6717fce49b094602a9fc2dd Mon Sep 17 00:00:00 2001 From: Ievgenii Kovtun Date: Mon, 19 Jun 2023 18:26:44 +0200 Subject: [PATCH 2/5] Add setPauseFor method for late setup. Rename method to changePauseFor. --- speech_to_text/lib/speech_to_text.dart | 2 +- speech_to_text/test/speech_to_text_test.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/speech_to_text/lib/speech_to_text.dart b/speech_to_text/lib/speech_to_text.dart index 646dfe77..22f92db4 100644 --- a/speech_to_text/lib/speech_to_text.dart +++ b/speech_to_text/lib/speech_to_text.dart @@ -435,7 +435,7 @@ class SpeechToText { throw ListenFailedException(e.message, e.details, e.stacktrace); } } - void setPauseFor(Duration pauseFor) { + void changePauseFor(Duration pauseFor) { //Setup new pauseFor only if listen is active and pauseFor is different if ((_listenTimer?.isActive ?? false) && (_pauseFor == null || _pauseFor!.compareTo(pauseFor) != 0)) { _listenTimer?.cancel(); diff --git a/speech_to_text/test/speech_to_text_test.dart b/speech_to_text/test/speech_to_text_test.dart index fd741a9d..46a2d42e 100644 --- a/speech_to_text/test/speech_to_text_test.dart +++ b/speech_to_text/test/speech_to_text_test.dart @@ -195,7 +195,7 @@ void main() { fa.flushMicrotasks(); expect(speech.isListening, isFalse); try { - speech.setPauseFor(Duration(seconds: 5)); + speech.changePauseFor(Duration(seconds: 5)); fail('Should have thrown'); } on ListenNotStartedException { // This is a good result @@ -213,7 +213,7 @@ void main() { fa.flushMicrotasks(); expect(speech.isListening, isTrue); fa.elapse(Duration(seconds: 1)); - speech.setPauseFor(Duration(seconds: 5)); + speech.changePauseFor(Duration(seconds: 5)); fa.flushMicrotasks(); fa.elapse(Duration(seconds: 3)); expect(speech.isListening, isTrue); @@ -230,7 +230,7 @@ void main() { fa.flushMicrotasks(); fa.elapse(Duration(seconds: 1)); expect(speech.isListening, isTrue); - speech.setPauseFor(Duration(seconds: 5)); + speech.changePauseFor(Duration(seconds: 5)); fa.flushMicrotasks(); fa.elapse(Duration(seconds: 3)); expect(speech.isListening, isTrue); From 2a8700cdff9e1e9682c32334fe622e40fb86b79a Mon Sep 17 00:00:00 2001 From: Ievgenii Kovtun Date: Mon, 19 Jun 2023 20:34:00 +0200 Subject: [PATCH 3/5] Add chengePauseFor method for late setup. Fix conditions for reload timer. Fix counting delta time for last speach event. --- speech_to_text/lib/speech_to_text.dart | 10 +++++--- speech_to_text/test/speech_to_text_test.dart | 25 +++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/speech_to_text/lib/speech_to_text.dart b/speech_to_text/lib/speech_to_text.dart index 22f92db4..721dceff 100644 --- a/speech_to_text/lib/speech_to_text.dart +++ b/speech_to_text/lib/speech_to_text.dart @@ -437,12 +437,16 @@ class SpeechToText { } void changePauseFor(Duration pauseFor) { //Setup new pauseFor only if listen is active and pauseFor is different - if ((_listenTimer?.isActive ?? false) && (_pauseFor == null || _pauseFor!.compareTo(pauseFor) != 0)) { + if(isNotListening) { + throw ListenNotStartedException(); + } + + if (_pauseFor == null || _pauseFor!.compareTo(pauseFor) != 0) { _listenTimer?.cancel(); _listenTimer = null; + //Reset _lastSpeechEventAt for new pauseFor duration will count from now but not from start of listen + _lastSpeechEventAt = clock.now().millisecondsSinceEpoch; _setupListenAndPause(pauseFor, _listenFor); - } else { - throw ListenNotStartedException(); } } diff --git a/speech_to_text/test/speech_to_text_test.dart b/speech_to_text/test/speech_to_text_test.dart index 46a2d42e..7dbd066c 100644 --- a/speech_to_text/test/speech_to_text_test.dart +++ b/speech_to_text/test/speech_to_text_test.dart @@ -187,7 +187,7 @@ void main() { expect(speech.isListening, isTrue); }); }); - test('trows on setPauseFor when not listening', () async { + test('trows on changePauseFor when not listening', () async { fakeAsync((fa) { speech.initialize(); fa.flushMicrotasks(); @@ -204,7 +204,7 @@ void main() { } }); }); - test('stops listen after late setPauseFor with no speech', () async { + test('stops listen after late changePauseFor with no speech', () async { fakeAsync((fa) { speech.initialize(); fa.flushMicrotasks(); @@ -221,7 +221,7 @@ void main() { expect(speech.isListening, isFalse); }); }); - test('keeps listening after late setPauseFor with speech event', () async { + test('keeps listening after late changePauseFor with speech event', () async { fakeAsync((fa) { speech.initialize(); fa.flushMicrotasks(); @@ -257,6 +257,25 @@ void main() { expect(listener.results.last.finalResult, isTrue); }); }); + test('Stop listen after late changePauseFor without initial pauseFor', () async { + fakeAsync((fa) { + speech.initialize(); + fa.flushMicrotasks(); + speech.listen(); + testPlatform.onStatus!(SpeechToText.listeningStatus); + fa.flushMicrotasks(); + fa.elapse(Duration(seconds: 5)); + expect(speech.isListening, isTrue); + fa.elapse(Duration(seconds: 1)); + speech.changePauseFor(Duration(seconds: 5)); + fa.elapse(Duration(seconds: 3)); + fa.flushMicrotasks(); + expect(speech.isListening, isTrue); + fa.elapse(Duration(seconds: 2)); + fa.flushMicrotasks(); + expect(speech.isListening, isFalse); + }); + }); test('respects finalTimeout', () async { fakeAsync((fa) { speech.initialize(finalTimeout: Duration(seconds: 0)); From 4c934f60d5f92ae6e7b78c9e6ccd730d28380a9a Mon Sep 17 00:00:00 2001 From: Ievgenii Kovtun Date: Mon, 19 Jun 2023 21:28:25 +0200 Subject: [PATCH 4/5] Add chengePauseFor method for late setup. Rearange tests. --- speech_to_text/test/speech_to_text_test.dart | 32 ++++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/speech_to_text/test/speech_to_text_test.dart b/speech_to_text/test/speech_to_text_test.dart index 7dbd066c..eab576e8 100644 --- a/speech_to_text/test/speech_to_text_test.dart +++ b/speech_to_text/test/speech_to_text_test.dart @@ -241,22 +241,6 @@ void main() { expect(speech.isListening, isTrue); }); }); - test('creates finalResult true if none provided', () async { - fakeAsync((fa) { - speech.initialize(finalTimeout: Duration(milliseconds: 100)); - fa.flushMicrotasks(); - speech.listen( - pauseFor: Duration(seconds: 2), onResult: listener.onSpeechResult); - fa.flushMicrotasks(); - testPlatform - .onTextRecognition!(TestSpeechChannelHandler.firstRecognizedJson); - fa.flushMicrotasks(); - // 2200 because it is the 2 second duration of the pauseFor then - // 100 milliseconds to create the synthetic result - fa.elapse(Duration(milliseconds: 2100)); - expect(listener.results.last.finalResult, isTrue); - }); - }); test('Stop listen after late changePauseFor without initial pauseFor', () async { fakeAsync((fa) { speech.initialize(); @@ -276,6 +260,22 @@ void main() { expect(speech.isListening, isFalse); }); }); + test('creates finalResult true if none provided', () async { + fakeAsync((fa) { + speech.initialize(finalTimeout: Duration(milliseconds: 100)); + fa.flushMicrotasks(); + speech.listen( + pauseFor: Duration(seconds: 2), onResult: listener.onSpeechResult); + fa.flushMicrotasks(); + testPlatform + .onTextRecognition!(TestSpeechChannelHandler.firstRecognizedJson); + fa.flushMicrotasks(); + // 2200 because it is the 2 second duration of the pauseFor then + // 100 milliseconds to create the synthetic result + fa.elapse(Duration(milliseconds: 2100)); + expect(listener.results.last.finalResult, isTrue); + }); + }); test('respects finalTimeout', () async { fakeAsync((fa) { speech.initialize(finalTimeout: Duration(seconds: 0)); From 0fa2e449e7312d820dcf60da3453f9fd5d763757 Mon Sep 17 00:00:00 2001 From: Ievgenii Kovtun Date: Tue, 20 Jun 2023 22:01:56 +0200 Subject: [PATCH 5/5] Add chengePauseFor method for late setup. Add ignoreElapsedPause arg for _setupListenAndPause --- speech_to_text/lib/speech_to_text.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/speech_to_text/lib/speech_to_text.dart b/speech_to_text/lib/speech_to_text.dart index 721dceff..13195dcc 100644 --- a/speech_to_text/lib/speech_to_text.dart +++ b/speech_to_text/lib/speech_to_text.dart @@ -444,14 +444,13 @@ class SpeechToText { if (_pauseFor == null || _pauseFor!.compareTo(pauseFor) != 0) { _listenTimer?.cancel(); _listenTimer = null; - //Reset _lastSpeechEventAt for new pauseFor duration will count from now but not from start of listen - _lastSpeechEventAt = clock.now().millisecondsSinceEpoch; - _setupListenAndPause(pauseFor, _listenFor); + //Ignore elapsed pause for prevent immediately stop listen + _setupListenAndPause(pauseFor, _listenFor, ignoreElapsedPause: true); } } void _setupListenAndPause( - Duration? initialPauseFor, Duration? initialListenFor) { + Duration? initialPauseFor, Duration? initialListenFor, {bool ignoreElapsedPause = false}) { _pauseFor = null; _listenFor = null; if (null == initialPauseFor && null == initialListenFor) { @@ -460,7 +459,7 @@ class SpeechToText { var pauseFor = initialPauseFor; var listenFor = initialListenFor; if (null != pauseFor) { - var remainingMillis = pauseFor.inMilliseconds - _elapsedSinceSpeechEvent; + var remainingMillis = pauseFor.inMilliseconds - (ignoreElapsedPause ? 0 : _elapsedSinceSpeechEvent); pauseFor = Duration(milliseconds: max(remainingMillis, 0)); } if (null != listenFor) {