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 */
156 /* Called from I/O thread context */
157 static void sink_request_rewind_cb(pa_sink
*s
) {
160 pa_sink_assert_ref(s
);
161 pa_assert_se(u
= s
->userdata
);
164 pa_sink_process_rewind(u
->sink
, 0);
168 /* Called from I/O thread context */
169 static int source_process_msg_cb(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
170 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
174 case PA_SOURCE_MESSAGE_GET_LATENCY
:
176 /* The source is _put() before the source output is, so let's
177 * make sure we don't access it in that time. Also, the
178 * source output is first shut down, the source second. */
179 if (!PA_SOURCE_IS_LINKED(u
->source
->thread_info
.state
) ||
180 !PA_SOURCE_OUTPUT_IS_LINKED(u
->source_output
->thread_info
.state
)) {
181 *((pa_usec_t
*) data
) = 0;
185 *((pa_usec_t
*) data
) =
187 /* Get the latency of the master source */
188 pa_source_get_latency_within_thread(u
->source_output
->source
) +
190 /* Add the latency internal to our source output on top */
191 /* FIXME, no idea what I am doing here */
192 pa_bytes_to_usec(pa_memblockq_get_length(u
->source_output
->thread_info
.delay_memblockq
), &u
->source_output
->source
->sample_spec
);
197 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
200 /* Called from main context */
201 static int source_set_state_cb(pa_source
*s
, pa_source_state_t state
) {
204 pa_source_assert_ref(s
);
205 pa_assert_se(u
= s
->userdata
);
207 if (!PA_SOURCE_IS_LINKED(state
) ||
208 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
)))
211 pa_source_output_cork(u
->source_output
, state
== PA_SOURCE_SUSPENDED
);
215 /* Called from I/O thread context */
216 static void source_update_requested_latency_cb(pa_source
*s
) {
219 pa_source_assert_ref(s
);
220 pa_assert_se(u
= s
->userdata
);
222 if (!PA_SOURCE_IS_LINKED(u
->source
->thread_info
.state
) ||
223 !PA_SOURCE_OUTPUT_IS_LINKED(u
->source_output
->thread_info
.state
))
226 /* Just hand this one over to the master source */
227 pa_source_output_set_requested_latency_within_thread(
229 pa_source_get_requested_latency_within_thread(s
));
232 /* Called from main context */
233 static void source_set_volume_cb(pa_source
*s
) {
236 pa_source_assert_ref(s
);
237 pa_assert_se(u
= s
->userdata
);
239 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s
)) ||
240 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
)))
243 pa_source_output_set_volume(u
->source_output
, &s
->real_volume
, s
->save_volume
, TRUE
);
246 /* Called from main context */
247 static void source_set_mute_cb(pa_source
*s
) {
250 pa_source_assert_ref(s
);
251 pa_assert_se(u
= s
->userdata
);
253 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s
)) ||
254 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
)))
257 pa_source_output_set_mute(u
->source_output
, s
->muted
, s
->save_muted
);
260 /* Called from input thread context */
261 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
264 pa_source_output_assert_ref(o
);
265 pa_source_output_assert_io_context(o
);
266 pa_assert_se(u
= o
->userdata
);
268 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
))) {
269 pa_log("push when no link?");
273 /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */
275 /* if uplink sink exists, pull data from there; simplify by using
276 same length as chunk provided by source */
277 if (u
->sink
&& (pa_sink_get_state(u
->sink
) == PA_SINK_RUNNING
)) {
279 size_t nbytes
= chunk
->length
;
280 pa_mix_info streams
[2];
281 pa_memchunk target_chunk
;
285 /* Hmm, process any rewind request that might be queued up */
286 pa_sink_process_rewind(u
->sink
, 0);
288 /* get data from the sink */
289 while (pa_memblockq_peek(u
->sink_memblockq
, &tchunk
) < 0) {
292 /* make sure we get nbytes from the sink with render_full,
293 otherwise we cannot mix with the uplink */
294 pa_sink_render_full(u
->sink
, nbytes
, &nchunk
);
295 pa_memblockq_push(u
->sink_memblockq
, &nchunk
);
296 pa_memblock_unref(nchunk
.memblock
);
298 pa_assert(tchunk
.length
== chunk
->length
);
300 /* move the read pointer for sink memblockq */
301 pa_memblockq_drop(u
->sink_memblockq
, tchunk
.length
);
303 /* allocate target chunk */
304 /* this could probably be done in-place, but having chunk as both
305 the input and output creates issues with reference counts */
306 target_chunk
.index
= 0;
307 target_chunk
.length
= chunk
->length
;
308 pa_assert(target_chunk
.length
== chunk
->length
);
310 target_chunk
.memblock
= pa_memblock_new(o
->source
->core
->mempool
,
311 target_chunk
.length
);
312 pa_assert( target_chunk
.memblock
);
314 /* get target pointer */
315 target
= pa_memblock_acquire_chunk(&target_chunk
);
317 /* set-up mixing structure
318 volume was taken care of in sink and source already */
319 streams
[0].chunk
= *chunk
;
320 for(ch
=0;ch
<o
->sample_spec
.channels
;ch
++)
321 streams
[0].volume
.values
[ch
] = PA_VOLUME_NORM
; /* FIXME */
322 streams
[0].volume
.channels
= o
->sample_spec
.channels
;
324 streams
[1].chunk
= tchunk
;
325 for(ch
=0;ch
<o
->sample_spec
.channels
;ch
++)
326 streams
[1].volume
.values
[ch
] = PA_VOLUME_NORM
; /* FIXME */
327 streams
[1].volume
.channels
= o
->sample_spec
.channels
;
330 pa_mix(streams
, /* 2 streams to be mixed */
332 target
, /* put result in target chunk */
333 chunk
->length
, /* same length as input */
334 (const pa_sample_spec
*)&o
->sample_spec
, /* same sample spec for input and output */
335 NULL
, /* no volume information */
336 FALSE
); /* no mute */
338 pa_memblock_release(target_chunk
.memblock
);
339 pa_memblock_unref(tchunk
.memblock
); /* clean-up */
341 /* forward the data to the virtual source */
342 pa_source_post(u
->source
, &target_chunk
);
344 pa_memblock_unref(target_chunk
.memblock
); /* clean-up */
347 /* forward the data to the virtual source */
348 pa_source_post(u
->source
, chunk
);
353 /* Called from input thread context */
354 static void source_output_process_rewind_cb(pa_source_output
*o
, size_t nbytes
) {
357 pa_source_output_assert_ref(o
);
358 pa_source_output_assert_io_context(o
);
359 pa_assert_se(u
= o
->userdata
);
361 /* FIXME, no idea what I am doing here */
363 pa_asyncmsgq_post(u
->asyncmsgq
, PA_MSGOBJECT(u
->sink_input
), SINK_INPUT_MESSAGE_REWIND
, NULL
, (int64_t) nbytes
, NULL
, NULL
);
364 u
->send_counter
-= (int64_t) nbytes
;
368 /* Called from output thread context */
369 static void source_output_attach_cb(pa_source_output
*o
) {
372 pa_source_output_assert_ref(o
);
373 pa_source_output_assert_io_context(o
);
374 pa_assert_se(u
= o
->userdata
);
376 pa_source_set_rtpoll(u
->source
, o
->source
->thread_info
.rtpoll
);
377 pa_source_set_latency_range_within_thread(u
->source
, o
->source
->thread_info
.min_latency
, o
->source
->thread_info
.max_latency
);
378 pa_source_set_fixed_latency_within_thread(u
->source
, o
->source
->thread_info
.fixed_latency
);
379 pa_source_set_max_rewind_within_thread(u
->source
, pa_source_output_get_max_rewind(o
));
381 pa_source_attach_within_thread(u
->source
);
384 /* Called from output thread context */
385 static void source_output_detach_cb(pa_source_output
*o
) {
388 pa_source_output_assert_ref(o
);
389 pa_source_output_assert_io_context(o
);
390 pa_assert_se(u
= o
->userdata
);
392 pa_source_detach_within_thread(u
->source
);
393 pa_source_set_rtpoll(u
->source
, NULL
);
396 /* Called from output thread context */
397 static void source_output_state_change_cb(pa_source_output
*o
, pa_source_output_state_t state
) {
400 pa_source_output_assert_ref(o
);
401 pa_source_output_assert_io_context(o
);
402 pa_assert_se(u
= o
->userdata
);
406 if (PA_SOURCE_OUTPUT_IS_LINKED(state
) && o
->thread_info
.state
== PA_SOURCE_OUTPUT_INIT
) {
408 u
->skip
= pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o
->source
),
412 pa_log_info("Skipping %lu bytes", (unsigned long) u
->skip
);
417 /* Called from main thread */
418 static void source_output_kill_cb(pa_source_output
*o
) {
421 pa_source_output_assert_ref(o
);
422 pa_assert_ctl_context();
423 pa_assert_se(u
= o
->userdata
);
425 /* The order here matters! We first kill the source output, followed
426 * by the source. That means the source callbacks must be protected
427 * against an unconnected source output! */
428 pa_source_output_unlink(u
->source_output
);
429 pa_source_unlink(u
->source
);
431 pa_source_output_unref(u
->source_output
);
432 u
->source_output
= NULL
;
434 pa_source_unref(u
->source
);
437 pa_module_unload_request(u
->module
, TRUE
);
440 /* Called from main thread */
441 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
444 pa_source_output_assert_ref(o
);
445 pa_assert_ctl_context();
446 pa_assert_se(u
= o
->userdata
);
449 pa_source_set_asyncmsgq(u
->source
, dest
->asyncmsgq
);
450 pa_source_update_flags(u
->source
, PA_SOURCE_LATENCY
|PA_SOURCE_DYNAMIC_LATENCY
, dest
->flags
);
452 pa_source_set_asyncmsgq(u
->source
, NULL
);
454 if (u
->auto_desc
&& dest
) {
458 pl
= pa_proplist_new();
459 z
= pa_proplist_gets(dest
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
460 pa_proplist_setf(pl
, PA_PROP_DEVICE_DESCRIPTION
, "Virtual Source %s on %s",
461 pa_proplist_gets(u
->source
->proplist
, "device.vsource.name"), z
? z
: dest
->name
);
463 pa_source_update_proplist(u
->source
, PA_UPDATE_REPLACE
, pl
);
464 pa_proplist_free(pl
);
468 int pa__init(pa_module
*m
) {
473 pa_source
*master
=NULL
;
474 pa_source_output_new_data source_output_data
;
475 pa_source_new_data source_data
;
476 pa_bool_t use_volume_sharing
= TRUE
;
477 pa_bool_t force_flat_volume
= FALSE
;
479 /* optional for uplink_sink */
480 pa_sink_new_data sink_data
;
485 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
486 pa_log("Failed to parse module arguments.");
490 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SOURCE
))) {
491 pa_log("Master source not found");
497 ss
= master
->sample_spec
;
498 ss
.format
= PA_SAMPLE_FLOAT32
;
499 map
= master
->channel_map
;
500 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
501 pa_log("Invalid sample format specification or channel map");
505 if (pa_modargs_get_value_boolean(ma
, "use_volume_sharing", &use_volume_sharing
) < 0) {
506 pa_log("use_volume_sharing= expects a boolean argument");
510 if (pa_modargs_get_value_boolean(ma
, "force_flat_volume", &force_flat_volume
) < 0) {
511 pa_log("force_flat_volume= expects a boolean argument");
515 if (use_volume_sharing
&& force_flat_volume
) {
516 pa_log("Flat volume can't be forced when using volume sharing.");
520 u
= pa_xnew0(struct userdata
, 1);
523 u
->memblockq
= pa_memblockq_new("module-virtual-source memblockq", 0, MEMBLOCKQ_MAXLENGTH
, 0, &ss
, 1, 1, 0, NULL
);
525 pa_log("Failed to create source memblockq.");
528 u
->channels
= ss
.channels
;
531 pa_source_new_data_init(&source_data
);
532 source_data
.driver
= __FILE__
;
533 source_data
.module
= m
;
534 if (!(source_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "source_name", NULL
))))
535 source_data
.name
= pa_sprintf_malloc("%s.vsource", master
->name
);
536 pa_source_new_data_set_sample_spec(&source_data
, &ss
);
537 pa_source_new_data_set_channel_map(&source_data
, &map
);
538 pa_proplist_sets(source_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
539 pa_proplist_sets(source_data
.proplist
, PA_PROP_DEVICE_CLASS
, "filter");
540 pa_proplist_sets(source_data
.proplist
, "device.vsource.name", source_data
.name
);
542 if (pa_modargs_get_proplist(ma
, "source_properties", source_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
543 pa_log("Invalid properties");
544 pa_source_new_data_done(&source_data
);
548 if ((u
->auto_desc
= !pa_proplist_contains(source_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
))) {
551 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
552 pa_proplist_setf(source_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Virtual Source %s on %s", source_data
.name
, z
? z
: master
->name
);
555 u
->source
= pa_source_new(m
->core
, &source_data
, (master
->flags
& (PA_SOURCE_LATENCY
|PA_SOURCE_DYNAMIC_LATENCY
))
556 | (use_volume_sharing
? PA_SOURCE_SHARE_VOLUME_WITH_MASTER
: 0));
558 pa_source_new_data_done(&source_data
);
561 pa_log("Failed to create source.");
565 u
->source
->parent
.process_msg
= source_process_msg_cb
;
566 u
->source
->set_state
= source_set_state_cb
;
567 u
->source
->update_requested_latency
= source_update_requested_latency_cb
;
568 pa_source_set_set_mute_callback(u
->source
, source_set_mute_cb
);
569 if (!use_volume_sharing
) {
570 pa_source_set_set_volume_callback(u
->source
, source_set_volume_cb
);
571 pa_source_enable_decibel_volume(u
->source
, TRUE
);
573 /* Normally this flag would be enabled automatically be we can force it. */
574 if (force_flat_volume
)
575 u
->source
->flags
|= PA_SOURCE_FLAT_VOLUME
;
576 u
->source
->userdata
= u
;
578 pa_source_set_asyncmsgq(u
->source
, master
->asyncmsgq
);
580 /* Create source output */
581 pa_source_output_new_data_init(&source_output_data
);
582 source_output_data
.driver
= __FILE__
;
583 source_output_data
.module
= m
;
584 pa_source_output_new_data_set_source(&source_output_data
, master
, FALSE
);
585 source_output_data
.destination_source
= u
->source
;
587 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
));
588 pa_proplist_sets(source_output_data
.proplist
, PA_PROP_MEDIA_ROLE
, "filter");
589 pa_source_output_new_data_set_sample_spec(&source_output_data
, &ss
);
590 pa_source_output_new_data_set_channel_map(&source_output_data
, &map
);
592 pa_source_output_new(&u
->source_output
, m
->core
, &source_output_data
);
593 pa_source_output_new_data_done(&source_output_data
);
595 if (!u
->source_output
)
598 u
->source_output
->push
= source_output_push_cb
;
599 u
->source_output
->process_rewind
= source_output_process_rewind_cb
;
600 u
->source_output
->kill
= source_output_kill_cb
;
601 u
->source_output
->attach
= source_output_attach_cb
;
602 u
->source_output
->detach
= source_output_detach_cb
;
603 u
->source_output
->state_change
= source_output_state_change_cb
;
604 u
->source_output
->moving
= source_output_moving_cb
;
605 u
->source_output
->userdata
= u
;
607 u
->source
->output_from_master
= u
->source_output
;
609 pa_source_put(u
->source
);
610 pa_source_output_put(u
->source_output
);
612 /* Create optional uplink sink */
613 pa_sink_new_data_init(&sink_data
);
614 sink_data
.driver
= __FILE__
;
615 sink_data
.module
= m
;
616 if ((sink_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "uplink_sink", NULL
)))) {
617 pa_sink_new_data_set_sample_spec(&sink_data
, &ss
);
618 pa_sink_new_data_set_channel_map(&sink_data
, &map
);
619 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
620 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_CLASS
, "uplink sink");
621 pa_proplist_sets(sink_data
.proplist
, "device.uplink_sink.name", sink_data
.name
);
623 if ((u
->auto_desc
= !pa_proplist_contains(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
))) {
626 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
627 pa_proplist_setf(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Uplink Sink %s on %s", sink_data
.name
, z
? z
: master
->name
);
630 u
->sink_memblockq
= pa_memblockq_new("module-virtual-source sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH
, 0, &ss
, 1, 1, 0, NULL
);
631 if (!u
->sink_memblockq
) {
632 pa_sink_new_data_done(&sink_data
);
633 pa_log("Failed to create sink memblockq.");
637 u
->sink
= pa_sink_new(m
->core
, &sink_data
, 0); /* FIXME, sink has no capabilities */
638 pa_sink_new_data_done(&sink_data
);
641 pa_log("Failed to create sink.");
645 u
->sink
->parent
.process_msg
= sink_process_msg_cb
;
646 u
->sink
->update_requested_latency
= sink_update_requested_latency_cb
;
647 u
->sink
->request_rewind
= sink_request_rewind_cb
;
648 u
->sink
->set_state
= sink_set_state_cb
;
649 u
->sink
->userdata
= u
;
651 pa_sink_set_asyncmsgq(u
->sink
, master
->asyncmsgq
);
653 /* FIXME: no idea what I am doing here */
654 u
->block_usec
= BLOCK_USEC
;
655 nbytes
= pa_usec_to_bytes(u
->block_usec
, &u
->sink
->sample_spec
);
656 pa_sink_set_max_rewind(u
->sink
, nbytes
);
657 pa_sink_set_max_request(u
->sink
, nbytes
);
659 pa_sink_put(u
->sink
);
661 pa_sink_new_data_done(&sink_data
);
662 /* optional uplink sink not enabled */
679 int pa__get_n_used(pa_module
*m
) {
683 pa_assert_se(u
= m
->userdata
);
685 return pa_source_linked_by(u
->source
);
688 void pa__done(pa_module
*m
) {
693 if (!(u
= m
->userdata
))
696 /* See comments in source_output_kill_cb() above regarding
697 * destruction order! */
699 if (u
->source_output
)
700 pa_source_output_unlink(u
->source_output
);
703 pa_source_unlink(u
->source
);
705 if (u
->source_output
)
706 pa_source_output_unref(u
->source_output
);
709 pa_source_unref(u
->source
);
712 pa_sink_unref(u
->sink
);
715 pa_memblockq_free(u
->memblockq
);
717 if (u
->sink_memblockq
)
718 pa_memblockq_free(u
->sink_memblockq
);