summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/audio_hw.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
index 9be5f33..6843fd2 100644
--- a/audio/audio_hw.c
+++ b/audio/audio_hw.c
@@ -985,6 +985,67 @@ int disable_snd_device(struct audio_device *adev,
return 0;
}
+static void check_and_route_usecases(struct audio_device *adev,
+ struct audio_usecase *uc_info,
+ usecase_type_t type,
+ snd_device_t snd_device)
+{
+ struct listnode *node;
+ struct audio_usecase *usecase;
+ bool switch_device[AUDIO_USECASE_MAX], need_switch = false;
+ snd_device_t usecase_snd_device = SND_DEVICE_NONE;
+ int i;
+
+ /*
+ * This function is to make sure that all the usecases that are active on
+ * the hardware codec backend are always routed to any one device that is
+ * handled by the hardware codec.
+ * For example, if low-latency and deep-buffer usecases are currently active
+ * on speaker and out_set_parameters(headset) is received on low-latency
+ * output, then we have to make sure deep-buffer is also switched to headset or
+ * if audio-record and voice-call usecases are currently
+ * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
+ * is received for voice call then we have to make sure that audio-record
+ * usecase is also switched to earpiece i.e.
+ * because of the limitation that both the devices cannot be enabled
+ * at the same time as they share the same backend.
+ */
+ /* Disable all the usecases on the shared backend other than the
+ specified usecase */
+ for (i = 0; i < AUDIO_USECASE_MAX; i++)
+ switch_device[i] = false;
+
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, adev_list_node);
+ if (usecase->type != type || usecase == uc_info)
+ continue;
+ usecase_snd_device = (type == PCM_PLAYBACK) ? usecase->out_snd_device :
+ usecase->in_snd_device;
+ if (usecase_snd_device != snd_device) {
+ ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
+ __func__, use_case_table[usecase->id],
+ get_snd_device_name(usecase_snd_device));
+ switch_device[usecase->id] = true;
+ need_switch = true;
+ }
+ }
+ if (need_switch) {
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, adev_list_node);
+ usecase_snd_device = (type == PCM_PLAYBACK) ? usecase->out_snd_device :
+ usecase->in_snd_device;
+ if (switch_device[usecase->id]) {
+ disable_snd_device(adev, usecase, usecase_snd_device);
+ enable_snd_device(adev, usecase, snd_device);
+ if (type == PCM_PLAYBACK)
+ usecase->out_snd_device = snd_device;
+ else
+ usecase->in_snd_device = snd_device;
+ }
+ }
+ }
+}
+
static int select_devices(struct audio_device *adev,
audio_usecase_t uc_id)
{
@@ -1084,10 +1145,12 @@ static int select_devices(struct audio_device *adev,
set_voice_session_audio_path(adev->voice.session);
}
+ check_and_route_usecases(adev, usecase, PCM_PLAYBACK, out_snd_device);
enable_snd_device(adev, usecase, out_snd_device);
}
if (in_snd_device != SND_DEVICE_NONE) {
+ check_and_route_usecases(adev, usecase, PCM_CAPTURE, in_snd_device);
enable_snd_device(adev, usecase, in_snd_device);
}