@@ -70,8 +70,37 @@ class RecorderController extends ChangeNotifier {
7070
7171 bool _useLegacyNormalization = false ;
7272
73+ /// Provides currently recorded audio duration. Use [onCurrentDuration]
74+ /// stream to get latest events duration.
75+ Duration elapsedDuration = Duration .zero;
76+
77+ /// Provides duration of recorded audio file when recording has been stopped.
78+ /// Until recording has been stopped, this duration will be
79+ /// zero(Duration.zero). Also, once new recording is started this duration
80+ /// will be reset to zero.
81+ Duration recordedDuration = Duration .zero;
82+
83+ Timer ? _recorderTimer;
84+
7385 final ValueNotifier <int > _currentScrolledDuration = ValueNotifier (0 );
7486
87+ final StreamController <Duration > _currentDurationController =
88+ StreamController .broadcast ();
89+
90+ /// A stream to get current duration of currently recording audio file.
91+ /// Events are emitted every 50 milliseconds which means current duration is
92+ /// accurate to 50 milliseconds. To get Fully accurate duration use
93+ /// [recordedDuration] after stopping the recording.
94+ Stream <Duration > get onCurrentDuration => _currentDurationController.stream;
95+
96+ final StreamController <RecorderState > _recorderStateController =
97+ StreamController .broadcast ();
98+
99+ /// A Stream to monitor change in RecorderState. Events are emitted whenever
100+ /// there is change in the RecorderState.
101+ Stream <RecorderState > get onRecorderStateChanged =>
102+ _recorderStateController.stream;
103+
75104 /// A class having controls for recording audio and other useful handlers.
76105 ///
77106 /// Use [useLegacyNormalization] parameter to use normalization before
@@ -140,15 +169,15 @@ class RecorderController extends ChangeNotifier {
140169 _isRecording = await AudioWaveformsInterface .instance.resume ();
141170 if (_isRecording) {
142171 _startTimer ();
143- _recorderState = RecorderState .recording;
172+ _setRecorderState ( RecorderState .recording) ;
144173 } else {
145174 throw "Failed to resume recording" ;
146175 }
147176 notifyListeners ();
148177 return ;
149178 }
150179 if (Platform .isIOS) {
151- _recorderState = RecorderState .initialized;
180+ _setRecorderState ( RecorderState .initialized) ;
152181 }
153182 if (_recorderState.isInitialized) {
154183 _isRecording = await AudioWaveformsInterface .instance.record (
@@ -161,15 +190,15 @@ class RecorderController extends ChangeNotifier {
161190 useLegacyNormalization: _useLegacyNormalization,
162191 );
163192 if (_isRecording) {
164- _recorderState = RecorderState .recording;
193+ _setRecorderState ( RecorderState .recording) ;
165194 _startTimer ();
166195 } else {
167196 throw "Failed to start recording" ;
168197 }
169198 notifyListeners ();
170199 }
171200 } else {
172- _recorderState = RecorderState .stopped;
201+ _setRecorderState ( RecorderState .stopped) ;
173202 notifyListeners ();
174203 }
175204 }
@@ -192,7 +221,7 @@ class RecorderController extends ChangeNotifier {
192221 bitRate: bitRate ?? this .bitRate,
193222 );
194223 if (initialized) {
195- _recorderState = RecorderState .initialized;
224+ _setRecorderState ( RecorderState .initialized) ;
196225 } else {
197226 throw "Failed to initialize recorder" ;
198227 }
@@ -223,8 +252,9 @@ class RecorderController extends ChangeNotifier {
223252 if (_isRecording) {
224253 throw "Failed to pause recording" ;
225254 }
255+ _recorderTimer? .cancel ();
226256 _timer? .cancel ();
227- _recorderState = RecorderState .paused;
257+ _setRecorderState ( RecorderState .paused) ;
228258 }
229259 notifyListeners ();
230260 }
@@ -242,14 +272,21 @@ class RecorderController extends ChangeNotifier {
242272 /// left of for previous recording.
243273 Future <String ?> stop ([bool callReset = true ]) async {
244274 if (_recorderState.isRecording || _recorderState.isPaused) {
245- final path = await AudioWaveformsInterface .instance.stop ();
246-
247- if (path != null ) {
275+ final audioInfo = await AudioWaveformsInterface .instance.stop ();
276+ if (audioInfo != null ) {
248277 _isRecording = false ;
249278 _timer? .cancel ();
250- _recorderState = RecorderState .stopped;
279+ _recorderTimer? .cancel ();
280+ if (audioInfo[1 ] != null ) {
281+ var duration = int .tryParse (audioInfo[1 ]! );
282+ if (duration != null ) {
283+ recordedDuration = Duration (milliseconds: duration);
284+ }
285+ }
286+ elapsedDuration = Duration .zero;
287+ _setRecorderState (RecorderState .stopped);
251288 if (callReset) reset ();
252- return path ;
289+ return audioInfo[ 0 ] ;
253290 } else {
254291 throw "Failed stop recording" ;
255292 }
@@ -282,6 +319,13 @@ class RecorderController extends ChangeNotifier {
282319
283320 /// Gets decibel by every defined frequency
284321 void _startTimer () {
322+ recordedDuration = Duration .zero;
323+ const duration = Duration (milliseconds: 50 );
324+ _recorderTimer = Timer .periodic (duration, (_) {
325+ elapsedDuration += duration;
326+ _currentDurationController.add (elapsedDuration);
327+ });
328+
285329 _timer = Timer .periodic (
286330 updateFrequency,
287331 (timer) async {
@@ -351,13 +395,30 @@ class RecorderController extends ChangeNotifier {
351395 _currentScrolledDuration.value = duration;
352396 }
353397
398+ void _setRecorderState (RecorderState state) {
399+ _recorderStateController.add (state);
400+ _recorderState = state;
401+ }
402+
403+ /// This function is to release resources taken by android native
404+ /// MetaDataRetriever.
405+ void _release () {
406+ AudioWaveformsInterface .instance.releaseMetaDataRetriever ();
407+ }
408+
354409 /// Releases any resources taken by this recorder and with this
355410 /// controller is also disposed.
356411 @override
357412 void dispose () async {
358- if (_timer != null ) _timer! .cancel ();
359413 if (recorderState != RecorderState .stopped) await stop ();
414+ if (Platform .isAndroid) _release ();
360415 _currentScrolledDuration.dispose ();
416+ _currentDurationController.close ();
417+ _recorderStateController.close ();
418+ _recorderTimer? .cancel ();
419+ _timer? .cancel ();
420+ _timer = null ;
421+ _recorderTimer = null ;
361422 super .dispose ();
362423 }
363424}
0 commit comments