hal: Adding support for AudioControl HAL's mute and duck features

* Add support for ducking and unducking in Auto HAL
* Add support for muting and unmuting in Auto HAL
* Route adev_set_parameters to Auto HAL

Change-Id: I266c13869219e6f7ffe4f5f2f3d3df16e9da4415
diff --git a/hal/audio_extn/Android.mk b/hal/audio_extn/Android.mk
index 7fc02cb..d43bbe7 100644
--- a/hal/audio_extn/Android.mk
+++ b/hal/audio_extn/Android.mk
@@ -1189,7 +1189,8 @@
     libcutils \
     libdl \
     libexpat \
-    liblog
+    liblog \
+    libtinyalsa
 
 LOCAL_C_INCLUDES := \
     $(PRIMARY_HAL_PATH) \
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index c4fa9ac..eb07557 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -6370,6 +6370,7 @@
         auto_hal_init_config.fp_platform_set_echo_reference = platform_set_echo_reference;
         auto_hal_init_config.fp_platform_get_eccarstate = platform_get_eccarstate;
         auto_hal_init_config.fp_generate_patch_handle = generate_patch_handle;
+        auto_hal_init_config.fp_platform_get_pcm_device_id = platform_get_pcm_device_id;
         return auto_hal_init(adev, auto_hal_init_config);
     }
     else
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 057d9a8..75ef7f2 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -1422,6 +1422,7 @@
     fp_platform_set_echo_reference_t             fp_platform_set_echo_reference;
     fp_platform_get_eccarstate_t                 fp_platform_get_eccarstate;
     fp_generate_patch_handle_t                   fp_generate_patch_handle;
+    fp_platform_get_pcm_device_id_t              fp_platform_get_pcm_device_id;
 } auto_hal_init_config_t;
 // END: AUTO_HAL FEATURE ==================================================
 
diff --git a/hal/audio_extn/auto_hal.c b/hal/audio_extn/auto_hal.c
index 903bc13..037b0e5 100644
--- a/hal/audio_extn/auto_hal.c
+++ b/hal/audio_extn/auto_hal.c
@@ -34,6 +34,7 @@
 #include <log/log.h>
 #include <math.h>
 #include <audio_hw.h>
+#include <tinyalsa/asoundlib.h>
 #include "audio_extn.h"
 #include "platform_api.h"
 #include "platform.h"
@@ -46,6 +47,17 @@
 #include <log_utils.h>
 #endif
 
+#define MAX_VOLUME 1.995262
+#define DSP_MAX_VOLUME 0x2000
+#define DUCKED_VOLUME 0.0035
+
+enum {
+    AUDIO_DEVICE_DUCKED = 0,
+    AUDIO_DEVICE_UNDUCKED,
+    AUDIO_DEVICE_MUTED,
+    AUDIO_DEVICE_UNMUTED
+};
+
 //external feature dependency
 static fp_audio_extn_ext_hw_plugin_usecase_start_t  fp_audio_extn_ext_hw_plugin_usecase_start;
 static fp_audio_extn_ext_hw_plugin_usecase_stop_t   fp_audio_extn_ext_hw_plugin_usecase_stop;
@@ -59,6 +71,7 @@
 static fp_platform_set_echo_reference_t             fp_platform_set_echo_reference;
 static fp_platform_get_eccarstate_t                 fp_platform_get_eccarstate;
 static fp_generate_patch_handle_t                   fp_generate_patch_handle;
+static fp_platform_get_pcm_device_id_t              fp_platform_get_pcm_device_id;
 
 /* Auto hal module struct */
 static struct auto_hal_module *auto_hal = NULL;
@@ -669,11 +682,84 @@
     return ret;
 }
 
