aaudio: fix race condition in requestStart()
Set callback enable flag before starting AudioTrack callback.
Bug: 72115512
Test: Repeat: adb shell write_sine_callback -pn -s4
Test: 20 times and make sure framesWritten is advancing.
Change-Id: I670fde46da0dccf8a6d03478fe2aa8b7ad596a3b
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index c5dfb7c..3352b33 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -86,10 +86,15 @@
// AudioRecord::Buffer
// TODO define our own AudioBuffer and pass it from the subclasses.
AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
- if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED || !mCallbackEnabled.load()) {
+ if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
+ ALOGW("processCallbackCommon() data, stream disconnected");
+ audioBuffer->size = SIZE_STOP_CALLBACKS;
+ } else if (!mCallbackEnabled.load()) {
+ ALOGW("processCallbackCommon() stopping because callback disabled");
audioBuffer->size = SIZE_STOP_CALLBACKS;
} else {
if (audioBuffer->frameCount == 0) {
+ ALOGW("processCallbackCommon() data, frameCount is zero");
return;
}
@@ -106,7 +111,7 @@
if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
} else { // STOP or invalid result
- ALOGW("%s() stop stream by faking an error", __func__);
+ ALOGW("%s() callback requested stop, fake an error", __func__);
audioBuffer->size = SIZE_STOP_CALLBACKS;
// Disable the callback just in case AudioFlinger keeps trying to call us.
mCallbackEnabled.store(false);
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index 6a506b3..494edbc 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -121,9 +121,6 @@
void forceDisconnect(bool errorCallbackEnabled = true);
- void onStart() { mCallbackEnabled.store(true); }
- void onStop() { mCallbackEnabled.store(false); }
-
int64_t incrementFramesWritten(int32_t frames) {
return mFramesWritten.increment(frames);
}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 5f4ab9b..2bdb057 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -234,11 +234,13 @@
return AAudioConvert_androidToAAudioResult(err);
}
+ // Enable callback before starting AudioTrack to avoid shutting
+ // down because of a race condition.
+ mCallbackEnabled.store(true);
err = mAudioRecord->start();
if (err != OK) {
return AAudioConvert_androidToAAudioResult(err);
} else {
- onStart();
setState(AAUDIO_STREAM_STATE_STARTING);
}
return AAUDIO_OK;
@@ -248,11 +250,11 @@
if (mAudioRecord.get() == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- onStop();
setState(AAUDIO_STREAM_STATE_STOPPING);
incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
mTimestampPosition.set(getFramesRead());
mAudioRecord->stop();
+ mCallbackEnabled.store(false);
mFramesRead.reset32();
mTimestampPosition.reset32();
// Pass false to prevent errorCallback from being called after disconnect
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 17a8d52..db07925 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -259,11 +259,13 @@
return AAudioConvert_androidToAAudioResult(err);
}
+ // Enable callback before starting AudioTrack to avoid shutting
+ // down because of a race condition.
+ mCallbackEnabled.store(true);
err = mAudioTrack->start();
if (err != OK) {
return AAudioConvert_androidToAAudioResult(err);
} else {
- onStart();
setState(AAUDIO_STREAM_STATE_STARTING);
}
return AAUDIO_OK;
@@ -280,9 +282,9 @@
AAudio_convertStreamStateToText(getState()));
return AAUDIO_ERROR_INVALID_STATE;
}
- onStop();
setState(AAUDIO_STREAM_STATE_PAUSING);
mAudioTrack->pause();
+ mCallbackEnabled.store(false);
status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
if (err != OK) {
return AAudioConvert_androidToAAudioResult(err);
@@ -311,13 +313,13 @@
ALOGE("requestStop() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
}
- onStop();
setState(AAUDIO_STREAM_STATE_STOPPING);
incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
mTimestampPosition.set(getFramesWritten());
mFramesWritten.reset32();
mTimestampPosition.reset32();
mAudioTrack->stop();
+ mCallbackEnabled.store(false);
return checkForDisconnectRequest(false);;
}