Skip to content

Commit

Permalink
audio: derive sound device for concurrent playback usecases
Browse files Browse the repository at this point in the history
When a new playback usecase has to be started, existing playback
usecases might have to be re-routed (or not) to the new device
based on usecase requirements or h/w limitations
(e.g headphones and speaker sharing the same backend).

This change addresses this requirement by deriving the
new device based on pre-defined cases.

Bug: 31671778
Change-Id: Ic0fd4e8d2c1119e7198dc5bb5e5a51817f0110c1
  • Loading branch information
Haynes Mathew George authored and Eric Laurent committed Oct 5, 2016
1 parent 7401c7c commit 2d809e0
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 29 deletions.
125 changes: 120 additions & 5 deletions hal/audio_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,9 @@ int enable_snd_device(struct audio_device *adev,
ALOGE("%s: spkr_start_processing failed", __func__);
goto on_error;
}
} else if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices)) {
} else if (platform_can_split_snd_device(snd_device,
&num_devices,
new_snd_devices) == 0) {
for (i = 0; i < num_devices; i++) {
enable_snd_device(adev, new_snd_devices[i]);
}
Expand Down Expand Up @@ -663,7 +665,9 @@ int disable_snd_device(struct audio_device *adev,
snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
audio_extn_spkr_prot_is_enabled()) {
audio_extn_spkr_prot_stop_processing(snd_device);
} else if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices)) {
} else if (platform_can_split_snd_device(snd_device,
&num_devices,
new_snd_devices) == 0) {
for (i = 0; i < num_devices; i++) {
disable_snd_device(adev, new_snd_devices[i]);
}
Expand All @@ -685,6 +689,114 @@ int disable_snd_device(struct audio_device *adev,
return 0;
}

/*
legend:
uc - existing usecase
new_uc - new usecase
d1, d11, d2 - SND_DEVICE enums
a1, a2 - corresponding ANDROID device enums
B, B1, B2 - backend strings
case 1
uc->dev d1 (a1) B1
new_uc->dev d1 (a1), d2 (a2) B1, B2
resolution: disable and enable uc->dev on d1
case 2
uc->dev d1 (a1) B1
new_uc->dev d11 (a1) B1
resolution: need to switch uc since d1 and d11 are related
(e.g. speaker and voice-speaker)
use ANDROID_DEVICE_OUT enums to match devices since SND_DEVICE enums may vary
case 3
uc->dev d1 (a1) B1
new_uc->dev d2 (a2) B2
resolution: no need to switch uc
case 4
uc->dev d1 (a1) B
new_uc->dev d2 (a2) B
resolution: disable enable uc-dev on d2 since backends match
we cannot enable two streams on two different devices if they
share the same backend. e.g. if offload is on speaker device using
QUAD_MI2S backend and a low-latency stream is started on voice-handset
using the same backend, offload must also be switched to voice-handset.
case 5
uc->dev d1 (a1) B
new_uc->dev d1 (a1), d2 (a2) B
resolution: disable enable uc-dev on d2 since backends match
we cannot enable two streams on two different devices if they
share the same backend.
case 6
uc->dev d1 a1 B1
new_uc->dev d2 a1 B2
resolution: no need to switch
case 7
uc->dev d1 (a1), d2 (a2) B1, B2
new_uc->dev d1 B1
resolution: no need to switch
*/
static snd_device_t derive_playback_snd_device(struct audio_usecase *uc,
struct audio_usecase *new_uc,
snd_device_t new_snd_device)
{
audio_devices_t a1 = uc->stream.out->devices;
audio_devices_t a2 = new_uc->stream.out->devices;

snd_device_t d1 = uc->out_snd_device;
snd_device_t d2 = new_snd_device;

// Treat as a special case when a1 and a2 are not disjoint
if ((a1 != a2) && (a1 & a2)) {
snd_device_t d3[2];
int num_devices = 0;
int ret = platform_can_split_snd_device(popcount(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);
}
goto end;
}

// NB: case 7 is hypothetical and isn't a practical usecase yet.
// But if it does happen, we need to give priority to d2 if
// the combo devices active on the existing usecase share a backend.
// This is because we cannot have a usecase active on a combo device
// and a new usecase requests one device in this combo pair.
if (platform_check_backends_match(d3[0], d3[1])) {
return d2; // case 5
} else {
return d1; // case 1
}
} else {
if (platform_check_backends_match(d1, d2)) {
return d2; // case 2, 4
} else {
return d1; // case 6, 3
}
}

end:
return d2; // return whatever was calculated before.
}

static void check_and_route_playback_usecases(struct audio_device *adev,
struct audio_usecase *uc_info,
snd_device_t snd_device)
Expand Down Expand Up @@ -733,20 +845,23 @@ static void check_and_route_playback_usecases(struct audio_device *adev,
}
}

