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_hw.c b/hal/audio_hw.c
index 337603a..b873874 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -660,7 +660,7 @@
                                                   uint32_t *dsp_frames) {
     // Adjustment accounts for A2dp encoder latency with offload usecases
     // Note: Encoder latency is returned in ms.
-    if (AUDIO_DEVICE_OUT_ALL_A2DP & out->devices) {
+    if (is_a2dp_out_device_type(&out->device_list)) {
         unsigned long offset =
                 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
         *dsp_frames = (*dsp_frames > offset) ? (*dsp_frames - offset) : 0;
@@ -1182,6 +1182,7 @@
     char mixer_path[MIXER_PATH_MAX_LENGTH];
     struct stream_out *out = NULL;
     struct stream_in *in = NULL;
+    struct listnode out_devices;
     int ret = 0;
 
     if (usecase == NULL)
@@ -1196,25 +1197,30 @@
 
         if (in) {
             if (in->enable_aec || in->enable_ec_port) {
-                audio_devices_t out_device = AUDIO_DEVICE_OUT_SPEAKER;
+                list_init(&out_devices);
+                update_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "", true);
                 struct listnode *node;
                 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
                                                            USECASE_AUDIO_PLAYBACK_VOIP);
                 if (voip_usecase) {
-                    out_device = voip_usecase->stream.out->devices;
+                    assign_devices(&out_devices,
+                                   &voip_usecase->stream.out->device_list);
                 } else if (adev->primary_output &&
                               !adev->primary_output->standby) {
-                    out_device = adev->primary_output->devices;
+                    assign_devices(&out_devices,
+                                   &adev->primary_output->device_list);
                 } else {
                     list_for_each(node, &adev->usecase_list) {
                         uinfo = node_to_item(node, struct audio_usecase, list);
                         if (uinfo->type != PCM_CAPTURE) {
-                            out_device = uinfo->stream.out->devices;
+                            assign_devices(&out_devices,
+                                           &uinfo->stream.out->device_list);
                             break;
                         }
                     }
                 }
-                platform_set_echo_reference(adev, true, out_device);
+
+                platform_set_echo_reference(adev, true, &out_devices);
                 in->ec_opened = true;
             }
         }
@@ -1245,7 +1251,7 @@
 
     if (usecase->type == PCM_CAPTURE) {
         in = usecase->stream.in;
-        if (in && is_loopback_input_device(in->device)) {
+        if (in && is_loopback_input_device(get_device_types(&in->device_list))) {
             ALOGD("%s: set custom mtmx params v1", __func__);
             audio_extn_set_custom_mtmx_params_v1(adev, usecase, true);
         }
@@ -1296,7 +1302,9 @@
     if (usecase->type == PCM_CAPTURE) {
         struct stream_in *in = usecase->stream.in;
         if (in && in->ec_opened) {
-            platform_set_echo_reference(in->dev, false, AUDIO_DEVICE_NONE);
+            struct listnode out_devices;
+            list_init(&out_devices);
+            platform_set_echo_reference(in->dev, false, &out_devices);
             in->ec_opened = false;
         }
     }
@@ -1305,7 +1313,7 @@
 
     if (usecase->type == PCM_CAPTURE) {
         in = usecase->stream.in;
-        if (in && is_loopback_input_device(in->device)) {
+        if (in && is_loopback_input_device(get_device_types(&in->device_list))) {
             ALOGD("%s: reset custom mtmx params v1", __func__);
             audio_extn_set_custom_mtmx_params_v1(adev, usecase, false);
         }
@@ -1598,35 +1606,39 @@
                                                struct audio_usecase *new_uc,
                                                snd_device_t new_snd_device)
 {
-    audio_devices_t a1, a2;
+    struct listnode a1, a2;
 
     snd_device_t d1 = uc->out_snd_device;
     snd_device_t d2 = new_snd_device;
 
+    list_init(&a1);
+    list_init(&a2);
+
     switch (uc->type) {
         case TRANSCODE_LOOPBACK_RX :
-            a1 = uc->stream.inout->out_config.devices;
-            a2 = new_uc->stream.inout->out_config.devices;
+            assign_devices(&a1, &uc->stream.inout->out_config.device_list);
+            assign_devices(&a2, &new_uc->stream.inout->out_config.device_list);
             break;
         default :
-            a1 = uc->stream.out->devices;
-            a2 = new_uc->stream.out->devices;
+            assign_devices(&a1, &uc->stream.out->device_list);
+            assign_devices(&a2, &new_uc->stream.out->device_list);
             break;
     }
 
     // Treat as a special case when a1 and a2 are not disjoint
-    if ((a1 != a2) && (a1 & a2)) {
+    if (!compare_devices(&a1, &a2) &&
+         compare_devices_for_any_match(&a1 ,&a2)) {
         snd_device_t d3[2];
         int num_devices = 0;
         int ret = platform_split_snd_device(platform,
-                                            popcount(a1) > 1 ? d1 : d2,
+                                            list_length(&a1) > 1 ? d1 : d2,
                                             &num_devices,
                                             d3);
         if (ret < 0) {
             if (ret != -ENOSYS) {
                 ALOGW("%s failed to split snd_device %d",
                       __func__,
-                      popcount(a1) > 1 ? d1 : d2);
+                      list_length(&a1) > 1 ? d1 : d2);
             }
             goto end;
         }
@@ -1634,7 +1646,7 @@
         if (platform_check_backends_match(d3[0], d3[1])) {
             return d2; // case 5
         } else {
-            if (popcount(a1) > 1)
+            if (list_length(&a1) > 1)
                 return d1; //case 7
             // check if d1 is related to any of d3's
             if (d1 == d3[0] || d1 == d3[1])
@@ -1716,12 +1728,12 @@
             uc_derive_snd_device = derive_playback_snd_device(adev->platform,
                                                usecase, uc_info, snd_device);
             if (((uc_derive_snd_device != usecase->out_snd_device) || force_routing) &&
-                ((usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
-                (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
-                (usecase->devices & AUDIO_DEVICE_OUT_USB_DEVICE) ||
-                (usecase->devices &  AUDIO_DEVICE_OUT_USB_HEADSET) ||
-                (usecase->devices & AUDIO_DEVICE_OUT_ALL_A2DP) ||
-                (usecase->devices & AUDIO_DEVICE_OUT_ALL_SCO)) &&
+                (is_codec_backend_out_device_type(&usecase->device_list) ||
+                compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
+                compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_DEVICE) ||
+                compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_HEADSET) ||
+                is_a2dp_out_device_type(&usecase->device_list) ||
+                is_sco_out_device_type(&usecase->device_list)) &&
                 ((force_restart_session) ||
                 (platform_check_backends_match(snd_device, usecase->out_snd_device)))) {
                 ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
@@ -1803,7 +1815,7 @@
                                                            usecase->out_snd_device,
                                                            platform_get_input_snd_device(
                                                                adev->platform, NULL,
-                                                               uc_info->devices));
+                                                               &uc_info->device_list));
                     enable_audio_route(adev, usecase);
                     if (usecase->stream.out && usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
                         out_set_voip_volume(&usecase->stream.out->stream,
@@ -1824,7 +1836,7 @@
     struct audio_usecase *usecase;
     bool switch_device[AUDIO_USECASE_MAX];
     int i, num_uc_to_switch = 0;
-    int backend_check_cond = AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND;
+    int backend_check_cond = is_codec_backend_out_device_type(&uc_info->device_list);
     int status = 0;
 
     bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
@@ -1837,7 +1849,7 @@
      * codec backend or vice versa causes issues.
      */
     if (uc_info->type == PCM_CAPTURE)
-        backend_check_cond = AUDIO_DEVICE_IN_ALL_CODEC_BACKEND;
+        backend_check_cond = is_codec_backend_in_device_type(&uc_info->device_list);
     /*
      * This function is to make sure that all the active capture usecases
      * are always routed to the same input sound device.
@@ -1859,13 +1871,14 @@
         if (usecase->type != PCM_PLAYBACK &&
                 usecase != uc_info &&
                 (usecase->in_snd_device != snd_device || force_routing) &&
-                ((uc_info->devices & backend_check_cond) &&
-                 (((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND) ||
+                ((backend_check_cond &&
+                 (is_codec_backend_in_device_type(&usecase->device_list) ||
                   (usecase->type == VOIP_CALL))) &&
                 ((uc_info->type == VOICE_CALL &&
-                  usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL) ||
+                 is_single_device_type_equal(&usecase->device_list,
+                                            AUDIO_DEVICE_IN_VOICE_CALL)) ||
                  platform_check_backends_match(snd_device,\
-                                              usecase->in_snd_device)) &&
+                                              usecase->in_snd_device))) &&
                 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                   __func__, use_case_table[usecase->id],
@@ -2334,8 +2347,8 @@
 
     if (is_offload_usecase(usecase->id) &&
         (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) &&
-        (usecase->stream.out->devices == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
-         usecase->stream.out->devices == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+        (compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
+         compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) {
         is_it_true_mode = (NATIVE_AUDIO_MODE_TRUE_44_1 == platform_get_native_support()? true : false);
          if ((is_it_true_mode && !adev->native_playback_enabled) ||
              (!is_it_true_mode && adev->native_playback_enabled)){
@@ -2347,7 +2360,7 @@
     // Force all a2dp output devices to reconfigure for proper AFE encode format
     //Also handle a case where in earlier a2dp start failed as A2DP stream was
     //in suspended state, hence try to trigger a retry when we again get a routing request.
-    if((usecase->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
+    if(is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
         audio_extn_a2dp_is_force_device_switch()) {
          ALOGD("Force a2dp device switch to update new encoder config");
          ret = true;
@@ -2571,7 +2584,7 @@
             ALOGE("%s: stream.out is NULL", __func__);
             return -EINVAL;
         }
-        if (usecase->devices & AUDIO_DEVICE_OUT_BUS) {
+        if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS)) {
             out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev,
                                                                        uc_id);
             in_snd_device = audio_extn_auto_hal_get_input_snd_device(adev,
@@ -2581,28 +2594,30 @@
                                                             usecase->stream.out);
             in_snd_device = platform_get_input_snd_device(adev->platform,
                                                           NULL,
-                                                          usecase->stream.out->devices);
+                                                          &usecase->stream.out->device_list);
         }
-        usecase->devices = usecase->stream.out->devices;
+        assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
     } else if (usecase->type == TRANSCODE_LOOPBACK_RX) {
         if (usecase->stream.inout == NULL) {
             ALOGE("%s: stream.inout is NULL", __func__);
             return -EINVAL;
         }
-        stream_out.devices = usecase->stream.inout->out_config.devices;
+        assign_devices(&stream_out.device_list, &usecase->stream.inout->out_config.device_list);
         stream_out.sample_rate = usecase->stream.inout->out_config.sample_rate;
         stream_out.format = usecase->stream.inout->out_config.format;
         stream_out.channel_mask = usecase->stream.inout->out_config.channel_mask;
         out_snd_device = platform_get_output_snd_device(adev->platform,
                                                         &stream_out);
-        usecase->devices = out_snd_device;
+        assign_devices(&usecase->device_list,
+                       &usecase->stream.inout->out_config.device_list);
     } else if (usecase->type == TRANSCODE_LOOPBACK_TX ) {
         if (usecase->stream.inout == NULL) {
             ALOGE("%s: stream.inout is NULL", __func__);
             return -EINVAL;
         }
-        in_snd_device = platform_get_input_snd_device(adev->platform, NULL, AUDIO_DEVICE_NONE);
-        usecase->devices = in_snd_device;
+        in_snd_device = platform_get_input_snd_device(adev->platform, NULL, NULL);
+        assign_devices(&usecase->device_list,
+                       &usecase->stream.inout->in_config.device_list);
     } else {
         /*
          * If the voice call is active, use the sound devices of voice call usecase
@@ -2616,12 +2631,14 @@
         if (voice_is_in_call(adev) && adev->mode != AUDIO_MODE_NORMAL) {
             vc_usecase = get_usecase_from_list(adev,
                                                get_usecase_id_from_usecase_type(adev, VOICE_CALL));
-            if ((vc_usecase) && (((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
-                                 (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) ||
-                                 ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
-                                 (usecase->devices & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND)) ||
-                                 (vc_usecase->devices == AUDIO_DEVICE_OUT_HEARING_AID) ||
-                                 (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
+            if ((vc_usecase) && ((is_codec_backend_out_device_type(&vc_usecase->device_list) &&
+                                 is_codec_backend_out_device_type(&usecase->device_list)) ||
+                                 (is_codec_backend_out_device_type(&vc_usecase->device_list) &&
+                                 is_codec_backend_in_device_type(&usecase->device_list)) ||
+                                 is_single_device_type_equal(&vc_usecase->device_list,
+                                                        AUDIO_DEVICE_OUT_HEARING_AID) ||
+                                 is_single_device_type_equal(&usecase->device_list,
+                                                     AUDIO_DEVICE_IN_VOICE_CALL))) {
                 in_snd_device = vc_usecase->in_snd_device;
                 out_snd_device = vc_usecase->out_snd_device;
             }
@@ -2637,9 +2654,9 @@
                                                        adev->platform,
                                                        usecase->stream.out));
             }
-            if ((voip_usecase) && ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
-                ((usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
-                  ((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND)) &&
+            if ((voip_usecase) && (is_codec_backend_out_device_type(&voip_usecase->device_list) &&
+                (is_codec_backend_out_device_type(&usecase->device_list) ||
+                 is_codec_backend_in_device_type(&usecase->device_list)) &&
                 out_snd_device_backend_match &&
                  (voip_usecase->stream.out != adev->primary_output))) {
                     in_snd_device = voip_usecase->in_snd_device;
@@ -2648,7 +2665,7 @@
         } else if (audio_extn_hfp_is_active(adev)) {
             hfp_ucid = audio_extn_hfp_get_usecase();
             hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
-            if ((hfp_usecase) && (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) {
+            if ((hfp_usecase) && is_codec_backend_out_device_type(&hfp_usecase->device_list)) {
                    in_snd_device = hfp_usecase->in_snd_device;
                    out_snd_device = hfp_usecase->out_snd_device;
             }
@@ -2658,12 +2675,12 @@
                 ALOGE("%s: stream.out is NULL", __func__);
                 return -EINVAL;
             }
-            usecase->devices = usecase->stream.out->devices;
+            assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
             in_snd_device = SND_DEVICE_NONE;
             if (out_snd_device == SND_DEVICE_NONE) {
                 struct stream_out *voip_out = adev->primary_output;
                 struct stream_in *voip_in = get_voice_communication_input(adev);
-                if (usecase->devices & AUDIO_DEVICE_OUT_BUS)
+                if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
                     out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
                 else
                     out_snd_device = platform_get_output_snd_device(adev->platform,
@@ -2681,13 +2698,14 @@
                 ALOGE("%s: stream.in is NULL", __func__);
                 return -EINVAL;
             }
-            usecase->devices = usecase->stream.in->device;
+            assign_devices(&usecase->device_list, &usecase->stream.in->device_list);
             out_snd_device = SND_DEVICE_NONE;
             if (in_snd_device == SND_DEVICE_NONE) {
-                audio_devices_t out_device = AUDIO_DEVICE_NONE;
+                struct listnode out_devices;
                 struct stream_in *voip_in = get_voice_communication_input(adev);
                 struct stream_in *priority_in = NULL;
 
+                list_init(&out_devices);
                 if (voip_in != NULL) {
                     struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
                                                              USECASE_AUDIO_PLAYBACK_VOIP);
@@ -2695,16 +2713,16 @@
                     usecase->stream.in->enable_ec_port = false;
 
                     if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
-                        out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
+                        reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_TELEPHONY_TX, "");
                     } else if (voip_usecase) {
-                        out_device = voip_usecase->stream.out->devices;
+                        assign_devices(&out_devices, &voip_usecase->stream.out->device_list);
                     } else if (adev->primary_output &&
                                   !adev->primary_output->standby) {
-                        out_device = adev->primary_output->devices;
+                        assign_devices(&out_devices, &adev->primary_output->device_list);
                     } else {
                         /* forcing speaker o/p device to get matching i/p pair
                            in case o/p is not routed from same primary HAL */
-                        out_device = AUDIO_DEVICE_OUT_SPEAKER;
+                        reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
                     }
                     priority_in = voip_in;
                 } else {
@@ -2717,7 +2735,7 @@
 
                 in_snd_device = platform_get_input_snd_device(adev->platform,
                                                               priority_in,
-                                                              out_device);
+                                                              &out_devices);
             }
         }
     }
@@ -2729,9 +2747,9 @@
             return 0;
     }
 
-    if (!(usecase->devices & AUDIO_DEVICE_OUT_BUS) &&
+    if (!compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) &&
         ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
-            (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
+         (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
         ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
         return 0;
     }
@@ -2852,7 +2870,7 @@
                                                             usecase);
     if (usecase->type == PCM_PLAYBACK) {
         if ((24 == usecase->stream.out->bit_width) &&
-                (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+                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 ((out_snd_device == SND_DEVICE_OUT_HDMI ||
                     out_snd_device == SND_DEVICE_OUT_USB_HEADSET ||
@@ -2982,7 +3000,7 @@
     /* 2. Disable the tx device */
     disable_snd_device(adev, uc_info->in_snd_device);
 
-    if (is_loopback_input_device(in->device))
+    if (is_loopback_input_device(get_device_types(&in->device_list)))
         audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
 
     list_remove(&uc_info->list);
@@ -3026,7 +3044,7 @@
         goto error_config;
     }
 
-    if (audio_is_bluetooth_sco_device(in->device)) {
+    if (is_sco_in_device_type(&in->device_list)) {
         if (!adev->bt_sco_on) {
             ALOGE("%s: SCO profile is not ready, return error", __func__);
             ret = -EIO;
@@ -3065,7 +3083,8 @@
     uc_info->id = in->usecase;
     uc_info->type = PCM_CAPTURE;
     uc_info->stream.in = in;
-    uc_info->devices = in->device;
+    list_init(&uc_info->device_list);
+    assign_devices(&uc_info->device_list, &in->device_list);
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
@@ -3175,7 +3194,7 @@
     audio_extn_audiozoom_set_microphone_direction(in, in->zoom);
     audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction);
 
-    if (is_loopback_input_device(in->device))
+    if (is_loopback_input_device(get_device_types(&in->device_list)))
         audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
 
 done_open:
@@ -3556,7 +3575,7 @@
                                                 adev->dsp_bit_width_enforce_mode,
                                                 false);
     }
-    if (audio_is_usb_out_device(out->devices & AUDIO_DEVICE_OUT_ALL_USB)) {
+    if (is_usb_out_device_type(&out->device_list)) {
         ret = audio_extn_usb_check_and_set_svc_int(uc_info,
                                                    false);
 
@@ -3584,7 +3603,7 @@
     }
 
     /* Must be called after removing the usecase from list */
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL))
         audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
 
     if (out->ip_hdlr_handle) {
@@ -3598,7 +3617,7 @@
        2) trigger voip input to reroute when voip output changes to
           hearing aid. */
     if (has_voip_usecase ||
-            out->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+            compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
         struct listnode *node;
         struct audio_usecase *usecase;
         list_for_each(node, &adev->usecase_list) {
@@ -3675,7 +3694,12 @@
 
     ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x) is_haptic_usecase(%d)",
           __func__, &out->stream, out->usecase, use_case_table[out->usecase],
-          out->devices, is_haptic_usecase);
+          get_device_types(&out->device_list), is_haptic_usecase);
+
+    bool is_speaker_active = compare_device_type(&out->device_list,
+                                                 AUDIO_DEVICE_OUT_SPEAKER);
+    bool is_speaker_safe_active = compare_device_type(&out->device_list,
+                                                      AUDIO_DEVICE_OUT_SPEAKER_SAFE);
 
     if (CARD_STATUS_OFFLINE == out->card_status ||
         CARD_STATUS_OFFLINE == adev->card_status) {
@@ -3694,10 +3718,9 @@
         }
     }
 
-    if (out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+    if (is_a2dp_out_device_type(&out->device_list)) {
         if (!audio_extn_a2dp_source_is_ready()) {
-            if (out->devices &
-                (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+            if (is_speaker_active || is_speaker_safe_active) {
                 a2dp_combo = true;
             } else {
                 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
@@ -3708,12 +3731,12 @@
             }
         }
     }
-    if (out->devices & AUDIO_DEVICE_OUT_ALL_SCO) {
+    if (is_sco_out_device_type(&out->device_list)) {
         if (!adev->bt_sco_on) {
-            if (out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+            if (is_speaker_active) {
                 //combo usecase just by pass a2dp
                 ALOGW("%s: SCO is not connected, route it to speaker", __func__);
-                out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+                reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
             } else {
                 ALOGE("%s: SCO profile is not ready, return error", __func__);
                 ret = -EAGAIN;
@@ -3750,12 +3773,13 @@
     uc_info->id = out->usecase;
     uc_info->type = PCM_PLAYBACK;
     uc_info->stream.out = out;
-    uc_info->devices = out->devices;
+    list_init(&uc_info->device_list);
+    assign_devices(&uc_info->device_list, &out->device_list);
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
 
     /* This must be called before adding this usecase to the list */
-    if (audio_is_usb_out_device(out->devices & AUDIO_DEVICE_OUT_ALL_USB)) {
+    if (is_usb_out_device_type(&out->device_list)) {
        audio_extn_usb_check_and_set_svc_int(uc_info, true);
        /* USB backend is not reopened immediately.
        This is eventually done as part of select_devices */
@@ -3768,7 +3792,7 @@
                                  adev->perf_lock_opts,
                                  adev->perf_lock_opts_size);
 
-    if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
         audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_HDMI);
         if (audio_extn_passthru_is_enabled() &&
             audio_extn_passthru_is_passthrough_stream(out)) {
@@ -3776,18 +3800,22 @@
         }
     }
 
-    if ((out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
+    if (is_a2dp_out_device_type(&out->device_list) &&
         (!audio_extn_a2dp_source_is_ready())) {
         if (!a2dp_combo) {
             check_a2dp_restore_l(adev, out, false);
         } else {
-            audio_devices_t dev = out->devices;
-            if (dev & AUDIO_DEVICE_OUT_SPEAKER_SAFE)
-                out->devices = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+            struct listnode dev;
+            list_init(&dev);
+            assign_devices(&dev, &out->device_list);
+            if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
+                reassign_device_list(&out->device_list,
+                                AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
             else
-                out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+                reassign_device_list(&out->device_list,
+                                AUDIO_DEVICE_OUT_SPEAKER, "");
             select_devices(adev, out->usecase);
-            out->devices = dev;
+            assign_devices(&out->device_list, &dev);
         }
     } else {
          select_devices(adev, out->usecase);
@@ -3951,7 +3979,7 @@
             audio_extn_check_and_set_dts_hpx_state(adev);
         }
 
-        if (out->devices & AUDIO_DEVICE_OUT_BUS) {
+        if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
             /* Update cached volume from media to offload/direct stream */
             struct listnode *node = NULL;
             list_for_each(node, &adev->active_outputs_list) {
@@ -4391,7 +4419,7 @@
             stop_output_stream(out);
         }
         // if fm is active route on selected device in UI
-        audio_extn_fm_route_on_selected_device(adev, out->devices);
+        audio_extn_fm_route_on_selected_device(adev, &out->device_list);
         pthread_mutex_unlock(&adev->lock);
     }
     pthread_mutex_unlock(&out->lock);
@@ -4602,22 +4630,20 @@
 }
 
 int route_output_stream(struct stream_out *out,
-                        audio_devices_t devices,
-                        char *address)
+                        struct listnode *devices)
 {
     struct audio_device *adev = out->dev;
-    struct str_parms *addr;
     int ret = 0;
-    audio_devices_t new_devices = devices;
+    struct listnode new_devices;
     bool bypass_a2dp = false;
     bool reconfig = false;
     unsigned long service_interval = 0;
 
     ALOGD("%s: enter: usecase(%d: %s) devices %x",
-          __func__, out->usecase, use_case_table[out->usecase], devices);
-    addr = str_parms_create_str(address);
-    if (!addr)
-        goto error;
+          __func__, out->usecase, use_case_table[out->usecase], get_device_types(devices));
+
+    list_init(&new_devices);
+    assign_devices(&new_devices, devices);
 
     lock_output_stream(out);
     pthread_mutex_lock(&adev->lock);
@@ -4629,11 +4655,11 @@
      * turned off, the write gets blocked.
      * Avoid this by routing audio to speaker until standby.
      */
-    if ((out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
-            (new_devices == AUDIO_DEVICE_NONE) &&
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+            list_empty(&new_devices) &&
             !audio_extn_passthru_is_passthrough_stream(out) &&
             (platform_get_edid_info(adev->platform) != 0) /* HDMI disconnected */) {
-        new_devices = AUDIO_DEVICE_OUT_SPEAKER;
+        reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
     }
     /*
      * When A2DP is disconnected the
@@ -4642,11 +4668,11 @@
      * (3sec). As BT is turned off, the write gets blocked.
      * Avoid this by routing audio to speaker until standby.
      */
-    if ((out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
-            (new_devices == AUDIO_DEVICE_NONE) &&
+    if (is_a2dp_out_device_type(&out->device_list) &&
+            list_empty(&new_devices) &&
             !audio_extn_a2dp_source_is_ready() &&
             !adev->bt_sco_on) {
-            new_devices = AUDIO_DEVICE_OUT_SPEAKER;
+        reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
     }
     /*
      * When USB headset is disconnected the music platback paused
@@ -4655,18 +4681,18 @@
      * when USB is connected back. So routing to speker will guarantee
      * AFE reconfiguration and AFE will be opend once USB is connected again
      */
-    if ((out->devices & AUDIO_DEVICE_OUT_ALL_USB) &&
-            (new_devices == AUDIO_DEVICE_NONE) &&
-            !audio_extn_usb_connected(addr))
-        new_devices = AUDIO_DEVICE_OUT_SPEAKER;
-
+    if (is_usb_out_device_type(&out->device_list) &&
+            list_empty(&new_devices) &&
+            !audio_extn_usb_connected(NULL)) {
+        reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
+    }
     /* To avoid a2dp to sco overlapping / BT device improper state
      * check with BT lib about a2dp streaming support before routing
      */
-    if (new_devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+    if (is_a2dp_out_device_type(&new_devices)) {
         if (!audio_extn_a2dp_source_is_ready()) {
-            if (new_devices &
-                (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+            if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
+                compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
                 //combo usecase just by pass a2dp
                 ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
                 bypass_a2dp = true;
@@ -4676,7 +4702,7 @@
                  * However it is still possible a2dp routing called because
                  * of current active device disconnection (like wired headset)
                  */
-                out->devices = new_devices;
+                assign_devices(&out->device_list, &new_devices);
                 pthread_mutex_unlock(&adev->lock);
                 pthread_mutex_unlock(&out->lock);
                 goto error;
@@ -4684,17 +4710,23 @@
         }
     }
 
-
     // Workaround: If routing to an non existing usb device, fail gracefully
     // The routing request will otherwise block during 10 second
     int card;
-    if (audio_is_usb_out_device(new_devices) &&
-        (card = get_alive_usb_card(addr)) >= 0) {
-        ALOGW("out_set_parameters() ignoring rerouting to non existing USB card %d", card);
-        pthread_mutex_unlock(&adev->lock);
-        pthread_mutex_unlock(&out->lock);
-        ret = -ENOSYS;
-        goto error;
+    if (is_usb_out_device_type(&new_devices)) {
+        struct str_parms *parms =
+            str_parms_create_str(get_usb_device_address(&new_devices));
+        if (!parms)
+            goto error;
+        if ((card = get_alive_usb_card(parms)) >= 0) {
+            ALOGW("%s: ignoring rerouting to non existing USB card %d", __func__, card);
+            pthread_mutex_unlock(&adev->lock);
+            pthread_mutex_unlock(&out->lock);
+            str_parms_destroy(parms);
+            ret = -ENOSYS;
+            goto error;
+        }
+        str_parms_destroy(parms);
     }
 
     /*
@@ -4715,15 +4747,15 @@
      *       Because select_devices() must be called to switch back the music
      *       playback to headset.
      */
-    if (new_devices != AUDIO_DEVICE_NONE) {
-        bool same_dev = out->devices == new_devices;
-        out->devices = new_devices;
+    if (!list_empty(&new_devices)) {
+        bool same_dev = compare_devices(&out->device_list, &new_devices);
+        assign_devices(&out->device_list, &new_devices);
 
         if (output_drives_call(adev, out)) {
             if (!voice_is_call_state_active(adev)) {
                 if (adev->mode == AUDIO_MODE_IN_CALL) {
                     adev->current_call_output = out;
-                    if (audio_is_usb_out_device(out->devices & AUDIO_DEVICE_OUT_ALL_USB)) {
+                    if (is_usb_out_device_type(&out->device_list)) {
                         service_interval =
                             audio_extn_usb_find_service_interval(true, true /*playback*/);
                         audio_extn_usb_set_service_interval(true /*playback*/,
@@ -4752,12 +4784,12 @@
             if (!bypass_a2dp) {
                 select_devices(adev, out->usecase);
             } else {
-                if (new_devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE)
-                    out->devices = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+                if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
+                    reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
                 else
-                    out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+                    reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
                 select_devices(adev, out->usecase);
-                out->devices = new_devices;
+                assign_devices(&out->device_list, &new_devices);
             }
 
             if (!same_dev) {
@@ -4768,7 +4800,7 @@
             }
             if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
                  out->a2dp_compress_mute &&
-                 (!(out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) || audio_extn_a2dp_source_is_ready())) {
+                 (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready())) {
                 pthread_mutex_lock(&out->compr_mute_lock);
                 out->a2dp_compress_mute = false;
                 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
@@ -4786,8 +4818,6 @@
     audio_extn_extspk_update(adev->extspk);
 
 error:
-    if (addr)
-        str_parms_destroy(addr);
     ALOGV("%s: exit: code(%d)", __func__, ret);
     return ret;
 }
@@ -4849,7 +4879,8 @@
         lock_output_stream(out);
         audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                           &adev->streams_output_cfg_list,
-                                                          out->devices, out->flags, out->hal_op_format,
+                                                          &out->device_list, out->flags,
+                                                          out->hal_op_format,
                                                           out->sample_rate, out->bit_width,
                                                           out->channel_mask, out->profile,
                                                           &out->app_type_cfg);
@@ -5178,7 +5209,7 @@
            (out->config.rate);
     }
 
-    if (AUDIO_DEVICE_OUT_ALL_A2DP & out->devices)
+    if (is_a2dp_out_device_type(&out->device_list))
         latency += audio_extn_a2dp_get_encoder_latency();
 
     ALOGV("%s: Latency %d", __func__, latency);
@@ -5352,7 +5383,7 @@
             volume[1] = (long)(AmpToDb(right));
             mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
             return 0;
-        } else if ((out->devices & AUDIO_DEVICE_OUT_BUS) &&
+        } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS) &&
                 (out->car_audio_stream == CAR_AUDIO_STREAM_MEDIA)) {
             ALOGD("%s: Overriding offload set volume for media bus stream", __func__);
             struct listnode *node = NULL;
@@ -5577,7 +5608,7 @@
         goto exit;
     }
 
-    if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
          !out->is_iec61937_info_available) {
 
         if (!audio_extn_passthru_is_passthrough_stream(out)) {
@@ -5631,10 +5662,10 @@
         }
     }
 
-    if ((out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) &&
+    if (is_a2dp_out_device_type(&out->device_list) &&
         (audio_extn_a2dp_source_is_suspended())) {
-        if (!(out->devices &
-            (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
+        if (!(compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
+              compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
             if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
                 ret = -EIO;
                 goto exit;
@@ -5672,7 +5703,9 @@
             audio_extn_send_dual_mono_mixing_coefficients(out);
     }
 
-    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, (void *)buffer, bytes);
         adev->is_channel_status_set = true;
     }
@@ -6029,7 +6062,7 @@
                  &out->sample_rate);
         // Adjustment accounts for A2dp encoder latency with offload usecases
         // Note: Encoder latency is returned in ms.
-        if (AUDIO_DEVICE_OUT_ALL_A2DP & out->devices) {
+        if (is_a2dp_out_device_type(&out->device_list)) {
             unsigned long offset =
                         (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
             dsp_frames = (dsp_frames > offset) ? (dsp_frames - offset) : 0;
@@ -6068,7 +6101,7 @@
 
                 // Adjustment accounts for A2dp encoder latency with non offload usecases
                 // Note: Encoder latency is returned in ms, while platform_render_latency in us.
-                if (AUDIO_DEVICE_OUT_ALL_A2DP & out->devices) {
+                if (is_a2dp_out_device_type(&out->device_list)) {
                     frames_temp = audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000;
                     if (signed_frames >= frames_temp)
                         signed_frames -= frames_temp;
@@ -6596,8 +6629,7 @@
 }
 
 int route_input_stream(struct stream_in *in,
-                       audio_devices_t devices,
-                       char *address,
+                       struct listnode *devices,
                        audio_source_t source)
 {
     struct audio_device *adev = in->dev;
@@ -6623,22 +6655,20 @@
         }
     }
 
-    if ((in->device != devices) && (devices != AUDIO_DEVICE_NONE) &&
-          audio_is_input_device(devices)) {
+    if (!compare_devices(&in->device_list, devices) && !list_empty(devices) &&
+          is_audio_in_device_type(devices)) {
         // Workaround: If routing to an non existing usb device, fail gracefully
         // The routing request will otherwise block during 10 second
         int card;
-        struct str_parms *addr = str_parms_create_str(address);
-
-        if (!addr)
-            return ret;
-        if (audio_is_usb_in_device(devices) &&
-            (card = get_alive_usb_card(addr)) >= 0) {
+        struct str_parms *usb_addr =
+                str_parms_create_str(get_usb_device_address(devices));
+        if (is_usb_in_device_type(devices) && usb_addr &&
+             (card = get_alive_usb_card(usb_addr)) >= 0) {
             ALOGW("%s: ignoring rerouting to non existing USB card %d", __func__, card);
             ret = -ENOSYS;
         } else {
-            in->device = devices;
             /* If recording is in progress, change the tx device to new device */
+            assign_devices(&in->device_list, devices);
             if (!in->standby && !in->is_st_session) {
                 ALOGV("update input routing change");
                 // inform adm before actual routing to prevent glitches.
@@ -6651,7 +6681,8 @@
                 }
             }
         }
-        str_parms_destroy(addr);
+        if (usb_addr)
+            str_parms_destroy(usb_addr);
     }
     pthread_mutex_unlock(&adev->lock);
     pthread_mutex_unlock(&in->lock);
@@ -6682,7 +6713,7 @@
         ALOGV("updating stream profile with value '%s'", in->profile);
         audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
                                                           &adev->streams_input_cfg_list,
-                                                          in->device, in->flags, in->format,
+                                                          &in->device_list, in->flags, in->format,
                                                           in->sample_rate, in->bit_width,
                                                           in->profile, &in->app_type_cfg);
     }
@@ -7358,22 +7389,24 @@
     int error = 0;
     struct stream_in *in = (struct stream_in *)stream;
     struct audio_device *adev = in->dev;
-    audio_devices_t device = AUDIO_DEVICE_NONE;
+    struct listnode devices;
+
+    list_init(&devices);
 
     if (sink_metadata->track_count != 0)
-        device = sink_metadata->tracks->dest_device;
+        reassign_device_list(&devices, sink_metadata->tracks->dest_device, "");
 
     lock_input_stream(in);
     pthread_mutex_lock(&adev->lock);
-    ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, device);
+    ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, get_device_types(&devices));
 
     if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY
-            && device != AUDIO_DEVICE_NONE
+            && !list_empty(&devices)
             && adev->voice_tx_output != NULL) {
         /* Use the rx device from afe-proxy record to route voice call because
            there is no routing if tx device is on primary hal and rx device
            is on other hal during voice call. */
-        adev->voice_tx_output->devices = device;
+        assign_devices(&adev->voice_tx_output->device_list, &devices);
 
         if (!voice_is_call_state_active(adev)) {
             if (adev->mode == AUDIO_MODE_IN_CALL) {
@@ -7456,7 +7489,8 @@
         devices = AUDIO_DEVICE_OUT_SPEAKER;
 
     out->flags = flags;
-    out->devices = devices;
+    list_init(&out->device_list);
+    update_device_list(&out->device_list, devices, address, true /* add devices */);
     out->dev = adev;
     out->hal_op_format = out->hal_ip_format = format = out->format = config->format;
     out->sample_rate = config->sample_rate;
@@ -7564,7 +7598,7 @@
     }
 
     /* validate bus device address */
-    if (out->devices & AUDIO_DEVICE_OUT_BUS) {
+    if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
         /* extract car audio stream index */
         out->car_audio_stream =
             audio_extn_auto_hal_get_car_audio_stream_from_address(address);
@@ -7709,7 +7743,7 @@
         }
 
         if (out->usecase == USECASE_INVALID) {
-            if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL &&
+            if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
                     config->format == 0 && config->sample_rate == 0 &&
                     config->channel_mask == 0) {
                 ALOGI("%s dummy open to query sink capability",__func__);
@@ -7962,7 +7996,8 @@
                 __func__, ret);
             goto error_open;
         }
-    } else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+    } else if (is_single_device_type_equal(&out->device_list,
+                                           AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
         switch (config->sample_rate) {
             case 0:
                 out->sample_rate = AFE_PROXY_SAMPLING_RATE;
@@ -8092,7 +8127,7 @@
                 adev->haptics_config.channels = 1;
             } else
                 adev->haptics_config.channels = audio_channel_count_from_out_mask(out->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL);
-        } else if (out->devices & AUDIO_DEVICE_OUT_BUS) {
+        } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
             ret = audio_extn_auto_hal_open_output_stream(out);
             if (ret) {
                 ALOGE("%s: Failed to open output stream for bus device", __func__);
@@ -8134,7 +8169,8 @@
         out->bit_width = 16;
     audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
-                                                devices, out->flags, out->hal_op_format, out->sample_rate,
+                                                &out->device_list, out->flags,
+                                                out->hal_op_format, out->sample_rate,
                                                 out->bit_width, out->channel_mask, out->profile,
                                                 &out->app_type_cfg);
     if ((out->usecase == (audio_usecase_t)(GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary))) ||
@@ -8421,10 +8457,10 @@
             list_for_each(node, &adev->usecase_list) {
                 usecase = node_to_item(node, struct audio_usecase, list);
                 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
-                    ((usecase->stream.in->device & ~AUDIO_DEVICE_BIT_IN) &
-                        AUDIO_DEVICE_IN_ALL_SCO)) {
+                    is_sco_in_device_type(&usecase->stream.in->device_list)) {
                     ALOGD("a2dp resumed, switch bt sco mic to handset mic");
-                    usecase->stream.in->device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+                    reassign_device_list(&usecase->stream.in->device_list,
+                                         AUDIO_DEVICE_IN_BUILTIN_MIC, "");
                     select_devices(adev, usecase->id);
                 }
             }
@@ -8571,7 +8607,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_A2DP)){
+                is_a2dp_out_device_type(&usecase->device_list)) {
                 ALOGD("reconfigure a2dp... forcing device switch");
                 pthread_mutex_unlock(&adev->lock);
                 lock_output_stream(usecase->stream.out);
@@ -8592,7 +8628,8 @@
                 pthread_mutex_unlock(&adev->lock);
                 lock_output_stream(usecase->stream.out);
                 pthread_mutex_lock(&adev->lock);
-                usecase->stream.out->devices = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+                reassign_device_list(&usecase->stream.out->device_list,
+                                     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
                 check_a2dp_restore_l(adev, usecase->stream.out, true);
                 pthread_mutex_unlock(&usecase->stream.out->lock);
                 break;
@@ -8927,7 +8964,7 @@
                                   struct audio_config *config,
                                   struct audio_stream_in **stream_in,
                                   audio_input_flags_t flags,
-                                  const char *address __unused,
+                                  const char *address,
                                   audio_source_t source)
 {
     struct audio_device *adev = (struct audio_device *)dev;
@@ -9013,7 +9050,8 @@
     in->stream.set_microphone_field_dimension = in_set_microphone_field_dimension;
     in->stream.update_sink_metadata = in_update_sink_metadata;
 
-    in->device = devices;
+    list_init(&in->device_list);
+    update_device_list(&in->device_list, devices, address, true);
     in->source = source;
     in->dev = adev;
     in->standby = 1;
@@ -9173,8 +9211,10 @@
         default:
             in->bit_width = 16;
         }
-    } else if ((in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) ||
-             (in->device == AUDIO_DEVICE_IN_PROXY)) {
+    } else if (is_single_device_type_equal(&in->device_list,
+                                           AUDIO_DEVICE_IN_TELEPHONY_RX) ||
+               is_single_device_type_equal(&in->device_list,
+                                           AUDIO_DEVICE_IN_PROXY)) {
         if (config->sample_rate == 0)
             config->sample_rate = AFE_PROXY_SAMPLING_RATE;
         if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
@@ -9299,7 +9339,7 @@
 
     audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
                                                 &adev->streams_input_cfg_list,
-                                                devices, flags, in->format,
+                                                &in->device_list, flags, in->format,
                                                 in->sample_rate, in->bit_width,
                                                 in->profile, &in->app_type_cfg);
     register_format(in->format, in->supported_formats);
@@ -9366,6 +9406,10 @@
 
     ALOGD("%s: enter:stream_handle(%p)",__func__, in);
 
+    if (in == NULL) {
+        ALOGE("%s: audio_stream_in ptr is NULL", __func__);
+        return;
+    }
     io_streams_map_remove(adev, in->capture_handle);
 
     /* must deregister from sndmonitor first to prevent races
@@ -9378,15 +9422,13 @@
      */
     if (adev_get_active_input(adev) == NULL &&
         !audio_extn_hfp_is_active(adev) &&
-        !audio_extn_sound_trigger_check_ec_ref_enable())
-        platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
-    else
+        !audio_extn_sound_trigger_check_ec_ref_enable()) {
+        struct listnode out_devices;
+        list_init(&out_devices);
+        platform_set_echo_reference(adev, false, &out_devices);
+    } else
         audio_extn_sound_trigger_update_ec_ref_status(false);
 
-    if (in == NULL) {
-        ALOGE("%s: audio_stream_in ptr is NULL", __func__);
-        return;
-    }
     error_log_destroy(in->error_log);
     in->error_log = NULL;
 
@@ -9525,14 +9567,14 @@
             uc_info.type = usecase_type;
             if (dir) {
                 memset(&in, 0, sizeof(in));
-                in.device = audio_device;
+                update_device_list(&in.device_list, audio_device, "", true);
                 in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
                 uc_info.stream.in = &in;
             }
             memset(&out, 0, sizeof(out));
-            out.devices = audio_device; /* only field needed in select_devices */
+            update_device_list(&out.device_list, audio_device, "", true);
             uc_info.stream.out = &out;
-            uc_info.devices = audio_device;
+            update_device_list(&uc_info.device_list, audio_device, "", true);
             uc_info.in_snd_device = SND_DEVICE_NONE;
             uc_info.out_snd_device = SND_DEVICE_NONE;
             list_add_tail(&adev->usecase_list, &uc_info.list);
@@ -9624,6 +9666,7 @@
     audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
     struct audio_stream_info *s_info = NULL;
     struct audio_stream *stream = NULL;
+    struct listnode devices;
     audio_devices_t device_type = AUDIO_DEVICE_NONE;
     bool new_patch = false;
     char addr[AUDIO_DEVICE_MAX_ADDRESS_LEN];
@@ -9652,17 +9695,19 @@
 
     ALOGV("%s: source role %d, source type %d", __func__,
            sources[0].type, sources[0].role);
+    list_init(&devices);
 
     // Populate source/sink information and fetch stream info
     switch (sources[0].type) {
         case AUDIO_PORT_TYPE_DEVICE: // Patch for audio capture or loopback
             device_type = sources[0].ext.device.type;
             strlcpy(&addr[0], &sources[0].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
+            update_device_list(&devices, device_type, &addr[0], true);
             if (sinks[0].type == AUDIO_PORT_TYPE_MIX) {
                 patch_type = PATCH_CAPTURE;
                 io_handle = sinks[0].ext.mix.handle;
                 input_source = sinks[0].ext.mix.usecase.source;
-                ALOGV("%s: Capture patch from device %x to mix %d",
+                ALOGD("%s: Capture patch from device %x to mix %d",
                        __func__, device_type, io_handle);
             } else {
                 // Device to device patch is not implemented.
@@ -9674,17 +9719,13 @@
         case AUDIO_PORT_TYPE_MIX: // Patch for audio playback
             io_handle = sources[0].ext.mix.handle;
             for (int i = 0; i < num_sinks; i++) {
-                if (sinks[i].type == AUDIO_PORT_TYPE_MIX) {
-                    ALOGE("%s: mix to mix patches are not supported", __func__);
-                    ret = -EINVAL;
-                    goto done;
-                }
-                device_type |= sinks[i].ext.device.type;
+                device_type = sinks[i].ext.device.type;
                 strlcpy(&addr[0], &sinks[i].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
+                update_device_list(&devices, device_type, &addr[0], true);
             }
             patch_type = PATCH_PLAYBACK;
-            ALOGV("%s: Playback patch from mix handle %d to device %x",
-                   __func__, io_handle, device_type);
+            ALOGD("%s: Playback patch from mix handle %d to device %x",
+                   __func__, io_handle, get_device_types(&devices));
             break;
         case AUDIO_PORT_TYPE_SESSION:
         case AUDIO_PORT_TYPE_NONE:
@@ -9747,10 +9788,9 @@
     // Update routing for stream
     if (stream != NULL) {
         if (p_info->patch_type == PATCH_PLAYBACK)
-            ret = route_output_stream((struct stream_out *) stream, device_type, &addr[0]);
+            ret = route_output_stream((struct stream_out *) stream, &devices);
         else if (p_info->patch_type == PATCH_CAPTURE)
-            ret = route_input_stream((struct stream_in *) stream,
-                                     device_type, &addr[0], input_source);
+            ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
     }
 
     if (ret < 0) {
@@ -9792,7 +9832,6 @@
 {
     struct audio_device *adev = (struct audio_device *) dev;
     int ret = 0;
-    char *addr = "";
     audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
 
     if (handle == AUDIO_PATCH_HANDLE_NONE) {
@@ -9845,11 +9884,12 @@
 
     pthread_mutex_lock(&p_info->lock);
     if (stream != NULL) {
+        struct listnode devices;
+        list_init(&devices);
         if (p_info->patch_type == PATCH_PLAYBACK)
-            ret = route_output_stream((struct stream_out *)stream, AUDIO_DEVICE_NONE, addr);
+            ret = route_output_stream((struct stream_out *) stream, &devices);
         else if (p_info->patch_type == PATCH_CAPTURE)
-            ret = route_input_stream((struct stream_in *)stream,
-                                      AUDIO_DEVICE_NONE, addr, input_source);
+            ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
     }
 
     if (ret < 0)
@@ -10011,7 +10051,7 @@
     struct audio_usecase *uc_info;
     float left_p;
     float right_p;
-    audio_devices_t devices;
+    struct listnode devices;
 
     uc_info = get_usecase_from_list(adev, out->usecase);
     if (uc_info == NULL) {
@@ -10025,7 +10065,7 @@
 
     if (restore) {
         // restore A2DP device for active usecases and unmute if required
-        if (out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
+        if (is_a2dp_out_device_type(&out->device_list)) {
             ALOGD("%s: restoring A2dp and unmuting stream", __func__);
             if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
                 select_devices(adev, uc_info->id);
@@ -10043,8 +10083,8 @@
             pthread_mutex_lock(&out->compr_mute_lock);
             if (!out->a2dp_compress_mute && !out->standby) {
                 ALOGD("%s: selecting speaker and muting stream", __func__);
-                devices = out->devices;
-                out->devices = AUDIO_DEVICE_OUT_SPEAKER;
+                assign_devices(&devices, &out->device_list);
+                reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
                 left_p = out->volume_l;
                 right_p = out->volume_r;
                 if (out->offload_state == OFFLOAD_STATE_PLAYING)
@@ -10054,7 +10094,7 @@
                 select_devices(adev, out->usecase);
                 if (out->offload_state == OFFLOAD_STATE_PLAYING)
                     compress_resume(out->compr);
-                out->devices = devices;
+                assign_devices(&out->device_list, &devices);
                 out->volume_l = left_p;
                 out->volume_r = right_p;
             }