merge in jb-mr2-release history after reset to jb-mr2-dev
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 42bbc59..b0afb0c 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -29,6 +29,7 @@
 #include <cutils/log.h>
 #include <cutils/str_parms.h>
 #include <cutils/properties.h>
+#include <cutils/list.h>
 
 #include "audio_hw.h"
 
@@ -209,42 +210,66 @@
 }
 
 static void add_backend_name(char *mixer_path,
-                             snd_device_t snd_device)
+                             struct audio_usecase *usecase)
 {
-    if (snd_device == SND_DEVICE_OUT_HDMI ||
-            snd_device == SND_DEVICE_IN_HDMI_MIC)
-        strcat(mixer_path, " hdmi");
-    else if(snd_device == SND_DEVICE_OUT_BT_SCO ||
-            snd_device == SND_DEVICE_IN_BT_SCO_MIC)
-        strcat(mixer_path, " bt-sco");
-    else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
-        strcat(mixer_path, " speaker-and-hdmi");
+    audio_devices_t in_device;
+    if (usecase->devices & AUDIO_DEVICE_BIT_IN) {
+        in_device = usecase->devices & ~AUDIO_DEVICE_BIT_IN;
+        if (in_device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            strcat(mixer_path, " bt-sco");
+        }
+    } else {
+        if (usecase->devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+            strcat(mixer_path, " bt-sco");
+        } else if ((usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+                   (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+            strcat(mixer_path, " speaker-and-hdmi");
+        } else if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            strcat(mixer_path, " hdmi");
+        }
+    }
 }
 
 static int enable_audio_route(struct audio_route *ar,
-                              audio_usecase_t usecase,
-                              snd_device_t    snd_device)
+                              struct audio_usecase *usecase)
 {
-    ALOGV("%s: enter: usecase(%d) snd_device(%d)",
-          __func__, usecase, snd_device);
     char mixer_path[50];
-    strcpy(mixer_path, use_case_table[usecase]);
-    add_backend_name(mixer_path, snd_device);
+
+    if (usecase == NULL)
+        return -EINVAL;
+
+    ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
+
+    /* Get the updated devices from associated stream */
+    if (usecase->type == PCM_CAPTURE)
+        usecase->devices = usecase->stream.in->device;
+    else
+        usecase->devices = usecase->stream.out->devices;
+
+    strcpy(mixer_path, use_case_table[usecase->id]);
+    add_backend_name(mixer_path, usecase);
+    ALOGD("%s: apply mixer path: %s", __func__, mixer_path);
     audio_route_apply_path(ar, mixer_path);
+
     ALOGV("%s: exit", __func__);
     return 0;
 }
 
 static int disable_audio_route(struct audio_route *ar,
-                               audio_usecase_t usecase,
-                               snd_device_t    snd_device)
+                               struct audio_usecase *usecase)
 {
-    ALOGV("%s: enter: usecase(%d) snd_device(%d)",
-          __func__, usecase, snd_device);
     char mixer_path[50];
-    strcpy(mixer_path, use_case_table[usecase]);
-    add_backend_name(mixer_path, snd_device);
+
+    if (usecase == NULL)
+        return -EINVAL;
+
+    ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
+
+    strcpy(mixer_path, use_case_table[usecase->id]);
+    add_backend_name(mixer_path, usecase);
+    ALOGD("%s: reset mixer path: %s", __func__, mixer_path);
     audio_route_reset_path(ar, mixer_path);
+
     ALOGV("%s: exit", __func__);
     return 0;
 }
@@ -258,6 +283,7 @@
           snd_device, device_table[snd_device]);
     if (snd_device < SND_DEVICE_MIN ||
         snd_device >= SND_DEVICE_MAX) {
+        ALOGE("%s: Invalid sound device %d", __func__, snd_device);
         return -EINVAL;
     }
     acdb_dev_id = get_acdb_device_id(snd_device);
