[pulseaudio-commits] r2527 - in /trunk/src: ./ pulse/ pulsecore/

svnmailer-noreply at 0pointer.de svnmailer-noreply at 0pointer.de
Fri Jun 13 14:56:20 PDT 2008


Author: lennart
Date: Fri Jun 13 23:56:19 2008
New Revision: 2527

URL: http://0pointer.de/cgi-bin/viewcvs.cgi?rev=2527&root=pulseaudio&view=rev
Log:
fix a bad memory access pulsecore/client.c

Modified:
    trunk/src/map-file
    trunk/src/pulse/internal.h
    trunk/src/pulse/stream.c
    trunk/src/pulse/stream.h
    trunk/src/pulsecore/cli-text.c
    trunk/src/pulsecore/client.c
    trunk/src/pulsecore/protocol-native.c
    trunk/src/pulsecore/sink-input.c
    trunk/src/pulsecore/sink-input.h
    trunk/src/pulsecore/sink.c
    trunk/src/pulsecore/source-output.c
    trunk/src/pulsecore/source-output.h
    trunk/src/pulsecore/source.c
    trunk/src/pulsecore/source.h

Modified: trunk/src/map-file
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/map-file?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/map-file (original)
+++ trunk/src/map-file Fri Jun 13 23:56:19 2008
@@ -180,6 +180,7 @@
 pa_stream_get_device_name;
 pa_stream_get_index;
 pa_stream_get_latency;
+pa_stream_get_monitor_stream;
 pa_stream_get_sample_spec;
 pa_stream_get_state;
 pa_stream_get_time;
@@ -197,6 +198,7 @@
 pa_stream_set_buffer_attr;
 pa_stream_set_latency_update_callback;
 pa_stream_set_moved_callback;
+pa_stream_set_monitor_stream;
 pa_stream_set_name;
 pa_stream_set_overflow_callback;
 pa_stream_set_read_callback;

Modified: trunk/src/pulse/internal.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/internal.h?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulse/internal.h (original)
+++ trunk/src/pulse/internal.h Fri Jun 13 23:56:19 2008
@@ -105,6 +105,8 @@
 
     pa_context *context;
     pa_mainloop_api *mainloop;
+
+    uint32_t direct_on_input;
 
     pa_stream_direction_t direction;
     pa_stream_state_t state;

Modified: trunk/src/pulse/stream.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/stream.c?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulse/stream.c (original)
+++ trunk/src/pulse/stream.c Fri Jun 13 23:56:19 2008
@@ -107,6 +107,8 @@
     s->sample_spec = *ss;
     s->channel_map = *map;
 
+    s->direct_on_input = PA_INVALID_INDEX;
+
     s->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
     if (name)
         pa_proplist_sets(s->proplist, PA_PROP_MEDIA_NAME, name);
@@ -838,6 +840,7 @@
     pa_assert(direction == PA_STREAM_PLAYBACK || direction == PA_STREAM_RECORD);
 
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY(s->context, s->direct_on_input == PA_INVALID_INDEX || direction == PA_STREAM_RECORD, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED|
                                               PA_STREAM_INTERPOLATE_TIMING|
                                               PA_STREAM_NOT_MONOTONOUS|
@@ -954,6 +957,9 @@
                 PA_TAG_BOOLEAN, flags & PA_STREAM_ADJUST_LATENCY,
                 PA_TAG_PROPLIST, s->proplist,
                 PA_TAG_INVALID);
+
+        if (s->direction == PA_STREAM_RECORD)
+            pa_tagstruct_putu32(t, s->direct_on_input);
     }
 
     pa_pstream_send_tagstruct(s->context->pstream, t);
@@ -2227,3 +2233,26 @@
 
     return o;
 }
