@@ -33,14 +33,14 @@ const INITIAL_STATE: AudioRecorderManagerState = {
3333export class AudioRecorderManager {
3434 state : StateStore < AudioRecorderManagerState > ;
3535 /**
36- * A boolean signifying whether we've tried to stop a recording while the
36+ * A Set signifying whether we've tried to stop a recording session while the
3737 * startRecording method is still executing. It is useful to identify race
3838 * conditions where we try to cancel the recording altogether while setting
3939 * up the recording session finishes (which can take up to 700ms on some
4040 * slower devices).
4141 * @private
4242 */
43- private hasPendingStopWhileStarting = false ;
43+ private pendingStopRequestIds = new Set < number > ( ) ;
4444 /**
4545 * A request ID for this recording session. Used to identify stale recording
4646 * sessions and respond adequately, avoiding race conditions.
@@ -53,8 +53,6 @@ export class AudioRecorderManager {
5353 }
5454
5555 reset ( ) {
56- this . startRequestId += 1 ;
57- this . hasPendingStopWhileStarting = false ;
5856 this . state . next ( INITIAL_STATE ) ;
5957 }
6058
@@ -82,7 +80,6 @@ export class AudioRecorderManager {
8280 if ( isStarting || status === 'recording' ) {
8381 return true ;
8482 }
85- this . hasPendingStopWhileStarting = false ;
8683 const requestId = ++ this . startRequestId ;
8784 this . state . partialNext ( {
8885 duration : 0 ,
@@ -101,21 +98,32 @@ export class AudioRecorderManager {
10198 this . onRecordingStatusUpdate ,
10299 ) ;
103100 } catch {
101+ this . pendingStopRequestIds . delete ( requestId ) ;
104102 if ( requestId === this . startRequestId ) {
105103 this . reset ( ) ;
106104 }
107105 return false ;
108106 }
109107
110108 const { accessGranted, recording } = recordingInfo ;
111- if ( this . hasPendingStopWhileStarting || requestId !== this . startRequestId ) {
112- try {
113- await NativeHandlers . Audio . stopRecording ( ) ;
114- } catch {
115- // If stopRecording fails, the native implementation has already stopped the
116- // recorder and so we do nothing.
109+ if ( this . pendingStopRequestIds . has ( requestId ) ) {
110+ if ( accessGranted ) {
111+ try {
112+ await NativeHandlers . Audio . stopRecording ( ) ;
113+ } catch {
114+ // If stopRecording fails, the native implementation has already stopped the
115+ // recorder and so we do nothing.
116+ }
117+ }
118+ this . pendingStopRequestIds . delete ( requestId ) ;
119+ if ( requestId === this . startRequestId ) {
120+ this . reset ( ) ;
117121 }
118- this . reset ( ) ;
122+ return accessGranted ;
123+ }
124+
125+ if ( requestId !== this . startRequestId ) {
126+ // Stale start completion, ignore to avoid affecting newer attempts
119127 return accessGranted ;
120128 }
121129
@@ -137,7 +145,8 @@ export class AudioRecorderManager {
137145 }
138146 const { isStarting, status } = this . state . getLatestValue ( ) ;
139147 if ( isStarting ) {
140- this . hasPendingStopWhileStarting = true ;
148+ this . pendingStopRequestIds . add ( this . startRequestId ) ;
149+ this . reset ( ) ;
141150 return ;
142151 }
143152 if ( status !== 'recording' ) {
0 commit comments