@@ -288,10 +314,11 @@
 static int disable_snd_device(struct audio_route *ar,
                               snd_device_t    snd_device)
 {
-    ALOGD("%s: enter: snd_device(%d: %s)", __func__,
+    ALOGD("%s: snd_device(%d: %s)", __func__,
           snd_device, device_table[snd_device]);
     if (snd_device < SND_DEVICE_MIN ||
         snd_device >= SND_DEVICE_MAX) {
+        ALOGE("%s: Invalid sound device %d", __func__, snd_device);
         return -EINVAL;
     }
     audio_route_reset_path(ar, device_table[snd_device]);
@@ -598,6 +625,7 @@
     snd_device_t out_snd_device = SND_DEVICE_NONE;
     snd_device_t in_snd_device = SND_DEVICE_NONE;
     struct audio_usecase *usecase;
+    struct listnode *node;
     int status = 0;
     int acdb_rx_id, acdb_tx_id;
     bool in_call_device_switch = false;
@@ -638,13 +666,10 @@
 
     if ((out_snd_device != adev->cur_out_snd_device || in_call_device_switch)
             && adev->out_snd_device_active) {
-        usecase = &adev->usecase_list;
-        while (usecase->next != NULL) {
-            usecase = usecase->next;
-            if (usecase->type == PCM_PLAYBACK || usecase->type == VOICE_CALL) {
-                disable_audio_route(adev->audio_route, usecase->id,
-                                    adev->cur_out_snd_device);
-            }
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (usecase->type == PCM_PLAYBACK || usecase->type == VOICE_CALL)
+                disable_audio_route(adev->audio_route, usecase);
         }
         audio_route_update_mixer(adev->audio_route);
         /* Disable current rx device */
@@ -654,13 +679,10 @@
 
     if ((in_snd_device != adev->cur_in_snd_device || in_call_device_switch)
             && adev->in_snd_device_active) {
-        usecase = &adev->usecase_list;
-        while (usecase->next != NULL) {
-            usecase = usecase->next;
-            if (usecase->type == PCM_CAPTURE) {
-                disable_audio_route(adev->audio_route, usecase->id,
-                                    adev->cur_in_snd_device);
-            }
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (usecase->type == PCM_CAPTURE)
+                disable_audio_route(adev->audio_route, usecase);
         }
         audio_route_update_mixer(adev->audio_route);
         /* Disable current tx device */
@@ -693,19 +715,13 @@
     }
     audio_route_update_mixer(adev->audio_route);
 
-    usecase = &adev->usecase_list;
-    while (usecase->next != NULL) {
-        usecase = usecase->next;
-        if (usecase->type == PCM_PLAYBACK || usecase->type == VOICE_CALL) {
-            usecase->devices = adev->out_device; /* TODO: fix device logic */
-            status = enable_audio_route(adev->audio_route, usecase->id,
-                                        adev->cur_out_snd_device);
-        } else {
-            status = enable_audio_route(adev->audio_route, usecase->id,
-                                        adev->cur_in_snd_device);
+    if (!list_empty(&adev->usecase_list)) {
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            enable_audio_route(adev->audio_route, usecase);
         }
+        audio_route_update_mixer(adev->audio_route);
     }
-    audio_route_update_mixer(adev->audio_route);
 
     if (adev->mode == AUDIO_MODE_IN_CALL && adev->csd_client) {
         if (adev->csd_enable_device == NULL) {
@@ -728,97 +744,54 @@
     return status;
 }
 
-static void add_usecase_to_list(struct audio_device *adev,
-                                struct audio_usecase *uc_info)
-{
-    struct audio_usecase *first_entry = adev->usecase_list.next;
-    ALOGV("%s: enter: usecase(%d)", __func__, uc_info->id);
-    /* Insert the new entry on the top of the list */
-    adev->usecase_list.next = uc_info;
-    uc_info->next = first_entry;
-    ALOGV("%s: exit", __func__);
-}
-
-static void remove_usecase_from_list(struct audio_device *adev,
-                                     audio_usecase_t uc_id)
-{
-    struct audio_usecase *uc_to_remove = NULL;
-    struct audio_usecase *list_head = &adev->usecase_list;
-    ALOGV("%s: enter: usecase(%d)", __func__, uc_id);
-    while (list_head->next != NULL) {
-        if (list_head->next->id == uc_id) {
-            uc_to_remove = list_head->next;
-            list_head->next = list_head->next->next;
-            free(uc_to_remove);
-            break;
-        }
-        list_head = list_head->next;
-    }
-    ALOGV("%s: exit", __func__);
-}
-
 static struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
                                                    audio_usecase_t uc_id)
 {
-    struct audio_usecase *uc_info = NULL;
-    struct audio_usecase *list_head = &adev->usecase_list;
-    ALOGV("%s: enter: uc_id(%d)", __func__, uc_id);
-    while (list_head->next != NULL) {
-        list_head = list_head->next;
-        if (list_head->id == uc_id) {
-            uc_info = list_head;
-            break;
-        }
-    }
-    ALOGV("%s: exit: uc_info(%p)", __func__, uc_info);
-    return uc_info;
-}
+    struct audio_usecase *usecase = NULL;
+    struct listnode *node;
 
-static int get_num_active_usecases(struct audio_device *adev)
-{
-    int num_uc = 0;
-    struct audio_usecase *list_head = &adev->usecase_list;
-    while (list_head->next != NULL) {
-        num_uc++;
-        list_head = list_head->next;
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->id == uc_id)
+            break;
     }
-    return num_uc;
+    return usecase;
 }
 
 static audio_devices_t get_active_out_devices(struct audio_device *adev,
-                                              audio_usecase_t usecase)
+                                              audio_usecase_t uc_id)
 {
-    audio_devices_t devices = 0;
-    struct audio_usecase *list_head = &adev->usecase_list;
+    audio_devices_t devices = AUDIO_DEVICE_NONE;
+    struct audio_usecase *usecase;
+    struct listnode *node;
+
     /* Return the output devices of usecases other than given usecase */
-    while (list_head->next != NULL) {
-        list_head = list_head->next;
-        if (list_head->type == PCM_PLAYBACK && list_head->id != usecase) {
-            devices |= list_head->devices;
-        }
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == PCM_PLAYBACK && usecase->id != uc_id)
+            devices |= usecase->stream.out->devices;
     }
+
     return devices;
 }
 
 static audio_devices_t get_voice_call_out_device(struct audio_device *adev)
 {
-    audio_devices_t devices = 0;
-    struct audio_usecase *list_head = &adev->usecase_list;
-    /* Return the output devices of usecases other than VOICE_CALL usecase */
-    while (list_head->next != NULL) {
-        list_head = list_head->next;
-        if (list_head->id == USECASE_VOICE_CALL) {
-            devices = list_head->devices;
-            break;
-        }
+    struct audio_usecase *usecase;
+    struct listnode *node;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == VOICE_CALL)
+            return usecase->stream.out->devices;
     }
-    return devices;
+
+    return AUDIO_DEVICE_NONE;
 }
 
 static int stop_input_stream(struct stream_in *in)
 {
     int i, ret = 0;
-    snd_device_t in_snd_device;
     struct audio_usecase *uc_info;
     struct audio_device *adev = in->dev;
 
@@ -833,14 +806,14 @@
     }
 
     /* 1. Disable stream specific mixer controls */
