esd,simple: use pa_memblockq_pop_missing()
[pulseaudio-mirror.git] / src / modules / module-loopback.c
blob15ef96efefd9bd15b4b85e0adcc1db4ae3142f17
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>");
58 #define DEFAULT_LATENCY_MSEC 200
60 #define MEMBLOCKQ_MAXLENGTH (1024*1024*16)
62 #define DEFAULT_ADJUST_TIME_USEC (10*PA_USEC_PER_SEC)
64 struct userdata {
65 pa_core *core;
66 pa_module *module;
68 pa_sink_input *sink_input;
69 pa_source_output *source_output;
71 pa_asyncmsgq *asyncmsgq;
72 pa_memblockq *memblockq;
74 pa_rtpoll_item *rtpoll_item_read, *rtpoll_item_write;
76 pa_time_event *time_event;
77 pa_usec_t adjust_time;
79 int64_t recv_counter;
80 int64_t send_counter;
82 size_t skip;
83 pa_usec_t latency;
85 pa_bool_t in_pop;
86 size_t min_memblockq_length;
88 struct {
89 int64_t send_counter;
90 size_t source_output_buffer;
91 pa_usec_t source_latency;
93 int64_t recv_counter;
94 size_t sink_input_buffer;
95 pa_usec_t sink_latency;
97 size_t min_memblockq_length;
98 size_t max_request;
99 } latency_snapshot;
102 static const char* const valid_modargs[] = {
103 "source",
104 "sink",
105 "latency_msec",
106 "format",
107 "rate",
108 "channels",
109 "channel_map",
110 NULL,
113 enum {
114 SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
115 SINK_INPUT_MESSAGE_REWIND,
116 SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT,
117 SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED
120 enum {
121 SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT
124 /* Called from main context */
125 static void teardown(struct userdata *u) {
126 pa_assert(u);
127 pa_assert_ctl_context();
129 if (u->sink_input)
130 pa_sink_input_unlink(u->sink_input);
132 if (u->source_output)
133 pa_source_output_unlink(u->source_output);
135 if (u->sink_input) {
136 pa_sink_input_unref(u->sink_input);
137 u->sink_input = NULL;
140 if (u->source_output) {
141 pa_source_output_unref(u->source_output);
142 u->source_output = NULL;
146 /* Called from main context */
147 static void adjust_rates(struct userdata *u) {
148 size_t buffer, fs;
149 uint32_t old_rate, base_rate, new_rate;
150 pa_usec_t buffer_latency;
152 pa_assert(u);
153 pa_assert_ctl_context();
155 pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
156 pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
158 buffer =
159 u->latency_snapshot.sink_input_buffer +
160 u->latency_snapshot.source_output_buffer;
162 if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter)
163 buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter);
164 else
165 buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter));
167 buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);
169 pa_log_info("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms",
170 (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
171 (double) buffer_latency / PA_USEC_PER_MSEC,
172 (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC,
173 ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC);
175 pa_log_info("Should buffer %zu bytes, buffered at minimum %zu bytes",
176 u->latency_snapshot.max_request*2,
177 u->latency_snapshot.min_memblockq_length);
179 fs = pa_frame_size(&u->sink_input->sample_spec);
180 old_rate = u->sink_input->sample_spec.rate;
181 base_rate = u->source_output->sample_spec.rate;
183 if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2)
184 new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
185 else
186 new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
188 pa_log_info("Old rate %lu Hz, new rate %lu Hz", (unsigned long) old_rate, (unsigned long) new_rate);
190 pa_sink_input_set_rate(u->sink_input, new_rate);
192 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
195 /* Called from main context */
196 static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
197 struct userdata *u = userdata;
199 pa_assert(u);
200 pa_assert(a);
201 pa_assert(u->time_event == e);
203 adjust_rates(u);
206 /* Called from input thread context */
207 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
208 struct userdata *u;
209 pa_memchunk copy;
211 pa_source_output_assert_ref(o);
212 pa_source_output_assert_io_context(o);
213 pa_assert_se(u = o->userdata);
215 if (u->skip > chunk->length) {
216 u->skip -= chunk->length;
217 return;
220 if (u->skip > 0) {
221 copy = *chunk;
222 copy.index += u->skip;
223 copy.length -= u->skip;
224 u->skip = 0;
226 chunk = &copy;
229 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, chunk, NULL);
230 u->send_counter += (int64_t) chunk->length;
233 /* Called from input thread context */
234 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
235 struct userdata *u;
237 pa_source_output_assert_ref(o);
238 pa_source_output_assert_io_context(o);
239 pa_assert_se(u = o->userdata);
241 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
242 u->send_counter -= (int64_t) nbytes;
245 /* Called from output thread context */
246 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
247 struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata;
249 switch (code) {
251 case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: {
252 size_t length;
254 length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq);
256 u->latency_snapshot.send_counter = u->send_counter;
257 u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length;
258 u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source);
260 return 0;
264 return pa_source_output_process_msg(obj, code, data, offset, chunk);
267 /* Called from output thread context */
268 static void source_output_attach_cb(pa_source_output *o) {
269 struct userdata *u;
271 pa_source_output_assert_ref(o);
272 pa_source_output_assert_io_context(o);
273 pa_assert_se(u = o->userdata);
275 u->rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
276 o->source->thread_info.rtpoll,
277 PA_RTPOLL_LATE,
278 u->asyncmsgq);
281 /* Called from output thread context */
282 static void source_output_detach_cb(pa_source_output *o) {
283 struct userdata *u;
285 pa_source_output_assert_ref(o);
286 pa_source_output_assert_io_context(o);
287 pa_assert_se(u = o->userdata);
289 if (u->rtpoll_item_write) {
290 pa_rtpoll_item_free(u->rtpoll_item_write);
291 u->rtpoll_item_write = NULL;
295 /* Called from output thread context */
296 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
297 struct userdata *u;
299 pa_source_output_assert_ref(o);
300 pa_source_output_assert_io_context(o);
301 pa_assert_se(u = o->userdata);
303 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
305 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
306 u->latency),
307 &o->sample_spec);
309 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
313 /* Called from main thread */
314 static void source_output_kill_cb(pa_source_output *o) {
315 struct userdata *u;
317 pa_source_output_assert_ref(o);
318 pa_assert_ctl_context();
319 pa_assert_se(u = o->userdata);
321 teardown(u);
322 pa_module_unload_request(u->module, TRUE);
325 /* Called from main thread */
326 static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
327 struct userdata *u;
329 pa_source_output_assert_ref(o);
330 pa_assert_ctl_context();
331 pa_assert_se(u = o->userdata);
333 return dest != u->sink_input->sink->monitor_source;
336 /* Called from main thread */
337 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
338 pa_proplist *p;
339 const char *n;
340 struct userdata *u;
342 pa_source_output_assert_ref(o);
343 pa_assert_ctl_context();
344 pa_assert_se(u = o->userdata);
346 p = pa_proplist_new();
347 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
349 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
350 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
352 pa_sink_input_update_proplist(u->sink_input, PA_UPDATE_REPLACE, p);
353 pa_proplist_free(p);
356 /* Called from output thread context */
357 static void update_min_memblockq_length(struct userdata *u) {
358 size_t length;
360 pa_assert(u);
361 pa_sink_input_assert_io_context(u->sink_input);
363 length = pa_memblockq_get_length(u->memblockq);
365 if (u->min_memblockq_length == (size_t) -1 ||
366 length < u->min_memblockq_length)
367 u->min_memblockq_length = length;
370 /* Called from output thread context */
371 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
372 struct userdata *u;
374 pa_sink_input_assert_ref(i);
375 pa_sink_input_assert_io_context(i);
376 pa_assert_se(u = i->userdata);
377 pa_assert(chunk);
379 u->in_pop = TRUE;
380 while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0)
382 u->in_pop = FALSE;
384 if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
385 pa_log_info("Coud not peek into queue");
386 return -1;
389 chunk->length = PA_MIN(chunk->length, nbytes);
390 pa_memblockq_drop(u->memblockq, chunk->length);
392 update_min_memblockq_length(u);
394 return 0;
397 /* Called from output thread context */
398 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
399 struct userdata *u;
401 pa_sink_input_assert_ref(i);
402 pa_sink_input_assert_io_context(i);
403 pa_assert_se(u = i->userdata);
405 pa_memblockq_rewind(u->memblockq, nbytes);
408 /* Called from output thread context */
409 static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
410 struct userdata *u = PA_SINK_INPUT(obj)->userdata;
412 switch (code) {
414 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
415 pa_usec_t *r = data;
417 pa_sink_input_assert_io_context(u->sink_input);
419 *r = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->sink_input->sample_spec);
421 /* Fall through, the default handler will add in the extra
422 * latency added by the resampler */
423 break;
426 case SINK_INPUT_MESSAGE_POST:
428 pa_sink_input_assert_io_context(u->sink_input);
430 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
431 pa_memblockq_push_align(u->memblockq, chunk);
432 else
433 pa_memblockq_flush_write(u->memblockq, TRUE);
435 update_min_memblockq_length(u);
437 /* Is this the end of an underrun? Then let's start things
438 * right-away */
439 if (!u->in_pop &&
440 u->sink_input->thread_info.underrun_for > 0 &&
441 pa_memblockq_is_readable(u->memblockq)) {
443 pa_log_debug("Requesting rewind due to end of underrun.");
444 pa_sink_input_request_rewind(u->sink_input,
445 (size_t) (u->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : u->sink_input->thread_info.underrun_for),
446 FALSE, TRUE, FALSE);
449 u->recv_counter += (int64_t) chunk->length;
451 return 0;
453 case SINK_INPUT_MESSAGE_REWIND:
455 pa_sink_input_assert_io_context(u->sink_input);
457 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
458 pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, TRUE);
459 else
460 pa_memblockq_flush_write(u->memblockq, TRUE);
462 u->recv_counter -= offset;
464 update_min_memblockq_length(u);
466 return 0;
468 case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
469 size_t length;
471 update_min_memblockq_length(u);
473 length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
475 u->latency_snapshot.recv_counter = u->recv_counter;
476 u->latency_snapshot.sink_input_buffer =
477 pa_memblockq_get_length(u->memblockq) +
478 (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, length) : length);
479 u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink);
481 u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
483 u->latency_snapshot.min_memblockq_length = u->min_memblockq_length;
484 u->min_memblockq_length = (size_t) -1;
486 return 0;
489 case SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED: {
490 /* This message is sent from the IO thread to the main
491 * thread! So don't be confused. All the user cases above
492 * are executed in thread context, but this one is not! */
494 pa_assert_ctl_context();
496 adjust_rates(u);
497 return 0;
501 return pa_sink_input_process_msg(obj, code, data, offset, chunk);
504 /* Called from output thread context */
505 static void sink_input_attach_cb(pa_sink_input *i) {
506 struct userdata *u;
508 pa_sink_input_assert_ref(i);
509 pa_sink_input_assert_io_context(i);
510 pa_assert_se(u = i->userdata);
512 u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
513 i->sink->thread_info.rtpoll,
514 PA_RTPOLL_LATE,
515 u->asyncmsgq);
517 pa_memblockq_set_prebuf(u->memblockq, pa_sink_input_get_max_request(i)*2);
518 pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i));
520 u->min_memblockq_length = (size_t) -1;
523 /* Called from output thread context */
524 static void sink_input_detach_cb(pa_sink_input *i) {
525 struct userdata *u;
527 pa_sink_input_assert_ref(i);
528 pa_sink_input_assert_io_context(i);
529 pa_assert_se(u = i->userdata);
531 if (u->rtpoll_item_read) {
532 pa_rtpoll_item_free(u->rtpoll_item_read);
533 u->rtpoll_item_read = NULL;
537 /* Called from output thread context */
538 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
539 struct userdata *u;
541 pa_sink_input_assert_ref(i);
542 pa_sink_input_assert_io_context(i);
543 pa_assert_se(u = i->userdata);
545 pa_memblockq_set_maxrewind(u->memblockq, nbytes);
548 /* Called from output thread context */
549 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
550 struct userdata *u;
552 pa_sink_input_assert_ref(i);
553 pa_sink_input_assert_io_context(i);
554 pa_assert_se(u = i->userdata);
556 pa_memblockq_set_prebuf(u->memblockq, nbytes*2);
557 pa_log_info("Max request changed");
558 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED, NULL, 0, NULL, NULL);
561 /* Called from main thread */
562 static void sink_input_kill_cb(pa_sink_input *i) {
563 struct userdata *u;
565 pa_sink_input_assert_ref(i);
566 pa_assert_ctl_context();
567 pa_assert_se(u = i->userdata);
569 teardown(u);
570 pa_module_unload_request(u->module, TRUE);
573 /* Called from main thread */
574 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
575 struct userdata *u;
576 pa_proplist *p;
577 const char *n;
579 pa_sink_input_assert_ref(i);
580 pa_assert_ctl_context();
581 pa_assert_se(u = i->userdata);
583 p = pa_proplist_new();
584 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
586 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
587 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
589 pa_source_output_update_proplist(u->source_output, PA_UPDATE_REPLACE, p);
590 pa_proplist_free(p);
593 /* Called from main thread */
594 static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
595 struct userdata *u;
597 pa_sink_input_assert_ref(i);
598 pa_assert_ctl_context();
599 pa_assert_se(u = i->userdata);
601 if (!u->source_output->source->monitor_of)
602 return TRUE;
604 return dest != u->source_output->source->monitor_of;
607 int pa__init(pa_module *m) {
608 pa_modargs *ma = NULL;
609 struct userdata *u;
610 pa_sink *sink;
611 pa_sink_input_new_data sink_input_data;
612 pa_source *source;
613 pa_source_output_new_data source_output_data;
614 uint32_t latency_msec;
615 pa_sample_spec ss;
616 pa_channel_map map;
617 pa_memchunk silence;
618 uint32_t adjust_time_sec;
619 const char *n;
621 pa_assert(m);
623 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
624 pa_log("Failed to parse module arguments");
625 goto fail;
628 if (!(source = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) {
629 pa_log("No such source.");
630 goto fail;
633 if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) {
634 pa_log("No such sink.");
635 goto fail;
638 ss = sink->sample_spec;
639 map = sink->channel_map;
640 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
641 pa_log("Invalid sample format specification or channel map");
642 goto fail;
645 latency_msec = DEFAULT_LATENCY_MSEC;
646 if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 2000) {
647 pa_log("Invalid latency specification");
648 goto fail;
651 m->userdata = u = pa_xnew0(struct userdata, 1);
652 u->core = m->core;
653 u->module = m;
654 u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC;
656 adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
657 if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) {
658 pa_log("Failed to parse adjust_time value");
659 goto fail;
662 if (adjust_time_sec != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC)
663 u->adjust_time = adjust_time_sec * PA_USEC_PER_SEC;
664 else
665 u->adjust_time = DEFAULT_ADJUST_TIME_USEC;
667 pa_sink_input_new_data_init(&sink_input_data);
668 sink_input_data.driver = __FILE__;
669 sink_input_data.module = m;
670 sink_input_data.sink = sink;
672 pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback of %s",
673 pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
674 if ((n = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)))
675 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
676 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
677 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
678 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
679 sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE;
681 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
682 pa_sink_input_new_data_done(&sink_input_data);
684 if (!u->sink_input)
685 goto fail;
687 u->sink_input->parent.process_msg = sink_input_process_msg_cb;
688 u->sink_input->pop = sink_input_pop_cb;
689 u->sink_input->process_rewind = sink_input_process_rewind_cb;
690 u->sink_input->kill = sink_input_kill_cb;
691 u->sink_input->attach = sink_input_attach_cb;
692 u->sink_input->detach = sink_input_detach_cb;
693 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
694 u->sink_input->update_max_request = sink_input_update_max_request_cb;
695 u->sink_input->may_move_to = sink_input_may_move_to_cb;
696 u->sink_input->moving = sink_input_moving_cb;
697 u->sink_input->userdata = u;
699 pa_sink_input_set_requested_latency(u->sink_input, u->latency/3);
701 pa_source_output_new_data_init(&source_output_data);
702 source_output_data.driver = __FILE__;
703 source_output_data.module = m;
704 source_output_data.source = source;
705 pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s",
706 pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
707 if ((n = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)))
708 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
709 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
710 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
711 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
713 pa_source_output_new(&u->source_output, m->core, &source_output_data);
714 pa_source_output_new_data_done(&source_output_data);
716 if (!u->source_output)
717 goto fail;
719 u->source_output->parent.process_msg = source_output_process_msg_cb;
720 u->source_output->push = source_output_push_cb;
721 u->source_output->process_rewind = source_output_process_rewind_cb;
722 u->source_output->kill = source_output_kill_cb;
723 u->source_output->attach = source_output_attach_cb;
724 u->source_output->detach = source_output_detach_cb;
725 u->source_output->state_change = source_output_state_change_cb;
726 u->source_output->may_move_to = source_output_may_move_to_cb;
727 u->source_output->moving = source_output_moving_cb;
728 u->source_output->userdata = u;
730 pa_source_output_set_requested_latency(u->source_output, u->latency/3);
732 pa_sink_input_get_silence(u->sink_input, &silence);
733 u->memblockq = pa_memblockq_new(
734 0, /* idx */
735 MEMBLOCKQ_MAXLENGTH, /* maxlength */
736 MEMBLOCKQ_MAXLENGTH, /* tlength */
737 pa_frame_size(&ss), /* base */
738 0, /* prebuf */
739 0, /* minreq */
740 0, /* maxrewind */
741 &silence); /* silence frame */
742 pa_memblock_unref(silence.memblock);
744 u->asyncmsgq = pa_asyncmsgq_new(0);
746 pa_sink_input_put(u->sink_input);
747 pa_source_output_put(u->source_output);
749 if (u->adjust_time > 0)
750 u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u);
752 pa_modargs_free(ma);
753 return 0;
755 fail:
756 if (ma)
757 pa_modargs_free(ma);
759 pa__done(m);
761 return -1;
764 void pa__done(pa_module*m) {
765 struct userdata *u;
767 pa_assert(m);
769 if (!(u = m->userdata))
770 return;
772 teardown(u);
774 if (u->memblockq)
775 pa_memblockq_free(u->memblockq);
777 if (u->asyncmsgq)
778 pa_asyncmsgq_unref(u->asyncmsgq);
780 if (u->time_event)
781 u->core->mainloop->time_free(u->time_event);
783 pa_xfree(u);