]> code.delx.au - pulseaudio/blob - src/modules/module-loopback.c
cf88267d8a21d94aa9a9456251ac036da22724cf
[pulseaudio] / src / modules / module-loopback.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2009 Intel Corporation
5 Contributor: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28
29 #include <pulse/xmalloc.h>
30
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>
37
38 #include <pulse/rtclock.h>
39 #include <pulse/timeval.h>
40
41 #include "module-loopback-symdef.h"
42
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?> ");
63
64 #define DEFAULT_LATENCY_MSEC 200
65
66 #define MEMBLOCKQ_MAXLENGTH (1024*1024*16)
67
68 #define DEFAULT_ADJUST_TIME_USEC (10*PA_USEC_PER_SEC)
69
70 struct userdata {
71 pa_core *core;
72 pa_module *module;
73
74 pa_sink_input *sink_input;
75 pa_source_output *source_output;
76
77 pa_asyncmsgq *asyncmsgq;
78 pa_memblockq *memblockq;
79
80 pa_rtpoll_item *rtpoll_item_read, *rtpoll_item_write;
81
82 pa_time_event *time_event;
83 pa_usec_t adjust_time;
84
85 int64_t recv_counter;
86 int64_t send_counter;
87
88 size_t skip;
89 pa_usec_t latency;
90
91 pa_bool_t in_pop;
92 size_t min_memblockq_length;
93
94 struct {
95 int64_t send_counter;
96 size_t source_output_buffer;
97 pa_usec_t source_latency;
98
99 int64_t recv_counter;
100 size_t sink_input_buffer;
101 pa_usec_t sink_latency;
102
103 size_t min_memblockq_length;
104 size_t max_request;
105 } latency_snapshot;
106 };
107
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,
125 };
126
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
132 };
133
134 enum {
135 SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT
136 };
137
138 /* Called from main context */
139 static void teardown(struct userdata *u) {
140 pa_assert(u);
141 pa_assert_ctl_context();
142
143 if (u->sink_input)
144 pa_sink_input_unlink(u->sink_input);
145
146 if (u->source_output)
147 pa_source_output_unlink(u->source_output);
148
149 if (u->sink_input) {
150 pa_sink_input_unref(u->sink_input);
151 u->sink_input = NULL;
152 }
153
154 if (u->source_output) {
155 pa_source_output_unref(u->source_output);
156 u->source_output = NULL;
157 }
158 }
159
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;
165
166 pa_assert(u);
167 pa_assert_ctl_context();
168
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);
171
172 buffer =
173 u->latency_snapshot.sink_input_buffer +
174 u->latency_snapshot.source_output_buffer;
175
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));
180
181 buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);
182
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);
188
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);
192
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;
196
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;
201
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));
212 }
213 }
214
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);
217
218 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
219 }
220
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;
224
225 pa_assert(u);
226 pa_assert(a);
227 pa_assert(u->time_event == e);
228
229 adjust_rates(u);
230 }
231
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;
236
237 pa_source_output_assert_ref(o);
238 pa_source_output_assert_io_context(o);
239 pa_assert_se(u = o->userdata);
240
241 if (u->skip > chunk->length) {
242 u->skip -= chunk->length;
243 return;
244 }
245
246 if (u->skip > 0) {
247 copy = *chunk;
248 copy.index += u->skip;
249 copy.length -= u->skip;
250 u->skip = 0;
251
252 chunk = &copy;
253 }
254
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;
257 }
258
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;
262
263 pa_source_output_assert_ref(o);
264 pa_source_output_assert_io_context(o);
265 pa_assert_se(u = o->userdata);
266
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;
269 }
270
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;
274
275 switch (code) {
276
277 case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: {
278 size_t length;
279
280 length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq);
281
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);
285
286 return 0;
287 }
288 }
289
290 return pa_source_output_process_msg(obj, code, data, offset, chunk);
291 }
292
293 /* Called from output thread context */
294 static void source_output_attach_cb(pa_source_output *o) {
295 struct userdata *u;
296
297 pa_source_output_assert_ref(o);
298 pa_source_output_assert_io_context(o);
299 pa_assert_se(u = o->userdata);
300
301 u->rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
302 o->source->thread_info.rtpoll,
303 PA_RTPOLL_LATE,
304 u->asyncmsgq);
305 }
306
307 /* Called from output thread context */
308 static void source_output_detach_cb(pa_source_output *o) {
309 struct userdata *u;
310
311 pa_source_output_assert_ref(o);
312 pa_source_output_assert_io_context(o);
313 pa_assert_se(u = o->userdata);
314
315 if (u->rtpoll_item_write) {
316 pa_rtpoll_item_free(u->rtpoll_item_write);
317 u->rtpoll_item_write = NULL;
318 }
319 }
320
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;
324
325 pa_source_output_assert_ref(o);
326 pa_source_output_assert_io_context(o);
327 pa_assert_se(u = o->userdata);
328
329 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
330
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);
334
335 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
336 }
337 }
338
339 /* Called from main thread */
340 static void source_output_kill_cb(pa_source_output *o) {
341 struct userdata *u;
342
343 pa_source_output_assert_ref(o);
344 pa_assert_ctl_context();
345 pa_assert_se(u = o->userdata);
346
347 teardown(u);
348 pa_module_unload_request(u->module, TRUE);
349 }
350
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;
354
355 pa_source_output_assert_ref(o);
356 pa_assert_ctl_context();
357 pa_assert_se(u = o->userdata);
358
359 return dest != u->sink_input->sink->monitor_source;
360 }
361
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;
367
368 pa_source_output_assert_ref(o);
369 pa_assert_ctl_context();
370 pa_assert_se(u = o->userdata);
371
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)));
374
375 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
376 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
377
378 pa_sink_input_update_proplist(u->sink_input, PA_UPDATE_REPLACE, p);
379 pa_proplist_free(p);
380 }
381
382 /* Called from output thread context */
383 static void update_min_memblockq_length(struct userdata *u) {
384 size_t length;
385
386 pa_assert(u);
387 pa_sink_input_assert_io_context(u->sink_input);
388
389 length = pa_memblockq_get_length(u->memblockq);
390
391 if (u->min_memblockq_length == (size_t) -1 ||
392 length < u->min_memblockq_length)
393 u->min_memblockq_length = length;
394 }
395
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;
399
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);
404
405 u->in_pop = TRUE;
406 while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0)
407 ;
408 u->in_pop = FALSE;
409
410 if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
411 pa_log_info("Could not peek into queue");
412 return -1;
413 }
414
415 chunk->length = PA_MIN(chunk->length, nbytes);
416 pa_memblockq_drop(u->memblockq, chunk->length);
417
418 update_min_memblockq_length(u);
419
420 return 0;
421 }
422
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;
426
427 pa_sink_input_assert_ref(i);
428 pa_sink_input_assert_io_context(i);
429 pa_assert_se(u = i->userdata);
430
431 pa_memblockq_rewind(u->memblockq, nbytes);
432 }
433
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;
437
438 switch (code) {
439
440 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
441 pa_usec_t *r = data;
442
443 pa_sink_input_assert_io_context(u->sink_input);
444
445 *r = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->sink_input->sample_spec);
446
447 /* Fall through, the default handler will add in the extra
448 * latency added by the resampler */
449 break;
450 }
451
452 case SINK_INPUT_MESSAGE_POST:
453
454 pa_sink_input_assert_io_context(u->sink_input);
455
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);
460
461 update_min_memblockq_length(u);
462
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)) {
468
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);
473 }
474
475 u->recv_counter += (int64_t) chunk->length;
476
477 return 0;
478
479 case SINK_INPUT_MESSAGE_REWIND:
480
481 pa_sink_input_assert_io_context(u->sink_input);
482
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);
487
488 u->recv_counter -= offset;
489
490 update_min_memblockq_length(u);
491
492 return 0;
493
494 case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
495 size_t length;
496
497 update_min_memblockq_length(u);
498
499 length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
500
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);
506
507 u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
508
509 u->latency_snapshot.min_memblockq_length = u->min_memblockq_length;
510 u->min_memblockq_length = (size_t) -1;
511
512 return 0;
513 }
514
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! */
519
520 pa_assert_ctl_context();
521
522 if (u->adjust_time > 0)
523 adjust_rates(u);
524 return 0;
525 }
526 }
527
528 return pa_sink_input_process_msg(obj, code, data, offset, chunk);
529 }
530
531 /* Called from output thread context */
532 static void sink_input_attach_cb(pa_sink_input *i) {
533 struct userdata *u;
534
535 pa_sink_input_assert_ref(i);
536 pa_sink_input_assert_io_context(i);
537 pa_assert_se(u = i->userdata);
538
539 u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
540 i->sink->thread_info.rtpoll,
541 PA_RTPOLL_LATE,
542 u->asyncmsgq);
543
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));
546
547 u->min_memblockq_length = (size_t) -1;
548 }
549
550 /* Called from output thread context */
551 static void sink_input_detach_cb(pa_sink_input *i) {
552 struct userdata *u;
553
554 pa_sink_input_assert_ref(i);
555 pa_sink_input_assert_io_context(i);
556 pa_assert_se(u = i->userdata);
557
558 if (u->rtpoll_item_read) {
559 pa_rtpoll_item_free(u->rtpoll_item_read);
560 u->rtpoll_item_read = NULL;
561 }
562 }
563
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;
567
568 pa_sink_input_assert_ref(i);
569 pa_sink_input_assert_io_context(i);
570 pa_assert_se(u = i->userdata);
571
572 pa_memblockq_set_maxrewind(u->memblockq, nbytes);
573 }
574
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;
578
579 pa_sink_input_assert_ref(i);
580 pa_sink_input_assert_io_context(i);
581 pa_assert_se(u = i->userdata);
582
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);
586 }
587
588 /* Called from main thread */
589 static void sink_input_kill_cb(pa_sink_input *i) {
590 struct userdata *u;
591
592 pa_sink_input_assert_ref(i);
593 pa_assert_ctl_context();
594 pa_assert_se(u = i->userdata);
595
596 teardown(u);
597 pa_module_unload_request(u->module, TRUE);
598 }
599
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;
605
606 pa_sink_input_assert_ref(i);
607 pa_assert_ctl_context();
608 pa_assert_se(u = i->userdata);
609
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)));
612
613 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
614 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
615
616 pa_source_output_update_proplist(u->source_output, PA_UPDATE_REPLACE, p);
617 pa_proplist_free(p);
618 }
619
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;
623
624 pa_sink_input_assert_ref(i);
625 pa_assert_ctl_context();
626 pa_assert_se(u = i->userdata);
627
628 if (!u->source_output->source->monitor_of)
629 return TRUE;
630
631 return dest != u->source_output->source->monitor_of;
632 }
633
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;
650
651 pa_assert(m);
652
653 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
654 pa_log("Failed to parse module arguments");
655 goto fail;
656 }
657
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;
661 }
662
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;
666 }
667
668 if (pa_modargs_get_value_boolean(ma, "remix", &remix) < 0) {
669 pa_log("Invalid boolean remix parameter");
670 goto fail;
671 }
672
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;
678 }
679
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;
684 }
685
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;
690
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;
695 }
696
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;
701
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);
706
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)));
712
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");
717
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);
720
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);
724
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;
729 }
730
731 if (sink_dont_move)
732 sink_input_data.flags |= PA_SINK_INPUT_DONT_MOVE;
733
734 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
735 pa_sink_input_new_data_done(&sink_input_data);
736
737 if (!u->sink_input)
738 goto fail;
739
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;
751
752 pa_sink_input_set_requested_latency(u->sink_input, u->latency/3);
753
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);
758
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)));
764
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");
769
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);
772
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);
776
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;
781 }
782
783 if (source_dont_move)
784 source_output_data.flags |= PA_SOURCE_OUTPUT_DONT_MOVE;
785
786 pa_source_output_new(&u->source_output, m->core, &source_output_data);
787 pa_source_output_new_data_done(&source_output_data);
788
789 if (!u->source_output)
790 goto fail;
791
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;
802
803 pa_source_output_set_requested_latency(u->source_output, u->latency/3);
804
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);
816
817 u->asyncmsgq = pa_asyncmsgq_new(0);
818
819 pa_sink_input_put(u->sink_input);
820 pa_source_output_put(u->source_output);
821
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);
824
825 pa_modargs_free(ma);
826 return 0;
827
828 fail:
829 if (ma)
830 pa_modargs_free(ma);
831
832 pa__done(m);
833
834 return -1;
835 }
836
837 void pa__done(pa_module*m) {
838 struct userdata *u;
839
840 pa_assert(m);
841
842 if (!(u = m->userdata))
843 return;
844
845 teardown(u);
846
847 if (u->memblockq)
848 pa_memblockq_free(u->memblockq);
849
850 if (u->asyncmsgq)
851 pa_asyncmsgq_unref(u->asyncmsgq);
852
853 if (u->time_event)
854 u->core->mainloop->time_free(u->time_event);
855
856 pa_xfree(u);
857 }