2 This file is part of PulseAudio.
4 Copyright 2010 Wim Taymans <wim.taymans@gmail.com>
6 Based on module-virtual-sink.c
7 module-virtual-source.c
10 Copyright 2010 Intel Corporation
11 Contributor: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
13 PulseAudio is free software; you can redistribute it and/or modify
14 it under the terms of the GNU Lesser General Public License as published
15 by the Free Software Foundation; either version 2.1 of the License,
16 or (at your option) any later version.
18 PulseAudio is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public License
24 along with PulseAudio; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
36 #include "echo-cancel.h"
38 #include <pulse/xmalloc.h>
39 #include <pulse/timeval.h>
40 #include <pulse/rtclock.h>
42 #include <pulsecore/i18n.h>
43 #include <pulsecore/atomic.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/namereg.h>
46 #include <pulsecore/sink.h>
47 #include <pulsecore/module.h>
48 #include <pulsecore/core-rtclock.h>
49 #include <pulsecore/core-util.h>
50 #include <pulsecore/modargs.h>
51 #include <pulsecore/log.h>
52 #include <pulsecore/rtpoll.h>
53 #include <pulsecore/sample-util.h>
54 #include <pulsecore/ltdl-helper.h>
56 #include <pulsecore/protocol-native.h>
57 #include <pulsecore/pstream-util.h>
59 #include "module-echo-cancel-symdef.h"
61 PA_MODULE_AUTHOR("Wim Taymans");
62 PA_MODULE_DESCRIPTION("Echo Cancellation");
63 PA_MODULE_VERSION(PACKAGE_VERSION);
64 PA_MODULE_LOAD_ONCE(false);
66 _("source_name=<name for the source> "
67 "source_properties=<properties for the source> "
68 "source_master=<name of source to filter> "
69 "sink_name=<name for the sink> "
70 "sink_properties=<properties for the sink> "
71 "sink_master=<name of sink to filter> "
72 "adjust_time=<how often to readjust rates in s> "
73 "adjust_threshold=<how much drift to readjust after in ms> "
74 "format=<sample format> "
76 "channels=<number of channels> "
77 "channel_map=<channel map> "
78 "aec_method=<implementation to use> "
79 "aec_args=<parameters for the AEC engine> "
80 "save_aec=<save AEC data in /tmp> "
81 "autoloaded=<set if this module is being loaded automatically> "
82 "use_volume_sharing=<yes or no> "
85 /* NOTE: Make sure the enum and ec_table are maintained in the correct order */
87 PA_ECHO_CANCELLER_INVALID = -1,
88 PA_ECHO_CANCELLER_NULL,
90 PA_ECHO_CANCELLER_SPEEX,
93 PA_ECHO_CANCELLER_ADRIAN,
96 PA_ECHO_CANCELLER_WEBRTC,
98 } pa_echo_canceller_method_t;
106 #define DEFAULT_ECHO_CANCELLER "webrtc"
108 #define DEFAULT_ECHO_CANCELLER "speex"
111 static const pa_echo_canceller ec_table[] = {
113 /* Null, Dummy echo canceller (just copies data) */
114 .init = pa_null_ec_init,
115 .run = pa_null_ec_run,
116 .done = pa_null_ec_done,
121 .init = pa_speex_ec_init,
122 .run = pa_speex_ec_run,
123 .done = pa_speex_ec_done,
126 #ifdef HAVE_ADRIAN_EC
128 /* Adrian Andre's NLMS implementation */
129 .init = pa_adrian_ec_init,
130 .run = pa_adrian_ec_run,
131 .done = pa_adrian_ec_done,
136 /* WebRTC's audio processing engine */
137 .init = pa_webrtc_ec_init,
138 .play = pa_webrtc_ec_play,
139 .record = pa_webrtc_ec_record,
140 .set_drift = pa_webrtc_ec_set_drift,
141 .run = pa_webrtc_ec_run,
142 .done = pa_webrtc_ec_done,
147 #define DEFAULT_RATE 32000
148 #define DEFAULT_CHANNELS 1
149 #define DEFAULT_ADJUST_TIME_USEC (1*PA_USEC_PER_SEC)
150 #define DEFAULT_ADJUST_TOLERANCE (5*PA_USEC_PER_MSEC)
151 #define DEFAULT_SAVE_AEC false
152 #define DEFAULT_AUTOLOADED false
154 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
156 /* Can only be used in main context */
157 #define IS_ACTIVE(u) ((pa_source_get_state((u)->source) == PA_SOURCE_RUNNING) && \
158 (pa_sink_get_state((u)->sink) == PA_SINK_RUNNING))
160 /* This module creates a new (virtual) source and sink.
162 * The data sent to the new sink is kept in a memblockq before being
163 * forwarded to the real sink_master.
165 * Data read from source_master is matched against the saved sink data and
166 * echo canceled data is then pushed onto the new source.
168 * Both source and sink masters have their own threads to push/pull data
169 * respectively. We however perform all our actions in the source IO thread.
170 * To do this we send all played samples to the source IO thread where they
171 * are then pushed into the memblockq.
173 * Alignment is performed in two steps:
175 * 1) when something happens that requires quick adjustment of the alignment of
176 * capture and playback samples, we perform a resync. This adjusts the
177 * position in the playback memblock to the requested sample. Quick
178 * adjustments include moving the playback samples before the capture
179 * samples (because else the echo canceler does not work) or when the
180 * playback pointer drifts too far away.
182 * 2) periodically check the difference between capture and playback. We use a
183 * low and high watermark for adjusting the alignment. Playback should always
184 * be before capture and the difference should not be bigger than one frame
185 * size. We would ideally like to resample the sink_input but most driver
186 * don't give enough accuracy to be able to do that right now.
191 struct pa_echo_canceller_msg {
193 struct userdata *userdata;
196 PA_DEFINE_PRIVATE_CLASS(pa_echo_canceller_msg, pa_msgobject);
197 #define PA_ECHO_CANCELLER_MSG(o) (pa_echo_canceller_msg_cast(o))
201 pa_usec_t sink_latency;
203 int64_t send_counter;
205 pa_usec_t source_now;
206 pa_usec_t source_latency;
208 int64_t recv_counter;
221 pa_echo_canceller *ec;
222 uint32_t source_output_blocksize;
223 uint32_t source_blocksize;
224 uint32_t sink_blocksize;
228 /* to wakeup the source I/O thread */
229 pa_asyncmsgq *asyncmsgq;
230 pa_rtpoll_item *rtpoll_item_read, *rtpoll_item_write;
233 bool source_auto_desc;
234 pa_source_output *source_output;
235 pa_memblockq *source_memblockq; /* echo canceler needs fixed sized chunks */
240 pa_sink_input *sink_input;
241 pa_memblockq *sink_memblockq;
242 int64_t send_counter; /* updated in sink IO thread */
243 int64_t recv_counter;
246 /* Bytes left over from previous iteration */
250 pa_atomic_t request_resync;
252 pa_time_event *time_event;
253 pa_usec_t adjust_time;
254 int adjust_threshold;
261 bool use_volume_sharing;
264 pa_cvolume current_volume;
267 pa_native_protocol *protocol;
270 static void source_output_snapshot_within_thread(struct userdata *u, struct snapshot *snapshot);
272 static const char* const valid_modargs[] = {
289 "use_volume_sharing",
294 SOURCE_OUTPUT_MESSAGE_POST = PA_SOURCE_OUTPUT_MESSAGE_MAX,
295 SOURCE_OUTPUT_MESSAGE_REWIND,
296 SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT,
297 SOURCE_OUTPUT_MESSAGE_APPLY_DIFF_TIME
301 SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT
305 ECHO_CANCELLER_MESSAGE_SET_VOLUME,
308 static int64_t calc_diff(struct userdata *u, struct snapshot *snapshot) {
309 int64_t diff_time, buffer_latency;
310 pa_usec_t plen, rlen, source_delay, sink_delay, recv_counter, send_counter;
312 /* get latency difference between playback and record */
313 plen = pa_bytes_to_usec(snapshot->plen, &u->sink_input->sample_spec);
314 rlen = pa_bytes_to_usec(snapshot->rlen, &u->source_output->sample_spec);
316 buffer_latency = plen - rlen;
320 source_delay = pa_bytes_to_usec(snapshot->source_delay, &u->source_output->sample_spec);
321 sink_delay = pa_bytes_to_usec(snapshot->sink_delay, &u->sink_input->sample_spec);
322 buffer_latency += source_delay + sink_delay;
324 /* add the latency difference due to samples not yet transferred */
325 send_counter = pa_bytes_to_usec(snapshot->send_counter, &u->sink->sample_spec);
326 recv_counter = pa_bytes_to_usec(snapshot->recv_counter, &u->sink->sample_spec);
327 if (recv_counter <= send_counter)
328 buffer_latency += (int64_t) (send_counter - recv_counter);
330 buffer_latency += PA_CLIP_SUB(buffer_latency, (int64_t) (recv_counter - send_counter));
332 /* capture and playback are perfectly aligned when diff_time is 0 */
333 diff_time = (snapshot->sink_now + snapshot->sink_latency - buffer_latency) -
334 (snapshot->source_now - snapshot->source_latency);
336 pa_log_debug("Diff %lld (%lld - %lld + %lld) %lld %lld %lld %lld", (long long) diff_time,
337 (long long) snapshot->sink_latency,
338 (long long) buffer_latency, (long long) snapshot->source_latency,
339 (long long) source_delay, (long long) sink_delay,
340 (long long) (send_counter - recv_counter),
341 (long long) (snapshot->sink_now - snapshot->source_now));
346 /* Called from main context */
347 static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
348 struct userdata *u = userdata;
349 uint32_t old_rate, base_rate, new_rate;
352 struct snapshot latency_snapshot;
356 pa_assert(u->time_event == e);
357 pa_assert_ctl_context();
362 /* update our snapshots */
363 pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, &latency_snapshot, 0, NULL);
364 pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, &latency_snapshot, 0, NULL);
366 /* calculate drift between capture and playback */
367 diff_time = calc_diff(u, &latency_snapshot);
369 /*fs = pa_frame_size(&u->source_output->sample_spec);*/
370 old_rate = u->sink_input->sample_spec.rate;
371 base_rate = u->source_output->sample_spec.rate;
374 /* recording before playback, we need to adjust quickly. The echo
375 * canceler does not work in this case. */
376 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_APPLY_DIFF_TIME,
377 NULL, diff_time, NULL, NULL);
378 /*new_rate = base_rate - ((pa_usec_to_bytes(-diff_time, &u->source_output->sample_spec) / fs) * PA_USEC_PER_SEC) / u->adjust_time;*/
379 new_rate = base_rate;
382 if (diff_time > u->adjust_threshold) {
383 /* diff too big, quickly adjust */
384 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_APPLY_DIFF_TIME,
385 NULL, diff_time, NULL, NULL);
388 /* recording behind playback, we need to slowly adjust the rate to match */
389 /*new_rate = base_rate + ((pa_usec_to_bytes(diff_time, &u->source_output->sample_spec) / fs) * PA_USEC_PER_SEC) / u->adjust_time;*/
391 /* assume equal samplerates for now */
392 new_rate = base_rate;
395 /* make sure we don't make too big adjustments because that sounds horrible */
396 if (new_rate > base_rate * 1.1 || new_rate < base_rate * 0.9)
397 new_rate = base_rate;
399 if (new_rate != old_rate) {
400 pa_log_info("Old rate %lu Hz, new rate %lu Hz", (unsigned long) old_rate, (unsigned long) new_rate);
402 pa_sink_input_set_rate(u->sink_input, new_rate);
405 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
408 /* Called from source I/O thread context */
409 static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
410 struct userdata *u = PA_SOURCE(o)->userdata;
414 case PA_SOURCE_MESSAGE_GET_LATENCY:
416 /* The source is _put() before the source output is, so let's
417 * make sure we don't access it in that time. Also, the
418 * source output is first shut down, the source second. */
419 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
420 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) {
421 *((pa_usec_t*) data) = 0;
425 *((pa_usec_t*) data) =
427 /* Get the latency of the master source */
428 pa_source_get_latency_within_thread(u->source_output->source) +
429 /* Add the latency internal to our source output on top */
430 pa_bytes_to_usec(pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq), &u->source_output->source->sample_spec) +
431 /* and the buffering we do on the source */
432 pa_bytes_to_usec(u->source_output_blocksize, &u->source_output->source->sample_spec);
436 case PA_SOURCE_MESSAGE_SET_VOLUME_SYNCED:
437 u->thread_info.current_volume = u->source->reference_volume;
441 return pa_source_process_msg(o, code, data, offset, chunk);
444 /* Called from sink I/O thread context */
445 static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
446 struct userdata *u = PA_SINK(o)->userdata;
450 case PA_SINK_MESSAGE_GET_LATENCY:
452 /* The sink is _put() before the sink input is, so let's
453 * make sure we don't access it in that time. Also, the
454 * sink input is first shut down, the sink second. */
455 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
456 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) {
457 *((pa_usec_t*) data) = 0;
461 *((pa_usec_t*) data) =
463 /* Get the latency of the master sink */
464 pa_sink_get_latency_within_thread(u->sink_input->sink) +
466 /* Add the latency internal to our sink input on top */
467 pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
472 return pa_sink_process_msg(o, code, data, offset, chunk);
475 /* Called from main context */
476 static int source_set_state_cb(pa_source *s, pa_source_state_t state) {
479 pa_source_assert_ref(s);
480 pa_assert_se(u = s->userdata);
482 if (!PA_SOURCE_IS_LINKED(state) ||
483 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
486 if (state == PA_SOURCE_RUNNING) {
487 /* restart timer when both sink and source are active */
488 if (IS_ACTIVE(u) && u->adjust_time)
489 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
491 pa_atomic_store(&u->request_resync, 1);
492 pa_source_output_cork(u->source_output, false);
493 } else if (state == PA_SOURCE_SUSPENDED) {
494 pa_source_output_cork(u->source_output, true);
500 /* Called from main context */
501 static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
504 pa_sink_assert_ref(s);
505 pa_assert_se(u = s->userdata);
507 if (!PA_SINK_IS_LINKED(state) ||
508 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
511 if (state == PA_SINK_RUNNING) {
512 /* restart timer when both sink and source are active */
513 if (IS_ACTIVE(u) && u->adjust_time)
514 pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
516 pa_atomic_store(&u->request_resync, 1);
517 pa_sink_input_cork(u->sink_input, false);
518 } else if (state == PA_SINK_SUSPENDED) {
519 pa_sink_input_cork(u->sink_input, true);
525 /* Called from source I/O thread context */
526 static void source_update_requested_latency_cb(pa_source *s) {
529 pa_source_assert_ref(s);
530 pa_assert_se(u = s->userdata);
532 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
533 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
536 pa_log_debug("Source update requested latency");
538 /* Just hand this one over to the master source */
539 pa_source_output_set_requested_latency_within_thread(
541 pa_source_get_requested_latency_within_thread(s));
544 /* Called from sink I/O thread context */
545 static void sink_update_requested_latency_cb(pa_sink *s) {
548 pa_sink_assert_ref(s);
549 pa_assert_se(u = s->userdata);
551 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
552 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
555 pa_log_debug("Sink update requested latency");
557 /* Just hand this one over to the master sink */
558 pa_sink_input_set_requested_latency_within_thread(
560 pa_sink_get_requested_latency_within_thread(s));
563 /* Called from sink I/O thread context */
564 static void sink_request_rewind_cb(pa_sink *s) {
567 pa_sink_assert_ref(s);
568 pa_assert_se(u = s->userdata);
570 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
571 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
574 pa_log_debug("Sink request rewind %lld", (long long) s->thread_info.rewind_nbytes);
576 /* Just hand this one over to the master sink */
577 pa_sink_input_request_rewind(u->sink_input,
578 s->thread_info.rewind_nbytes, true, false, false);
581 /* Called from main context */
582 static void source_set_volume_cb(pa_source *s) {
585 pa_source_assert_ref(s);
586 pa_assert_se(u = s->userdata);
588 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
589 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
592 pa_source_output_set_volume(u->source_output, &s->real_volume, s->save_volume, true);
595 /* Called from main context */
596 static void sink_set_volume_cb(pa_sink *s) {
599 pa_sink_assert_ref(s);
600 pa_assert_se(u = s->userdata);
602 if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
603 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
606 pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, true);
609 /* Called from main context. */
610 static void source_get_volume_cb(pa_source *s) {
614 pa_source_assert_ref(s);
615 pa_assert_se(u = s->userdata);
617 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
618 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
621 pa_source_output_get_volume(u->source_output, &v, true);
623 if (pa_cvolume_equal(&s->real_volume, &v))
628 pa_source_set_soft_volume(s, NULL);
631 /* Called from main context */
632 static void source_set_mute_cb(pa_source *s) {
635 pa_source_assert_ref(s);
636 pa_assert_se(u = s->userdata);
638 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
639 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
642 pa_source_output_set_mute(u->source_output, s->muted, s->save_muted);
645 /* Called from main context */
646 static void sink_set_mute_cb(pa_sink *s) {
649 pa_sink_assert_ref(s);
650 pa_assert_se(u = s->userdata);
652 if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
653 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
656 pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
659 /* Called from main context */
660 static void source_get_mute_cb(pa_source *s) {
663 pa_source_assert_ref(s);
664 pa_assert_se(u = s->userdata);
666 if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s)) ||
667 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
670 pa_source_output_get_mute(u->source_output);
673 /* Called from source I/O thread context. */
674 static void apply_diff_time(struct userdata *u, int64_t diff_time) {
678 diff = pa_usec_to_bytes(-diff_time, &u->sink_input->sample_spec);
681 /* add some extra safety samples to compensate for jitter in the
683 diff += 10 * pa_frame_size (&u->sink_input->sample_spec);
685 pa_log("Playback after capture (%lld), drop sink %lld", (long long) diff_time, (long long) diff);
690 } else if (diff_time > 0) {
691 diff = pa_usec_to_bytes(diff_time, &u->source_output->sample_spec);
694 pa_log("Playback too far ahead (%lld), drop source %lld", (long long) diff_time, (long long) diff);
696 u->source_skip = diff;
702 /* Called from source I/O thread context. */
703 static void do_resync(struct userdata *u) {
705 struct snapshot latency_snapshot;
707 pa_log("Doing resync");
709 /* update our snapshot */
710 source_output_snapshot_within_thread(u, &latency_snapshot);
711 pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, &latency_snapshot, 0, NULL);
713 /* calculate drift between capture and playback */
714 diff_time = calc_diff(u, &latency_snapshot);
716 /* and adjust for the drift */
717 apply_diff_time(u, diff_time);
720 /* 1. Calculate drift at this point, pass to canceller
721 * 2. Push out playback samples in blocksize chunks
722 * 3. Push out capture samples in blocksize chunks
726 * Called from source I/O thread context.
728 static void do_push_drift_comp(struct userdata *u) {
730 pa_memchunk rchunk, pchunk, cchunk;
731 uint8_t *rdata, *pdata, *cdata;
733 int unused PA_GCC_UNUSED;
735 rlen = pa_memblockq_get_length(u->source_memblockq);
736 plen = pa_memblockq_get_length(u->sink_memblockq);
738 /* Estimate snapshot drift as follows:
739 * pd: amount of data consumed since last time
740 * rd: amount of data consumed since last time
742 * drift = (pd - rd) / rd;
744 * We calculate pd and rd as the memblockq length less the number of
745 * samples left from the last iteration (to avoid double counting
746 * those remainder samples.
748 drift = ((float)(plen - u->sink_rem) - (rlen - u->source_rem)) / ((float)(rlen - u->source_rem));
749 u->sink_rem = plen % u->sink_blocksize;
750 u->source_rem = rlen % u->source_output_blocksize;
752 /* Now let the canceller work its drift compensation magic */
753 u->ec->set_drift(u->ec, drift);
757 fprintf(u->drift_file, "d %a\n", drift);
760 /* Send in the playback samples first */
761 while (plen >= u->sink_blocksize) {
762 pa_memblockq_peek_fixed_size(u->sink_memblockq, u->sink_blocksize, &pchunk);
763 pdata = pa_memblock_acquire(pchunk.memblock);
764 pdata += pchunk.index;
766 u->ec->play(u->ec, pdata);
770 fprintf(u->drift_file, "p %d\n", u->sink_blocksize);
772 unused = fwrite(pdata, 1, u->sink_blocksize, u->played_file);
775 pa_memblock_release(pchunk.memblock);
776 pa_memblockq_drop(u->sink_memblockq, u->sink_blocksize);
777 pa_memblock_unref(pchunk.memblock);
779 plen -= u->sink_blocksize;
782 /* And now the capture samples */
783 while (rlen >= u->source_output_blocksize) {
784 pa_memblockq_peek_fixed_size(u->source_memblockq, u->source_output_blocksize, &rchunk);
786 rdata = pa_memblock_acquire(rchunk.memblock);
787 rdata += rchunk.index;
790 cchunk.length = u->source_output_blocksize;
791 cchunk.memblock = pa_memblock_new(u->source->core->mempool, cchunk.length);
792 cdata = pa_memblock_acquire(cchunk.memblock);
794 u->ec->record(u->ec, rdata, cdata);
798 fprintf(u->drift_file, "c %d\n", u->source_output_blocksize);
799 if (u->captured_file)
800 unused = fwrite(rdata, 1, u->source_output_blocksize, u->captured_file);
801 if (u->canceled_file)
802 unused = fwrite(cdata, 1, u->source_output_blocksize, u->canceled_file);
805 pa_memblock_release(cchunk.memblock);
806 pa_memblock_release(rchunk.memblock);
808 pa_memblock_unref(rchunk.memblock);
810 pa_source_post(u->source, &cchunk);
811 pa_memblock_unref(cchunk.memblock);
813 pa_memblockq_drop(u->source_memblockq, u->source_output_blocksize);
814 rlen -= u->source_output_blocksize;
818 /* This one's simpler than the drift compensation case -- we just iterate over
819 * the capture buffer, and pass the canceller blocksize bytes of playback and
822 * Called from source I/O thread context. */
823 static void do_push(struct userdata *u) {
825 pa_memchunk rchunk, pchunk, cchunk;
826 uint8_t *rdata, *pdata, *cdata;
827 int unused PA_GCC_UNUSED;
829 rlen = pa_memblockq_get_length(u->source_memblockq);
830 plen = pa_memblockq_get_length(u->sink_memblockq);
832 while (rlen >= u->source_output_blocksize) {
834 /* take fixed blocks from recorded and played samples */
835 pa_memblockq_peek_fixed_size(u->source_memblockq, u->source_output_blocksize, &rchunk);
836 pa_memblockq_peek_fixed_size(u->sink_memblockq, u->sink_blocksize, &pchunk);
838 /* we ran out of played data and pchunk has been filled with silence bytes */
839 if (plen < u->sink_blocksize)
840 pa_memblockq_seek(u->sink_memblockq, u->sink_blocksize - plen, PA_SEEK_RELATIVE, true);
842 rdata = pa_memblock_acquire(rchunk.memblock);
843 rdata += rchunk.index;
844 pdata = pa_memblock_acquire(pchunk.memblock);
845 pdata += pchunk.index;
848 cchunk.length = u->source_blocksize;
849 cchunk.memblock = pa_memblock_new(u->source->core->mempool, cchunk.length);
850 cdata = pa_memblock_acquire(cchunk.memblock);
853 if (u->captured_file)
854 unused = fwrite(rdata, 1, u->source_output_blocksize, u->captured_file);
856 unused = fwrite(pdata, 1, u->sink_blocksize, u->played_file);
859 /* perform echo cancellation */
860 u->ec->run(u->ec, rdata, pdata, cdata);
863 if (u->canceled_file)
864 unused = fwrite(cdata, 1, u->source_blocksize, u->canceled_file);
867 pa_memblock_release(cchunk.memblock);
868 pa_memblock_release(pchunk.memblock);
869 pa_memblock_release(rchunk.memblock);
871 /* drop consumed source samples */
872 pa_memblockq_drop(u->source_memblockq, u->source_output_blocksize);
873 pa_memblock_unref(rchunk.memblock);
874 rlen -= u->source_output_blocksize;
876 /* drop consumed sink samples */
877 pa_memblockq_drop(u->sink_memblockq, u->sink_blocksize);
878 pa_memblock_unref(pchunk.memblock);
880 if (plen >= u->sink_blocksize)
881 plen -= u->sink_blocksize;
885 /* forward the (echo-canceled) data to the virtual source */
886 pa_source_post(u->source, &cchunk);
887 pa_memblock_unref(cchunk.memblock);
891 /* Called from source I/O thread context. */
892 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
894 size_t rlen, plen, to_skip;
897 pa_source_output_assert_ref(o);
898 pa_source_output_assert_io_context(o);
899 pa_assert_se(u = o->userdata);
901 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output))) {
902 pa_log("Push when no link?");
906 if (PA_UNLIKELY(u->source->thread_info.state != PA_SOURCE_RUNNING ||
907 u->sink->thread_info.state != PA_SINK_RUNNING)) {
908 pa_source_post(u->source, chunk);
912 /* handle queued messages, do any message sending of our own */
913 while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0)
916 pa_memblockq_push_align(u->source_memblockq, chunk);
918 rlen = pa_memblockq_get_length(u->source_memblockq);
919 plen = pa_memblockq_get_length(u->sink_memblockq);
921 /* Let's not do anything else till we have enough data to process */
922 if (rlen < u->source_output_blocksize)
925 /* See if we need to drop samples in order to sync */
926 if (pa_atomic_cmpxchg (&u->request_resync, 1, 0)) {
930 /* Okay, skip cancellation for skipped source samples if needed. */
931 if (PA_UNLIKELY(u->source_skip)) {
932 /* The slightly tricky bit here is that we drop all but modulo
933 * blocksize bytes and then adjust for that last bit on the sink side.
934 * We do this because the source data is coming at a fixed rate, which
935 * means the only way to try to catch up is drop sink samples and let
936 * the canceller cope up with this. */
937 to_skip = rlen >= u->source_skip ? u->source_skip : rlen;
938 to_skip -= to_skip % u->source_output_blocksize;
941 pa_memblockq_peek_fixed_size(u->source_memblockq, to_skip, &rchunk);
942 pa_source_post(u->source, &rchunk);
944 pa_memblock_unref(rchunk.memblock);
945 pa_memblockq_drop(u->source_memblockq, to_skip);
948 u->source_skip -= to_skip;
951 if (rlen && u->source_skip % u->source_output_blocksize) {
952 u->sink_skip += (uint64_t) (u->source_output_blocksize - (u->source_skip % u->source_output_blocksize)) * u->sink_blocksize / u->source_output_blocksize;
953 u->source_skip -= (u->source_skip % u->source_output_blocksize);
957 /* And for the sink, these samples have been played back already, so we can
958 * just drop them and get on with it. */
959 if (PA_UNLIKELY(u->sink_skip)) {
960 to_skip = plen >= u->sink_skip ? u->sink_skip : plen;
962 pa_memblockq_drop(u->sink_memblockq, to_skip);
965 u->sink_skip -= to_skip;
968 /* process and push out samples */
969 if (u->ec->params.drift_compensation)
970 do_push_drift_comp(u);
975 /* Called from sink I/O thread context. */
976 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
979 pa_sink_input_assert_ref(i);
981 pa_assert_se(u = i->userdata);
983 if (u->sink->thread_info.rewind_requested)
984 pa_sink_process_rewind(u->sink, 0);
986 pa_sink_render_full(u->sink, nbytes, chunk);
988 if (i->thread_info.underrun_for > 0) {
989 pa_log_debug("Handling end of underrun.");
990 pa_atomic_store(&u->request_resync, 1);
993 /* let source thread handle the chunk. pass the sample count as well so that
994 * the source IO thread can update the right variables. */
995 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_POST,
996 NULL, 0, chunk, NULL);
997 u->send_counter += chunk->length;
1002 /* Called from source I/O thread context. */
1003 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
1006 pa_source_output_assert_ref(o);
1007 pa_source_output_assert_io_context(o);
1008 pa_assert_se(u = o->userdata);
1010 pa_source_process_rewind(u->source, nbytes);
1012 /* go back on read side, we need to use older sink data for this */
1013 pa_memblockq_rewind(u->sink_memblockq, nbytes);
1015 /* manipulate write index */
1016 pa_memblockq_seek(u->source_memblockq, -nbytes, PA_SEEK_RELATIVE, true);
1018 pa_log_debug("Source rewind (%lld) %lld", (long long) nbytes,
1019 (long long) pa_memblockq_get_length (u->source_memblockq));
1022 /* Called from sink I/O thread context. */
1023 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1026 pa_sink_input_assert_ref(i);
1027 pa_assert_se(u = i->userdata);
1029 pa_log_debug("Sink process rewind %lld", (long long) nbytes);
1031 pa_sink_process_rewind(u->sink, nbytes);
1033 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL);
1034 u->send_counter -= nbytes;
1037 /* Called from source I/O thread context. */
1038 static void source_output_snapshot_within_thread(struct userdata *u, struct snapshot *snapshot) {
1039 size_t delay, rlen, plen;
1040 pa_usec_t now, latency;
1042 now = pa_rtclock_now();
1043 latency = pa_source_get_latency_within_thread(u->source_output->source);
1044 delay = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq);
1046 delay = (u->source_output->thread_info.resampler ? pa_resampler_request(u->source_output->thread_info.resampler, delay) : delay);
1047 rlen = pa_memblockq_get_length(u->source_memblockq);
1048 plen = pa_memblockq_get_length(u->sink_memblockq);
1050 snapshot->source_now = now;
1051 snapshot->source_latency = latency;
1052 snapshot->source_delay = delay;
1053 snapshot->recv_counter = u->recv_counter;
1054 snapshot->rlen = rlen + u->sink_skip;
1055 snapshot->plen = plen + u->source_skip;
1058 /* Called from source I/O thread context. */
1059 static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
1060 struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata;
1064 case SOURCE_OUTPUT_MESSAGE_POST:
1066 pa_source_output_assert_io_context(u->source_output);
1068 if (u->source_output->source->thread_info.state == PA_SOURCE_RUNNING)
1069 pa_memblockq_push_align(u->sink_memblockq, chunk);
1071 pa_memblockq_flush_write(u->sink_memblockq, true);
1073 u->recv_counter += (int64_t) chunk->length;
1077 case SOURCE_OUTPUT_MESSAGE_REWIND:
1078 pa_source_output_assert_io_context(u->source_output);
1080 /* manipulate write index, never go past what we have */
1081 if (PA_SOURCE_IS_OPENED(u->source_output->source->thread_info.state))
1082 pa_memblockq_seek(u->sink_memblockq, -offset, PA_SEEK_RELATIVE, true);
1084 pa_memblockq_flush_write(u->sink_memblockq, true);
1086 pa_log_debug("Sink rewind (%lld)", (long long) offset);
1088 u->recv_counter -= offset;
1092 case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: {
1093 struct snapshot *snapshot = (struct snapshot *) data;
1095 source_output_snapshot_within_thread(u, snapshot);
1099 case SOURCE_OUTPUT_MESSAGE_APPLY_DIFF_TIME:
1100 apply_diff_time(u, offset);
1105 return pa_source_output_process_msg(obj, code, data, offset, chunk);
1108 /* Called from sink I/O thread context. */
1109 static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
1110 struct userdata *u = PA_SINK_INPUT(obj)->userdata;
1114 case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: {
1116 pa_usec_t now, latency;
1117 struct snapshot *snapshot = (struct snapshot *) data;
1119 pa_sink_input_assert_io_context(u->sink_input);
1121 now = pa_rtclock_now();
1122 latency = pa_sink_get_latency_within_thread(u->sink_input->sink);
1123 delay = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq);
1125 delay = (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, delay) : delay);
1127 snapshot->sink_now = now;
1128 snapshot->sink_latency = latency;
1129 snapshot->sink_delay = delay;
1130 snapshot->send_counter = u->send_counter;
1135 return pa_sink_input_process_msg(obj, code, data, offset, chunk);
1138 /* Called from sink I/O thread context. */
1139 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1142 pa_sink_input_assert_ref(i);
1143 pa_assert_se(u = i->userdata);
1145 pa_log_debug("Sink input update max rewind %lld", (long long) nbytes);
1147 /* FIXME: Too small max_rewind:
1148 * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
1149 pa_memblockq_set_maxrewind(u->sink_memblockq, nbytes);
1150 pa_sink_set_max_rewind_within_thread(u->sink, nbytes);
1153 /* Called from source I/O thread context. */
1154 static void source_output_update_max_rewind_cb(pa_source_output *o, size_t nbytes) {
1157 pa_source_output_assert_ref(o);
1158 pa_assert_se(u = o->userdata);
1160 pa_log_debug("Source output update max rewind %lld", (long long) nbytes);
1162 pa_source_set_max_rewind_within_thread(u->source, nbytes);
1165 /* Called from sink I/O thread context. */
1166 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1169 pa_sink_input_assert_ref(i);
1170 pa_assert_se(u = i->userdata);
1172 pa_log_debug("Sink input update max request %lld", (long long) nbytes);
1174 pa_sink_set_max_request_within_thread(u->sink, nbytes);
1177 /* Called from sink I/O thread context. */
1178 static void sink_input_update_sink_requested_latency_cb(pa_sink_input *i) {
1182 pa_sink_input_assert_ref(i);
1183 pa_assert_se(u = i->userdata);
1185 latency = pa_sink_get_requested_latency_within_thread(i->sink);
1187 pa_log_debug("Sink input update requested latency %lld", (long long) latency);
1190 /* Called from source I/O thread context. */
1191 static void source_output_update_source_requested_latency_cb(pa_source_output *o) {
1195 pa_source_output_assert_ref(o);
1196 pa_assert_se(u = o->userdata);
1198 latency = pa_source_get_requested_latency_within_thread(o->source);
1200 pa_log_debug("Source output update requested latency %lld", (long long) latency);
1203 /* Called from sink I/O thread context. */
1204 static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
1207 pa_sink_input_assert_ref(i);
1208 pa_assert_se(u = i->userdata);
1210 pa_log_debug("Sink input update latency range %lld %lld",
1211 (long long) i->sink->thread_info.min_latency,
1212 (long long) i->sink->thread_info.max_latency);
1214 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
1217 /* Called from source I/O thread context. */
1218 static void source_output_update_source_latency_range_cb(pa_source_output *o) {
1221 pa_source_output_assert_ref(o);
1222 pa_assert_se(u = o->userdata);
1224 pa_log_debug("Source output update latency range %lld %lld",
1225 (long long) o->source->thread_info.min_latency,
1226 (long long) o->source->thread_info.max_latency);
1228 pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
1231 /* Called from sink I/O thread context. */
1232 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input *i) {
1235 pa_sink_input_assert_ref(i);
1236 pa_assert_se(u = i->userdata);
1238 pa_log_debug("Sink input update fixed latency %lld",
1239 (long long) i->sink->thread_info.fixed_latency);
1241 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
1244 /* Called from source I/O thread context. */
1245 static void source_output_update_source_fixed_latency_cb(pa_source_output *o) {
1248 pa_source_output_assert_ref(o);
1249 pa_assert_se(u = o->userdata);
1251 pa_log_debug("Source output update fixed latency %lld",
1252 (long long) o->source->thread_info.fixed_latency);
1254 pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency);
1257 /* Called from source I/O thread context. */
1258 static void source_output_attach_cb(pa_source_output *o) {
1261 pa_source_output_assert_ref(o);
1262 pa_source_output_assert_io_context(o);
1263 pa_assert_se(u = o->userdata);
1265 pa_source_set_rtpoll(u->source, o->source->thread_info.rtpoll);
1266 pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
1267 pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency);
1268 pa_source_set_max_rewind_within_thread(u->source, pa_source_output_get_max_rewind(o));
1270 pa_log_debug("Source output %d attach", o->index);
1272 pa_source_attach_within_thread(u->source);
1274 u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read(
1275 o->source->thread_info.rtpoll,
1280 /* Called from sink I/O thread context. */
1281 static void sink_input_attach_cb(pa_sink_input *i) {
1284 pa_sink_input_assert_ref(i);
1285 pa_assert_se(u = i->userdata);
1287 pa_sink_set_rtpoll(u->sink, i->sink->thread_info.rtpoll);
1288 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
1290 /* (8.1) IF YOU NEED A FIXED BLOCK SIZE ADD THE LATENCY FOR ONE
1291 * BLOCK MINUS ONE SAMPLE HERE. SEE (7) */
1292 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
1294 /* (8.2) IF YOU NEED A FIXED BLOCK SIZE ROUND
1295 * pa_sink_input_get_max_request(i) UP TO MULTIPLES OF IT
1297 pa_sink_set_max_request_within_thread(u->sink, pa_sink_input_get_max_request(i));
1299 /* FIXME: Too small max_rewind:
1300 * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
1301 pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i));
1303 pa_log_debug("Sink input %d attach", i->index);
1305 u->rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write(
1306 i->sink->thread_info.rtpoll,
1310 pa_sink_attach_within_thread(u->sink);
1313 /* Called from source I/O thread context. */
1314 static void source_output_detach_cb(pa_source_output *o) {
1317 pa_source_output_assert_ref(o);
1318 pa_source_output_assert_io_context(o);
1319 pa_assert_se(u = o->userdata);
1321 pa_source_detach_within_thread(u->source);
1322 pa_source_set_rtpoll(u->source, NULL);
1324 pa_log_debug("Source output %d detach", o->index);
1326 if (u->rtpoll_item_read) {
1327 pa_rtpoll_item_free(u->rtpoll_item_read);
1328 u->rtpoll_item_read = NULL;
1332 /* Called from sink I/O thread context. */
1333 static void sink_input_detach_cb(pa_sink_input *i) {
1336 pa_sink_input_assert_ref(i);
1337 pa_assert_se(u = i->userdata);
1339 pa_sink_detach_within_thread(u->sink);
1341 pa_sink_set_rtpoll(u->sink, NULL);
1343 pa_log_debug("Sink input %d detach", i->index);
1345 if (u->rtpoll_item_write) {
1346 pa_rtpoll_item_free(u->rtpoll_item_write);
1347 u->rtpoll_item_write = NULL;
1351 /* Called from source I/O thread context. */
1352 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
1355 pa_source_output_assert_ref(o);
1356 pa_source_output_assert_io_context(o);
1357 pa_assert_se(u = o->userdata);
1359 pa_log_debug("Source output %d state %d", o->index, state);
1362 /* Called from sink I/O thread context. */
1363 static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) {
1366 pa_sink_input_assert_ref(i);
1367 pa_assert_se(u = i->userdata);
1369 pa_log_debug("Sink input %d state %d", i->index, state);
1371 /* If we are added for the first time, ask for a rewinding so that
1372 * we are heard right-away. */
1373 if (PA_SINK_INPUT_IS_LINKED(state) &&
1374 i->thread_info.state == PA_SINK_INPUT_INIT) {
1375 pa_log_debug("Requesting rewind due to state change.");
1376 pa_sink_input_request_rewind(i, 0, false, true, true);
1380 /* Called from main context. */
1381 static void source_output_kill_cb(pa_source_output *o) {
1384 pa_source_output_assert_ref(o);
1385 pa_assert_ctl_context();
1386 pa_assert_se(u = o->userdata);
1390 /* The order here matters! We first kill the source output, followed
1391 * by the source. That means the source callbacks must be protected
1392 * against an unconnected source output! */
1393 pa_source_output_unlink(u->source_output);
1394 pa_source_unlink(u->source);
1396 pa_source_output_unref(u->source_output);
1397 u->source_output = NULL;
1399 pa_source_unref(u->source);
1402 pa_log_debug("Source output kill %d", o->index);
1404 pa_module_unload_request(u->module, true);
1407 /* Called from main context */
1408 static void sink_input_kill_cb(pa_sink_input *i) {
1411 pa_sink_input_assert_ref(i);
1412 pa_assert_se(u = i->userdata);
1416 /* The order here matters! We first kill the sink input, followed
1417 * by the sink. That means the sink callbacks must be protected
1418 * against an unconnected sink input! */
1419 pa_sink_input_unlink(u->sink_input);
1420 pa_sink_unlink(u->sink);
1422 pa_sink_input_unref(u->sink_input);
1423 u->sink_input = NULL;
1425 pa_sink_unref(u->sink);
1428 pa_log_debug("Sink input kill %d", i->index);
1430 pa_module_unload_request(u->module, true);
1433 /* Called from main context. */
1434 static bool source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) {
1437 pa_source_output_assert_ref(o);
1438 pa_assert_ctl_context();
1439 pa_assert_se(u = o->userdata);
1441 if (u->dead || u->autoloaded)
1444 return (u->source != dest) && (u->sink != dest->monitor_of);
1447 /* Called from main context */
1448 static bool sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
1451 pa_sink_input_assert_ref(i);
1452 pa_assert_se(u = i->userdata);
1454 if (u->dead || u->autoloaded)
1457 return u->sink != dest;
1460 /* Called from main context. */
1461 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1464 pa_source_output_assert_ref(o);
1465 pa_assert_ctl_context();
1466 pa_assert_se(u = o->userdata);
1469 pa_source_set_asyncmsgq(u->source, dest->asyncmsgq);
1470 pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags);
1472 pa_source_set_asyncmsgq(u->source, NULL);
1474 if (u->source_auto_desc && dest) {
1478 pl = pa_proplist_new();
1479 y = pa_proplist_gets(u->sink_input->sink->proplist, PA_PROP_DEVICE_DESCRIPTION);
1480 z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
1481 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "%s (echo cancelled with %s)", z ? z : dest->name,
1482 y ? y : u->sink_input->sink->name);
1484 pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
1485 pa_proplist_free(pl);
1489 /* Called from main context */
1490 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1493 pa_sink_input_assert_ref(i);
1494 pa_assert_se(u = i->userdata);
1497 pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq);
1498 pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags);
1500 pa_sink_set_asyncmsgq(u->sink, NULL);
1502 if (u->sink_auto_desc && dest) {
1506 pl = pa_proplist_new();
1507 y = pa_proplist_gets(u->source_output->source->proplist, PA_PROP_DEVICE_DESCRIPTION);
1508 z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
1509 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "%s (echo cancelled with %s)", z ? z : dest->name,
1510 y ? y : u->source_output->source->name);
1512 pa_sink_update_proplist(u->sink, PA_UPDATE_REPLACE, pl);
1513 pa_proplist_free(pl);
1517 /* Called from main context */
1518 static void sink_input_volume_changed_cb(pa_sink_input *i) {
1521 pa_sink_input_assert_ref(i);
1522 pa_assert_se(u = i->userdata);
1524 pa_sink_volume_changed(u->sink, &i->volume);
1527 /* Called from main context */
1528 static void sink_input_mute_changed_cb(pa_sink_input *i) {
1531 pa_sink_input_assert_ref(i);
1532 pa_assert_se(u = i->userdata);
1534 pa_sink_mute_changed(u->sink, i->muted);
1537 /* Called from main context */
1538 static int canceller_process_msg_cb(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1539 struct pa_echo_canceller_msg *msg;
1544 msg = PA_ECHO_CANCELLER_MSG(o);
1548 case ECHO_CANCELLER_MESSAGE_SET_VOLUME: {
1549 pa_cvolume *v = (pa_cvolume *) userdata;
1551 if (u->use_volume_sharing)
1552 pa_source_set_volume(u->source, v, true, false);
1554 pa_source_output_set_volume(u->source_output, v, false, true);
1560 pa_assert_not_reached();
1567 /* Called by the canceller, so source I/O thread context. */
1568 void pa_echo_canceller_get_capture_volume(pa_echo_canceller *ec, pa_cvolume *v) {
1569 *v = ec->msg->userdata->thread_info.current_volume;
1572 /* Called by the canceller, so source I/O thread context. */
1573 void pa_echo_canceller_set_capture_volume(pa_echo_canceller *ec, pa_cvolume *v) {
1574 if (!pa_cvolume_equal(&ec->msg->userdata->thread_info.current_volume, v)) {
1575 pa_cvolume *vol = pa_xnewdup(pa_cvolume, v, 1);
1577 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(ec->msg), ECHO_CANCELLER_MESSAGE_SET_VOLUME, vol, 0, NULL,
1582 uint32_t pa_echo_canceller_blocksize_power2(unsigned rate, unsigned ms) {
1583 unsigned nframes = (rate * ms) / 1000;
1584 uint32_t y = 1 << ((8 * sizeof(uint32_t)) - 2);
1586 assert(rate >= 4000);
1589 /* nframes should be a power of 2, round down to nearest power of two */
1597 static pa_echo_canceller_method_t get_ec_method_from_string(const char *method) {
1598 if (pa_streq(method, "null"))
1599 return PA_ECHO_CANCELLER_NULL;
1601 if (pa_streq(method, "speex"))
1602 return PA_ECHO_CANCELLER_SPEEX;
1604 #ifdef HAVE_ADRIAN_EC
1605 if (pa_streq(method, "adrian"))
1606 return PA_ECHO_CANCELLER_ADRIAN;
1609 if (pa_streq(method, "webrtc"))
1610 return PA_ECHO_CANCELLER_WEBRTC;
1612 return PA_ECHO_CANCELLER_INVALID;
1615 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
1618 struct userdata *u = NULL;
1619 pa_tagstruct *reply = NULL;
1627 if (pa_tagstruct_getu32(t, &command) < 0)
1630 reply = pa_tagstruct_new(NULL, 0);
1631 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1632 pa_tagstruct_putu32(reply, tag);
1635 case AEC_SET_VOLUME: {
1636 pa_tagstruct_getu32(t,&value);
1637 pa_log_debug("AEC_SET_VOLUME in echo cancel = %d",value);
1640 case AEC_SET_DEVICE: {
1641 pa_tagstruct_getu32(t,&value);
1642 pa_log_debug("AEC_SET_DEVICE in echo cancel = %d",value);
1648 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1655 /* Common initialisation bits between module-echo-cancel and the standalone
1658 * Called from main context. */
1659 static int init_common(pa_modargs *ma, struct userdata *u, pa_sample_spec *source_ss, pa_channel_map *source_map) {
1660 const char *ec_string;
1661 pa_echo_canceller_method_t ec_method;
1663 if (pa_modargs_get_sample_spec_and_channel_map(ma, source_ss, source_map, PA_CHANNEL_MAP_DEFAULT) < 0) {
1664 pa_log("Invalid sample format specification or channel map");
1668 u->ec = pa_xnew0(pa_echo_canceller, 1);
1670 pa_log("Failed to alloc echo canceller");
1674 ec_string = pa_modargs_get_value(ma, "aec_method", DEFAULT_ECHO_CANCELLER);
1675 if ((ec_method = get_ec_method_from_string(ec_string)) < 0) {
1676 pa_log("Invalid echo canceller implementation '%s'", ec_string);
1680 pa_log_info("Using AEC engine: %s", ec_string);
1682 u->ec->init = ec_table[ec_method].init;
1683 u->ec->play = ec_table[ec_method].play;
1684 u->ec->record = ec_table[ec_method].record;
1685 u->ec->set_drift = ec_table[ec_method].set_drift;
1686 u->ec->run = ec_table[ec_method].run;
1687 u->ec->done = ec_table[ec_method].done;
1695 /* Called from main context. */
1696 int pa__init(pa_module*m) {
1698 pa_sample_spec source_output_ss, source_ss, sink_ss;
1699 pa_channel_map source_output_map, source_map, sink_map;
1701 pa_source *source_master=NULL;
1702 pa_sink *sink_master=NULL;
1703 pa_source_output_new_data source_output_data;
1704 pa_sink_input_new_data sink_input_data;
1705 pa_source_new_data source_data;
1706 pa_sink_new_data sink_data;
1707 pa_memchunk silence;
1709 uint32_t nframes = 0;
1713 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1714 pa_log("Failed to parse module arguments.");
1718 if (!(source_master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source_master", NULL), PA_NAMEREG_SOURCE))) {
1719 pa_log("Master source not found");
1722 pa_assert(source_master);
1724 if (!(sink_master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink_master", NULL), PA_NAMEREG_SINK))) {
1725 pa_log("Master sink not found");
1728 pa_assert(sink_master);
1730 if (source_master->monitor_of == sink_master) {
1731 pa_log("Can't cancel echo between a sink and its monitor");
1735 source_ss = source_master->sample_spec;
1736 source_ss.rate = DEFAULT_RATE;
1737 source_ss.channels = DEFAULT_CHANNELS;
1738 pa_channel_map_init_auto(&source_map, source_ss.channels, PA_CHANNEL_MAP_DEFAULT);
1740 sink_ss = sink_master->sample_spec;
1741 sink_map = sink_master->channel_map;
1743 u = pa_xnew0(struct userdata, 1);
1745 pa_log("Failed to alloc userdata");
1753 u->use_volume_sharing = true;
1754 if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &u->use_volume_sharing) < 0) {
1755 pa_log("use_volume_sharing= expects a boolean argument");
1759 temp = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
1760 if (pa_modargs_get_value_u32(ma, "adjust_time", &temp) < 0) {
1761 pa_log("Failed to parse adjust_time value");
1765 if (temp != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC)
1766 u->adjust_time = temp * PA_USEC_PER_SEC;
1768 u->adjust_time = DEFAULT_ADJUST_TIME_USEC;
1770 temp = DEFAULT_ADJUST_TOLERANCE / PA_USEC_PER_MSEC;
1771 if (pa_modargs_get_value_u32(ma, "adjust_threshold", &temp) < 0) {
1772 pa_log("Failed to parse adjust_threshold value");
1776 if (temp != DEFAULT_ADJUST_TOLERANCE / PA_USEC_PER_MSEC)
1777 u->adjust_threshold = temp * PA_USEC_PER_MSEC;
1779 u->adjust_threshold = DEFAULT_ADJUST_TOLERANCE;
1781 u->save_aec = DEFAULT_SAVE_AEC;
1782 if (pa_modargs_get_value_boolean(ma, "save_aec", &u->save_aec) < 0) {
1783 pa_log("Failed to parse save_aec value");
1787 u->autoloaded = DEFAULT_AUTOLOADED;
1788 if (pa_modargs_get_value_boolean(ma, "autoloaded", &u->autoloaded) < 0) {
1789 pa_log("Failed to parse autoloaded value");
1793 if (init_common(ma, u, &source_ss, &source_map) < 0)
1796 u->asyncmsgq = pa_asyncmsgq_new(0);
1797 u->need_realign = true;
1799 source_output_ss = source_ss;
1800 source_output_map = source_map;
1802 if (sink_ss.rate != source_ss.rate) {
1803 pa_log_info("Sample rates of play and out stream differ. Adjusting rate of play stream.");
1804 sink_ss.rate = source_ss.rate;
1807 pa_assert(u->ec->init);
1808 if (!u->ec->init(u->core, u->ec, &source_output_ss, &source_output_map, &sink_ss, &sink_map, &source_ss, &source_map, &nframes, pa_modargs_get_value(ma, "aec_args", NULL))) {
1809 pa_log("Failed to init AEC engine");
1813 pa_assert(source_output_ss.rate == source_ss.rate);
1814 pa_assert(sink_ss.rate == source_ss.rate);
1816 u->source_output_blocksize = nframes * pa_frame_size(&source_output_ss);
1817 u->source_blocksize = nframes * pa_frame_size(&source_ss);
1818 u->sink_blocksize = nframes * pa_frame_size(&sink_ss);
1820 if (u->ec->params.drift_compensation)
1821 pa_assert(u->ec->set_drift);
1824 pa_source_new_data_init(&source_data);
1825 source_data.driver = __FILE__;
1826 source_data.module = m;
1827 if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
1828 source_data.name = pa_sprintf_malloc("%s.echo-cancel", source_master->name);
1829 pa_source_new_data_set_sample_spec(&source_data, &source_ss);
1830 pa_source_new_data_set_channel_map(&source_data, &source_map);
1831 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, source_master->name);
1832 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
1834 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
1836 if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
1837 pa_log("Invalid properties");
1838 pa_source_new_data_done(&source_data);
1842 if ((u->source_auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
1845 y = pa_proplist_gets(sink_master->proplist, PA_PROP_DEVICE_DESCRIPTION);
1846 z = pa_proplist_gets(source_master->proplist, PA_PROP_DEVICE_DESCRIPTION);
1847 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "%s (echo cancelled with %s)",
1848 z ? z : source_master->name, y ? y : sink_master->name);
1851 u->source = pa_source_new(m->core, &source_data, (source_master->flags & (PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY))
1852 | (u->use_volume_sharing ? PA_SOURCE_SHARE_VOLUME_WITH_MASTER : 0));
1853 pa_source_new_data_done(&source_data);
1856 pa_log("Failed to create source.");
1860 u->source->parent.process_msg = source_process_msg_cb;
1861 u->source->set_state = source_set_state_cb;
1862 u->source->update_requested_latency = source_update_requested_latency_cb;
1863 pa_source_set_get_mute_callback(u->source, source_get_mute_cb);
1864 pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
1865 if (!u->use_volume_sharing) {
1866 pa_source_set_get_volume_callback(u->source, source_get_volume_cb);
1867 pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
1868 pa_source_enable_decibel_volume(u->source, true);
1870 u->source->userdata = u;
1872 pa_source_set_asyncmsgq(u->source, source_master->asyncmsgq);
1875 pa_sink_new_data_init(&sink_data);
1876 sink_data.driver = __FILE__;
1877 sink_data.module = m;
1878 if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL))))
1879 sink_data.name = pa_sprintf_malloc("%s.echo-cancel", sink_master->name);
1880 pa_sink_new_data_set_sample_spec(&sink_data, &sink_ss);
1881 pa_sink_new_data_set_channel_map(&sink_data, &sink_map);
1882 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, sink_master->name);
1883 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
1885 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
1887 if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
1888 pa_log("Invalid properties");
1889 pa_sink_new_data_done(&sink_data);
1893 if ((u->sink_auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
1896 y = pa_proplist_gets(source_master->proplist, PA_PROP_DEVICE_DESCRIPTION);
1897 z = pa_proplist_gets(sink_master->proplist, PA_PROP_DEVICE_DESCRIPTION);
1898 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "%s (echo cancelled with %s)",
1899 z ? z : sink_master->name, y ? y : source_master->name);
1902 u->sink = pa_sink_new(m->core, &sink_data, (sink_master->flags & (PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY))
1903 | (u->use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
1904 pa_sink_new_data_done(&sink_data);
1907 pa_log("Failed to create sink.");
1911 u->sink->parent.process_msg = sink_process_msg_cb;
1912 u->sink->set_state = sink_set_state_cb;
1913 u->sink->update_requested_latency = sink_update_requested_latency_cb;
1914 u->sink->request_rewind = sink_request_rewind_cb;
1915 pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
1916 if (!u->use_volume_sharing) {
1917 pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
1918 pa_sink_enable_decibel_volume(u->sink, true);
1920 u->sink->userdata = u;
1922 pa_sink_set_asyncmsgq(u->sink, sink_master->asyncmsgq);
1924 /* Create source output */
1925 pa_source_output_new_data_init(&source_output_data);
1926 source_output_data.driver = __FILE__;
1927 source_output_data.module = m;
1928 pa_source_output_new_data_set_source(&source_output_data, source_master, false);
1929 source_output_data.destination_source = u->source;
1931 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Echo-Cancel Source Stream");
1932 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
1933 pa_source_output_new_data_set_sample_spec(&source_output_data, &source_output_ss);
1934 pa_source_output_new_data_set_channel_map(&source_output_data, &source_output_map);
1936 pa_source_output_new(&u->source_output, m->core, &source_output_data);
1937 pa_source_output_new_data_done(&source_output_data);
1939 if (!u->source_output)
1942 u->source_output->parent.process_msg = source_output_process_msg_cb;
1943 u->source_output->push = source_output_push_cb;
1944 u->source_output->process_rewind = source_output_process_rewind_cb;
1945 u->source_output->update_max_rewind = source_output_update_max_rewind_cb;
1946 u->source_output->update_source_requested_latency = source_output_update_source_requested_latency_cb;
1947 u->source_output->update_source_latency_range = source_output_update_source_latency_range_cb;
1948 u->source_output->update_source_fixed_latency = source_output_update_source_fixed_latency_cb;
1949 u->source_output->kill = source_output_kill_cb;
1950 u->source_output->attach = source_output_attach_cb;
1951 u->source_output->detach = source_output_detach_cb;
1952 u->source_output->state_change = source_output_state_change_cb;
1953 u->source_output->may_move_to = source_output_may_move_to_cb;
1954 u->source_output->moving = source_output_moving_cb;
1955 u->source_output->userdata = u;
1957 u->source->output_from_master = u->source_output;
1959 /* Create sink input */
1960 pa_sink_input_new_data_init(&sink_input_data);
1961 sink_input_data.driver = __FILE__;
1962 sink_input_data.module = m;
1963 pa_sink_input_new_data_set_sink(&sink_input_data, sink_master, false);
1964 sink_input_data.origin_sink = u->sink;
1965 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Echo-Cancel Sink Stream");
1966 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
1967 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &sink_ss);
1968 pa_sink_input_new_data_set_channel_map(&sink_input_data, &sink_map);
1969 sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE;
1971 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
1972 pa_sink_input_new_data_done(&sink_input_data);
1977 u->sink_input->parent.process_msg = sink_input_process_msg_cb;
1978 u->sink_input->pop = sink_input_pop_cb;
1979 u->sink_input->process_rewind = sink_input_process_rewind_cb;
1980 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1981 u->sink_input->update_max_request = sink_input_update_max_request_cb;
1982 u->sink_input->update_sink_requested_latency = sink_input_update_sink_requested_latency_cb;
1983 u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
1984 u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb;
1985 u->sink_input->kill = sink_input_kill_cb;
1986 u->sink_input->attach = sink_input_attach_cb;
1987 u->sink_input->detach = sink_input_detach_cb;
1988 u->sink_input->state_change = sink_input_state_change_cb;
1989 u->sink_input->may_move_to = sink_input_may_move_to_cb;
1990 u->sink_input->moving = sink_input_moving_cb;
1991 if (!u->use_volume_sharing)
1992 u->sink_input->volume_changed = sink_input_volume_changed_cb;
1993 u->sink_input->mute_changed = sink_input_mute_changed_cb;
1994 u->sink_input->userdata = u;
1996 u->sink->input_to_master = u->sink_input;
1998 pa_sink_input_get_silence(u->sink_input, &silence);
2000 u->source_memblockq = pa_memblockq_new("module-echo-cancel source_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0,
2001 &source_output_ss, 1, 1, 0, &silence);
2002 u->sink_memblockq = pa_memblockq_new("module-echo-cancel sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0,
2003 &sink_ss, 0, 1, 0, &silence);
2005 pa_memblock_unref(silence.memblock);
2007 if (!u->source_memblockq || !u->sink_memblockq) {
2008 pa_log("Failed to create memblockq.");
2012 if (u->adjust_time > 0 && !u->ec->params.drift_compensation)
2013 u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u);
2014 else if (u->ec->params.drift_compensation) {
2015 pa_log_info("Canceller does drift compensation -- built-in compensation will be disabled");
2017 /* Perform resync just once to give the canceller a leg up */
2018 pa_atomic_store(&u->request_resync, 1);
2022 pa_log("Creating AEC files in /tmp");
2023 u->captured_file = fopen("/tmp/aec_rec.sw", "wb");
2024 if (u->captured_file == NULL)
2025 perror ("fopen failed");
2026 u->played_file = fopen("/tmp/aec_play.sw", "wb");
2027 if (u->played_file == NULL)
2028 perror ("fopen failed");
2029 u->canceled_file = fopen("/tmp/aec_out.sw", "wb");
2030 if (u->canceled_file == NULL)
2031 perror ("fopen failed");
2032 if (u->ec->params.drift_compensation) {
2033 u->drift_file = fopen("/tmp/aec_drift.txt", "w");
2034 if (u->drift_file == NULL)
2035 perror ("fopen failed");
2039 u->ec->msg = pa_msgobject_new(pa_echo_canceller_msg);
2040 u->ec->msg->parent.process_msg = canceller_process_msg_cb;
2041 u->ec->msg->userdata = u;
2043 u->thread_info.current_volume = u->source->reference_volume;
2045 u->protocol = pa_native_protocol_get(m->core);
2046 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
2048 pa_sink_put(u->sink);
2049 pa_source_put(u->source);
2051 pa_sink_input_put(u->sink_input);
2052 pa_source_output_put(u->source_output);
2053 pa_modargs_free(ma);
2059 pa_modargs_free(ma);
2066 /* Called from main context. */
2067 int pa__get_n_used(pa_module *m) {
2071 pa_assert_se(u = m->userdata);
2073 return pa_sink_linked_by(u->sink) + pa_source_linked_by(u->source);
2076 /* Called from main context. */
2077 void pa__done(pa_module*m) {
2082 if (!(u = m->userdata))
2087 /* See comments in source_output_kill_cb() above regarding
2088 * destruction order! */
2091 u->core->mainloop->time_free(u->time_event);
2093 if (u->source_output)
2094 pa_source_output_unlink(u->source_output);
2096 pa_sink_input_unlink(u->sink_input);
2099 pa_source_unlink(u->source);
2101 pa_sink_unlink(u->sink);
2103 if (u->source_output)
2104 pa_source_output_unref(u->source_output);
2106 pa_sink_input_unref(u->sink_input);
2109 pa_source_unref(u->source);
2111 pa_sink_unref(u->sink);
2113 if (u->source_memblockq)
2114 pa_memblockq_free(u->source_memblockq);
2115 if (u->sink_memblockq)
2116 pa_memblockq_free(u->sink_memblockq);
2126 pa_native_protocol_remove_ext(u->protocol, m);
2127 pa_native_protocol_unref(u->protocol);
2131 pa_asyncmsgq_unref(u->asyncmsgq);
2135 fclose(u->played_file);
2136 if (u->captured_file)
2137 fclose(u->captured_file);
2138 if (u->canceled_file)
2139 fclose(u->canceled_file);
2141 fclose(u->drift_file);
2147 #ifdef ECHO_CANCEL_TEST
2149 * Stand-alone test program for running in the canceller on pre-recorded files.
2151 int main(int argc, char* argv[]) {
2153 pa_sample_spec source_output_ss, source_ss, sink_ss;
2154 pa_channel_map source_output_map, source_map, sink_map;
2155 pa_modargs *ma = NULL;
2156 uint8_t *rdata = NULL, *pdata = NULL, *cdata = NULL;
2157 int unused PA_GCC_UNUSED;
2163 if (!getenv("MAKE_CHECK"))
2164 pa_log_set_level(PA_LOG_DEBUG);
2166 pa_memzero(&u, sizeof(u));
2168 if (argc < 4 || argc > 7) {
2172 u.captured_file = fopen(argv[2], "rb");
2173 if (u.captured_file == NULL) {
2174 perror ("Could not open capture file");
2177 u.played_file = fopen(argv[1], "rb");
2178 if (u.played_file == NULL) {
2179 perror ("Could not open play file");
2182 u.canceled_file = fopen(argv[3], "wb");
2183 if (u.canceled_file == NULL) {
2184 perror ("Could not open canceled file");
2188 u.core = pa_xnew0(pa_core, 1);
2189 u.core->cpu_info.cpu_type = PA_CPU_X86;
2190 u.core->cpu_info.flags.x86 |= PA_CPU_X86_SSE;
2192 if (!(ma = pa_modargs_new(argc > 4 ? argv[4] : NULL, valid_modargs))) {
2193 pa_log("Failed to parse module arguments.");
2197 source_ss.format = PA_SAMPLE_S16LE;
2198 source_ss.rate = DEFAULT_RATE;
2199 source_ss.channels = DEFAULT_CHANNELS;
2200 pa_channel_map_init_auto(&source_map, source_ss.channels, PA_CHANNEL_MAP_DEFAULT);
2202 sink_ss.format = PA_SAMPLE_S16LE;
2203 sink_ss.rate = DEFAULT_RATE;
2204 sink_ss.channels = DEFAULT_CHANNELS;
2205 pa_channel_map_init_auto(&sink_map, sink_ss.channels, PA_CHANNEL_MAP_DEFAULT);
2207 if (init_common(ma, &u, &source_ss, &source_map) < 0)
2210 source_output_ss = source_ss;
2211 source_output_map = source_map;
2213 if (!u.ec->init(u.core, u.ec, &source_output_ss, &source_output_map, &sink_ss, &sink_map, &source_ss, &source_map, &nframes,
2214 pa_modargs_get_value(ma, "aec_args", NULL))) {
2215 pa_log("Failed to init AEC engine");
2218 u.source_output_blocksize = nframes * pa_frame_size(&source_output_ss);
2219 u.source_blocksize = nframes * pa_frame_size(&source_ss);
2220 u.sink_blocksize = nframes * pa_frame_size(&sink_ss);
2222 if (u.ec->params.drift_compensation) {
2224 pa_log("Drift compensation enabled but drift file not specified");
2228 u.drift_file = fopen(argv[5], "rt");
2230 if (u.drift_file == NULL) {
2231 perror ("Could not open drift file");
2236 rdata = pa_xmalloc(u.source_output_blocksize);
2237 pdata = pa_xmalloc(u.sink_blocksize);
2238 cdata = pa_xmalloc(u.source_blocksize);
2240 if (!u.ec->params.drift_compensation) {
2241 while (fread(rdata, u.source_output_blocksize, 1, u.captured_file) > 0) {
2242 if (fread(pdata, u.sink_blocksize, 1, u.played_file) == 0) {
2243 perror("Played file ended before captured file");
2247 u.ec->run(u.ec, rdata, pdata, cdata);
2249 unused = fwrite(cdata, u.source_blocksize, 1, u.canceled_file);
2252 while (fscanf(u.drift_file, "%c", &c) > 0) {
2255 if (!fscanf(u.drift_file, "%a", &drift)) {
2256 perror("Drift file incomplete");
2260 u.ec->set_drift(u.ec, drift);
2265 if (!fscanf(u.drift_file, "%d", &i)) {
2266 perror("Drift file incomplete");
2270 if (fread(rdata, i, 1, u.captured_file) <= 0) {
2271 perror("Captured file ended prematurely");
2275 u.ec->record(u.ec, rdata, cdata);
2277 unused = fwrite(cdata, i, 1, u.canceled_file);
2282 if (!fscanf(u.drift_file, "%d", &i)) {
2283 perror("Drift file incomplete");
2287 if (fread(pdata, i, 1, u.played_file) <= 0) {
2288 perror("Played file ended prematurely");
2292 u.ec->play(u.ec, pdata);
2298 if (fread(rdata, i, 1, u.captured_file) > 0)
2299 pa_log("All capture data was not consumed");
2300 if (fread(pdata, i, 1, u.played_file) > 0)
2301 pa_log("All playback data was not consumed");
2307 if (u.captured_file)
2308 fclose(u.captured_file);
2310 fclose(u.played_file);
2311 if (u.canceled_file)
2312 fclose(u.canceled_file);
2314 fclose(u.drift_file);
2324 pa_modargs_free(ma);
2329 pa_log("Usage: %s play_file rec_file out_file [module args] [drift_file]", argv[0]);
2335 #endif /* ECHO_CANCEL_TEST */