+
+int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) {
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+    PA_CHECK_VALIDITY(s->context, sink_input_idx != PA_INVALID_INDEX, PA_ERR_INVALID);
+    PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED);
+
+    s->direct_on_input = sink_input_idx;
+
+    return 0;
+}
+
+uint32_t pa_stream_get_monitor_stream(pa_stream *s) {
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+    PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direct_on_input != PA_INVALID_INDEX, PA_ERR_BADSTATE, PA_INVALID_INDEX);
+    PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
+
+    return s->direct_on_input;
+}

Modified: trunk/src/pulse/stream.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/stream.h?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulse/stream.h (original)
+++ trunk/src/pulse/stream.h Fri Jun 13 23:56:19 2008
@@ -527,14 +527,14 @@
  * server is at least PulseAudio 0.9.8. \since 0.9.8 */
 pa_operation *pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata);
 
-/* Change the stream sampling rate during playback. You need to pass
+/** Change the stream sampling rate during playback. You need to pass
  * PA_STREAM_VARIABLE_RATE in the flags parameter of
  * pa_stream_connect() if you plan to use this function. Only valid
  * after the stream has been connected successfully and if the server
  * is at least PulseAudio 0.9.8. \since 0.9.8 */
 pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata);
 
-/* Update the property list of the sink input/source output of this
+/** Update the property list of the sink input/source output of this
  * stream, adding new entries. Please note that it is highly
  * recommended to set as much properties initially via
  * pa_stream_new_with_proplist() as possible instead a posteriori with
@@ -542,10 +542,20 @@
  * this stream to the right device. \since 0.9.11 */
 pa_operation *pa_stream_proplist_update(pa_stream *s, pa_update_mode_t mode, pa_proplist *p, pa_stream_success_cb_t cb, void *userdata);
 
-/* Update the property list of the sink input/source output of this
+/** Update the property list of the sink input/source output of this
  * stream, remove entries. \since 0.9.11 */
 pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[], pa_stream_success_cb_t cb, void *userdata);
 
+/** For record streams connected to a monitor source: monitor only a
+ * very specific sink input of the sink. Thus function needs to be
+ * called before pa_stream_connect_record() is called. \since
+ * 0.9.11 */
+int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx);
+
+/** Return what has been set with pa_stream_set_monitor_stream()
+ * ebfore. \since 0.9.11 */
+uint32_t pa_stream_get_monitor_stream(pa_stream *s);
+
 PA_C_DECL_END
 
 #endif

Modified: trunk/src/pulsecore/cli-text.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/cli-text.c?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/cli-text.c (original)
+++ trunk/src/pulsecore/cli-text.c Fri Jun 13 23:56:19 2008
@@ -296,6 +296,8 @@
             pa_strbuf_printf(s, "\towner module: %u\n", o->module->index);
         if (o->client)
             pa_strbuf_printf(s, "\tclient: %u <%s>\n", o->client->index, pa_strnull(pa_proplist_gets(o->client->proplist, PA_PROP_APPLICATION_NAME)));
+        if (o->direct_on_input)
+            pa_strbuf_printf(s, "\tdirect on input: %u\n", o->direct_on_input->index);
 
         t = pa_proplist_to_string(o->proplist);
         pa_strbuf_printf(s, "\tproperties:\n%s", t);

Modified: trunk/src/pulsecore/client.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/client.c?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/client.c (original)
+++ trunk/src/pulsecore/client.c Fri Jun 13 23:56:19 2008
@@ -80,7 +80,7 @@
     pa_xfree(c->driver);
     pa_xfree(c);
 
