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
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);
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> "
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>");
62 #define DEFAULT_LATENCY_MSEC 200
64 #define MEMBLOCKQ_MAXLENGTH (1024*1024*16)
66 #define DEFAULT_ADJUST_TIME_USEC (10*PA_USEC_PER_SEC)
72 pa_sink_input *sink_input;
73 pa_source_output *source_output;
75 pa_asyncmsgq *asyncmsgq;
76 pa_memblockq *memblockq;
78 pa_rtpoll_item *rtpoll_item_read, *rtpoll_item_write;
80 pa_time_event *time_event;
81 pa_usec_t adjust_time;
90 size_t min_memblockq_length;
94 size_t source_output_buffer;
95 pa_usec_t source_latency;
98 size_t sink_input_buffer;
99 pa_usec_t sink_latency;
101 size_t min_memblockq_length;
106 static const char* const valid_modargs[] = {
115 "source_output_name",
117 "source_output_role",
122 SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
123 SINK_INPUT_MESSAGE_REWIND,
124 SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT,
125 SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED
129 SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT
132 /* Called from main context */
133 static void teardown(struct userdata *u) {
135 pa_assert_ctl_context();
138 pa_sink_input_unlink(u->sink_input);
140 if (u->source_output)
141 pa_source_output_unlink(u->source_output);
144 pa_sink_input_unref(u->sink_input);
145 u->sink_input = NULL;
148 if (u->source_output) {
149 pa_source_output_unref(u->source_output);
150 u->source_output = NULL;
154 /* Called from main context */
155 static void adjust_rates(struct userdata *u) {
157 uint32_t old_rate, base_rate, new_rate;
158 pa_usec_t buffer_latency;
161 pa_assert_ctl_context();
163 pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
164 pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
167 u->latency_snapshot.sink_input_buffer +
168 u->latency_snapshot.source_output_buffer;
170 if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter)
171 buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter);
173 buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter));
175 buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);
177 pa_log_info("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms",
178 (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
179 (double) buffer_latency / PA_USEC_PER_MSEC,
180 (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC,
181 ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC);
183 pa_log_info("Should buffer %zu bytes, buffered at minimum %zu bytes",
184 u->latency_snapshot.max_request*2,
185 u->latency_snapshot.min_memblockq_length);
187 fs = pa_frame_size(&u->sink_input->sample_spec);
188 old_rate = u->sink_input->sample_spec.rate;
189 base_rate = u->source_output->sample_spec.rate;
191 if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2)
192 new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
194 new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
196 pa_log_info("Old rate %lu Hz, new rate %lu Hz", (unsigned long) old_rate, (unsigned long) new_rate);
198 pa_sink_input_set_rate(u->sink_input, new_rate);
200 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
203 /* Called from main context */
204 static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
205 struct userdata *u = userdata;
209 pa_assert(u->time_event == e);
214 /* Called from input thread context */
215 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
219 pa_source_output_assert_ref(o);
220 pa_source_output_assert_io_context(o);
221 pa_assert_se(u = o->userdata);
223 if (u->skip > chunk->length) {
224 u->skip -= chunk->length;
230 copy.index += u->skip;
231 copy.length -= u->skip;
237 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, chunk, NULL);
238 u->send_counter += (int64_t) chunk->length;
241 /* Called from input thread context */
242 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
245 pa_source_output_assert_ref(o);
246 pa_source_output_assert_io_context(o);
247 pa_assert_se(u = o->userdata);
249 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
250 u->send_counter -= (int64_t) nbytes;
253 /* Called from output thread context */
254 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
255 struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata;
259 case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: {
262 length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq);
264 u->latency_snapshot.send_counter = u->send_counter;
265 u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length;
266 u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source);
272 return pa_source_output_process_msg(obj, code, data, offset, chunk);
275 /* Called from output thread context */
276 static void source_output_attach_cb(pa_source_output *o) {
279 pa_source_output_assert_ref(o);
280 pa_source_output_assert_io_context(o);
281 pa_assert_se(u = o->userdata);
283 u->rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
284 o->source->thread_info.rtpoll,
289 /* Called from output thread context */
290 static void source_output_detach_cb(pa_source_output *o) {
293 pa_source_output_assert_ref(o);
294 pa_source_output_assert_io_context(o);
295 pa_assert_se(u = o->userdata);
297 if (u->rtpoll_item_write) {
298 pa_rtpoll_item_free(u->rtpoll_item_write);
299 u->rtpoll_item_write = NULL;
303 /* Called from output thread context */
304 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
307 pa_source_output_assert_ref(o);
308 pa_source_output_assert_io_context(o);
309 pa_assert_se(u = o->userdata);
311 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
313 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
317 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
321 /* Called from main thread */
322 static void source_output_kill_cb(pa_source_output *o) {
325 pa_source_output_assert_ref(o);
326 pa_assert_ctl_context();
327 pa_assert_se(u = o->userdata);
330 pa_module_unload_request(u->module, TRUE);
333 /* Called from main thread */
334 static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
337 pa_source_output_assert_ref(o);
338 pa_assert_ctl_context();
339 pa_assert_se(u = o->userdata);
341 return dest != u->sink_input->sink->monitor_source;
344 /* Called from main thread */
345 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
350 pa_source_output_assert_ref(o);
351 pa_assert_ctl_context();
352 pa_assert_se(u = o->userdata);
354 p = pa_proplist_new();
355 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
357 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
358 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
360 pa_sink_input_update_proplist(u->sink_input, PA_UPDATE_REPLACE, p);
364 /* Called from output thread context */
365 static void update_min_memblockq_length(struct userdata *u) {
369 pa_sink_input_assert_io_context(u->sink_input);
371 length = pa_memblockq_get_length(u->memblockq);
373 if (u->min_memblockq_length == (size_t) -1 ||
374 length < u->min_memblockq_length)
375 u->min_memblockq_length = length;
378 /* Called from output thread context */
379 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
382 pa_sink_input_assert_ref(i);
383 pa_sink_input_assert_io_context(i);
384 pa_assert_se(u = i->userdata);
388 while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0)
392 if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
393 pa_log_info("Coud not peek into queue");
397 chunk->length = PA_MIN(chunk->length, nbytes);
398 pa_memblockq_drop(u->memblockq, chunk->length);
400 update_min_memblockq_length(u);
405 /* Called from output thread context */
406 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
409 pa_sink_input_assert_ref(i);
410 pa_sink_input_assert_io_context(i);
411 pa_assert_se(u = i->userdata);
413 pa_memblockq_rewind(u->memblockq, nbytes);
416 /* Called from output thread context */
417 static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
418 struct userdata *u = PA_SINK_INPUT(obj)->userdata;
422 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
425 pa_sink_input_assert_io_context(u->sink_input);
427 *r = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->sink_input->sample_spec);
429 /* Fall through, the default handler will add in the extra
430 * latency added by the resampler */
434 case SINK_INPUT_MESSAGE_POST:
436 pa_sink_input_assert_io_context(u->sink_input);
438 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
439 pa_memblockq_push_align(u->memblockq, chunk);
441 pa_memblockq_flush_write(u->memblockq, TRUE);
443 update_min_memblockq_length(u);
445 /* Is this the end of an underrun? Then let's start things
448 u->sink_input->thread_info.underrun_for > 0 &&
449 pa_memblockq_is_readable(u->memblockq)) {
451 pa_log_debug("Requesting rewind due to end of underrun.");
452 pa_sink_input_request_rewind(u->sink_input,
453 (size_t) (u->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : u->sink_input->thread_info.underrun_for),
457 u->recv_counter += (int64_t) chunk->length;
461 case SINK_INPUT_MESSAGE_REWIND:
463 pa_sink_input_assert_io_context(u->sink_input);
465 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
466 pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, TRUE);
468 pa_memblockq_flush_write(u->memblockq, TRUE);
470 u->recv_counter -= offset;
472 update_min_memblockq_length(u);
476 case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
479 update_min_memblockq_length(u);
481 length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
483 u->latency_snapshot.recv_counter = u->recv_counter;
484 u->latency_snapshot.sink_input_buffer =
485 pa_memblockq_get_length(u->memblockq) +
486 (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, length) : length);
487 u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink);
489 u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
491 u->latency_snapshot.min_memblockq_length = u->min_memblockq_length;
492 u->min_memblockq_length = (size_t) -1;
497 case SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED: {
498 /* This message is sent from the IO thread to the main
499 * thread! So don't be confused. All the user cases above
500 * are executed in thread context, but this one is not! */
502 pa_assert_ctl_context();
509 return pa_sink_input_process_msg(obj, code, data, offset, chunk);
512 /* Called from output thread context */
513 static void sink_input_attach_cb(pa_sink_input *i) {
516 pa_sink_input_assert_ref(i);
517 pa_sink_input_assert_io_context(i);
518 pa_assert_se(u = i->userdata);
520 u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
521 i->sink->thread_info.rtpoll,
525 pa_memblockq_set_prebuf(u->memblockq, pa_sink_input_get_max_request(i)*2);
526 pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i));
528 u->min_memblockq_length = (size_t) -1;
531 /* Called from output thread context */
532 static void sink_input_detach_cb(pa_sink_input *i) {
535 pa_sink_input_assert_ref(i);
536 pa_sink_input_assert_io_context(i);
537 pa_assert_se(u = i->userdata);
539 if (u->rtpoll_item_read) {
540 pa_rtpoll_item_free(u->rtpoll_item_read);
541 u->rtpoll_item_read = NULL;
545 /* Called from output thread context */
546 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
549 pa_sink_input_assert_ref(i);
550 pa_sink_input_assert_io_context(i);
551 pa_assert_se(u = i->userdata);
553 pa_memblockq_set_maxrewind(u->memblockq, nbytes);
556 /* Called from output thread context */
557 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
560 pa_sink_input_assert_ref(i);
561 pa_sink_input_assert_io_context(i);
562 pa_assert_se(u = i->userdata);
564 pa_memblockq_set_prebuf(u->memblockq, nbytes*2);
565 pa_log_info("Max request changed");
566 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED, NULL, 0, NULL, NULL);
569 /* Called from main thread */
570 static void sink_input_kill_cb(pa_sink_input *i) {
573 pa_sink_input_assert_ref(i);
574 pa_assert_ctl_context();
575 pa_assert_se(u = i->userdata);
578 pa_module_unload_request(u->module, TRUE);
581 /* Called from main thread */
582 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
587 pa_sink_input_assert_ref(i);
588 pa_assert_ctl_context();
589 pa_assert_se(u = i->userdata);
591 p = pa_proplist_new();
592 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
594 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
595 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
597 pa_source_output_update_proplist(u->source_output, PA_UPDATE_REPLACE, p);
601 /* Called from main thread */
602 static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
605 pa_sink_input_assert_ref(i);
606 pa_assert_ctl_context();
607 pa_assert_se(u = i->userdata);
609 if (!u->source_output->source->monitor_of)
612 return dest != u->source_output->source->monitor_of;
615 int pa__init(pa_module *m) {
616 pa_modargs *ma = NULL;
619 pa_sink_input_new_data sink_input_data;
621 pa_source_output_new_data source_output_data;
622 uint32_t latency_msec;
626 uint32_t adjust_time_sec;
631 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
632 pa_log("Failed to parse module arguments");
636 if (!(source = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) {
637 pa_log("No such source.");
641 if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) {
642 pa_log("No such sink.");
646 ss = sink->sample_spec;
647 map = sink->channel_map;
648 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
649 pa_log("Invalid sample format specification or channel map");
653 latency_msec = DEFAULT_LATENCY_MSEC;
654 if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 2000) {
655 pa_log("Invalid latency specification");
659 m->userdata = u = pa_xnew0(struct userdata, 1);
662 u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC;
664 adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
665 if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) {
666 pa_log("Failed to parse adjust_time value");
670 if (adjust_time_sec != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC)
671 u->adjust_time = adjust_time_sec * PA_USEC_PER_SEC;
673 u->adjust_time = DEFAULT_ADJUST_TIME_USEC;
675 pa_sink_input_new_data_init(&sink_input_data);
676 sink_input_data.driver = __FILE__;
677 sink_input_data.module = m;
678 sink_input_data.sink = sink;
680 if ((n = pa_modargs_get_value(ma, "sink_input_name", NULL)))
681 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, n);
683 pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback from %s",
684 pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
686 if ((n = pa_modargs_get_value(ma, "sink_input_role", NULL)))
687 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, n);
689 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
691 if ((n = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)))
692 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
694 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
695 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
696 sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE;
698 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
699 pa_sink_input_new_data_done(&sink_input_data);
704 u->sink_input->parent.process_msg = sink_input_process_msg_cb;
705 u->sink_input->pop = sink_input_pop_cb;
706 u->sink_input->process_rewind = sink_input_process_rewind_cb;
707 u->sink_input->kill = sink_input_kill_cb;
708 u->sink_input->attach = sink_input_attach_cb;
709 u->sink_input->detach = sink_input_detach_cb;
710 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
711 u->sink_input->update_max_request = sink_input_update_max_request_cb;
712 u->sink_input->may_move_to = sink_input_may_move_to_cb;
713 u->sink_input->moving = sink_input_moving_cb;
714 u->sink_input->userdata = u;
716 pa_sink_input_set_requested_latency(u->sink_input, u->latency/3);
718 pa_source_output_new_data_init(&source_output_data);
719 source_output_data.driver = __FILE__;
720 source_output_data.module = m;
721 source_output_data.source = source;
723 if ((n = pa_modargs_get_value(ma, "source_output_name", NULL)))
724 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, n);
726 pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s",
727 pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
729 if ((n = pa_modargs_get_value(ma, "source_output_role", NULL)))
730 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, n);
732 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
734 if ((n = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)))
735 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
737 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
738 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
740 pa_source_output_new(&u->source_output, m->core, &source_output_data);
741 pa_source_output_new_data_done(&source_output_data);
743 if (!u->source_output)
746 u->source_output->parent.process_msg = source_output_process_msg_cb;
747 u->source_output->push = source_output_push_cb;
748 u->source_output->process_rewind = source_output_process_rewind_cb;
749 u->source_output->kill = source_output_kill_cb;
750 u->source_output->attach = source_output_attach_cb;
751 u->source_output->detach = source_output_detach_cb;
752 u->source_output->state_change = source_output_state_change_cb;
753 u->source_output->may_move_to = source_output_may_move_to_cb;
754 u->source_output->moving = source_output_moving_cb;
755 u->source_output->userdata = u;
757 pa_source_output_set_requested_latency(u->source_output, u->latency/3);
759 pa_sink_input_get_silence(u->sink_input, &silence);
760 u->memblockq = pa_memblockq_new(
762 MEMBLOCKQ_MAXLENGTH, /* maxlength */
763 MEMBLOCKQ_MAXLENGTH, /* tlength */
764 pa_frame_size(&ss), /* base */
768 &silence); /* silence frame */
769 pa_memblock_unref(silence.memblock);
771 u->asyncmsgq = pa_asyncmsgq_new(0);
773 pa_sink_input_put(u->sink_input);
774 pa_source_output_put(u->source_output);
776 if (u->adjust_time > 0)
777 u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u);
791 void pa__done(pa_module*m) {
796 if (!(u = m->userdata))
802 pa_memblockq_free(u->memblockq);
805 pa_asyncmsgq_unref(u->asyncmsgq);
808 u->core->mainloop->time_free(u->time_event);