Skip to content

Commit

Permalink
[expo-av] Fix Audio.stopAndUnloadAsync not handling no-data on Android
Browse files Browse the repository at this point in the history
  • Loading branch information
IjzerenHein committed Aug 21, 2020
1 parent bb43845 commit ee78f0d
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 6 deletions.
2 changes: 2 additions & 0 deletions docs/pages/versions/unversioned/sdk/audio.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ try {

Stops the recording and deallocates the recorder from memory. This reverts the `Recording` instance to an unprepared state, and another `Recording` instance must be created in order to record again. This method can only be called if the `Recording` has been prepared.

NOTE: On Android this method may fail with `E_AUDIO_NODATA` when called too soon after `startAsync` and no audio data has been recorded yet. In that case the recorded file will be invalid and should be discarded.

#### Returns

A `Promise` that is fulfilled when recording has stopped, or rejects if recording could not be stopped. The promise is resolved with the `status` of the recording (see `getStatusAsync()` for details).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,13 @@ public void stopAudioRecording(final Promise promise) {
try {
mAudioRecorder.stop();
} catch (final RuntimeException e) {
promise.reject("E_AUDIO_RECORDINGSTOP", "Stop encountered an error: recording not stopped", e);
mAudioRecorderIsPaused = false;
if (!mAudioRecorderIsRecording) {
promise.reject("E_AUDIO_RECORDINGSTOP", "Stop encountered an error: recording not started", e);
} else {
mAudioRecorderIsRecording = false;
promise.reject("E_AUDIO_NODATA", "Stop encountered an error: no valid audio data has been received", e);
}
return;
}

Expand Down
18 changes: 13 additions & 5 deletions packages/expo-av/src/Audio/Recording.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,10 @@ export class Recording {

// Internal methods

_cleanupForUnloadedRecorder = async (finalStatus: RecordingStatus) => {
_cleanupForUnloadedRecorder = async (finalStatus?: RecordingStatus) => {
this._canRecord = false;
this._isDoneRecording = true;
// $FlowFixMe(greg): durationMillis is not always defined
this._finalDurationMillis = finalStatus.durationMillis;
this._finalDurationMillis = finalStatus?.durationMillis || 0;
_recorderExists = false;
if (this._subscription) {
this._subscription.remove();
Expand Down Expand Up @@ -354,9 +353,18 @@ export class Recording {
}
// We perform a separate native API call so that the state of the Recording can be updated with
// the final duration of the recording. (We cast stopStatus as Object to appease Flow)
const finalStatus = await ExponentAV.stopAudioRecording();
let stopResult: RecordingStatus | undefined;
let stopError: Error | undefined;
try {
stopResult = await ExponentAV.stopAudioRecording();
} catch (err) {
stopError = err;
}

// Clean-up and return status
await ExponentAV.unloadAudioRecorder();
return this._cleanupForUnloadedRecorder(finalStatus);
const status = await this._cleanupForUnloadedRecorder(stopResult);
return stopError ? Promise.reject(stopError) : status;
}

// Read API
Expand Down

0 comments on commit ee78f0d

Please sign in to comment.