hal: Add support for Native Audio(44.1kHz)

- Changes for device/Usecase selection
- Add new and combo devices for headphones
- Combo device handling
- Add new backend and logic to handle multiple
  backends
- Remove hardcoded mixers and select them
  dynamically based on the device

Change-Id: I7207291f2c27da13ba0cc77c66de1144f4b9888a
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 82b596f..dbfac87 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -430,6 +430,7 @@
      * than all sample rates in list for the input bit width.
      */
     sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+
     list_for_each(node_i, &so_info->sample_rate_list) {
         ss_info = node_to_item(node_i, struct stream_sample_rate, list);
         if ((sample_rate <= ss_info->sample_rate) &&
@@ -437,7 +438,7 @@
             app_type_cfg->app_type = so_info->app_type_cfg.app_type;
             app_type_cfg->sample_rate = sample_rate;
             app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
-            ALOGV("%s Assuming default sample rate. app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
+            ALOGV("%s Assuming sample rate. app_type_cfg->app_type %d, app_type_cfg->sample_rate %d, app_type_cfg->bit_width %d",
                    __func__, app_type_cfg->app_type, app_type_cfg->sample_rate, app_type_cfg->bit_width);
             return true;
         }
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 3d157da..266dbd9 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -603,7 +603,12 @@
     bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info);
 
     /* Disable all the usecases on the shared backend other than the
-       specified usecase */
+     * specified usecase.
+     * For native(44.1k) usecases, we don't need this as it uses a different
+     * backend, but we need to make sure that we reconfigure the backend
+     * if there is bit_width change, this should not affect shared backend
+     * usecases.
+     */
     for (i = 0; i < AUDIO_USECASE_MAX; i++)
         switch_device[i] = false;
 
@@ -612,13 +617,20 @@
         if (usecase->type != PCM_CAPTURE &&
                 usecase != uc_info &&
                 (usecase->out_snd_device != snd_device || force_routing)  &&
-                usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+                usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND
+                && usecase->stream.out->sample_rate != OUTPUT_SAMPLING_RATE_44100) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                   __func__, use_case_table[usecase->id],
                   platform_get_snd_device_name(usecase->out_snd_device));
             disable_audio_route(adev, usecase);
             switch_device[usecase->id] = true;
             num_uc_to_switch++;
+        } else if (usecase->type == PCM_PLAYBACK &&
+                  usecase->stream.out->sample_rate ==
+                  OUTPUT_SAMPLING_RATE_44100 && force_routing){
+           disable_audio_route(adev, usecase);
+           switch_device[usecase->id] = true;
+           num_uc_to_switch++;
         }
     }
 
@@ -814,7 +826,7 @@
         (usecase->type == VOIP_CALL)  ||
         (usecase->type == PCM_HFP_CALL)) {
         out_snd_device = platform_get_output_snd_device(adev->platform,
-                                                        usecase->stream.out->devices);
+                                                        usecase->stream.out);
         in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
         usecase->devices = usecase->stream.out->devices;
     } else {
@@ -854,7 +866,7 @@
             in_snd_device = SND_DEVICE_NONE;
             if (out_snd_device == SND_DEVICE_NONE) {
                 out_snd_device = platform_get_output_snd_device(adev->platform,
-                                            usecase->stream.out->devices);
+                                            usecase->stream.out);
                 if (usecase->stream.out == adev->primary_output &&
                         adev->active_input &&
                         adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
@@ -3637,8 +3649,6 @@
     adev->bluetooth_nrec = true;
     adev->acdb_settings = TTY_MODE_OFF;
     /* adev->cur_hdmi_channels = 0;  by calloc() */
-    adev->cur_codec_backend_samplerate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
-    adev->cur_codec_backend_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
     adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
     voice_init(adev);
     list_init(&adev->usecase_list);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 67f5279..0fc52f4 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -309,8 +309,6 @@
     bool bt_wb_speech_enabled;
 
     int snd_card;
-    unsigned int cur_codec_backend_samplerate;
-    unsigned int cur_codec_backend_bit_width;
     void *platform;
     unsigned int offload_usecases_state;
     void *visualizer_lib;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index b4c4c44..7b8f2d3 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -171,6 +171,11 @@
 typedef int (*acdb_set_audio_cal_t) (void *, void *, uint32_t);
 typedef int (*acdb_get_audio_cal_t) (void *, void *, uint32_t*);
 
+typedef struct codec_backend_cfg {
+    uint32_t sample_rate;
+    uint32_t bit_width;
+}codec_backend_t;
+
 struct platform_data {
     struct audio_device *adev;
     bool fluence_in_spkr_mode;
@@ -203,6 +208,7 @@
     struct csd_data *csd;
     void *edid_info;
     bool edid_valid;
+    codec_backend_t backend_cfg[MAX_PORT];
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -287,6 +293,7 @@
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = "speaker-ext-2",
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
     [SND_DEVICE_OUT_HEADPHONES] = "headphones",
+    [SND_DEVICE_OUT_HEADPHONES_44_1] = "headphones-44.1",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = "speaker-and-headphones-ext-1",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = "speaker-and-headphones-ext-2",
@@ -384,9 +391,10 @@
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 130,
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
     [SND_DEVICE_OUT_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_HEADPHONES_44_1] = 10,
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
-    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = 130,
-    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = 130,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = 10,
     [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
@@ -475,7 +483,7 @@
 
 #define TO_NAME_INDEX(X)   #X, X
 
-/* Used to get index from parsed sting */
+/* Used to get index from parsed string */
 static struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
     {TO_NAME_INDEX(SND_DEVICE_OUT_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER)},
@@ -483,6 +491,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_2)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES_44_1)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2)},
@@ -901,6 +910,8 @@
     backend_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
     backend_table[SND_DEVICE_IN_CAPTURE_FM] = strdup("capture-fm");
     backend_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
