build-sys: Use ax_check_flag macros from autoconf archive
[pulseaudio-mirror.git] / src / modules / module-loopback.c
blobcf88267d8a21d94aa9a9456251ac036da22724cf
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>
29 #include <pulse/xmalloc.h>
31 #include <pulsecore/sink-input.h>
32 #include <pulsecore/module.h>
33 #include <pulsecore/modargs.h>
34 #include <pulsecore/namereg.h>
35 #include <pulsecore/log.h>
36 #include <pulsecore/core-util.h>
38 #include <pulse/rtclock.h>
39 #include <pulse/timeval.h>
41 #include "module-loopback-symdef.h"
43 PA_MODULE_AUTHOR("Pierre-Louis Bossart");
44 PA_MODULE_DESCRIPTION("Loopback from source to sink");
45 PA_MODULE_VERSION(PACKAGE_VERSION);
46 PA_MODULE_LOAD_ONCE(FALSE);
47 PA_MODULE_USAGE(
48 "source=<source to connect to> "
49 "sink=<sink to connect to> "
50 "adjust_time=<how often to readjust rates in s> "
51 "latency_msec=<latency in ms> "
52 "format=<sample format> "
53 "rate=<sample rate> "
54 "channels=<number of channels> "
55 "channel_map=<channel map> "
56 "sink_input_name=<custom name for the sink input> "
57 "source_output_name=<custom name for the source output> "
58 "sink_input_role=<media.role for the sink input> "
59 "source_output_role=<media.role for the source output> "
60 "source_dont_move=<boolean> "
61 "sink_dont_move=<boolean> "
62 "remix=<remix channels?> ");
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 "remix",
124 NULL,
127 enum {
128 SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
129 SINK_INPUT_MESSAGE_REWIND,
130 SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT,
131 SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED
134 enum {
135 SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT
138 /* Called from main context */
139 static void teardown(struct userdata *u) {
140 pa_assert(u);
141 pa_assert_ctl_context();
143 if (u->sink_input)
144 pa_sink_input_unlink(u->sink_input);
146 if (u->source_output)
147 pa_source_output_unlink(u->source_output);
149 if (u->sink_input) {
150 pa_sink_input_unref(u->sink_input);
151 u->sink_input = NULL;
154 if (u->source_output) {
155 pa_source_output_unref(u->source_output);
156 u->source_output = NULL;
160 /* Called from main context */
161 static void adjust_rates(struct userdata *u) {
162 size_t buffer, fs;
163 uint32_t old_rate, base_rate, new_rate;
164 pa_usec_t buffer_latency;
166 pa_assert(u);
167 pa_assert_ctl_context();
169 pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
170 pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
172 buffer =
173 u->latency_snapshot.sink_input_buffer +
174 u->latency_snapshot.source_output_buffer;
176 if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter)
177 buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter);
178 else
179 buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter));
181 buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);
183 pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms",
184 (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
185 (double) buffer_latency / PA_USEC_PER_MSEC,
186 (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC,
187 ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC);
189 pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes",
190 u->latency_snapshot.max_request*2,
191 u->latency_snapshot.min_memblockq_length);
193 fs = pa_frame_size(&u->sink_input->sample_spec);
194 old_rate = u->sink_input->sample_spec.rate;
195 base_rate = u->source_output->sample_spec.rate;
197 if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2)
198 new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
199 else
200 new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
202 if (new_rate < (uint32_t) (base_rate*0.8) || new_rate > (uint32_t) (base_rate*1.25)) {
203 pa_log_warn("Sample rates too different, not adjusting (%u vs. %u).", base_rate, new_rate);
204 new_rate = base_rate;
205 } else {
206 if (base_rate < new_rate + 20 && new_rate < base_rate + 20)
207 new_rate = base_rate;
208 /* Do the adjustment in small steps; 2‰ can be considered inaudible */
209 if (new_rate < (uint32_t) (old_rate*0.998) || new_rate > (uint32_t) (old_rate*1.002)) {
210 pa_log_info("New rate of %u Hz not within 2‰ of %u Hz, forcing smaller adjustment", new_rate, old_rate);
211 new_rate = PA_CLAMP(new_rate, (uint32_t) (old_rate*0.998), (uint32_t) (old_rate*1.002));
215 pa_sink_input_set_rate(u->sink_input, new_rate);
216 pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate);
218 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
221 /* Called from main context */
222 static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
223 struct userdata *u = userdata;
225 pa_assert(u);
226 pa_assert(a);
227 pa_assert(u->time_event == e);
229 adjust_rates(u);
232 /* Called from input thread context */
233 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
234 struct userdata *u;
235 pa_memchunk copy;
237 pa_source_output_assert_ref(o);
238 pa_source_output_assert_io_context(o);
239 pa_assert_se(u = o->userdata);
241 if (u->skip > chunk->length) {
242 u->skip -= chunk->length;
243 return;
246 if (u->skip > 0) {
247 copy = *chunk;
248 copy.index += u->skip;
249 copy.length -= u->skip;
250 u->skip = 0;
252 chunk = &copy;
255 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, chunk, NULL);
256 u->send_counter += (int64_t) chunk->length;
259 /* Called from input thread context */
260 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
261 struct userdata *u;
263 pa_source_output_assert_ref(o);
264 pa_source_output_assert_io_context(o);
265 pa_assert_se(u = o->userdata);
267 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
268 u->send_counter -= (int64_t) nbytes;
271 /* Called from output thread context */
272 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
273 struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata;
275 switch (code) {
277 case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: {
278 size_t length;
280 length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq);
282 u->latency_snapshot.send_counter = u->send_counter;
283 u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length;
284 u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source);
286 return 0;
290 return pa_source_output_process_msg(obj, code, data, offset, chunk);
293 /* Called from output thread context */
294 static void source_output_attach_cb(pa_source_output *o) {
295 struct userdata *u;
297 pa_source_output_assert_ref(o);
298 pa_source_output_assert_io_context(o);
299 pa_assert_se(u = o->userdata);
301 u->rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
302 o->source->thread_info.rtpoll,
303 PA_RTPOLL_LATE,
304 u->asyncmsgq);
307 /* Called from output thread context */
308 static void source_output_detach_cb(pa_source_output *o) {
309 struct userdata *u;
311 pa_source_output_assert_ref(o);
312 pa_source_output_assert_io_context(o);
313 pa_assert_se(u = o->userdata);
315 if (u->rtpoll_item_write) {
316 pa_rtpoll_item_free(u->rtpoll_item_write);
317 u->rtpoll_item_write = NULL;
321 /* Called from output thread context */
322 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
323 struct userdata *u;
325 pa_source_output_assert_ref(o);
326 pa_source_output_assert_io_context(o);
327 pa_assert_se(u = o->userdata);
329 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
331 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
332 u->latency),
333 &o->sample_spec);
335 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
339 /* Called from main thread */
340 static void source_output_kill_cb(pa_source_output *o) {
341 struct userdata *u;
343 pa_source_output_assert_ref(o);
344 pa_assert_ctl_context();
345 pa_assert_se(u = o->userdata);
347 teardown(u);
348 pa_module_unload_request(u->module, TRUE);
351 /* Called from main thread */
352 static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
353 struct userdata *u;
355 pa_source_output_assert_ref(o);
356 pa_assert_ctl_context();
357 pa_assert_se(u = o->userdata);
359 return dest != u->sink_input->sink->monitor_source;
362 /* Called from main thread */
363 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
364 pa_proplist *p;
365 const char *n;
366 struct userdata *u;
368 pa_source_output_assert_ref(o);
369 pa_assert_ctl_context();
370 pa_assert_se(u = o->userdata);
372 p = pa_proplist_new();
373 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
375 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
376 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
378 pa_sink_input_update_proplist(u->sink_input, PA_UPDATE_REPLACE, p);
379 pa_proplist_free(p);
382 /* Called from output thread context */
383 static void update_min_memblockq_length(struct userdata *u) {
384 size_t length;
386 pa_assert(u);
387 pa_sink_input_assert_io_context(u->sink_input);
389 length = pa_memblockq_get_length(u->memblockq);
391 if (u->min_memblockq_length == (size_t) -1 ||
392 length < u->min_memblockq_length)
393 u->min_memblockq_length = length;
396 /* Called from output thread context */
397 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
398 struct userdata *u;
400 pa_sink_input_assert_ref(i);
401 pa_sink_input_assert_io_context(i);
402 pa_assert_se(u = i->userdata);
403 pa_assert(chunk);
405 u->in_pop = TRUE;
406 while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0)
408 u->in_pop = FALSE;
410 if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
411 pa_log_info("Could not peek into queue");
412 return -1;
415 chunk->length = PA_MIN(chunk->length, nbytes);
416 pa_memblockq_drop(u->memblockq, chunk->length);
418 update_min_memblockq_length(u);
420 return 0;
423 /* Called from output thread context */
424 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
425 struct userdata *u;
427 pa_sink_input_assert_ref(i);
428 pa_sink_input_assert_io_context(i);
429 pa_assert_se(u = i->userdata);
431 pa_memblockq_rewind(u->memblockq, nbytes);
434 /* Called from output thread context */
435 static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
436 struct userdata *u = PA_SINK_INPUT(obj)->userdata;
438 switch (code) {
440 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
441 pa_usec_t *r = data;
443 pa_sink_input_assert_io_context(u->sink_input);
445 *r = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->sink_input->sample_spec);
447 /* Fall through, the default handler will add in the extra
448 * latency added by the resampler */
449 break;
452 case SINK_INPUT_MESSAGE_POST:
454 pa_sink_input_assert_io_context(u->sink_input);
456 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
457 pa_memblockq_push_align(u->memblockq, chunk);
458 else
459 pa_memblockq_flush_write(u->memblockq, TRUE);
461 update_min_memblockq_length(u);
463 /* Is this the end of an underrun? Then let's start things
464 * right-away */
465 if (!u->in_pop &&
466 u->sink_input->thread_info.underrun_for > 0 &&
467 pa_memblockq_is_readable(u->memblockq)) {
469 pa_log_debug("Requesting rewind due to end of underrun.");
470 pa_sink_input_request_rewind(u->sink_input,
471 (size_t) (u->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : u->sink_input->thread_info.underrun_for),
472 FALSE, TRUE, FALSE);
475 u->recv_counter += (int64_t) chunk->length;
477 return 0;
479 case SINK_INPUT_MESSAGE_REWIND:
481 pa_sink_input_assert_io_context(u->sink_input);
483 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
484 pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, TRUE);
485 else
486 pa_memblockq_flush_write(u->memblockq, TRUE);
488 u->recv_counter -= offset;
490 update_min_memblockq_length(u);
492 return 0;
494 case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
495 size_t length;
497 update_min_memblockq_length(u);
499 length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
501 u->latency_snapshot.recv_counter = u->recv_counter;
502 u->latency_snapshot.sink_input_buffer =
503 pa_memblockq_get_length(u->memblockq) +
504 (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, length) : length);
505 u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink);
507 u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
509 u->latency_snapshot.min_memblockq_length = u->min_memblockq_length;
510 u->min_memblockq_length = (size_t) -1;
512 return 0;
515 case SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED: {
516 /* This message is sent from the IO thread to the main
517 * thread! So don't be confused. All the user cases above
518 * are executed in thread context, but this one is not! */
520 pa_assert_ctl_context();
522 if (u->adjust_time > 0)
523 adjust_rates(u);
524 return 0;
528 return pa_sink_input_process_msg(obj, code, data, offset, chunk);
531 /* Called from output thread context */
532 static void sink_input_attach_cb(pa_sink_input *i) {
533 struct userdata *u;
535 pa_sink_input_assert_ref(i);
536 pa_sink_input_assert_io_context(i);
537 pa_assert_se(u = i->userdata);
539 u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
540 i->sink->thread_info.rtpoll,
541 PA_RTPOLL_LATE,
542 u->asyncmsgq);
544 pa_memblockq_set_prebuf(u->memblockq, pa_sink_input_get_max_request(i)*2);
545 pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i));
547 u->min_memblockq_length = (size_t) -1;
550 /* Called from output thread context */
551 static void sink_input_detach_cb(pa_sink_input *i) {
552 struct userdata *u;
554 pa_sink_input_assert_ref(i);
555 pa_sink_input_assert_io_context(i);
556 pa_assert_se(u = i->userdata);
558 if (u->rtpoll_item_read) {
559 pa_rtpoll_item_free(u->rtpoll_item_read);
560 u->rtpoll_item_read = NULL;
564 /* Called from output thread context */
565 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
566 struct userdata *u;
568 pa_sink_input_assert_ref(i);
569 pa_sink_input_assert_io_context(i);
570 pa_assert_se(u = i->userdata);
572 pa_memblockq_set_maxrewind(u->memblockq, nbytes);
575 /* Called from output thread context */
576 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
577 struct userdata *u;
579 pa_sink_input_assert_ref(i);
580 pa_sink_input_assert_io_context(i);
581 pa_assert_se(u = i->userdata);
583 pa_memblockq_set_prebuf(u->memblockq, nbytes*2);
584 pa_log_info("Max request changed");
585 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED, NULL, 0, NULL, NULL);
588 /* Called from main thread */
589 static void sink_input_kill_cb(pa_sink_input *i) {
590 struct userdata *u;
592 pa_sink_input_assert_ref(i);
593 pa_assert_ctl_context();
594 pa_assert_se(u = i->userdata);
596 teardown(u);
597 pa_module_unload_request(u->module, TRUE);
600 /* Called from main thread */
601 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
602 struct userdata *u;
603 pa_proplist *p;
604 const char *n;
606 pa_sink_input_assert_ref(i);
607 pa_assert_ctl_context();
608 pa_assert_se(u = i->userdata);
610 p = pa_proplist_new();
611 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
613 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
614 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
616 pa_source_output_update_proplist(u->source_output, PA_UPDATE_REPLACE, p);
617 pa_proplist_free(p);
620 /* Called from main thread */
621 static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
622 struct userdata *u;
624 pa_sink_input_assert_ref(i);
625 pa_assert_ctl_context();
626 pa_assert_se(u = i->userdata);
628 if (!u->source_output->source->monitor_of)
629 return TRUE;
631 return dest != u->source_output->source->monitor_of;
634 int pa__init(pa_module *m) {
635 pa_modargs *ma = NULL;
636 struct userdata *u;
637 pa_sink *sink;
638 pa_sink_input_new_data sink_input_data;
639 pa_bool_t sink_dont_move;
640 pa_source *source;
641 pa_source_output_new_data source_output_data;
642 pa_bool_t source_dont_move;
643 uint32_t latency_msec;
644 pa_sample_spec ss;
645 pa_channel_map map;
646 pa_memchunk silence;
647 uint32_t adjust_time_sec;
648 const char *n;
649 pa_bool_t remix = TRUE;
651 pa_assert(m);
653 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
654 pa_log("Failed to parse module arguments");
655 goto fail;
658 if (!(source = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) {
659 pa_log("No such source.");
660 goto fail;
663 if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) {
664 pa_log("No such sink.");
665 goto fail;
668 if (pa_modargs_get_value_boolean(ma, "remix", &remix) < 0) {
669 pa_log("Invalid boolean remix parameter");
670 goto fail;
673 ss = sink->sample_spec;
674 map = sink->channel_map;
675 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
676 pa_log("Invalid sample format specification or channel map");
677 goto fail;
680 latency_msec = DEFAULT_LATENCY_MSEC;
681 if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 2000) {
682 pa_log("Invalid latency specification");
683 goto fail;
686 m->userdata = u = pa_xnew0(struct userdata, 1);
687 u->core = m->core;
688 u->module = m;
689 u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC;
691 adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
692 if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) {
693 pa_log("Failed to parse adjust_time value");
694 goto fail;
697 if (adjust_time_sec != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC)
698 u->adjust_time = adjust_time_sec * PA_USEC_PER_SEC;
699 else
700 u->adjust_time = DEFAULT_ADJUST_TIME_USEC;
702 pa_sink_input_new_data_init(&sink_input_data);
703 sink_input_data.driver = __FILE__;
704 sink_input_data.module = m;
705 pa_sink_input_new_data_set_sink(&sink_input_data, sink, FALSE);
707 if ((n = pa_modargs_get_value(ma, "sink_input_name", NULL)))
708 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, n);
709 else
710 pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback from %s",
711 pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
713 if ((n = pa_modargs_get_value(ma, "sink_input_role", NULL)))
714 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, n);
715 else
716 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
718 if ((n = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)))
719 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
721 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
722 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
723 sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE | (remix ? 0 : PA_SINK_INPUT_NO_REMIX);
725 sink_dont_move = FALSE;
726 if (pa_modargs_get_value_boolean(ma, "sink_dont_move", &sink_dont_move) < 0) {
727 pa_log("sink_dont_move= expects a boolean argument.");
728 goto fail;
731 if (sink_dont_move)
732 sink_input_data.flags |= PA_SINK_INPUT_DONT_MOVE;
734 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
735 pa_sink_input_new_data_done(&sink_input_data);
737 if (!u->sink_input)
738 goto fail;
740 u->sink_input->parent.process_msg = sink_input_process_msg_cb;
741 u->sink_input->pop = sink_input_pop_cb;
742 u->sink_input->process_rewind = sink_input_process_rewind_cb;
743 u->sink_input->kill = sink_input_kill_cb;
744 u->sink_input->attach = sink_input_attach_cb;
745 u->sink_input->detach = sink_input_detach_cb;
746 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
747 u->sink_input->update_max_request = sink_input_update_max_request_cb;
748 u->sink_input->may_move_to = sink_input_may_move_to_cb;
749 u->sink_input->moving = sink_input_moving_cb;
750 u->sink_input->userdata = u;
752 pa_sink_input_set_requested_latency(u->sink_input, u->latency/3);
754 pa_source_output_new_data_init(&source_output_data);
755 source_output_data.driver = __FILE__;
756 source_output_data.module = m;
757 pa_source_output_new_data_set_source(&source_output_data, source, FALSE);
759 if ((n = pa_modargs_get_value(ma, "source_output_name", NULL)))
760 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, n);
761 else
762 pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s",
763 pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
765 if ((n = pa_modargs_get_value(ma, "source_output_role", NULL)))
766 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, n);
767 else
768 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
770 if ((n = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)))
771 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
773 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
774 pa_source_output_new_data_set_channel_map(&source_output_data, &map);
775 source_output_data.flags = (remix ? 0 : PA_SOURCE_OUTPUT_NO_REMIX);
777 source_dont_move = FALSE;
778 if (pa_modargs_get_value_boolean(ma, "source_dont_move", &source_dont_move) < 0) {
779 pa_log("source_dont_move= expects a boolean argument.");
780 goto fail;
783 if (source_dont_move)
784 source_output_data.flags |= PA_SOURCE_OUTPUT_DONT_MOVE;
786 pa_source_output_new(&u->source_output, m->core, &source_output_data);
787 pa_source_output_new_data_done(&source_output_data);
789 if (!u->source_output)
790 goto fail;
792 u->source_output->parent.process_msg = source_output_process_msg_cb;
793 u->source_output->push = source_output_push_cb;
794 u->source_output->process_rewind = source_output_process_rewind_cb;
795 u->source_output->kill = source_output_kill_cb;
796 u->source_output->attach = source_output_attach_cb;
797 u->source_output->detach = source_output_detach_cb;
798 u->source_output->state_change = source_output_state_change_cb;
799 u->source_output->may_move_to = source_output_may_move_to_cb;
800 u->source_output->moving = source_output_moving_cb;
801 u->source_output->userdata = u;
803 pa_source_output_set_requested_latency(u->source_output, u->latency/3);
805 pa_sink_input_get_silence(u->sink_input, &silence);
806 u->memblockq = pa_memblockq_new(
807 0, /* idx */
808 MEMBLOCKQ_MAXLENGTH, /* maxlength */
809 MEMBLOCKQ_MAXLENGTH, /* tlength */
810 pa_frame_size(&ss), /* base */
811 0, /* prebuf */
812 0, /* minreq */
813 0, /* maxrewind */
814 &silence); /* silence frame */
815 pa_memblock_unref(silence.memblock);
817 u->asyncmsgq = pa_asyncmsgq_new(0);
819 pa_sink_input_put(u->sink_input);
820 pa_source_output_put(u->source_output);
822 if (u->adjust_time > 0)
823 u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u);
825 pa_modargs_free(ma);
826 return 0;
828 fail:
829 if (ma)
830 pa_modargs_free(ma);
832 pa__done(m);
834 return -1;
837 void pa__done(pa_module*m) {
838 struct userdata *u;
840 pa_assert(m);
842 if (!(u = m->userdata))
843 return;
845 teardown(u);
847 if (u->memblockq)
848 pa_memblockq_free(u->memblockq);
850 if (u->asyncmsgq)
851 pa_asyncmsgq_unref(u->asyncmsgq);
853 if (u->time_event)
854 u->core->mainloop->time_free(u->time_event);
856 pa_xfree(u);