-    pa_core_check_quit(c->core);
+    pa_core_check_quit(core);
 }
 
 void pa_client_kill(pa_client *c) {

Modified: trunk/src/pulsecore/protocol-native.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/protocol-native.c?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/protocol-native.c (original)
+++ trunk/src/pulsecore/protocol-native.c Fri Jun 13 23:56:19 2008
@@ -499,7 +499,8 @@
             fragsize_usec = s->source_latency;
 
         *fragsize = pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
-    }
+    } else
+        s->source_latency = 0;
 }
 
 static void fix_record_buffer_attr_post(record_stream *s, uint32_t *maxlength, uint32_t *fragsize) {
@@ -533,7 +534,8 @@
         uint32_t *fragsize,
         pa_source_output_flags_t flags,
         pa_proplist *p,
-        pa_bool_t adjust_latency) {
+        pa_bool_t adjust_latency,
+        pa_sink_input *direct_on_input) {
 
     record_stream *s;
     pa_source_output *source_output;
@@ -553,6 +555,7 @@
     data.module = c->protocol->module;
     data.client = c->client;
     data.source = source;
+    data.direct_on_input = direct_on_input;
     pa_source_output_new_data_set_sample_spec(&data, ss);
     pa_source_output_new_data_set_channel_map(&data, map);
     if (peak_detect)
@@ -1757,7 +1760,7 @@
     record_stream *s;
     uint32_t maxlength, fragment_size;
     uint32_t source_index;
-    const char *name, *source_name;
+    const char *name = NULL, *source_name;
     pa_sample_spec ss;
     pa_channel_map map;
     pa_tagstruct *reply;
@@ -1775,6 +1778,8 @@
         peak_detect = FALSE;
     pa_source_output_flags_t flags = 0;
     pa_proplist *p;
+    uint32_t direct_on_input_idx = PA_INVALID_INDEX;
+    pa_sink_input *direct_on_input = NULL;
 
     connection_assert_ref(c);
     pa_assert(t);
@@ -1823,7 +1828,8 @@
 
         if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
             pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
-            pa_tagstruct_get_proplist(t, p) < 0) {
+            pa_tagstruct_get_proplist(t, p) < 0 ||
+            pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
             protocol_error(c);
             pa_proplist_free(p);
             return;
@@ -1847,6 +1853,15 @@
     } else if (source_name) {
 
         if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1))) {
+            pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
+            pa_proplist_free(p);
+            return;
+        }
+    }
+
+    if (direct_on_input_idx != PA_INVALID_INDEX) {
+
+        if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
             pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
             pa_proplist_free(p);
             return;
@@ -1863,7 +1878,7 @@
         (no_move ?  PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
         (variable_rate ?  PA_SOURCE_OUTPUT_VARIABLE_RATE : 0);
 
-    s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency);
+    s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input);
     pa_proplist_free(p);
 
     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);

Modified: trunk/src/pulsecore/sink-input.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sink-input.c?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/sink-input.c (original)
+++ trunk/src/pulsecore/sink-input.c Fri Jun 13 23:56:19 2008
@@ -219,6 +219,8 @@
     i->module = data->module;
     i->sink = data->sink;
     i->client = data->client;
+
+    i->direct_outputs = pa_idxset_new(NULL, NULL);
 
     i->resample_method = data->resample_method;
     i->sample_spec = data->sample_spec;
@@ -252,6 +254,7 @@
     i->thread_info.rewrite_flush = FALSE;
     i->thread_info.underrun_for = (uint64_t) -1;
     i->thread_info.playing_for = 0;
