hal: Remove storage of audio device on bitfields

Audio devices were stored in HAL on variables with
type audio_devices_t. This change removes the storage
of multiple devices on a bitfield. Device comparisons,
assigments, removal have been updated. Helper functions
have been introduced for device operations.

Change-Id: I9ce8b0f9bdc542c386cbfe45b685158cc51d47b6
diff --git a/hal/audio_extn/Android.mk b/hal/audio_extn/Android.mk
index b5c32cd..b889212 100644
--- a/hal/audio_extn/Android.mk
+++ b/hal/audio_extn/Android.mk
@@ -136,7 +136,8 @@
   MULTIPLE_HW_VARIANTS_ENABLED := true
 endif
 
-LOCAL_SRC_FILES:= ssr.c
+LOCAL_SRC_FILES:= ssr.c \
+                  device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -383,7 +384,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        a2dp.c
+        a2dp.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -514,7 +516,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        hfp.c
+        hfp.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -577,7 +580,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        passthru.c
+        passthru.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -779,7 +783,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        maxxaudio.c
+        maxxaudio.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -840,7 +845,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        audiozoom.c
+        audiozoom.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
@@ -904,7 +910,8 @@
 endif
 
 LOCAL_SRC_FILES:= \
-        auto_hal.c
+        auto_hal.c \
+        device_utils.c
 
 LOCAL_CFLAGS += \
     -Wall \
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index bffa3fd..e0aebf0 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -2786,7 +2786,7 @@
                 list_for_each(node, &a2dp.adev->usecase_list) {
                     uc_info = node_to_item(node, struct audio_usecase, list);
                     if (uc_info->stream.out && uc_info->type == PCM_PLAYBACK &&
-                         (uc_info->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+                        is_a2dp_out_device_type(&uc_info->stream.out->device_list)) {
                         pthread_mutex_unlock(&a2dp.adev->lock);
                         fp_check_a2dp_restore(a2dp.adev, uc_info->stream.out, false);
                         pthread_mutex_lock(&a2dp.adev->lock);
@@ -2827,7 +2827,7 @@
                 list_for_each(node, &a2dp.adev->usecase_list) {
                     uc_info = node_to_item(node, struct audio_usecase, list);
                     if (uc_info->stream.out && uc_info->type == PCM_PLAYBACK &&
-                         (uc_info->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
+                        is_a2dp_out_device_type(&uc_info->stream.out->device_list)) {
                         pthread_mutex_unlock(&a2dp.adev->lock);
                         fp_check_a2dp_restore(a2dp.adev, uc_info->stream.out, true);
                         pthread_mutex_lock(&a2dp.adev->lock);
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 45da9b5..620e7c6 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1247,12 +1247,12 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->stream.out && usecase->type != PCM_CAPTURE) {
-                if (usecase->stream.out->devices == \
-                    AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                    usecase->stream.out->devices ==  \
-                    AUDIO_DEVICE_OUT_WIRED_HEADSET ||
-                    usecase->stream.out->devices ==  \
-                    AUDIO_DEVICE_OUT_EARPIECE) {
+                if (is_single_device_type_equal(&usecase->stream.out->device_list,
+                                AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+                    is_single_device_type_equal(&usecase->stream.out->device_list,
+                                AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+                    is_single_device_type_equal(&usecase->stream.out->device_list,
+                                AUDIO_DEVICE_OUT_EARPIECE)) {
                         select_devices(adev, usecase->id);
                         ALOGV("%s: switching device completed", __func__);
                         break;
@@ -3387,7 +3387,7 @@
     /* validate input params. Avoid updated channel mask if loopback device */
     if ((channel_count == 6) &&
         (in->format == AUDIO_FORMAT_PCM_16_BIT) &&
-        (!is_loopback_input_device(in->device))) {
+        (!is_loopback_input_device(get_device_types(&in->device_list)))) {
         switch (max_mic_count) {
             case 4:
                 config->channel_mask = AUDIO_CHANNEL_INDEX_MASK_4;
@@ -3662,13 +3662,13 @@
 
     adev_device_cfg_ptr = adev->device_cfg_params;
     /* Create an out stream to get snd device from audio device */
-    out.devices = device_cfg_params->device;
+    reassign_device_list(&out.device_list, device_cfg_params->device, "");
     out.sample_rate = device_cfg_params->sample_rate;
     snd_device = platform_get_output_snd_device(adev->platform, &out);
     backend_idx = platform_get_backend_index(snd_device);
 
     ALOGV("%s:: device %d sample_rate %d snd_device %d backend_idx %d",
-                __func__, out.devices, out.sample_rate, snd_device, backend_idx);
+                __func__, get_device_types(&out.device_list), out.sample_rate, snd_device, backend_idx);
 
     ALOGV("%s:: Device Config Params from Client samplerate %d  channels %d"
           " bit_width %d  format %d  device %d  channel_map[0] %d channel_map[1] %d"
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 986e24a..b01915a 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -680,7 +680,7 @@
 typedef int (*fp_platform_set_mic_mute_t)(void *, bool);
 //typedef int (*fp_platform_get_pcm_device_id_t)(audio_usecase_t, int);
 typedef void (*fp_platform_set_echo_reference_t)(struct audio_device *, bool,
-                                                            audio_devices_t);
+                                                     struct listnode *);
 typedef int (*fp_select_devices_t)(struct audio_device *, audio_usecase_t);
 typedef int (*fp_audio_extn_ext_hw_plugin_usecase_start_t)(void *,
                                                       struct audio_usecase *);
@@ -795,7 +795,7 @@
                                   struct listnode *streams_input_cfg_list);
 void audio_extn_utils_update_stream_output_app_type_cfg(void *platform,
                                   struct listnode *streams_output_cfg_list,
-                                  audio_devices_t devices,
+                                  struct listnode *devices,
                                   audio_output_flags_t flags,
                                   audio_format_t format,
                                   uint32_t sample_rate,
@@ -805,7 +805,7 @@
                                   struct stream_app_type_cfg *app_type_cfg);
 void audio_extn_utils_update_stream_input_app_type_cfg(void *platform,
                                   struct listnode *streams_input_cfg_list,
-                                  audio_devices_t devices,
+                                  struct listnode *devices,
                                   audio_input_flags_t flags,
                                   audio_format_t format,
                                   uint32_t sample_rate,
@@ -1063,7 +1063,7 @@
 void audio_extn_gef_init(struct audio_device *adev);
 void audio_extn_gef_deinit(struct audio_device *adev);
 
-void audio_extn_gef_notify_device_config(audio_devices_t audio_device,
+void audio_extn_gef_notify_device_config(struct listnode *audio_devices,
     audio_channel_mask_t channel_mask, int sample_rate, int acdb_id, int app_type);
 #ifndef INSTANCE_ID_ENABLED
 int audio_extn_gef_send_audio_cal(void* adev, int acdb_dev_id, int acdb_device_type,
@@ -1126,7 +1126,8 @@
 void audio_extn_fm_set_parameters(struct audio_device *adev,
                                    struct str_parms *parms);
 void audio_extn_fm_get_parameters(struct str_parms *query, struct str_parms *reply);
-void audio_extn_fm_route_on_selected_device(struct audio_device *adev, audio_devices_t device);
+void audio_extn_fm_route_on_selected_device(struct audio_device *adev,
+                                            struct listnode *devices);
 
 #ifndef APTX_DECODER_ENABLED
 #define audio_extn_aptx_dec_set_license(adev); (0)
diff --git a/hal/audio_extn/audiozoom.c b/hal/audio_extn/audiozoom.c
index 9958cc4..e2bde0f 100644
--- a/hal/audio_extn/audiozoom.c
+++ b/hal/audio_extn/audiozoom.c
@@ -203,7 +203,7 @@
         qdsp_audiozoom.zoom_param_id == 0)
         return -ENOSYS;
 
-    str_parms_add_int(parms, "cal_devid", in->device);
+    str_parms_add_int(parms, "cal_devid", get_device_types(&in->device_list));
     str_parms_add_int(parms, "cal_apptype", in->app_type_cfg.app_type);
     str_parms_add_int(parms, "cal_topoid", qdsp_audiozoom.topo_id);
     str_parms_add_int(parms, "cal_moduleid", qdsp_audiozoom.module_id);
diff --git a/hal/audio_extn/auto_hal.c b/hal/audio_extn/auto_hal.c
index 41b3762..580d446 100644
--- a/hal/audio_extn/auto_hal.c
+++ b/hal/audio_extn/auto_hal.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -230,7 +230,8 @@
                 ALOGV("Creating audio patch for external FM tuner");
                 uc_info->id = USECASE_AUDIO_FM_TUNER_EXT;
                 uc_info->type = PCM_PASSTHROUGH;
-                uc_info->devices = AUDIO_DEVICE_IN_FM_TUNER;
+                reassign_device_list(&uc_info->device_list, AUDIO_DEVICE_IN_FM_TUNER,
+                                     sources->ext.device.address);
                 uc_info->in_snd_device = SND_DEVICE_IN_CAPTURE_FM;
                 uc_info->out_snd_device = SND_DEVICE_OUT_BUS_MEDIA;
                 break;
@@ -599,8 +600,10 @@
                                                     streams_output_ctxt_t,
                                                     list);
                 /* limit audio gain support for bus device only */
-                if (out_ctxt->output->devices == AUDIO_DEVICE_OUT_BUS &&
-                    out_ctxt->output->devices == config->ext.device.type &&
+                if (is_single_device_type_equal(
+                        &out_ctxt->output->device_list, AUDIO_DEVICE_OUT_BUS) &&
+                    is_single_device_type_equal(&out_ctxt->output->device_list,
+                                                config->ext.device.type) &&
                     strcmp(out_ctxt->output->address,
                         config->ext.device.address) == 0) {
                     /* millibel = 1/100 dB = 1/1000 bel
@@ -710,7 +713,7 @@
 
     uc_downlink_info->type = PCM_HFP_CALL;
     uc_downlink_info->stream.out = adev->primary_output;
-    uc_downlink_info->devices = adev->primary_output->devices;
+    assign_devices(&uc_downlink_info->device_list, &adev->primary_output->device_list);
     uc_downlink_info->in_snd_device = SND_DEVICE_NONE;
     uc_downlink_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -790,12 +793,16 @@
                                 audio_usecase_t uc_id)
 {
     snd_device_t snd_device = SND_DEVICE_NONE;
-    audio_devices_t out_device = AUDIO_DEVICE_NONE;
+    struct listnode out_devices;
     struct audio_usecase *usecase = NULL;
     struct stream_in *in = fp_adev_get_active_input(adev);
-    audio_devices_t in_device = ((in == NULL) ?
-                                    AUDIO_DEVICE_NONE : in->device)
-                                & ~AUDIO_DEVICE_BIT_IN;
+    struct listnode in_devices;
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    list_init(&in_devices);
+    if (in != NULL)
+        assign_devices(&in_devices, &in->device_list);
 
     if (uc_id == USECASE_INVALID) {
         ALOGE("%s: Invalid usecase (%d)", __func__, uc_id);
@@ -813,17 +820,18 @@
         return -EINVAL;
     }
 
-    out_device = usecase->stream.out->devices;
-    if (out_device == AUDIO_DEVICE_NONE ||
-        out_device & AUDIO_DEVICE_BIT_IN) {
-        ALOGE("%s: Invalid output devices (%#x)", __func__, out_device);
+    list_init(&out_devices);
+    assign_devices(&out_devices, &usecase->stream.out->device_list);
+    if (list_empty(&out_devices) ||
+        compare_device_type(&out_devices, AUDIO_DEVICE_BIT_IN)) {
+        ALOGE("%s: Invalid output devices (%#x)", __func__, get_device_types(&out_devices));
         return -EINVAL;
     }
 
     ALOGV("%s: output device(%#x), input device(%#x), usecase(%d)",
-        __func__, out_device, in_device, uc_id);
+        __func__, get_device_types(&out_devices), get_device_types(&in_devices), uc_id);
 
-    if (out_device & AUDIO_DEVICE_OUT_BUS) {
+    if (compare_device_type(&out_devices, AUDIO_DEVICE_OUT_BUS)) {
         /* usecase->id is token as judgement for HFP calls */
         switch (usecase->id) {
         case USECASE_AUDIO_HFP_SCO:
@@ -834,7 +842,7 @@
                 snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP;
             }
             if (adev->enable_hfp)
-                fp_platform_set_echo_reference(adev, true, out_device);
+                fp_platform_set_echo_reference(adev, false, &out_devices);
             break;
         case USECASE_AUDIO_HFP_SCO_DOWNLINK:
             snd_device = SND_DEVICE_IN_BT_SCO_MIC;
@@ -850,7 +858,7 @@
             return -EINVAL;
         }
     } else {
-        ALOGE("%s: Output devices (%#x) not supported", __func__, out_device);
+        ALOGE("%s: Output devices (%#x) not supported", __func__, get_device_types(&out_devices));
         return -EINVAL;
     }
 
@@ -861,7 +869,7 @@
                                 audio_usecase_t uc_id)
 {
     snd_device_t snd_device = SND_DEVICE_NONE;
-    audio_devices_t devices = AUDIO_DEVICE_NONE;
+    struct listnode devices;
     struct audio_usecase *usecase = NULL;
 
     if (uc_id == USECASE_INVALID) {
@@ -880,16 +888,18 @@
         return -EINVAL;
     }
 
-    devices = usecase->stream.out->devices;
-    if (devices == AUDIO_DEVICE_NONE ||
-        devices & AUDIO_DEVICE_BIT_IN) {
-        ALOGE("%s: Invalid output devices (%#x)", __func__, devices);
+    list_init(&devices);
+    assign_devices(&devices, &usecase->stream.out->device_list);
+    if (list_empty(&devices) ||
+        compare_device_type(&devices, AUDIO_DEVICE_BIT_IN)) {
+        ALOGE("%s: Invalid output devices (%#x)", __func__, get_device_types(&devices));
         return -EINVAL;
     }
 
-    ALOGV("%s: output devices(%#x), usecase(%d)", __func__, devices, uc_id);
+    ALOGV("%s: output devices(%#x), usecase(%d)", __func__,
+              get_device_types(&devices), uc_id);
 
-    if (devices & AUDIO_DEVICE_OUT_BUS) {
+    if (compare_device_type(&devices, AUDIO_DEVICE_OUT_BUS)) {
         /* usecase->id is token as judgement for HFP calls */
         switch (usecase->id) {
         case USECASE_AUDIO_HFP_SCO:
@@ -937,7 +947,7 @@
             return -EINVAL;
         }
     } else {
-        ALOGE("%s: Output devices (%#x) not supported", __func__, devices);
+        ALOGE("%s: Output devices (%#x) not supported", __func__, get_device_types(&devices));
         return -EINVAL;
     }
 
diff --git a/hal/audio_extn/device_utils.c b/hal/audio_extn/device_utils.c
new file mode 100644
index 0000000..e67676d
--- /dev/null
+++ b/hal/audio_extn/device_utils.c
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "device_utils"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <stdlib.h>
+#include <hardware/audio.h>
+#include <cutils/list.h>
+#include <log/log.h>
+
+#include "device_utils.h"
+
+/*
+ * 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. 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.
+ */
+static const uint32_t AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND_ARRAY[] = {
+    AUDIO_DEVICE_OUT_EARPIECE,
+    AUDIO_DEVICE_OUT_SPEAKER,
+    AUDIO_DEVICE_OUT_WIRED_HEADSET,
+    AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
+    AUDIO_DEVICE_OUT_LINE,
+    AUDIO_DEVICE_OUT_SPEAKER_SAFE,
+};
+
+/*
+ * Below are the input devices for which back end is same, SLIMBUS_0_TX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+static const uint32_t AUDIO_DEVICE_IN_ALL_CODEC_BACKEND_ARRAY[] = {
+    AUDIO_DEVICE_IN_BUILTIN_MIC,
+    AUDIO_DEVICE_IN_WIRED_HEADSET,
+    AUDIO_DEVICE_IN_VOICE_CALL,
+    AUDIO_DEVICE_IN_BACK_MIC,
+};
+
+static const uint32_t AUDIO_DEVICE_OUT_CODEC_BACKEND_CNT =
+                    AUDIO_ARRAY_SIZE(AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND_ARRAY);
+static const uint32_t AUDIO_DEVICE_IN_CODEC_BACKEND_CNT =
+                    AUDIO_ARRAY_SIZE(AUDIO_DEVICE_IN_ALL_CODEC_BACKEND_ARRAY);
+
+
+int list_length(struct listnode *list)
+{
+    struct listnode *node;
+    int length = 0;
+
+    if (list == NULL)
+        goto done;
+
+    for (node = list->next; node != list; node = node->next)
+        ++length;
+done:
+    return length;
+}
+
+/*
+ * Returns true if devices list contains input device type.
+ */
+bool is_audio_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_input_device(item->type)) {
+            ALOGV("%s: in device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if devices list contains output device type.
+ */
+bool is_audio_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_output_device(item->type)) {
+            ALOGV("%s: out device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if devices list contains codec backend
+ * input device type.
+ */
+bool is_codec_backend_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item == NULL)
+            return false;
+        for (int i = 0; i < AUDIO_DEVICE_IN_CODEC_BACKEND_CNT; i++) {
+            if (item->type == AUDIO_DEVICE_IN_ALL_CODEC_BACKEND_ARRAY[i]) {
+                ALOGV("%s: codec backend in device %#x", __func__, item->type);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if devices list contains codec backend
+ * output device type.
+ */
+bool is_codec_backend_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item == NULL)
+            return false;
+        for (int i = 0; i < AUDIO_DEVICE_OUT_CODEC_BACKEND_CNT; i++) {
+            if (item->type == AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND_ARRAY[i]) {
+                ALOGV("%s: codec backend out device %#x", __func__, item->type);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/* Returns true if USB input device is found in passed devices list */
+bool is_usb_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_usb_in_device(item->type)) {
+            ALOGV("%s: USB in device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if USB output device is found in passed devices list
+ */
+bool is_usb_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_usb_out_device(item->type)) {
+            ALOGV("%s: USB out device %#x address %s", __func__,
+                   item->type, item->address);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns USB device address information (card, device)
+ */
+const char *get_usb_device_address(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && (audio_is_usb_out_device(item->type) ||
+                        audio_is_usb_in_device(item->type))) {
+            ALOGV("%s: USB device %#x address %s", __func__,
+                   item->type, item->address);
+            return (const char *)&item->address[0];
+        }
+    }
+    return "";
+}
+
+/*
+ * Returns true if SCO output device is found in passed devices list
+ */
+bool is_sco_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL &&
+                audio_is_bluetooth_in_sco_device(item->type)) {
+            ALOGV("%s: SCO in device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if SCO output device is found in passed devices list
+ */
+bool is_sco_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL &&
+                audio_is_bluetooth_out_sco_device(item->type)) {
+            ALOGV("%s: SCO out device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if A2DP input device is found in passed devices list
+ */
+bool is_a2dp_in_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_a2dp_in_device(item->type)) {
+            ALOGV("%s: A2DP in device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if A2DP output device is found in passed devices list
+ */
+bool is_a2dp_out_device_type(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_a2dp_out_device(item->type)) {
+            ALOGV("%s: A2DP out device %#x", __func__, item->type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Clear device list
+ * Operation: devices = {};
+ */
+
+int clear_devices(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return 0;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL) {
+            list_remove(&item->list);
+            free(item);
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Check if a device with given type is present in devices list
+ */
+bool compare_device_type(struct listnode *devices, audio_devices_t device_type)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && (item->type == device_type)) {
+            ALOGV("%s: device types %d match", __func__, device_type);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * Returns true if intersection of d1 and d2 is not NULL
+ */
+bool compare_devices_for_any_match(struct listnode *d1, struct listnode *d2)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (d1 == NULL || d2 == NULL)
+        return false;
+
+    list_for_each (node, d1) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && compare_device_type(d2, item->type))
+            return true;
+    }
+    return false;
+}
+
+/*
+ * Returns all device types from list in bitfield
+ * ToDo: Use of this function is not recommended.
+ * It has been introduced for compatability with legacy functions.
+ * This can be removed once audio HAL switches to device
+ * list usage for all audio extensions.
+ */
+audio_devices_t get_device_types(struct listnode *devices)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    audio_devices_t device_type = AUDIO_DEVICE_NONE;
+
+    if (devices == NULL)
+        return false;
+
+    list_for_each (node, devices) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL)
+            device_type |= item->type;
+    }
+    return device_type;
+}
+
+/*
+ * If single device in devices list is equal to passed type
+ * type should represent a single device.
+ */
+bool is_single_device_type_equal(struct listnode *devices,
+                                 audio_devices_t type)
+{
+    struct listnode *node = devices;
+    struct audio_device_info *item = NULL;
+
+    if (devices == NULL)
+        return false;
+
+    if (list_length(devices) == 1) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && (item->type == type))
+            return true;
+    }
+    return false;
+}
+
+/*
+ * Returns true if lists are equal in terms of device type
+ * ToDO: Check if device addresses are also equal in the future
+ */
+bool compare_devices(struct listnode *d1, struct listnode *d2)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+
+    if (d1 == NULL && d2 == NULL)
+        return true;
+
+    if (d1 == NULL || d2 == NULL ||
+            (list_length(d1) != list_length(d2)))
+        return false;
+
+    list_for_each (node, d1) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && !compare_device_type(d2, item->type))
+            return false;
+    }
+    return true;
+}
+
+/*
+ * Add or remove device from list denoted by head
+ */
+int update_device_list(struct listnode *head, audio_devices_t type,
+                       const char* address, bool add_device)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    struct audio_device_info *device = NULL;
+    int ret = 0;
+
+    if (head == NULL)
+        goto done;
+
+    if (type == AUDIO_DEVICE_NONE) {
+        ALOGE("%s: Invalid device: %#x", __func__, type);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    list_for_each (node, head) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && (item->type == type)) {
+            device = item;
+            break;
+        }
+    }
+
+    if (add_device) {
+        if (device == NULL) {
+            device = (struct audio_device_info *)
+                        calloc (1, sizeof(struct audio_device_info));
+            if (!device) {
+                ALOGE("%s: Cannot allocate memory for device_info", __func__);
+                ret = -ENOMEM;
+                goto done;
+            }
+            device->type = type;
+            list_add_tail(head, &device->list);
+        }
+        strlcpy(device->address, address, AUDIO_DEVICE_MAX_ADDRESS_LEN);
+        ALOGV("%s: Added device type %#x, address %s", __func__, type, address);
+    } else {
+        if (device != NULL) {
+            list_remove(&device->list);
+            free(device);
+            ALOGV("%s: Removed device type %#x, address %s", __func__, type, address);
+        }
+    }
+done:
+    return ret;
+}
+
+/*
+ * Assign source device list to destination device list
+ * Operation: dest list = source list
+ */
+int assign_devices(struct listnode *dest, const struct listnode *source)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    int ret = 0;
+
+    if (source == NULL || dest == NULL)
+        return ret;
+
+    if (!list_empty(dest))
+        clear_devices(dest);
+
+    list_for_each (node, source) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL)
+            ret = update_device_list(dest, item->type, item->address, true);
+    }
+    return ret;
+}
+
+/*
+ * Assign output devices from source device list to destination device list
+ * Operation: dest devices = source output devices
+ */
+int assign_output_devices(struct listnode *dest, const struct listnode *source)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    int ret = 0;
+
+    if (source == NULL || dest == NULL)
+        return ret;
+
+    if (!list_empty(dest))
+        clear_devices(dest);
+
+    list_for_each (node, source) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL && audio_is_output_device(item->type))
+            ret = update_device_list(dest, item->type, item->address, true);
+    }
+    return ret;
+}
+
+/*
+ * Clear device list and replace it with single device
+ */
+int reassign_device_list(struct listnode *device_list,
+                            audio_devices_t type, char *address)
+{
+    if (device_list == NULL)
+        return 0;
+
+    if (!list_empty(device_list))
+        clear_devices(device_list);
+
+    return update_device_list(device_list, type, address, true);
+}
+
+/*
+ * Append source devices to destination devices
+ * Operation: dest devices |= source devices
+ */
+int append_devices(struct listnode *dest, const struct listnode *source)
+{
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
+    int ret = 0;
+
+    if (source == NULL || dest == NULL)
+        return ret;
+
+    list_for_each (node, source) {
+        item = node_to_item(node, struct audio_device_info, list);
+        if (item != NULL)
+            ret = update_device_list(dest, item->type, item->address, true);
+    }
+    return ret;
+}
diff --git a/hal/audio_extn/device_utils.h b/hal/audio_extn/device_utils.h
new file mode 100644
index 0000000..b6d4c9b
--- /dev/null
+++ b/hal/audio_extn/device_utils.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AUDIO_HW_EXTN_DEVICE_UTILS_H
+#define AUDIO_HW_EXTN_DEVICE_UTILS_H
+
+struct audio_device_info {
+    struct listnode list;
+    audio_devices_t type;
+    char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+};
+
+int list_length(struct listnode *list);
+bool is_audio_in_device_type(struct listnode *devices);
+bool is_audio_out_device_type(struct listnode *devices);
+bool is_codec_backend_in_device_type(struct listnode *devices);
+bool is_codec_backend_out_device_type(struct listnode *devices);
+bool is_usb_in_device_type(struct listnode *devices);
+bool is_usb_out_device_type(struct listnode *devices);
+const char *get_usb_device_address(struct listnode *devices);
+bool is_sco_in_device_type(struct listnode *devices);
+bool is_sco_out_device_type(struct listnode *devices);
+bool is_a2dp_in_device_type(struct listnode *devices);
+bool is_a2dp_out_device_type(struct listnode *devices);
+int clear_devices(struct listnode *devices);
+bool compare_device_type(struct listnode *devices, audio_devices_t device_type);
+bool compare_devices_for_any_match(struct listnode *d1, struct listnode *d2);
+audio_devices_t get_device_types(struct listnode *devices);
+bool is_single_device_type_equal(struct listnode *devices,
+                                 audio_devices_t type);
+bool compare_devices(struct listnode *d1, struct listnode *d2);
+int update_device_list(struct listnode *head, audio_devices_t type,
+                       const char* address, bool add_device);
+int assign_devices(struct listnode *dest, const struct listnode *source);
+int assign_output_devices(struct listnode *dest, const struct listnode *source);
+int reassign_device_list(struct listnode *device_list,
+                            audio_devices_t type, char *address);
+int append_devices(struct listnode *dest, const struct listnode *source);
+
+#endif
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index 335cfbd..f4a1a97 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, 2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2010 The Android Open Source Project
@@ -246,7 +246,7 @@
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->stream.out && (usecase->type == PCM_PLAYBACK) &&
-            (usecase->devices & ddp_dev) &&
+            (compare_device_type(&usecase->device_list, ddp_dev)) &&
             (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
             ((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
              (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
@@ -264,7 +264,7 @@
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->stream.out && (usecase->type == PCM_PLAYBACK) &&
-            (usecase->devices & AUDIO_DEVICE_OUT_ALL) &&
+            is_audio_out_device_type(&usecase->device_list) &&
             (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
             ((usecase->stream.out->format == AUDIO_FORMAT_AC3) ||
              (usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
@@ -273,11 +273,14 @@
              * Use wfd /hdmi sink channel cap for dolby params if device is wfd
              * or hdmi. Otherwise use stereo configuration
              */
-            int channel_cap = usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ?
+            int channel_cap = compare_device_type(&usecase->device_list,
+                                                  AUDIO_DEVICE_OUT_AUX_DIGITAL) ?
                               adev->cur_hdmi_channels :
-                              usecase->devices & AUDIO_DEVICE_OUT_PROXY ?
+                              compare_device_type(&usecase->device_list,
+                                                  AUDIO_DEVICE_OUT_PROXY) ?
                               adev->cur_wfd_channels : 2;
-            send_ddp_endp_params_stream(usecase->stream.out, usecase->devices,
+            send_ddp_endp_params_stream(usecase->stream.out,
+                                        get_device_types(&usecase->device_list),
                                         channel_cap, false /* set cache */);
         }
     }
@@ -302,7 +305,7 @@
                             sizeof(value));
     if (ret >= 0) {
         ddp_dev = atoi(value);
-        if (!(AUDIO_DEVICE_OUT_ALL & ddp_dev))
+        if (!audio_is_output_device(ddp_dev))
             return;
     } else
         return;
@@ -376,7 +379,7 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if ((usecase->type == PCM_PLAYBACK) &&
             (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) {
-            endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL;
+            endpoint |= is_audio_out_device_type(&usecase->device_list);
             send = true;
         }
     }
@@ -528,7 +531,7 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if ((usecase->type == PCM_PLAYBACK) &&
             (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY)) {
-            endpoint |= usecase->devices & AUDIO_DEVICE_OUT_ALL;
+            endpoint |= is_audio_out_device_type(&usecase->device_list);
             send = true;
         }
     }
diff --git a/hal/audio_extn/ffv.c b/hal/audio_extn/ffv.c
index b97eedc..fe6ffa6 100644
--- a/hal/audio_extn/ffv.c
+++ b/hal/audio_extn/ffv.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -365,13 +365,13 @@
 bool  audio_extn_ffv_check_usecase(struct stream_in *in) {
     int ret = false;
     int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
-    audio_devices_t devices = in->device;
     audio_source_t source = in->source;
 
     if ((audio_extn_ffv_get_enabled()) &&
             (channel_count == 1) &&
             (AUDIO_SOURCE_MIC == source) &&
-            ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
+            (is_single_device_type_equal(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
+             is_single_device_type_equal(&in->device_list, AUDIO_DEVICE_IN_BACK_MIC)) &&
             (in->format == AUDIO_FORMAT_PCM_16_BIT) &&
             (in->sample_rate == FFV_SAMPLING_RATE_16000)) {
         in->config.channels = channel_count;
diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c
index 435c377..a0c2410 100644
--- a/hal/audio_extn/fm.c
+++ b/hal/audio_extn/fm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -182,7 +182,7 @@
     fm_out->format = AUDIO_FORMAT_PCM_16_BIT;
     fm_out->usecase = USECASE_AUDIO_PLAYBACK_FM;
     fm_out->config = pcm_config_fm;
-    fm_out->devices = outputDevices;
+    reassign_device_list(&fm_out->device_list, outputDevices, "");
     fmmod.is_fm_running = true;
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
@@ -195,7 +195,7 @@
     uc_info->id = USECASE_AUDIO_PLAYBACK_FM;
     uc_info->type = PCM_PLAYBACK;
     uc_info->stream.out = fm_out;
-    uc_info->devices = outputDevices;
+    reassign_device_list(&uc_info->device_list, outputDevices, "");
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -240,7 +240,7 @@
     pcm_start(fmmod.fm_pcm_rx);
     pcm_start(fmmod.fm_pcm_tx);
 
-    fmmod.fm_device = fm_out->devices;
+    fmmod.fm_device = get_device_types(&fm_out->device_list);
 
     ALOGD("%s: exit: status(%d)", __func__, ret);
     return 0;
@@ -388,7 +388,8 @@
     ALOGV("%s: exit", __func__);
 }
 
-void audio_extn_fm_route_on_selected_device(struct audio_device *adev, audio_devices_t device)
+void audio_extn_fm_route_on_selected_device(struct audio_device *adev,
+                                            struct listnode *devices)
 {
     struct listnode *node;
     struct audio_usecase *usecase;
@@ -397,10 +398,10 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
-                if (fmmod.fm_device != device) {
+                if (fmmod.fm_device != get_device_types(devices)) {
                     ALOGV("%s selected routing device %x current device %x"
                           "are different, reroute on selected device", __func__,
-                          fmmod.fm_device, device);
+                          fmmod.fm_device, get_device_types(devices));
                     select_devices(adev, usecase->id);
                 }
             }
diff --git a/hal/audio_extn/gef.c b/hal/audio_extn/gef.c
index 83e9d45..69b1e41 100644
--- a/hal/audio_extn/gef.c
+++ b/hal/audio_extn/gef.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -427,15 +427,15 @@
 #endif
 
 //this will be called from HAL to notify GEF of new device configuration
-void audio_extn_gef_notify_device_config(audio_devices_t audio_device,
+void audio_extn_gef_notify_device_config(struct listnode *audio_devices,
     audio_channel_mask_t channel_mask, int sample_rate, int acdb_id, int app_type)
 {
     ALOGV("%s: Enter", __func__);
 
     //call into GEF to share channel mask and device info
     if (gef_hal_handle.handle && gef_hal_handle.device_config_cb) {
-        gef_hal_handle.device_config_cb(gef_hal_handle.gef_ptr, audio_device, channel_mask,
-            sample_rate, acdb_id, app_type);
+        gef_hal_handle.device_config_cb(gef_hal_handle.gef_ptr, get_device_types(audio_devices),
+            channel_mask, sample_rate, acdb_id, app_type);
     }
 
     ALOGV("%s: Exit", __func__);
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index e646bc1..2b63277 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -309,7 +309,7 @@
     uc_info->id = hfpmod.ucid;
     uc_info->type = PCM_HFP_CALL;
     uc_info->stream.out = adev->primary_output;
-    uc_info->devices = adev->primary_output->devices;
+    assign_devices(&uc_info->device_list, &adev->primary_output->device_list);
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -440,6 +440,8 @@
 {
     int32_t ret = 0;
     struct audio_usecase *uc_info;
+    struct listnode *node;
+    struct audio_device_info *item = NULL;
 
     ALOGD("%s: enter", __func__);
     hfpmod.is_hfp_running = false;
@@ -484,7 +486,7 @@
     }
 
     /* 2. Disable echo reference while stopping hfp */
-    fp_platform_set_echo_reference(adev, false, uc_info->devices);
+    fp_platform_set_echo_reference(adev, false, &uc_info->device_list);
 
     /* 3. Get and set stream specific mixer controls */
     fp_disable_audio_route(adev, uc_info);
diff --git a/hal/audio_extn/hw_loopback.c b/hal/audio_extn/hw_loopback.c
index afc029b..0b81fde 100644
--- a/hal/audio_extn/hw_loopback.c
+++ b/hal/audio_extn/hw_loopback.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -496,7 +496,8 @@
     uc_info_rx->id = USECASE_AUDIO_TRANSCODE_LOOPBACK_RX;
     uc_info_rx->type = audio_loopback_mod->uc_type_rx;
     uc_info_rx->stream.inout = &active_loopback_patch->patch_stream;
-    uc_info_rx->devices = active_loopback_patch->patch_stream.out_config.devices;
+    assign_devices(&uc_info_rx->device_list,
+                   &active_loopback_patch->patch_stream.out_config.device_list);
     uc_info_rx->in_snd_device = SND_DEVICE_NONE;
     uc_info_rx->out_snd_device = SND_DEVICE_NONE;
 
@@ -504,7 +505,8 @@
     uc_info_tx->id = USECASE_AUDIO_TRANSCODE_LOOPBACK_TX;
     uc_info_tx->type = audio_loopback_mod->uc_type_tx;
     uc_info_tx->stream.inout = &active_loopback_patch->patch_stream;
-    uc_info_tx->devices = active_loopback_patch->patch_stream.in_config.devices;
+    assign_devices(&uc_info_tx->device_list,
+                   &active_loopback_patch->patch_stream.in_config.device_list);
     uc_info_tx->in_snd_device = SND_DEVICE_NONE;
     uc_info_tx->out_snd_device = SND_DEVICE_NONE;
 
@@ -678,7 +680,7 @@
     stream_cfg->sample_rate = port_cfg->sample_rate;
     stream_cfg->channel_mask = port_cfg->channel_mask;
     stream_cfg->format = port_cfg->format;
-    stream_cfg->devices = port_cfg->ext.device.type;
+    reassign_device_list(&stream_cfg->device_list, port_cfg->ext.device.type, "");
     stream_cfg->bit_width = format_to_bitwidth(port_cfg->format);
 }
 /* API to create audio patch */
diff --git a/hal/audio_extn/keep_alive.c b/hal/audio_extn/keep_alive.c
index 79f2bb0..15725b2 100644
--- a/hal/audio_extn/keep_alive.c
+++ b/hal/audio_extn/keep_alive.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2018, 2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -72,7 +72,7 @@
     ka_mode_t prev_mode;
     bool done;
     void * userdata;
-    audio_devices_t active_devices;
+    struct listnode active_devices;
 } keep_alive_t;
 
 struct keep_alive_cmd {
@@ -128,7 +128,7 @@
     }
     ka.done = false;
     ka.prev_mode = KEEP_ALIVE_OUT_NONE;
-    ka.active_devices = AUDIO_DEVICE_NONE;
+    list_init(&ka.active_devices);
 
     pthread_mutex_init(&ka.lock, (const pthread_mutexattr_t *) NULL);
     pthread_cond_init(&ka.cond, (const pthread_condattr_t *) NULL);
@@ -164,38 +164,38 @@
     ALOGV("%s deinit done", __func__);
 }
 
-audio_devices_t get_device_id_from_mode(ka_mode_t ka_mode)
+void get_device_id_from_mode(ka_mode_t ka_mode,
+                             struct listnode *out_devices)
 {
     struct audio_device * adev = (struct audio_device *)ka.userdata;
-    audio_devices_t out_device = AUDIO_DEVICE_NONE;
+
     switch (ka_mode)
     {
         case KEEP_ALIVE_OUT_PRIMARY:
             if (adev->primary_output) {
-                if (adev->primary_output->devices & AUDIO_DEVICE_OUT_ALL)
-                    out_device = adev->primary_output->devices & AUDIO_DEVICE_OUT_ALL;
+                if (is_audio_out_device_type(&adev->primary_output->device_list))
+                    assign_output_devices(out_devices, &adev->primary_output->device_list);
                 else
-                    out_device = AUDIO_DEVICE_OUT_SPEAKER;
+                    reassign_device_list(out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
             }
             else {
-                out_device = AUDIO_DEVICE_OUT_SPEAKER;
+                reassign_device_list(out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
             }
             break;
 
         case KEEP_ALIVE_OUT_HDMI:
-            out_device = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+            reassign_device_list(out_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL, "");
             break;
-
+        case KEEP_ALIVE_OUT_NONE:
         default:
-            out_device = AUDIO_DEVICE_NONE;
+            break;
     }
-    return out_device;
 }
 
 void keep_alive_start(ka_mode_t ka_mode)
 {
     struct audio_device * adev = (struct audio_device *)ka.userdata;
-    audio_devices_t out_devices = AUDIO_DEVICE_NONE;
+    struct listnode out_devices;
 
     pthread_mutex_lock(&ka.lock);
     ALOGV("%s: mode %x", __func__, ka_mode);
@@ -204,27 +204,32 @@
         goto exit;
     }
 
-    out_devices = get_device_id_from_mode(ka_mode);
-    if ((out_devices == ka.active_devices) && (ka.state == STATE_ACTIVE)) {
-        ALOGV(" %s : Already feeding silence to device %x",__func__, out_devices);
+    list_init(&out_devices);
+    get_device_id_from_mode(ka_mode, &out_devices);
+    if (compare_devices(&out_devices, &ka.active_devices) &&
+            (ka.state == STATE_ACTIVE)) {
+        ALOGV(" %s : Already feeding silence to device %x",__func__,
+              get_device_types(&out_devices));
         ka.prev_mode |= ka_mode;
         goto exit;
     }
-    ALOGV(" %s : active devices %x, new device %x",__func__, ka.active_devices, out_devices);
+    ALOGV(" %s : active devices %x, new device %x",__func__,
+           get_device_types(&ka.active_devices), get_device_types(&out_devices));
 
-    if (out_devices == AUDIO_DEVICE_NONE)
+    if (list_empty(&out_devices))
         goto exit;
 
     if (audio_extn_passthru_is_active()) {
-        ka.active_devices &= ~AUDIO_DEVICE_OUT_AUX_DIGITAL;
-        if(ka.active_devices == AUDIO_DEVICE_NONE)
+        update_device_list(&ka.active_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL,
+                           "", false);
+        if (list_empty(&ka.active_devices))
             goto exit;
     }
 
-    ka.active_devices |= out_devices;
+    append_devices(&ka.active_devices, &out_devices);
     ka.prev_mode |= ka_mode;
     if (ka.state == STATE_ACTIVE) {
-        ka.out->devices = ka.active_devices;
+        assign_devices(&ka.out->device_list, &ka.active_devices);
         select_devices(adev, USECASE_AUDIO_PLAYBACK_SILENCE);
     } else if (ka.state == STATE_IDLE) {
         keep_alive_start_l();
@@ -263,7 +268,7 @@
     }
 
     ka.out->flags = 0;
-    ka.out->devices = ka.active_devices;
+    assign_devices(&ka.out->device_list, &ka.active_devices);
     ka.out->dev = adev;
     ka.out->format = AUDIO_FORMAT_PCM_16_BIT;
     ka.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
@@ -274,6 +279,7 @@
     usecase->stream.out = ka.out;
     usecase->type = PCM_PLAYBACK;
     usecase->id = USECASE_AUDIO_PLAYBACK_SILENCE;
+    list_init(&usecase->device_list);
     usecase->out_snd_device = SND_DEVICE_NONE;
     usecase->in_snd_device = SND_DEVICE_NONE;
 
@@ -304,7 +310,7 @@
 void keep_alive_stop(ka_mode_t ka_mode)
 {
     struct audio_device * adev = (struct audio_device *)ka.userdata;
-    audio_devices_t out_devices;
+    struct listnode out_devices;
     if (ka.state == STATE_DISABLED)
         return;
 
@@ -312,21 +318,23 @@
 
     ALOGV("%s: mode %x", __func__, ka_mode);
     if (ka_mode && (ka.state != STATE_ACTIVE)) {
+        get_device_id_from_mode(ka_mode, &out_devices);
         ALOGV(" %s : Can't stop, keep_alive",__func__);
-        ALOGV(" %s : keep_alive is not running on device %x",__func__, get_device_id_from_mode(ka_mode));
+        ALOGV(" %s : keep_alive is not running on device %x",__func__,
+                get_device_types(&out_devices));
         ka.prev_mode |= ka_mode;
         goto exit;
     }
-    out_devices = get_device_id_from_mode(ka_mode);
+    get_device_id_from_mode(ka_mode, &out_devices);
     if (ka.prev_mode & ka_mode) {
         ka.prev_mode &= ~ka_mode;
-        ka.active_devices = get_device_id_from_mode(ka.prev_mode);
+        get_device_id_from_mode(ka.prev_mode, &ka.active_devices);
     }
 
-    if (ka.active_devices == AUDIO_DEVICE_NONE) {
+    if (list_empty(&ka.active_devices)) {
         keep_alive_cleanup();
-    } else if (ka.out->devices != ka.active_devices){
-        ka.out->devices = ka.active_devices;
+    } else if (!compare_devices(&ka.out->device_list, &ka.active_devices)) {
+        assign_devices(&ka.out->device_list, &ka.active_devices);
         select_devices(adev, USECASE_AUDIO_PLAYBACK_SILENCE);
     }
 exit:
@@ -362,7 +370,7 @@
     }
     pcm_close(ka.pcm);
     ka.pcm = NULL;
-    ka.active_devices = KEEP_ALIVE_OUT_NONE;
+    clear_devices(&ka.active_devices);
     return 0;
 }
 
diff --git a/hal/audio_extn/maxxaudio.c b/hal/audio_extn/maxxaudio.c
index a8f09fc..88de2f2 100644
--- a/hal/audio_extn/maxxaudio.c
+++ b/hal/audio_extn/maxxaudio.c
@@ -100,7 +100,7 @@
 
 typedef struct ma_audio_cal_common_settings {
     unsigned int app_type;
-    unsigned int device;
+    struct listnode devices;
 } ma_audio_cal_common_settings_t;
 
 struct ma_audio_cal_settings {
@@ -237,16 +237,16 @@
          (usecase->id == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) ||
          (usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD)) &&
         /* support devices */
-        ((usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) ||
-         (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
-         (audio_is_usb_out_device(usecase->devices) &&
+        (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
+         compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
+         (is_usb_out_device_type(&usecase->device_list) &&
           ma_supported_usb())))
         /* TODO: enable A2DP when it is ready */
 
         return true;
 
     ALOGV("%s: not support type %d usecase %d device %d",
-           __func__, usecase->type, usecase->id, usecase->devices);
+           __func__, usecase->type, usecase->id, get_device_types(&usecase->device_list));
 
     return false;
 }
@@ -268,7 +268,9 @@
     ma_cal->version.major = AUDIO_CAL_SETTINGS_VERSION_MAJOR_DEFAULT;
     ma_cal->version.minor = AUDIO_CAL_SETTINGS_VERSION_MINOR_DEFAULT;
     ma_cal->common.app_type = APP_TYPE_DEFAULT;
-    ma_cal->common.device = DEVICE_DEFAULT;
+    list_init(&ma_cal->common.devices);
+    update_device_list(&ma_cal->common.devices, DEVICE_DEFAULT,
+                       "", true);
     ma_cal->effect_scope_flag = EFFECTIVE_SCOPE_ALL;
 }
 
@@ -286,10 +288,10 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->stream.out && valid_usecase(usecase)) {
             ma_cal.common.app_type = usecase->stream.out->app_type_cfg.app_type;
-            ma_cal.common.device = usecase->stream.out->devices;
+            assign_devices(&ma_cal.common.devices, &usecase->stream.out->device_list);
             ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
                       __func__, usecase->id, ma_cal.common.app_type,
-                      ma_cal.common.device);
+                      get_device_types(&ma_cal.common.devices));
 
             switch (cmd) {
                 case MA_CMD_VOL:
@@ -304,7 +306,8 @@
 
                 case MA_CMD_SWAP_ENABLE:
                     /* lr swap only enable for speaker path */
-                    if (ma_cal.common.device & AUDIO_DEVICE_OUT_SPEAKER) {
+                    if (compare_device_type(&ma_cal.common.devices,
+                                            AUDIO_DEVICE_OUT_SPEAKER)) {
                         ret = ma_set_lr_swap_l(&ma_cal, true);
                         if (ret)
                             ALOGV("ma_set_lr_swap_l enable returned with success.");
@@ -322,7 +325,8 @@
                     break;
 
                 case MA_CMD_ROTATE_ENABLE:
-                    if (ma_cal.common.device & AUDIO_DEVICE_OUT_SPEAKER) {
+                    if (compare_device_type(&ma_cal.common.devices,
+                                            AUDIO_DEVICE_OUT_SPEAKER)) {
                         ret = ma_set_orientation_l(&ma_cal, my_data->dispaly_orientation);
                         if (ret)
                             ALOGV("ma_set_orientation_l %d returned with success.",
@@ -692,16 +696,17 @@
 
     /* update audio_cal and send it */
     ma_cal.common.app_type = usecase->stream.out->app_type_cfg.app_type;
-    ma_cal.common.device = usecase->stream.out->devices;
+    assign_devices(&ma_cal.common.devices, &usecase->stream.out->device_list);
     ALOGV("%s: send usecase(%d) app_type(%d) device(%d)",
               __func__, usecase->id, ma_cal.common.app_type,
-              ma_cal.common.device);
+              get_device_types(&ma_cal.common.devices));
 
     pthread_mutex_lock(&my_data->lock);
 
     if (is_active()) {
 
-        if (ma_cal.common.device & AUDIO_DEVICE_OUT_SPEAKER) {
+        if (compare_device_type(&ma_cal.common.devices,
+                                AUDIO_DEVICE_OUT_SPEAKER)) {
             if (my_data->orientation_used)
                 ma_set_rotation_l(usecase->stream.out->dev,
                                   my_data->dispaly_orientation);
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index 78a5b7f..293ffac 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -256,7 +256,7 @@
 #else
     compr_passthr = out->compr_config.codec->compr_passthr;
 #endif
-    if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
         (((out->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) ||
         ((out->compr_config.codec != NULL) && (compr_passthr == LEGACY_PCM)))) {
         if (android_atomic_acquire_load(&compress_passthru_active) > 0) {
@@ -292,7 +292,7 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->stream.out && usecase->type == PCM_PLAYBACK &&
-                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+                compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
                 o = usecase->stream.out;
                 temp = o->config.period_size * 1000000LL / o->sample_rate;
                 if (temp > max_period_us)
@@ -321,7 +321,7 @@
         android_atomic_dec(&compress_passthru_active);
     }
 
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         ALOGD("%s: passthru on aux digital, start keep alive", __func__);
         fp_audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
     }
@@ -502,7 +502,7 @@
     }
 
     //check supported device, currently only on HDMI.
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         //passthrough flag
         if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
             return true;
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 4ec524e..46e625d 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -464,7 +464,9 @@
         }
 
         if ((p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD])
-            && (p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+            && compare_device_type(
+                   &p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]->device_list,
+                   AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
                                      (struct audio_stream_out *)(p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD]));
             p_qaf->qaf_mod[i].stream_out[QAF_OUT_OFFLOAD] = NULL;
@@ -525,7 +527,7 @@
         config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
 
         //Device is copied from the QAF passthrough input stream.
-        devices = out->devices;
+        devices = get_device_types(&out->device_list);
         flags = out->flags;
 
         ret = adev_open_output_stream((struct audio_hw_device *)p_qaf->adev,
@@ -711,7 +713,7 @@
 
     ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
           __func__, &out->stream, out->usecase, use_case_table[out->usecase],
-          out->devices);
+          get_device_types(&out->device_list));
 
     if (CARD_STATUS_OFFLINE == out->card_status ||
         CARD_STATUS_OFFLINE == adev->card_status) {
@@ -781,7 +783,8 @@
         }
     }
 
-    if ((adev->is_channel_status_set == false) && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+    if ((adev->is_channel_status_set == false) &&
+         compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
         adev->is_channel_status_set = true;
     }
@@ -1637,9 +1640,9 @@
                 audio_devices_t devices;
 
                 if (qaf_mod->stream_in[QAF_IN_MAIN])
-                    devices = qaf_mod->stream_in[QAF_IN_MAIN]->devices;
+                    devices = get_device_types(&qaf_mod->stream_in[QAF_IN_MAIN]->device_list);
                 else
-                    devices = qaf_mod->stream_in[QAF_IN_PCM]->devices;
+                    devices = get_device_types(&qaf_mod->stream_in[QAF_IN_PCM]->device_list);
 
                 //If multi channel pcm or passthrough is already enabled then remove the hdmi flag from device.
                 if (p_qaf->mch_pcm_hdmi_enabled || p_qaf->passthrough_enabled) {
@@ -2348,7 +2351,7 @@
     /* Setting new device information to the mm module input streams.
      * This is needed if QAF module output streams are not created yet.
      */
-    out->devices = val;
+    reassign_device_list(&out->device_list, val, "");
 
 #ifndef A2DP_OFFLOAD_ENABLED
     if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
diff --git a/hal/audio_extn/qap.c b/hal/audio_extn/qap.c
index 0625737..30ebe6d 100644
--- a/hal/audio_extn/qap.c
+++ b/hal/audio_extn/qap.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -431,7 +431,9 @@
         }
 
         if ((p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD])
-            && (p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD]->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+            && compare_device_type(
+                    &p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD]->device_list,
+                    AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
             adev_close_output_stream((struct audio_hw_device *)p_qap->adev,
                                      (struct audio_stream_out *)(p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD]));
             p_qap->qap_mod[i].stream_out[QAP_OUT_OFFLOAD] = NULL;
@@ -492,7 +494,7 @@
         config.offload_info.channel_mask = config.channel_mask = out->channel_mask;
 
         //Device is copied from the QAP passthrough input stream.
-        devices = out->devices;
+        devices = get_device_types(&out->device_list);
         flags = out->flags;
 
         ret = adev_open_output_stream((struct audio_hw_device *)p_qap->adev,
@@ -870,7 +872,7 @@
 
     ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
           __func__, &out->stream, out->usecase, use_case_table[out->usecase],
-          out->devices);
+          get_device_types(&out->device_list));
 
     if (CARD_STATUS_OFFLINE == out->card_status ||
         CARD_STATUS_OFFLINE == adev->card_status) {
@@ -959,7 +961,8 @@
         }
     }
 
-    if ((adev->is_channel_status_set == false) && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+    if ((adev->is_channel_status_set == false) &&
+         compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
         adev->is_channel_status_set = true;
     }
@@ -1759,9 +1762,9 @@
                 audio_devices_t devices;
 
                 if (qap_mod->stream_in[QAP_IN_MAIN])
-                    devices = qap_mod->stream_in[QAP_IN_MAIN]->devices;
+                    devices = get_device_types(&qap_mod->stream_in[QAP_IN_MAIN]->device_list);
                 else
-                    devices = qap_mod->stream_in[QAP_IN_PCM]->devices;
+                    devices = get_device_types(&qap_mod->stream_in[QAP_IN_PCM]->device_list);
 
                 //If multi channel pcm or passthrough is already enabled then remove the hdmi flag from device.
                 if (p_qap->mch_pcm_hdmi_enabled || p_qap->passthrough_enabled) {
@@ -2595,6 +2598,7 @@
     int ret = 0;
     int err = 0;
     struct qap_module *qap_mod = NULL;
+    char *address = "";
 
     DEBUG_MSG("usecase(%d: %s) kvpairs: %s", out->usecase, use_case_table[out->usecase], kvpairs);
 
@@ -2612,7 +2616,7 @@
     /* Setting new device information to the mm module input streams.
      * This is needed if QAP module output streams are not created yet.
      */
-    out->devices = val;
+    reassign_device_list(&out->device_list, val, address);
 
 #ifndef SPLIT_A2DP_ENABLED
     if (val == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index a175b83..4ef3581 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, 2016-2019 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -53,9 +53,8 @@
 #define MINOR_VERSION(ver) ((ver) & 0x00ff)
 
 /* Proprietary interface version used for compatibility with STHAL */
-#define STHAL_PROP_API_VERSION_1_0 MAKE_HAL_VERSION(1, 0)
-#define STHAL_PROP_API_VERSION_1_1 MAKE_HAL_VERSION(1, 1)
-#define STHAL_PROP_API_CURRENT_VERSION STHAL_PROP_API_VERSION_1_1
+#define STHAL_PROP_API_VERSION_2_0 MAKE_HAL_VERSION(2, 0)
+#define STHAL_PROP_API_CURRENT_VERSION STHAL_PROP_API_VERSION_2_0
 
 #define ST_EVENT_CONFIG_MAX_STR_VALUE 32
 #define ST_DEVICE_HANDSET_MIC 1
@@ -129,7 +128,7 @@
 typedef struct sound_trigger_event_info sound_trigger_event_info_t;
 
 struct sound_trigger_device_info {
-    int device;
+    struct listnode devices;
 };
 
 struct sound_trigger_get_param_data {
@@ -571,7 +570,7 @@
     struct audio_event_info ev_info;
     audio_event_type_t ev;
     /*Initialize to invalid device*/
-    ev_info.device_info.device = -1;
+    list_init(&ev_info.device_info.devices);
 
     if (!st_dev)
        return;
@@ -581,14 +580,10 @@
         return;
     }
 
-    if ((st_dev->sthal_prop_api_version < STHAL_PROP_API_VERSION_1_0) &&
-        (uc_info->type != PCM_PLAYBACK))
-        return;
-
     if ((uc_info->in_snd_device >= SND_DEVICE_IN_BEGIN &&
         uc_info->in_snd_device < SND_DEVICE_IN_END)) {
         if (is_same_as_st_device(uc_info->in_snd_device))
-            ev_info.device_info.device = ST_DEVICE_HANDSET_MIC;
+            update_device_list(&ev_info.device_info.devices, ST_DEVICE_HANDSET_MIC, "", true);
     } else {
         ALOGE("%s: invalid input device 0x%x, for event %d",
                     __func__, uc_info->in_snd_device, event);
@@ -599,9 +594,10 @@
     if (raise_event) {
         if (uc_info->type == PCM_PLAYBACK) {
             if (uc_info->stream.out)
-                ev_info.device_info.device = uc_info->stream.out->devices;
+                assign_devices(&ev_info.device_info.devices, &uc_info->stream.out->device_list);
             else
-                ev_info.device_info.device = AUDIO_DEVICE_OUT_SPEAKER;
+                reassign_device_list(&ev_info.device_info.devices,
+                                     AUDIO_DEVICE_OUT_SPEAKER, "");
             switch(event) {
             case ST_EVENT_STREAM_FREE:
                 st_dev->st_callback(AUDIO_EVENT_PLAYBACK_STREAM_INACTIVE, &ev_info);
@@ -629,9 +625,9 @@
 
 void audio_extn_sound_trigger_update_battery_status(bool charging)
 {
-    struct audio_event_info ev_info;
+    struct audio_event_info ev_info = {{0}, {0}};
 
-    if (!st_dev || st_dev->sthal_prop_api_version < STHAL_PROP_API_VERSION_1_0)
+    if (!st_dev)
         return;
 
     ev_info.u.value = charging;
diff --git a/hal/audio_extn/source_track.c b/hal/audio_extn/source_track.c
index 064fad8..9705d55 100644
--- a/hal/audio_extn/source_track.c
+++ b/hal/audio_extn/source_track.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -230,7 +230,7 @@
 
     if (usecase && (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
         if (is_stt_supported_snd_device(usecase->in_snd_device)) {
-             in_device = get_input_audio_device(usecase->devices);
+             in_device = get_input_audio_device(get_device_types(&usecase->device_list));
              ret = add_audio_intf_name_to_mixer_ctl(in_device, mixer_ctl_name,
                 audio_device_to_interface_table, audio_device_to_interface_table_len);
         } else {
diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c
index d83b508..8cb7b4e 100644
--- a/hal/audio_extn/ssr.c
+++ b/hal/audio_extn/ssr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, 2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -339,7 +339,7 @@
 bool  ssr_check_usecase(struct stream_in *in) {
     int ret = false;
     int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
-    audio_devices_t devices = in->device;
+    audio_devices_t devices = get_device_types(&in->device_list);
     audio_source_t source = in->source;
 
     if ((ssr_get_enabled()) &&
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index a2d559d..531c4b2 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016-2020, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -1472,7 +1472,7 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (usecase->type == PCM_PLAYBACK &&
-                audio_is_usb_out_device(usecase->devices & AUDIO_DEVICE_OUT_ALL_USB )) {
+                is_usb_out_device_type(&usecase->device_list)) {
                 switch (usecase->id) {
                     case USECASE_AUDIO_PLAYBACK_MMAP:
                     case USECASE_AUDIO_PLAYBACK_ULL:
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 92887f0..e56fee3 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -672,7 +672,7 @@
 
 void audio_extn_utils_update_stream_input_app_type_cfg(void *platform,
                                   struct listnode *streams_input_cfg_list,
-                                  audio_devices_t devices __unused,
+                                  struct listnode *devices __unused,
                                   audio_input_flags_t flags,
                                   audio_format_t format,
                                   uint32_t sample_rate,
@@ -710,7 +710,7 @@
 
 void audio_extn_utils_update_stream_output_app_type_cfg(void *platform,
                                   struct listnode *streams_output_cfg_list,
-                                  audio_devices_t devices,
+                                  struct listnode *devices,
                                   audio_output_flags_t flags,
                                   audio_format_t format,
                                   uint32_t sample_rate,
@@ -724,7 +724,7 @@
     struct stream_format *sf_info;
     char value[PROPERTY_VALUE_MAX] = {0};
 
-    if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
+    if (compare_device_type(devices, AUDIO_DEVICE_OUT_SPEAKER)) {
         int bw = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
         if ((-ENOSYS != bw) && (bit_width > (uint32_t)bw))
             bit_width = (uint32_t)bw;
@@ -866,7 +866,7 @@
     case PCM_PLAYBACK:
         audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
-                                                usecase->stream.out->devices,
+                                                &usecase->stream.out->device_list,
                                                 usecase->stream.out->flags,
                                                 usecase->stream.out->hal_op_format,
                                                 usecase->stream.out->sample_rate,
@@ -882,7 +882,7 @@
         else
             audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
                                                 &adev->streams_input_cfg_list,
-                                                usecase->stream.in->device,
+                                                &usecase->stream.in->device_list,
                                                 usecase->stream.in->flags,
                                                 usecase->stream.in->format,
                                                 usecase->stream.in->sample_rate,
@@ -894,7 +894,7 @@
     case TRANSCODE_LOOPBACK_RX :
         audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
-                                                usecase->stream.inout->out_config.devices,
+                                                &usecase->stream.inout->out_config.device_list,
                                                 0,
                                                 usecase->stream.inout->out_config.format,
                                                 usecase->stream.inout->out_config.sample_rate,
@@ -1012,7 +1012,7 @@
         goto exit_send_app_type_cfg;
     }
 
-    if (usecase->devices & AUDIO_DEVICE_OUT_BUS)
+    if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
         is_bus_dev_usecase = true;
 
     snd_device = usecase->out_snd_device;
@@ -1118,7 +1118,8 @@
 
         if (usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
             usecase->stream.out->app_type_cfg.sample_rate = usecase->stream.out->sample_rate;
-        } else if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+        } else if (compare_device_type(&usecase->stream.out->device_list,
+                                       AUDIO_DEVICE_OUT_SPEAKER)) {
             usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         } else if ((snd_device == SND_DEVICE_OUT_HDMI ||
                     snd_device == SND_DEVICE_OUT_USB_HEADSET ||
@@ -1138,7 +1139,7 @@
             (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
             /* Reset to default if no native stream is active*/
             usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-        } else if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        } else if (is_a2dp_out_device_type(&usecase->stream.out->device_list)) {
                  /*
                   * For a2dp playback get encoder sampling rate and set copp sampling rate,
                   * for bit width use the stream param only.
@@ -2101,7 +2102,7 @@
         backend = platform_get_snd_device_backend_interface(usecase->out_snd_device);
         if (!backend) {
             ALOGE("%s: Unsupported device %d", __func__,
-                   usecase->stream.out->devices);
+                   get_device_types(&usecase->stream.out->device_list));
             ret = -EINVAL;
             goto done;
         }