From 7a4e1c9a0ea6143553d6f63ad4b2f96f3c7bb9be Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 15:08:09 +0000 Subject: ALSA: handle write()/read() errors properly by unloading the driver module. This should fix problems when removing USB audio device while pulseaudio is running. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1194 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-alsa-source.c | 76 +++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 24 deletions(-) (limited to 'src/modules/module-alsa-source.c') diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index 3952a385..b5cf9c70 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -96,13 +96,50 @@ static void update_usage(struct userdata *u) { (u->source ? pa_idxset_size(u->source->outputs) : 0)); } -static void xrun_recovery(struct userdata *u) { +static void clear_up(struct userdata *u) { assert(u); + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } + + if (u->pcm_fdl) + pa_alsa_fdlist_free(u->pcm_fdl); + if (u->mixer_fdl) + pa_alsa_fdlist_free(u->mixer_fdl); - pa_log(__FILE__": *** ALSA-XRUN (capture) ***"); + u->pcm_fdl = u->mixer_fdl = NULL; + + if (u->mixer_handle) { + snd_mixer_close(u->mixer_handle); + u->mixer_handle = NULL; + } - if (snd_pcm_prepare(u->pcm_handle) < 0) - pa_log(__FILE__": snd_pcm_prepare() failed"); + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + u->pcm_handle = NULL; + } +} + +static int xrun_recovery(struct userdata *u) { + int ret; + assert(u); + + pa_log_info(__FILE__": *** ALSA-XRUN (capture) ***"); + + if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) { + pa_log(__FILE__": snd_pcm_prepare() failed: %s", snd_strerror(-ret)); + + clear_up(u); + pa_module_unload_request(u->module); + + return -1; + } + + return 0; } static void do_read(struct userdata *u) { @@ -131,11 +168,16 @@ static void do_read(struct userdata *u) { return; if (frames == -EPIPE) { - xrun_recovery(u); + if (xrun_recovery(u) < 0) + return; + continue; } - pa_log(__FILE__": snd_pcm_readi() failed: %s", pa_cstrerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s", snd_strerror(-frames)); + + clear_up(u); + pa_module_unload_request(u->module); return; } @@ -164,7 +206,8 @@ static void fdl_callback(void *userdata) { assert(u); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) - xrun_recovery(u); + if (xrun_recovery(u) < 0) + return; do_read(u); } @@ -182,6 +225,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { u->source->get_hw_volume(u->source); if (u->source->get_hw_mute) u->source->get_hw_mute(u->source); + pa_subscription_post(u->source->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, u->source->index); @@ -468,24 +512,8 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - if (u->pcm_fdl) - pa_alsa_fdlist_free(u->pcm_fdl); - if (u->mixer_fdl) - pa_alsa_fdlist_free(u->mixer_fdl); - if (u->mixer_handle) - snd_mixer_close(u->mixer_handle); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } + clear_up(u); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); -- cgit