]> code.delx.au - pulseaudio/blob - src/modules/module-virtual-source.c
Make connect-stress test compile for win32
[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 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 NULL
97 };
98
99 /* Called from I/O thread context */
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 *((pa_usec_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 */
116 static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
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_source_suspend(u->source, FALSE, PA_SUSPEND_ALL);
129
130 /* FIXME: if there's no client connected, the source will suspend
131 and playback will be stuck. You'd want to prevent the source from
132 sleeping when the uplink sink is active; even if the audio is
133 discarded at least the app isn't stuck */
134
135 } else {
136 /* nothing to do, if the sink becomes idle or suspended let
137 module-suspend-idle handle the sources later */
138 }
139
140 return 0;
141 }
142
143 static void sink_update_requested_latency_cb(pa_sink *s) {
144 struct userdata *u;
145
146 pa_sink_assert_ref(s);
147 pa_assert_se(u = s->userdata);
148
149 /* FIXME: there's no latency support */
150
151 }
152
153
154 /* Called from I/O thread context */
155 static void sink_request_rewind_cb(pa_sink *s) {
156 struct userdata *u;
157
158 pa_sink_assert_ref(s);
159 pa_assert_se(u = s->userdata);
160
161 /* Do nothing */
162 pa_sink_process_rewind(u->sink, 0);
163
164 }
165
166 /* Called from I/O thread context */
167 static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
168 struct userdata *u = PA_SOURCE(o)->userdata;
169
170 switch (code) {
171
172 case PA_SOURCE_MESSAGE_GET_LATENCY:
173
174 /* The source is _put() before the source output is, so let's
175 * make sure we don't access it in that time. Also, the
176 * source output is first shut down, the source second. */
177 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
178 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) {
179 *((pa_usec_t*) data) = 0;
180 return 0;
181 }
182
183 *((pa_usec_t*) data) =
184
185 /* Get the latency of the master source */
186 pa_source_get_latency_within_thread(u->source_output->source) +
187
188 /* Add the latency internal to our source output on top */
189 /* FIXME, no idea what I am doing here */
190 pa_bytes_to_usec(pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq), &u->source_output->source->sample_spec);
191
192 return 0;
193 }
194
195 return pa_source_process_msg(o, code, data, offset, chunk);
196 }
197
198 /* Called from main context */
199 static int source_set_state_cb(pa_source *s, pa_source_state_t state) {
200 struct userdata *u;
201
202 pa_source_assert_ref(s);
203 pa_assert_se(u = s->userdata);
204
205 if (!PA_SOURCE_IS_LINKED(state) ||
206 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
207 return 0;
208
209 pa_source_output_cork(u->source_output, state == PA_SOURCE_SUSPENDED);
210 return 0;
211 }
212
213 /* Called from I/O thread context */
214 static void source_update_requested_latency_cb(pa_source *s) {
215 struct userdata *u;
216
217 pa_source_assert_ref(s);
218 pa_assert_se(u = s->userdata);
219
220 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
221 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
222 return;
223
224 /* Just hand this one over to the master source */
225 pa_source_output_set_requested_latency_within_thread(
226 u->source_output,
227 pa_source_get_requested_latency_within_thread(s));
228 }
229
230 /* Called from main context */
231 static void source_set_volume_cb(pa_source *s) {
232 struct userdata *u;
233
234 pa_source_assert_ref(s);
235 pa_assert_se(u = s->userdata);
236
237 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
238 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
239 return;
240
241 /* FIXME, no volume control in source_output, set volume at the master */
242 pa_source_set_volume(u->source_output->source, &s->volume, TRUE);
243 }
244
245 static void source_get_volume_cb(pa_source *s) {
246 struct userdata *u;
247
248 pa_source_assert_ref(s);
249 pa_assert_se(u = s->userdata);
250
251 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
252 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
253 return;
254
255 /* FIXME, no volume control in source_output, get the info from the master */
256 pa_source_get_volume(u->source_output->source, TRUE);
257
258 if (pa_cvolume_equal(&s->volume,&u->source_output->source->volume))
259 /* no change */
260 return;
261
262 s->volume = u->source_output->source->volume;
263 pa_source_set_soft_volume(s, NULL);
264 }
265
266
267 /* Called from main context */
268 static void source_set_mute_cb(pa_source *s) {
269 struct userdata *u;
270
271 pa_source_assert_ref(s);
272 pa_assert_se(u = s->userdata);
273
274 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
275 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
276 return;
277
278 /* FIXME, no volume control in source_output, set mute at the master */
279 pa_source_set_mute(u->source_output->source, TRUE, TRUE);
280 }
281
282 /* Called from main context */
283 static void source_get_mute_cb(pa_source *s) {
284 struct userdata *u;
285
286 pa_source_assert_ref(s);
287 pa_assert_se(u = s->userdata);
288
289 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
290 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
291 return;
292
293 /* FIXME, no volume control in source_output, get the info from the master */
294 pa_source_get_mute(u->source_output->source, TRUE);
295 }
296
297 /* Called from input thread context */
298 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
299 struct userdata *u;
300
301 pa_source_output_assert_ref(o);
302 pa_source_output_assert_io_context(o);
303 pa_assert_se(u = o->userdata);
304
305 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output))) {
306 pa_log("push when no link?");
307 return;
308 }
309
310 /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */
311
312 /* if uplink sink exists, pull data from there; simplify by using
313 same length as chunk provided by source */
314 if(u->sink && (pa_sink_get_state(u->sink) == PA_SINK_RUNNING)) {
315 pa_memchunk tchunk;
316 size_t nbytes = chunk->length;
317 pa_mix_info streams[2];
318 pa_memchunk target_chunk;
319 void *target;
320 int ch;
321
322 /* Hmm, process any rewind request that might be queued up */
323 pa_sink_process_rewind(u->sink, 0);
324
325 /* get data from the sink */
326 while (pa_memblockq_peek(u->sink_memblockq, &tchunk) < 0) {
327 pa_memchunk nchunk;
328
329 /* make sure we get nbytes from the sink with render_full,
330 otherwise we cannot mix with the uplink */
331 pa_sink_render_full(u->sink, nbytes, &nchunk);
332 pa_memblockq_push(u->sink_memblockq, &nchunk);
333 pa_memblock_unref(nchunk.memblock);
334 }
335 pa_assert(tchunk.length == chunk->length);
336
337 /* move the read pointer for sink memblockq */
338 pa_memblockq_drop(u->sink_memblockq, tchunk.length);
339
340 /* allocate target chunk */
341 /* this could probably be done in-place, but having chunk as both
342 the input and output creates issues with reference counts */
343 target_chunk.index = 0;
344 target_chunk.length = chunk->length;
345 pa_assert(target_chunk.length == chunk->length);
346
347 target_chunk.memblock = pa_memblock_new(o->source->core->mempool,
348 target_chunk.length);
349 pa_assert( target_chunk.memblock );
350
351 /* get target pointer */
352 target = (void*)((uint8_t*)pa_memblock_acquire(target_chunk.memblock)
353 + target_chunk.index);
354
355 /* set-up mixing structure
356 volume was taken care of in sink and source already */
357 streams[0].chunk = *chunk;
358 for(ch=0;ch<o->sample_spec.channels;ch++)
359 streams[0].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
360 streams[0].volume.channels = o->sample_spec.channels;
361
362 streams[1].chunk = tchunk;
363 for(ch=0;ch<o->sample_spec.channels;ch++)
364 streams[1].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
365 streams[1].volume.channels = o->sample_spec.channels;
366
367 /* do mixing */
368 pa_mix(streams, /* 2 streams to be mixed */
369 2,
370 target, /* put result in target chunk */
371 chunk->length, /* same length as input */
372 (const pa_sample_spec *)&o->sample_spec, /* same sample spec for input and output */
373 NULL, /* no volume information */
374 FALSE); /* no mute */
375
376 pa_memblock_release(target_chunk.memblock);
377 pa_memblock_unref(tchunk.memblock); /* clean-up */
378
379 /* forward the data to the virtual source */
380 pa_source_post(u->source, &target_chunk);
381
382 pa_memblock_unref(target_chunk.memblock); /* clean-up */
383
384 } else {
385 /* forward the data to the virtual source */
386 pa_source_post(u->source, chunk);
387 }
388
389
390 }
391
392 /* Called from input thread context */
393 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
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 /* FIXME, no idea what I am doing here */
401 #if 0
402 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
403 u->send_counter -= (int64_t) nbytes;
404 #endif
405 }
406
407 /* Called from output thread context */
408 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
409
410 /* FIXME, nothing to do here ? */
411
412 return pa_source_output_process_msg(obj, code, data, offset, chunk);
413 }
414
415 /* Called from output thread context */
416 static void source_output_attach_cb(pa_source_output *o) {
417 struct userdata *u;
418
419 pa_source_output_assert_ref(o);
420 pa_source_output_assert_io_context(o);
421 pa_assert_se(u = o->userdata);
422
423 pa_source_set_rtpoll(u->source, o->source->thread_info.rtpoll);
424 pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
425 pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency);
426 pa_source_set_max_rewind_within_thread(u->source, pa_source_output_get_max_rewind(o));
427
428 pa_source_attach_within_thread(u->source);
429 }
430
431 /* Called from output thread context */
432 static void source_output_detach_cb(pa_source_output *o) {
433 struct userdata *u;
434
435 pa_source_output_assert_ref(o);
436 pa_source_output_assert_io_context(o);
437 pa_assert_se(u = o->userdata);
438
439 pa_source_detach_within_thread(u->source);
440 pa_source_set_rtpoll(u->source, NULL);
441 }
442
443 /* Called from output thread context */
444 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
445 struct userdata *u;
446
447 pa_source_output_assert_ref(o);
448 pa_source_output_assert_io_context(o);
449 pa_assert_se(u = o->userdata);
450
451 /* FIXME */
452 #if 0
453 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
454
455 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
456 u->latency),
457 &o->sample_spec);
458
459 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
460 }
461 #endif
462 }
463
464 /* Called from main thread */
465 static void source_output_kill_cb(pa_source_output *o) {
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 /* The order here matters! We first kill the source output, followed
473 * by the source. That means the source callbacks must be protected
474 * against an unconnected source output! */
475 pa_source_output_unlink(u->source_output);
476 pa_source_unlink(u->source);
477
478 pa_source_output_unref(u->source_output);
479 u->source_output = NULL;
480
481 pa_source_unref(u->source);
482 u->source = NULL;
483
484 pa_module_unload_request(u->module, TRUE);
485 }
486
487 /* Called from main thread */
488 static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
489 struct userdata *u;
490
491 pa_source_output_assert_ref(o);
492 pa_assert_ctl_context();
493 pa_assert_se(u = o->userdata);
494
495 /* FIXME */
496 //return dest != u->source_input->source->monitor_source;
497
498 return TRUE;
499 }
500
501 /* Called from main thread */
502 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
503 struct userdata *u;
504
505 pa_source_output_assert_ref(o);
506 pa_assert_ctl_context();
507 pa_assert_se(u = o->userdata);
508
509 if (dest) {
510 pa_source_set_asyncmsgq(u->source, dest->asyncmsgq);
511 pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags);
512 } else
513 pa_source_set_asyncmsgq(u->source, NULL);
514
515 if (u->auto_desc && dest) {
516 const char *z;
517 pa_proplist *pl;
518
519 pl = pa_proplist_new();
520 z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
521 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s",
522 pa_proplist_gets(u->source->proplist, "device.vsource.name"), z ? z : dest->name);
523
524 pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
525 pa_proplist_free(pl);
526 }
527 }
528
529
530 int pa__init(pa_module*m) {
531 struct userdata *u;
532 pa_sample_spec ss;
533 pa_channel_map map;
534 pa_modargs *ma;
535 pa_source *master=NULL;
536 pa_source_output_new_data source_output_data;
537 pa_source_new_data source_data;
538
539 /* optional for uplink_sink */
540 pa_sink_new_data sink_data;
541 size_t nbytes;
542
543 pa_assert(m);
544
545 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
546 pa_log("Failed to parse module arguments.");
547 goto fail;
548 }
549
550 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) {
551 pa_log("Master source not found");
552 goto fail;
553 }
554
555 pa_assert(master);
556
557 ss = master->sample_spec;
558 ss.format = PA_SAMPLE_FLOAT32;
559 map = master->channel_map;
560 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
561 pa_log("Invalid sample format specification or channel map");
562 goto fail;
563 }
564
565
566 u = pa_xnew0(struct userdata, 1);
567 if (!u) {
568 pa_log("Failed to alloc userdata");
569 goto fail;
570 }
571 u->module = m;
572 m->userdata = u;
573 u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
574 if (!u->memblockq) {
575 pa_log("Failed to create source memblockq.");
576 goto fail;
577 }
578 u->channels = ss.channels;
579
580 /* Create source */
581 pa_source_new_data_init(&source_data);
582 source_data.driver = __FILE__;
583 source_data.module = m;
584 if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
585 source_data.name = pa_sprintf_malloc("%s.vsource", master->name);
586 pa_source_new_data_set_sample_spec(&source_data, &ss);
587 pa_source_new_data_set_channel_map(&source_data, &map);
588 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
589 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
590 pa_proplist_sets(source_data.proplist, "device.vsource.name", source_data.name);
591
592 if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
593 pa_log("Invalid properties");
594 pa_source_new_data_done(&source_data);
595 goto fail;
596 }
597
598 if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
599 const char *z;
600
601 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
602 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s", source_data.name, z ? z : master->name);
603 }
604
605 u->source = pa_source_new(m->core, &source_data,
606 PA_SOURCE_HW_MUTE_CTRL|PA_SOURCE_HW_VOLUME_CTRL|PA_SOURCE_DECIBEL_VOLUME|
607 (master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY)));
608 pa_source_new_data_done(&source_data);
609
610 if (!u->source) {
611 pa_log("Failed to create source.");
612 goto fail;
613 }
614
615 u->source->parent.process_msg = source_process_msg_cb;
616 u->source->set_state = source_set_state_cb;
617 u->source->update_requested_latency = source_update_requested_latency_cb;
618 u->source->set_volume = source_set_volume_cb;
619 u->source->set_mute = source_set_mute_cb;
620 u->source->get_volume = source_get_volume_cb;
621 u->source->get_mute = source_get_mute_cb;
622 u->source->userdata = u;
623
624 pa_source_set_asyncmsgq(u->source, master->asyncmsgq);
625
626 /* Create source output */
627 pa_source_output_new_data_init(&source_output_data);
628 source_output_data.driver = __FILE__;
629 source_output_data.module = m;
630 source_output_data.source = master;
631 source_output_data.destination_source = u->source;
632 /* FIXME
633 source_output_data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; */
634
635 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));
636 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
637 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
638 pa_source_output_new_data_set_channel_map(&source_output_data, &map);
639
640 pa_source_output_new(&u->source_output, m->core, &source_output_data);
641 pa_source_output_new_data_done(&source_output_data);
642
643 if (!u->source_output)
644 goto fail;
645
646 u->source_output->parent.process_msg = source_output_process_msg_cb;
647 u->source_output->push = source_output_push_cb;
648 u->source_output->process_rewind = source_output_process_rewind_cb;
649 u->source_output->kill = source_output_kill_cb;
650 u->source_output->attach = source_output_attach_cb;
651 u->source_output->detach = source_output_detach_cb;
652 u->source_output->state_change = source_output_state_change_cb;
653 u->source_output->may_move_to = source_output_may_move_to_cb;
654 u->source_output->moving = source_output_moving_cb;
655 u->source_output->userdata = u;
656
657 u->source->output_from_master = u->source_output;
658
659 pa_source_put(u->source);
660 pa_source_output_put(u->source_output);
661
662 /* Create optional uplink sink */
663 pa_sink_new_data_init(&sink_data);
664 sink_data.driver = __FILE__;
665 sink_data.module = m;
666 if ((sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "uplink_sink", NULL)))) {
667 pa_sink_new_data_set_sample_spec(&sink_data, &ss);
668 pa_sink_new_data_set_channel_map(&sink_data, &map);
669 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
670 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "uplink sink");
671 pa_proplist_sets(sink_data.proplist, "device.uplink_sink.name", sink_data.name);
672
673 if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
674 const char *z;
675
676 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
677 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Uplink Sink %s on %s", sink_data.name, z ? z : master->name);
678 }
679
680 u->sink_memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
681 if (!u->sink_memblockq) {
682 pa_log("Failed to create sink memblockq.");
683 goto fail;
684 }
685
686 u->sink = pa_sink_new(m->core, &sink_data, 0); /* FIXME, sink has no capabilities */
687 pa_sink_new_data_done(&sink_data);
688
689 if (!u->sink) {
690 pa_log("Failed to create sink.");
691 goto fail;
692 }
693
694 u->sink->parent.process_msg = sink_process_msg_cb;
695 u->sink->update_requested_latency = sink_update_requested_latency_cb;
696 u->sink->request_rewind = sink_request_rewind_cb;
697 u->sink->set_state = sink_set_state_cb;
698 u->sink->userdata = u;
699
700 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
701
702 /* FIXME: no idea what I am doing here */
703 u->block_usec = BLOCK_USEC;
704 nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
705 pa_sink_set_max_rewind(u->sink, nbytes);
706 pa_sink_set_max_request(u->sink, nbytes);
707
708 pa_sink_put(u->sink);
709 } else {
710 /* optional uplink sink not enabled */
711 u->sink = NULL;
712 }
713
714 pa_modargs_free(ma);
715
716 return 0;
717
718 fail:
719 if (ma)
720 pa_modargs_free(ma);
721
722 pa__done(m);
723
724 return -1;
725 }
726
727 int pa__get_n_used(pa_module *m) {
728 struct userdata *u;
729
730 pa_assert(m);
731 pa_assert_se(u = m->userdata);
732
733 return pa_source_linked_by(u->source);
734 }
735
736 void pa__done(pa_module*m) {
737 struct userdata *u;
738
739 pa_assert(m);
740
741 if (!(u = m->userdata))
742 return;
743
744 /* See comments in source_output_kill_cb() above regarding
745 * destruction order! */
746
747 if (u->source_output)
748 pa_source_output_unlink(u->source_output);
749
750 if (u->source)
751 pa_source_unlink(u->source);
752
753 if (u->source_output)
754 pa_source_output_unref(u->source_output);
755
756 if (u->source)
757 pa_source_unref(u->source);
758
759 if (u->sink)
760 pa_sink_unref(u->sink);
761
762 if (u->memblockq)
763 pa_memblockq_free(u->memblockq);
764
765 if (u->sink_memblockq)
766 pa_memblockq_free(u->sink_memblockq);
767
768 pa_xfree(u);
769 }