1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2010 Intel Corporation
5 Contributor: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
6
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.
11
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.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26
27 #include <pulse/xmalloc.h>
28
29 #include <pulsecore/i18n.h>
30 #include <pulsecore/macro.h>
31 #include <pulsecore/namereg.h>
32 #include <pulsecore/sink.h>
33 #include <pulsecore/module.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/modargs.h>
36 #include <pulsecore/log.h>
37 #include <pulsecore/rtpoll.h>
38 #include <pulsecore/sample-util.h>
39 #include <pulsecore/ltdl-helper.h>
40 #include <pulsecore/mix.h>
41 #include <pulsecore/rtpoll.h>
42
43 PA_MODULE_AUTHOR("Pierre-Louis Bossart");
44 PA_MODULE_DESCRIPTION("Virtual source");
45 PA_MODULE_VERSION(PACKAGE_VERSION);
46 PA_MODULE_LOAD_ONCE(false);
47 PA_MODULE_USAGE(
48 _("source_name=<name for the source> "
49 "source_properties=<properties for the source> "
50 "master=<name of source to filter> "
51 "uplink_sink=<name> (optional)"
52 "format=<sample format> "
53 "rate=<sample rate> "
54 "channels=<number of channels> "
55 "channel_map=<channel map> "
56 "use_volume_sharing=<yes or no> "
57 "force_flat_volume=<yes or no> "
58 ));
59
60 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
61 #define BLOCK_USEC 1000 /* FIXME */
62
63 struct userdata {
64 pa_module *module;
65
66 /* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */
67 /* bool autoloaded; */
68
69 pa_source *source;
70 pa_source_output *source_output;
71
72 pa_memblockq *memblockq;
73
74 bool auto_desc;
75 unsigned channels;
76
77 /* optional fields for uplink sink */
78 pa_sink *sink;
79 pa_usec_t block_usec;
80 pa_memblockq *sink_memblockq;
81 pa_rtpoll *rtpoll;
82
83 };
84
85 static const char* const valid_modargs[] = {
86 "source_name",
87 "source_properties",
88 "master",
89 "uplink_sink",
90 "format",
91 "rate",
92 "channels",
93 "channel_map",
94 "use_volume_sharing",
95 "force_flat_volume",
96 NULL
97 };
98
99 /* Called from I/O thread context */
sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk)100 static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
101
102 switch (code) {
103
104 case PA_SINK_MESSAGE_GET_LATENCY:
105
106 /* there's no real latency here */
107 *((int64_t*) data) = 0;
108
109 return 0;
110 }
111
112 return pa_sink_process_msg(o, code, data, offset, chunk);
113 }
114
115 /* Called from main context */
sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause)116 static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause) {
117 struct userdata *u;
118
119 pa_sink_assert_ref(s);
120 pa_assert_se(u = s->userdata);
121
122 if (!PA_SINK_IS_LINKED(state)) {
123 return 0;
124 }
125
126 if (state == PA_SINK_RUNNING) {
127 /* need to wake-up source if it was suspended */
128 pa_log_debug("Resuming source %s, because its uplink sink became active.", u->source->name);
129 pa_source_suspend(u->source, false, PA_SUSPEND_ALL);
130
131 /* FIXME: if there's no client connected, the source will suspend
132 and playback will be stuck. You'd want to prevent the source from
133 sleeping when the uplink sink is active; even if the audio is
134 discarded at least the app isn't stuck */
135
136 } else {
137 /* nothing to do, if the sink becomes idle or suspended let
138 module-suspend-idle handle the sources later */
139 }
140
141 return 0;
142 }
143
sink_update_requested_latency_cb(pa_sink *s)144 static void sink_update_requested_latency_cb(pa_sink *s) {
145 struct userdata *u;
146
147 pa_sink_assert_ref(s);
148 pa_assert_se(u = s->userdata);
149
150 /* FIXME: there's no latency support */
151
152 }
153
154 /* Called from I/O thread context */
source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk)155 static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
156 struct userdata *u = PA_SOURCE(o)->userdata;
157
158 switch (code) {
159
160 case PA_SOURCE_MESSAGE_GET_LATENCY:
161
162 /* The source is _put() before the source output is, so let's
163 * make sure we don't access it in that time. Also, the
164 * source output is first shut down, the source second. */
165 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
166 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) {
167 *((pa_usec_t*) data) = 0;
168 return 0;
169 }
170
171 *((pa_usec_t*) data) =
172
173 /* Get the latency of the master source */
174 pa_source_get_latency_within_thread(u->source_output->source, true) +
175
176 /* Add the latency internal to our source output on top */
177 /* FIXME, no idea what I am doing here */
178 pa_bytes_to_usec(pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq), &u->source_output->source->sample_spec);
179
180 /* Add resampler delay */
181 *((int64_t*) data) += pa_resampler_get_delay_usec(u->source_output->thread_info.resampler);
182
183 return 0;
184 }
185
186 return pa_source_process_msg(o, code, data, offset, chunk);
187 }
188
189 /* Called from main context */
source_set_state_in_main_thread_cb(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause)190 static int source_set_state_in_main_thread_cb(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause) {
191 struct userdata *u;
192
193 pa_source_assert_ref(s);
194 pa_assert_se(u = s->userdata);
195
196 if (!PA_SOURCE_IS_LINKED(state) ||
197 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state))
198 return 0;
199
200 pa_source_output_cork(u->source_output, state == PA_SOURCE_SUSPENDED);
201 return 0;
202 }
203
204 /* Called from I/O thread context */
source_update_requested_latency_cb(pa_source *s)205 static void source_update_requested_latency_cb(pa_source *s) {
206 struct userdata *u;
207
208 pa_source_assert_ref(s);
209 pa_assert_se(u = s->userdata);
210
211 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
212 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
213 return;
214
215 /* Just hand this one over to the master source */
216 pa_source_output_set_requested_latency_within_thread(
217 u->source_output,
218 pa_source_get_requested_latency_within_thread(s));
219 }
220
221 /* Called from main context */
source_set_volume_cb(pa_source *s)222 static void source_set_volume_cb(pa_source *s) {
223 struct userdata *u;
224
225 pa_source_assert_ref(s);
226 pa_assert_se(u = s->userdata);
227
228 if (!PA_SOURCE_IS_LINKED(s->state) ||
229 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state))
230 return;
231
232 pa_source_output_set_volume(u->source_output, &s->real_volume, s->save_volume, true);
233 }
234
235 /* Called from main context */
source_set_mute_cb(pa_source *s)236 static void source_set_mute_cb(pa_source *s) {
237 struct userdata *u;
238
239 pa_source_assert_ref(s);
240 pa_assert_se(u = s->userdata);
241
242 if (!PA_SOURCE_IS_LINKED(s->state) ||
243 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state))
244 return;
245
246 pa_source_output_set_mute(u->source_output, s->muted, s->save_muted);
247 }
248
249 /* Called from input thread context */
source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk)250 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
251 struct userdata *u;
252
253 pa_source_output_assert_ref(o);
254 pa_source_output_assert_io_context(o);
255 pa_assert_se(u = o->userdata);
256
257 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state))
258 return;
259
260 if (!PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) {
261 pa_log("push when no link?");
262 return;
263 }
264
265 /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */
266
267 /* if uplink sink exists, pull data from there; simplify by using
268 same length as chunk provided by source */
269 if (u->sink && (u->sink->thread_info.state == PA_SINK_RUNNING)) {
270 pa_memchunk tchunk;
271 size_t nbytes = chunk->length;
272 pa_mix_info streams[2];
273 pa_memchunk target_chunk;
274 void *target;
275 int ch;
276
277 /* Hmm, process any rewind request that might be queued up */
278 pa_sink_process_rewind(u->sink, 0);
279
280 /* get data from the sink */
281 while (pa_memblockq_peek(u->sink_memblockq, &tchunk) < 0) {
282 pa_memchunk nchunk;
283
284 /* make sure we get nbytes from the sink with render_full,
285 otherwise we cannot mix with the uplink */
286 pa_sink_render_full(u->sink, nbytes, &nchunk);
287 pa_memblockq_push(u->sink_memblockq, &nchunk);
288 pa_memblock_unref(nchunk.memblock);
289 }
290 pa_assert(tchunk.length == chunk->length);
291
292 /* move the read pointer for sink memblockq */
293 pa_memblockq_drop(u->sink_memblockq, tchunk.length);
294
295 /* allocate target chunk */
296 /* this could probably be done in-place, but having chunk as both
297 the input and output creates issues with reference counts */
298 target_chunk.index = 0;
299 target_chunk.length = chunk->length;
300 pa_assert(target_chunk.length == chunk->length);
301
302 target_chunk.memblock = pa_memblock_new(o->source->core->mempool,
303 target_chunk.length);
304 pa_assert( target_chunk.memblock );
305
306 /* get target pointer */
307 target = pa_memblock_acquire_chunk(&target_chunk);
308
309 /* set-up mixing structure
310 volume was taken care of in sink and source already */
311 streams[0].chunk = *chunk;
312 for(ch=0;ch<o->sample_spec.channels;ch++)
313 streams[0].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
314 streams[0].volume.channels = o->sample_spec.channels;
315
316 streams[1].chunk = tchunk;
317 for(ch=0;ch<o->sample_spec.channels;ch++)
318 streams[1].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
319 streams[1].volume.channels = o->sample_spec.channels;
320
321 /* do mixing */
322 pa_mix(streams, /* 2 streams to be mixed */
323 2,
324 target, /* put result in target chunk */
325 chunk->length, /* same length as input */
326 (const pa_sample_spec *)&o->sample_spec, /* same sample spec for input and output */
327 NULL, /* no volume information */
328 false); /* no mute */
329
330 pa_memblock_release(target_chunk.memblock);
331 pa_memblock_unref(tchunk.memblock); /* clean-up */
332
333 /* forward the data to the virtual source */
334 pa_source_post(u->source, &target_chunk);
335
336 pa_memblock_unref(target_chunk.memblock); /* clean-up */
337
338 } else {
339 /* forward the data to the virtual source */
340 pa_source_post(u->source, chunk);
341 }
342
343 }
344
345 /* Called from input thread context */
source_output_process_rewind_cb(pa_source_output *o, size_t nbytes)346 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
347 struct userdata *u;
348
349 pa_source_output_assert_ref(o);
350 pa_source_output_assert_io_context(o);
351 pa_assert_se(u = o->userdata);
352
353 /* If the source is not yet linked, there is nothing to rewind */
354 if (PA_SOURCE_IS_LINKED(u->source->thread_info.state))
355 pa_source_process_rewind(u->source, nbytes);
356
357 /* FIXME, no idea what I am doing here */
358 #if 0
359 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
360 u->send_counter -= (int64_t) nbytes;
361 #endif
362 }
363
364 /* Called from output thread context */
source_output_update_max_rewind_cb(pa_source_output *o, size_t nbytes)365 static void source_output_update_max_rewind_cb(pa_source_output *o, size_t nbytes) {
366 struct userdata *u;
367
368 pa_source_output_assert_ref(o);
369 pa_source_output_assert_io_context(o);
370 pa_assert_se(u = o->userdata);
371
372 pa_source_set_max_rewind_within_thread(u->source, nbytes);
373 }
374
375 /* Called from output thread context */
source_output_attach_cb(pa_source_output *o)376 static void source_output_attach_cb(pa_source_output *o) {
377 struct userdata *u;
378
379 pa_source_output_assert_ref(o);
380 pa_source_output_assert_io_context(o);
381 pa_assert_se(u = o->userdata);
382
383 pa_source_set_rtpoll(u->source, o->source->thread_info.rtpoll);
384 pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
385 pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency);
386 pa_source_set_max_rewind_within_thread(u->source, pa_source_output_get_max_rewind(o));
387
388 if (PA_SOURCE_IS_LINKED(u->source->thread_info.state))
389 pa_source_attach_within_thread(u->source);
390 }
391
392 /* Called from output thread context */
source_output_detach_cb(pa_source_output *o)393 static void source_output_detach_cb(pa_source_output *o) {
394 struct userdata *u;
395
396 pa_source_output_assert_ref(o);
397 pa_source_output_assert_io_context(o);
398 pa_assert_se(u = o->userdata);
399
400 if (PA_SOURCE_IS_LINKED(u->source->thread_info.state))
401 pa_source_detach_within_thread(u->source);
402 pa_source_set_rtpoll(u->source, NULL);
403 }
404
405 /* Called from output thread context except when cork() is called without valid source.*/
source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state)406 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
407 struct userdata *u;
408
409 pa_source_output_assert_ref(o);
410 pa_assert_se(u = o->userdata);
411
412 /* FIXME */
413 #if 0
414 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT && o->source) {
415
416 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source, false),
417 u->latency),
418 &o->sample_spec);
419
420 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
421 }
422 #endif
423 }
424
425 /* Called from main thread */
source_output_kill_cb(pa_source_output *o)426 static void source_output_kill_cb(pa_source_output *o) {
427 struct userdata *u;
428
429 pa_source_output_assert_ref(o);
430 pa_assert_ctl_context();
431 pa_assert_se(u = o->userdata);
432
433 /* The order here matters! We first kill the source so that streams
434 * can properly be moved away while the source output is still connected
435 * to the master. */
436 pa_source_output_cork(u->source_output, true);
437 pa_source_unlink(u->source);
438 pa_source_output_unlink(u->source_output);
439
440 pa_source_output_unref(u->source_output);
441 u->source_output = NULL;
442
443 pa_source_unref(u->source);
444 u->source = NULL;
445
446 pa_module_unload_request(u->module, true);
447 }
448
449 /* Called from main thread */
source_output_moving_cb(pa_source_output *o, pa_source *dest)450 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
451 struct userdata *u;
452 uint32_t idx;
453 pa_source_output *output;
454
455 pa_source_output_assert_ref(o);
456 pa_assert_ctl_context();
457 pa_assert_se(u = o->userdata);
458
459 if (dest) {
460 pa_source_set_asyncmsgq(u->source, dest->asyncmsgq);
461 pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags);
462 } else
463 pa_source_set_asyncmsgq(u->source, NULL);
464
465 /* Propagate asyncmsq change to attached virtual sources */
466 PA_IDXSET_FOREACH(output, u->source->outputs, idx) {
467 if (output->destination_source && output->moving)
468 output->moving(output, u->source);
469 }
470
471 if (u->auto_desc && dest) {
472 const char *z;
473 pa_proplist *pl;
474
475 pl = pa_proplist_new();
476 z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
477 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s",
478 pa_proplist_gets(u->source->proplist, "device.vsource.name"), z ? z : dest->name);
479
480 pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
481 pa_proplist_free(pl);
482 }
483 }
484
pa__init(pa_module*m)485 int pa__init(pa_module*m) {
486 struct userdata *u;
487 pa_sample_spec ss;
488 pa_channel_map map;
489 pa_modargs *ma;
490 pa_source *master=NULL;
491 pa_source_output_new_data source_output_data;
492 pa_source_new_data source_data;
493 bool use_volume_sharing = true;
494 bool force_flat_volume = false;
495
496 /* optional for uplink_sink */
497 pa_sink_new_data sink_data;
498 size_t nbytes;
499
500 pa_assert(m);
501
502 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
503 pa_log("Failed to parse module arguments.");
504 goto fail;
505 }
506
507 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) {
508 pa_log("Master source not found");
509 goto fail;
510 }
511
512 pa_assert(master);
513
514 ss = master->sample_spec;
515 ss.format = PA_SAMPLE_FLOAT32;
516 map = master->channel_map;
517 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
518 pa_log("Invalid sample format specification or channel map");
519 goto fail;
520 }
521
522 if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
523 pa_log("use_volume_sharing= expects a boolean argument");
524 goto fail;
525 }
526
527 if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) {
528 pa_log("force_flat_volume= expects a boolean argument");
529 goto fail;
530 }
531
532 if (use_volume_sharing && force_flat_volume) {
533 pa_log("Flat volume can't be forced when using volume sharing.");
534 goto fail;
535 }
536
537 u = pa_xnew0(struct userdata, 1);
538 u->module = m;
539 m->userdata = u;
540 u->memblockq = pa_memblockq_new("module-virtual-source memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
541 if (!u->memblockq) {
542 pa_log("Failed to create source memblockq.");
543 goto fail;
544 }
545 u->channels = ss.channels;
546
547 /* The rtpoll created here is never run. It is only necessary to avoid crashes
548 * when module-virtual-source is used together with module-loopback or
549 * module-combine-sink. Both modules base their asyncmsq on the rtpoll provided
550 * by the sink. module-loopback and combine-sink only work because they
551 * call pa_asyncmsq_process_one() themselves. */
552 u->rtpoll = pa_rtpoll_new();
553
554 /* Create source */
555 pa_source_new_data_init(&source_data);
556 source_data.driver = __FILE__;
557 source_data.module = m;
558 if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
559 source_data.name = pa_sprintf_malloc("%s.vsource", master->name);
560 pa_source_new_data_set_sample_spec(&source_data, &ss);
561 pa_source_new_data_set_channel_map(&source_data, &map);
562 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
563 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
564 pa_proplist_sets(source_data.proplist, "device.vsource.name", source_data.name);
565
566 if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
567 pa_log("Invalid properties");
568 pa_source_new_data_done(&source_data);
569 goto fail;
570 }
571
572 if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
573 const char *z;
574
575 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
576 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s", source_data.name, z ? z : master->name);
577 }
578
579 u->source = pa_source_new(m->core, &source_data, (master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY))
580 | (use_volume_sharing ? PA_SOURCE_SHARE_VOLUME_WITH_MASTER : 0));
581
582 pa_source_new_data_done(&source_data);
583
584 if (!u->source) {
585 pa_log("Failed to create source.");
586 goto fail;
587 }
588
589 u->source->parent.process_msg = source_process_msg_cb;
590 u->source->set_state_in_main_thread = source_set_state_in_main_thread_cb;
591 u->source->update_requested_latency = source_update_requested_latency_cb;
592 pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
593 if (!use_volume_sharing) {
594 pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
595 pa_source_enable_decibel_volume(u->source, true);
596 }
597 /* Normally this flag would be enabled automatically be we can force it. */
598 if (force_flat_volume)
599 u->source->flags |= PA_SOURCE_FLAT_VOLUME;
600 u->source->userdata = u;
601
602 pa_source_set_asyncmsgq(u->source, master->asyncmsgq);
603
604 /* Create source output */
605 pa_source_output_new_data_init(&source_output_data);
606 source_output_data.driver = __FILE__;
607 source_output_data.module = m;
608 pa_source_output_new_data_set_source(&source_output_data, master, false, true);
609 source_output_data.destination_source = u->source;
610
611 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));
612 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
613 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
614 pa_source_output_new_data_set_channel_map(&source_output_data, &map);
615 source_output_data.flags |= PA_SOURCE_OUTPUT_START_CORKED;
616
617 pa_source_output_new(&u->source_output, m->core, &source_output_data);
618 pa_source_output_new_data_done(&source_output_data);
619
620 if (!u->source_output)
621 goto fail;
622
623 u->source_output->push = source_output_push_cb;
624 u->source_output->process_rewind = source_output_process_rewind_cb;
625 u->source_output->update_max_rewind = source_output_update_max_rewind_cb;
626 u->source_output->kill = source_output_kill_cb;
627 u->source_output->attach = source_output_attach_cb;
628 u->source_output->detach = source_output_detach_cb;
629 u->source_output->state_change = source_output_state_change_cb;
630 u->source_output->moving = source_output_moving_cb;
631 u->source_output->userdata = u;
632
633 u->source->output_from_master = u->source_output;
634
635 /* The order here is important. The output must be put first,
636 * otherwise streams might attach to the source before the
637 * source output is attached to the master. */
638 pa_source_output_put(u->source_output);
639 pa_source_put(u->source);
640 pa_source_output_cork(u->source_output, false);
641
642 /* Create optional uplink sink */
643 pa_sink_new_data_init(&sink_data);
644 sink_data.driver = __FILE__;
645 sink_data.module = m;
646 if ((sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "uplink_sink", NULL)))) {
647 pa_sink_new_data_set_sample_spec(&sink_data, &ss);
648 pa_sink_new_data_set_channel_map(&sink_data, &map);
649 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
650 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "uplink sink");
651 pa_proplist_sets(sink_data.proplist, "device.uplink_sink.name", sink_data.name);
652
653 if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
654 const char *z;
655
656 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
657 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Uplink Sink %s on %s", sink_data.name, z ? z : master->name);
658 }
659
660 u->sink_memblockq = pa_memblockq_new("module-virtual-source sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
661 if (!u->sink_memblockq) {
662 pa_sink_new_data_done(&sink_data);
663 pa_log("Failed to create sink memblockq.");
664 goto fail;
665 }
666
667 u->sink = pa_sink_new(m->core, &sink_data, 0); /* FIXME, sink has no capabilities */
668 pa_sink_new_data_done(&sink_data);
669
670 if (!u->sink) {
671 pa_log("Failed to create sink.");
672 goto fail;
673 }
674
675 u->sink->parent.process_msg = sink_process_msg_cb;
676 u->sink->update_requested_latency = sink_update_requested_latency_cb;
677 u->sink->set_state_in_main_thread = sink_set_state_in_main_thread_cb;
678 u->sink->userdata = u;
679
680 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
681 pa_sink_set_rtpoll(u->sink, u->rtpoll);
682
683 /* FIXME: no idea what I am doing here */
684 u->block_usec = BLOCK_USEC;
685 nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
686 pa_sink_set_max_rewind(u->sink, 0);
687 pa_sink_set_max_request(u->sink, nbytes);
688
689 pa_sink_put(u->sink);
690 } else {
691 pa_sink_new_data_done(&sink_data);
692 /* optional uplink sink not enabled */
693 u->sink = NULL;
694 }
695
696 pa_modargs_free(ma);
697
698 return 0;
699
700 fail:
701 if (ma)
702 pa_modargs_free(ma);
703
704 pa__done(m);
705
706 return -1;
707 }
708
pa__get_n_used(pa_module *m)709 int pa__get_n_used(pa_module *m) {
710 struct userdata *u;
711
712 pa_assert(m);
713 pa_assert_se(u = m->userdata);
714
715 return pa_source_linked_by(u->source);
716 }
717
pa__done(pa_module*m)718 void pa__done(pa_module*m) {
719 struct userdata *u;
720
721 pa_assert(m);
722
723 if (!(u = m->userdata))
724 return;
725
726 /* See comments in source_output_kill_cb() above regarding
727 * destruction order! */
728
729 if (u->source_output)
730 pa_source_output_cork(u->source_output, true);
731
732 if (u->source)
733 pa_source_unlink(u->source);
734
735 if (u->source_output) {
736 pa_source_output_unlink(u->source_output);
737 pa_source_output_unref(u->source_output);
738 }
739
740 if (u->source)
741 pa_source_unref(u->source);
742
743 if (u->sink) {
744 pa_sink_unlink(u->sink);
745 pa_sink_unref(u->sink);
746 }
747
748 if (u->memblockq)
749 pa_memblockq_free(u->memblockq);
750
751 if (u->sink_memblockq)
752 pa_memblockq_free(u->sink_memblockq);
753
754 if (u->rtpoll)
755 pa_rtpoll_free(u->rtpoll);
756
757 pa_xfree(u);
758 }
759