2 This file is part of PulseAudio.
4 Copyright 2010 Intel Corporation
5 Contributor: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include <pulse/xmalloc.h>
31 #include <pulsecore/i18n.h>
32 #include <pulsecore/macro.h>
33 #include <pulsecore/namereg.h>
34 #include <pulsecore/sink.h>
35 #include <pulsecore/module.h>
36 #include <pulsecore/core-util.h>
37 #include <pulsecore/modargs.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/rtpoll.h>
40 #include <pulsecore/sample-util.h>
41 #include <pulsecore/ltdl-helper.h>
42 #include <pulsecore/mix.h>
44 #include "module-virtual-source-symdef.h"
46 PA_MODULE_AUTHOR("Pierre-Louis Bossart");
47 PA_MODULE_DESCRIPTION("Virtual source");
48 PA_MODULE_VERSION(PACKAGE_VERSION
);
49 PA_MODULE_LOAD_ONCE(FALSE
);
51 _("source_name=<name for the source> "
52 "source_properties=<properties for the source> "
53 "master=<name of source to filter> "
54 "uplink_sink=<name> (optional)"
55 "format=<sample format> "
57 "channels=<number of channels> "
58 "channel_map=<channel map> "
59 "use_volume_sharing=<yes or no> "
60 "force_flat_volume=<yes or no> "
63 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
64 #define BLOCK_USEC 1000 /* FIXME */
69 /* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */
70 /* pa_bool_t autoloaded; */
73 pa_source_output
*source_output
;
75 pa_memblockq
*memblockq
;
80 /* optional fields for uplink sink */
83 pa_memblockq
*sink_memblockq
;
87 static const char* const valid_modargs
[] = {
101 /* Called from I/O thread context */
102 static int sink_process_msg_cb(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
106 case PA_SINK_MESSAGE_GET_LATENCY
:
108 /* there's no real latency here */
109 *((pa_usec_t
*) data
) = 0;
114 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
117 /* Called from main context */
118 static int sink_set_state_cb(pa_sink
*s
, pa_sink_state_t state
) {
121 pa_sink_assert_ref(s
);
122 pa_assert_se(u
= s
->userdata
);
124 if (!PA_SINK_IS_LINKED(state
)) {
128 if (state
== PA_SINK_RUNNING
) {
129 /* need to wake-up source if it was suspended */
130 pa_log_debug("Resuming source %s, because its uplink sink became active.", u
->source
->name
);
131 pa_source_suspend(u
->source
, FALSE
, PA_SUSPEND_ALL
);
133 /* FIXME: if there's no client connected, the source will suspend
134 and playback will be stuck. You'd want to prevent the source from
135 sleeping when the uplink sink is active; even if the audio is
136 discarded at least the app isn't stuck */
139 /* nothing to do, if the sink becomes idle or suspended let
140 module-suspend-idle handle the sources later */
146 static void sink_update_requested_latency_cb(pa_sink
*s
) {
149 pa_sink_assert_ref(s
);
150 pa_assert_se(u
= s
->userdata
);
152 /* FIXME: there's no latency support */
157 /* Called from I/O thread context */
158 static void sink_request_rewind_cb(pa_sink
*s
) {
161 pa_sink_assert_ref(s
);
162 pa_assert_se(u
= s
->userdata
);
165 pa_sink_process_rewind(u
->sink
, 0);
169 /* Called from I/O thread context */
170 static int source_process_msg_cb(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
171 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
175 case PA_SOURCE_MESSAGE_GET_LATENCY
:
177 /* The source is _put() before the source output is, so let's
178 * make sure we don't access it in that time. Also, the
179 * source output is first shut down, the source second. */
180 if (!PA_SOURCE_IS_LINKED(u
->source
->thread_info
.state
) ||
181 !PA_SOURCE_OUTPUT_IS_LINKED(u
->source_output
->thread_info
.state
)) {
182 *((pa_usec_t
*) data
) = 0;
186 *((pa_usec_t
*) data
) =
188 /* Get the latency of the master source */
189 pa_source_get_latency_within_thread(u
->source_output
->source
) +
191 /* Add the latency internal to our source output on top */
192 /* FIXME, no idea what I am doing here */
193 pa_bytes_to_usec(pa_memblockq_get_length(u
->source_output
->thread_info
.delay_memblockq
), &u
->source_output
->source
->sample_spec
);
198 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
201 /* Called from main context */
202 static int source_set_state_cb(pa_source
*s
, pa_source_state_t state
) {
205 pa_source_assert_ref(s
);
206 pa_assert_se(u
= s
->userdata
);
208 if (!PA_SOURCE_IS_LINKED(state
) ||
209 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
)))
212 pa_source_output_cork(u
->source_output
, state
== PA_SOURCE_SUSPENDED
);
216 /* Called from I/O thread context */
217 static void source_update_requested_latency_cb(pa_source
*s
) {
220 pa_source_assert_ref(s
);
221 pa_assert_se(u
= s
->userdata
);
223 if (!PA_SOURCE_IS_LINKED(u
->source
->thread_info
.state
) ||
224 !PA_SOURCE_OUTPUT_IS_LINKED(u
->source_output
->thread_info
.state
))
227 /* Just hand this one over to the master source */
228 pa_source_output_set_requested_latency_within_thread(
230 pa_source_get_requested_latency_within_thread(s
));
233 /* Called from main context */
234 static void source_set_volume_cb(pa_source
*s
) {
237 pa_source_assert_ref(s
);
238 pa_assert_se(u
= s
->userdata
);
240 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s
)) ||
241 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
)))
244 pa_source_output_set_volume(u
->source_output
, &s
->real_volume
, s
->save_volume
, TRUE
);
247 /* Called from main context */
248 static void source_set_mute_cb(pa_source
*s
) {
251 pa_source_assert_ref(s
);
252 pa_assert_se(u
= s
->userdata
);
254 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s
)) ||
255 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
)))
258 pa_source_output_set_mute(u
->source_output
, s
->muted
, s
->save_muted
);
261 /* Called from input thread context */
262 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
265 pa_source_output_assert_ref(o
);
266 pa_source_output_assert_io_context(o
);
267 pa_assert_se(u
= o
->userdata
);
269 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
))) {
270 pa_log("push when no link?");
274 /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */
276 /* if uplink sink exists, pull data from there; simplify by using
277 same length as chunk provided by source */
278 if (u
->sink
&& (pa_sink_get_state(u
->sink
) == PA_SINK_RUNNING
)) {
280 size_t nbytes
= chunk
->length
;
281 pa_mix_info streams
[2];
282 pa_memchunk target_chunk
;
286 /* Hmm, process any rewind request that might be queued up */
287 pa_sink_process_rewind(u
->sink
, 0);
289 /* get data from the sink */
290 while (pa_memblockq_peek(u
->sink_memblockq
, &tchunk
) < 0) {
293 /* make sure we get nbytes from the sink with render_full,
294 otherwise we cannot mix with the uplink */
295 pa_sink_render_full(u
->sink
, nbytes
, &nchunk
);
296 pa_memblockq_push(u
->sink_memblockq
, &nchunk
);
297 pa_memblock_unref(nchunk
.memblock
);
299 pa_assert(tchunk
.length
== chunk
->length
);
301 /* move the read pointer for sink memblockq */
302 pa_memblockq_drop(u
->sink_memblockq
, tchunk
.length
);
304 /* allocate target chunk */
305 /* this could probably be done in-place, but having chunk as both
306 the input and output creates issues with reference counts */
307 target_chunk
.index
= 0;
308 target_chunk
.length
= chunk
->length
;
309 pa_assert(target_chunk
.length
== chunk
->length
);
311 target_chunk
.memblock
= pa_memblock_new(o
->source
->core
->mempool
,
312 target_chunk
.length
);
313 pa_assert( target_chunk
.memblock
);
315 /* get target pointer */
316 target
= pa_memblock_acquire_chunk(&target_chunk
);
318 /* set-up mixing structure
319 volume was taken care of in sink and source already */
320 streams
[0].chunk
= *chunk
;
321 for(ch
=0;ch
<o
->sample_spec
.channels
;ch
++)
322 streams
[0].volume
.values
[ch
] = PA_VOLUME_NORM
; /* FIXME */
323 streams
[0].volume
.channels
= o
->sample_spec
.channels
;
325 streams
[1].chunk
= tchunk
;
326 for(ch
=0;ch
<o
->sample_spec
.channels
;ch
++)
327 streams
[1].volume
.values
[ch
] = PA_VOLUME_NORM
; /* FIXME */
328 streams
[1].volume
.channels
= o
->sample_spec
.channels
;
331 pa_mix(streams
, /* 2 streams to be mixed */
333 target
, /* put result in target chunk */
334 chunk
->length
, /* same length as input */
335 (const pa_sample_spec
*)&o
->sample_spec
, /* same sample spec for input and output */
336 NULL
, /* no volume information */
337 FALSE
); /* no mute */
339 pa_memblock_release(target_chunk
.memblock
);
340 pa_memblock_unref(tchunk
.memblock
); /* clean-up */
342 /* forward the data to the virtual source */
343 pa_source_post(u
->source
, &target_chunk
);
345 pa_memblock_unref(target_chunk
.memblock
); /* clean-up */
348 /* forward the data to the virtual source */
349 pa_source_post(u
->source
, chunk
);
355 /* Called from input thread context */
356 static void source_output_process_rewind_cb(pa_source_output
*o
, size_t nbytes
) {
359 pa_source_output_assert_ref(o
);
360 pa_source_output_assert_io_context(o
);
361 pa_assert_se(u
= o
->userdata
);
363 /* FIXME, no idea what I am doing here */
365 pa_asyncmsgq_post(u
->asyncmsgq
, PA_MSGOBJECT(u
->sink_input
), SINK_INPUT_MESSAGE_REWIND
, NULL
, (int64_t) nbytes
, NULL
, NULL
);
366 u
->send_counter
-= (int64_t) nbytes
;
370 /* Called from output thread context */
371 static void source_output_attach_cb(pa_source_output
*o
) {
374 pa_source_output_assert_ref(o
);
375 pa_source_output_assert_io_context(o
);
376 pa_assert_se(u
= o
->userdata
);
378 pa_source_set_rtpoll(u
->source
, o
->source
->thread_info
.rtpoll
);
379 pa_source_set_latency_range_within_thread(u
->source
, o
->source
->thread_info
.min_latency
, o
->source
->thread_info
.max_latency
);
380 pa_source_set_fixed_latency_within_thread(u
->source
, o
->source
->thread_info
.fixed_latency
);
381 pa_source_set_max_rewind_within_thread(u
->source
, pa_source_output_get_max_rewind(o
));
383 pa_source_attach_within_thread(u
->source
);
386 /* Called from output thread context */
387 static void source_output_detach_cb(pa_source_output
*o
) {
390 pa_source_output_assert_ref(o
);
391 pa_source_output_assert_io_context(o
);
392 pa_assert_se(u
= o
->userdata
);
394 pa_source_detach_within_thread(u
->source
);
395 pa_source_set_rtpoll(u
->source
, NULL
);
398 /* Called from output thread context */
399 static void source_output_state_change_cb(pa_source_output
*o
, pa_source_output_state_t state
) {
402 pa_source_output_assert_ref(o
);
403 pa_source_output_assert_io_context(o
);
404 pa_assert_se(u
= o
->userdata
);
408 if (PA_SOURCE_OUTPUT_IS_LINKED(state
) && o
->thread_info
.state
== PA_SOURCE_OUTPUT_INIT
) {
410 u
->skip
= pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o
->source
),
414 pa_log_info("Skipping %lu bytes", (unsigned long) u
->skip
);
419 /* Called from main thread */
420 static void source_output_kill_cb(pa_source_output
*o
) {
423 pa_source_output_assert_ref(o
);
424 pa_assert_ctl_context();
425 pa_assert_se(u
= o
->userdata
);
427 /* The order here matters! We first kill the source output, followed
428 * by the source. That means the source callbacks must be protected
429 * against an unconnected source output! */
430 pa_source_output_unlink(u
->source_output
);
431 pa_source_unlink(u
->source
);
433 pa_source_output_unref(u
->source_output
);
434 u
->source_output
= NULL
;
436 pa_source_unref(u
->source
);
439 pa_module_unload_request(u
->module
, TRUE
);
442 /* Called from main thread */
443 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
446 pa_source_output_assert_ref(o
);
447 pa_assert_ctl_context();
448 pa_assert_se(u
= o
->userdata
);
451 pa_source_set_asyncmsgq(u
->source
, dest
->asyncmsgq
);
452 pa_source_update_flags(u
->source
, PA_SOURCE_LATENCY
|PA_SOURCE_DYNAMIC_LATENCY
, dest
->flags
);
454 pa_source_set_asyncmsgq(u
->source
, NULL
);
456 if (u
->auto_desc
&& dest
) {
460 pl
= pa_proplist_new();
461 z
= pa_proplist_gets(dest
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
462 pa_proplist_setf(pl
, PA_PROP_DEVICE_DESCRIPTION
, "Virtual Source %s on %s",
463 pa_proplist_gets(u
->source
->proplist
, "device.vsource.name"), z
? z
: dest
->name
);
465 pa_source_update_proplist(u
->source
, PA_UPDATE_REPLACE
, pl
);
466 pa_proplist_free(pl
);
471 int pa__init(pa_module
*m
) {
476 pa_source
*master
=NULL
;
477 pa_source_output_new_data source_output_data
;
478 pa_source_new_data source_data
;
479 pa_bool_t use_volume_sharing
= TRUE
;
480 pa_bool_t force_flat_volume
= FALSE
;
482 /* optional for uplink_sink */
483 pa_sink_new_data sink_data
;
488 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
489 pa_log("Failed to parse module arguments.");
493 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SOURCE
))) {
494 pa_log("Master source not found");
500 ss
= master
->sample_spec
;
501 ss
.format
= PA_SAMPLE_FLOAT32
;
502 map
= master
->channel_map
;
503 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
504 pa_log("Invalid sample format specification or channel map");
508 if (pa_modargs_get_value_boolean(ma
, "use_volume_sharing", &use_volume_sharing
) < 0) {
509 pa_log("use_volume_sharing= expects a boolean argument");
513 if (pa_modargs_get_value_boolean(ma
, "force_flat_volume", &force_flat_volume
) < 0) {
514 pa_log("force_flat_volume= expects a boolean argument");
518 if (use_volume_sharing
&& force_flat_volume
) {
519 pa_log("Flat volume can't be forced when using volume sharing.");
523 u
= pa_xnew0(struct userdata
, 1);
526 u
->memblockq
= pa_memblockq_new("module-virtual-source memblockq", 0, MEMBLOCKQ_MAXLENGTH
, 0, &ss
, 1, 1, 0, NULL
);
528 pa_log("Failed to create source memblockq.");
531 u
->channels
= ss
.channels
;
534 pa_source_new_data_init(&source_data
);
535 source_data
.driver
= __FILE__
;
536 source_data
.module
= m
;
537 if (!(source_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "source_name", NULL
))))
538 source_data
.name
= pa_sprintf_malloc("%s.vsource", master
->name
);
539 pa_source_new_data_set_sample_spec(&source_data
, &ss
);
540 pa_source_new_data_set_channel_map(&source_data
, &map
);
541 pa_proplist_sets(source_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
542 pa_proplist_sets(source_data
.proplist
, PA_PROP_DEVICE_CLASS
, "filter");
543 pa_proplist_sets(source_data
.proplist
, "device.vsource.name", source_data
.name
);
545 if (pa_modargs_get_proplist(ma
, "source_properties", source_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
546 pa_log("Invalid properties");
547 pa_source_new_data_done(&source_data
);
551 if ((u
->auto_desc
= !pa_proplist_contains(source_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
))) {
554 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
555 pa_proplist_setf(source_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Virtual Source %s on %s", source_data
.name
, z
? z
: master
->name
);
558 u
->source
= pa_source_new(m
->core
, &source_data
, (master
->flags
& (PA_SOURCE_LATENCY
|PA_SOURCE_DYNAMIC_LATENCY
))
559 | (use_volume_sharing
? PA_SOURCE_SHARE_VOLUME_WITH_MASTER
: 0));
561 pa_source_new_data_done(&source_data
);
564 pa_log("Failed to create source.");
568 u
->source
->parent
.process_msg
= source_process_msg_cb
;
569 u
->source
->set_state
= source_set_state_cb
;
570 u
->source
->update_requested_latency
= source_update_requested_latency_cb
;
571 pa_source_set_set_mute_callback(u
->source
, source_set_mute_cb
);
572 if (!use_volume_sharing
) {
573 pa_source_set_set_volume_callback(u
->source
, source_set_volume_cb
);
574 pa_source_enable_decibel_volume(u
->source
, TRUE
);
576 /* Normally this flag would be enabled automatically be we can force it. */
577 if (force_flat_volume
)
578 u
->source
->flags
|= PA_SOURCE_FLAT_VOLUME
;
579 u
->source
->userdata
= u
;
581 pa_source_set_asyncmsgq(u
->source
, master
->asyncmsgq
);
583 /* Create source output */
584 pa_source_output_new_data_init(&source_output_data
);
585 source_output_data
.driver
= __FILE__
;
586 source_output_data
.module
= m
;
587 pa_source_output_new_data_set_source(&source_output_data
, master
, FALSE
);
588 source_output_data
.destination_source
= u
->source
;
590 pa_proplist_setf(source_output_data
.proplist
, PA_PROP_MEDIA_NAME
, "Virtual Source Stream of %s", pa_proplist_gets(u
->source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
));
591 pa_proplist_sets(source_output_data
.proplist
, PA_PROP_MEDIA_ROLE
, "filter");
592 pa_source_output_new_data_set_sample_spec(&source_output_data
, &ss
);
593 pa_source_output_new_data_set_channel_map(&source_output_data
, &map
);
595 pa_source_output_new(&u
->source_output
, m
->core
, &source_output_data
);
596 pa_source_output_new_data_done(&source_output_data
);
598 if (!u
->source_output
)
601 u
->source_output
->push
= source_output_push_cb
;
602 u
->source_output
->process_rewind
= source_output_process_rewind_cb
;
603 u
->source_output
->kill
= source_output_kill_cb
;
604 u
->source_output
->attach
= source_output_attach_cb
;
605 u
->source_output
->detach
= source_output_detach_cb
;
606 u
->source_output
->state_change
= source_output_state_change_cb
;
607 u
->source_output
->moving
= source_output_moving_cb
;
608 u
->source_output
->userdata
= u
;
610 u
->source
->output_from_master
= u
->source_output
;
612 pa_source_put(u
->source
);
613 pa_source_output_put(u
->source_output
);
615 /* Create optional uplink sink */
616 pa_sink_new_data_init(&sink_data
);
617 sink_data
.driver
= __FILE__
;
618 sink_data
.module
= m
;
619 if ((sink_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "uplink_sink", NULL
)))) {
620 pa_sink_new_data_set_sample_spec(&sink_data
, &ss
);
621 pa_sink_new_data_set_channel_map(&sink_data
, &map
);
622 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
623 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_CLASS
, "uplink sink");
624 pa_proplist_sets(sink_data
.proplist
, "device.uplink_sink.name", sink_data
.name
);
626 if ((u
->auto_desc
= !pa_proplist_contains(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
))) {
629 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
630 pa_proplist_setf(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Uplink Sink %s on %s", sink_data
.name
, z
? z
: master
->name
);
633 u
->sink_memblockq
= pa_memblockq_new("module-virtual-source sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH
, 0, &ss
, 1, 1, 0, NULL
);
634 if (!u
->sink_memblockq
) {
635 pa_sink_new_data_done(&sink_data
);
636 pa_log("Failed to create sink memblockq.");
640 u
->sink
= pa_sink_new(m
->core
, &sink_data
, 0); /* FIXME, sink has no capabilities */
641 pa_sink_new_data_done(&sink_data
);
644 pa_log("Failed to create sink.");
648 u
->sink
->parent
.process_msg
= sink_process_msg_cb
;
649 u
->sink
->update_requested_latency
= sink_update_requested_latency_cb
;
650 u
->sink
->request_rewind
= sink_request_rewind_cb
;
651 u
->sink
->set_state
= sink_set_state_cb
;
652 u
->sink
->userdata
= u
;
654 pa_sink_set_asyncmsgq(u
->sink
, master
->asyncmsgq
);
656 /* FIXME: no idea what I am doing here */
657 u
->block_usec
= BLOCK_USEC
;
658 nbytes
= pa_usec_to_bytes(u
->block_usec
, &u
->sink
->sample_spec
);
659 pa_sink_set_max_rewind(u
->sink
, nbytes
);
660 pa_sink_set_max_request(u
->sink
, nbytes
);
662 pa_sink_put(u
->sink
);
664 pa_sink_new_data_done(&sink_data
);
665 /* optional uplink sink not enabled */
682 int pa__get_n_used(pa_module
*m
) {
686 pa_assert_se(u
= m
->userdata
);
688 return pa_source_linked_by(u
->source
);
691 void pa__done(pa_module
*m
) {
696 if (!(u
= m
->userdata
))
699 /* See comments in source_output_kill_cb() above regarding
700 * destruction order! */
702 if (u
->source_output
)
703 pa_source_output_unlink(u
->source_output
);
706 pa_source_unlink(u
->source
);
708 if (u
->source_output
)
709 pa_source_output_unref(u
->source_output
);
712 pa_source_unref(u
->source
);
715 pa_sink_unref(u
->sink
);
718 pa_memblockq_free(u
->memblockq
);
720 if (u
->sink_memblockq
)
721 pa_memblockq_free(u
->sink_memblockq
);