1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2010 Intel Corporation
5 Contributor: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <pulse/gccmacro.h>
26 #include <pulse/xmalloc.h>
27
28 #include <pulsecore/i18n.h>
29 #include <pulsecore/namereg.h>
30 #include <pulsecore/sink.h>
31 #include <pulsecore/module.h>
32 #include <pulsecore/core-util.h>
33 #include <pulsecore/modargs.h>
34 #include <pulsecore/log.h>
35 #include <pulsecore/rtpoll.h>
36 #include <pulsecore/sample-util.h>
37 #include <pulsecore/ltdl-helper.h>
38
39 PA_MODULE_AUTHOR("Pierre-Louis Bossart");
40 PA_MODULE_DESCRIPTION(_("Virtual sink"));
41 PA_MODULE_VERSION(PACKAGE_VERSION);
42 PA_MODULE_LOAD_ONCE(false);
43 PA_MODULE_USAGE(
44 _("sink_name=<name for the sink> "
45 "sink_properties=<properties for the sink> "
46 "master=<name of sink to filter> "
47 "rate=<sample rate> "
48 "channels=<number of channels> "
49 "channel_map=<channel map> "
50 "use_volume_sharing=<yes or no> "
51 "force_flat_volume=<yes or no> "
52 ));
53
54 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
55
56 struct userdata {
57 pa_module *module;
58
59 /* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */
60 /* bool autoloaded; */
61
62 pa_sink *sink;
63 pa_sink_input *sink_input;
64
65 pa_memblockq *memblockq;
66
67 bool auto_desc;
68 unsigned channels;
69 };
70
71 static const char* const valid_modargs[] = {
72 "sink_name",
73 "sink_properties",
74 "master",
75 "rate",
76 "channels",
77 "channel_map",
78 "use_volume_sharing",
79 "force_flat_volume",
80 NULL
81 };
82
83 /* Called from I/O thread context */
sink_process_msg_cb(pa_msgobject * o,int code,void * data,int64_t offset,pa_memchunk * chunk)84 static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
85 struct userdata *u = PA_SINK(o)->userdata;
86
87 switch (code) {
88
89 case PA_SINK_MESSAGE_GET_LATENCY:
90
91 /* The sink is _put() before the sink input is, so let's
92 * make sure we don't access it in that time. Also, the
93 * sink input is first shut down, the sink second. */
94 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
95 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) {
96 *((int64_t*) data) = 0;
97 return 0;
98 }
99
100 *((int64_t*) data) =
101
102 /* Get the latency of the master sink */
103 pa_sink_get_latency_within_thread(u->sink_input->sink, true) +
104
105 /* Add the latency internal to our sink input on top */
106 pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
107
108 return 0;
109 }
110
111 return pa_sink_process_msg(o, code, data, offset, chunk);
112 }
113
114 /* Called from main context */
sink_set_state_in_main_thread_cb(pa_sink * s,pa_sink_state_t state,pa_suspend_cause_t suspend_cause)115 static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause) {
116 struct userdata *u;
117
118 pa_sink_assert_ref(s);
119 pa_assert_se(u = s->userdata);
120
121 if (!PA_SINK_IS_LINKED(state) ||
122 !PA_SINK_INPUT_IS_LINKED(u->sink_input->state))
123 return 0;
124
125 pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
126 return 0;
127 }
128
129 /* Called from the IO thread. */
sink_set_state_in_io_thread_cb(pa_sink * s,pa_sink_state_t new_state,pa_suspend_cause_t new_suspend_cause)130 static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
131 struct userdata *u;
132
133 pa_assert(s);
134 pa_assert_se(u = s->userdata);
135
136 /* When set to running or idle for the first time, request a rewind
137 * of the master sink to make sure we are heard immediately */
138 if (PA_SINK_IS_OPENED(new_state) && s->thread_info.state == PA_SINK_INIT) {
139 pa_log_debug("Requesting rewind due to state change.");
140 pa_sink_input_request_rewind(u->sink_input, 0, false, true, true);
141 }
142
143 return 0;
144 }
145
146 /* Called from I/O thread context */
sink_request_rewind_cb(pa_sink * s)147 static void sink_request_rewind_cb(pa_sink *s) {
148 struct userdata *u;
149
150 pa_sink_assert_ref(s);
151 pa_assert_se(u = s->userdata);
152
153 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
154 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
155 return;
156
157 /* Just hand this one over to the master sink */
158 pa_sink_input_request_rewind(u->sink_input,
159 s->thread_info.rewind_nbytes +
160 pa_memblockq_get_length(u->memblockq), true, false, false);
161 }
162
163 /* Called from I/O thread context */
sink_update_requested_latency_cb(pa_sink * s)164 static void sink_update_requested_latency_cb(pa_sink *s) {
165 struct userdata *u;
166
167 pa_sink_assert_ref(s);
168 pa_assert_se(u = s->userdata);
169
170 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
171 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
172 return;
173
174 /* Just hand this one over to the master sink */
175 pa_sink_input_set_requested_latency_within_thread(
176 u->sink_input,
177 pa_sink_get_requested_latency_within_thread(s));
178 }
179
180 /* Called from main context */
sink_set_volume_cb(pa_sink * s)181 static void sink_set_volume_cb(pa_sink *s) {
182 struct userdata *u;
183
184 pa_sink_assert_ref(s);
185 pa_assert_se(u = s->userdata);
186
187 if (!PA_SINK_IS_LINKED(s->state) ||
188 !PA_SINK_INPUT_IS_LINKED(u->sink_input->state))
189 return;
190
191 pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, true);
192 }
193
194 /* Called from main context */
sink_set_mute_cb(pa_sink * s)195 static void sink_set_mute_cb(pa_sink *s) {
196 struct userdata *u;
197
198 pa_sink_assert_ref(s);
199 pa_assert_se(u = s->userdata);
200
201 if (!PA_SINK_IS_LINKED(s->state) ||
202 !PA_SINK_INPUT_IS_LINKED(u->sink_input->state))
203 return;
204
205 pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
206 }
207
208 /* Called from I/O thread context */
sink_input_pop_cb(pa_sink_input * i,size_t nbytes,pa_memchunk * chunk)209 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
210 struct userdata *u;
211 float *src, *dst;
212 size_t fs;
213 unsigned n, c;
214 pa_memchunk tchunk;
215 pa_usec_t current_latency PA_GCC_UNUSED;
216
217 pa_sink_input_assert_ref(i);
218 pa_assert(chunk);
219 pa_assert_se(u = i->userdata);
220
221 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state))
222 return -1;
223
224 /* Hmm, process any rewind request that might be queued up */
225 pa_sink_process_rewind(u->sink, 0);
226
227 /* (1) IF YOU NEED A FIXED BLOCK SIZE USE
228 * pa_memblockq_peek_fixed_size() HERE INSTEAD. NOTE THAT FILTERS
229 * WHICH CAN DEAL WITH DYNAMIC BLOCK SIZES ARE HIGHLY
230 * PREFERRED. */
231 while (pa_memblockq_peek(u->memblockq, &tchunk) < 0) {
232 pa_memchunk nchunk;
233
234 pa_sink_render(u->sink, nbytes, &nchunk);
235 pa_memblockq_push(u->memblockq, &nchunk);
236 pa_memblock_unref(nchunk.memblock);
237 }
238
239 /* (2) IF YOU NEED A FIXED BLOCK SIZE, THIS NEXT LINE IS NOT
240 * NECESSARY */
241 tchunk.length = PA_MIN(nbytes, tchunk.length);
242 pa_assert(tchunk.length > 0);
243
244 fs = pa_frame_size(&i->sample_spec);
245 n = (unsigned) (tchunk.length / fs);
246
247 pa_assert(n > 0);
248
249 chunk->index = 0;
250 chunk->length = n*fs;
251 chunk->memblock = pa_memblock_new(i->sink->core->mempool, chunk->length);
252
253 pa_memblockq_drop(u->memblockq, chunk->length);
254
255 src = pa_memblock_acquire_chunk(&tchunk);
256 dst = pa_memblock_acquire(chunk->memblock);
257
258 /* (3) PUT YOUR CODE HERE TO DO SOMETHING WITH THE DATA */
259
260 /* As an example, copy input to output */
261 for (c = 0; c < u->channels; c++) {
262 pa_sample_clamp(PA_SAMPLE_FLOAT32NE,
263 dst+c, u->channels * sizeof(float),
264 src+c, u->channels * sizeof(float),
265 n);
266 }
267
268 pa_memblock_release(tchunk.memblock);
269 pa_memblock_release(chunk->memblock);
270
271 pa_memblock_unref(tchunk.memblock);
272
273 /* (4) IF YOU NEED THE LATENCY FOR SOMETHING ACQUIRE IT LIKE THIS: */
274 current_latency =
275 /* Get the latency of the master sink */
276 pa_sink_get_latency_within_thread(i->sink, false) +
277
278 /* Add the latency internal to our sink input on top */
279 pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec);
280
281 return 0;
282 }
283
284 /* Called from I/O thread context */
sink_input_process_rewind_cb(pa_sink_input * i,size_t nbytes)285 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
286 struct userdata *u;
287 size_t amount = 0;
288
289 pa_sink_input_assert_ref(i);
290 pa_assert_se(u = i->userdata);
291
292 /* If the sink is not yet linked, there is nothing to rewind */
293 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state))
294 return;
295
296 if (u->sink->thread_info.rewind_nbytes > 0) {
297 size_t max_rewrite;
298
299 max_rewrite = nbytes + pa_memblockq_get_length(u->memblockq);
300 amount = PA_MIN(u->sink->thread_info.rewind_nbytes, max_rewrite);
301 u->sink->thread_info.rewind_nbytes = 0;
302
303 if (amount > 0) {
304 pa_memblockq_seek(u->memblockq, - (int64_t) amount, PA_SEEK_RELATIVE, true);
305
306 /* (5) PUT YOUR CODE HERE TO RESET YOUR FILTER */
307 }
308 }
309
310 pa_sink_process_rewind(u->sink, amount);
311 pa_memblockq_rewind(u->memblockq, nbytes);
312 }
313
314 /* Called from I/O thread context */
sink_input_update_max_rewind_cb(pa_sink_input * i,size_t nbytes)315 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
316 struct userdata *u;
317
318 pa_sink_input_assert_ref(i);
319 pa_assert_se(u = i->userdata);
320
321 /* FIXME: Too small max_rewind:
322 * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
323 pa_memblockq_set_maxrewind(u->memblockq, nbytes);
324 pa_sink_set_max_rewind_within_thread(u->sink, nbytes);
325 }
326
327 /* Called from I/O thread context */
sink_input_update_max_request_cb(pa_sink_input * i,size_t nbytes)328 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
329 struct userdata *u;
330
331 pa_sink_input_assert_ref(i);
332 pa_assert_se(u = i->userdata);
333
334 /* (6) IF YOU NEED A FIXED BLOCK SIZE ROUND nbytes UP TO MULTIPLES
335 * OF IT HERE. THE PA_ROUND_UP MACRO IS USEFUL FOR THAT. */
336
337 pa_sink_set_max_request_within_thread(u->sink, nbytes);
338 }
339
340 /* Called from I/O thread context */
sink_input_update_sink_latency_range_cb(pa_sink_input * i)341 static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
342 struct userdata *u;
343
344 pa_sink_input_assert_ref(i);
345 pa_assert_se(u = i->userdata);
346
347 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
348 }
349
350 /* Called from I/O thread context */
sink_input_update_sink_fixed_latency_cb(pa_sink_input * i)351 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input *i) {
352 struct userdata *u;
353
354 pa_sink_input_assert_ref(i);
355 pa_assert_se(u = i->userdata);
356
357 /* (7) IF YOU NEED A FIXED BLOCK SIZE ADD THE LATENCY FOR ONE
358 * BLOCK MINUS ONE SAMPLE HERE. pa_usec_to_bytes_round_up() IS
359 * USEFUL FOR THAT. */
360
361 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
362 }
363
364 /* Called from I/O thread context */
sink_input_detach_cb(pa_sink_input * i)365 static void sink_input_detach_cb(pa_sink_input *i) {
366 struct userdata *u;
367
368 pa_sink_input_assert_ref(i);
369 pa_assert_se(u = i->userdata);
370
371 if (PA_SINK_IS_LINKED(u->sink->thread_info.state))
372 pa_sink_detach_within_thread(u->sink);
373
374 pa_sink_set_rtpoll(u->sink, NULL);
375 }
376
377 /* Called from I/O thread context */
sink_input_attach_cb(pa_sink_input * i)378 static void sink_input_attach_cb(pa_sink_input *i) {
379 struct userdata *u;
380
381 pa_sink_input_assert_ref(i);
382 pa_assert_se(u = i->userdata);
383
384 pa_sink_set_rtpoll(u->sink, i->sink->thread_info.rtpoll);
385 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
386
387 /* (8.1) IF YOU NEED A FIXED BLOCK SIZE ADD THE LATENCY FOR ONE
388 * BLOCK MINUS ONE SAMPLE HERE. SEE (7) */
389 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
390
391 /* (8.2) IF YOU NEED A FIXED BLOCK SIZE ROUND
392 * pa_sink_input_get_max_request(i) UP TO MULTIPLES OF IT
393 * HERE. SEE (6) */
394 pa_sink_set_max_request_within_thread(u->sink, pa_sink_input_get_max_request(i));
395
396 /* FIXME: Too small max_rewind:
397 * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
398 pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i));
399
400 if (PA_SINK_IS_LINKED(u->sink->thread_info.state))
401 pa_sink_attach_within_thread(u->sink);
402 }
403
404 /* Called from main context */
sink_input_kill_cb(pa_sink_input * i)405 static void sink_input_kill_cb(pa_sink_input *i) {
406 struct userdata *u;
407
408 pa_sink_input_assert_ref(i);
409 pa_assert_se(u = i->userdata);
410
411 /* The order here matters! We first kill the sink so that streams
412 * can properly be moved away while the sink input is still connected
413 * to the master. */
414 pa_sink_input_cork(u->sink_input, true);
415 pa_sink_unlink(u->sink);
416 pa_sink_input_unlink(u->sink_input);
417
418 pa_sink_input_unref(u->sink_input);
419 u->sink_input = NULL;
420
421 pa_sink_unref(u->sink);
422 u->sink = NULL;
423
424 pa_module_unload_request(u->module, true);
425 }
426
427 /* Called from main context */
sink_input_moving_cb(pa_sink_input * i,pa_sink * dest)428 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
429 struct userdata *u;
430
431 pa_sink_input_assert_ref(i);
432 pa_assert_se(u = i->userdata);
433
434 if (dest) {
435 pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq);
436 pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags);
437 } else
438 pa_sink_set_asyncmsgq(u->sink, NULL);
439
440 if (u->auto_desc && dest) {
441 const char *z;
442 pa_proplist *pl;
443
444 pl = pa_proplist_new();
445 z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
446 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Sink %s on %s",
447 pa_proplist_gets(u->sink->proplist, "device.vsink.name"), z ? z : dest->name);
448
449 pa_sink_update_proplist(u->sink, PA_UPDATE_REPLACE, pl);
450 pa_proplist_free(pl);
451 }
452 }
453
454 /* Called from main context */
sink_input_volume_changed_cb(pa_sink_input * i)455 static void sink_input_volume_changed_cb(pa_sink_input *i) {
456 struct userdata *u;
457
458 pa_sink_input_assert_ref(i);
459 pa_assert_se(u = i->userdata);
460
461 pa_sink_volume_changed(u->sink, &i->volume);
462 }
463
464 /* Called from main context */
sink_input_mute_changed_cb(pa_sink_input * i)465 static void sink_input_mute_changed_cb(pa_sink_input *i) {
466 struct userdata *u;
467
468 pa_sink_input_assert_ref(i);
469 pa_assert_se(u = i->userdata);
470
471 pa_sink_mute_changed(u->sink, i->muted);
472 }
473
pa__init(pa_module * m)474 int pa__init(pa_module*m) {
475 struct userdata *u;
476 pa_sample_spec ss;
477 pa_channel_map map;
478 pa_modargs *ma;
479 pa_sink *master=NULL;
480 pa_sink_input_new_data sink_input_data;
481 pa_sink_new_data sink_data;
482 bool use_volume_sharing = true;
483 bool force_flat_volume = false;
484 pa_memchunk silence;
485
486 pa_assert(m);
487
488 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
489 pa_log("Failed to parse module arguments.");
490 goto fail;
491 }
492
493 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SINK))) {
494 pa_log("Master sink not found");
495 goto fail;
496 }
497
498 pa_assert(master);
499
500 ss = master->sample_spec;
501 ss.format = PA_SAMPLE_FLOAT32;
502 map = master->channel_map;
503 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
504 pa_log("Invalid sample format specification or channel map");
505 goto fail;
506 }
507
508 if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
509 pa_log("use_volume_sharing= expects a boolean argument");
510 goto fail;
511 }
512
513 if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) {
514 pa_log("force_flat_volume= expects a boolean argument");
515 goto fail;
516 }
517
518 if (use_volume_sharing && force_flat_volume) {
519 pa_log("Flat volume can't be forced when using volume sharing.");
520 goto fail;
521 }
522
523 u = pa_xnew0(struct userdata, 1);
524 u->module = m;
525 m->userdata = u;
526 u->channels = ss.channels;
527
528 /* Create sink */
529 pa_sink_new_data_init(&sink_data);
530 sink_data.driver = __FILE__;
531 sink_data.module = m;
532 if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL))))
533 sink_data.name = pa_sprintf_malloc("%s.vsink", master->name);
534 pa_sink_new_data_set_sample_spec(&sink_data, &ss);
535 pa_sink_new_data_set_channel_map(&sink_data, &map);
536 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
537 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
538 pa_proplist_sets(sink_data.proplist, "device.vsink.name", sink_data.name);
539
540 if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
541 pa_log("Invalid properties");
542 pa_sink_new_data_done(&sink_data);
543 goto fail;
544 }
545
546 if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
547 const char *z;
548
549 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
550 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Sink %s on %s", sink_data.name, z ? z : master->name);
551 }
552
553 u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))
554 | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
555 pa_sink_new_data_done(&sink_data);
556
557 if (!u->sink) {
558 pa_log("Failed to create sink.");
559 goto fail;
560 }
561
562 u->sink->parent.process_msg = sink_process_msg_cb;
563 u->sink->set_state_in_main_thread = sink_set_state_in_main_thread_cb;
564 u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
565 u->sink->update_requested_latency = sink_update_requested_latency_cb;
566 u->sink->request_rewind = sink_request_rewind_cb;
567 pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
568 if (!use_volume_sharing) {
569 pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
570 pa_sink_enable_decibel_volume(u->sink, true);
571 }
572 /* Normally this flag would be enabled automatically be we can force it. */
573 if (force_flat_volume)
574 u->sink->flags |= PA_SINK_FLAT_VOLUME;
575 u->sink->userdata = u;
576
577 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
578
579 /* Create sink input */
580 pa_sink_input_new_data_init(&sink_input_data);
581 sink_input_data.driver = __FILE__;
582 sink_input_data.module = m;
583 pa_sink_input_new_data_set_sink(&sink_input_data, master, false, true);
584 sink_input_data.origin_sink = u->sink;
585 pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Sink Stream from %s", pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION));
586 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
587 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
588 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
589 sink_input_data.flags |= PA_SINK_INPUT_START_CORKED;
590
591 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
592 pa_sink_input_new_data_done(&sink_input_data);
593
594 if (!u->sink_input)
595 goto fail;
596
597 u->sink_input->pop = sink_input_pop_cb;
598 u->sink_input->process_rewind = sink_input_process_rewind_cb;
599 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
600 u->sink_input->update_max_request = sink_input_update_max_request_cb;
601 u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
602 u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb;
603 u->sink_input->kill = sink_input_kill_cb;
604 u->sink_input->attach = sink_input_attach_cb;
605 u->sink_input->detach = sink_input_detach_cb;
606 u->sink_input->moving = sink_input_moving_cb;
607 u->sink_input->volume_changed = use_volume_sharing ? NULL : sink_input_volume_changed_cb;
608 u->sink_input->mute_changed = sink_input_mute_changed_cb;
609 u->sink_input->userdata = u;
610
611 u->sink->input_to_master = u->sink_input;
612
613 pa_sink_input_get_silence(u->sink_input, &silence);
614 u->memblockq = pa_memblockq_new("module-virtual-sink memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence);
615 pa_memblock_unref(silence.memblock);
616
617 /* (9) INITIALIZE ANYTHING ELSE YOU NEED HERE */
618
619 /* The order here is important. The input must be put first,
620 * otherwise streams might attach to the sink before the sink
621 * input is attached to the master. */
622 pa_sink_input_put(u->sink_input);
623 pa_sink_put(u->sink);
624 pa_sink_input_cork(u->sink_input, false);
625
626 pa_modargs_free(ma);
627
628 return 0;
629
630 fail:
631 if (ma)
632 pa_modargs_free(ma);
633
634 pa__done(m);
635
636 return -1;
637 }
638
pa__get_n_used(pa_module * m)639 int pa__get_n_used(pa_module *m) {
640 struct userdata *u;
641
642 pa_assert(m);
643 pa_assert_se(u = m->userdata);
644
645 return pa_sink_linked_by(u->sink);
646 }
647
pa__done(pa_module * m)648 void pa__done(pa_module*m) {
649 struct userdata *u;
650
651 pa_assert(m);
652
653 if (!(u = m->userdata))
654 return;
655
656 /* See comments in sink_input_kill_cb() above regarding
657 * destruction order! */
658
659 if (u->sink_input)
660 pa_sink_input_cork(u->sink_input, true);
661
662 if (u->sink)
663 pa_sink_unlink(u->sink);
664
665 if (u->sink_input) {
666 pa_sink_input_unlink(u->sink_input);
667 pa_sink_input_unref(u->sink_input);
668 }
669
670 if (u->sink)
671 pa_sink_unref(u->sink);
672
673 if (u->memblockq)
674 pa_memblockq_free(u->memblockq);
675
676 pa_xfree(u);
677 }
678