-    in_snd_device = adev->cur_in_snd_device;
-    disable_audio_route(adev->audio_route, in->usecase, in_snd_device);
+    disable_audio_route(adev->audio_route, uc_info);
     audio_route_update_mixer(adev->audio_route);
 
-    remove_usecase_from_list(adev, in->usecase);
+    list_remove(&uc_info->list);
+    free(uc_info);
 
     /* 2. Disable the tx device */
-    select_devices(adev);
+    ret = select_devices(adev);
 
     ALOGD("%s: exit: status(%d)", __func__, ret);
     return ret;
@@ -876,6 +849,7 @@
     uc_info->id = in->usecase;
     uc_info->type = PCM_CAPTURE;
     uc_info->devices = in->device;
+    uc_info->stream.in = in;
 
     /* 1. Enable the TX device */
     ret = select_devices(adev);
@@ -885,14 +859,13 @@
         free(uc_info);
         goto error_config;
     }
-    in_snd_device = adev->cur_in_snd_device;
 
     /* 2. Enable the mixer controls for the audio route */
-    enable_audio_route(adev->audio_route, in->usecase, in_snd_device);
+    enable_audio_route(adev->audio_route, uc_info);
     audio_route_update_mixer(adev->audio_route);
 
     /* 3. Add the usecase info to usecase list */
