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