remove underrun condition in pa_sinks. Instead return silence in pa_sink_render(...
authorLennart Poettering <lennart@poettering.net>
Sat, 23 Jun 2007 20:04:47 +0000 (20:04 +0000)
committerLennart Poettering <lennart@poettering.net>
Sat, 23 Jun 2007 20:04:47 +0000 (20:04 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1490 fefdeb5f-60dc-0310-8127-8f9354f1896f

src/pulsecore/sink.c
src/pulsecore/sink.h

index 7f00904..11effe2 100644 (file)
@@ -116,6 +116,7 @@ pa_sink* pa_sink_new(
     s->userdata = NULL;
 
     s->asyncmsgq = NULL;
+    s->silence = NULL;
 
     r = pa_idxset_put(core->sinks, s, &s->index);
     pa_assert(s->index != PA_IDXSET_INVALID && r >= 0);
@@ -222,6 +223,9 @@ static void sink_free(pa_object *o) {
     
     pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
 
+    if (s->silence)
+        pa_memblock_unref(s->silence);
+    
     pa_xfree(s->name);
     pa_xfree(s->description);
     pa_xfree(s->driver);
@@ -270,53 +274,85 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) {
     pa_sink_assert_ref(s);
     pa_assert(info);
 
-    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
-        /* Increase ref counter, to make sure that this input doesn't
-         * vanish while we still need it */
-        pa_sink_input_ref(i);
+    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
+        pa_sink_input_assert_ref(i);
 
-        if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) {
-            pa_sink_input_unref(i);
+        if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0)
             continue;
-        }
 
-        info->userdata = i;
+        info->userdata = pa_sink_input_ref(i);
 
         pa_assert(info->chunk.memblock);
-        pa_assert(info->chunk.length);
+        pa_assert(info->chunk.length > 0);
 
         info++;
-        maxinfo--;
         n++;
+        maxinfo--;
     }
 
     return n;
 }
 
-static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) {
+static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length) {
+    pa_sink_input *i;
+    void *state = NULL;
+    unsigned p = 0;
+    unsigned n_unreffed = 0;
+
     pa_sink_assert_ref(s);
-    pa_assert(info);
 
-    for (; maxinfo > 0; maxinfo--, info++) {
-        pa_sink_input *i = info->userdata;
+    /* We optimize for the case where the order of the inputs has not changed */
 
-        pa_assert(i);
-        pa_assert(info->chunk.memblock);
+    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
+        unsigned j;
+        pa_mix_info* m;
+
+        pa_sink_input_assert_ref(i);
+
+        m = NULL;
+
+        /* Let's try to find the matching entry info the pa_mix_info array */
+        for (j = 0; j < n; j ++) {
+
+            if (info[p].userdata == i) {
+                m = info + p;
+                break;
+            }
+
+            if (++p > n)
+                p = 0;
+        }
 
         /* Drop read data */
-        pa_sink_input_drop(i, &info->chunk, length);
-        pa_memblock_unref(info->chunk.memblock);
+        pa_sink_input_drop(i, m ? &m->chunk : NULL, length);
 
-        /* Decrease ref counter */
-        pa_sink_input_unref(i);
-        info->userdata = NULL;
+        if (m) {
+            pa_sink_input_unref(m->userdata);
+            m->userdata = NULL;
+            if (m->chunk.memblock)
+                pa_memblock_unref(m->chunk.memblock);
+            pa_memchunk_reset(&m->chunk);
+
+            n_unreffed += 1;
+        }
+    }
+
+    /* Now drop references to entries that are included in the
+     * pa_mix_info array but don't exist anymore */
+
+    if (n_unreffed < n) {
+        for (; n > 0; info++, n--) {
+            if (info->userdata)
+                pa_sink_input_unref(info->userdata);
+            if (info->chunk.memblock)
+                pa_memblock_unref(info->chunk.memblock);
+        }
     }
 }
 
-int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
+void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
     pa_mix_info info[MAX_MIX_CHANNELS];
     unsigned n;
-    int r = -1;
 
     pa_sink_assert_ref(s);
     pa_assert(length);
@@ -326,10 +362,19 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
 
     n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
 
-    if (n <= 0)
-        goto finish;
+    if (n == 0) {
+
+        if (!s->silence || pa_memblock_get_length(s->silence) < length) {
+            if (s->silence)
+                pa_memblock_unref(s->silence);
+            s->silence = pa_silence_memblock_new(s->core->mempool, &s->sample_spec, length);
+        }
+
+        result->memblock = pa_memblock_ref(s->silence);
+        result->length = length;
+        result->index = 0;
 
-    if (n == 1) {
+    } else if (n == 1) {
         pa_cvolume volume;
 
         *result = info[0].chunk;
@@ -363,18 +408,12 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
     if (s->monitor_source)
         pa_source_post(s->monitor_source, result);
 
-    r = 0;
-
-finish:
     pa_sink_unref(s);
-
-    return r;
 }
 
-int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
+void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
     pa_mix_info info[MAX_MIX_CHANNELS];
     unsigned n;
-    int r = -1;
 
     pa_sink_assert_ref(s);
     pa_assert(target);
@@ -385,11 +424,9 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
 
     n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
 
-    if (n <= 0)
-        goto finish;
-
-
-    if (n == 1) {
+    if (n == 0) {
+        pa_silence_memchunk(target, &s->sample_spec);
+    } else if (n == 1) {
         if (target->length > info[0].chunk.length)
             target->length = info[0].chunk.length;
 
@@ -435,12 +472,7 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
     if (s->monitor_source)
         pa_source_post(s->monitor_source, target);
 
-    r = 0;
-
-finish:
     pa_sink_unref(s);
-
-    return r;
 }
 
 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
@@ -461,20 +493,12 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
         chunk.index += d;
         chunk.length -= d;
 
-        if (pa_sink_render_into(s, &chunk) < 0)
-            break;
+        pa_sink_render_into(s, &chunk);
 
         d += chunk.length;
         l -= chunk.length;
     }
 
-    if (l > 0) {
-        chunk = *target;
-        chunk.index += d;
-        chunk.length -= d;
-        pa_silence_memchunk(&chunk, &s->sample_spec);
-    }
-
     pa_sink_unref(s);
 }
 
@@ -668,7 +692,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *
         case PA_SINK_MESSAGE_SET_STATE:
             s->thread_info.state = PA_PTR_TO_UINT(userdata);
             return 0;
-            
+
         case PA_SINK_MESSAGE_GET_LATENCY:
         case PA_SINK_MESSAGE_MAX:
             ;
index 0b308e5..dab9745 100644 (file)
@@ -92,6 +92,8 @@ struct pa_sink {
         int soft_muted;
     } thread_info;
 
+    pa_memblock *silence;
+
     void *userdata;
 };
 
@@ -149,9 +151,9 @@ unsigned pa_sink_used_by(pa_sink *s);
 
 /* To be used exclusively by the sink driver thread */
 
-int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result);
+void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result);
 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result);
-int pa_sink_render_into(pa_sink*s, pa_memchunk *target);
+void pa_sink_render_into(pa_sink*s, pa_memchunk *target);
 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target);
 
 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);