+    i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
     i->thread_info.render_memblockq = pa_memblockq_new(
             0,
@@ -322,6 +325,7 @@
 
 void pa_sink_input_unlink(pa_sink_input *i) {
     pa_bool_t linked;
+    pa_source_output *o, *p =  NULL;
     pa_assert(i);
 
     /* See pa_sink_unlink() for a couple of comments how this function
@@ -345,6 +349,12 @@
     if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL))
         pa_sink_input_unref(i);
 
+    while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
+        pa_assert(o != p);
+        pa_source_output_kill(o);
+        p = o;
+    }
+
     update_n_corked(i, PA_SINK_INPUT_UNLINKED);
     i->state = PA_SINK_INPUT_UNLINKED;
 
@@ -384,6 +394,12 @@
 
     if (i->proplist)
         pa_proplist_free(i->proplist);
+
+    if (i->direct_outputs)
+        pa_idxset_free(i->direct_outputs, NULL, NULL);
+
+    if (i->thread_info.direct_outputs)
+        pa_hashmap_free(i->thread_info.direct_outputs, NULL, NULL);
 
     pa_xfree(i->driver);
     pa_xfree(i);
@@ -839,6 +855,7 @@
     pa_resampler *new_resampler;
     pa_sink *origin;
     pa_sink_input_move_hook_data hook_data;
+    pa_source_output *o, *p = NULL;
 
     pa_sink_input_assert_ref(i);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
@@ -860,6 +877,13 @@
     if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) {
         pa_log_warn("Failed to move sink input: too many inputs per sink.");
         return -1;
+    }
+
+    /* Kill directly connected outputs */
+    while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
+        pa_assert(o != p);
+        pa_source_output_kill(o);
+        p = o;
     }
 
     if (i->thread_info.resampler &&

Modified: trunk/src/pulsecore/sink-input.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sink-input.h?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/sink-input.h (original)
+++ trunk/src/pulsecore/sink-input.h Fri Jun 13 23:56:19 2008
@@ -80,6 +80,11 @@
 
     pa_sink *sink;
 
+    /* A sink input may be connected to multiple source outputs
+     * directly, so that they don't get mixed data of the entire
+     * source. */
+    pa_idxset *direct_outputs;
+
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
 
@@ -166,6 +171,8 @@
 
         /* The requested latency for the sink */
         pa_usec_t requested_sink_latency;
+
+        pa_hashmap *direct_outputs;
     } thread_info;
 
     void *userdata;

Modified: trunk/src/pulsecore/sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sink.c?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/sink.c (original)
+++ trunk/src/pulsecore/sink.c Fri Jun 13 23:56:19 2008
@@ -498,23 +498,24 @@
     return n;
 }
 
-static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length) {
+static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
     pa_sink_input *i;
     void *state = NULL;
     unsigned p = 0;
     unsigned n_unreffed = 0;
 
     pa_sink_assert_ref(s);
+    pa_assert(result);
+    pa_assert(result->memblock);
+    pa_assert(result->length > 0);
 
     /* We optimize for the case where the order of the inputs has not changed */
 
     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
         unsigned j;
-        pa_mix_info* m;
+        pa_mix_info* m = NULL;
 
         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 ++) {
@@ -530,14 +531,47 @@
         }
 
         /* Drop read data */
-        pa_sink_input_drop(i, length);
+        pa_sink_input_drop(i, result->length);
+
+        if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) {
+
+            if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
+                void *ostate = NULL;
+                pa_source_output *o;
+                pa_memchunk c;
+
+                if (m && m->chunk.memblock) {
+                    c = m->chunk;
+                    pa_memblock_ref(c.memblock);
+                    pa_assert(result->length <= c.length);
+                    c.length = result->length;
+
+                    pa_memchunk_make_writable(&c, 0);
+                    pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
+                } else {
+                    c = s->silence;
+                    pa_memblock_ref(c.memblock);
+                    pa_assert(result->length <= c.length);
+                    c.length = result->length;
+                }
+
+                while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
+                    pa_source_output_assert_ref(o);
+                    pa_assert(o->direct_on_input == i);
+                    pa_source_post_direct(s->monitor_source, o, &c);
+                }
+
+                pa_memblock_unref(c.memblock);
+            }
+        }
 
         if (m) {
+            if (m->chunk.memblock)
+                pa_memblock_unref(m->chunk.memblock);
+                pa_memchunk_reset(&m->chunk);
+
             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;
         }
@@ -554,6 +588,9 @@
                 pa_memblock_unref(info->chunk.memblock);
         }
     }
+
+    if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
+        pa_source_post(s->monitor_source, result);
 }
 
 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
@@ -624,10 +661,7 @@
     }
 
     if (s->thread_info.state == PA_SINK_RUNNING)
-        inputs_drop(s, info, n, result->length);
-
-    if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
-        pa_source_post(s->monitor_source, result);
+        inputs_drop(s, info, n, result);
 
     pa_sink_unref(s);
 }