+    backend_table[SND_DEVICE_OUT_HEADPHONES] = strdup("headphones");
+    backend_table[SND_DEVICE_OUT_HEADPHONES_44_1] = strdup("headphones-44.1");
 }
 
 void get_cvd_version(char *cvd_version, struct audio_device *adev)
@@ -1028,6 +1039,7 @@
     char *snd_internal_name = NULL;
     char *tmp = NULL;
     char mixer_xml_file[MIXER_PATH_MAX_LENGTH]= {0};
+    int idx;
 
     my_data = calloc(1, sizeof(struct platform_data));
 
@@ -1291,6 +1303,12 @@
     /* init audio device arbitration */
     audio_extn_dev_arbi_init();
 
+    /* initialize backend config */
+    for (idx = 0; idx < MAX_PORT; idx++) {
+        my_data->backend_cfg[idx].sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        my_data->backend_cfg[idx].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    }
+
     my_data->edid_info = NULL;
     return my_data;
 }
@@ -1550,7 +1568,7 @@
 
     if (usecase->type == PCM_PLAYBACK)
         snd_device = platform_get_output_snd_device(adev->platform,
-                                            usecase->stream.out->devices);
+                                            usecase->stream.out);
     else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
         snd_device = platform_get_input_snd_device(adev->platform,
                                             adev->primary_output->devices);
@@ -1831,12 +1849,14 @@
     return ret;
 }
 
-snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
+snd_device_t platform_get_output_snd_device(void *platform, struct stream_out *out)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
     audio_mode_t mode = adev->mode;
     snd_device_t snd_device = SND_DEVICE_NONE;
+    audio_devices_t devices = out->devices;
+    unsigned int sample_rate = out->sample_rate;
 
     audio_channel_mask_t channel_mask = (adev->active_input == NULL) ?
                                 AUDIO_CHANNEL_IN_MONO : adev->active_input->channel_mask;
@@ -1949,8 +1969,10 @@
                 snd_device = SND_DEVICE_OUT_ANC_FB_HEADSET;
             else
                 snd_device = SND_DEVICE_OUT_ANC_HEADSET;
-        } else
-            snd_device = SND_DEVICE_OUT_HEADPHONES;
+        } else if (OUTPUT_SAMPLING_RATE_44100 == sample_rate)
+                snd_device = SND_DEVICE_OUT_HEADPHONES_44_1;
+            else
+                snd_device = SND_DEVICE_OUT_HEADPHONES;
     } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
         if (my_data->external_spk_1)
             snd_device = SND_DEVICE_OUT_SPEAKER_EXTERNAL_1;
@@ -2507,6 +2529,7 @@
     uint8_t *dptr = NULL;
     int32_t dlen;
     int err, ret;
