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;
}