-    add_usecase_to_list(adev, uc_info);
+    list_add_tail(&adev->usecase_list, &uc_info->list);
 
     /* 2. Open the pcm device */
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
@@ -922,7 +895,6 @@
 static int stop_output_stream(struct stream_out *out)
 {
     int i, ret = 0;
-    snd_device_t out_snd_device;
     struct audio_usecase *uc_info;
     struct audio_device *adev = out->dev;
 
@@ -935,11 +907,11 @@
     }
 
     /* 1. Get and set stream specific mixer controls */
-    out_snd_device = adev->cur_out_snd_device;
-    disable_audio_route(adev->audio_route, out->usecase, out_snd_device);
+    disable_audio_route(adev->audio_route, uc_info);
     audio_route_update_mixer(adev->audio_route);
 
-    remove_usecase_from_list(adev, uc_info->id);
+    list_remove(&uc_info->list);
+    free(uc_info);
 
     /* 2. Disable the rx device */
     adev->out_device = get_active_out_devices(adev, out->usecase);
@@ -983,6 +955,7 @@
     uc_info->id = out->usecase;
     uc_info->type = PCM_PLAYBACK;
     uc_info->devices = out->devices;
+    uc_info->stream.out = out;
 
     ret = select_devices(adev);
     if (ret) {
@@ -992,11 +965,10 @@
         goto error_config;
     }
 
-    out_snd_device = adev->cur_out_snd_device;
-    enable_audio_route(adev->audio_route, out->usecase, out_snd_device);
+    enable_audio_route(adev->audio_route, uc_info);
     audio_route_update_mixer(adev->audio_route);
 
-    add_usecase_to_list(adev, uc_info);
+    list_add_tail(&adev->usecase_list, &uc_info->list);
 
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d)",
           __func__, 0, out->pcm_device_id);
@@ -1022,7 +994,6 @@
 static int stop_voice_call(struct audio_device *adev)
 {
     int i, ret = 0;
-    snd_device_t out_snd_device;
     struct audio_usecase *uc_info;
 
     ALOGD("%s: enter", __func__);
@@ -1054,13 +1025,13 @@
               __func__, USECASE_VOICE_CALL);
         return -EINVAL;
     }
-    out_snd_device = adev->cur_out_snd_device;
 
     /* 2. Get and set stream specific mixer controls */
-    disable_audio_route(adev->audio_route, USECASE_VOICE_CALL, out_snd_device);
+    disable_audio_route(adev->audio_route, uc_info);
     audio_route_update_mixer(adev->audio_route);
 
-    remove_usecase_from_list(adev, uc_info->id);
+    list_remove(&uc_info->list);
+    free(uc_info);
 
     /* 3. Disable the rx and tx devices */
     ret = select_devices(adev);
