]> code.delx.au - pulseaudio/blob - src/modules/module-virtual-source.c
835cf3ce1f92cdec48dbd59c1b2b73de645e33af
[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 #include <math.h>
29
30 #include <pulse/xmalloc.h>
31 #include <pulse/i18n.h>
32
33 #include <pulsecore/macro.h>
34 #include <pulsecore/core-error.h>
35 #include <pulsecore/namereg.h>
36 #include <pulsecore/sink.h>
37 #include <pulsecore/module.h>
38 #include <pulsecore/core-rtclock.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/core-error.h>
41 #include <pulsecore/modargs.h>
42 #include <pulsecore/log.h>
43 #include <pulsecore/thread.h>
44 #include <pulsecore/thread-mq.h>
45 #include <pulsecore/rtpoll.h>
46 #include <pulsecore/sample-util.h>
47 #include <pulsecore/ltdl-helper.h>
48
49 #include "module-virtual-source-symdef.h"
50
51 PA_MODULE_AUTHOR("Pierre-Louis Bossart");
52 PA_MODULE_DESCRIPTION("Virtual source");
53 PA_MODULE_VERSION(PACKAGE_VERSION);
54 PA_MODULE_LOAD_ONCE(FALSE);
55 PA_MODULE_USAGE(
56 _("source_name=<name for the source> "
57 "source_properties=<properties for the source> "
58 "master=<name of source to filter> "
59 "uplink_sink=<name> (optional)"
60 "format=<sample format> "
61 "rate=<sample rate> "
62 "channels=<number of channels> "
63 "channel_map=<channel map> "
64 ));
65
66 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
67 #define BLOCK_USEC 1000 /* FIXME */
68
69 struct userdata {
70 pa_module *module;
71
72 /* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */
73 /* pa_bool_t autoloaded; */
74
75 pa_source *source;
76 pa_source_output *source_output;
77
78 pa_memblockq *memblockq;
79
80 pa_bool_t auto_desc;
81 unsigned channels;
82
83 /* optional fields for uplink sink */
84 pa_sink *sink;
85 pa_usec_t block_usec;
86 pa_memblockq *sink_memblockq;
87
88 };
89
90 static const char* const valid_modargs[] = {
91 "source_name",
92 "source_properties",
93 "master",
94 "uplink_sink",
95 "format",
96 "rate",
97 "channels",
98 "channel_map",
99 NULL
100 };
101
102 /* Called from I/O thread context */
103 static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
104
105 switch (code) {
106
107 case PA_SINK_MESSAGE_GET_LATENCY:
108
109 /* there's no real latency here */
110 *((pa_usec_t*) data) = 0;
111
112 return 0;
113 }
114
115 return pa_sink_process_msg(o, code, data, offset, chunk);
116 }
117
118 /* Called from main context */
119 static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
120 struct userdata *u;
121
122 pa_sink_assert_ref(s);
123 pa_assert_se(u = s->userdata);
124
125 if (!PA_SINK_IS_LINKED(state)) {
126 return 0;
127 }
128
129 if (state == PA_SINK_RUNNING) {
130 /* need to wake-up source if it was suspended */
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 /* FIXME, no volume control in source_output, set volume at the master */
245 pa_source_set_volume(u->source_output->source, &s->volume, TRUE);
246 }
247
248 static void source_get_volume_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 /* FIXME, no volume control in source_output, get the info from the master */
259 pa_source_get_volume(u->source_output->source, TRUE);
260
261 if (pa_cvolume_equal(&s->volume,&u->source_output->source->volume))
262 /* no change */
263 return;
264
265 s->volume = u->source_output->source->volume;
266 pa_source_set_soft_volume(s, NULL);
267 }
268
269
270 /* Called from main context */
271 static void source_set_mute_cb(pa_source *s) {
272 struct userdata *u;
273
274 pa_source_assert_ref(s);
275 pa_assert_se(u = s->userdata);
276
277 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
278 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
279 return;
280
281 /* FIXME, no volume control in source_output, set mute at the master */
282 pa_source_set_mute(u->source_output->source, TRUE, TRUE);
283 }
284
285 /* Called from main context */
286 static void source_get_mute_cb(pa_source *s) {
287 struct userdata *u;
288
289 pa_source_assert_ref(s);
290 pa_assert_se(u = s->userdata);
291
292 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
293 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
294 return;
295
296 /* FIXME, no volume control in source_output, get the info from the master */
297 pa_source_get_mute(u->source_output->source, TRUE);
298 }
299
300 /* Called from input thread context */
301 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
302 struct userdata *u;
303
304 pa_source_output_assert_ref(o);
305 pa_source_output_assert_io_context(o);
306 pa_assert_se(u = o->userdata);
307
308 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output))) {
309 pa_log("push when no link?");
310 return;
311 }
312
313 /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */
314
315 /* if uplink sink exists, pull data from there; simplify by using
316 same length as chunk provided by source */
317 if(u->sink && (pa_sink_get_state(u->sink) == PA_SINK_RUNNING)) {
318 pa_memchunk tchunk;
319 size_t nbytes = chunk->length;
320 pa_mix_info streams[2];
321 pa_memchunk target_chunk;
322 void *target;
323 int ch;
324
325 /* Hmm, process any rewind request that might be queued up */
326 pa_sink_process_rewind(u->sink, 0);
327
328 /* get data from the sink */
329 while (pa_memblockq_peek(u->sink_memblockq, &tchunk) < 0) {
330 pa_memchunk nchunk;
331
332 /* make sure we get nbytes from the sink with render_full,
333 otherwise we cannot mix with the uplink */
334 pa_sink_render_full(u->sink, nbytes, &nchunk);
335 pa_memblockq_push(u->sink_memblockq, &nchunk);
336 pa_memblock_unref(nchunk.memblock);
337 }
338 pa_assert(tchunk.length == chunk->length);
339
340 /* move the read pointer for sink memblockq */
341 pa_memblockq_drop(u->sink_memblockq, tchunk.length);
342
343 /* allocate target chunk */
344 /* this could probably be done in-place, but having chunk as both
345 the input and output creates issues with reference counts */
346 target_chunk.index = 0;
347 target_chunk.length = chunk->length;
348 pa_assert(target_chunk.length == chunk->length);
349
350 target_chunk.memblock = pa_memblock_new(o->source->core->mempool,
351 target_chunk.length);
352 pa_assert( target_chunk.memblock );
353
354 /* get target pointer */
355 target = (void*)((uint8_t*)pa_memblock_acquire(target_chunk.memblock)
356 + target_chunk.index);
357
358 /* set-up mixing structure
359 volume was taken care of in sink and source already */
360 streams[0].chunk = *chunk;
361 for(ch=0;ch<o->sample_spec.channels;ch++)
362 streams[0].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
363 streams[0].volume.channels = o->sample_spec.channels;
364
365 streams[1].chunk = tchunk;
366 for(ch=0;ch<o->sample_spec.channels;ch++)
367 streams[1].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
368 streams[1].volume.channels = o->sample_spec.channels;
369
370 /* do mixing */
371 pa_mix(streams, /* 2 streams to be mixed */
372 2,
373 target, /* put result in target chunk */
374 chunk->length, /* same length as input */
375 (const pa_sample_spec *)&o->sample_spec, /* same sample spec for input and output */
376 NULL, /* no volume information */
377 FALSE); /* no mute */
378
379 pa_memblock_release(target_chunk.memblock);
380 pa_memblock_unref(tchunk.memblock); /* clean-up */
381
382 /* forward the data to the virtual source */
383 pa_source_post(u->source, &target_chunk);
384
385 pa_memblock_unref(target_chunk.memblock); /* clean-up */
386
387 } else {
388 /* forward the data to the virtual source */
389 pa_source_post(u->source, chunk);
390 }
391
392
393 }
394
395 /* Called from input thread context */
396 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
397 struct userdata *u;
398
399 pa_source_output_assert_ref(o);
400 pa_source_output_assert_io_context(o);
401 pa_assert_se(u = o->userdata);
402
403 /* FIXME, no idea what I am doing here */
404 #if 0
405 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
406 u->send_counter -= (int64_t) nbytes;
407 #endif
408 }
409
410 /* Called from output thread context */
411 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
412
413 /* FIXME, nothing to do here ? */
414
415 return pa_source_output_process_msg(obj, code, data, offset, chunk);
416 }
417
418 /* Called from output thread context */
419 static void source_output_attach_cb(pa_source_output *o) {
420 struct userdata *u;
421
422 pa_source_output_assert_ref(o);
423 pa_source_output_assert_io_context(o);
424 pa_assert_se(u = o->userdata);
425
426 pa_source_set_rtpoll(u->source, o->source->thread_info.rtpoll);
427 pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
428 pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency);
429 pa_source_set_max_rewind_within_thread(u->source, pa_source_output_get_max_rewind(o));
430
431 pa_source_attach_within_thread(u->source);
432 }
433
434 /* Called from output thread context */
435 static void source_output_detach_cb(pa_source_output *o) {
436 struct userdata *u;
437
438 pa_source_output_assert_ref(o);
439 pa_source_output_assert_io_context(o);
440 pa_assert_se(u = o->userdata);
441
442 pa_source_detach_within_thread(u->source);
443 pa_source_set_rtpoll(u->source, NULL);
444 }
445
446 /* Called from output thread context */
447 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
448 struct userdata *u;
449
450 pa_source_output_assert_ref(o);
451 pa_source_output_assert_io_context(o);
452 pa_assert_se(u = o->userdata);
453
454 /* FIXME */
455 #if 0
456 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
457
458 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
459 u->latency),
460 &o->sample_spec);
461
462 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
463 }
464 #endif
465 }
466
467 /* Called from main thread */
468 static void source_output_kill_cb(pa_source_output *o) {
469 struct userdata *u;
470
471 pa_source_output_assert_ref(o);
472 pa_assert_ctl_context();
473 pa_assert_se(u = o->userdata);
474
475 /* The order here matters! We first kill the source output, followed
476 * by the source. That means the source callbacks must be protected
477 * against an unconnected source output! */
478 pa_source_output_unlink(u->source_output);
479 pa_source_unlink(u->source);
480
481 pa_source_output_unref(u->source_output);
482 u->source_output = NULL;
483
484 pa_source_unref(u->source);
485 u->source = NULL;
486
487 pa_module_unload_request(u->module, TRUE);
488 }
489
490 /* Called from main thread */
491 static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
492 struct userdata *u;
493
494 pa_source_output_assert_ref(o);
495 pa_assert_ctl_context();
496 pa_assert_se(u = o->userdata);
497
498 /* FIXME */
499 //return dest != u->source_input->source->monitor_source;
500
501 return TRUE;
502 }
503
504 /* Called from main thread */
505 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
506 struct userdata *u;
507
508 pa_source_output_assert_ref(o);
509 pa_assert_ctl_context();
510 pa_assert_se(u = o->userdata);
511
512 if (dest) {
513 pa_source_set_asyncmsgq(u->source, dest->asyncmsgq);
514 pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags);
515 } else
516 pa_source_set_asyncmsgq(u->source, NULL);
517
518 if (u->auto_desc && dest) {
519 const char *z;
520 pa_proplist *pl;
521
522 pl = pa_proplist_new();
523 z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
524 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s",
525 pa_proplist_gets(u->source->proplist, "device.vsource.name"), z ? z : dest->name);
526
527 pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
528 pa_proplist_free(pl);
529 }
530 }
531
532
533 int pa__init(pa_module*m) {
534 struct userdata *u;
535 pa_sample_spec ss;
536 pa_channel_map map;
537 pa_modargs *ma;
538 pa_source *master=NULL;
539 pa_source_output_new_data source_output_data;
540 pa_source_new_data source_data;
541
542 /* optional for uplink_sink */
543 pa_sink_new_data sink_data;
544 size_t nbytes;
545
546 pa_assert(m);
547
548 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
549 pa_log("Failed to parse module arguments.");
550 goto fail;
551 }
552
553 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) {
554 pa_log("Master source not found");
555 goto fail;
556 }
557
558 pa_assert(master);
559
560 ss = master->sample_spec;
561 ss.format = PA_SAMPLE_FLOAT32;
562 map = master->channel_map;
563 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
564 pa_log("Invalid sample format specification or channel map");
565 goto fail;
566 }
567
568
569 u = pa_xnew0(struct userdata, 1);
570 if (!u) {
571 pa_log("Failed to alloc userdata");
572 goto fail;
573 }
574 u->module = m;
575 m->userdata = u;
576 u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
577 if (!u->memblockq) {
578 pa_log("Failed to create source memblockq.");
579 goto fail;
580 }
581 u->channels = ss.channels;
582
583 /* Create source */
584 pa_source_new_data_init(&source_data);
585 source_data.driver = __FILE__;
586 source_data.module = m;
587 if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
588 source_data.name = pa_sprintf_malloc("%s.vsource", master->name);
589 pa_source_new_data_set_sample_spec(&source_data, &ss);
590 pa_source_new_data_set_channel_map(&source_data, &map);
591 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
592 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
593 pa_proplist_sets(source_data.proplist, "device.vsource.name", source_data.name);
594
595 if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
596 pa_log("Invalid properties");
597 pa_source_new_data_done(&source_data);
598 goto fail;
599 }
600
601 if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
602 const char *z;
603
604 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
605 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s", source_data.name, z ? z : master->name);
606 }
607
608 u->source = pa_source_new(m->core, &source_data,
609 PA_SOURCE_HW_MUTE_CTRL|PA_SOURCE_HW_VOLUME_CTRL|PA_SOURCE_DECIBEL_VOLUME|
610 (master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY)));
611 pa_source_new_data_done(&source_data);
612
613 if (!u->source) {
614 pa_log("Failed to create source.");
615 goto fail;
616 }
617
618 u->source->parent.process_msg = source_process_msg_cb;
619 u->source->set_state = source_set_state_cb;
620 u->source->update_requested_latency = source_update_requested_latency_cb;
621 u->source->set_volume = source_set_volume_cb;
622 u->source->set_mute = source_set_mute_cb;
623 u->source->get_volume = source_get_volume_cb;
624 u->source->get_mute = source_get_mute_cb;
625 u->source->userdata = u;
626
627 pa_source_set_asyncmsgq(u->source, master->asyncmsgq);
628
629 /* Create source output */
630 pa_source_output_new_data_init(&source_output_data);
631 source_output_data.driver = __FILE__;
632 source_output_data.module = m;
633 source_output_data.source = master;
634 source_output_data.destination_source = u->source;
635 /* FIXME
636 source_output_data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; */
637
638 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));
639 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
640 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
641 pa_source_output_new_data_set_channel_map(&source_output_data, &map);
642
643 pa_source_output_new(&u->source_output, m->core, &source_output_data);
644 pa_source_output_new_data_done(&source_output_data);
645
646 if (!u->source_output)
647 goto fail;
648
649 u->source_output->parent.process_msg = source_output_process_msg_cb;
650 u->source_output->push = source_output_push_cb;
651 u->source_output->process_rewind = source_output_process_rewind_cb;
652 u->source_output->kill = source_output_kill_cb;
653 u->source_output->attach = source_output_attach_cb;
654 u->source_output->detach = source_output_detach_cb;
655 u->source_output->state_change = source_output_state_change_cb;
656 u->source_output->may_move_to = source_output_may_move_to_cb;
657 u->source_output->moving = source_output_moving_cb;
658 u->source_output->userdata = u;
659
660 u->source->output_from_master = u->source_output;
661
662 pa_source_put(u->source);
663 pa_source_output_put(u->source_output);
664
665 /* Create optional uplink sink */
666 pa_sink_new_data_init(&sink_data);
667 sink_data.driver = __FILE__;
668 sink_data.module = m;
669 if ((sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "uplink_sink", NULL)))) {
670 pa_sink_new_data_set_sample_spec(&sink_data, &ss);
671 pa_sink_new_data_set_channel_map(&sink_data, &map);
672 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
673 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "uplink sink");
674 pa_proplist_sets(sink_data.proplist, "device.uplink_sink.name", sink_data.name);
675
676 if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
677 const char *z;
678
679 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
680 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Uplink Sink %s on %s", sink_data.name, z ? z : master->name);
681 }
682
683 u->sink_memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
684 if (!u->sink_memblockq) {
685 pa_log("Failed to create sink memblockq.");
686 goto fail;
687 }
688
689 u->sink = pa_sink_new(m->core, &sink_data, 0); /* FIXME, sink has no capabilities */
690 pa_sink_new_data_done(&sink_data);
691
692 if (!u->sink) {
693 pa_log("Failed to create sink.");
694 goto fail;
695 }
696
697 u->sink->parent.process_msg = sink_process_msg_cb;
698 u->sink->update_requested_latency = sink_update_requested_latency_cb;
699 u->sink->request_rewind = sink_request_rewind_cb;
700 u->sink->set_state = sink_set_state_cb;
701 u->sink->userdata = u;
702
703 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
704
705 /* FIXME: no idea what I am doing here */
706 u->block_usec = BLOCK_USEC;
707 nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
708 pa_sink_set_max_rewind(u->sink, nbytes);
709 pa_sink_set_max_request(u->sink, nbytes);
710
711 pa_sink_put(u->sink);
712 } else {
713 /* optional uplink sink not enabled */
714 u->sink = NULL;
715 }
716
717 pa_modargs_free(ma);
718
719 return 0;
720
721 fail:
722 if (ma)
723 pa_modargs_free(ma);
724
725 pa__done(m);
726
727 return -1;
728 }
729
730 int pa__get_n_used(pa_module *m) {
731 struct userdata *u;
732
733 pa_assert(m);
734 pa_assert_se(u = m->userdata);
735
736 return pa_source_linked_by(u->source);
737 }
738
739 void pa__done(pa_module*m) {
740 struct userdata *u;
741
742 pa_assert(m);
743
744 if (!(u = m->userdata))
745 return;
746
747 /* See comments in source_output_kill_cb() above regarding
748 * destruction order! */
749
750 if (u->source_output)
751 pa_source_output_unlink(u->source_output);
752
753 if (u->source)
754 pa_source_unlink(u->source);
755
756 if (u->source_output)
757 pa_source_output_unref(u->source_output);
758
759 if (u->source)
760 pa_source_unref(u->source);
761
762 if (u->sink)
763 pa_sink_unref(u->sink);
764
765 if (u->memblockq)
766 pa_memblockq_free(u->memblockq);
767
768 if (u->sink_memblockq)
769 pa_memblockq_free(u->sink_memblockq);
770
771 pa_xfree(u);
772 }