audio: ucm: Route voice call only after enabling device

- Voice call is sometimes enabled without enabling both Rx and
Tx device. This is resulting in improper configuration of
voice call
- Fix this problem by checking if both Rx and Tx devices are
enabled before routing voice call

Change-Id: Ie0850eb7d0beafe7db150138b3aff1b2696db591
diff --git a/libalsa-intf/alsa_ucm.c b/libalsa-intf/alsa_ucm.c
index 0c29c94..3548f67 100644
--- a/libalsa-intf/alsa_ucm.c
+++ b/libalsa-intf/alsa_ucm.c
@@ -535,6 +535,46 @@
     return ret;
 }
 
+static int check_devices_for_voice_call(snd_use_case_mgr_t *uc_mgr,
+const char *use_case)
+{
+    struct snd_ucm_ident_node *dev_node = NULL;
+    int index = 0, list_size = 0, rx_dev_status = 0, tx_dev_status = 0;
+
+    if ((!strncmp(use_case, SND_USE_CASE_VERB_VOICECALL,
+        strlen(SND_USE_CASE_VERB_VOICECALL))) ||
+        (!strncmp(use_case, SND_USE_CASE_VERB_IP_VOICECALL,
+        strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
+        (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE,
+        strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
+        (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOIP,
+        strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
+        ALOGV("check_devices_for_voice_call(): voice cap detected\n");
+        list_size =
+        snd_ucm_get_size_of_list(uc_mgr->card_ctxt_ptr->dev_list_head);
+        for (index = 0; index < list_size; index++) {
+            if ((dev_node =
+                snd_ucm_get_device_node(uc_mgr->card_ctxt_ptr->dev_list_head,
+                index))) {
+                if (dev_node->capability == CAP_RX && dev_node->active == 1) {
+                    rx_dev_status = 1;
+                } else if (dev_node->capability == CAP_TX && dev_node->active == 1) {
+                    tx_dev_status = 1;
+                }
+            }
+        }
+        if (rx_dev_status == 1 && tx_dev_status == 1) {
+            ALOGV("check_devices_for_voice_call(): Rx and Tx devices enabled\n");
+            return 0;
+        } else {
+            ALOGV("check_devices_for_voice_call(): Rx/Tx dev not enabled: \
+                  %d,%d\n", rx_dev_status, tx_dev_status);
+            return 1;
+        }
+    }
+    return 0;
+}
+
 static int snd_use_case_apply_voice_acdb(snd_use_case_mgr_t *uc_mgr,
 int use_case_index)
 {
@@ -748,6 +788,9 @@
             ALOGE("Control device not initialized");
             ret = -ENODEV;
         } else {
+            if (enable &&
+                (check_devices_for_voice_call(uc_mgr, use_case) != NULL))
+                return ret;
             ALOGD("Set mixer controls for %s enable %d", use_case, enable);
             if (ctrl_list[uc_index].acdb_id && ctrl_list[uc_index].capability) {
                 if (enable) {
@@ -917,7 +960,7 @@
     card_mctrl_t *dev_list, *uc_list;
     char *current_device, use_case[MAX_UC_LEN];
     int list_size, index, uc_index, ret = 0, intdev_flag = 0;
-    int verb_index, capability = 0, ident_cap = 0;
+    int verb_index, capability = 0, ident_cap = 0, dev_cap =0;
 
     ALOGV("set_use_case_ident_for_all_devices(): %s", ident);
     if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
@@ -941,44 +984,47 @@
         if (current_device != NULL) {
             uc_index = get_use_case_index(uc_mgr, current_device,
                        CTRL_LIST_DEVICE);
+            dev_cap = dev_list[uc_index].capability;
             if (!capability) {
                 capability = dev_list[uc_index].capability;
             } else if (capability != dev_list[uc_index].capability) {
                 capability = CAP_VOICE;
             }
-            if (enable) {
-                if (!snd_ucm_get_status_at_index(
+            if (ident_cap == CAP_VOICE  || ident_cap == dev_cap) {
+                if (enable) {
+                    if (!snd_ucm_get_status_at_index(
                         uc_mgr->card_ctxt_ptr->dev_list_head, current_device)) {
-                    if (uc_index >= 0) {
-                        ALOGV("Applying mixer controls for device: %s",
-                            current_device);
-                        ret = snd_use_case_apply_mixer_controls(uc_mgr,
-                            current_device, enable, CTRL_LIST_DEVICE, uc_index);
-                        if (!ret)
-                           snd_ucm_set_status_at_index(
-                              uc_mgr->card_ctxt_ptr->dev_list_head,
-                              current_device, enable);
-                    }
-                } else if (ident_cap == CAP_VOICE) {
-                    snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
-                }
-            }
-            strlcpy(use_case, ident, sizeof(use_case));
-            strlcat(use_case, current_device, sizeof(use_case));
-            ALOGV("Applying mixer controls for use case: %s", use_case);
-            if ((uc_index =
-                get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
-                ALOGV("No valid use case found: %s", use_case);
-                intdev_flag++;
-            } else {
-                if (capability == CAP_VOICE || ident_cap == CAP_VOICE ||
-                    capability == ident_cap) {
-                    ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
-                          enable, ctrl_list_type, uc_index);
-                }
-            }
-            use_case[0] = 0;
-            free(current_device);
+                        if (uc_index >= 0) {
+                            ALOGV("Applying mixer controls for device: %s",
+                                  current_device);
+                            ret = snd_use_case_apply_mixer_controls(uc_mgr,
+                                  current_device, enable, CTRL_LIST_DEVICE, uc_index);
+                            if (!ret)
+                                snd_ucm_set_status_at_index(
+                                  uc_mgr->card_ctxt_ptr->dev_list_head,
+                                  current_device, enable, dev_cap);
+                        }
+                     } else if (ident_cap == CAP_VOICE) {
+                        snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
+                     }
+                 }
+                 strlcpy(use_case, ident, sizeof(use_case));
+                 strlcat(use_case, current_device, sizeof(use_case));
+                 ALOGV("Applying mixer controls for use case: %s", use_case);
+                 if ((uc_index =
+                      get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
+                      ALOGV("No valid use case found: %s", use_case);
+                      intdev_flag++;
+                 } else {
+                      if (capability == CAP_VOICE || ident_cap == CAP_VOICE ||
+                          capability == ident_cap) {
+                          ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
+                                enable, ctrl_list_type, uc_index);
+                      }
+                 }
+                 use_case[0] = 0;
+                 free(current_device);
+             }
         }
     }
     if (intdev_flag) {
@@ -1005,21 +1051,29 @@
 static int set_controls_of_usecase_for_device(snd_use_case_mgr_t *uc_mgr,
 const char *ident, const char *device, int enable, int ctrl_list_type)
 {
+    card_mctrl_t *dev_list;
     char use_case[MAX_UC_LEN];
     int list_size, index, dev_index, uc_index, ret = 0;
+    int verb_index, capability = 0;
 
     ALOGV("set_use_case_ident_for_device(): use case %s device %s", ident,
         device);
+    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
+        verb_index = 0;
+    dev_list =
+        uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
     if (device != NULL) {
         if (enable) {
             dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
+            capability = dev_list[dev_index].capability;
             if (!snd_ucm_get_status_at_index(
                 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
                 ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
                          enable, CTRL_LIST_DEVICE, dev_index);
                 if (!ret)
                     snd_ucm_set_status_at_index(
-                    uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
+                    uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
+                    capability);
             }
         }
         strlcpy(use_case, ident, sizeof(use_case));
@@ -1074,30 +1128,29 @@
         strlen(SND_USE_CASE_VERB_INACTIVE))) {
         uc_list =
             uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].verb_ctrls;
-        strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
-            sizeof(use_case));
-        strlcat(use_case, device, sizeof(use_case));
-        if ((uc_index =
-            get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
-            ALOGV("No valid use case found: %s", use_case);
-            intdev_flag = 1;
-        } else {
-            if (enable) {
-                if (!snd_ucm_get_status_at_index(
-                    uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
-                    ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
-                              enable, CTRL_LIST_DEVICE, dev_index);
-                    if (!ret)
-                        snd_ucm_set_status_at_index(
-                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
-                    flag = 1;
+        if (capability == CAP_VOICE ||
+            capability == getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
+            getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) == CAP_VOICE) {
+            strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
+                sizeof(use_case));
+            strlcat(use_case, device, sizeof(use_case));
+            if ((uc_index =
+                get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
+                ALOGV("No valid use case found: %s", use_case);
+                intdev_flag = 1;
+            } else {
+                if (enable) {
+                    if (!snd_ucm_get_status_at_index(
+                        uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
+                        ret = snd_use_case_apply_mixer_controls(uc_mgr, device,
+                                  enable, CTRL_LIST_DEVICE, dev_index);
+                        if (!ret)
+                            snd_ucm_set_status_at_index(
+                            uc_mgr->card_ctxt_ptr->dev_list_head, device,
+                            enable, capability);
+                            flag = 1;
+                    }
                 }
-            }
-            if (capability == CAP_VOICE ||
-                capability ==
-                getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
-                getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ==
-                CAP_VOICE) {
                 ALOGV("set %d for use case value: %s", enable, use_case);
                 ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
                           enable, CTRL_LIST_VERB, uc_index);
@@ -1114,7 +1167,8 @@
                               device, enable, CTRL_LIST_DEVICE, dev_index);
                     if (!ret)
                         snd_ucm_set_status_at_index(
-                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
+                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
+                        capability);
                     flag = 1;
                 }
             }
@@ -1146,34 +1200,35 @@
         if ((ident_value =
             snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
             index))) {
-            strlcpy(use_case, ident_value, sizeof(use_case));
-            strlcat(use_case, device, sizeof(use_case));
-            if ((uc_index = get_use_case_index(uc_mgr, use_case,
-                CTRL_LIST_MODIFIER)) < 0) {
-                ALOGV("No valid use case found: %s", use_case);
-                intdev_flag = 1;
-            } else {
-                if (enable && !flag) {
-                    if (!snd_ucm_get_status_at_index(
-                        uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
-                        ret = snd_use_case_apply_mixer_controls(uc_mgr,
-                                  device, enable, CTRL_LIST_DEVICE, dev_index);
-                        if (!ret)
-                            snd_ucm_set_status_at_index(
-                                uc_mgr->card_ctxt_ptr->dev_list_head,
-                                device, enable);
-                        flag = 1;
+            if (capability == CAP_VOICE ||
+                getUseCaseType(ident_value) == CAP_VOICE ||
+                capability == getUseCaseType(ident_value)) {
+                strlcpy(use_case, ident_value, sizeof(use_case));
+                strlcat(use_case, device, sizeof(use_case));
+                if ((uc_index = get_use_case_index(uc_mgr, use_case,
+                    CTRL_LIST_MODIFIER)) < 0) {
+                    ALOGV("No valid use case found: %s", use_case);
+                    intdev_flag = 1;
+                } else {
+                    if (enable && !flag) {
+                        if (!snd_ucm_get_status_at_index(
+                            uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
+                            ret = snd_use_case_apply_mixer_controls(uc_mgr,
+                                      device, enable, CTRL_LIST_DEVICE,
+                                      dev_index);
+                            if (!ret)
+                                snd_ucm_set_status_at_index(
+                                    uc_mgr->card_ctxt_ptr->dev_list_head,
+                                    device, enable, capability);
+                            flag = 1;
+                        }
                     }
-                }
-                if (capability == CAP_VOICE ||
-                    getUseCaseType(ident_value) == CAP_VOICE ||
-                    capability == getUseCaseType(ident_value)) {
                     ALOGV("set %d for use case value: %s", enable, use_case);
-                     ret = snd_use_case_apply_mixer_controls(uc_mgr,
-                           use_case, enable, CTRL_LIST_MODIFIER, uc_index);
-                     if (ret != 0)
-                         ALOGE("No valid controls exists for usecase %s and \
-                              device %s, enable: %d", use_case, device, enable);
+                    ret = snd_use_case_apply_mixer_controls(uc_mgr,
+                          use_case, enable, CTRL_LIST_MODIFIER, uc_index);
+                    if (ret != 0)
+                        ALOGE("No valid controls exists for usecase %s and \
+                            device %s, enable: %d", use_case, device, enable);
                 }
             }
             if (intdev_flag) {
@@ -1185,7 +1240,7 @@
                         if (!ret)
                             snd_ucm_set_status_at_index(
                             uc_mgr->card_ctxt_ptr->dev_list_head, device,
-                            enable);
+                            enable, capability);
                         flag = 1;
                     }
                 }
@@ -1214,7 +1269,7 @@
                   CTRL_LIST_DEVICE, dev_index);
         if (!ret)
             snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
-                device, enable);
+                device, enable, capability);
     }
     return ret;
 }
@@ -1253,11 +1308,18 @@
 static int set_controls_of_device_for_usecase(snd_use_case_mgr_t *uc_mgr,
     const char *device, const char *usecase, int enable)
 {
+    card_mctrl_t *dev_list;
     char use_case[MAX_UC_LEN];
     int ret = -ENODEV, uc_index, dev_index;
+    int verb_index, capability = 0;
 
     ALOGV("set_device_for_ident(): %s %s", device, usecase);
+    if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
+        verb_index = 0;
+    dev_list =
+         uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
     dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
+    capability = dev_list[dev_index].capability;
     if (usecase != NULL) {
         strlcpy(use_case, usecase, sizeof(use_case));
         strlcat(use_case, device, sizeof(use_case));
@@ -1272,7 +1334,8 @@
                           enable, CTRL_LIST_DEVICE, dev_index);
                     if (!ret)
                         snd_ucm_set_status_at_index
-                        (uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
+                        (uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
+                        capability);
                 }
             }
             ALOGV("set %d for use case value: %s", enable, use_case);
@@ -1291,7 +1354,8 @@
                           CTRL_LIST_DEVICE, dev_index);
                 if (!ret)
                     snd_ucm_set_status_at_index(
-                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable);
+                        uc_mgr->card_ctxt_ptr->dev_list_head, device, enable,
+                        capability);
             }
         }
     }
@@ -1300,7 +1364,7 @@
                   CTRL_LIST_DEVICE, dev_index);
         if (!ret)
             snd_ucm_set_status_at_index(uc_mgr->card_ctxt_ptr->dev_list_head,
-                device, enable);
+                device, enable, capability);
     }
     return ret;
 }