-void auto_hal_set_parameters(struct audio_device *adev __unused,
+
+static int auto_hal_out_set_pcm_volume(struct stream_out *out, float volume)
+{
+    /* Volume control for pcm playback */
+    char mixer_ctl_name[128];
+    struct audio_device *adev = out->dev;
+    struct mixer_ctl *ctl;
+    int pcm_device_id = fp_platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Volume", pcm_device_id);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    int dsp_vol = (int) (volume * DSP_MAX_VOLUME);
+    int ret = mixer_ctl_set_value(ctl, 0, dsp_vol);
+    if (ret < 0) {
+        ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static void auto_hal_set_mute_duck_state(struct audio_device *adev,
+                                         char* duck_mute_value,
+                                         int duck_mute_state)
+{
+    struct listnode *node = NULL;
+    char *ptr = NULL;
+    char *saveptr = NULL;
+    struct stream_out *out = NULL;
+    int car_audio_stream = -1;
+
+    for (ptr = strtok_r(duck_mute_value, ",", &saveptr);
+         ptr != NULL; ptr = strtok_r(NULL, ",", &saveptr)) {
+        list_for_each(node, &adev->active_outputs_list) {
+            streams_output_ctxt_t *out_ctxt = node_to_item(node,
+                                              streams_output_ctxt_t,
+                                              list);
+            out = out_ctxt->output;
+            car_audio_stream = auto_hal_get_car_audio_stream_from_address(ptr);
+            if (car_audio_stream == out->car_audio_stream) {
+                switch(duck_mute_state) {
+                    case AUDIO_DEVICE_DUCKED:
+                        ALOGD("%s: Ducking BUS device %s", __func__, ptr);
+                        auto_hal_out_set_pcm_volume(out, DUCKED_VOLUME);
+                        break;
+
+                    case AUDIO_DEVICE_UNDUCKED:
+                        ALOGD("%s: Unducking BUS device %s", __func__, ptr);
+                        auto_hal_out_set_pcm_volume(out, out->volume_l);
+                        break;
+
+                    case AUDIO_DEVICE_MUTED:
+                        ALOGD("%s: Muting BUS device %s", __func__, ptr);
+                        out->muted = true;
+                        break;
+
+                    case AUDIO_DEVICE_UNMUTED:
+                        ALOGD("%s: Unmuting BUS device %s", __func__, ptr);
+                        out->muted = false;
+                        break;
+                }
+            }
+        }
+    }
+
+}
+
+void auto_hal_set_parameters(struct audio_device *adev,
                                         struct str_parms *parms)
 {
     int ret = 0;
     char value[32]={0};
+    char duck_mute_value[128] = {0};
+    char *ptr = NULL;
 
     ALOGV("%s: enter", __func__);
 
@@ -689,6 +775,22 @@
         }
     }
 
+    ret = str_parms_get_str(parms, "DevicesToDuck", duck_mute_value, sizeof(duck_mute_value));
+    if (ret >= 0)
+        auto_hal_set_mute_duck_state(adev, duck_mute_value, AUDIO_DEVICE_DUCKED);
+
+    ret = str_parms_get_str(parms, "DevicesToUnduck", duck_mute_value, sizeof(duck_mute_value));
+    if (ret >= 0)
+        auto_hal_set_mute_duck_state(adev, duck_mute_value, AUDIO_DEVICE_UNDUCKED);
+
+    ret = str_parms_get_str(parms, "DevicesToMute", duck_mute_value, sizeof(duck_mute_value));
+    if (ret >= 0)
+        auto_hal_set_mute_duck_state(adev, duck_mute_value, AUDIO_DEVICE_MUTED);
+
+    ret = str_parms_get_str(parms, "DevicesToUnmute", duck_mute_value, sizeof(duck_mute_value));
+    if (ret >= 0)
+        auto_hal_set_mute_duck_state(adev, duck_mute_value, AUDIO_DEVICE_UNMUTED);
+
     ALOGV("%s: exit", __func__);
 }
 
@@ -1031,6 +1133,7 @@
     fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
     fp_platform_get_eccarstate = init_config.fp_platform_get_eccarstate;
     fp_generate_patch_handle = init_config.fp_generate_patch_handle;
+    fp_platform_get_pcm_device_id = init_config.fp_platform_get_pcm_device_id;
 
     return ret;
 }
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 5a284ea..ccabe30 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -9422,6 +9422,7 @@
         }
     }
 
+    audio_extn_auto_hal_set_parameters(adev, parms);
     audio_extn_set_parameters(adev, parms);
 done:
     str_parms_destroy(parms);