Fix up according to Coding Style
[pulseaudio-mirror.git] / src / modules / module-loopback.c
blob9a8640b11af0749bde3d4bd57b4432b962bcafbf
1 /***
2 This file is part of PulseAudio.
4 Copyright 2009 Intel Corporation
5 Contributor: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
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.
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.
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 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <stdio.h>
28 #include <math.h>
30 #include <pulse/xmalloc.h>
32 #include <pulsecore/sink-input.h>
33 #include <pulsecore/module.h>
34 #include <pulsecore/modargs.h>
35 #include <pulsecore/namereg.h>
36 #include <pulsecore/log.h>
37 #include <pulsecore/core-util.h>
39 #include <pulse/rtclock.h>
40 #include <pulse/timeval.h>
42 #include "module-loopback-symdef.h"
44 PA_MODULE_AUTHOR("Pierre-Louis Bossart");
45 PA_MODULE_DESCRIPTION("Loopback from source to sink");
46 PA_MODULE_VERSION(PACKAGE_VERSION);
47 PA_MODULE_LOAD_ONCE(FALSE);
48 PA_MODULE_USAGE(
49 "source=<source to connect to> "
50 "sink=<sink to connect to> "
51 "adjust_time=<how often to readjust rates in s> "
52 "latency_msec=<latency in ms> "
53 "format=<sample format> "
54 "rate=<sample rate> "
55 "channels=<number of channels> "
56 "channel_map=<channel map> "
57 "sink_input_name=<custom name for the sink input> "
58 "source_output_name=<custom name for the source output> "
59 "sink_input_role=<media.role for the sink input> "
60 "source_output_role=<media.role for the source output> "
61 "source_dont_move=<boolean> "
62 "sink_dont_move=<boolean>");
64 #define DEFAULT_LATENCY_MSEC 200
66 #define MEMBLOCKQ_MAXLENGTH (1024*1024*16)
68 #define DEFAULT_ADJUST_TIME_USEC (10*PA_USEC_PER_SEC)
70 struct userdata {
71 pa_core *core;
72 pa_module *module;
74 pa_sink_input *sink_input;
75 pa_source_output *source_output;
77 pa_asyncmsgq *asyncmsgq;
78 pa_memblockq *memblockq;
80 pa_rtpoll_item *rtpoll_item_read, *rtpoll_item_write;
82 pa_time_event *time_event;
83 pa_usec_t adjust_time;
85 int64_t recv_counter;
86 int64_t send_counter;
88 size_t skip;
89 pa_usec_t latency;
91 pa_bool_t in_pop;
92 size_t min_memblockq_length;
94 struct {
95 int64_t send_counter;
96 size_t source_output_buffer;
97 pa_usec_t source_latency;
99 int64_t recv_counter;
100 size_t sink_input_buffer;
101 pa_usec_t sink_latency;
103 size_t min_memblockq_length;
104 size_t max_request;
105 } latency_snapshot;
108 static const char* const valid_modargs[] = {
109 "source",
110 "sink",
111 "adjust_time",
112 "latency_msec",
113 "format",
114 "rate",
115 "channels",
116 "channel_map",
117 "sink_input_name",
118 "source_output_name",
119 "sink_input_role",
120 "source_output_role",
121 "source_dont_move",
122 "sink_dont_move",
123 NULL,
126 enum {
127 SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
128 SINK_INPUT_MESSAGE_REWIND,
129 SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT,
130 SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED
133 enum {
134 SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT
137 /* Called from main context */
138 static void teardown(struct userdata *u) {
139 pa_assert(u);
140 pa_assert_ctl_context();
142 if (u->sink_input)
143 pa_sink_input_unlink(u->sink_input);
145 if (u->source_output)
146 pa_source_output_unlink(u->source_output);
148 if (u->sink_input) {
149 pa_sink_input_unref(u->sink_input);
150 u->sink_input = NULL;
153 if (u->source_output) {
154 pa_source_output_unref(u->source_output);
155 u->source_output = NULL;
159 /* Called from main context */
160 static void adjust_rates(struct userdata *u) {
161 size_t buffer, fs;
162 uint32_t old_rate, base_rate, new_rate;
163 pa_usec_t buffer_latency;
165 pa_assert(u);
166 pa_assert_ctl_context();
168 pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
169 pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
171 buffer =
172 u->latency_snapshot.sink_input_buffer +
173 u->latency_snapshot.source_output_buffer;
175 if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter)
176 buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter);
177 else
178 buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter));
180 buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);
182 pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms",
183 (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
184 (double) buffer_latency / PA_USEC_PER_MSEC,
185 (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC,
186 ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC);
188 pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes",
189 u->latency_snapshot.max_request*2,
190 u->latency_snapshot.min_memblockq_length);
192 fs = pa_frame_size(&u->sink_input->sample_spec);
193 old_rate = u->sink_input->sample_spec.rate;
194 base_rate = u->source_output->sample_spec.rate;
196 if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2)
197 new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
198 else
199 new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
201 if (new_rate < (uint32_t) (base_rate*0.8) || new_rate > (uint32_t) (base_rate*1.25)) {
202 pa_log_warn("Sample rates too different, not adjusting (%u vs. %u).", base_rate, new_rate);
203 new_rate = base_rate;
204 } else {
205 if (base_rate < new_rate + 20 && new_rate < base_rate + 20)
206 new_rate = base_rate;
207 /* Do the adjustment in small steps; 2‰ can be considered inaudible */
208 if (new_rate < (uint32_t) (old_rate*0.998) || new_rate > (uint32_t) (old_rate*1.002)) {
209 pa_log_info("New rate of %u Hz not within 2‰ of %u Hz, forcing smaller adjustment", new_rate, old_rate);
210 new_rate = PA_CLAMP(new_rate, (uint32_t) (old_rate*0.998), (uint32_t) (old_rate*1.002));
214 pa_sink_input_set_rate(u->sink_input, new_rate);
215 pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate);
217 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
220 /* Called from main context */
221 static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
222 struct userdata *u = userdata;
224 pa_assert(u);
225 pa_assert(a);
226 pa_assert(u->time_event == e);
228 adjust_rates(u);
231 /* Called from input thread context */
232 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
233 struct userdata *u;
234 pa_memchunk copy;
236 pa_source_output_assert_ref(o);
237 pa_source_output_assert_io_context(o);
238 pa_assert_se(u = o->userdata);
240 if (u->skip > chunk->length) {
241 u->skip -= chunk->length;
242 return;
245 if (u->skip > 0) {
246 copy = *chunk;
247 copy.index += u->skip;
248 copy.length -= u->skip;
249 u->skip = 0;
251 chunk = &copy;
254 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, chunk, NULL);
255 u->send_counter += (int64_t) chunk->length;
258 /* Called from input thread context */
259 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
260 struct userdata *u;
262 pa_source_output_assert_ref(o);
263 pa_source_output_assert_io_context(o);
264 pa_assert_se(u = o->userdata);
266 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
267 u->send_counter -= (int64_t) nbytes;
270 /* Called from output thread context */
271 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
272 struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata;
274 switch (code) {
276 case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: {
277 size_t length;
279 length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq);
281 u->latency_snapshot.send_counter = u->send_counter;
282 u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length;
283 u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source);
285 return 0;
289 return pa_source_output_process_msg(obj, code, data, offset, chunk);
292 /* Called from output thread context */
293 static void source_output_attach_cb(pa_source_output *o) {
294 struct userdata *u;
296 pa_source_output_assert_ref(o);
297 pa_source_output_assert_io_context(o);
298 pa_assert_se(u = o->userdata);
300 u->rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
301 o->source->thread_info.rtpoll,
302 PA_RTPOLL_LATE,
303 u->asyncmsgq);
306 /* Called from output thread context */
307 static void source_output_detach_cb(pa_source_output *o) {
308 struct userdata *u;
310 pa_source_output_assert_ref(o);
311 pa_source_output_assert_io_context(o);
312 pa_assert_se(u = o->userdata);
314 if (u->rtpoll_item_write) {
315 pa_rtpoll_item_free(u->rtpoll_item_write);
316 u->rtpoll_item_write = NULL;
320 /* Called from output thread context */
321 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
322 struct userdata *u;
324 pa_source_output_assert_ref(o);
325 pa_source_output_assert_io_context(o);
326 pa_assert_se(u = o->userdata);
328 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
330 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
331 u->latency),
332 &o->sample_spec);
334 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
338 /* Called from main thread */
339 static void source_output_kill_cb(pa_source_output *o) {
340 struct userdata *u;
342 pa_source_output_assert_ref(o);
343 pa_assert_ctl_context();
344 pa_assert_se(u = o->userdata);
346 teardown(u);
347 pa_module_unload_request(u->module, TRUE);
350 /* Called from main thread */
351 static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
352 struct userdata *u;
354 pa_source_output_assert_ref(o);
355 pa_assert_ctl_context();
356 pa_assert_se(u = o->userdata);
358 return dest != u->sink_input->sink->monitor_source;
361 /* Called from main thread */
362 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
363 pa_proplist *p;
364 const char *n;
365 struct userdata *u;
367 pa_source_output_assert_ref(o);
368 pa_assert_ctl_context();
369 pa_assert_se(u = o->userdata);
371 p = pa_proplist_new();
372 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
374 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
375 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
377 pa_sink_input_update_proplist(u->sink_input, PA_UPDATE_REPLACE, p);
378 pa_proplist_free(p);
381 /* Called from output thread context */
382 static void update_min_memblockq_length(struct userdata *u) {
383 size_t length;
385 pa_assert(u);
386 pa_sink_input_assert_io_context(u->sink_input);
388 length = pa_memblockq_get_length(u->memblockq);
390 if (u->min_memblockq_length == (size_t) -1 ||
391 length < u->min_memblockq_length)
392 u->min_memblockq_length = length;
395 /* Called from output thread context */
396 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
397 struct userdata *u;
399 pa_sink_input_assert_ref(i);
400 pa_sink_input_assert_io_context(i);
401 pa_assert_se(u = i->userdata);
402 pa_assert(chunk);
404 u->in_pop = TRUE;
405 while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0)
407 u->in_pop = FALSE;
409 if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
410 pa_log_info("Coud not peek into queue");
411 return -1;
414 chunk->length = PA_MIN(chunk->length, nbytes);
415 pa_memblockq_drop(u->memblockq, chunk->length);
417 update_min_memblockq_length(u);
419 return 0;
422 /* Called from output thread context */
423 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
424 struct userdata *u;
426 pa_sink_input_assert_ref(i);
427 pa_sink_input_assert_io_context(i);
428 pa_assert_se(u = i->userdata);
430 pa_memblockq_rewind(u->memblockq, nbytes);
433 /* Called from output thread context */
434 static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
435 struct userdata *u = PA_SINK_INPUT(obj)->userdata;
437 switch (code) {
439 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
440 pa_usec_t *r = data;
442 pa_sink_input_assert_io_context(u->sink_input);
444 *r = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->sink_input->sample_spec);
446 /* Fall through, the default handler will add in the extra
447 * latency added by the resampler */
448 break;
451 case SINK_INPUT_MESSAGE_POST:
453 pa_sink_input_assert_io_context(u->sink_input);
455 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
456 pa_memblockq_push_align(u->memblockq, chunk);
457 else
458 pa_memblockq_flush_write(u->memblockq, TRUE);
460 update_min_memblockq_length(u);
462 /* Is this the end of an underrun? Then let's start things
463 * right-away */
464 if (!u->in_pop &&
465 u->sink_input->thread_info.underrun_for > 0 &&
466 pa_memblockq_is_readable(u->memblockq)) {
468 pa_log_debug("Requesting rewind due to end of underrun.");
469 pa_sink_input_request_rewind(u->sink_input,
470 (size_t) (u->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : u->sink_input->thread_info.underrun_for),
471 FALSE, TRUE, FALSE);
474 u->recv_counter += (int64_t) chunk->length;
476 return 0;
478 case SINK_INPUT_MESSAGE_REWIND:
480 pa_sink_input_assert_io_context(u->sink_input);
482 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
483 pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, TRUE);
484 else
485 pa_memblockq_flush_write(u->memblockq, TRUE);
487 u->recv_counter -= offset;
489 update_min_memblockq_length(u);
491 return 0;
493 case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
494 size_t length;
496 update_min_memblockq_length(u);
498 length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
500 u->latency_snapshot.recv_counter = u->recv_counter;
501 u->latency_snapshot.sink_input_buffer =
502 pa_memblockq_get_length(u->memblockq) +
503 (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, length) : length);
504 u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink);
506 u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
508 u->latency_snapshot.min_memblockq_length = u->min_memblockq_length;
509 u->min_memblockq_length = (size_t) -1;
511 return 0;
514 case SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED: {
515 /* This message is sent from the IO thread to the main
516 * thread! So don't be confused. All the user cases above
517 * are executed in thread context, but this one is not! */
519 pa_assert_ctl_context();
521 if (u->adjust_time > 0)
522 adjust_rates(u);
523 return 0;
527 return pa_sink_input_process_msg(obj, code, data, offset, chunk);
530 /* Called from output thread context */
531 static void sink_input_attach_cb(pa_sink_input *i) {
532 struct userdata *u;
534 pa_sink_input_assert_ref(i);
535 pa_sink_input_assert_io_context(i);
536 pa_assert_se(u = i->userdata);
538 u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
539 i->sink->thread_info.rtpoll,
540 PA_RTPOLL_LATE,
541 u->asyncmsgq);
543 pa_memblockq_set_prebuf(u->memblockq, pa_sink_input_get_max_request(i)*2);
544 pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i));
546 u->min_memblockq_length = (size_t) -1;
549 /* Called from output thread context */
550 static void sink_input_detach_cb(pa_sink_input *i) {
551 struct userdata *u;
553 pa_sink_input_assert_ref(i);
554 pa_sink_input_assert_io_context(i);
555 pa_assert_se(u = i->userdata);
557 if (u->rtpoll_item_read) {
558 pa_rtpoll_item_free(u->rtpoll_item_read);
559 u->rtpoll_item_read = NULL;
563 /* Called from output thread context */
564 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
565 struct userdata *u;
567 pa_sink_input_assert_ref(i);
568 pa_sink_input_assert_io_context(i);
569 pa_assert_se(u = i->userdata);
571 pa_memblockq_set_maxrewind(u->memblockq, nbytes);
574 /* Called from output thread context */
575 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
576 struct userdata *u;
578 pa_sink_input_assert_ref(i);
579 pa_sink_input_assert_io_context(i);
580 pa_assert_se(u = i->userdata);
582 pa_memblockq_set_prebuf(u->memblockq, nbytes*2);
583 pa_log_info("Max request changed");
584 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED, NULL, 0, NULL, NULL);
587 /* Called from main thread */
588 static void sink_input_kill_cb(pa_sink_input *i) {
589 struct userdata *u;
591 pa_sink_input_assert_ref(i);
592 pa_assert_ctl_context();
593 pa_assert_se(u = i->userdata);
595 teardown(u);
596 pa_module_unload_request(u->module, TRUE);
599 /* Called from main thread */
600 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
601 struct userdata *u;
602 pa_proplist *p;
603 const char *n;
605 pa_sink_input_assert_ref(i);
606 pa_assert_ctl_context();
607 pa_assert_se(u = i->userdata);
609 p = pa_proplist_new();
610 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
612 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
613 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
615 pa_source_output_update_proplist(u->source_output, PA_UPDATE_REPLACE, p);
616 pa_proplist_free(p);
619 /* Called from main thread */
620 static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
621 struct userdata *u;
623 pa_sink_input_assert_ref(i);
624 pa_assert_ctl_context();
625 pa_assert_se(u = i->userdata);
627 if (!u->source_output->source->monitor_of)
628 return TRUE;
630 return dest != u->source_output->source->monitor_of;
633 int pa__init(pa_module *m) {
634 pa_modargs *ma = NULL;
635 struct userdata *u;
636 pa_sink *sink;
637 pa_sink_input_new_data sink_input_data;
638 pa_bool_t sink_dont_move;
639 pa_source *source;
640 pa_source_output_new_data source_output_data;
641 pa_bool_t source_dont_move;
642 uint32_t latency_msec;
643 pa_sample_spec ss;
644 pa_channel_map map;
645 pa_memchunk silence;
646 uint32_t adjust_time_sec;
647 const char *n;
649 pa_assert(m);
651 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
652 pa_log("Failed to parse module arguments");
653 goto fail;
656 if (!(source = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) {
657 pa_log("No such source.");
658 goto fail;
661 if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) {
662 pa_log("No such sink.");
663 goto fail;
666 ss = sink->sample_spec;
667 map = sink->channel_map;
668 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
669 pa_log("Invalid sample format specification or channel map");
670 goto fail;
673 latency_msec = DEFAULT_LATENCY_MSEC;
674 if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 2000) {
675 pa_log("Invalid latency specification");
676 goto fail;
679 m->userdata = u = pa_xnew0(struct userdata, 1);
680 u->core = m->core;
681 u->module = m;
682 u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC;
684 adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
685 if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) {
686 pa_log("Failed to parse adjust_time value");
687 goto fail;
690 if (adjust_time_sec != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC)
691 u->adjust_time = adjust_time_sec * PA_USEC_PER_SEC;
692 else
693 u->adjust_time = DEFAULT_ADJUST_TIME_USEC;
695 pa_sink_input_new_data_init(&sink_input_data);
696 sink_input_data.driver = __FILE__;
697 sink_input_data.module = m;
698 sink_input_data.sink = sink;
700 if ((n = pa_modargs_get_value(ma, "sink_input_name", NULL)))
701 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, n);
702 else
703 pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback from %s",
704 pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
706 if ((n = pa_modargs_get_value(ma, "sink_input_role", NULL)))
707 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, n);
708 else
709 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
711 if ((n = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)))
712 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
714 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
715 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
716 sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE;
718 sink_dont_move = FALSE;
719 if (pa_modargs_get_value_boolean(ma, "sink_dont_move", &sink_dont_move) < 0) {
720 pa_log("sink_dont_move= expects a boolean argument.");
721 goto fail;
724 if (sink_dont_move)
725 sink_input_data.flags |= PA_SINK_INPUT_DONT_MOVE;
727 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
728 pa_sink_input_new_data_done(&sink_input_data);
730 if (!u->sink_input)
731 goto fail;
733 u->sink_input->parent.process_msg = sink_input_process_msg_cb;
734 u->sink_input->pop = sink_input_pop_cb;
735 u->sink_input->process_rewind = sink_input_process_rewind_cb;
736 u->sink_input->kill = sink_input_kill_cb;
737 u->sink_input->attach = sink_input_attach_cb;
738 u->sink_input->detach = sink_input_detach_cb;
739 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
740 u->sink_input->update_max_request = sink_input_update_max_request_cb;
741 u->sink_input->may_move_to = sink_input_may_move_to_cb;
742 u->sink_input->moving = sink_input_moving_cb;
743 u->sink_input->userdata = u;
745 pa_sink_input_set_requested_latency(u->sink_input, u->latency/3);
747 pa_source_output_new_data_init(&source_output_data);
748 source_output_data.driver = __FILE__;
749 source_output_data.module = m;
750 source_output_data.source = source;
752 if ((n = pa_modargs_get_value(ma, "source_output_name", NULL)))
753 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, n);
754 else
755 pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s",
756 pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
758 if ((n = pa_modargs_get_value(ma, "source_output_role", NULL)))
759 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, n);
760 else
761 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
763 if ((n = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)))
764 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
766 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
767 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
768 source_output_data.flags = (pa_source_output_flags_t)0;
770 source_dont_move = FALSE;
771 if (pa_modargs_get_value_boolean(ma, "source_dont_move", &source_dont_move) < 0) {
772 pa_log("source_dont_move= expects a boolean argument.");
773 goto fail;
776 if (source_dont_move)
777 source_output_data.flags |= PA_SOURCE_OUTPUT_DONT_MOVE;
779 pa_source_output_new(&u->source_output, m->core, &source_output_data);
780 pa_source_output_new_data_done(&source_output_data);
782 if (!u->source_output)
783 goto fail;
785 u->source_output->parent.process_msg = source_output_process_msg_cb;
786 u->source_output->push = source_output_push_cb;
787 u->source_output->process_rewind = source_output_process_rewind_cb;
788 u->source_output->kill = source_output_kill_cb;
789 u->source_output->attach = source_output_attach_cb;
790 u->source_output->detach = source_output_detach_cb;
791 u->source_output->state_change = source_output_state_change_cb;
792 u->source_output->may_move_to = source_output_may_move_to_cb;
793 u->source_output->moving = source_output_moving_cb;
794 u->source_output->userdata = u;
796 pa_source_output_set_requested_latency(u->source_output, u->latency/3);
798 pa_sink_input_get_silence(u->sink_input, &silence);
799 u->memblockq = pa_memblockq_new(
800 0, /* idx */
801 MEMBLOCKQ_MAXLENGTH, /* maxlength */
802 MEMBLOCKQ_MAXLENGTH, /* tlength */
803 pa_frame_size(&ss), /* base */
804 0, /* prebuf */
805 0, /* minreq */
806 0, /* maxrewind */
807 &silence); /* silence frame */
808 pa_memblock_unref(silence.memblock);
810 u->asyncmsgq = pa_asyncmsgq_new(0);
812 pa_sink_input_put(u->sink_input);
813 pa_source_output_put(u->source_output);
815 if (u->adjust_time > 0)
816 u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u);
818 pa_modargs_free(ma);
819 return 0;
821 fail:
822 if (ma)
823 pa_modargs_free(ma);
825 pa__done(m);
827 return -1;
830 void pa__done(pa_module*m) {
831 struct userdata *u;
833 pa_assert(m);
835 if (!(u = m->userdata))
836 return;
838 teardown(u);
840 if (u->memblockq)
841 pa_memblockq_free(u->memblockq);
843 if (u->asyncmsgq)
844 pa_asyncmsgq_unref(u->asyncmsgq);
846 if (u->time_event)
847 u->core->mainloop->time_free(u->time_event);
849 pa_xfree(u);