snd_device_t d_device;
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
if (switch_device[usecase->id]) {
enable_snd_device(adev, snd_device);
d_device = derive_playback_snd_device(usecase, uc_info,
snd_device);
enable_snd_device(adev, d_device);
/* Update the out_snd_device before enabling the audio route */
usecase->out_snd_device = d_device;
}
}

/* Re-route all the usecases on the shared backend other than the
specified usecase to new snd devices */
list_for_each(node, &adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
/* Update the out_snd_device only before enabling the audio route */
if (switch_device[usecase->id] ) {
usecase->out_snd_device = snd_device;
enable_audio_route(adev, usecase);
}
}
Expand Down
14 changes: 7 additions & 7 deletions hal/msm8916/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -1424,35 +1424,35 @@ int platform_set_device_mute(void *platform, bool state, char *dir)
return ret;
}

bool platform_can_split_snd_device(snd_device_t snd_device,
int platform_can_split_snd_device(snd_device_t snd_device,
int *num_devices,
snd_device_t *new_snd_devices)
{
bool status = false;
int ret = -EINVAL;

if (NULL == num_devices || NULL == new_snd_devices) {
ALOGE("%s: NULL pointer ..", __func__);
return false;
return -EINVAL;
}

/*
* If wired headset/headphones/line devices share the same backend
* with speaker/earpiece this routine returns false.
* with speaker/earpiece this routine -EINVAL.
*/
if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES &&
!platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_HEADPHONES)) {
*num_devices = 2;
new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
new_snd_devices[1] = SND_DEVICE_OUT_HEADPHONES;
status = true;
ret = 0;
} else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_LINE &&
!platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_LINE)) {
*num_devices = 2;
new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
new_snd_devices[1] = SND_DEVICE_OUT_LINE;
status = true;
ret = 0;
}
return status;
return ret;
}

snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
Expand Down
4 changes: 2 additions & 2 deletions hal/msm8960/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -1075,11 +1075,11 @@ bool platform_send_gain_dep_cal(void *platform __unused,
return true;
}

bool platform_can_split_snd_device(snd_device_t in_snd_device __unused,
int platform_can_split_snd_device(snd_device_t in_snd_device __unused,
int *num_devices __unused,
snd_device_t *out_snd_devices __unused)
{
return false;
return -ENOSYS;
}

bool platform_check_backends_match(snd_device_t snd_device1 __unused,
Expand Down
23 changes: 11 additions & 12 deletions hal/msm8974/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -1863,47 +1863,46 @@ int platform_set_device_mute(void *platform, bool state, char *dir)
return ret;
}

bool platform_can_split_snd_device(snd_device_t snd_device,
int *num_devices,
snd_device_t *new_snd_devices)
int platform_can_split_snd_device(snd_device_t snd_device,
int *num_devices,
snd_device_t *new_snd_devices)
{
bool status = false;

int ret = -EINVAL;
if (NULL == num_devices || NULL == new_snd_devices) {
ALOGE("%s: NULL pointer ..", __func__);
return false;
return -EINVAL;
}

/*
* If wired headset/headphones/line devices share the same backend
* with speaker/earpiece this routine returns false.
* with speaker/earpiece this routine returns -EINVAL.
*/
if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES &&
!platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_HEADPHONES)) {
*num_devices = 2;
new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
new_snd_devices[1] = SND_DEVICE_OUT_HEADPHONES;
status = true;
ret = 0;
} else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_LINE &&
!platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_LINE)) {
*num_devices = 2;
new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
new_snd_devices[1] = SND_DEVICE_OUT_LINE;
status = true;
ret = 0;
} else if (snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_HEADPHONES &&
!platform_check_backends_match(SND_DEVICE_OUT_SPEAKER_SAFE, SND_DEVICE_OUT_HEADPHONES)) {
*num_devices = 2;
new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER_SAFE;
new_snd_devices[1] = SND_DEVICE_OUT_HEADPHONES;
status = true;
ret = 0;
} else if (snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_LINE &&
!platform_check_backends_match(SND_DEVICE_OUT_SPEAKER_SAFE, SND_DEVICE_OUT_LINE)) {
*num_devices = 2;
new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER_SAFE;
new_snd_devices[1] = SND_DEVICE_OUT_LINE;
status = true;
ret = 0;
}
return status;
return ret;
}

snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
Expand Down
6 changes: 3 additions & 3 deletions hal/platform_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t p
void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
int platform_swap_lr_channels(struct audio_device *adev, bool swap_channels);

bool platform_can_split_snd_device(snd_device_t in_snd_device,
int *num_devices,
snd_device_t *out_snd_devices);
int platform_can_split_snd_device(snd_device_t in_snd_device,
int *num_devices,
snd_device_t *out_snd_devices);

bool platform_check_backends_match(snd_device_t snd_device1, snd_device_t snd_device2);

Expand Down

0 comments on commit 2d809e0

Please sign in to comment.