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 <stdio.h>
26
27#include <pulse/xmalloc.h>
28
29#include <pulsecore/i18n.h>
30#include <pulsecore/macro.h>
31#include <pulsecore/namereg.h>
32#include <pulsecore/sink.h>
33#include <pulsecore/module.h>
34#include <pulsecore/core-util.h>
35#include <pulsecore/modargs.h>
36#include <pulsecore/log.h>
37#include <pulsecore/rtpoll.h>
38#include <pulsecore/sample-util.h>
39#include <pulsecore/ltdl-helper.h>
40#include <pulsecore/mix.h>
41#include <pulsecore/rtpoll.h>
42
43PA_MODULE_AUTHOR("Pierre-Louis Bossart");
44PA_MODULE_DESCRIPTION("Virtual source");
45PA_MODULE_VERSION(PACKAGE_VERSION);
46PA_MODULE_LOAD_ONCE(false);
47PA_MODULE_USAGE(
48        _("source_name=<name for the source> "
49          "source_properties=<properties for the source> "
50          "master=<name of source to filter> "
51          "uplink_sink=<name> (optional)"
52          "format=<sample format> "
53          "rate=<sample rate> "
54          "channels=<number of channels> "
55          "channel_map=<channel map> "
56          "use_volume_sharing=<yes or no> "
57          "force_flat_volume=<yes or no> "
58        ));
59
60#define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
61#define BLOCK_USEC 1000 /* FIXME */
62
63struct userdata {
64    pa_module *module;
65
66    /* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */
67    /* bool autoloaded; */
68
69    pa_source *source;
70    pa_source_output *source_output;
71
72    pa_memblockq *memblockq;
73
74    bool auto_desc;
75    unsigned channels;
76
77    /* optional fields for uplink sink */
78    pa_sink *sink;
79    pa_usec_t block_usec;
80    pa_memblockq *sink_memblockq;
81    pa_rtpoll *rtpoll;
82
83};
84
85static const char* const valid_modargs[] = {
86    "source_name",
87    "source_properties",
88    "master",
89    "uplink_sink",
90    "format",
91    "rate",
92    "channels",
93    "channel_map",
94    "use_volume_sharing",
95    "force_flat_volume",
96    NULL
97};
98
99/* Called from I/O thread context */
100static 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            *((int64_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 */
116static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause) {
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_log_debug("Resuming source %s, because its uplink sink became active.", u->source->name);
129        pa_source_suspend(u->source, false, PA_SUSPEND_ALL);
130
131        /* FIXME: if there's no client connected, the source will suspend
132           and playback will be stuck. You'd want to prevent the source from
133           sleeping when the uplink sink is active; even if the audio is
134           discarded at least the app isn't stuck */
135
136    } else {
137        /* nothing to do, if the sink becomes idle or suspended let
138           module-suspend-idle handle the sources later */
139    }
140
141    return 0;
142}
143
144static void sink_update_requested_latency_cb(pa_sink *s) {
145    struct userdata *u;
146
147    pa_sink_assert_ref(s);
148    pa_assert_se(u = s->userdata);
149
150    /* FIXME: there's no latency support */
151
152}
153
154/* Called from I/O thread context */
155static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
156    struct userdata *u = PA_SOURCE(o)->userdata;
157
158    switch (code) {
159
160        case PA_SOURCE_MESSAGE_GET_LATENCY:
161
162            /* The source is _put() before the source output is, so let's
163             * make sure we don't access it in that time. Also, the
164             * source output is first shut down, the source second. */
165            if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
166                !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) {
167                *((pa_usec_t*) data) = 0;
168                return 0;
169            }
170
171            *((pa_usec_t*) data) =
172
173                /* Get the latency of the master source */
174                pa_source_get_latency_within_thread(u->source_output->source, true) +
175
176                /* Add the latency internal to our source output on top */
177                /* FIXME, no idea what I am doing here */
178                pa_bytes_to_usec(pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq), &u->source_output->source->sample_spec);
179
180            /* Add resampler delay */
181            *((int64_t*) data) += pa_resampler_get_delay_usec(u->source_output->thread_info.resampler);
182
183            return 0;
184    }
185
186    return pa_source_process_msg(o, code, data, offset, chunk);
187}
188
189/* Called from main context */
190static int source_set_state_in_main_thread_cb(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause) {
191    struct userdata *u;
192
193    pa_source_assert_ref(s);
194    pa_assert_se(u = s->userdata);
195
196    if (!PA_SOURCE_IS_LINKED(state) ||
197        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state))
198        return 0;
199
200    pa_source_output_cork(u->source_output, state == PA_SOURCE_SUSPENDED);
201    return 0;
202}
203
204/* Called from I/O thread context */
205static void source_update_requested_latency_cb(pa_source *s) {
206    struct userdata *u;
207
208    pa_source_assert_ref(s);
209    pa_assert_se(u = s->userdata);
210
211    if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
212        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
213        return;
214
215    /* Just hand this one over to the master source */
216    pa_source_output_set_requested_latency_within_thread(
217            u->source_output,
218            pa_source_get_requested_latency_within_thread(s));
219}
220
221/* Called from main context */
222static void source_set_volume_cb(pa_source *s) {
223    struct userdata *u;
224
225    pa_source_assert_ref(s);
226    pa_assert_se(u = s->userdata);
227
228    if (!PA_SOURCE_IS_LINKED(s->state) ||
229        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state))
230        return;
231
232    pa_source_output_set_volume(u->source_output, &s->real_volume, s->save_volume, true);
233}
234
235/* Called from main context */
236static void source_set_mute_cb(pa_source *s) {
237    struct userdata *u;
238
239    pa_source_assert_ref(s);
240    pa_assert_se(u = s->userdata);
241
242    if (!PA_SOURCE_IS_LINKED(s->state) ||
243        !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state))
244        return;
245
246    pa_source_output_set_mute(u->source_output, s->muted, s->save_muted);
247}
248
249/* Called from input thread context */
250static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
251    struct userdata *u;
252
253    pa_source_output_assert_ref(o);
254    pa_source_output_assert_io_context(o);
255    pa_assert_se(u = o->userdata);
256
257    if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state))
258        return;
259
260    if (!PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) {
261        pa_log("push when no link?");
262        return;
263    }
264
265    /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */
266
267    /* if uplink sink exists, pull data from there; simplify by using
268       same length as chunk provided by source */
269    if (u->sink && (u->sink->thread_info.state == PA_SINK_RUNNING)) {
270        pa_memchunk tchunk;
271        size_t nbytes = chunk->length;
272        pa_mix_info streams[2];
273        pa_memchunk target_chunk;
274        void *target;
275        int ch;
276
277        /* Hmm, process any rewind request that might be queued up */
278        pa_sink_process_rewind(u->sink, 0);
279
280        /* get data from the sink */
281        while (pa_memblockq_peek(u->sink_memblockq, &tchunk) < 0) {
282            pa_memchunk nchunk;
283
284            /* make sure we get nbytes from the sink with render_full,
285               otherwise we cannot mix with the uplink */
286            pa_sink_render_full(u->sink, nbytes, &nchunk);
287            pa_memblockq_push(u->sink_memblockq, &nchunk);
288            pa_memblock_unref(nchunk.memblock);
289        }
290        pa_assert(tchunk.length == chunk->length);
291
292        /* move the read pointer for sink memblockq */
293        pa_memblockq_drop(u->sink_memblockq, tchunk.length);
294
295        /* allocate target chunk */
296        /* this could probably be done in-place, but having chunk as both
297           the input and output creates issues with reference counts */
298        target_chunk.index = 0;
299        target_chunk.length = chunk->length;
300        pa_assert(target_chunk.length == chunk->length);
301
302        target_chunk.memblock = pa_memblock_new(o->source->core->mempool,
303                                                target_chunk.length);
304        pa_assert( target_chunk.memblock );
305
306        /* get target pointer */
307        target = pa_memblock_acquire_chunk(&target_chunk);
308
309        /* set-up mixing structure
310           volume was taken care of in sink and source already */
311        streams[0].chunk = *chunk;
312        for(ch=0;ch<o->sample_spec.channels;ch++)
313            streams[0].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
314        streams[0].volume.channels = o->sample_spec.channels;
315
316        streams[1].chunk = tchunk;
317        for(ch=0;ch<o->sample_spec.channels;ch++)
318            streams[1].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
319        streams[1].volume.channels = o->sample_spec.channels;
320
321        /* do mixing */
322        pa_mix(streams,                /* 2 streams to be mixed */
323               2,
324               target,                 /* put result in target chunk */
325               chunk->length,          /* same length as input */
326               (const pa_sample_spec *)&o->sample_spec, /* same sample spec for input and output */
327               NULL,                   /* no volume information */
328               false);                 /* no mute */
329
330        pa_memblock_release(target_chunk.memblock);
331        pa_memblock_unref(tchunk.memblock); /* clean-up */
332
333        /* forward the data to the virtual source */
334        pa_source_post(u->source, &target_chunk);
335
336        pa_memblock_unref(target_chunk.memblock); /* clean-up */
337
338    } else {
339        /* forward the data to the virtual source */
340        pa_source_post(u->source, chunk);
341    }
342
343}
344
345/* Called from input thread context */
346static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
347    struct userdata *u;
348
349    pa_source_output_assert_ref(o);
350    pa_source_output_assert_io_context(o);
351    pa_assert_se(u = o->userdata);
352
353    /* If the source is not yet linked, there is nothing to rewind */
354    if (PA_SOURCE_IS_LINKED(u->source->thread_info.state))
355        pa_source_process_rewind(u->source, nbytes);
356
357    /* FIXME, no idea what I am doing here */
358#if 0
359    pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
360    u->send_counter -= (int64_t) nbytes;
361#endif
362}
363
364/* Called from output thread context */
365static void source_output_update_max_rewind_cb(pa_source_output *o, size_t nbytes) {
366    struct userdata *u;
367
368    pa_source_output_assert_ref(o);
369    pa_source_output_assert_io_context(o);
370    pa_assert_se(u = o->userdata);
371
372    pa_source_set_max_rewind_within_thread(u->source, nbytes);
373}
374
375/* Called from output thread context */
376static void source_output_attach_cb(pa_source_output *o) {
377    struct userdata *u;
378
379    pa_source_output_assert_ref(o);
380    pa_source_output_assert_io_context(o);
381    pa_assert_se(u = o->userdata);
382
383    pa_source_set_rtpoll(u->source, o->source->thread_info.rtpoll);
384    pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
385    pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency);
386    pa_source_set_max_rewind_within_thread(u->source, pa_source_output_get_max_rewind(o));
387
388    if (PA_SOURCE_IS_LINKED(u->source->thread_info.state))
389        pa_source_attach_within_thread(u->source);
390}
391
392/* Called from output thread context */
393static void source_output_detach_cb(pa_source_output *o) {
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    if (PA_SOURCE_IS_LINKED(u->source->thread_info.state))
401        pa_source_detach_within_thread(u->source);
402    pa_source_set_rtpoll(u->source, NULL);
403}
404
405/* Called from output thread context except when cork() is called without valid source.*/
406static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
407    struct userdata *u;
408
409    pa_source_output_assert_ref(o);
410    pa_assert_se(u = o->userdata);
411
412    /* FIXME */
413#if 0
414    if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT && o->source) {
415
416        u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source, false),
417                                               u->latency),
418                                   &o->sample_spec);
419
420        pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
421    }
422#endif
423}
424
425/* Called from main thread */
426static void source_output_kill_cb(pa_source_output *o) {
427    struct userdata *u;
428
429    pa_source_output_assert_ref(o);
430    pa_assert_ctl_context();
431    pa_assert_se(u = o->userdata);
432
433    /* The order here matters! We first kill the source so that streams
434     * can properly be moved away while the source output is still connected
435     * to the master. */
436    pa_source_output_cork(u->source_output, true);
437    pa_source_unlink(u->source);
438    pa_source_output_unlink(u->source_output);
439
440    pa_source_output_unref(u->source_output);
441    u->source_output = NULL;
442
443    pa_source_unref(u->source);
444    u->source = NULL;
445
446    pa_module_unload_request(u->module, true);
447}
448
449/* Called from main thread */
450static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
451    struct userdata *u;
452    uint32_t idx;
453    pa_source_output *output;
454
455    pa_source_output_assert_ref(o);
456    pa_assert_ctl_context();
457    pa_assert_se(u = o->userdata);
458
459    if (dest) {
460        pa_source_set_asyncmsgq(u->source, dest->asyncmsgq);
461        pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags);
462    } else
463        pa_source_set_asyncmsgq(u->source, NULL);
464
465    /* Propagate asyncmsq change to attached virtual sources */
466    PA_IDXSET_FOREACH(output, u->source->outputs, idx) {
467        if (output->destination_source && output->moving)
468            output->moving(output, u->source);
469    }
470
471    if (u->auto_desc && dest) {
472        const char *z;
473        pa_proplist *pl;
474
475        pl = pa_proplist_new();
476        z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
477        pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s",
478                         pa_proplist_gets(u->source->proplist, "device.vsource.name"), z ? z : dest->name);
479
480        pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
481        pa_proplist_free(pl);
482    }
483}
484
485int pa__init(pa_module*m) {
486    struct userdata *u;
487    pa_sample_spec ss;
488    pa_channel_map map;
489    pa_modargs *ma;
490    pa_source *master=NULL;
491    pa_source_output_new_data source_output_data;
492    pa_source_new_data source_data;
493    bool use_volume_sharing = true;
494    bool force_flat_volume = false;
495
496    /* optional for uplink_sink */
497    pa_sink_new_data sink_data;
498    size_t nbytes;
499
500    pa_assert(m);
501
502    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
503        pa_log("Failed to parse module arguments.");
504        goto fail;
505    }
506
507    if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) {
508        pa_log("Master source not found");
509        goto fail;
510    }
511
512    pa_assert(master);
513
514    ss = master->sample_spec;
515    ss.format = PA_SAMPLE_FLOAT32;
516    map = master->channel_map;
517    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
518        pa_log("Invalid sample format specification or channel map");
519        goto fail;
520    }
521
522    if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
523        pa_log("use_volume_sharing= expects a boolean argument");
524        goto fail;
525    }
526
527    if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) {
528        pa_log("force_flat_volume= expects a boolean argument");
529        goto fail;
530    }
531
532    if (use_volume_sharing && force_flat_volume) {
533        pa_log("Flat volume can't be forced when using volume sharing.");
534        goto fail;
535    }
536
537    u = pa_xnew0(struct userdata, 1);
538    u->module = m;
539    m->userdata = u;
540    u->memblockq = pa_memblockq_new("module-virtual-source memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
541    if (!u->memblockq) {
542        pa_log("Failed to create source memblockq.");
543        goto fail;
544    }
545    u->channels = ss.channels;
546
547    /* The rtpoll created here is never run. It is only necessary to avoid crashes
548     * when module-virtual-source is used together with module-loopback or
549     * module-combine-sink. Both modules base their asyncmsq on the rtpoll provided
550     * by the sink. module-loopback and combine-sink only work because they
551     * call pa_asyncmsq_process_one() themselves. */
552    u->rtpoll = pa_rtpoll_new();
553
554    /* Create source */
555    pa_source_new_data_init(&source_data);
556    source_data.driver = __FILE__;
557    source_data.module = m;
558    if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
559        source_data.name = pa_sprintf_malloc("%s.vsource", master->name);
560    pa_source_new_data_set_sample_spec(&source_data, &ss);
561    pa_source_new_data_set_channel_map(&source_data, &map);
562    pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
563    pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
564    pa_proplist_sets(source_data.proplist, "device.vsource.name", source_data.name);
565
566    if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
567        pa_log("Invalid properties");
568        pa_source_new_data_done(&source_data);
569        goto fail;
570    }
571
572    if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
573        const char *z;
574
575        z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
576        pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s", source_data.name, z ? z : master->name);
577    }
578
579    u->source = pa_source_new(m->core, &source_data, (master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY))
580                                                     | (use_volume_sharing ? PA_SOURCE_SHARE_VOLUME_WITH_MASTER : 0));
581
582    pa_source_new_data_done(&source_data);
583
584    if (!u->source) {
585        pa_log("Failed to create source.");
586        goto fail;
587    }
588
589    u->source->parent.process_msg = source_process_msg_cb;
590    u->source->set_state_in_main_thread = source_set_state_in_main_thread_cb;
591    u->source->update_requested_latency = source_update_requested_latency_cb;
592    pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
593    if (!use_volume_sharing) {
594        pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
595        pa_source_enable_decibel_volume(u->source, true);
596    }
597    /* Normally this flag would be enabled automatically be we can force it. */
598    if (force_flat_volume)
599        u->source->flags |= PA_SOURCE_FLAT_VOLUME;
600    u->source->userdata = u;
601
602    pa_source_set_asyncmsgq(u->source, master->asyncmsgq);
603
604    /* Create source output */
605    pa_source_output_new_data_init(&source_output_data);
606    source_output_data.driver = __FILE__;
607    source_output_data.module = m;
608    pa_source_output_new_data_set_source(&source_output_data, master, false, true);
609    source_output_data.destination_source = u->source;
610
611    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));
612    pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
613    pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
614    pa_source_output_new_data_set_channel_map(&source_output_data, &map);
615    source_output_data.flags |= PA_SOURCE_OUTPUT_START_CORKED;
616
617    pa_source_output_new(&u->source_output, m->core, &source_output_data);
618    pa_source_output_new_data_done(&source_output_data);
619
620    if (!u->source_output)
621        goto fail;
622
623    u->source_output->push = source_output_push_cb;
624    u->source_output->process_rewind = source_output_process_rewind_cb;
625    u->source_output->update_max_rewind = source_output_update_max_rewind_cb;
626    u->source_output->kill = source_output_kill_cb;
627    u->source_output->attach = source_output_attach_cb;
628    u->source_output->detach = source_output_detach_cb;
629    u->source_output->state_change = source_output_state_change_cb;
630    u->source_output->moving = source_output_moving_cb;
631    u->source_output->userdata = u;
632
633    u->source->output_from_master = u->source_output;
634
635    /* The order here is important. The output must be put first,
636     * otherwise streams might attach to the source before the
637     * source output is attached to the master. */
638    pa_source_output_put(u->source_output);
639    pa_source_put(u->source);
640    pa_source_output_cork(u->source_output, false);
641
642    /* Create optional uplink sink */
643    pa_sink_new_data_init(&sink_data);
644    sink_data.driver = __FILE__;
645    sink_data.module = m;
646    if ((sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "uplink_sink", NULL)))) {
647        pa_sink_new_data_set_sample_spec(&sink_data, &ss);
648        pa_sink_new_data_set_channel_map(&sink_data, &map);
649        pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
650        pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "uplink sink");
651        pa_proplist_sets(sink_data.proplist, "device.uplink_sink.name", sink_data.name);
652
653        if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
654            const char *z;
655
656            z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
657            pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Uplink Sink %s on %s", sink_data.name, z ? z : master->name);
658        }
659
660        u->sink_memblockq = pa_memblockq_new("module-virtual-source sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
661        if (!u->sink_memblockq) {
662            pa_sink_new_data_done(&sink_data);
663            pa_log("Failed to create sink memblockq.");
664            goto fail;
665        }
666
667        u->sink = pa_sink_new(m->core, &sink_data, 0);  /* FIXME, sink has no capabilities */
668        pa_sink_new_data_done(&sink_data);
669
670        if (!u->sink) {
671            pa_log("Failed to create sink.");
672            goto fail;
673        }
674
675        u->sink->parent.process_msg = sink_process_msg_cb;
676        u->sink->update_requested_latency = sink_update_requested_latency_cb;
677        u->sink->set_state_in_main_thread = sink_set_state_in_main_thread_cb;
678        u->sink->userdata = u;
679
680        pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
681        pa_sink_set_rtpoll(u->sink, u->rtpoll);
682
683        /* FIXME: no idea what I am doing here */
684        u->block_usec = BLOCK_USEC;
685        nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
686        pa_sink_set_max_rewind(u->sink, 0);
687        pa_sink_set_max_request(u->sink, nbytes);
688
689        pa_sink_put(u->sink);
690    } else {
691        pa_sink_new_data_done(&sink_data);
692        /* optional uplink sink not enabled */
693        u->sink = NULL;
694    }
695
696    pa_modargs_free(ma);
697
698    return 0;
699
700fail:
701    if (ma)
702        pa_modargs_free(ma);
703
704    pa__done(m);
705
706    return -1;
707}
708
709int pa__get_n_used(pa_module *m) {
710    struct userdata *u;
711
712    pa_assert(m);
713    pa_assert_se(u = m->userdata);
714
715    return pa_source_linked_by(u->source);
716}
717
718void pa__done(pa_module*m) {
719    struct userdata *u;
720
721    pa_assert(m);
722
723    if (!(u = m->userdata))
724        return;
725
726    /* See comments in source_output_kill_cb() above regarding
727     * destruction order! */
728
729    if (u->source_output)
730        pa_source_output_cork(u->source_output, true);
731
732    if (u->source)
733        pa_source_unlink(u->source);
734
735    if (u->source_output) {
736        pa_source_output_unlink(u->source_output);
737        pa_source_output_unref(u->source_output);
738    }
739
740    if (u->source)
741        pa_source_unref(u->source);
742
743    if (u->sink) {
744        pa_sink_unlink(u->sink);
745        pa_sink_unref(u->sink);
746    }
747
748    if (u->memblockq)
749        pa_memblockq_free(u->memblockq);
750
751    if (u->sink_memblockq)
752        pa_memblockq_free(u->sink_memblockq);
753
754    if (u->rtpoll)
755        pa_rtpoll_free(u->rtpoll);
756
757    pa_xfree(u);
758}
759