]> code.delx.au - pulseaudio/commitdiff
ALSA: handle write()/read() errors properly by unloading the driver module. This...
authorLennart Poettering <lennart@poettering.net>
Fri, 11 Aug 2006 15:08:09 +0000 (15:08 +0000)
committerLennart Poettering <lennart@poettering.net>
Fri, 11 Aug 2006 15:08:09 +0000 (15:08 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1194 fefdeb5f-60dc-0310-8127-8f9354f1896f

src/modules/module-alsa-sink.c
src/modules/module-alsa-source.c

index 0a0717df1e531ab0b08869173888055b89bef596..d47e8c3b608574f8631886eda34db2a3c3a7d115 100644 (file)
@@ -96,13 +96,49 @@ static void update_usage(struct userdata *u) {
                       (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0));
 }
 
-static void xrun_recovery(struct userdata *u) {
+static void clear_up(struct userdata *u) {
     assert(u);
+    
+    if (u->sink) {
+        pa_sink_disconnect(u->sink);
+        pa_sink_unref(u->sink);
+        u->sink = 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 (playback) ***");
+    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 (playback) ***");
+    
+    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 ret;
 }
 
 static void do_write(struct userdata *u) {
@@ -130,11 +166,16 @@ static void do_write(struct userdata *u) {
                 return;
 
             if (frames == -EPIPE) {
-                xrun_recovery(u);
+                if (xrun_recovery(u) < 0)
+                    return;
+                
                 continue;
             }
 
-            pa_log(__FILE__": snd_pcm_writei() failed: %s", snd_strerror(frames));
+            pa_log(__FILE__": snd_pcm_writei() failed: %s", snd_strerror(-frames));
+
+            clear_up(u);
+            pa_module_unload_request(u->module);
             return;
         }
 
@@ -159,7 +200,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_write(u);
 }
@@ -480,25 +522,9 @@ void pa__done(pa_core *c, pa_module*m) {
 
     if (!(u = m->userdata))
         return;
-    
-    if (u->sink) {
-        pa_sink_disconnect(u->sink);
-        pa_sink_unref(u->sink);
-    }
-    
-    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);
     if (u->silence.memblock)
index 3952a38507c43fcc4acf8474d24db69249e6dbe0..b5cf9c7052a58730f7ba6c4de88d341a23ff4c55 100644 (file)
@@ -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);