Runtime configuration of period size

Bug: 14938247
Change-Id: I0b846e7b27155aba26c86d9232aa3fcd4aa9b8e1
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 4a15874..9c16d4d 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -56,6 +56,9 @@
 #define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
 
+static unsigned int configured_low_latency_capture_period_size =
+        LOW_LATENCY_CAPTURE_PERIOD_SIZE;
+
 /* This constant enables extended precision handling.
  * TODO The flag is off until more testing is done.
  */
@@ -1098,13 +1101,19 @@
         return 0;
 
     size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
+    if (sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE)
+        size = configured_low_latency_capture_period_size;
     /* ToDo: should use frame_size computed based on the format and
        channel_count here. */
     size *= sizeof(short) * channel_count;
 
-    /* make sure the size is multiple of 64 */
-    size += 0x3f;
-    size &= ~0x3f;
+    /* make sure the size is multiple of 32 bytes
+     * At 48 kHz mono 16-bit PCM:
+     *  5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
+     *  3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
+     */
+    size += 0x1f;
+    size &= ~0x1f;
 
     return size;
 }
@@ -2280,6 +2289,10 @@
 
     /* Update config params with the requested sample rate and channels */
     in->usecase = USECASE_AUDIO_RECORD;
+#if LOW_LATENCY_CAPTURE_USE_CASE
+    if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE)
+        in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
+#endif
     in->config = pcm_config_audio_capture;
     in->config.channels = channel_count;
     in->config.rate = config->sample_rate;
@@ -2464,6 +2477,23 @@
     return 0;
 }
 
+/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
+ * or 0 otherwise.  A return value of 1 doesn't mean the value is guaranteed to work,
+ * just that it _might_ work.
+ */
+static int period_size_is_plausible_for_low_latency(int period_size)
+{
+    switch (period_size) {
+    case 160:
+    case 240:
+    case 320:
+    case 480:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
 static int adev_open(const hw_module_t *module, const char *name,
                      hw_device_t **device)
 {
@@ -2546,6 +2576,24 @@
     if (k_enable_extended_precision)
         adev_verify_devices(adev);
 
+    char value[PROPERTY_VALUE_MAX];
+    int trial;
+    if (property_get("audio_hal.period_size", value, NULL) > 0) {
+        trial = atoi(value);
+        if (period_size_is_plausible_for_low_latency(trial)) {
+            pcm_config_low_latency.period_size = trial;
+            pcm_config_low_latency.start_threshold = trial / 4;
+            pcm_config_low_latency.avail_min = trial / 4;
+            configured_low_latency_capture_period_size = trial;
+        }
+    }
+    if (property_get("audio_hal.in_period_size", value, NULL) > 0) {
+        trial = atoi(value);
+        if (period_size_is_plausible_for_low_latency(trial)) {
+            configured_low_latency_capture_period_size = trial;
+        }
+    }
+
     ALOGV("%s: exit", __func__);
     return 0;
 }
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 391e911..a2ae80f 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -116,4 +116,8 @@
 #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
 #define AUDIO_CAPTURE_PERIOD_COUNT 2
 
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 0
+
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 558c91c..19f5d0b 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -124,4 +124,8 @@
 #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
 #define AUDIO_CAPTURE_PERIOD_COUNT 2
 
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 1
+
 #endif // QCOM_AUDIO_PLATFORM_H