aaudio: fix output bugs and improve input performance, add loopback test
Support AAUDIO_PERFORMANCE_MODE in AudioStreamRecord.cpp
Fix race condition when closing a stream, which this test revealed.
Fix setting of negative notificationFrames for non-FAST tracks.
Convert test from old Oboe API to AAudio.
Add command line options to the test.
Add systrace calls.
Bug: 34093052
Bug: 38313432
Bug: 38178592
Test: loopback.cpp
Change-Id: Ib6d2995cdd3ed432937fde2f26c5394013f0d6e0
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 027d66d..e6751c49 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -182,6 +182,15 @@
mDownDataQueue->getEmptyRoomAvailable(wrappingBuffer);
}
+int32_t AudioEndpoint::getEmptyFramesAvailable() {
+ return mDownDataQueue->getFifoControllerBase()->getEmptyFramesAvailable();
+}
+
+int32_t AudioEndpoint::getFullFramesAvailable()
+{
+ return mDownDataQueue->getFifoControllerBase()->getFullFramesAvailable();
+}
+
void AudioEndpoint::advanceWriteIndex(int32_t deltaFrames) {
mDownDataQueue->getFifoControllerBase()->advanceWriteIndex(deltaFrames);
}
@@ -227,7 +236,3 @@
return (int32_t)mDownDataQueue->getBufferCapacityInFrames();
}
-int32_t AudioEndpoint::getFullFramesAvailable()
-{
- return mDownDataQueue->getFifoControllerBase()->getFullFramesAvailable();
-}
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index 46a3fc5..3a2099f 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -56,6 +56,9 @@
void getEmptyRoomAvailable(android::WrappingBuffer *wrappingBuffer);
+ int32_t getEmptyFramesAvailable();
+ int32_t getFullFramesAvailable();
+
void advanceWriteIndex(int32_t deltaFrames);
/**
@@ -81,8 +84,6 @@
int32_t getBufferCapacityInFrames() const;
- int32_t getFullFramesAvailable();
-
private:
android::FifoBuffer *mUpCommandQueue;
android::FifoBuffer *mDownDataQueue;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index eee860e..143d4b7 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
#include <stdint.h>
#include <assert.h>
@@ -25,6 +27,7 @@
#include <aaudio/AAudio.h>
#include <utils/String16.h>
+#include <utils/Trace.h>
#include "AudioClock.h"
#include "AudioEndpointParcelable.h"
@@ -188,11 +191,25 @@
ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X",
mServiceStreamHandle);
if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
+ // Don't close a stream while it is running.
+ aaudio_stream_state_t currentState = getState();
+ if (isPlaying()) {
+ requestStop();
+ aaudio_stream_state_t nextState;
+ int64_t timeoutNanoseconds = MIN_TIMEOUT_NANOS;
+ aaudio_result_t result = waitForStateChange(currentState, &nextState,
+ timeoutNanoseconds);
+ if (result != AAUDIO_OK) {
+ ALOGE("AudioStreamInternal::close() waitForStateChange() returned %d %s",
+ result, AAudio_convertResultToText(result));
+ }
+ }
aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
mServiceInterface.closeStream(serviceStreamHandle);
delete[] mCallbackBuffer;
+ mCallbackBuffer = nullptr;
return mEndPointParcelable.close();
} else {
return AAUDIO_ERROR_INVALID_HANDLE;
@@ -524,6 +541,8 @@
aaudio_result_t AudioStreamInternal::write(const void *buffer, int32_t numFrames,
int64_t timeoutNanoseconds)
{
+ const char * traceName = (mInService) ? "aaWrtS" : "aaWrtC";
+ ATRACE_BEGIN(traceName);
aaudio_result_t result = AAUDIO_OK;
int32_t loopCount = 0;
uint8_t* source = (uint8_t*)buffer;
@@ -531,6 +550,12 @@
int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
int32_t framesLeft = numFrames;
+ int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
+ if (ATRACE_ENABLED()) {
+ const char * traceName = (mInService) ? "aaFullS" : "aaFullC";
+ ATRACE_INT(traceName, fullFrames);
+ }
+
// Write until all the data has been written or until a timeout occurs.
while (framesLeft > 0) {
// The call to writeNow() will not block. It will just write as much as it can.
@@ -568,6 +593,7 @@
// return error or framesWritten
(void) loopCount;
+ ATRACE_END();
return (result < 0) ? result : numFrames - framesLeft;
}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index eb6bfd5..a74a030 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -60,15 +60,29 @@
? 2 : getSamplesPerFrame();
audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
- audio_input_flags_t flags = (audio_input_flags_t) AUDIO_INPUT_FLAG_NONE;
-
size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
: builder.getBufferCapacity();
+
// TODO implement an unspecified Android format then use that.
audio_format_t format = (getFormat() == AAUDIO_UNSPECIFIED)
? AUDIO_FORMAT_PCM_FLOAT
: AAudioConvert_aaudioToAndroidDataFormat(getFormat());
+ audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
+ switch(getPerformanceMode()) {
+ case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+ flags = (audio_input_flags_t) (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW);
+ break;
+
+ case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+ case AAUDIO_PERFORMANCE_MODE_NONE:
+ default:
+ // No flags.
+ break;
+ }
+
+ uint32_t notificationFrames = 0;
+
// Setup the callback if there is one.
AudioRecord::callback_t callback = nullptr;
void *callbackData = nullptr;
@@ -77,11 +91,12 @@
streamTransferType = AudioRecord::transfer_type::TRANSFER_CALLBACK;
callback = getLegacyCallback();
callbackData = this;
+ notificationFrames = builder.getFramesPerDataCallback();
}
mCallbackBufferSize = builder.getFramesPerDataCallback();
mAudioRecord = new AudioRecord(
- AUDIO_SOURCE_DEFAULT,
+ AUDIO_SOURCE_VOICE_RECOGNITION,
getSampleRate(),
format,
channelMask,
@@ -89,7 +104,7 @@
frameCount,
callback,
callbackData,
- 0, // uint32_t notificationFrames = 0,
+ notificationFrames,
AUDIO_SESSION_ALLOCATE,
streamTransferType,
flags
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index f4a78e1..0af6457 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -29,7 +29,7 @@
namespace aaudio {
/**
- * Internal stream that uses the legacy AudioTrack path.
+ * Internal stream that uses the legacy AudioRecord path.
*/
class AudioStreamRecord : public AudioStreamLegacy {
public:
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index a7c7673..8c3732e 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -105,12 +105,14 @@
callback = getLegacyCallback();
callbackData = this;
- notificationFrames = builder.getFramesPerDataCallback();
// If the total buffer size is unspecified then base the size on the burst size.
- if (frameCount == AAUDIO_UNSPECIFIED) {
+ if (frameCount == 0
+ && ((flags & AUDIO_OUTPUT_FLAG_FAST) != 0)) {
// Take advantage of a special trick that allows us to create a buffer
// that is some multiple of the burst size.
notificationFrames = 0 - DEFAULT_BURSTS_PER_BUFFER_CAPACITY;
+ } else {
+ notificationFrames = builder.getFramesPerDataCallback();
}
}
mCallbackBufferSize = builder.getFramesPerDataCallback();