aaudio: control MMAP mode using system properties
To facilitate testing of MMAP mode.
Bug: 38268547
Test: set properties, see framesPerBurst in write_sine_callback.cpp
Change-Id: I6e15c563215017f6a5020d89ac312ff8331afc4f
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index f313b58..6c8f7f5 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -30,12 +30,6 @@
#include "legacy/AudioStreamRecord.h"
#include "legacy/AudioStreamTrack.h"
-// Enable a mixer in AAudio service that will mix streams to an ALSA MMAP buffer.
-#define MMAP_SHARED_ENABLED 0
-
-// Enable AAUDIO_SHARING_MODE_EXCLUSIVE that uses an ALSA MMAP buffer directly.
-#define MMAP_EXCLUSIVE_ENABLED 0
-
using namespace aaudio;
/*
@@ -53,6 +47,7 @@
AudioStream **audioStreamPtr) {
*audioStreamPtr = nullptr;
aaudio_result_t result = AAUDIO_OK;
+
switch (direction) {
case AAUDIO_DIRECTION_INPUT:
@@ -81,20 +76,30 @@
return result;
}
+// Try to open using MMAP path if that is enabled.
+// Fall back to Legacy path is MMAP not available.
aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
- 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;
- }
-
AudioStream *audioStream = nullptr;
*streamPtr = nullptr;
- bool tryMMap = ((sharingMode == AAUDIO_SHARING_MODE_SHARED) && MMAP_SHARED_ENABLED) ||
- ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) && MMAP_EXCLUSIVE_ENABLED);
+ int32_t mmapEnabled = AAudioProperty_getMMapEnabled();
+ int32_t mmapExclusiveEnabled = AAudioProperty_getMMapExclusiveEnabled();
+ ALOGD("AudioStreamBuilder(): mmapEnabled = %d, mmapExclusiveEnabled = %d",
+ mmapEnabled, mmapExclusiveEnabled);
+
+ aaudio_sharing_mode_t sharingMode = getSharingMode();
+ if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE)
+ && (mmapExclusiveEnabled == AAUDIO_USE_NEVER)) {
+ ALOGW("AudioStreamBuilder(): EXCLUSIVE sharing mode not supported. Use SHARED.");
+ sharingMode = AAUDIO_SHARING_MODE_SHARED;
+ setSharingMode(sharingMode);
+ }
+
+ bool allowMMap = mmapEnabled != AAUDIO_USE_NEVER;
+ bool allowLegacy = mmapEnabled != AAUDIO_USE_ALWAYS;
+
aaudio_result_t result = builder_createStream(getDirection(), sharingMode,
- tryMMap, &audioStream);
+ allowMMap, &audioStream);
if (result == AAUDIO_OK) {
// Open the stream using the parameters from the builder.
result = audioStream->open(*this);
@@ -105,7 +110,7 @@
delete audioStream;
audioStream = nullptr;
- if (isMMap) {
+ if (isMMap && allowLegacy) {
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,
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index be2bd10..168ed86 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <cutils/properties.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
@@ -322,3 +323,52 @@
*sizeInBytes = numFrames * bytesPerFrame;
return AAUDIO_OK;
}
+
+static int32_t AAudioProperty_getMMapProperty(const char *propName,
+ int32_t defaultValue,
+ const char * caller) {
+ int32_t prop = property_get_int32(AAUDIO_PROP_MMAP_ENABLED, defaultValue);
+ switch (prop) {
+ case AAUDIO_USE_NEVER:
+ case AAUDIO_USE_ALWAYS:
+ case AAUDIO_USE_AUTO:
+ break;
+ default:
+ ALOGE("%s: invalid = %d", caller, prop);
+ prop = defaultValue;
+ break;
+ }
+ return prop;
+}
+
+int32_t AAudioProperty_getMMapEnabled() {
+ return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_ENABLED,
+ AAUDIO_USE_NEVER, __func__);
+}
+
+int32_t AAudioProperty_getMMapExclusiveEnabled() {
+ return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_EXCLUSIVE_ENABLED,
+ AAUDIO_USE_NEVER, __func__);
+}
+
+int32_t AAudioProperty_getMixerBursts() {
+ const int32_t defaultBursts = 2; // arbitrary
+ const int32_t maxBursts = 1024; // arbitrary
+ int32_t prop = property_get_int32(AAUDIO_PROP_MIXER_BURSTS, defaultBursts); // use 2 for double buffered
+ if (prop < 1 || prop > maxBursts) {
+ ALOGE("AAudioProperty_getMixerBursts: invalid = %d", prop);
+ prop = defaultBursts;
+ }
+ return prop;
+}
+
+int32_t AAudioProperty_getHardwareBurstMinMicros() {
+ const int32_t defaultMicros = 1000; // arbitrary
+ const int32_t maxMicros = 1000 * 1000; // arbitrary
+ int32_t prop = property_get_int32(AAUDIO_PROP_HW_BURST_MIN_USEC, defaultMicros);
+ if (prop < 1 || prop > maxMicros) {
+ ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d", prop);
+ prop = defaultMicros;
+ }
+ return prop;
+}
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 0078cbb..7c383c7 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -170,4 +170,54 @@
*/
int32_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format);
+
+// Note that this code may be replaced by Settings or by some other system configuration tool.
+
+enum : int32_t {
+ // Related feature is disabled
+ AAUDIO_USE_NEVER = 0,
+ // If related feature works then use it. Otherwise fall back to something else.
+ AAUDIO_USE_AUTO = 1,
+ // Related feature must be used. If not available then fail.
+ AAUDIO_USE_ALWAYS = 2
+};
+
+#define AAUDIO_PROP_MMAP_ENABLED "aaudio.mmap_enabled"
+
+/**
+ * Read system property.
+ * @return AAUDIO_USE_NEVER or AAUDIO_USE_AUTO or AAUDIO_USE_ALWAYS
+ */
+int32_t AAudioProperty_getMMapEnabled();
+
+#define AAUDIO_PROP_MMAP_EXCLUSIVE_ENABLED "aaudio.mmap_exclusive_enabled"
+
+/**
+ * Read system property.
+ * @return AAUDIO_USE_NEVER or AAUDIO_USE_AUTO or AAUDIO_USE_ALWAYS
+ */
+int32_t AAudioProperty_getMMapExclusiveEnabled();
+
+#define AAUDIO_PROP_MIXER_BURSTS "aaudio.mixer_bursts"
+
+/**
+ * Read system property.
+ * @return number of bursts per mixer cycle
+ */
+int32_t AAudioProperty_getMixerBursts();
+
+#define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec"
+
+/**
+ * Read system property.
+ * This is handy in case the DMA is bursting too quickly for the CPU to keep up.
+ * For example, there may be a DMA burst every 100 usec but you only
+ * want to feed the MMAP buffer every 2000 usec.
+ *
+ * This will affect the framesPerBurst for an MMAP stream.
+ *
+ * @return minimum number of microseconds for a MMAP HW burst
+ */
+int32_t AAudioProperty_getHardwareBurstMinMicros();
+
#endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index d3e182a..a2e6d33 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -44,10 +44,6 @@
// This is the maximum size in frames. The effective size can be tuned smaller at runtime.
#define DEFAULT_BUFFER_CAPACITY (48 * 8)
-// Use 2 for "double buffered"
-#define BUFFER_SIZE_IN_BURSTS 2
-#define BURSTS_PER_MIX_LOOP 1
-
// The mStreamInternal will use a service interface that does not go through Binder.
AAudioServiceEndpoint::AAudioServiceEndpoint(AAudioService &audioService)
: mStreamInternal(audioService, true)
@@ -71,7 +67,13 @@
if (result == AAUDIO_OK) {
mMixer.allocate(mStreamInternal.getSamplesPerFrame(), mStreamInternal.getFramesPerBurst());
- int32_t desiredBufferSize = BUFFER_SIZE_IN_BURSTS * mStreamInternal.getFramesPerBurst();
+ int32_t burstsPerBuffer = AAudioProperty_getMixerBursts();
+ if (burstsPerBuffer == 0) {
+ mLatencyTuningEnabled = true;
+ burstsPerBuffer = 2;
+ }
+ ALOGD("AAudioServiceEndpoint(): burstsPerBuffer = %d", burstsPerBuffer);
+ int32_t desiredBufferSize = burstsPerBuffer * mStreamInternal.getFramesPerBurst();
mStreamInternal.setBufferSize(desiredBufferSize);
}
return result;
@@ -117,7 +119,6 @@
static void *aaudio_mixer_thread_proc(void *context) {
AAudioServiceEndpoint *stream = (AAudioServiceEndpoint *) context;
- //LOGD("AudioStreamAAudio(): oboe_callback_thread, stream = %p", stream);
if (stream != NULL) {
return stream->callbackLoop();
} else {
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index a4ceae6..d0c2f53 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -77,6 +77,7 @@
std::atomic<bool> mCallbackEnabled;
int32_t mReferenceCount = 0;
+ bool mLatencyTuningEnabled = false; // TODO implement tuning
std::mutex mLockStreams;
std::vector<AAudioServiceStreamShared *> mRegisteredStreams;
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index cadc2a4..78a1583 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -178,6 +178,21 @@
mAudioFormat = AAudioConvert_androidToAAudioDataFormat(config.format);
mSampleRate = config.sample_rate;
+ // Scale up the burst size to meet the minimum equivalent in microseconds.
+ // This is to avoid waking the CPU too often when the HW burst is very small
+ // or at high sample rates.
+ int32_t burstMinMicros = AAudioProperty_getHardwareBurstMinMicros();
+ int32_t burstMicros = 0;
+ do {
+ if (burstMicros > 0) { // skip first loop
+ mFramesPerBurst *= 2;
+ }
+ burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / mSampleRate;
+ } while (burstMicros < burstMinMicros);
+
+ ALOGD("AAudioServiceStreamMMAP::open() original burst = %d, minMicros = %d, final burst = %d\n",
+ mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
+
ALOGD("AAudioServiceStreamMMAP::open() got devId = %d, sRate = %d",
deviceId, config.sample_rate);