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