comparison spandsp-0.0.6pre17/tests/echo_tests.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * echo_tests.c
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2001 Steve Underwood
9 *
10 * Based on a bit from here, a bit from there, eye of toad,
11 * ear of bat, etc - plus, of course, my own 2 cents.
12 *
13 * All rights reserved.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License version 2, as
17 * published by the Free Software Foundation.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *
28 * $Id: echo_tests.c,v 1.39 2009/05/30 15:23:13 steveu Exp $
29 */
30
31 /*! \page echo_can_tests_page Line echo cancellation for voice tests
32
33 \section echo_can_tests_page_sec_1 What does it do?
34 The echo cancellation tests test the echo cancellor against the G.168 spec. Not
35 all the tests in G.168 are fully implemented at this time.
36
37 \section echo_can_tests_page_sec_2 How does it work?
38
39 \section echo_can_tests_page_sec_2 How do I use it?
40
41 */
42
43 #if defined(HAVE_CONFIG_H)
44 #include "config.h"
45 #endif
46
47 #if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H)
48 #define ENABLE_GUI
49 #endif
50
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <unistd.h>
54 #include <string.h>
55 #include <strings.h>
56 #include <assert.h>
57 #include <sndfile.h>
58
59 #define GEN_CONST
60 #include <math.h>
61
62 //#if defined(WITH_SPANDSP_INTERNALS)
63 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
64 //#endif
65
66 #include "spandsp.h"
67 #include "spandsp/g168models.h"
68 #include "spandsp-sim.h"
69 #if defined(ENABLE_GUI)
70 #include "echo_monitor.h"
71 #endif
72
73 #if !defined(NULL)
74 #define NULL (void *) 0
75 #endif
76
77 #define TEST_EC_TAPS 256
78
79 #define RESIDUE_FILE_NAME "residue_sound.wav"
80
81 /*
82 The key signal names, as defined in G.168
83
84 +--------------+ +------------+
85 | | Sin | |
86 Sgen -->--| Echoey |--->---| Echo |-->-- Sout
87 | | | |
88 | World | Rout | Canceller |
89 --<--| |---<---| |--<-- Rin
90 | | | |
91 +--------------+ +------------+
92
93 Echoey world model. Munge means linear->PCM->linear distortion.
94 +-------------------------+
95 | | Sin
96 Sgen -->--|-->munge--->sum-->munge--|--->---
97 | +--> |
98 | FIR | Rout
99 --<--|--------+--------munge<--|---<---
100 | |
101 +-------------------------+
102 */
103
104 typedef struct
105 {
106 const char *name;
107 int max;
108 int cur;
109 float gain;
110 SNDFILE *handle;
111 int16_t signal[SAMPLE_RATE];
112 } signal_source_t;
113
114 /* Level measurement device, specified in G.168 section 6.4.1.2.1 */
115 typedef struct
116 {
117 int type;
118 fir_float_state_t *fir;
119 float history[35*8];
120 int pos;
121 float factor;
122 float power;
123 float peak;
124 } level_measurement_device_t;
125
126 typedef struct
127 {
128 int model_no;
129 float erl;
130 fir32_state_t impulse;
131 float gain;
132 int munging_codec;
133 } channel_model_state_t;
134
135 channel_model_state_t chan_model;
136
137 signal_source_t local_css;
138 signal_source_t far_css;
139 awgn_state_t local_noise_source;
140 awgn_state_t far_noise_source;
141
142 SNDFILE *residue_handle;
143 int16_t residue_sound[SAMPLE_RATE];
144 int residue_cur = 0;
145
146 level_measurement_device_t *power_meter_1;
147 level_measurement_device_t *power_meter_2;
148
149 int line_model_no;
150 int supp_line_model_no;
151 int munger;
152
153 level_measurement_device_t *rin_power_meter; /* Also known as Lrin */
154 level_measurement_device_t *rout_power_meter;
155 level_measurement_device_t *sin_power_meter;
156 level_measurement_device_t *sout_power_meter; /* Also known as Lret (pre NLP value is known as Lres) */
157 level_measurement_device_t *sgen_power_meter;
158
159 #define RESULT_CHANNELS 7
160 SNDFILE *result_handle;
161 int16_t result_sound[SAMPLE_RATE*RESULT_CHANNELS];
162 int result_cur;
163
164 const char *test_name;
165 int quiet;
166 int use_gui;
167
168 float erl;
169
170 /* Dump estimated echo response */
171 static void dump_ec_state(echo_can_state_t *ctx)
172 {
173 int i;
174 FILE *f;
175
176 if ((f = fopen("echo_tests_state.txt", "wt")) == NULL)
177 return;
178 for (i = 0; i < TEST_EC_TAPS; i++)
179 fprintf(f, "%f\n", (float) ctx->fir_taps16[0][i]/(1 << 15));
180 fclose(f);
181 }
182 /*- End of function --------------------------------------------------------*/
183
184 static inline void put_residue(int16_t amp)
185 {
186 int outframes;
187
188 residue_sound[residue_cur++] = amp;
189 if (residue_cur >= SAMPLE_RATE)
190 {
191 outframes = sf_writef_short(residue_handle, residue_sound, residue_cur);
192 if (outframes != residue_cur)
193 {
194 fprintf(stderr, " Error writing residue sound\n");
195 exit(2);
196 }
197 residue_cur = 0;
198 }
199 }
200 /*- End of function --------------------------------------------------------*/
201
202 static void signal_load(signal_source_t *sig, const char *name)
203 {
204 sig->handle = sf_open_telephony_read(name, 1);
205 sig->name = name;
206 sig->max = sf_readf_short(sig->handle, sig->signal, SAMPLE_RATE);
207 if (sig->max < 0)
208 {
209 fprintf(stderr, " Error reading sound file '%s'\n", sig->name);
210 exit(2);
211 }
212 }
213 /*- End of function --------------------------------------------------------*/
214
215 static void signal_free(signal_source_t *sig)
216 {
217 if (sf_close(sig->handle) != 0)
218 {
219 fprintf(stderr, " Cannot close sound file '%s'\n", sig->name);
220 exit(2);
221 }
222 }
223 /*- End of function --------------------------------------------------------*/
224
225 static void signal_restart(signal_source_t *sig, float gain)
226 {
227 sig->cur = 0;
228 sig->gain = powf(10.0f, gain/20.0f);
229 }
230 /*- End of function --------------------------------------------------------*/
231
232 static int16_t signal_amp(signal_source_t *sig)
233 {
234 int16_t tx;
235
236 tx = sig->signal[sig->cur++]*sig->gain;
237 if (sig->cur >= sig->max)
238 sig->cur = 0;
239 return tx;
240 }
241 /*- End of function --------------------------------------------------------*/
242
243 static level_measurement_device_t *level_measurement_device_create(int type)
244 {
245 level_measurement_device_t *dev;
246 int i;
247
248 dev = (level_measurement_device_t *) malloc(sizeof(level_measurement_device_t));
249 dev->fir = (fir_float_state_t *) malloc(sizeof(fir_float_state_t));
250 fir_float_create(dev->fir,
251 level_measurement_bp_coeffs,
252 sizeof(level_measurement_bp_coeffs)/sizeof(float));
253 for (i = 0; i < 35*8; i++)
254 dev->history[i] = 0.0f;
255 dev->pos = 0;
256 dev->factor = expf(-1.0f/((float) SAMPLE_RATE*0.035f));
257 dev->power = 0;
258 dev->type = type;
259 return dev;
260 }
261 /*- End of function --------------------------------------------------------*/
262
263 #if 0
264 static void level_measurement_device_reset(level_measurement_device_t *dev)
265 {
266 int i;
267
268 for (i = 0; i < 35*8; i++)
269 dev->history[i] = 0.0f;
270 dev->pos = 0;
271 dev->power = 0;
272 dev->peak = 0.0f;
273 }
274 /*- End of function --------------------------------------------------------*/
275
276 static int level_measurement_device_release(level_measurement_device_t *s)
277 {
278 fir_float_free(s->fir);
279 free(s->fir);
280 free(s);
281 return 0;
282 }
283 /*- End of function --------------------------------------------------------*/
284 #endif
285
286 static float level_measurement_device_get_peak(level_measurement_device_t *dev)
287 {
288 return dev->peak;
289 }
290 /*- End of function --------------------------------------------------------*/
291
292 static float level_measurement_device_reset_peak(level_measurement_device_t *dev)
293 {
294 float power;
295
296 power = dev->peak;
297 dev->peak = -99.0f;
298 return power;
299 }
300 /*- End of function --------------------------------------------------------*/
301
302 static float level_measurement_device(level_measurement_device_t *dev, int16_t amp)
303 {
304 float signal;
305 float power;
306
307 /* Level measurement device(s), specified in G.168 section 6.4.1.2.1 and 6.4.1.2.2 */
308 signal = fir_float(dev->fir, amp);
309 signal *= signal;
310 if (dev->type == 0)
311 {
312 /* Level measurement device, specified in G.168 section 6.4.1.2.1 -
313 level measurement device. This version uses a single pole
314 estimator.*/
315 dev->power = dev->power*dev->factor + signal*(1.0f - dev->factor);
316 signal = sqrtf(dev->power);
317 }
318 else
319 {
320 /* Level measurement device, specified in G.168 section 6.4.1.2.2 -
321 level measurement device for peaks. This version uses a sliding
322 window estimator. */
323 dev->power += (signal - dev->history[dev->pos]);
324 dev->history[dev->pos++] = signal;
325 signal = sqrtf(dev->power/(35.8f*8.0f));
326 }
327 if (signal <= 0.0f)
328 return -99.0f;
329 power = DBM0_MAX_POWER + 20.0f*log10f(signal/32767.0f);
330 if (power > dev->peak)
331 dev->peak = power;
332 return power;
333 }
334 /*- End of function --------------------------------------------------------*/
335
336 static void level_measurements_create(int type)
337 {
338 rin_power_meter = level_measurement_device_create(type);
339 rout_power_meter = level_measurement_device_create(type);
340 sin_power_meter = level_measurement_device_create(type);
341 sout_power_meter = level_measurement_device_create(type);
342 sgen_power_meter = level_measurement_device_create(type);
343 }
344 /*- End of function --------------------------------------------------------*/
345
346 static void level_measurements_update(int16_t rin, int16_t sin, int16_t rout, int16_t sout, int16_t sgen)
347 {
348 level_measurement_device(rin_power_meter, rin);
349 level_measurement_device(rout_power_meter, rout);
350 level_measurement_device(sin_power_meter, sin);
351 level_measurement_device(sout_power_meter, sout);
352 level_measurement_device(sgen_power_meter, sgen);
353 }
354 /*- End of function --------------------------------------------------------*/
355
356 static void level_measurements_reset_peaks(void)
357 {
358 level_measurement_device_reset_peak(rin_power_meter);
359 level_measurement_device_reset_peak(rout_power_meter);
360 level_measurement_device_reset_peak(sin_power_meter);
361 level_measurement_device_reset_peak(sout_power_meter);
362 level_measurement_device_reset_peak(sgen_power_meter);
363 }
364 /*- End of function --------------------------------------------------------*/
365
366 static void print_results(void)
367 {
368 if (!quiet)
369 printf("test model ERL time Max Rin Max Rout Max Sgen Max Sin Max Sout\n");
370 printf("%-4s %-1d %-5.1f%6.2fs%9.2f%9.2f%9.2f%9.2f%9.2f\n",
371 test_name,
372 chan_model.model_no,
373 20.0f*log10f(-chan_model.erl),
374 0.0f, //test_clock,
375 level_measurement_device_get_peak(rin_power_meter),
376 level_measurement_device_get_peak(rout_power_meter),
377 level_measurement_device_get_peak(sgen_power_meter),
378 level_measurement_device_get_peak(sin_power_meter),
379 level_measurement_device_get_peak(sout_power_meter));
380 }
381 /*- End of function --------------------------------------------------------*/
382
383 static int channel_model_create(channel_model_state_t *chan, int model, float erl, int codec)
384 {
385 static const int32_t line_model_clear_coeffs[] =
386 {
387 32768
388 };
389 static const int32_t *line_models[] =
390 {
391 line_model_clear_coeffs,
392 line_model_d2_coeffs,
393 line_model_d3_coeffs,
394 line_model_d4_coeffs,
395 line_model_d5_coeffs,
396 line_model_d6_coeffs,
397 line_model_d7_coeffs,
398 line_model_d8_coeffs,
399 line_model_d9_coeffs
400 };
401 static const int line_model_sizes[] =
402 {
403 sizeof(line_model_clear_coeffs)/sizeof(line_model_clear_coeffs[0]),
404 sizeof(line_model_d2_coeffs)/sizeof(line_model_d2_coeffs[0]),
405 sizeof(line_model_d3_coeffs)/sizeof(line_model_d3_coeffs[0]),
406 sizeof(line_model_d4_coeffs)/sizeof(line_model_d4_coeffs[0]),
407 sizeof(line_model_d5_coeffs)/sizeof(line_model_d5_coeffs[0]),
408 sizeof(line_model_d6_coeffs)/sizeof(line_model_d6_coeffs[0]),
409 sizeof(line_model_d7_coeffs)/sizeof(line_model_d7_coeffs[0]),
410 sizeof(line_model_d8_coeffs)/sizeof(line_model_d8_coeffs[0]),
411 sizeof(line_model_d9_coeffs)/sizeof(line_model_d9_coeffs[0])
412 };
413 static const float ki[] =
414 {
415 3.05e-5f,
416 LINE_MODEL_D2_GAIN,
417 LINE_MODEL_D3_GAIN,
418 LINE_MODEL_D4_GAIN,
419 LINE_MODEL_D5_GAIN,
420 LINE_MODEL_D6_GAIN,
421 LINE_MODEL_D7_GAIN,
422 LINE_MODEL_D8_GAIN,
423 LINE_MODEL_D9_GAIN
424 };
425
426 if (model < 0 || model >= (int) (sizeof(line_model_sizes)/sizeof(line_model_sizes[0])))
427 return -1;
428 fir32_create(&chan->impulse, line_models[model], line_model_sizes[model]);
429 chan->gain = 32768.0f*powf(10.0f, erl/20.0f)*ki[model];
430 chan->munging_codec = codec;
431 chan->model_no = model;
432 chan->erl = erl;
433 return 0;
434 }
435 /*- End of function --------------------------------------------------------*/
436
437 static int16_t channel_model(channel_model_state_t *chan, int16_t rout, int16_t sgen)
438 {
439 int16_t echo;
440 int16_t sin;
441
442 /* Channel modelling is merely simulating the effects of A-law or u-law distortion
443 and using one of the echo models from G.168. Simulating the codec is very important,
444 as this is usually the limiting factor in how much echo reduction is achieved. */
445
446 /* The far end signal will have been through codec munging. */
447 switch (chan->munging_codec)
448 {
449 case G711_ALAW:
450 sgen = alaw_to_linear(linear_to_alaw(sgen));
451 break;
452 case G711_ULAW:
453 sgen = ulaw_to_linear(linear_to_ulaw(sgen));
454 break;
455 }
456
457 /* The local tx signal will usually have gone through codec munging before
458 it reached the line's analogue area, where the echo occurs. */
459 switch (chan->munging_codec)
460 {
461 case G711_ALAW:
462 rout = alaw_to_linear(linear_to_alaw(rout));
463 break;
464 case G711_ULAW:
465 rout = ulaw_to_linear(linear_to_ulaw(rout));
466 break;
467 }
468 /* Now we need to model the echo. We only model a single analogue segment, as per
469 the G.168 spec. However, there will generally be near end and far end analogue/echoey
470 segments in the real world, unless an end is purely digital. */
471 echo = fir32(&chan->impulse, rout*chan->gain);
472 sin = saturate(echo + sgen);
473
474 /* This mixed echo and far end signal will have been through codec munging
475 when it came back into the digital network. */
476 switch (chan->munging_codec)
477 {
478 case G711_ALAW:
479 sin = alaw_to_linear(linear_to_alaw(sin));
480 break;
481 case G711_ULAW:
482 sin = ulaw_to_linear(linear_to_ulaw(sin));
483 break;
484 }
485 return sin;
486 }
487 /*- End of function --------------------------------------------------------*/
488
489 static void write_log_files(int16_t rout, int16_t sin)
490 {
491 #if 0
492 fprintf(flevel, "%f\t%f\t%f\t%f\n", LRin, LSin, LSout, LSgen);
493 fprintf(fdump, "%d %d %d", ctx->tx, ctx->rx, ctx->clean);
494 fprintf(fdump,
495 " %d %d %d %d %d %d %d %d %d %d\n",
496 ctx->clean_nlp,
497 ctx->Ltx,
498 ctx->Lrx,
499 ctx->Lclean,
500 (ctx->nonupdate_dwell > 0),
501 ctx->adapt,
502 ctx->Lclean_bg,
503 ctx->Pstates,
504 ctx->Lbgn_upper,
505 ctx->Lbgn);
506 #endif
507 }
508 /*- End of function --------------------------------------------------------*/
509
510 static int16_t silence(void)
511 {
512 return 0;
513 }
514 /*- End of function --------------------------------------------------------*/
515
516 static int16_t local_css_signal(void)
517 {
518 return signal_amp(&local_css);
519 }
520 /*- End of function --------------------------------------------------------*/
521
522 static int16_t far_css_signal(void)
523 {
524 return signal_amp(&far_css);
525 }
526 /*- End of function --------------------------------------------------------*/
527
528 static int16_t local_noise_signal(void)
529 {
530 return awgn(&local_noise_source);
531 }
532 /*- End of function --------------------------------------------------------*/
533
534 static int16_t far_noise_signal(void)
535 {
536 return awgn(&far_noise_source);
537 }
538 /*- End of function --------------------------------------------------------*/
539
540 #if 0
541 static int16_t local_hoth_noise_signal(void)
542 {
543 static float hoth_noise = 0.0;
544
545 hoth_noise = hoth_noise*0.625 + awgn(&local_noise_source)*0.375;
546 return (int16_t) hoth_noise;
547 }
548 /*- End of function --------------------------------------------------------*/
549 #endif
550
551 static int16_t far_hoth_noise_signal(void)
552 {
553 static float hoth_noise = 0.0;
554
555 hoth_noise = hoth_noise*0.625 + awgn(&far_noise_source)*0.375;
556 return (int16_t) hoth_noise;
557 }
558 /*- End of function --------------------------------------------------------*/
559
560 static void run_test(echo_can_state_t *ctx, int16_t (*tx_source)(void), int16_t (*rx_source)(void), int period)
561 {
562 int i;
563 int16_t rin;
564 int16_t rout;
565 int16_t sin;
566 int16_t sout;
567 int16_t sgen;
568 int outframes;
569
570 for (i = 0; i < period*SAMPLE_RATE/1000; i++)
571 {
572 rin = tx_source();
573 sgen = rx_source();
574
575 rout = echo_can_hpf_tx(ctx, rin);
576 sin = channel_model(&chan_model, rout, sgen);
577 sout = echo_can_update(ctx, rout, sin);
578
579 level_measurements_update(rin, sin, rout, sout, sgen);
580 //residue = 100.0f*pp1/pp2;
581 //put_residue(residue);
582
583 //put_residue(clean - rx);
584 #if defined(ENABLE_GUI)
585 if (use_gui)
586 echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS);
587 #endif
588 result_sound[result_cur++] = rin;
589 result_sound[result_cur++] = sgen;
590 result_sound[result_cur++] = sin;
591 result_sound[result_cur++] = rout;
592 result_sound[result_cur++] = sout;
593 result_sound[result_cur++] = sout - sgen;
594 result_sound[result_cur++] = 0; // TODO: insert the EC's internal status here
595 if (result_cur >= RESULT_CHANNELS*SAMPLE_RATE)
596 {
597 outframes = sf_writef_short(result_handle, result_sound, result_cur/RESULT_CHANNELS);
598 if (outframes != result_cur/RESULT_CHANNELS)
599 {
600 fprintf(stderr, " Error writing result sound\n");
601 exit(2);
602 }
603 result_cur = 0;
604 }
605 }
606 #if defined(ENABLE_GUI)
607 if (use_gui)
608 echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS);
609 #endif
610 if (result_cur >= 0)
611 {
612 outframes = sf_writef_short(result_handle, result_sound, result_cur/RESULT_CHANNELS);
613 if (outframes != result_cur/RESULT_CHANNELS)
614 {
615 fprintf(stderr, " Error writing result sound\n");
616 exit(2);
617 }
618 result_cur = 0;
619 }
620 }
621 /*- End of function --------------------------------------------------------*/
622
623 static void print_test_title(const char *title)
624 {
625 if (quiet == FALSE)
626 printf(title);
627 }
628 /*- End of function --------------------------------------------------------*/
629
630 static int perform_test_sanity(void)
631 {
632 echo_can_state_t *ctx;
633 int i;
634 int16_t rx;
635 int16_t tx;
636 int16_t clean;
637 int far_tx;
638 int16_t far_sound[SAMPLE_RATE];
639 int16_t result_sound[64000];
640 int result_cur;
641 int outframes;
642 int local_cur;
643 int far_cur;
644 //int32_t coeffs[200][128];
645 //int coeff_index;
646
647 print_test_title("Performing basic sanity test\n");
648 ctx = echo_can_init(TEST_EC_TAPS, 0);
649
650 local_cur = 0;
651 far_cur = 0;
652 result_cur = 0;
653
654 echo_can_flush(ctx);
655 /* Converge the canceller */
656 signal_restart(&local_css, 0.0f);
657 run_test(ctx, silence, silence, 200);
658 run_test(ctx, local_css_signal, silence, 5000);
659 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP | ECHO_CAN_USE_CNG);
660 run_test(ctx, local_css_signal, silence, 5000);
661 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
662
663 for (i = 0; i < SAMPLE_RATE*10; i++)
664 {
665 tx = local_css_signal();
666 #if 0
667 if ((i/10000)%10 == 9)
668 {
669 /* Inject a burst of far sound */
670 if (far_cur >= far_max)
671 {
672 far_max = sf_readf_short(farhandle, far_sound, SAMPLE_RATE);
673 if (far_max < 0)
674 {
675 fprintf(stderr, " Error reading far sound\n");
676 exit(2);
677 }
678 if (far_max == 0)
679 break;
680 far_cur = 0;
681 }
682 far_tx = far_sound[far_cur++];
683 }
684 else
685 {
686 far_tx = 0;
687 }
688 #else
689 far_sound[0] = 0;
690 far_tx = 0;
691 #endif
692 rx = channel_model(&chan_model, tx, far_tx);
693 //rx += awgn(&far_noise_source);
694 //tx += awgn(&far_noise_source);
695 clean = echo_can_update(ctx, tx, rx);
696
697 #if defined(XYZZY)
698 if (i%SAMPLE_RATE == 0)
699 {
700 if (coeff_index < 200)
701 {
702 for (j = 0; j < ctx->taps; j++)
703 coeffs[coeff_index][j] = ctx->fir_taps32[j];
704 coeff_index++;
705 }
706 }
707 #endif
708 result_sound[result_cur++] = tx;
709 result_sound[result_cur++] = rx;
710 result_sound[result_cur++] = clean - far_tx;
711 //result_sound[result_cur++] = ctx->tx_power[2];
712 //result_sound[result_cur++] = ctx->tx_power[1];
713 ////result_sound[result_cur++] = (ctx->tx_power[1] > 64) ? SAMPLE_RATE : -SAMPLE_RATE;
714 //result_sound[result_cur++] = ctx->tap_set*SAMPLE_RATE;
715 //result_sound[result_cur++] = (ctx->nonupdate_dwell > 0) ? SAMPLE_RATE : -SAMPLE_RATE;
716 //result_sound[result_cur++] = ctx->latest_correction >> 8;
717 //result_sound[result_cur++] = level_measurement_device(tx)/(16.0*65536.0);
718 //result_sound[result_cur++] = level_measurement_device(tx)/4096.0;
719 ////result_sound[result_cur++] = (ctx->tx_power[1] > ctx->rx_power[0]) ? SAMPLE_RATE : -SAMPLE_RATE;
720 //result_sound[result_cur++] = (ctx->tx_power[1] > ctx->rx_power[0]) ? SAMPLE_RATE : -SAMPLE_RATE;
721 //result_sound[result_cur++] = (ctx->narrowband_score)*5; // ? SAMPLE_RATE : -SAMPLE_RATE;
722 //result_sound[result_cur++] = ctx->tap_rotate_counter*10;
723 ////result_sound[result_cur++] = ctx->vad;
724
725 put_residue(clean - far_tx);
726 if (result_cur >= RESULT_CHANNELS*SAMPLE_RATE)
727 {
728 outframes = sf_writef_short(result_handle, result_sound, result_cur/RESULT_CHANNELS);
729 if (outframes != result_cur/RESULT_CHANNELS)
730 {
731 fprintf(stderr, " Error writing result sound\n");
732 exit(2);
733 }
734 result_cur = 0;
735 }
736 }
737 if (result_cur > 0)
738 {
739 outframes = sf_writef_short(result_handle, result_sound, result_cur/RESULT_CHANNELS);
740 if (outframes != result_cur/RESULT_CHANNELS)
741 {
742 fprintf(stderr, " Error writing result sound\n");
743 exit(2);
744 }
745 }
746 #if defined(XYZZY)
747 for (j = 0; j < ctx->taps; j++)
748 {
749 for (i = 0; i < coeff_index; i++)
750 fprintf(stderr, "%d ", coeffs[i][j]);
751 fprintf(stderr, "\n");
752 }
753 #endif
754
755 echo_can_free(ctx);
756 return 0;
757 }
758 /*- End of function --------------------------------------------------------*/
759
760 static int perform_test_2a(void)
761 {
762 echo_can_state_t *ctx;
763
764 /* Test 2 - Convergence and steady state residual and returned echo level test */
765 /* Test 2A - Convergence and reconvergence test with NLP enabled */
766 print_test_title("Performing test 2A - Convergence and reconvergence test with NLP enabled\n");
767 ctx = echo_can_init(TEST_EC_TAPS, 0);
768
769 echo_can_flush(ctx);
770 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP);
771
772 /* Test 2A (a) - Convergence test with NLP enabled */
773
774 /* Converge the canceller. */
775 run_test(ctx, silence, silence, 200);
776 signal_restart(&local_css, 0.0f);
777 run_test(ctx, local_css_signal, silence, 1000);
778 level_measurements_reset_peaks();
779 run_test(ctx, local_css_signal, silence, 9000);
780 print_results();
781 if (level_measurement_device_get_peak(sout_power_meter) > -65.0f)
782 printf("Test failed\n");
783 else
784 printf("Test passed\n");
785
786 /* Test 2A (b) - Reconvergence test with NLP enabled */
787
788 /* Make an abrupt change of channel characteristic, to another of the channel echo models. */
789 if (channel_model_create(&chan_model, supp_line_model_no, erl, munger))
790 {
791 fprintf(stderr, " Failed to create line model\n");
792 exit(2);
793 }
794 signal_restart(&local_css, 0.0f);
795 run_test(ctx, local_css_signal, silence, 1000);
796 level_measurements_reset_peaks();
797 run_test(ctx, local_css_signal, silence, 9000);
798 print_results();
799 if (level_measurement_device_get_peak(sout_power_meter) > -65.0f)
800 printf("Test failed\n");
801 else
802 printf("Test passed\n");
803
804 echo_can_free(ctx);
805 return 0;
806 }
807 /*- End of function --------------------------------------------------------*/
808
809 static int perform_test_2b(void)
810 {
811 echo_can_state_t *ctx;
812
813 /* Test 2 - Convergence and steady state residual and returned echo level test */
814 /* Test 2B - Convergence and reconverge with NLP disabled */
815 print_test_title("Performing test 2B - Convergence and reconverge with NLP disabled\n");
816 ctx = echo_can_init(TEST_EC_TAPS, 0);
817
818 echo_can_flush(ctx);
819 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
820 signal_restart(&local_css, 0.0f);
821
822 /* Test 2B (a) - Convergence test with NLP disabled */
823
824 /* Converge the canceller */
825 run_test(ctx, silence, silence, 200);
826 run_test(ctx, local_css_signal, silence, 1000);
827 level_measurements_reset_peaks();
828 run_test(ctx, local_css_signal, silence, 9000);
829 print_results();
830 level_measurements_reset_peaks();
831 run_test(ctx, local_css_signal, silence, 170000);
832 print_results();
833 if (level_measurement_device_get_peak(sout_power_meter) > -65.0)
834 printf("Test failed\n");
835 else
836 printf("Test passed\n");
837
838 /* Test 2B (b) - Reconvergence test with NLP disabled */
839
840 /* Make an abrupt change of channel characteristic, to another of the channel echo models. */
841 if (channel_model_create(&chan_model, supp_line_model_no, erl, munger))
842 {
843 fprintf(stderr, " Failed to create line model\n");
844 exit(2);
845 }
846 run_test(ctx, local_css_signal, silence, 1000);
847 level_measurements_reset_peaks();
848 run_test(ctx, local_css_signal, silence, 9000);
849 print_results();
850 level_measurements_reset_peaks();
851 run_test(ctx, local_css_signal, silence, 170000);
852 print_results();
853 if (level_measurement_device_get_peak(sout_power_meter) > -65.0)
854 printf("Test failed\n");
855 else
856 printf("Test passed\n");
857
858 echo_can_free(ctx);
859 return 0;
860 }
861 /*- End of function --------------------------------------------------------*/
862
863 static int perform_test_2ca(void)
864 {
865 echo_can_state_t *ctx;
866
867 /* Test 2 - Convergence and steady state residual and returned echo level test */
868 /* Test 2C(a) - Convergence with background noise present */
869 print_test_title("Performing test 2C(a) - Convergence with background noise present\n");
870 ctx = echo_can_init(TEST_EC_TAPS, 0);
871 awgn_init_dbm0(&far_noise_source, 7162534, -50.0f);
872
873 echo_can_flush(ctx);
874 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
875
876 /* Converge a canceller */
877 signal_restart(&local_css, 0.0f);
878 run_test(ctx, silence, silence, 200);
879
880 awgn_init_dbm0(&far_noise_source, 7162534, -40.0f);
881 run_test(ctx, local_css_signal, far_hoth_noise_signal, 5000);
882
883 /* Now freeze adaption, and measure the echo. */
884 echo_can_adaption_mode(ctx, 0);
885 level_measurements_reset_peaks();
886 run_test(ctx, local_css_signal, silence, 5000);
887 print_results();
888 if (level_measurement_device_get_peak(sout_power_meter) > level_measurement_device_get_peak(sgen_power_meter))
889 printf("Test failed\n");
890 else
891 printf("Test passed\n");
892
893 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
894 echo_can_free(ctx);
895 return 0;
896 }
897 /*- End of function --------------------------------------------------------*/
898
899 static int perform_test_3a(void)
900 {
901 echo_can_state_t *ctx;
902
903 /* Test 3 - Performance under double talk conditions */
904 /* Test 3A - Double talk test with low cancelled-end levels */
905 print_test_title("Performing test 3A - Double talk test with low cancelled-end levels\n");
906 ctx = echo_can_init(TEST_EC_TAPS, 0);
907
908 echo_can_flush(ctx);
909 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
910
911 run_test(ctx, silence, silence, 200);
912 signal_restart(&local_css, 0.0f);
913 signal_restart(&far_css, -20.0f);
914
915 /* Apply double talk, with a weak far end signal */
916 run_test(ctx, local_css_signal, far_css_signal, 5000);
917
918 /* Now freeze adaption. */
919 echo_can_adaption_mode(ctx, 0);
920 run_test(ctx, local_css_signal, silence, 500);
921
922 /* Now measure the echo */
923 level_measurements_reset_peaks();
924 run_test(ctx, local_css_signal, silence, 5000);
925 print_results();
926 if (level_measurement_device_get_peak(sout_power_meter) > level_measurement_device_get_peak(sgen_power_meter))
927 printf("Test failed\n");
928 else
929 printf("Test passed\n");
930
931 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
932 echo_can_free(ctx);
933 return 0;
934 }
935 /*- End of function --------------------------------------------------------*/
936
937 static int perform_test_3ba(void)
938 {
939 echo_can_state_t *ctx;
940
941 /* Test 3 - Performance under double talk conditions */
942 /* Test 3B(a) - Double talk stability test with high cancelled-end levels */
943 print_test_title("Performing test 3B(b) - Double talk stability test with high cancelled-end levels\n");
944 ctx = echo_can_init(TEST_EC_TAPS, 0);
945
946 echo_can_flush(ctx);
947 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
948
949 run_test(ctx, silence, silence, 200);
950 signal_restart(&local_css, 0.0f);
951 signal_restart(&far_css, 0.0f);
952
953 /* Converge the canceller */
954 run_test(ctx, local_css_signal, silence, 5000);
955
956 /* Apply double talk */
957 run_test(ctx, local_css_signal, far_css_signal, 5000);
958
959 /* Now freeze adaption. */
960 echo_can_adaption_mode(ctx, 0);
961 run_test(ctx, local_css_signal, far_css_signal, 1000);
962
963 /* Turn off the double talk. */
964 run_test(ctx, local_css_signal, silence, 500);
965
966 /* Now measure the echo */
967 level_measurements_reset_peaks();
968 run_test(ctx, local_css_signal, silence, 5000);
969 print_results();
970
971 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
972 echo_can_free(ctx);
973 return 0;
974 }
975 /*- End of function --------------------------------------------------------*/
976
977 static int perform_test_3bb(void)
978 {
979 echo_can_state_t *ctx;
980
981 /* Test 3 - Performance under double talk conditions */
982 /* Test 3B(b) - Double talk stability test with low cancelled-end levels */
983 print_test_title("Performing test 3B(b) - Double talk stability test with low cancelled-end levels\n");
984 ctx = echo_can_init(TEST_EC_TAPS, 0);
985
986 echo_can_flush(ctx);
987 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
988
989 run_test(ctx, silence, silence, 200);
990 signal_restart(&local_css, 0.0f);
991 signal_restart(&far_css, -15.0f);
992
993 /* Converge the canceller */
994 run_test(ctx, local_css_signal, silence, 5000);
995
996 /* Apply double talk */
997 run_test(ctx, local_css_signal, far_css_signal, 5000);
998
999 /* Now freeze adaption. */
1000 echo_can_adaption_mode(ctx, 0);
1001 run_test(ctx, local_css_signal, silence, 1000);
1002
1003 /* Turn off the double talk. */
1004 run_test(ctx, local_css_signal, silence, 500);
1005
1006 /* Now measure the echo */
1007 level_measurements_reset_peaks();
1008 run_test(ctx, local_css_signal, silence, 5000);
1009 print_results();
1010
1011 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
1012 echo_can_free(ctx);
1013 return 0;
1014 }
1015 /*- End of function --------------------------------------------------------*/
1016
1017 static int perform_test_3c(void)
1018 {
1019 echo_can_state_t *ctx;
1020
1021 /* Test 3 - Performance under double talk conditions */
1022 /* Test 3C - Double talk test with simulated conversation */
1023 print_test_title("Performing test 3C - Double talk test with simulated conversation\n");
1024 ctx = echo_can_init(TEST_EC_TAPS, 0);
1025
1026 echo_can_flush(ctx);
1027 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
1028 run_test(ctx, silence, silence, 200);
1029
1030 signal_restart(&local_css, 0.0f);
1031 signal_restart(&far_css, -15.0f);
1032
1033 /* Apply double talk */
1034 run_test(ctx, local_css_signal, far_css_signal, 5600);
1035
1036 /* Stop the far signal, and measure the echo. */
1037 level_measurements_reset_peaks();
1038 run_test(ctx, local_css_signal, silence, 1400);
1039 print_results();
1040
1041 /* Continue measuring the resulting echo */
1042 run_test(ctx, local_css_signal, silence, 5000);
1043
1044 /* Reapply double talk */
1045 signal_restart(&far_css, 0.0f);
1046 run_test(ctx, local_css_signal, far_css_signal, 5600);
1047
1048 /* Now the far signal only */
1049 run_test(ctx, silence, far_css_signal, 5600);
1050
1051 echo_can_free(ctx);
1052 return 0;
1053 }
1054 /*- End of function --------------------------------------------------------*/
1055
1056 static int perform_test_4(void)
1057 {
1058 echo_can_state_t *ctx;
1059
1060 /* Test 4 - Leak rate test */
1061 print_test_title("Performing test 4 - Leak rate test\n");
1062 ctx = echo_can_init(TEST_EC_TAPS, 0);
1063
1064 echo_can_flush(ctx);
1065 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
1066
1067 run_test(ctx, silence, silence, 200);
1068
1069 /* Converge the canceller */
1070 signal_restart(&local_css, 0.0f);
1071 run_test(ctx, local_css_signal, silence, 5000);
1072
1073 /* Put 2 minutes of silence through it */
1074 run_test(ctx, silence, silence, 120000);
1075
1076 /* Now freeze it, and check if it is still well adapted. */
1077 echo_can_adaption_mode(ctx, 0);
1078 level_measurements_reset_peaks();
1079 run_test(ctx, local_css_signal, silence, 5000);
1080 print_results();
1081
1082 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
1083 echo_can_free(ctx);
1084 return 0;
1085 }
1086 /*- End of function --------------------------------------------------------*/
1087
1088 static int perform_test_5(void)
1089 {
1090 echo_can_state_t *ctx;
1091
1092 /* Test 5 - Infinite return loss convergence test */
1093 print_test_title("Performing test 5 - Infinite return loss convergence test\n");
1094 ctx = echo_can_init(TEST_EC_TAPS, 0);
1095
1096 echo_can_flush(ctx);
1097 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
1098
1099 /* Converge the canceller */
1100 signal_restart(&local_css, 0.0f);
1101 run_test(ctx, local_css_signal, silence, 5000);
1102
1103 /* Now stop echoing, and see we don't do anything unpleasant as the
1104 echo path is open looped. */
1105 run_test(ctx, local_css_signal, silence, 5000);
1106 print_results();
1107
1108 echo_can_free(ctx);
1109 return 0;
1110 }
1111 /*- End of function --------------------------------------------------------*/
1112
1113 static int perform_test_6(void)
1114 {
1115 echo_can_state_t *ctx;
1116 int i;
1117 int j;
1118 int k;
1119 int16_t rx;
1120 int16_t tx;
1121 int16_t clean;
1122 int local_max;
1123 tone_gen_descriptor_t tone_desc;
1124 tone_gen_state_t tone_state;
1125 int16_t local_sound[40000];
1126
1127 /* Test 6 - Non-divergence on narrow-band signals */
1128 print_test_title("Performing test 6 - Non-divergence on narrow-band signals\n");
1129 ctx = echo_can_init(TEST_EC_TAPS, 0);
1130
1131 echo_can_flush(ctx);
1132 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
1133
1134 /* Converge the canceller */
1135 signal_restart(&local_css, 0.0f);
1136 run_test(ctx, local_css_signal, silence, 5000);
1137
1138 /* Now put 5s bursts of a list of tones through the converged canceller, and check
1139 that nothing unpleasant happens. */
1140 for (k = 0; tones_6_4_2_7[k][0]; k++)
1141 {
1142 make_tone_gen_descriptor(&tone_desc,
1143 tones_6_4_2_7[k][0],
1144 -11,
1145 tones_6_4_2_7[k][1],
1146 -9,
1147 1,
1148 0,
1149 0,
1150 0,
1151 1);
1152 tone_gen_init(&tone_state, &tone_desc);
1153 j = 0;
1154 for (i = 0; i < 5; i++)
1155 {
1156 local_max = tone_gen(&tone_state, local_sound, SAMPLE_RATE);
1157 for (j = 0; j < SAMPLE_RATE; j++)
1158 {
1159 tx = local_sound[j];
1160 rx = channel_model(&chan_model, tx, 0);
1161 clean = echo_can_update(ctx, tx, rx);
1162 put_residue(clean);
1163 }
1164 #if defined(ENABLE_GUI)
1165 if (use_gui)
1166 {
1167 echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS);
1168 echo_can_monitor_update_display();
1169 usleep(100000);
1170 }
1171 #endif
1172 }
1173 }
1174 #if defined(ENABLE_GUI)
1175 if (use_gui)
1176 echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS);
1177 #endif
1178 echo_can_free(ctx);
1179 return 0;
1180 }
1181 /*- End of function --------------------------------------------------------*/
1182
1183 static int perform_test_7(void)
1184 {
1185 echo_can_state_t *ctx;
1186 int i;
1187 int j;
1188 int16_t rx;
1189 int16_t tx;
1190 int16_t clean;
1191 int local_max;
1192 tone_gen_descriptor_t tone_desc;
1193 tone_gen_state_t tone_state;
1194 int16_t local_sound[40000];
1195
1196 /* Test 7 - Stability */
1197 print_test_title("Performing test 7 - Stability\n");
1198 ctx = echo_can_init(TEST_EC_TAPS, 0);
1199
1200 /* Put tones through an unconverged canceller, and check nothing unpleasant
1201 happens. */
1202 echo_can_flush(ctx);
1203 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION);
1204 make_tone_gen_descriptor(&tone_desc,
1205 tones_6_4_2_7[0][0],
1206 -11,
1207 tones_6_4_2_7[0][1],
1208 -9,
1209 1,
1210 0,
1211 0,
1212 0,
1213 1);
1214 tone_gen_init(&tone_state, &tone_desc);
1215 j = 0;
1216 for (i = 0; i < 120; i++)
1217 {
1218 local_max = tone_gen(&tone_state, local_sound, SAMPLE_RATE);
1219 for (j = 0; j < SAMPLE_RATE; j++)
1220 {
1221 tx = local_sound[j];
1222 rx = channel_model(&chan_model, tx, 0);
1223 clean = echo_can_update(ctx, tx, rx);
1224 put_residue(clean);
1225 }
1226 #if defined(ENABLE_GUI)
1227 if (use_gui)
1228 {
1229 echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS);
1230 echo_can_monitor_update_display();
1231 usleep(100000);
1232 }
1233 #endif
1234 }
1235 #if defined(ENABLE_GUI)
1236 if (use_gui)
1237 echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS);
1238 #endif
1239 echo_can_free(ctx);
1240 return 0;
1241 }
1242 /*- End of function --------------------------------------------------------*/
1243
1244 static int perform_test_8(void)
1245 {
1246 echo_can_state_t *ctx;
1247
1248 /* Test 8 - Non-convergence on No 5, 6, and 7 in-band signalling */
1249 print_test_title("Performing test 8 - Non-convergence on No 5, 6, and 7 in-band signalling\n");
1250 ctx = echo_can_init(TEST_EC_TAPS, 0);
1251
1252 fprintf(stderr, "Test 8 not yet implemented\n");
1253
1254 echo_can_free(ctx);
1255 return 0;
1256 }
1257 /*- End of function --------------------------------------------------------*/
1258
1259 static int perform_test_9(void)
1260 {
1261 echo_can_state_t *ctx;
1262 awgn_state_t local_noise_source;
1263 awgn_state_t far_noise_source;
1264
1265 /* Test 9 - Comfort noise test */
1266 print_test_title("Performing test 9 - Comfort noise test\n");
1267 ctx = echo_can_init(TEST_EC_TAPS, 0);
1268 awgn_init_dbm0(&far_noise_source, 7162534, -50.0f);
1269
1270 echo_can_flush(ctx);
1271 echo_can_adaption_mode(ctx,
1272 ECHO_CAN_USE_ADAPTION
1273 | ECHO_CAN_USE_NLP
1274 | ECHO_CAN_USE_CNG);
1275
1276 /* Test 9 part 1 - matching */
1277 /* Converge the canceller */
1278 signal_restart(&local_css, 0.0f);
1279 run_test(ctx, local_css_signal, silence, 5000);
1280
1281 echo_can_adaption_mode(ctx, ECHO_CAN_USE_ADAPTION | ECHO_CAN_USE_NLP | ECHO_CAN_USE_CNG);
1282 awgn_init_dbm0(&far_noise_source, 7162534, -45.0f);
1283 run_test(ctx, silence, far_noise_signal, 30000);
1284
1285 awgn_init_dbm0(&local_noise_source, 1234567, -10.0f);
1286 run_test(ctx, local_noise_signal, far_noise_signal, 2000);
1287
1288 /* Test 9 part 2 - adjust down */
1289 awgn_init_dbm0(&far_noise_source, 7162534, -55.0f);
1290 run_test(ctx, silence, far_noise_signal, 10000);
1291 run_test(ctx, local_noise_signal, far_noise_signal, 2000);
1292
1293 echo_can_free(ctx);
1294 return 0;
1295 }
1296 /*- End of function --------------------------------------------------------*/
1297
1298 static int perform_test_10a(void)
1299 {
1300 echo_can_state_t *ctx;
1301
1302 /* Test 10 - FAX test during call establishment phase */
1303 /* Test 10A - Canceller operation on the calling station side */
1304 print_test_title("Performing test 10A - Canceller operation on the calling station side\n");
1305 ctx = echo_can_init(TEST_EC_TAPS, 0);
1306
1307 fprintf(stderr, "Test 10A not yet implemented\n");
1308
1309 echo_can_free(ctx);
1310 return 0;
1311 }
1312 /*- End of function --------------------------------------------------------*/
1313
1314 static int perform_test_10b(void)
1315 {
1316 echo_can_state_t *ctx;
1317
1318 /* Test 10 - FAX test during call establishment phase */
1319 /* Test 10B - Canceller operation on the called station side */
1320 print_test_title("Performing test 10B - Canceller operation on the called station side\n");
1321 ctx = echo_can_init(TEST_EC_TAPS, 0);
1322
1323 fprintf(stderr, "Test 10B not yet implemented\n");
1324
1325 echo_can_free(ctx);
1326 return 0;
1327 }
1328 /*- End of function --------------------------------------------------------*/
1329
1330 static int perform_test_10c(void)
1331 {
1332 echo_can_state_t *ctx;
1333
1334 /* Test 10 - FAX test during call establishment phase */
1335 /* Test 10C - Canceller operation on the calling station side during page
1336 transmission and page breaks (for further study) */
1337 print_test_title("Performing test 10C - Canceller operation on the calling station side during page\n"
1338 "transmission and page breaks (for further study)\n");
1339 ctx = echo_can_init(TEST_EC_TAPS, 0);
1340
1341 fprintf(stderr, "Test 10C not yet implemented\n");
1342
1343 echo_can_free(ctx);
1344 return 0;
1345 }
1346 /*- End of function --------------------------------------------------------*/
1347
1348 static int perform_test_11(void)
1349 {
1350 echo_can_state_t *ctx;
1351
1352 /* Test 11 - Tandem echo canceller test (for further study) */
1353 print_test_title("Performing test 11 - Tandem echo canceller test (for further study)\n");
1354 ctx = echo_can_init(TEST_EC_TAPS, 0);
1355
1356 fprintf(stderr, "Test 11 not yet implemented\n");
1357
1358 echo_can_free(ctx);
1359 return 0;
1360 }
1361 /*- End of function --------------------------------------------------------*/
1362
1363 static int perform_test_12(void)
1364 {
1365 echo_can_state_t *ctx;
1366
1367 /* Test 12 - Residual acoustic echo test (for further study) */
1368 print_test_title("Performing test 12 - Residual acoustic echo test (for further study)\n");
1369 ctx = echo_can_init(TEST_EC_TAPS, 0);
1370
1371 fprintf(stderr, "Test 12 not yet implemented\n");
1372
1373 echo_can_free(ctx);
1374 return 0;
1375 }
1376 /*- End of function --------------------------------------------------------*/
1377
1378 static int perform_test_13(void)
1379 {
1380 echo_can_state_t *ctx;
1381
1382 /* Test 13 - Performance with ITU-T low-bit rate coders in echo path
1383 (Optional, under study) */
1384 print_test_title("Performing test 13 - Performance with ITU-T low-bit rate coders in echo path (Optional, under study)\n");
1385 ctx = echo_can_init(TEST_EC_TAPS, 0);
1386
1387 fprintf(stderr, "Test 13 not yet implemented\n");
1388
1389 echo_can_free(ctx);
1390 return 0;
1391 }
1392 /*- End of function --------------------------------------------------------*/
1393
1394 static int perform_test_14(void)
1395 {
1396 echo_can_state_t *ctx;
1397
1398 /* Test 14 - Performance with V-series low-speed data modems */
1399 print_test_title("Performing test 14 - Performance with V-series low-speed data modems\n");
1400 ctx = echo_can_init(TEST_EC_TAPS, 0);
1401
1402 fprintf(stderr, "Test 14 not yet implemented\n");
1403
1404 echo_can_free(ctx);
1405 return 0;
1406 }
1407 /*- End of function --------------------------------------------------------*/
1408
1409 static int perform_test_15(void)
1410 {
1411 echo_can_state_t *ctx;
1412
1413 /* Test 15 - PCM offset test (Optional) */
1414 print_test_title("Performing test 15 - PCM offset test (Optional)\n");
1415 ctx = echo_can_init(TEST_EC_TAPS, 0);
1416
1417 fprintf(stderr, "Test 15 not yet implemented\n");
1418
1419 echo_can_free(ctx);
1420 return 0;
1421 }
1422 /*- End of function --------------------------------------------------------*/
1423
1424 static int match_test_name(const char *name)
1425 {
1426 const struct
1427 {
1428 const char *name;
1429 int (*func)(void);
1430 } tests[] =
1431 {
1432 {"sanity", perform_test_sanity},
1433 {"2a", perform_test_2a},
1434 {"2b", perform_test_2b},
1435 {"2ca", perform_test_2ca},
1436 {"3a", perform_test_3a},
1437 {"3ba", perform_test_3ba},
1438 {"3bb", perform_test_3bb},
1439 {"3c", perform_test_3c},
1440 {"4", perform_test_4},
1441 {"5", perform_test_5},
1442 {"6", perform_test_6},
1443 {"7", perform_test_7},
1444 {"8", perform_test_8},
1445 {"9", perform_test_9},
1446 {"10a", perform_test_10a},
1447 {"10b", perform_test_10b},
1448 {"10c", perform_test_10c},
1449 {"11", perform_test_11},
1450 {"12", perform_test_12},
1451 {"13", perform_test_13},
1452 {"14", perform_test_14},
1453 {"15", perform_test_15},
1454 {NULL, NULL}
1455 };
1456 int i;
1457
1458 for (i = 0; tests[i].name; i++)
1459 {
1460 if (strcasecmp(name, tests[i].name) == 0)
1461 {
1462 test_name = name;
1463 tests[i].func();
1464 return 0;
1465 }
1466 }
1467 printf("Unknown test name '%s' specified. The known test names are ", name);
1468 for (i = 0; tests[i].name; i++)
1469 {
1470 printf("%s", tests[i].name);
1471 if (tests[i + 1].name)
1472 printf(", ");
1473 }
1474 printf("\n");
1475 return -1;
1476 }
1477 /*- End of function --------------------------------------------------------*/
1478
1479 static void simulate_ec(char *argv[], int two_channel_file, int mode)
1480 {
1481 echo_can_state_t *ctx;
1482 SNDFILE *txfile;
1483 SNDFILE *rxfile;
1484 SNDFILE *rxtxfile;
1485 SNDFILE *ecfile;
1486 int ntx;
1487 int nrx;
1488 int nec;
1489 int16_t buf[2];
1490 int16_t rin;
1491 int16_t rout;
1492 int16_t sin;
1493 int16_t sout;
1494 int32_t samples;
1495
1496 mode |= ECHO_CAN_USE_ADAPTION;
1497 txfile = NULL;
1498 rxfile = NULL;
1499 rxtxfile = NULL;
1500 ecfile = NULL;
1501 if (two_channel_file)
1502 {
1503 txfile = sf_open_telephony_read(argv[0], 1);
1504 rxfile = sf_open_telephony_read(argv[1], 1);
1505 ecfile = sf_open_telephony_write(argv[2], 1);
1506 }
1507 else
1508 {
1509 rxtxfile = sf_open_telephony_read(argv[0], 2);
1510 ecfile = sf_open_telephony_write(argv[1], 1);
1511 }
1512
1513 ctx = echo_can_init(TEST_EC_TAPS, 0);
1514 echo_can_adaption_mode(ctx, mode);
1515 samples = 0;
1516 do
1517 {
1518 if (two_channel_file)
1519 {
1520 if ((ntx = sf_readf_short(rxtxfile, buf, 1)) < 0)
1521 {
1522 fprintf(stderr, " Error reading tx sound file\n");
1523 exit(2);
1524 }
1525 rin = buf[0];
1526 sin = buf[1];
1527 nrx = ntx;
1528 }
1529 else
1530 {
1531 if ((ntx = sf_readf_short(txfile, &rin, 1)) < 0)
1532 {
1533 fprintf(stderr, " Error reading tx sound file\n");
1534 exit(2);
1535 }
1536 if ((nrx = sf_readf_short(rxfile, &sin, 1)) < 0)
1537 {
1538 fprintf(stderr, " Error reading rx sound file\n");
1539 exit(2);
1540 }
1541 }
1542 rout = echo_can_hpf_tx(ctx, rin);
1543 sout = echo_can_update(ctx, rout, sin);
1544
1545 if ((nec = sf_writef_short(ecfile, &sout, 1)) != 1)
1546 {
1547 fprintf(stderr, " Error writing ec sound file\n");
1548 exit(2);
1549 }
1550 level_measurements_update(rin, sin, rout, sout, 0);
1551 write_log_files(rin, sin);
1552 #if defined(ENABLE_GUI)
1553 if (use_gui)
1554 echo_can_monitor_can_update(ctx->fir_taps16[0], TEST_EC_TAPS);
1555 #endif
1556 }
1557 while (ntx && nrx);
1558 dump_ec_state(ctx);
1559
1560 echo_can_free(ctx);
1561
1562 if (two_channel_file)
1563 {
1564 sf_close(rxtxfile);
1565 }
1566 else
1567 {
1568 sf_close(txfile);
1569 sf_close(rxfile);
1570 }
1571 sf_close(ecfile);
1572 }
1573 /*- End of function --------------------------------------------------------*/
1574
1575 int main(int argc, char *argv[])
1576 {
1577 int i;
1578 time_t now;
1579 int simulate;
1580 int cng;
1581 int hpf;
1582 int two_channel_file;
1583 int opt;
1584 int mode;
1585
1586 /* Check which tests we should run */
1587 if (argc < 2)
1588 fprintf(stderr, "Usage: echo tests [-g] [-m <model number>] [-s] <list of test numbers>\n");
1589 line_model_no = 0;
1590 supp_line_model_no = 0;
1591 cng = FALSE;
1592 hpf = FALSE;
1593 use_gui = FALSE;
1594 simulate = FALSE;
1595 munger = -1;
1596 two_channel_file = FALSE;
1597 erl = -12.0f;
1598
1599 while ((opt = getopt(argc, argv, "2ace:ghm:M:su")) != -1)
1600 {
1601 switch (opt)
1602 {
1603 case '2':
1604 two_channel_file = TRUE;
1605 break;
1606 case 'a':
1607 munger = G711_ALAW;
1608 break;
1609 case 'c':
1610 cng = TRUE;
1611 break;
1612 case 'e':
1613 /* Allow for ERL being entered as x or -x */
1614 erl = -fabs(atof(optarg));
1615 break;
1616 case 'g':
1617 #if defined(ENABLE_GUI)
1618 use_gui = TRUE;
1619 #else
1620 fprintf(stderr, "Graphical monitoring not available\n");
1621 exit(2);
1622 #endif
1623 break;
1624 case 'h':
1625 hpf = TRUE;
1626 break;
1627 case 'm':
1628 line_model_no = atoi(optarg);
1629 break;
1630 case 'M':
1631 supp_line_model_no = atoi(optarg);
1632 break;
1633 case 's':
1634 simulate = TRUE;
1635 break;
1636 case 'u':
1637 munger = G711_ULAW;
1638 break;
1639 default:
1640 //usage();
1641 exit(2);
1642 break;
1643 }
1644 }
1645 argc -= optind;
1646 argv += optind;
1647
1648 #if defined(ENABLE_GUI)
1649 if (use_gui)
1650 start_echo_can_monitor(TEST_EC_TAPS);
1651 #endif
1652 if (simulate)
1653 {
1654 /* Process a pair of transmitted and received audio files, and produce
1655 an echo cancelled audio file. */
1656 if (argc < ((two_channel_file) ? 2 : 3))
1657 {
1658 printf("not enough arguments for a simulation\n");
1659 exit(2);
1660 }
1661 mode = ECHO_CAN_USE_NLP;
1662 mode |= ((cng) ? ECHO_CAN_USE_CNG : ECHO_CAN_USE_CLIP);
1663 if (hpf)
1664 {
1665 mode |= ECHO_CAN_USE_TX_HPF;
1666 mode |= ECHO_CAN_USE_RX_HPF;
1667 }
1668 simulate_ec(argv, two_channel_file, mode);
1669 }
1670 else
1671 {
1672 /* Run some G.168 tests */
1673 #if defined(ENABLE_GUI)
1674 if (use_gui)
1675 echo_can_monitor_line_model_update(chan_model.impulse.coeffs, chan_model.impulse.taps);
1676 #endif
1677 signal_load(&local_css, "sound_c1_8k.wav");
1678 signal_load(&far_css, "sound_c3_8k.wav");
1679
1680 if ((residue_handle = sf_open_telephony_write(RESIDUE_FILE_NAME, 1)) == NULL)
1681 {
1682 fprintf(stderr, " Failed to open '%s'\n", RESIDUE_FILE_NAME);
1683 exit(2);
1684 }
1685 if (argc <= 0)
1686 {
1687 printf("No tests specified\n");
1688 }
1689 else
1690 {
1691 time(&now);
1692 if ((result_handle = sf_open_telephony_write("echo_tests_result.wav", RESULT_CHANNELS)) == NULL)
1693 {
1694 fprintf(stderr, " Failed to open result file\n");
1695 exit(2);
1696 }
1697 result_cur = 0;
1698 level_measurements_create(0);
1699 for (i = 0; i < argc; i++)
1700 {
1701 if (channel_model_create(&chan_model, line_model_no, erl, munger))
1702 {
1703 fprintf(stderr, " Failed to create line model\n");
1704 exit(2);
1705 }
1706 match_test_name(argv[i]);
1707 }
1708 if (sf_close(result_handle) != 0)
1709 {
1710 fprintf(stderr, " Cannot close speech file '%s'\n", "result_sound.wav");
1711 exit(2);
1712 }
1713 printf("Run time %lds\n", time(NULL) - now);
1714 }
1715 signal_free(&local_css);
1716 signal_free(&far_css);
1717 if (sf_close(residue_handle) != 0)
1718 {
1719 fprintf(stderr, " Cannot close speech file '%s'\n", RESIDUE_FILE_NAME);
1720 exit(2);
1721 }
1722 }
1723 #if defined(ENABLE_GUI)
1724 if (use_gui)
1725 echo_can_monitor_wait_to_end();
1726 #endif
1727
1728 printf("Tests passed.\n");
1729 return 0;
1730 }
1731 /*- End of function --------------------------------------------------------*/
1732 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.