@@ -1072,7 +1043,6 @@
 static int start_voice_call(struct audio_device *adev)
 {
     int i, ret = 0;
-    snd_device_t out_snd_device;
     struct audio_usecase *uc_info;
     int pcm_dev_rx_id, pcm_dev_tx_id;
 
@@ -1081,7 +1051,8 @@
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
     uc_info->id = USECASE_VOICE_CALL;
     uc_info->type = VOICE_CALL;
-    uc_info->devices = adev->out_device;
+    uc_info->devices = adev->primary_output->devices;
+    uc_info->stream.out = adev->primary_output;
 
     ret = select_devices(adev);
     if (ret) {
@@ -1089,11 +1060,10 @@
         return ret;
     }
 
-    out_snd_device = adev->cur_out_snd_device;
-    enable_audio_route(adev->audio_route, uc_info->id, out_snd_device);
+    enable_audio_route(adev->audio_route, uc_info);
     audio_route_update_mixer(adev->audio_route);
 
-    add_usecase_to_list(adev, uc_info);
+    list_add_tail(&adev->usecase_list, &uc_info->list);
 
     pcm_dev_rx_id = get_pcm_device_id(adev->audio_route, uc_info->id,
                                       PCM_PLAYBACK);
@@ -1268,9 +1238,12 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
+    struct audio_usecase *usecase;
+    struct listnode *node;
     struct str_parms *parms;
     char value[32];
     int ret, val = 0;
+    bool select_new_device = false;
 
     ALOGD("%s: enter: usecase(%d) kvpairs: %s",
           __func__, out->usecase, kvpairs);
@@ -1281,22 +1254,34 @@
         pthread_mutex_lock(&out->lock);
         pthread_mutex_lock(&adev->lock);
 
-        if (adev->mode == AUDIO_MODE_IN_CALL && !adev->in_call && (val != 0)) {
-            adev->out_device = get_active_out_devices(adev, out->usecase) | val;
+        if (val != 0) {
+            /* ToDo: Fix device updation logic */
+            list_for_each(node, &adev->usecase_list) {
+                usecase = node_to_item(node, struct audio_usecase, list);
+                if ((usecase->type == PCM_PLAYBACK || usecase->type == VOICE_CALL)
+                        && usecase->stream.out != out)
+                    usecase->stream.out->devices = val;
+            }
+        }
+
+        adev->out_device = get_active_out_devices(adev, out->usecase) | val;
+        if ((adev->mode == AUDIO_MODE_IN_CALL) && !adev->in_call &&
+            (out == adev->primary_output) && (val != 0)) {
             out->devices = val;
             start_voice_call(adev);
-        } else if (adev->mode != AUDIO_MODE_IN_CALL && adev->in_call) {
+        } else if ((adev->mode != AUDIO_MODE_IN_CALL) && adev->in_call &&
+                   (out == adev->primary_output)) {
             if (val != 0) {
-                adev->out_device = get_active_out_devices(adev, out->usecase) | val;
                 out->devices = val;
             }
             stop_voice_call(adev);
         } else if ((out->devices != (audio_devices_t)val) && (val != 0)) {
-            if (!out->standby || adev->in_call) {
-                adev->out_device = get_active_out_devices(adev, out->usecase) | val;
+            /* Update the devices so that select_devices() enables the new devies */
+            out->devices = val;
+            if ((adev->in_call && (out == adev->primary_output)) ||
+                    !out->standby) {
                 ret = select_devices(adev);
             }
-            out->devices = val;
         }
 
         pthread_mutex_unlock(&adev->lock);
@@ -1640,6 +1625,15 @@
         out->config = pcm_config_low_latency;
     }
 
+    if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+        if(adev->primary_output == NULL)
+            adev->primary_output = out;
+        else {
+            ALOGE("%s: Primary output is already opened", __func__);
+            return -EEXIST;
+        }
+    }
+
     /* Check if this usecase is already existing */
     pthread_mutex_lock(&adev->lock);
     if (get_usecase_from_list(adev, out->usecase) != NULL) {
@@ -2104,6 +2098,7 @@
     pthread_mutex_lock(&adev->lock);
     adev->mode = AUDIO_MODE_NORMAL;
     adev->active_input = NULL;
+    adev->primary_output = NULL;
     adev->out_device = AUDIO_DEVICE_NONE;
     adev->voice_call_rx = NULL;
     adev->voice_call_tx = NULL;
@@ -2114,10 +2109,9 @@
     adev->cur_in_snd_device = 0;
     adev->out_snd_device_active = false;
     adev->in_snd_device_active = false;
-    adev->usecase_list.next = NULL;
-    adev->usecase_list.id = USECASE_INVALID;
     adev->in_call = false;
     adev->acdb_settings = TTY_MODE_OFF;
+    list_init(&adev->usecase_list);
     pthread_mutex_unlock(&adev->lock);
 
     /* Loads platform specific libraries dynamically */
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 0781688..0c4f526 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -174,12 +174,17 @@
     VOICE_CALL
 } usecase_type_t;
 
-// To store active use cases.
+union stream_ptr {
+    struct stream_in *in;
+    struct stream_out *out;
+};
+
 struct audio_usecase {
+    struct listnode list;
     audio_usecase_t id;
     usecase_type_t  type;
     audio_devices_t devices;
-    struct audio_usecase *next;
+    union stream_ptr stream;
 };
 
 typedef void (*acdb_deallocate_t)();
@@ -203,6 +208,7 @@
     audio_mode_t mode;
     audio_devices_t out_device;
     struct stream_in *active_input;
+    struct stream_out *primary_output;
     int in_call;
     float voice_volume;
     bool mic_mute;
@@ -215,7 +221,7 @@
     snd_device_t cur_in_snd_device;
     bool out_snd_device_active;
     bool in_snd_device_active;
-    struct audio_usecase usecase_list;
+    struct listnode usecase_list;
     struct audio_route *audio_route;
     int acdb_settings;