]> code.delx.au - pulseaudio/blob - src/modules/module-virtual-source.c
bluetooth: Fix possible adapter duplicates
[pulseaudio] / src / modules / module-virtual-source.c
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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28
29 #include <pulse/xmalloc.h>
30
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>
43
44 #include "module-virtual-source-symdef.h"
45
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);
50 PA_MODULE_USAGE(
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> "
56 "rate=<sample rate> "
57 "channels=<number of channels> "
58 "channel_map=<channel map> "
59 "use_volume_sharing=<yes or no> "
60 "force_flat_volume=<yes or no> "
61 ));
62
63 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
64 #define BLOCK_USEC 1000 /* FIXME */
65
66 struct userdata {
67 pa_module *module;
68
69 /* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */
70 /* pa_bool_t autoloaded; */
71
72 pa_source *source;
73 pa_source_output *source_output;
74
75 pa_memblockq *memblockq;
76
77 pa_bool_t auto_desc;
78 unsigned channels;
79
80 /* optional fields for uplink sink */
81 pa_sink *sink;
82 pa_usec_t block_usec;
83 pa_memblockq *sink_memblockq;
84
85 };
86
87 static const char* const valid_modargs[] = {
88 "source_name",
89 "source_properties",
90 "master",
91 "uplink_sink",
92 "format",
93 "rate",
94 "channels",
95 "channel_map",
96 "use_volume_sharing",
97 "force_flat_volume",
98 NULL
99 };
100
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) {
103
104 switch (code) {
105
106 case PA_SINK_MESSAGE_GET_LATENCY:
107
108 /* there's no real latency here */
109 *((pa_usec_t*) data) = 0;
110
111 return 0;
112 }
113
114 return pa_sink_process_msg(o, code, data, offset, chunk);
115 }
116
117 /* Called from main context */
118 static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
119 struct userdata *u;
120
121 pa_sink_assert_ref(s);
122 pa_assert_se(u = s->userdata);
123
124 if (!PA_SINK_IS_LINKED(state)) {
125 return 0;
126 }
127
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);
132
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 */
137
138 } else {
139 /* nothing to do, if the sink becomes idle or suspended let
140 module-suspend-idle handle the sources later */
141 }
142
143 return 0;
144 }
145
146 static void sink_update_requested_latency_cb(pa_sink *s) {
147 struct userdata *u;
148
149 pa_sink_assert_ref(s);
150 pa_assert_se(u = s->userdata);
151
152 /* FIXME: there's no latency support */
153
154 }
155
156
157 /* Called from I/O thread context */
158 static void sink_request_rewind_cb(pa_sink *s) {
159 struct userdata *u;
160
161 pa_sink_assert_ref(s);
162 pa_assert_se(u = s->userdata);
163
164 /* Do nothing */
165 pa_sink_process_rewind(u->sink, 0);
166
167 }
168
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;
172
173 switch (code) {
174
175 case PA_SOURCE_MESSAGE_GET_LATENCY:
176
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;
183 return 0;
184 }
185
186 *((pa_usec_t*) data) =
187
188 /* Get the latency of the master source */
189 pa_source_get_latency_within_thread(u->source_output->source) +
190
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);
194
195 return 0;
196 }
197
198 return pa_source_process_msg(o, code, data, offset, chunk);
199 }
200
201 /* Called from main context */
202 static int source_set_state_cb(pa_source *s, pa_source_state_t state) {
203 struct userdata *u;
204
205 pa_source_assert_ref(s);
206 pa_assert_se(u = s->userdata);
207
208 if (!PA_SOURCE_IS_LINKED(state) ||
209 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
210 return 0;
211
212 pa_source_output_cork(u->source_output, state == PA_SOURCE_SUSPENDED);
213 return 0;
214 }
215
216 /* Called from I/O thread context */
217 static void source_update_requested_latency_cb(pa_source *s) {
218 struct userdata *u;
219
220 pa_source_assert_ref(s);
221 pa_assert_se(u = s->userdata);
222
223 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
224 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
225 return;
226
227 /* Just hand this one over to the master source */
228 pa_source_output_set_requested_latency_within_thread(
229 u->source_output,
230 pa_source_get_requested_latency_within_thread(s));
231 }
232
233 /* Called from main context */
234 static void source_set_volume_cb(pa_source *s) {
235 struct userdata *u;
236
237 pa_source_assert_ref(s);
238 pa_assert_se(u = s->userdata);
239
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)))
242 return;
243
244 pa_source_output_set_volume(u->source_output, &s->real_volume, s->save_volume, TRUE);
245 }
246
247 /* Called from main context */
248 static void source_set_mute_cb(pa_source *s) {
249 struct userdata *u;
250
251 pa_source_assert_ref(s);
252 pa_assert_se(u = s->userdata);
253
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)))
256 return;
257
258 pa_source_output_set_mute(u->source_output, s->muted, s->save_muted);
259 }
260
261 /* Called from input thread context */
262 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
263 struct userdata *u;
264
265 pa_source_output_assert_ref(o);
266 pa_source_output_assert_io_context(o);
267 pa_assert_se(u = o->userdata);
268
269 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output))) {
270 pa_log("push when no link?");
271 return;
272 }
273
274 /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */
275
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)) {
279 pa_memchunk tchunk;
280 size_t nbytes = chunk->length;
281 pa_mix_info streams[2];
282 pa_memchunk target_chunk;
283 void *target;
284 int ch;
285
286 /* Hmm, process any rewind request that might be queued up */
287 pa_sink_process_rewind(u->sink, 0);
288
289 /* get data from the sink */
290 while (pa_memblockq_peek(u->sink_memblockq, &tchunk) < 0) {
291 pa_memchunk nchunk;
292
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);
298 }
299 pa_assert(tchunk.length == chunk->length);
300
301 /* move the read pointer for sink memblockq */
302 pa_memblockq_drop(u->sink_memblockq, tchunk.length);
303
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);
310
311 target_chunk.memblock = pa_memblock_new(o->source->core->mempool,
312 target_chunk.length);
313 pa_assert( target_chunk.memblock );
314
315 /* get target pointer */
316 target = pa_memblock_acquire_chunk(&target_chunk);
317
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;
324
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;
329
330 /* do mixing */
331 pa_mix(streams, /* 2 streams to be mixed */
332 2,
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 */
338
339 pa_memblock_release(target_chunk.memblock);
340 pa_memblock_unref(tchunk.memblock); /* clean-up */
341
342 /* forward the data to the virtual source */
343 pa_source_post(u->source, &target_chunk);
344
345 pa_memblock_unref(target_chunk.memblock); /* clean-up */
346
347 } else {
348 /* forward the data to the virtual source */
349 pa_source_post(u->source, chunk);
350 }
351
352
353 }
354
355 /* Called from input thread context */
356 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
357 struct userdata *u;
358
359 pa_source_output_assert_ref(o);
360 pa_source_output_assert_io_context(o);
361 pa_assert_se(u = o->userdata);
362
363 /* FIXME, no idea what I am doing here */
364 #if 0
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;
367 #endif
368 }
369
370 /* Called from output thread context */
371 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
372
373 /* FIXME, nothing to do here ? */
374
375 return pa_source_output_process_msg(obj, code, data, offset, chunk);
376 }
377
378 /* Called from output thread context */
379 static void source_output_attach_cb(pa_source_output *o) {
380 struct userdata *u;
381
382 pa_source_output_assert_ref(o);
383 pa_source_output_assert_io_context(o);
384 pa_assert_se(u = o->userdata);
385
386 pa_source_set_rtpoll(u->source, o->source->thread_info.rtpoll);
387 pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
388 pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency);
389 pa_source_set_max_rewind_within_thread(u->source, pa_source_output_get_max_rewind(o));
390
391 pa_source_attach_within_thread(u->source);
392 }
393
394 /* Called from output thread context */
395 static void source_output_detach_cb(pa_source_output *o) {
396 struct userdata *u;
397
398 pa_source_output_assert_ref(o);
399 pa_source_output_assert_io_context(o);
400 pa_assert_se(u = o->userdata);
401
402 pa_source_detach_within_thread(u->source);
403 pa_source_set_rtpoll(u->source, NULL);
404 }
405
406 /* Called from output thread context */
407 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
408 struct userdata *u;
409
410 pa_source_output_assert_ref(o);
411 pa_source_output_assert_io_context(o);
412 pa_assert_se(u = o->userdata);
413
414 /* FIXME */
415 #if 0
416 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
417
418 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
419 u->latency),
420 &o->sample_spec);
421
422 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
423 }
424 #endif
425 }
426
427 /* Called from main thread */
428 static void source_output_kill_cb(pa_source_output *o) {
429 struct userdata *u;
430
431 pa_source_output_assert_ref(o);
432 pa_assert_ctl_context();
433 pa_assert_se(u = o->userdata);
434
435 /* The order here matters! We first kill the source output, followed
436 * by the source. That means the source callbacks must be protected
437 * against an unconnected source output! */
438 pa_source_output_unlink(u->source_output);
439 pa_source_unlink(u->source);
440
441 pa_source_output_unref(u->source_output);
442 u->source_output = NULL;
443
444 pa_source_unref(u->source);
445 u->source = NULL;
446
447 pa_module_unload_request(u->module, TRUE);
448 }
449
450 /* Called from main thread */
451 static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
452 struct userdata *u;
453
454 pa_source_output_assert_ref(o);
455 pa_assert_ctl_context();
456 pa_assert_se(u = o->userdata);
457
458 /* FIXME */
459 //return dest != u->source_input->source->monitor_source;
460
461 return TRUE;
462 }
463
464 /* Called from main thread */
465 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
466 struct userdata *u;
467
468 pa_source_output_assert_ref(o);
469 pa_assert_ctl_context();
470 pa_assert_se(u = o->userdata);
471
472 if (dest) {
473 pa_source_set_asyncmsgq(u->source, dest->asyncmsgq);
474 pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags);
475 } else
476 pa_source_set_asyncmsgq(u->source, NULL);
477
478 if (u->auto_desc && dest) {
479 const char *z;
480 pa_proplist *pl;
481
482 pl = pa_proplist_new();
483 z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
484 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s",
485 pa_proplist_gets(u->source->proplist, "device.vsource.name"), z ? z : dest->name);
486
487 pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
488 pa_proplist_free(pl);
489 }
490 }
491
492
493 int pa__init(pa_module*m) {
494 struct userdata *u;
495 pa_sample_spec ss;
496 pa_channel_map map;
497 pa_modargs *ma;
498 pa_source *master=NULL;
499 pa_source_output_new_data source_output_data;
500 pa_source_new_data source_data;
501 pa_bool_t use_volume_sharing = TRUE;
502 pa_bool_t force_flat_volume = FALSE;
503
504 /* optional for uplink_sink */
505 pa_sink_new_data sink_data;
506 size_t nbytes;
507
508 pa_assert(m);
509
510 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
511 pa_log("Failed to parse module arguments.");
512 goto fail;
513 }
514
515 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) {
516 pa_log("Master source not found");
517 goto fail;
518 }
519
520 pa_assert(master);
521
522 ss = master->sample_spec;
523 ss.format = PA_SAMPLE_FLOAT32;
524 map = master->channel_map;
525 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
526 pa_log("Invalid sample format specification or channel map");
527 goto fail;
528 }
529
530 if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
531 pa_log("use_volume_sharing= expects a boolean argument");
532 goto fail;
533 }
534
535 if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) {
536 pa_log("force_flat_volume= expects a boolean argument");
537 goto fail;
538 }
539
540 if (use_volume_sharing && force_flat_volume) {
541 pa_log("Flat volume can't be forced when using volume sharing.");
542 goto fail;
543 }
544
545 u = pa_xnew0(struct userdata, 1);
546 if (!u) {
547 pa_log("Failed to alloc userdata");
548 goto fail;
549 }
550 u->module = m;
551 m->userdata = u;
552 u->memblockq = pa_memblockq_new("module-virtual-source memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
553 if (!u->memblockq) {
554 pa_log("Failed to create source memblockq.");
555 goto fail;
556 }
557 u->channels = ss.channels;
558
559 /* Create source */
560 pa_source_new_data_init(&source_data);
561 source_data.driver = __FILE__;
562 source_data.module = m;
563 if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
564 source_data.name = pa_sprintf_malloc("%s.vsource", master->name);
565 pa_source_new_data_set_sample_spec(&source_data, &ss);
566 pa_source_new_data_set_channel_map(&source_data, &map);
567 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
568 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
569 pa_proplist_sets(source_data.proplist, "device.vsource.name", source_data.name);
570
571 if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
572 pa_log("Invalid properties");
573 pa_source_new_data_done(&source_data);
574 goto fail;
575 }
576
577 if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
578 const char *z;
579
580 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
581 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s", source_data.name, z ? z : master->name);
582 }
583
584 u->source = pa_source_new(m->core, &source_data, (master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY))
585 | (use_volume_sharing ? PA_SOURCE_SHARE_VOLUME_WITH_MASTER : 0));
586
587 pa_source_new_data_done(&source_data);
588
589 if (!u->source) {
590 pa_log("Failed to create source.");
591 goto fail;
592 }
593
594 u->source->parent.process_msg = source_process_msg_cb;
595 u->source->set_state = source_set_state_cb;
596 u->source->update_requested_latency = source_update_requested_latency_cb;
597 pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
598 if (!use_volume_sharing) {
599 pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
600 pa_source_enable_decibel_volume(u->source, TRUE);
601 }
602 /* Normally this flag would be enabled automatically be we can force it. */
603 if (force_flat_volume)
604 u->source->flags |= PA_SOURCE_FLAT_VOLUME;
605 u->source->userdata = u;
606
607 pa_source_set_asyncmsgq(u->source, master->asyncmsgq);
608
609 /* Create source output */
610 pa_source_output_new_data_init(&source_output_data);
611 source_output_data.driver = __FILE__;
612 source_output_data.module = m;
613 pa_source_output_new_data_set_source(&source_output_data, master, FALSE);
614 source_output_data.destination_source = u->source;
615 /* FIXME
616 source_output_data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; */
617
618 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));
619 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
620 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
621 pa_source_output_new_data_set_channel_map(&source_output_data, &map);
622
623 pa_source_output_new(&u->source_output, m->core, &source_output_data);
624 pa_source_output_new_data_done(&source_output_data);
625
626 if (!u->source_output)
627 goto fail;
628
629 u->source_output->parent.process_msg = source_output_process_msg_cb;
630 u->source_output->push = source_output_push_cb;
631 u->source_output->process_rewind = source_output_process_rewind_cb;
632 u->source_output->kill = source_output_kill_cb;
633 u->source_output->attach = source_output_attach_cb;
634 u->source_output->detach = source_output_detach_cb;
635 u->source_output->state_change = source_output_state_change_cb;
636 u->source_output->may_move_to = source_output_may_move_to_cb;
637 u->source_output->moving = source_output_moving_cb;
638 u->source_output->userdata = u;
639
640 u->source->output_from_master = u->source_output;
641
642 pa_source_put(u->source);
643 pa_source_output_put(u->source_output);
644
645 /* Create optional uplink sink */
646 pa_sink_new_data_init(&sink_data);
647 sink_data.driver = __FILE__;
648 sink_data.module = m;
649 if ((sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "uplink_sink", NULL)))) {
650 pa_sink_new_data_set_sample_spec(&sink_data, &ss);
651 pa_sink_new_data_set_channel_map(&sink_data, &map);
652 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
653 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "uplink sink");
654 pa_proplist_sets(sink_data.proplist, "device.uplink_sink.name", sink_data.name);
655
656 if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
657 const char *z;
658
659 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
660 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Uplink Sink %s on %s", sink_data.name, z ? z : master->name);
661 }
662
663 u->sink_memblockq = pa_memblockq_new("module-virtual-source sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
664 if (!u->sink_memblockq) {
665 pa_sink_new_data_done(&sink_data);
666 pa_log("Failed to create sink memblockq.");
667 goto fail;
668 }
669
670 u->sink = pa_sink_new(m->core, &sink_data, 0); /* FIXME, sink has no capabilities */
671 pa_sink_new_data_done(&sink_data);
672
673 if (!u->sink) {
674 pa_log("Failed to create sink.");
675 goto fail;
676 }
677
678 u->sink->parent.process_msg = sink_process_msg_cb;
679 u->sink->update_requested_latency = sink_update_requested_latency_cb;
680 u->sink->request_rewind = sink_request_rewind_cb;
681 u->sink->set_state = sink_set_state_cb;
682 u->sink->userdata = u;
683
684 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
685
686 /* FIXME: no idea what I am doing here */
687 u->block_usec = BLOCK_USEC;
688 nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
689 pa_sink_set_max_rewind(u->sink, nbytes);
690 pa_sink_set_max_request(u->sink, nbytes);
691
692 pa_sink_put(u->sink);
693 } else {
694 pa_sink_new_data_done(&sink_data);
695 /* optional uplink sink not enabled */
696 u->sink = NULL;
697 }
698
699 pa_modargs_free(ma);
700
701 return 0;
702
703 fail:
704 if (ma)
705 pa_modargs_free(ma);
706
707 pa__done(m);
708
709 return -1;
710 }
711
712 int pa__get_n_used(pa_module *m) {
713 struct userdata *u;
714
715 pa_assert(m);
716 pa_assert_se(u = m->userdata);
717
718 return pa_source_linked_by(u->source);
719 }
720
721 void pa__done(pa_module*m) {
722 struct userdata *u;
723
724 pa_assert(m);
725
726 if (!(u = m->userdata))
727 return;
728
729 /* See comments in source_output_kill_cb() above regarding
730 * destruction order! */
731
732 if (u->source_output)
733 pa_source_output_unlink(u->source_output);
734
735 if (u->source)
736 pa_source_unlink(u->source);
737
738 if (u->source_output)
739 pa_source_output_unref(u->source_output);
740
741 if (u->source)
742 pa_source_unref(u->source);
743
744 if (u->sink)
745 pa_sink_unref(u->sink);
746
747 if (u->memblockq)
748 pa_memblockq_free(u->memblockq);
749
750 if (u->sink_memblockq)
751 pa_memblockq_free(u->sink_memblockq);
752
753 pa_xfree(u);
754 }