]> code.delx.au - pulseaudio/blob - src/modules/module-loopback.c
936133fc7e1eaa0a60da91cdc9e434042464d144
[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 #include <math.h>
29
30 #include <pulse/xmalloc.h>
31
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>
38
39 #include <pulse/rtclock.h>
40 #include <pulse/timeval.h>
41
42 #include "module-loopback-symdef.h"
43
44 PA_MODULE_AUTHOR("Pierre-Louis Bossart");
45 PA_MODULE_DESCRIPTION("Loopback from source to sink");
46 PA_MODULE_VERSION(PACKAGE_VERSION);
47 PA_MODULE_LOAD_ONCE(FALSE);
48 PA_MODULE_USAGE(
49 "source=<source to connect to> "
50 "sink=<sink to connect to> "
51 "adjust_time=<how often to readjust rates in s> "
52 "latency_msec=<latency in ms> "
53 "format=<sample format> "
54 "rate=<sample rate> "
55 "channels=<number of channels> "
56 "channel_map=<channel map> "
57 "sink_input_name=<custom name for the sink input> "
58 "source_output_name=<custom name for the source output> "
59 "sink_input_role=<media.role for the sink input> "
60 "source_output_role=<media.role for the source output> "
61 "source_dont_move=<boolean> "
62 "sink_dont_move=<boolean> "
63 "remix=<remix channels?> ");
64
65 #define DEFAULT_LATENCY_MSEC 200
66
67 #define MEMBLOCKQ_MAXLENGTH (1024*1024*16)
68
69 #define DEFAULT_ADJUST_TIME_USEC (10*PA_USEC_PER_SEC)
70
71 struct userdata {
72 pa_core *core;
73 pa_module *module;
74
75 pa_sink_input *sink_input;
76 pa_source_output *source_output;
77
78 pa_asyncmsgq *asyncmsgq;
79 pa_memblockq *memblockq;
80
81 pa_rtpoll_item *rtpoll_item_read, *rtpoll_item_write;
82
83 pa_time_event *time_event;
84 pa_usec_t adjust_time;
85
86 int64_t recv_counter;
87 int64_t send_counter;
88
89 size_t skip;
90 pa_usec_t latency;
91
92 pa_bool_t in_pop;
93 size_t min_memblockq_length;
94
95 struct {
96 int64_t send_counter;
97 size_t source_output_buffer;
98 pa_usec_t source_latency;
99
100 int64_t recv_counter;
101 size_t sink_input_buffer;
102 pa_usec_t sink_latency;
103
104 size_t min_memblockq_length;
105 size_t max_request;
106 } latency_snapshot;
107 };
108
109 static const char* const valid_modargs[] = {
110 "source",
111 "sink",
112 "adjust_time",
113 "latency_msec",
114 "format",
115 "rate",
116 "channels",
117 "channel_map",
118 "sink_input_name",
119 "source_output_name",
120 "sink_input_role",
121 "source_output_role",
122 "source_dont_move",
123 "sink_dont_move",
124 "remix",
125 NULL,
126 };
127
128 enum {
129 SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX,
130 SINK_INPUT_MESSAGE_REWIND,
131 SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT,
132 SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED
133 };
134
135 enum {
136 SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT
137 };
138
139 /* Called from main context */
140 static void teardown(struct userdata *u) {
141 pa_assert(u);
142 pa_assert_ctl_context();
143
144 if (u->sink_input)
145 pa_sink_input_unlink(u->sink_input);
146
147 if (u->source_output)
148 pa_source_output_unlink(u->source_output);
149
150 if (u->sink_input) {
151 pa_sink_input_unref(u->sink_input);
152 u->sink_input = NULL;
153 }
154
155 if (u->source_output) {
156 pa_source_output_unref(u->source_output);
157 u->source_output = NULL;
158 }
159 }
160
161 /* Called from main context */
162 static void adjust_rates(struct userdata *u) {
163 size_t buffer, fs;
164 uint32_t old_rate, base_rate, new_rate;
165 pa_usec_t buffer_latency;
166
167 pa_assert(u);
168 pa_assert_ctl_context();
169
170 pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
171 pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
172
173 buffer =
174 u->latency_snapshot.sink_input_buffer +
175 u->latency_snapshot.source_output_buffer;
176
177 if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter)
178 buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter);
179 else
180 buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter));
181
182 buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);
183
184 pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms",
185 (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
186 (double) buffer_latency / PA_USEC_PER_MSEC,
187 (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC,
188 ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC);
189
190 pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes",
191 u->latency_snapshot.max_request*2,
192 u->latency_snapshot.min_memblockq_length);
193
194 fs = pa_frame_size(&u->sink_input->sample_spec);
195 old_rate = u->sink_input->sample_spec.rate;
196 base_rate = u->source_output->sample_spec.rate;
197
198 if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2)
199 new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
200 else
201 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
203 if (new_rate < (uint32_t) (base_rate*0.8) || new_rate > (uint32_t) (base_rate*1.25)) {
204 pa_log_warn("Sample rates too different, not adjusting (%u vs. %u).", base_rate, new_rate);
205 new_rate = base_rate;
206 } else {
207 if (base_rate < new_rate + 20 && new_rate < base_rate + 20)
208 new_rate = base_rate;
209 /* Do the adjustment in small steps; 2‰ can be considered inaudible */
210 if (new_rate < (uint32_t) (old_rate*0.998) || new_rate > (uint32_t) (old_rate*1.002)) {
211 pa_log_info("New rate of %u Hz not within 2‰ of %u Hz, forcing smaller adjustment", new_rate, old_rate);
212 new_rate = PA_CLAMP(new_rate, (uint32_t) (old_rate*0.998), (uint32_t) (old_rate*1.002));
213 }
214 }
215
216 pa_sink_input_set_rate(u->sink_input, new_rate);
217 pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate);
218
219 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
220 }
221
222 /* Called from main context */
223 static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
224 struct userdata *u = userdata;
225
226 pa_assert(u);
227 pa_assert(a);
228 pa_assert(u->time_event == e);
229
230 adjust_rates(u);
231 }
232
233 /* Called from input thread context */
234 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
235 struct userdata *u;
236 pa_memchunk copy;
237
238 pa_source_output_assert_ref(o);
239 pa_source_output_assert_io_context(o);
240 pa_assert_se(u = o->userdata);
241
242 if (u->skip > chunk->length) {
243 u->skip -= chunk->length;
244 return;
245 }
246
247 if (u->skip > 0) {
248 copy = *chunk;
249 copy.index += u->skip;
250 copy.length -= u->skip;
251 u->skip = 0;
252
253 chunk = &copy;
254 }
255
256 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, chunk, NULL);
257 u->send_counter += (int64_t) chunk->length;
258 }
259
260 /* Called from input thread context */
261 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
262 struct userdata *u;
263
264 pa_source_output_assert_ref(o);
265 pa_source_output_assert_io_context(o);
266 pa_assert_se(u = o->userdata);
267
268 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
269 u->send_counter -= (int64_t) nbytes;
270 }
271
272 /* Called from output thread context */
273 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
274 struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata;
275
276 switch (code) {
277
278 case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: {
279 size_t length;
280
281 length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq);
282
283 u->latency_snapshot.send_counter = u->send_counter;
284 u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length;
285 u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source);
286
287 return 0;
288 }
289 }
290
291 return pa_source_output_process_msg(obj, code, data, offset, chunk);
292 }
293
294 /* Called from output thread context */
295 static void source_output_attach_cb(pa_source_output *o) {
296 struct userdata *u;
297
298 pa_source_output_assert_ref(o);
299 pa_source_output_assert_io_context(o);
300 pa_assert_se(u = o->userdata);
301
302 u->rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
303 o->source->thread_info.rtpoll,
304 PA_RTPOLL_LATE,
305 u->asyncmsgq);
306 }
307
308 /* Called from output thread context */
309 static void source_output_detach_cb(pa_source_output *o) {
310 struct userdata *u;
311
312 pa_source_output_assert_ref(o);
313 pa_source_output_assert_io_context(o);
314 pa_assert_se(u = o->userdata);
315
316 if (u->rtpoll_item_write) {
317 pa_rtpoll_item_free(u->rtpoll_item_write);
318 u->rtpoll_item_write = NULL;
319 }
320 }
321
322 /* Called from output thread context */
323 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
324 struct userdata *u;
325
326 pa_source_output_assert_ref(o);
327 pa_source_output_assert_io_context(o);
328 pa_assert_se(u = o->userdata);
329
330 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
331
332 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
333 u->latency),
334 &o->sample_spec);
335
336 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip);
337 }
338 }
339
340 /* Called from main thread */
341 static void source_output_kill_cb(pa_source_output *o) {
342 struct userdata *u;
343
344 pa_source_output_assert_ref(o);
345 pa_assert_ctl_context();
346 pa_assert_se(u = o->userdata);
347
348 teardown(u);
349 pa_module_unload_request(u->module, TRUE);
350 }
351
352 /* Called from main thread */
353 static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
354 struct userdata *u;
355
356 pa_source_output_assert_ref(o);
357 pa_assert_ctl_context();
358 pa_assert_se(u = o->userdata);
359
360 return dest != u->sink_input->sink->monitor_source;
361 }
362
363 /* Called from main thread */
364 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
365 pa_proplist *p;
366 const char *n;
367 struct userdata *u;
368
369 pa_source_output_assert_ref(o);
370 pa_assert_ctl_context();
371 pa_assert_se(u = o->userdata);
372
373 p = pa_proplist_new();
374 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
375
376 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
377 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
378
379 pa_sink_input_update_proplist(u->sink_input, PA_UPDATE_REPLACE, p);
380 pa_proplist_free(p);
381 }
382
383 /* Called from output thread context */
384 static void update_min_memblockq_length(struct userdata *u) {
385 size_t length;
386
387 pa_assert(u);
388 pa_sink_input_assert_io_context(u->sink_input);
389
390 length = pa_memblockq_get_length(u->memblockq);
391
392 if (u->min_memblockq_length == (size_t) -1 ||
393 length < u->min_memblockq_length)
394 u->min_memblockq_length = length;
395 }
396
397 /* Called from output thread context */
398 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
399 struct userdata *u;
400
401 pa_sink_input_assert_ref(i);
402 pa_sink_input_assert_io_context(i);
403 pa_assert_se(u = i->userdata);
404 pa_assert(chunk);
405
406 u->in_pop = TRUE;
407 while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0)
408 ;
409 u->in_pop = FALSE;
410
411 if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
412 pa_log_info("Could not peek into queue");
413 return -1;
414 }
415
416 chunk->length = PA_MIN(chunk->length, nbytes);
417 pa_memblockq_drop(u->memblockq, chunk->length);
418
419 update_min_memblockq_length(u);
420
421 return 0;
422 }
423
424 /* Called from output thread context */
425 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
426 struct userdata *u;
427
428 pa_sink_input_assert_ref(i);
429 pa_sink_input_assert_io_context(i);
430 pa_assert_se(u = i->userdata);
431
432 pa_memblockq_rewind(u->memblockq, nbytes);
433 }
434
435 /* Called from output thread context */
436 static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
437 struct userdata *u = PA_SINK_INPUT(obj)->userdata;
438
439 switch (code) {
440
441 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
442 pa_usec_t *r = data;
443
444 pa_sink_input_assert_io_context(u->sink_input);
445
446 *r = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->sink_input->sample_spec);
447
448 /* Fall through, the default handler will add in the extra
449 * latency added by the resampler */
450 break;
451 }
452
453 case SINK_INPUT_MESSAGE_POST:
454
455 pa_sink_input_assert_io_context(u->sink_input);
456
457 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
458 pa_memblockq_push_align(u->memblockq, chunk);
459 else
460 pa_memblockq_flush_write(u->memblockq, TRUE);
461
462 update_min_memblockq_length(u);
463
464 /* Is this the end of an underrun? Then let's start things
465 * right-away */
466 if (!u->in_pop &&
467 u->sink_input->thread_info.underrun_for > 0 &&
468 pa_memblockq_is_readable(u->memblockq)) {
469
470 pa_log_debug("Requesting rewind due to end of underrun.");
471 pa_sink_input_request_rewind(u->sink_input,
472 (size_t) (u->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : u->sink_input->thread_info.underrun_for),
473 FALSE, TRUE, FALSE);
474 }
475
476 u->recv_counter += (int64_t) chunk->length;
477
478 return 0;
479
480 case SINK_INPUT_MESSAGE_REWIND:
481
482 pa_sink_input_assert_io_context(u->sink_input);
483
484 if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state))
485 pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, TRUE);
486 else
487 pa_memblockq_flush_write(u->memblockq, TRUE);
488
489 u->recv_counter -= offset;
490
491 update_min_memblockq_length(u);
492
493 return 0;
494
495 case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
496 size_t length;
497
498 update_min_memblockq_length(u);
499
500 length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
501
502 u->latency_snapshot.recv_counter = u->recv_counter;
503 u->latency_snapshot.sink_input_buffer =
504 pa_memblockq_get_length(u->memblockq) +
505 (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, length) : length);
506 u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink);
507
508 u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input);
509
510 u->latency_snapshot.min_memblockq_length = u->min_memblockq_length;
511 u->min_memblockq_length = (size_t) -1;
512
513 return 0;
514 }
515
516 case SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED: {
517 /* This message is sent from the IO thread to the main
518 * thread! So don't be confused. All the user cases above
519 * are executed in thread context, but this one is not! */
520
521 pa_assert_ctl_context();
522
523 if (u->adjust_time > 0)
524 adjust_rates(u);
525 return 0;
526 }
527 }
528
529 return pa_sink_input_process_msg(obj, code, data, offset, chunk);
530 }
531
532 /* Called from output thread context */
533 static void sink_input_attach_cb(pa_sink_input *i) {
534 struct userdata *u;
535
536 pa_sink_input_assert_ref(i);
537 pa_sink_input_assert_io_context(i);
538 pa_assert_se(u = i->userdata);
539
540 u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
541 i->sink->thread_info.rtpoll,
542 PA_RTPOLL_LATE,
543 u->asyncmsgq);
544
545 pa_memblockq_set_prebuf(u->memblockq, pa_sink_input_get_max_request(i)*2);
546 pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i));
547
548 u->min_memblockq_length = (size_t) -1;
549 }
550
551 /* Called from output thread context */
552 static void sink_input_detach_cb(pa_sink_input *i) {
553 struct userdata *u;
554
555 pa_sink_input_assert_ref(i);
556 pa_sink_input_assert_io_context(i);
557 pa_assert_se(u = i->userdata);
558
559 if (u->rtpoll_item_read) {
560 pa_rtpoll_item_free(u->rtpoll_item_read);
561 u->rtpoll_item_read = NULL;
562 }
563 }
564
565 /* Called from output thread context */
566 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
567 struct userdata *u;
568
569 pa_sink_input_assert_ref(i);
570 pa_sink_input_assert_io_context(i);
571 pa_assert_se(u = i->userdata);
572
573 pa_memblockq_set_maxrewind(u->memblockq, nbytes);
574 }
575
576 /* Called from output thread context */
577 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
578 struct userdata *u;
579
580 pa_sink_input_assert_ref(i);
581 pa_sink_input_assert_io_context(i);
582 pa_assert_se(u = i->userdata);
583
584 pa_memblockq_set_prebuf(u->memblockq, nbytes*2);
585 pa_log_info("Max request changed");
586 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED, NULL, 0, NULL, NULL);
587 }
588
589 /* Called from main thread */
590 static void sink_input_kill_cb(pa_sink_input *i) {
591 struct userdata *u;
592
593 pa_sink_input_assert_ref(i);
594 pa_assert_ctl_context();
595 pa_assert_se(u = i->userdata);
596
597 teardown(u);
598 pa_module_unload_request(u->module, TRUE);
599 }
600
601 /* Called from main thread */
602 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
603 struct userdata *u;
604 pa_proplist *p;
605 const char *n;
606
607 pa_sink_input_assert_ref(i);
608 pa_assert_ctl_context();
609 pa_assert_se(u = i->userdata);
610
611 p = pa_proplist_new();
612 pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION)));
613
614 if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME)))
615 pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n);
616
617 pa_source_output_update_proplist(u->source_output, PA_UPDATE_REPLACE, p);
618 pa_proplist_free(p);
619 }
620
621 /* Called from main thread */
622 static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
623 struct userdata *u;
624
625 pa_sink_input_assert_ref(i);
626 pa_assert_ctl_context();
627 pa_assert_se(u = i->userdata);
628
629 if (!u->source_output->source->monitor_of)
630 return TRUE;
631
632 return dest != u->source_output->source->monitor_of;
633 }
634
635 int pa__init(pa_module *m) {
636 pa_modargs *ma = NULL;
637 struct userdata *u;
638 pa_sink *sink;
639 pa_sink_input_new_data sink_input_data;
640 pa_bool_t sink_dont_move;
641 pa_source *source;
642 pa_source_output_new_data source_output_data;
643 pa_bool_t source_dont_move;
644 uint32_t latency_msec;
645 pa_sample_spec ss;
646 pa_channel_map map;
647 pa_memchunk silence;
648 uint32_t adjust_time_sec;
649 const char *n;
650 pa_bool_t remix = TRUE;
651
652 pa_assert(m);
653
654 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
655 pa_log("Failed to parse module arguments");
656 goto fail;
657 }
658
659 if (!(source = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) {
660 pa_log("No such source.");
661 goto fail;
662 }
663
664 if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) {
665 pa_log("No such sink.");
666 goto fail;
667 }
668
669 if (pa_modargs_get_value_boolean(ma, "remix", &remix) < 0) {
670 pa_log("Invalid boolean remix parameter");
671 goto fail;
672 }
673
674 ss = sink->sample_spec;
675 map = sink->channel_map;
676 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
677 pa_log("Invalid sample format specification or channel map");
678 goto fail;
679 }
680
681 latency_msec = DEFAULT_LATENCY_MSEC;
682 if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 2000) {
683 pa_log("Invalid latency specification");
684 goto fail;
685 }
686
687 m->userdata = u = pa_xnew0(struct userdata, 1);
688 u->core = m->core;
689 u->module = m;
690 u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC;
691
692 adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
693 if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) {
694 pa_log("Failed to parse adjust_time value");
695 goto fail;
696 }
697
698 if (adjust_time_sec != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC)
699 u->adjust_time = adjust_time_sec * PA_USEC_PER_SEC;
700 else
701 u->adjust_time = DEFAULT_ADJUST_TIME_USEC;
702
703 pa_sink_input_new_data_init(&sink_input_data);
704 sink_input_data.driver = __FILE__;
705 sink_input_data.module = m;
706 pa_sink_input_new_data_set_sink(&sink_input_data, sink, FALSE);
707
708 if ((n = pa_modargs_get_value(ma, "sink_input_name", NULL)))
709 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, n);
710 else
711 pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback from %s",
712 pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
713
714 if ((n = pa_modargs_get_value(ma, "sink_input_role", NULL)))
715 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, n);
716 else
717 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
718
719 if ((n = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)))
720 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
721
722 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
723 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
724 sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE | (remix ? 0 : PA_SINK_INPUT_NO_REMIX);
725
726 sink_dont_move = FALSE;
727 if (pa_modargs_get_value_boolean(ma, "sink_dont_move", &sink_dont_move) < 0) {
728 pa_log("sink_dont_move= expects a boolean argument.");
729 goto fail;
730 }
731
732 if (sink_dont_move)
733 sink_input_data.flags |= PA_SINK_INPUT_DONT_MOVE;
734
735 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
736 pa_sink_input_new_data_done(&sink_input_data);
737
738 if (!u->sink_input)
739 goto fail;
740
741 u->sink_input->parent.process_msg = sink_input_process_msg_cb;
742 u->sink_input->pop = sink_input_pop_cb;
743 u->sink_input->process_rewind = sink_input_process_rewind_cb;
744 u->sink_input->kill = sink_input_kill_cb;
745 u->sink_input->attach = sink_input_attach_cb;
746 u->sink_input->detach = sink_input_detach_cb;
747 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
748 u->sink_input->update_max_request = sink_input_update_max_request_cb;
749 u->sink_input->may_move_to = sink_input_may_move_to_cb;
750 u->sink_input->moving = sink_input_moving_cb;
751 u->sink_input->userdata = u;
752
753 pa_sink_input_set_requested_latency(u->sink_input, u->latency/3);
754
755 pa_source_output_new_data_init(&source_output_data);
756 source_output_data.driver = __FILE__;
757 source_output_data.module = m;
758 pa_source_output_new_data_set_source(&source_output_data, source, FALSE);
759
760 if ((n = pa_modargs_get_value(ma, "source_output_name", NULL)))
761 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, n);
762 else
763 pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s",
764 pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
765
766 if ((n = pa_modargs_get_value(ma, "source_output_role", NULL)))
767 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, n);
768 else
769 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract");
770
771 if ((n = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)))
772 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ICON_NAME, n);
773
774 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
775 pa_source_output_new_data_set_channel_map(&source_output_data, &map);
776 source_output_data.flags = (remix ? 0 : PA_SOURCE_OUTPUT_NO_REMIX);
777
778 source_dont_move = FALSE;
779 if (pa_modargs_get_value_boolean(ma, "source_dont_move", &source_dont_move) < 0) {
780 pa_log("source_dont_move= expects a boolean argument.");
781 goto fail;
782 }
783
784 if (source_dont_move)
785 source_output_data.flags |= PA_SOURCE_OUTPUT_DONT_MOVE;
786
787 pa_source_output_new(&u->source_output, m->core, &source_output_data);
788 pa_source_output_new_data_done(&source_output_data);
789
790 if (!u->source_output)
791 goto fail;
792
793 u->source_output->parent.process_msg = source_output_process_msg_cb;
794 u->source_output->push = source_output_push_cb;
795 u->source_output->process_rewind = source_output_process_rewind_cb;
796 u->source_output->kill = source_output_kill_cb;
797 u->source_output->attach = source_output_attach_cb;
798 u->source_output->detach = source_output_detach_cb;
799 u->source_output->state_change = source_output_state_change_cb;
800 u->source_output->may_move_to = source_output_may_move_to_cb;
801 u->source_output->moving = source_output_moving_cb;
802 u->source_output->userdata = u;
803
804 pa_source_output_set_requested_latency(u->source_output, u->latency/3);
805
806 pa_sink_input_get_silence(u->sink_input, &silence);
807 u->memblockq = pa_memblockq_new(
808 0, /* idx */
809 MEMBLOCKQ_MAXLENGTH, /* maxlength */
810 MEMBLOCKQ_MAXLENGTH, /* tlength */
811 pa_frame_size(&ss), /* base */
812 0, /* prebuf */
813 0, /* minreq */
814 0, /* maxrewind */
815 &silence); /* silence frame */
816 pa_memblock_unref(silence.memblock);
817
818 u->asyncmsgq = pa_asyncmsgq_new(0);
819
820 pa_sink_input_put(u->sink_input);
821 pa_source_output_put(u->source_output);
822
823 if (u->adjust_time > 0)
824 u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u);
825
826 pa_modargs_free(ma);
827 return 0;
828
829 fail:
830 if (ma)
831 pa_modargs_free(ma);
832
833 pa__done(m);
834
835 return -1;
836 }
837
838 void pa__done(pa_module*m) {
839 struct userdata *u;
840
841 pa_assert(m);
842
843 if (!(u = m->userdata))
844 return;
845
846 teardown(u);
847
848 if (u->memblockq)
849 pa_memblockq_free(u->memblockq);
850
851 if (u->asyncmsgq)
852 pa_asyncmsgq_unref(u->asyncmsgq);
853
854 if (u->time_event)
855 u->core->mainloop->time_free(u->time_event);
856
857 pa_xfree(u);
858 }