+    struct stream_out out;
     if(value == NULL || platform == NULL || parms == NULL) {
         ALOGE("[%s] received null pointer, failed",__func__);
         goto done_key_audcal;
@@ -2539,7 +2562,8 @@
           if(audio_is_input_device(cal.dev_id)) {
               cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
           } else {
-              cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+              out.devices = cal.dev_id;
+              cal.snd_dev_id = platform_get_output_snd_device(platform, &out);
           }
         }
         cal.acdb_dev_id = platform_get_snd_device_acdb_id(cal.snd_dev_id);
@@ -2770,6 +2794,7 @@
     char *rparms=NULL;
     int ret=0, err;
     uint32_t param_len;
+    struct stream_out out;
 
     if(query==NULL || platform==NULL || reply==NULL) {
         ALOGE("[%s] received null pointer",__func__);
@@ -2792,7 +2817,8 @@
     if(cal.dev_id & AUDIO_DEVICE_BIT_IN) {
         cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
     } else if(cal.dev_id) {
-        cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+        out.devices = cal.dev_id;
+        cal.snd_dev_id = platform_get_output_snd_device(platform, &out);
     }
     cal.acdb_dev_id =  platform_get_snd_device_acdb_id(cal.snd_dev_id);
     if (cal.acdb_dev_id < 0) {
@@ -3036,13 +3062,27 @@
 }
 
 int platform_set_codec_backend_cfg(struct audio_device* adev,
+                         struct audio_usecase *usecase,
                          unsigned int bit_width, unsigned int sample_rate)
 {
+    int ret = 0;
+    char backend_port = ALL_CODEC_BACKEND_PORT;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
     ALOGV("%s bit width: %d, sample rate: %d", __func__, bit_width, sample_rate);
 
-    int ret = 0;
-    if (bit_width != adev->cur_codec_backend_bit_width) {
-        const char * mixer_ctl_name = "SLIM_0_RX Format";
+    if(usecase->stream.out->devices & SND_DEVICE_OUT_HEADPHONES_44_1)
+        backend_port = HEADPHONE_44_1_BACKEND_PORT;
+
+    // form the mixer string with appropriate backend port
+    char * mixer_ctl_name = "SLIM_";
+    strlcat(mixer_ctl_name, &backend_port, sizeof(mixer_ctl_name));
+    strlcat(mixer_ctl_name, "_RX Format", sizeof(mixer_ctl_name));
+    ALOGV("%s: Format mixer command - %s", __func__, mixer_ctl_name);
+
+    if (bit_width !=
+        my_data->backend_cfg[(int)backend_port].bit_width) {
+
         struct  mixer_ctl *ctl;
         ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
         if (!ctl) {
@@ -3057,7 +3097,7 @@
             mixer_ctl_set_enum_by_string(ctl, "S16_LE");
             sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
         }
-        adev->cur_codec_backend_bit_width = bit_width;
+        my_data->backend_cfg[(int)backend_port].bit_width = bit_width;
         ALOGE("Backend bit width is set to %d ", bit_width);
     }
 
@@ -3070,9 +3110,15 @@
      * Upper limit is inclusive in the sample rate range.
      */
     // TODO: This has to be more dynamic based on policy file
-    if (sample_rate != adev->cur_codec_backend_samplerate) {
+        // form the mixer string with appropriate backend port
+    mixer_ctl_name = "SLIM_";
+    strlcat(mixer_ctl_name, &backend_port, sizeof(mixer_ctl_name));
+    strlcat(mixer_ctl_name, "_RX SampleRate", sizeof(mixer_ctl_name));
+    ALOGV("%s: SampleRate mixer command - %s", __func__, mixer_ctl_name);
+
+    if (sample_rate !=
+       my_data->backend_cfg[(int)backend_port].sample_rate) {
             char *rate_str = NULL;
-            const char * mixer_ctl_name = "SLIM_0_RX SampleRate";
             struct  mixer_ctl *ctl;
 
             switch (sample_rate) {
@@ -3108,7 +3154,7 @@
 
             ALOGV("Set sample rate as rate_str = %s", rate_str);
             mixer_ctl_set_enum_by_string(ctl, rate_str);
-            adev->cur_codec_backend_samplerate = sample_rate;
+            my_data->backend_cfg[(int)backend_port].sample_rate = sample_rate;
     }
 
     return ret;
@@ -3124,6 +3170,11 @@
     struct stream_out *out = NULL;
     unsigned int bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
     unsigned int sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    char backend_port = ALL_CODEC_BACKEND_PORT;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    if(usecase->stream.out->devices & SND_DEVICE_OUT_HEADPHONES_44_1)
+        backend_port = HEADPHONE_44_1_BACKEND_PORT;
 
     // For voice calls use default configuration
     // force routing is not required here, caller will do it anyway
@@ -3172,8 +3223,8 @@
     }
     // Force routing if the expected bitwdith or samplerate
     // is not same as current backend comfiguration
-    if ((bit_width != adev->cur_codec_backend_bit_width) ||
-        (sample_rate != adev->cur_codec_backend_samplerate)) {
+    if ((bit_width != my_data->backend_cfg[(int)backend_port].bit_width) ||
+        (sample_rate != my_data->backend_cfg[(int)backend_port].sample_rate)) {
         *new_bit_width = bit_width;
         *new_sample_rate = sample_rate;
         backend_change = true;
@@ -3186,18 +3237,23 @@
 
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase)
 {
-    ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
-
     unsigned int new_bit_width, old_bit_width;
     unsigned int new_sample_rate, old_sample_rate;
+    char backend_port = ALL_CODEC_BACKEND_PORT;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
 
-    new_bit_width = old_bit_width = adev->cur_codec_backend_bit_width;
-    new_sample_rate = old_sample_rate = adev->cur_codec_backend_samplerate;
+    ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
+
+    if(usecase->stream.out->devices & SND_DEVICE_OUT_HEADPHONES_44_1)
+        backend_port = HEADPHONE_44_1_BACKEND_PORT;
+
+    new_bit_width = old_bit_width = my_data->backend_cfg[(int)backend_port].bit_width;
+    new_sample_rate = old_sample_rate = my_data->backend_cfg[(int)backend_port].sample_rate;
 
     ALOGW("Codec backend bitwidth %d, samplerate %d", old_bit_width, old_sample_rate);
     if (platform_check_codec_backend_cfg(adev, usecase,
                                       &new_bit_width, &new_sample_rate)) {
-        platform_set_codec_backend_cfg(adev, new_bit_width, new_sample_rate);
+        platform_set_codec_backend_cfg(adev, usecase, new_bit_width, new_sample_rate);
         return true;
     }
 
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 83922d5..b863a22 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -35,7 +35,11 @@
 /*
  * Below are the devices for which is back end is same, SLIMBUS_0_RX.
  * All these devices are handled by the internal HW codec. We can
- * enable any one of these devices at any time
+ * enable any one of these devices at any time. An exception here is
+ * 44.1k headphone which uses different backend. This is filtered
+ * as different hal internal device in the code but remains same
+ * as standard android device AUDIO_DEVICE_OUT_WIRED_HEADPHONE
+ * for other layers.
  */
 #define AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND \
     (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
@@ -57,7 +61,9 @@
     SND_DEVICE_OUT_SPEAKER_EXTERNAL_2,
     SND_DEVICE_OUT_SPEAKER_REVERSE,
     SND_DEVICE_OUT_HEADPHONES,
+    SND_DEVICE_OUT_HEADPHONES_44_1,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_44_1,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2,
     SND_DEVICE_OUT_VOICE_HANDSET,
@@ -151,7 +157,11 @@
 
 };
 
-#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
+#define DEFAULT_OUTPUT_SAMPLING_RATE    48000
+#define OUTPUT_SAMPLING_RATE_44100      44100
+#define MAX_PORT                        6
+#define ALL_CODEC_BACKEND_PORT          0
+#define HEADPHONE_44_1_BACKEND_PORT     5
 
 #define ALL_SESSION_VSID                0xFFFFFFFF
 #define DEFAULT_MUTE_RAMP_DURATION_MS   20
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 4ecdd36..0ae35e6 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -57,7 +57,7 @@
 int platform_set_mic_mute(void *platform, bool state);
 int platform_get_sample_rate(void *platform, uint32_t *rate);
 int platform_set_device_mute(void *platform, bool state, char *dir);
-snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices);
+snd_device_t platform_get_output_snd_device(void *platform, struct stream_out *out);
 snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device);
 int platform_set_hdmi_channels(void *platform, int channel_count);
 int platform_edid_get_max_channels(void *platform);