aaudio: add setPerformanceMode()
The performance mode affects the latency and the implementation of the
data path.
MMAP is still disabled for now.
Bug: 37867485
Test: write_sine.cpp
Change-Id: I9bf5d5d13d1047d5ace69bd5ebdce7b6d65c14e7
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 9107a7c..57a5273 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -23,7 +23,7 @@
#include "SineGenerator.h"
#define SAMPLE_RATE 48000
-#define NUM_SECONDS 15
+#define NUM_SECONDS 5
#define NANOS_PER_MICROSECOND ((int64_t)1000)
#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
#define NANOS_PER_SECOND (NANOS_PER_MILLISECOND * 1000)
@@ -104,6 +104,10 @@
AAudioStreamBuilder_setFormat(aaudioBuilder, REQUESTED_FORMAT);
AAudioStreamBuilder_setSharingMode(aaudioBuilder, REQUESTED_SHARING_MODE);
+ AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_NONE);
+ //AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+ //AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_POWER_SAVING);
+
// Create an AAudioStream using the Builder.
result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
if (result != AAUDIO_OK) {
@@ -132,7 +136,6 @@
// This is the number of frames that are read in one chunk by a DMA controller
// or a DSP or a mixer.
framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
- printf("Buffer: framesPerBurst = %d\n",framesPerBurst);
printf("Buffer: bufferSize = %d\n", AAudioStream_getBufferSizeInFrames(aaudioStream));
bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
printf("Buffer: bufferCapacity = %d, remainder = %d\n",
@@ -144,12 +147,15 @@
while (framesPerWrite < 48) {
framesPerWrite *= 2;
}
- printf("DataFormat: framesPerWrite = %d\n",framesPerWrite);
+ printf("Buffer: framesPerBurst = %d\n",framesPerBurst);
+ printf("Buffer: framesPerWrite = %d\n",framesPerWrite);
actualDataFormat = AAudioStream_getFormat(aaudioStream);
printf("DataFormat: requested = %d, actual = %d\n", REQUESTED_FORMAT, actualDataFormat);
// TODO handle other data formats
+ printf("PerformanceMode: %d\n", AAudioStream_getPerformanceMode(aaudioStream));
+
// Allocate a buffer for the audio data.
if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
floatData = new float[framesPerWrite * actualChannelCount];
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index cc0c3a4..1a66f35 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -26,7 +26,7 @@
#include <aaudio/AAudio.h>
#include "SineGenerator.h"
-#define NUM_SECONDS 15
+#define NUM_SECONDS 5
//#define SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE
#define SHARING_MODE AAUDIO_SHARING_MODE_SHARED
@@ -88,6 +88,10 @@
// AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8);
+ //AAudioStreamBuilder_setPerformanceMode(mBuilder, AAUDIO_PERFORMANCE_MODE_NONE);
+ AAudioStreamBuilder_setPerformanceMode(mBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+ //AAudioStreamBuilder_setPerformanceMode(mBuilder, AAUDIO_PERFORMANCE_MODE_POWER_SAVING);
+
// Open an AAudioStream using the Builder.
result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
if (result != AAUDIO_OK) goto finish1;
@@ -98,7 +102,6 @@
AAudioStream_getBufferSizeInFrames(mStream));
printf("AAudioStream_getBufferCapacityInFrames() = %d\n",
AAudioStream_getBufferCapacityInFrames(mStream));
- return result;
finish1:
AAudioStreamBuilder_delete(mBuilder);
@@ -227,7 +230,7 @@
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine sweep using an AAudio callback, Z1\n", argv[0]);
+ printf("%s - Play a sine sweep using an AAudio callback\n", argv[0]);
player.setSharingMode(SHARING_MODE);
@@ -278,6 +281,7 @@
printf("Stream state is %d %s!\n", state, AAudio_convertStreamStateToText(state));
break;
}
+ printf("framesWritten = %d\n", (int) AAudioStream_getFramesWritten(player.getStream()));
}
printf("Woke up now.\n");
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 532c372..8498950 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -125,6 +125,25 @@
};
typedef int32_t aaudio_sharing_mode_t;
+
+enum {
+ /**
+ * No particular performance needs. Default.
+ */
+ AAUDIO_PERFORMANCE_MODE_NONE = 10,
+
+ /**
+ * Extending battery life is most important.
+ */
+ AAUDIO_PERFORMANCE_MODE_POWER_SAVING,
+
+ /**
+ * Reducing latency is most important.
+ */
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+};
+typedef int32_t aaudio_performance_mode_t;
+
typedef struct AAudioStreamStruct AAudioStream;
typedef struct AAudioStreamBuilderStruct AAudioStreamBuilder;
@@ -279,6 +298,18 @@
*/
AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
int32_t numFrames);
+
+/**
+ * Set the requested performance mode.
+ *
+ * The default, if you do not call this function, is AAUDIO_PERFORMANCE_MODE_NONE.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param mode the desired performance mode, eg. AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+ */
+AAUDIO_API void AAudioStreamBuilder_setPerformanceMode(AAudioStreamBuilder* builder,
+ aaudio_performance_mode_t mode);
+
/**
* Return one of these values from the data callback function.
*/
@@ -722,6 +753,13 @@
AAUDIO_API aaudio_sharing_mode_t AAudioStream_getSharingMode(AAudioStream* stream);
/**
+ * Get the performance mode used by the stream.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ */
+AAUDIO_API aaudio_performance_mode_t AAudioStream_getPerformanceMode(AAudioStream* stream);
+
+/**
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return direction
*/
diff --git a/media/libaaudio/libaaudio.map.txt b/media/libaaudio/libaaudio.map.txt
index efd92ae..8f74800 100644
--- a/media/libaaudio/libaaudio.map.txt
+++ b/media/libaaudio/libaaudio.map.txt
@@ -3,6 +3,7 @@
AAudio_convertResultToText;
AAudio_convertStreamStateToText;
AAudio_createStreamBuilder;
+ AAudioStreamBuilder_setPerformanceMode;
AAudioStreamBuilder_setDeviceId;
AAudioStreamBuilder_setDataCallback;
AAudioStreamBuilder_setErrorCallback;
@@ -34,6 +35,7 @@
AAudioStream_getSampleRate;
AAudioStream_getSamplesPerFrame;
AAudioStream_getChannelCount;
+ AAudioStream_getPerformanceMode;
AAudioStream_getDeviceId;
AAudioStream_getFormat;
AAudioStream_getSharingMode;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 18a55cf..a43f6c5 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -90,6 +90,11 @@
// Called internally from 'C'
void *callbackLoop();
+
+ bool isMMap() override {
+ return true;
+ }
+
protected:
aaudio_result_t processCommands();
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index e5239e8..59032d5 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -114,8 +114,15 @@
return AAUDIO_OK;
}
+AAUDIO_API void AAudioStreamBuilder_setPerformanceMode(AAudioStreamBuilder* builder,
+ aaudio_performance_mode_t mode)
+{
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setPerformanceMode(mode);
+}
+
AAUDIO_API void AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder* builder,
- int32_t deviceId)
+ int32_t deviceId)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setDeviceId(deviceId);
@@ -403,6 +410,12 @@
return audioStream->getXRunCount();
}
+AAUDIO_API aaudio_performance_mode_t AAudioStream_getPerformanceMode(AAudioStream* stream)
+{
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->getPerformanceMode();
+}
+
AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 598fbaa..c3cf27f 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -47,6 +47,8 @@
mSharingMode = builder.getSharingMode();
mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
+ mPerformanceMode = builder.getPerformanceMode();
+
// callbacks
mFramesPerDataCallback = builder.getFramesPerDataCallback();
mDataCallbackProc = builder.getDataCallbackProc();
@@ -73,6 +75,16 @@
return AAUDIO_ERROR_UNEXPECTED_VALUE;
}
+ switch(mPerformanceMode) {
+ case AAUDIO_PERFORMANCE_MODE_NONE:
+ case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+ case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+ break;
+ default:
+ ALOGE("AudioStream::open(): illegal performanceMode %d", mPerformanceMode);
+ return AAUDIO_ERROR_UNEXPECTED_VALUE;
+ }
+
return AAUDIO_OK;
}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 74a1f77..c49b46b 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -134,6 +134,10 @@
return mState == AAUDIO_STREAM_STATE_STARTING || mState == AAUDIO_STREAM_STATE_STARTED;
}
+ virtual bool isMMap() {
+ return false;
+ }
+
aaudio_result_t getSampleRate() const {
return mSampleRate;
}
@@ -146,6 +150,14 @@
return mSamplesPerFrame;
}
+ virtual int32_t getPerformanceMode() const {
+ return mPerformanceMode;
+ }
+
+ void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
+ mPerformanceMode = performanceMode;
+ }
+
int32_t getDeviceId() const {
return mDeviceId;
}
@@ -293,6 +305,8 @@
aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
+ aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
+
// callback ----------------------------------
AAudioStream_dataCallback mDataCallbackProc = nullptr; // external callback functions
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index d51eeb3..9bc2ef2 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -47,67 +47,80 @@
AudioStreamBuilder::~AudioStreamBuilder() {
}
+static aaudio_result_t builder_createStream(aaudio_direction_t direction,
+ aaudio_sharing_mode_t sharingMode,
+ bool tryMMap,
+ AudioStream **audioStreamPtr) {
+ *audioStreamPtr = nullptr;
+ aaudio_result_t result = AAUDIO_OK;
+ switch (direction) {
+
+ case AAUDIO_DIRECTION_INPUT:
+ if (sharingMode == AAUDIO_SHARING_MODE_SHARED) {
+ *audioStreamPtr = new AudioStreamRecord();
+ } else {
+ ALOGE("AudioStreamBuilder(): bad sharing mode = %d for input", sharingMode);
+ result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ break;
+
+ case AAUDIO_DIRECTION_OUTPUT:
+ if (tryMMap) {
+ // TODO use a singleton for the AAudioBinderClient
+ AAudioBinderClient *aaudioClient = new AAudioBinderClient();
+ *audioStreamPtr = new AudioStreamInternal(*aaudioClient, false);
+ } else {
+ *audioStreamPtr = new AudioStreamTrack();
+ }
+ break;
+
+ default:
+ ALOGE("AudioStreamBuilder(): bad direction = %d", direction);
+ result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ return result;
+}
+
aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
- AudioStream* audioStream = nullptr;
- AAudioBinderClient *aaudioClient = nullptr;
- const aaudio_sharing_mode_t sharingMode = getSharingMode();
+ aaudio_sharing_mode_t sharingMode = getSharingMode();
+ if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) && (MMAP_EXCLUSIVE_ENABLED == 0)) {
+ ALOGE("AudioStreamBuilder(): EXCLUSIVE sharing mode not supported");
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
- switch (getDirection()) {
+ AudioStream *audioStream = nullptr;
+ *streamPtr = nullptr;
- case AAUDIO_DIRECTION_INPUT:
- switch (sharingMode) {
- case AAUDIO_SHARING_MODE_SHARED:
- audioStream = new(std::nothrow) AudioStreamRecord();
- break;
- default:
- ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
- return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
- break;
+ bool tryMMap = (sharingMode == AAUDIO_SHARING_MODE_SHARED) && MMAP_SHARED_ENABLED;
+ aaudio_result_t result = builder_createStream(getDirection(), sharingMode,
+ tryMMap, &audioStream);
+ if (result == AAUDIO_OK) {
+ // Open the stream using the parameters from the builder.
+ result = audioStream->open(*this);
+ if (result == AAUDIO_OK) {
+ *streamPtr = audioStream;
+ } else {
+ bool isMMap = audioStream->isMMap();
+ delete audioStream;
+ audioStream = nullptr;
+
+ if (isMMap) {
+ ALOGD("AudioStreamBuilder.build() MMAP stream did not open so try Legacy path");
+ // If MMAP stream failed to open then TRY using a legacy stream.
+ result = builder_createStream(getDirection(), sharingMode,
+ false, &audioStream);
+ if (result == AAUDIO_OK) {
+ result = audioStream->open(*this);
+ if (result == AAUDIO_OK) {
+ *streamPtr = audioStream;
+ } else {
+ delete audioStream;
+ }
+ }
+ }
}
- break;
-
- case AAUDIO_DIRECTION_OUTPUT:
- switch (sharingMode) {
- case AAUDIO_SHARING_MODE_SHARED:
-#if MMAP_SHARED_ENABLED
- aaudioClient = new AAudioBinderClient();
- audioStream = new(std::nothrow) AudioStreamInternal(*aaudioClient, false);
-#else
- audioStream = new(std::nothrow) AudioStreamTrack();
-#endif
- break;
-#if MMAP_EXCLUSIVE_ENABLED
- case AAUDIO_SHARING_MODE_EXCLUSIVE:
- aaudioClient = new AAudioBinderClient();
- audioStream = new(std::nothrow) AudioStreamInternal(*aaudioClient, false);
- break;
-#endif
- default:
- ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
- return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
- break;
- }
- break;
-
- default:
- ALOGE("AudioStreamBuilder(): bad direction = %d", getDirection());
- return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
- break;
}
- if (audioStream == nullptr) {
- delete aaudioClient;
- return AAUDIO_ERROR_NO_MEMORY;
- }
- ALOGD("AudioStreamBuilder(): created audioStream = %p", audioStream);
- // TODO maybe move this out of build and pass the builder to the constructors
- // Open the stream using the parameters from the builder.
- const aaudio_result_t result = audioStream->open(*this);
- if (result != AAUDIO_OK) {
- delete audioStream;
- } else {
- *streamPtr = audioStream;
- }
- ALOGD("AudioStreamBuilder(): return %d", result);
+ ALOGD("AudioStreamBuilder(): returned %d", result);
return result;
}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index 25baf4c..569ca63 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -100,6 +100,15 @@
return this;
}
+ int32_t getPerformanceMode() const {
+ return mPerformanceMode;
+ }
+
+ AudioStreamBuilder* setPerformanceMode(aaudio_performance_mode_t performanceMode) {
+ mPerformanceMode = performanceMode;
+ return this;
+ }
+
int32_t getDeviceId() const {
return mDeviceId;
}
@@ -157,14 +166,15 @@
aaudio_result_t build(AudioStream **streamPtr);
private:
- int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
- int32_t mSampleRate = AAUDIO_UNSPECIFIED;
- int32_t mDeviceId = AAUDIO_DEVICE_UNSPECIFIED;
- aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
- bool mSharingModeMatchRequired = false; // must match sharing mode requested
- aaudio_audio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED;
- aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
- int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
+ int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+ int32_t mSampleRate = AAUDIO_UNSPECIFIED;
+ int32_t mDeviceId = AAUDIO_DEVICE_UNSPECIFIED;
+ aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
+ bool mSharingModeMatchRequired = false; // must match sharing mode requested
+ aaudio_audio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED;
+ aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
+ int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
+ aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
AAudioStream_dataCallback mDataCallbackProc = nullptr; // external callback functions
void *mDataCallbackUserData = nullptr;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index b71b74a..b4b1c04 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -32,7 +32,6 @@
// Arbitrary and somewhat generous number of bursts.
#define DEFAULT_BURSTS_PER_BUFFER_CAPACITY 8
-static const bool FAST_TRACKS_ENABLED = true;
/*
* Create a stream that uses the AudioTrack.
@@ -69,17 +68,29 @@
ALOGD("AudioStreamTrack::open(), samplesPerFrame = %d, channelMask = 0x%08x",
samplesPerFrame, channelMask);
- // TODO add more performance options
- audio_output_flags_t flags = FAST_TRACKS_ENABLED
- ? AUDIO_OUTPUT_FLAG_FAST
- : AUDIO_OUTPUT_FLAG_NONE;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ switch(getPerformanceMode()) {
+ case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+ // Bypass the normal mixer and go straight to the FAST mixer.
+ flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW);
+ break;
+
+ case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+ // This uses a mixer that wakes up less often than the FAST mixer.
+ flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ break;
+
+ case AAUDIO_PERFORMANCE_MODE_NONE:
+ default:
+ // No flags. Use a normal mixer in front of the FAST mixer.
+ break;
+ }
int32_t frameCount = builder.getBufferCapacity();
ALOGD("AudioStreamTrack::open(), requested buffer capacity %d", frameCount);
int32_t notificationFrames = 0;
- // TODO implement an unspecified AudioTrack format then use that.
audio_format_t format = (getFormat() == AAUDIO_FORMAT_UNSPECIFIED)
? AUDIO_FORMAT_PCM_FLOAT
: AAudioConvert_aaudioToAndroidDataFormat(getFormat());