Merge "audio: close dlopen'ed library on error" into oc-mr1-dev
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 36a8ba5..c7d6768 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -82,6 +82,7 @@
#define audio_extn_usb_get_max_channels(dir) (0)
#define audio_extn_usb_get_max_bit_width(dir) (0)
#define audio_extn_usb_sup_sample_rates(t, s, l) (0)
+#define audio_extn_usb_alive(adev) (false)
#else
void audio_extn_usb_init(void *adev);
void audio_extn_usb_deinit();
@@ -98,6 +99,7 @@
int audio_extn_usb_get_max_channels(bool is_playback);
int audio_extn_usb_get_max_bit_width(bool is_playback);
int audio_extn_usb_sup_sample_rates(bool is_playback, uint32_t *sr, uint32_t l);
+bool audio_extn_usb_alive(int card);
#endif
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index b29ab0c..dc1afa1 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -306,6 +306,7 @@
goto done;
}
+ // TODO: figure up if this wait is needed any more
while (tries--) {
if (access(path, F_OK) < 0) {
ALOGW("stream %s doesn't exist retrying\n", path);
@@ -1102,6 +1103,13 @@
return;
}
+bool audio_extn_usb_alive(int card) {
+ char path[PATH_MAX] = {0};
+ // snprintf should never fail
+ (void) snprintf(path, sizeof(path), "/proc/asound/card%u/stream0", card);
+ return access(path, F_OK) == 0;
+}
+
void audio_extn_usb_init(void *adev)
{
if (usbmod == NULL) {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index bdc90bf..ad5d1f1 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1793,6 +1793,15 @@
/* Must be called after removing the usecase from list */
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
+ else if (out->devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ struct listnode *node;
+ struct audio_usecase *usecase;
+ list_for_each(node, &adev->usecase_list) {
+ usecase = node_to_item(node, struct audio_usecase, list);
+ if (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER)
+ select_devices(adev, usecase->id);
+ }
+ }
ALOGV("%s: exit: status(%d)", __func__, ret);
return ret;
@@ -2050,16 +2059,13 @@
return -ENOSYS;
}
-static int out_standby(struct audio_stream *stream)
+/* must be called with out->lock locked */
+static int out_standby_l(struct audio_stream *stream)
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
bool do_stop = true;
- ALOGV("%s: enter: usecase(%d: %s)", __func__,
- out->usecase, use_case_table[out->usecase]);
-
- lock_output_stream(out);
if (!out->standby) {
if (adev->adm_deregister_stream)
adev->adm_deregister_stream(adev->adm_data, out->handle);
@@ -2088,6 +2094,18 @@
}
pthread_mutex_unlock(&adev->lock);
}
+ return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+
+ ALOGV("%s: enter: usecase(%d: %s)", __func__,
+ out->usecase, use_case_table[out->usecase]);
+
+ lock_output_stream(out);
+ out_standby_l(stream);
pthread_mutex_unlock(&out->lock);
ALOGV("%s: exit", __func__);
return 0;
@@ -2174,6 +2192,15 @@
return out == adev->primary_output || out == adev->voice_tx_output;
}
+static int get_alive_usb_card(struct str_parms* parms) {
+ int card;
+ if ((str_parms_get_int(parms, "card", &card) >= 0) &&
+ !audio_extn_usb_alive(card)) {
+ return card;
+ }
+ return -ENODEV;
+}
+
static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
struct stream_out *out = (struct stream_out *)stream;
@@ -2192,7 +2219,19 @@
ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
if (ret >= 0) {
val = atoi(value);
+
lock_output_stream(out);
+
+ // The usb driver needs to be closed after usb device disconnection
+ // otherwise audio is no longer played on the new usb devices.
+ // By forcing the stream in standby, the usb stack refcount drops to 0
+ // and the driver is closed.
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD && val == AUDIO_DEVICE_NONE &&
+ audio_is_usb_out_device(out->devices)) {
+ ALOGD("%s() putting the usb device in standby after disconnection", __func__);
+ out_standby_l(&out->stream.common);
+ }
+
pthread_mutex_lock(&adev->lock);
/*
@@ -2207,6 +2246,21 @@
val = AUDIO_DEVICE_OUT_SPEAKER;
}
+ audio_devices_t new_dev = val;
+
+ // 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_dev) &&
+ (card = get_alive_usb_card(parms)) >= 0) {
+
+ ALOGW("out_set_parameters() ignoring rerouting to non existing USB card %d", card);
+ pthread_mutex_unlock(&adev->lock);
+ pthread_mutex_unlock(&out->lock);
+ status = -ENOSYS;
+ goto routing_fail;
+ }
+
/*
* select_devices() call below switches all the usecases on the same
* backend to the new device. Refer to check_and_route_playback_usecases() in
@@ -2225,7 +2279,6 @@
* Because select_devices() must be called to switch back the music
* playback to headset.
*/
- audio_devices_t new_dev = val;
if (new_dev != AUDIO_DEVICE_NONE) {
bool same_dev = out->devices == new_dev;
out->devices = new_dev;
@@ -2269,6 +2322,7 @@
/*handles device and call state changes*/
audio_extn_extspk_update(adev->extspk);
}
+ routing_fail:
if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
parse_compress_metadata(out, parms);
@@ -3124,16 +3178,28 @@
if (ret >= 0) {
val = atoi(value);
if (((int)in->device != val) && (val != 0) && audio_is_input_device(val) ) {
- in->device = val;
- /* If recording is in progress, change the tx device to new device */
- if (!in->standby) {
- ALOGV("update input routing change");
- // inform adm before actual routing to prevent glitches.
- if (adev->adm_on_routing_change) {
- adev->adm_on_routing_change(adev->adm_data,
- in->capture_handle);
+
+ // 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_in_device(val) &&
+ (card = get_alive_usb_card(parms)) >= 0) {
+
+ ALOGW("in_set_parameters() ignoring rerouting to non existing USB card %d", card);
+ status = -ENOSYS;
+ } else {
+
+ in->device = val;
+ /* If recording is in progress, change the tx device to new device */
+ if (!in->standby) {
+ ALOGV("update input routing change");
+ // inform adm before actual routing to prevent glitches.
+ if (adev->adm_on_routing_change) {
+ adev->adm_on_routing_change(adev->adm_data,
+ in->capture_handle);
+ }
+ select_devices(adev, in->usecase);
}
- select_devices(adev, in->usecase);
}
}
}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index d6b393f..b324b66 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2548,9 +2548,15 @@
} else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX) {
snd_device = SND_DEVICE_IN_VOICE_RX;
} else if (out_device & (AUDIO_DEVICE_OUT_USB_DEVICE|AUDIO_DEVICE_OUT_USB_HEADSET)) {
- if (audio_extn_usb_is_capture_supported()) {
- snd_device = SND_DEVICE_IN_VOICE_USB_HEADSET_MIC;
- }
+ if (audio_extn_usb_is_capture_supported()) {
+ snd_device = SND_DEVICE_IN_VOICE_USB_HEADSET_MIC;
+ } else if (my_data->fluence_in_voice_call && my_data->fluence_in_spkr_mode) {
+ if (my_data->source_mic_type & SOURCE_DUAL_MIC) {
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
+ } else {
+ snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
+ }
+ }
}
} else if (source == AUDIO_SOURCE_CAMCORDER) {
if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
@@ -2632,8 +2638,12 @@
}
} else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
mode == AUDIO_MODE_IN_COMMUNICATION) {
- if (out_device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE))
+ if (out_device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE) ||
+ out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+ (out_device & (AUDIO_DEVICE_OUT_USB_DEVICE | AUDIO_DEVICE_OUT_USB_HEADSET) &&
+ !audio_extn_usb_is_capture_supported())) {
in_device = AUDIO_DEVICE_IN_BACK_MIC;
+ }
if (adev->active_input) {
if (adev->active_input->enable_aec &&
adev->active_input->enable_ns) {