@@ -3658,6 +3722,7 @@
         node->next = NULL;
         strlcpy(node->ident, value, MAX_STR_LEN);
         node->active = 0;
+        node->capability = 0;
     }
     if (*head == NULL) {
         *head = node;
@@ -3694,13 +3759,38 @@
     return -EINVAL;
 }
 
+/* Get the node at particular index
+ * head - list head
+ * index - index value
+ */
+struct snd_ucm_ident_node *snd_ucm_get_device_node(struct snd_ucm_ident_node *head,
+int index)
+{
+    if (head == NULL) {
+        ALOGV("Empty list");
+        return NULL;
+    }
+
+    if ((index < 0) || (index >= (snd_ucm_get_size_of_list(head)))) {
+        ALOGE("Element with given index %d doesn't exist in the list", index);
+        return NULL;
+    }
+
+    while (index) {
+        head = head->next;
+        index--;
+    }
+
+    return head;
+}
+
 /* Set the status of identifier at particulare index of the list
  * head - list head
  * ident - identifier value for which status needs to be set
  * status - status to be set (1 - active, 0 - inactive)
  */
 static void snd_ucm_set_status_at_index(struct snd_ucm_ident_node *head,
-const char *ident, int status)
+const char *ident, int status, int capability)
 {
     while (head != NULL) {
         if(!strncmp(ident, head->ident, (strlen(head->ident)+1))) {
@@ -3712,6 +3802,7 @@
         ALOGE("Element not found to set the status");
     } else {
         head->active = status;
+        head->capability = capability;
     }
 }
 
@@ -3818,6 +3909,7 @@
         temp2->next = NULL;
         temp2->ident[0] = 0;
         temp2->active = 0;
+        temp2->capability = 0;
         free(temp2);
         temp2 = NULL;
     }