@@ -653,6 +687,8 @@
     if (length > block_size_max)
         length = pa_frame_align(block_size_max, &s->sample_spec);
 
+    pa_assert(length > 0);
+
     n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, &length, info, MAX_MIX_CHANNELS) : 0;
 
     if (n == 0) {
@@ -676,8 +712,8 @@
             vchunk = info[0].chunk;
             pa_memblock_ref(vchunk.memblock);
 
-            if (vchunk.length > target->length)
-                vchunk.length = target->length;
+            if (vchunk.length > length)
+                vchunk.length = length;
 
             if (!pa_cvolume_is_norm(&volume)) {
                 pa_memchunk_make_writable(&vchunk, 0);
@@ -703,10 +739,7 @@
     }
 
     if (s->thread_info.state == PA_SINK_RUNNING)
-        inputs_drop(s, info, n, target->length);
-
-    if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
-        pa_source_post(s->monitor_source, target);
+        inputs_drop(s, info, n, target);
 
     pa_sink_unref(s);
 }

Modified: trunk/src/pulsecore/source-output.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/source-output.c?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/source-output.c (original)
+++ trunk/src/pulsecore/source-output.c Fri Jun 13 23:56:19 2008
@@ -113,6 +113,8 @@
 
     pa_return_null_if_fail(data->source);
     pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_UNLINKED);
+
+    pa_return_null_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of);
 
     if (!data->sample_spec_is_set)
         data->sample_spec = data->source->sample_spec;
@@ -192,6 +194,8 @@
     o->sample_spec = data->sample_spec;
     o->channel_map = data->channel_map;
 
+    o->direct_on_input = data->direct_on_input;
+
     reset_callbacks(o);
     o->userdata = NULL;
 
@@ -200,6 +204,7 @@
     o->thread_info.sample_spec = o->sample_spec;
     o->thread_info.resampler = resampler;
     o->thread_info.requested_source_latency = (pa_usec_t) -1;
+    o->thread_info.direct_on_input = o->direct_on_input;
 
     o->thread_info.delay_memblockq = pa_memblockq_new(
             0,
@@ -214,6 +219,9 @@
     pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
     pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0);
 
+    if (o->direct_on_input)
+        pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0);
+
     pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s",
                 o->index,
                 pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)),
@@ -269,6 +277,8 @@
     if (linked)
         pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);
 
+    if (o->direct_on_input)
+        pa_idxset_remove_by_data(o->direct_on_input->direct_outputs, o, NULL);
     pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
     if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
         pa_source_output_unref(o);
@@ -368,10 +378,10 @@
     pa_assert(chunk);
     pa_assert(pa_frame_aligned(chunk->length, &o->source->sample_spec));
 
-    if (!o->push || o->state == PA_SOURCE_OUTPUT_CORKED)
+    if (!o->push || o->thread_info.state == PA_SOURCE_OUTPUT_CORKED)
         return;
 
