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