aaudio: fix CTS for MMAP mode
Improve calculation of buffer capacity based on requested minimum.
Adjust timing of start() to reduce underflows.
Track ServiceEndpoints based on requested deviceId.
Fix getFramesRead() and flush() behavior.
Fix timeouts due to ClockModel lateness bug.
Misc cleanup.
Bug: 37755299
Test: test_aaudio.cpp
Change-Id: I637c16e87fbe14b6f28c60aeea0b9dfed965ecd0
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 494b18e..f246fc02 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -34,8 +34,10 @@
using namespace android;
using namespace aaudio;
-#define MIN_BURSTS_PER_BUFFER 2
-#define MAX_BURSTS_PER_BUFFER 32
+#define MIN_BURSTS_PER_BUFFER 2
+#define DEFAULT_BURSTS_PER_BUFFER 16
+// This is an arbitrary range. TODO review.
+#define MAX_FRAMES_PER_BUFFER (32 * 1024)
AAudioServiceStreamShared::AAudioServiceStreamShared(AAudioService &audioService)
: mAudioService(audioService)
@@ -46,12 +48,58 @@
close();
}
+int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames,
+ int32_t framesPerBurst) {
+
+ if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) {
+ ALOGE("AAudioServiceStreamShared::open(), requested capacity %d > max %d",
+ requestedCapacityFrames, MAX_FRAMES_PER_BUFFER);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+
+ // Determine how many bursts will fit in the buffer.
+ int32_t numBursts;
+ if (requestedCapacityFrames == AAUDIO_UNSPECIFIED) {
+ // Use fewer bursts if default is too many.
+ if ((DEFAULT_BURSTS_PER_BUFFER * framesPerBurst) > MAX_FRAMES_PER_BUFFER) {
+ numBursts = MAX_FRAMES_PER_BUFFER / framesPerBurst;
+ } else {
+ numBursts = DEFAULT_BURSTS_PER_BUFFER;
+ }
+ } else {
+ // round up to nearest burst boundary
+ numBursts = (requestedCapacityFrames + framesPerBurst - 1) / framesPerBurst;
+ }
+
+ // Clip to bare minimum.
+ if (numBursts < MIN_BURSTS_PER_BUFFER) {
+ numBursts = MIN_BURSTS_PER_BUFFER;
+ }
+ // Check for numeric overflow.
+ if (numBursts > 0x8000 || framesPerBurst > 0x8000) {
+ ALOGE("AAudioServiceStreamShared::open(), numeric overflow, capacity = %d * %d",
+ numBursts, framesPerBurst);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+ int32_t capacityInFrames = numBursts * framesPerBurst;
+
+ // Final sanity check.
+ if (capacityInFrames > MAX_FRAMES_PER_BUFFER) {
+ ALOGE("AAudioServiceStreamShared::open(), calculated capacity %d > max %d",
+ capacityInFrames, MAX_FRAMES_PER_BUFFER);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+ ALOGD("AAudioServiceStreamShared::open(), requested capacity = %d frames, actual = %d",
+ requestedCapacityFrames, capacityInFrames);
+ return capacityInFrames;
+}
+
aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) {
aaudio_result_t result = AAudioServiceStreamBase::open(request, configurationOutput);
if (result != AAUDIO_OK) {
- ALOGE("AAudioServiceStreamBase open returned %d", result);
+ ALOGE("AAudioServiceStreamBase open() returned %d", result);
return result;
}
@@ -72,16 +120,18 @@
mAudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
} else if (mAudioFormat != AAUDIO_FORMAT_PCM_FLOAT) {
ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need FLOAT", mAudioFormat);
- return AAUDIO_ERROR_INVALID_FORMAT;
+ result = AAUDIO_ERROR_INVALID_FORMAT;
+ goto error;
}
mSampleRate = configurationInput.getSampleRate();
if (mSampleRate == AAUDIO_UNSPECIFIED) {
mSampleRate = mServiceEndpoint->getSampleRate();
} else if (mSampleRate != mServiceEndpoint->getSampleRate()) {
- ALOGE("AAudioServiceStreamShared::open(), mAudioFormat = %d, need %d",
+ ALOGE("AAudioServiceStreamShared::open(), mSampleRate = %d, need %d",
mSampleRate, mServiceEndpoint->getSampleRate());
- return AAUDIO_ERROR_INVALID_RATE;
+ result = AAUDIO_ERROR_INVALID_RATE;
+ goto error;
}
mSamplesPerFrame = configurationInput.getSamplesPerFrame();
@@ -90,37 +140,51 @@
} else if (mSamplesPerFrame != mServiceEndpoint->getSamplesPerFrame()) {
ALOGE("AAudioServiceStreamShared::open(), mSamplesPerFrame = %d, need %d",
mSamplesPerFrame, mServiceEndpoint->getSamplesPerFrame());
- return AAUDIO_ERROR_OUT_OF_RANGE;
+ result = AAUDIO_ERROR_OUT_OF_RANGE;
+ goto error;
}
- // Determine this stream's shared memory buffer capacity.
mFramesPerBurst = mServiceEndpoint->getFramesPerBurst();
- int32_t minCapacityFrames = configurationInput.getBufferCapacity();
- int32_t numBursts = MAX_BURSTS_PER_BUFFER;
- if (minCapacityFrames != AAUDIO_UNSPECIFIED) {
- numBursts = (minCapacityFrames + mFramesPerBurst - 1) / mFramesPerBurst;
- if (numBursts < MIN_BURSTS_PER_BUFFER) {
- numBursts = MIN_BURSTS_PER_BUFFER;
- } else if (numBursts > MAX_BURSTS_PER_BUFFER) {
- numBursts = MAX_BURSTS_PER_BUFFER;
- }
+ ALOGD("AAudioServiceStreamShared::open(), mSampleRate = %d, mFramesPerBurst = %d",
+ mSampleRate, mFramesPerBurst);
+
+ mCapacityInFrames = calculateBufferCapacity(configurationInput.getBufferCapacity(),
+ mFramesPerBurst);
+ if (mCapacityInFrames < 0) {
+ result = mCapacityInFrames; // negative error code
+ mCapacityInFrames = 0;
+ goto error;
}
- mCapacityInFrames = numBursts * mFramesPerBurst;
- ALOGD("AAudioServiceStreamShared::open(), mCapacityInFrames = %d", mCapacityInFrames);
// Create audio data shared memory buffer for client.
mAudioDataQueue = new SharedRingBuffer();
- mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames);
+ result = mAudioDataQueue->allocate(calculateBytesPerFrame(), mCapacityInFrames);
+ if (result != AAUDIO_OK) {
+ ALOGE("AAudioServiceStreamShared::open(), could not allocate FIFO with %d frames",
+ mCapacityInFrames);
+ result = AAUDIO_ERROR_NO_MEMORY;
+ goto error;
+ }
+
+ ALOGD("AAudioServiceStreamShared::open() actual rate = %d, channels = %d, deviceId = %d",
+ mSampleRate, mSamplesPerFrame, mServiceEndpoint->getDeviceId());
// Fill in configuration for client.
configurationOutput.setSampleRate(mSampleRate);
configurationOutput.setSamplesPerFrame(mSamplesPerFrame);
configurationOutput.setAudioFormat(mAudioFormat);
- configurationOutput.setDeviceId(deviceId);
+ configurationOutput.setDeviceId(mServiceEndpoint->getDeviceId());
- mServiceEndpoint->registerStream(this);
+ result = mServiceEndpoint->registerStream(this);
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
return AAUDIO_OK;
+
+error:
+ close();
+ return result;
}
/**
@@ -137,11 +201,11 @@
aaudio_result_t result = endpoint->startStream(this);
if (result != AAUDIO_OK) {
ALOGE("AAudioServiceStreamShared::start() mServiceEndpoint returned %d", result);
- processError();
+ processFatalError();
} else {
result = AAudioServiceStreamBase::start();
}
- return AAUDIO_OK;
+ return result;
}
/**
@@ -154,11 +218,10 @@
if (endpoint == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- // Add this stream to the mixer.
aaudio_result_t result = endpoint->stopStream(this);
if (result != AAUDIO_OK) {
ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
- processError();
+ processFatalError();
}
return AAudioServiceStreamBase::pause();
}
@@ -168,11 +231,10 @@
if (endpoint == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- // Add this stream to the mixer.
aaudio_result_t result = endpoint->stopStream(this);
if (result != AAUDIO_OK) {
ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
- processError();
+ processFatalError();
}
return AAudioServiceStreamBase::stop();
}
@@ -183,9 +245,17 @@
* An AAUDIO_SERVICE_EVENT_FLUSHED will be sent to the client when complete.
*/
aaudio_result_t AAudioServiceStreamShared::flush() {
- // TODO make sure we are paused
- // TODO actually flush the data
- return AAudioServiceStreamBase::flush() ;
+ AAudioServiceEndpoint *endpoint = mServiceEndpoint;
+ if (endpoint == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ if (mState != AAUDIO_STREAM_STATE_PAUSED) {
+ ALOGE("AAudioServiceStreamShared::flush() stream not paused, state = %s",
+ AAudio_convertStreamStateToText(mState));
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ // Data will get flushed when the client receives the FLUSHED event.
+ return AAudioServiceStreamBase::flush();
}
aaudio_result_t AAudioServiceStreamShared::close() {