-    pa_assert(o->state == PA_SOURCE_OUTPUT_RUNNING);
+    pa_assert(o->thread_info.state == PA_SOURCE_OUTPUT_RUNNING);
 
     if (pa_memblockq_push(o->thread_info.delay_memblockq, chunk) < 0) {
         pa_log_debug("Delay queue overflow!");
@@ -422,7 +432,7 @@
 void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in sink sample spec */) {
     pa_source_output_assert_ref(o);
 
-    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
+    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
     pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
 
     if (nbytes <= 0)
@@ -581,6 +591,9 @@
         return 0;
 
     if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
+        return -1;
+
+    if (o->direct_on_input)
         return -1;
 
     if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {

Modified: trunk/src/pulsecore/source-output.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/source-output.h?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/source-output.h (original)
+++ trunk/src/pulsecore/source-output.h Fri Jun 13 23:56:19 2008
@@ -73,6 +73,9 @@
 
     pa_source *source;
 
+    /* A source output can monitor just a single input of a sink, in which case we find it here */
+    pa_sink_input *direct_on_input;       /* may be NULL */
+
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
 
@@ -135,6 +138,8 @@
 
         /* The requested latency for the source */
         pa_usec_t requested_source_latency;
+
+        pa_sink_input *direct_on_input;       /* may be NULL */
     } thread_info;
 
     void *userdata;
@@ -154,6 +159,7 @@
 
 typedef struct pa_source_output_new_data {
     pa_proplist *proplist;
+    pa_sink_input *direct_on_input;
 
     const char *driver;
     pa_module *module;

Modified: trunk/src/pulsecore/source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/source.c?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/source.c (original)
+++ trunk/src/pulsecore/source.c Fri Jun 13 23:56:19 2008
@@ -417,7 +417,9 @@
 
         while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
             pa_source_output_assert_ref(o);
-            pa_source_output_push(o, &vchunk);
+
+            if (!o->thread_info.direct_on_input)
+                pa_source_output_push(o, &vchunk);
         }
 
         pa_memblock_unref(vchunk.memblock);
@@ -425,9 +427,39 @@
 
         while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
             pa_source_output_assert_ref(o);
-            pa_source_output_push(o, chunk);
+
+            if (!o->thread_info.direct_on_input)
+                pa_source_output_push(o, chunk);
         }
     }
+}
+
+void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state));
+    pa_source_output_assert_ref(o);
+    pa_assert(o->thread_info.direct_on_input);
+    pa_assert(chunk);
+
+    if (s->thread_info.state != PA_SOURCE_RUNNING)
+        return;
+
+    if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
+        pa_memchunk vchunk = *chunk;
+
+        pa_memblock_ref(vchunk.memblock);
+        pa_memchunk_make_writable(&vchunk, 0);
+
+        if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
+            pa_silence_memchunk(&vchunk, &s->sample_spec);
+        else
+            pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
+
+        pa_source_output_push(o, &vchunk);
+
+        pa_memblock_unref(vchunk.memblock);
+    } else
+        pa_source_output_push(o, chunk);
 }
 
 pa_usec_t pa_source_get_latency(pa_source *s) {
@@ -577,6 +609,11 @@
 
             pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
 
+            if (o->direct_on_input) {
+                o->thread_info.direct_on_input = o->direct_on_input;
+                pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
+            }
+
             pa_assert(!o->thread_info.attached);
             o->thread_info.attached = TRUE;
 
@@ -606,6 +643,11 @@
             pa_assert(o->thread_info.attached);
             o->thread_info.attached = FALSE;
 
+            if (o->thread_info.direct_on_input) {
+                pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
+                o->thread_info.direct_on_input = NULL;
+            }
+
             if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
                 pa_source_output_unref(o);
 

Modified: trunk/src/pulsecore/source.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/source.h?rev=2527&root=pulseaudio&r1=2526&r2=2527&view=diff
==============================================================================
--- trunk/src/pulsecore/source.h (original)
+++ trunk/src/pulsecore/source.h Fri Jun 13 23:56:19 2008
@@ -42,6 +42,7 @@
 #include <pulsecore/asyncmsgq.h>
 #include <pulsecore/msgobject.h>
 #include <pulsecore/rtpoll.h>
+#include <pulsecore/source-output.h>
 
 #define PA_MAX_OUTPUTS_PER_SOURCE 32
 
@@ -205,7 +206,8 @@
 
 /* To be called exclusively by the source driver, from IO context */
 
-void pa_source_post(pa_source*s, const pa_memchunk *b);
+void pa_source_post(pa_source*s, const pa_memchunk *chunk);
+void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk);
 void pa_source_process_rewind(pa_source *s, size_t nbytes);
 
 int pa_source_process_msg(pa_msgobject *o, int code, void *userdata, int64_t, pa_memchunk *chunk);




More information about the pulseaudio-commits mailing list