diff --git a/speech_to_text/lib/speech_to_text.dart b/speech_to_text/lib/speech_to_text.dart index f1d1f3de..13195dcc 100644 --- a/speech_to_text/lib/speech_to_text.dart +++ b/speech_to_text/lib/speech_to_text.dart @@ -435,9 +435,22 @@ class SpeechToText { throw ListenFailedException(e.message, e.details, e.stacktrace); } } + void changePauseFor(Duration pauseFor) { + //Setup new pauseFor only if listen is active and pauseFor is different + if(isNotListening) { + throw ListenNotStartedException(); + } + + if (_pauseFor == null || _pauseFor!.compareTo(pauseFor) != 0) { + _listenTimer?.cancel(); + _listenTimer = null; + //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) { @@ -446,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) { @@ -658,3 +671,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..eab576e8 100644 --- a/speech_to_text/test/speech_to_text_test.dart +++ b/speech_to_text/test/speech_to_text_test.dart @@ -187,6 +187,79 @@ void main() { expect(speech.isListening, isTrue); }); }); + test('trows on changePauseFor when not listening', () async { + fakeAsync((fa) { + speech.initialize(); + fa.flushMicrotasks(); + testPlatform.onStatus!(SpeechToText.notListeningStatus); + fa.flushMicrotasks(); + expect(speech.isListening, isFalse); + try { + speech.changePauseFor(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 changePauseFor 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.changePauseFor(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 changePauseFor 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.changePauseFor(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('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('creates finalResult true if none provided', () async { fakeAsync((fa) { speech.initialize(finalTimeout: Duration(milliseconds: 100));