]> code.delx.au - pulseaudio/blobdiff - polyp/sink.c
add input latency measurement
[pulseaudio] / polyp / sink.c
index 1fe38e9f919b068279f15bda82c9e821783b75a8..8133d65a23e38610b9fbd10938f4d9809f990cc3 100644 (file)
@@ -52,9 +52,12 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co
         pa_xfree(s);
         return NULL;
     }
-    
+
     s->name = pa_xstrdup(name);
     s->description = NULL;
+
+    s->ref = 1;
+    s->state = PA_SINK_RUNNING;
     
     s->owner = NULL;
     s->core = core;
@@ -85,9 +88,9 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co
     return s;
 }
 
-void pa_sink_free(struct pa_sink *s) {
+void pa_sink_disconnect(struct pa_sink* s) {
     struct pa_sink_input *i, *j = NULL;
-    assert(s);
+    assert(s && s->state == PA_SINK_RUNNING);
 
     pa_namereg_unregister(s->core, s->name);
     
@@ -96,22 +99,51 @@ void pa_sink_free(struct pa_sink *s) {
         pa_sink_input_kill(i);
         j = i;
     }
-    pa_idxset_free(s->inputs, NULL, NULL);
 
-    pa_source_free(s->monitor_source);
+    pa_source_disconnect(s->monitor_source);
+
     pa_idxset_remove_by_data(s->core->sinks, s, NULL);
+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
+
+    s->notify = NULL;
+    s->get_latency = NULL;
+    
+    s->state = PA_SINK_DISCONNECTED;
+}
+
+static void sink_free(struct pa_sink *s) {
+    assert(s && s->ref == 0);
+    
+    if (s->state != PA_SINK_DISCONNECTED)
+        pa_sink_disconnect(s);
 
     pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name);
 
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
+    pa_source_unref(s->monitor_source);
+    s->monitor_source = NULL;
     
+    pa_idxset_free(s->inputs, NULL, NULL);
+
     pa_xfree(s->name);
     pa_xfree(s->description);
     pa_xfree(s);
 }
 
+void pa_sink_unref(struct pa_sink*s) {
+    assert(s && s->ref >= 1);
+
+    if (!(--s->ref))
+        sink_free(s);
+}
+
+struct pa_sink* pa_sink_ref(struct pa_sink *s) {
+    assert(s && s->ref >= 1);
+    s->ref++;
+    return s;
+}
+
 void pa_sink_notify(struct pa_sink*s) {
-    assert(s);
+    assert(s && s->ref >= 1);
 
     if (s->notify)
         s->notify(s);
@@ -122,16 +154,20 @@ static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsig
     struct pa_sink_input *i;
     unsigned n = 0;
     
-    assert(s && info);
+    assert(s && s->ref >= 1 && info);
 
     for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) {
-        if (pa_sink_input_peek(i, &info->chunk) < 0)
+        pa_sink_input_ref(i);
+
+        if (pa_sink_input_peek(i, &info->chunk) < 0) {
+            pa_sink_input_unref(i);
             continue;
+        }
 
         info->volume = i->volume;
+        info->userdata = i;
         
         assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length);
-        info->userdata = i;
         
         info++;
         maxinfo--;
@@ -142,7 +178,7 @@ static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsig
 }
 
 static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) {
-    assert(s && info);
+    assert(s && s->ref >= 1 && info);
 
     for (; maxinfo > 0; maxinfo--, info++) {
         struct pa_sink_input *i = info->userdata;
@@ -150,6 +186,9 @@ static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned ma
         
         pa_sink_input_drop(i, &info->chunk, length);
         pa_memblock_unref(info->chunk.memblock);
+
+        pa_sink_input_unref(i);
+        info->userdata = NULL;
     }
 }
         
@@ -157,12 +196,18 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result)
     struct pa_mix_info info[MAX_MIX_CHANNELS];
     unsigned n;
     size_t l;
-    assert(s && length && result);
+    int r = -1;
+    assert(s);
+    assert(s->ref >= 1);
+    assert(length);
+    assert(result);
 
+    pa_sink_ref(s);
+    
     n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
 
     if (n <= 0)
-        return -1;
+        goto finish;
 
     if (n == 1) {
         uint32_t volume = PA_VOLUME_NORM;
@@ -198,19 +243,27 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result)
     assert(s->monitor_source);
     pa_source_post(s->monitor_source, result);
 
-    return 0;
+    r = 0;
+
+finish:
+    pa_sink_unref(s);
+
+    return r;
 }
 
 int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) {
     struct pa_mix_info info[MAX_MIX_CHANNELS];
     unsigned n;
     size_t l;
-    assert(s && target && target->length && target->memblock && target->memblock->data);
+    int r = -1;
+    assert(s && s->ref >= 1 && target && target->length && target->memblock && target->memblock->data);
+
+    pa_sink_ref(s);
     
     n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
 
     if (n <= 0)
-        return -1;
+        goto finish;
 
     if (n == 1) {
         uint32_t volume = PA_VOLUME_NORM;
@@ -238,14 +291,21 @@ int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) {
     assert(s->monitor_source);
     pa_source_post(s->monitor_source, target);
 
-    return 0;
+    r = 0;
+
+finish:
+    pa_sink_unref(s);
+    
+    return r;
 }
 
 void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) {
     struct pa_memchunk chunk;
     size_t l, d;
-    assert(s && target && target->memblock && target->length && target->memblock->data);
+    assert(s && s->ref >= 1 && target && target->memblock && target->length && target->memblock->data);
 
+    pa_sink_ref(s);
+    
     l = target->length;
     d = 0;
     while (l > 0) {
@@ -266,10 +326,12 @@ void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) {
         chunk.length -= d;
         pa_silence_memchunk(&chunk, &s->sample_spec);
     }
+
+    pa_sink_unref(s);
 }
 
 void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result) {
-    assert(s && length && result);
+    assert(s && s->ref >= 1 && length && result);
 
     /*** This needs optimization ***/
     
@@ -280,7 +342,7 @@ void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *r
 }
 
 pa_usec_t pa_sink_get_latency(struct pa_sink *s) {
-    assert(s);
+    assert(s && s->ref >= 1);
 
     if (!s->get_latency)
         return 0;
@@ -288,18 +350,20 @@ pa_usec_t pa_sink_get_latency(struct pa_sink *s) {
     return s->get_latency(s);
 }
 
-void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) {
-    sink->owner = m;
+void pa_sink_set_owner(struct pa_sink *s, struct pa_module *m) {
+    assert(s && s->ref >= 1);
+           
+    s->owner = m;
 
-    if (sink->monitor_source)
-        pa_source_set_owner(sink->monitor_source, m);
+    if (s->monitor_source)
+        pa_source_set_owner(s->monitor_source, m);
 }
 
-void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume) {
-    assert(sink);
+void pa_sink_set_volume(struct pa_sink *s, pa_volume_t volume) {
+    assert(s && s->ref >= 1);
     
-    if (sink->volume != volume) {
-        sink->volume = volume;
-        pa_subscription_post(sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, sink->index);
+    if (s->volume != volume) {
+        s->volume = volume;
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
     }
 }