BLOG | DOCUMENTATION | TRAC

Home --> Documentations --> PJMEDIA Reference

Samples: AEC Test (aectest.c)

Play a file to speaker, run AEC, and record the microphone input to see if echo is coming.

This file is pjsip-apps/src/samples/aectest.c

00001 /* $Id: aectest.c 3664 2011-07-19 03:42:28Z nanang $ */
00002 /* 
00003  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
00004  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
00019  */
00020 
00021 
00032 #include <pjmedia.h>
00033 #include <pjlib-util.h> /* pj_getopt */
00034 #include <pjlib.h>
00035 
00036 #define THIS_FILE   "aectest.c"
00037 #define PTIME       20
00038 #define TAIL_LENGTH 200
00039 
00040 static const char *desc = 
00041 " FILE                                                              \n"
00042 "                                                                   \n"
00043 "  aectest.c                                                        \n"
00044 "                                                                   \n"
00045 " PURPOSE                                                           \n"
00046 "                                                                   \n"
00047 "  Test the AEC effectiveness.                                      \n"
00048 "                                                                   \n"
00049 " USAGE                                                             \n"
00050 "                                                                   \n"
00051 "  aectest [options] <PLAY.WAV> <REC.WAV> <OUTPUT.WAV>              \n"
00052 "                                                                   \n"
00053 "  <PLAY.WAV>   is the signal played to the speaker.                \n"
00054 "  <REC.WAV>    is the signal captured from the microphone.         \n"
00055 "  <OUTPUT.WAV> is the output file to store the test result         \n"
00056 "\n"
00057 " options:\n"
00058 "  -d  The delay between playback and capture in ms, at least 25 ms.\n"
00059 "      Default is 25 ms. See note below.                            \n"
00060 "  -l  Set the echo tail length in ms. Default is 200 ms            \n"
00061 "  -r  Set repeat count (default=1)                                 \n"
00062 "  -a  Algorithm: 0=default, 1=speex, 3=echo suppress               \n"
00063 "  -i  Interactive                                                  \n"
00064 "\n"
00065 " Note that for the AEC internal buffering mechanism, it is required\n"
00066 " that the echoed signal (in REC.WAV) is delayed from the           \n"
00067 " corresponding reference signal (in PLAY.WAV) at least as much as  \n"
00068 " frame time + PJMEDIA_WSOLA_DELAY_MSEC. In this application, frame \n"
00069 " time is 20 ms and default PJMEDIA_WSOLA_DELAY_MSEC is 5 ms, hence \n"
00070 " 25 ms delay is the minimum value.                                 \n";
00071 
00072 /* 
00073  * Sample session:
00074  *
00075  * -d 100 -a 1 ../bin/orig8.wav ../bin/echo8.wav ../bin/result8.wav 
00076  */
00077 
00078 static void app_perror(const char *sender, const char *title, pj_status_t st)
00079 {
00080     char errmsg[PJ_ERR_MSG_SIZE];
00081 
00082     pj_strerror(st, errmsg, sizeof(errmsg));
00083     PJ_LOG(3,(sender, "%s: %s", title, errmsg));
00084 }
00085 
00086 
00087 /*
00088  * main()
00089  */
00090 int main(int argc, char *argv[])
00091 {
00092     pj_caching_pool cp;
00093     pjmedia_endpt *med_endpt;
00094     pj_pool_t     *pool;
00095     pjmedia_port  *wav_play;
00096     pjmedia_port  *wav_rec;
00097     pjmedia_port  *wav_out;
00098     pj_status_t status;
00099     pjmedia_echo_state *ec;
00100     pjmedia_frame play_frame, rec_frame;
00101     unsigned opt = 0;
00102     unsigned latency_ms = 25;
00103     unsigned tail_ms = TAIL_LENGTH;
00104     pj_timestamp t0, t1;
00105     int i, repeat=1, interactive=0, c;
00106 
00107     pj_optind = 0;
00108     while ((c=pj_getopt(argc, argv, "d:l:a:r:i")) !=-1) {
00109         switch (c) {
00110         case 'd':
00111             latency_ms = atoi(pj_optarg);
00112             if (latency_ms < 25) {
00113                 puts("Invalid delay");
00114                 puts(desc);
00115             }
00116             break;
00117         case 'l':
00118             tail_ms = atoi(pj_optarg);
00119             break;
00120         case 'a':
00121             {
00122                 int alg = atoi(pj_optarg);
00123                 switch (alg) {
00124                 case 0:
00125                     opt = 0;
00126                 case 1:
00127                     opt = PJMEDIA_ECHO_SPEEX;
00128                     break;
00129                 case 3:
00130                     opt = PJMEDIA_ECHO_SIMPLE;
00131                     break;
00132                 default:
00133                     puts("Invalid algorithm");
00134                     puts(desc);
00135                     return 1;
00136                 }
00137             }
00138             break;
00139         case 'r':
00140             repeat = atoi(pj_optarg);
00141             if (repeat < 1) {
00142                 puts("Invalid repeat count");
00143                 puts(desc);
00144                 return 1;
00145             }
00146             break;
00147         case 'i':
00148             interactive = 1;
00149             break;
00150         }
00151     }
00152 
00153     if (argc - pj_optind != 3) {
00154         puts("Error: missing argument(s)");
00155         puts(desc);
00156         return 1;
00157     }
00158 
00159     /* Must init PJLIB first: */
00160     status = pj_init();
00161     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00162 
00163     /* Must create a pool factory before we can allocate any memory. */
00164     pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
00165 
00166     /* 
00167      * Initialize media endpoint.
00168      * This will implicitly initialize PJMEDIA too.
00169      */
00170     status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
00171     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00172 
00173     /* Create memory pool for our file player */
00174     pool = pj_pool_create( &cp.factory,     /* pool factory         */
00175                            "wav",           /* pool name.           */
00176                            4000,            /* init size            */
00177                            4000,            /* increment size       */
00178                            NULL             /* callback on error    */
00179                            );
00180 
00181     /* Open wav_play */
00182     status = pjmedia_wav_player_port_create(pool, argv[pj_optind], PTIME, 
00183                                             PJMEDIA_FILE_NO_LOOP, 0, 
00184                                             &wav_play);
00185     if (status != PJ_SUCCESS) {
00186         app_perror(THIS_FILE, "Error opening playback WAV file", status);
00187         return 1;
00188     }
00189     
00190     /* Open recorded wav */
00191     status = pjmedia_wav_player_port_create(pool, argv[pj_optind+1], PTIME, 
00192                                             PJMEDIA_FILE_NO_LOOP, 0, 
00193                                             &wav_rec);
00194     if (status != PJ_SUCCESS) {
00195         app_perror(THIS_FILE, "Error opening recorded WAV file", status);
00196         return 1;
00197     }
00198 
00199     /* play and rec WAVs must have the same clock rate */
00200     if (PJMEDIA_PIA_SRATE(&wav_play->info) != PJMEDIA_PIA_SRATE(&wav_rec->info)) {
00201         puts("Error: clock rate mismatch in the WAV files");
00202         return 1;
00203     }
00204 
00205     /* .. and channel count */
00206     if (PJMEDIA_PIA_CCNT(&wav_play->info) != PJMEDIA_PIA_CCNT(&wav_rec->info)) {
00207         puts("Error: clock rate mismatch in the WAV files");
00208         return 1;
00209     }
00210 
00211     /* Create output wav */
00212     status = pjmedia_wav_writer_port_create(pool, argv[pj_optind+2],
00213                                             PJMEDIA_PIA_SRATE(&wav_play->info),
00214                                             PJMEDIA_PIA_CCNT(&wav_play->info),
00215                                             PJMEDIA_PIA_SPF(&wav_play->info),
00216                                             PJMEDIA_PIA_BITS(&wav_play->info),
00217                                             0, 0, &wav_out);
00218     if (status != PJ_SUCCESS) {
00219         app_perror(THIS_FILE, "Error opening output WAV file", status);
00220         return 1;
00221     }
00222 
00223     /* Create echo canceller */
00224     status = pjmedia_echo_create2(pool, PJMEDIA_PIA_SRATE(&wav_play->info),
00225                                   PJMEDIA_PIA_CCNT(&wav_play->info),
00226                                   PJMEDIA_PIA_SPF(&wav_play->info),
00227                                   tail_ms, latency_ms,
00228                                   opt, &ec);
00229     if (status != PJ_SUCCESS) {
00230         app_perror(THIS_FILE, "Error creating EC", status);
00231         return 1;
00232     }
00233 
00234 
00235     /* Processing loop */
00236     play_frame.buf = pj_pool_alloc(pool, PJMEDIA_PIA_SPF(&wav_play->info)<<1);
00237     rec_frame.buf = pj_pool_alloc(pool, PJMEDIA_PIA_SPF(&wav_play->info)<<1);
00238     pj_get_timestamp(&t0);
00239     for (i=0; i < repeat; ++i) {
00240         for (;;) {
00241             play_frame.size = PJMEDIA_PIA_SPF(&wav_play->info) << 1;
00242             status = pjmedia_port_get_frame(wav_play, &play_frame);
00243             if (status != PJ_SUCCESS)
00244                 break;
00245 
00246             status = pjmedia_echo_playback(ec, (short*)play_frame.buf);
00247 
00248             rec_frame.size = PJMEDIA_PIA_SPF(&wav_play->info) << 1;
00249             status = pjmedia_port_get_frame(wav_rec, &rec_frame);
00250             if (status != PJ_SUCCESS)
00251                 break;
00252 
00253             status = pjmedia_echo_capture(ec, (short*)rec_frame.buf, 0);
00254 
00255             //status = pjmedia_echo_cancel(ec, (short*)rec_frame.buf, 
00256             //                       (short*)play_frame.buf, 0, NULL);
00257 
00258             pjmedia_port_put_frame(wav_out, &rec_frame);
00259         }
00260 
00261         pjmedia_wav_player_port_set_pos(wav_play, 0);
00262         pjmedia_wav_player_port_set_pos(wav_rec, 0);
00263     }
00264     pj_get_timestamp(&t1);
00265 
00266     i = pjmedia_wav_writer_port_get_pos(wav_out) / sizeof(pj_int16_t) * 1000 / 
00267          (PJMEDIA_PIA_SRATE(&wav_out->info) * PJMEDIA_PIA_CCNT(&wav_out->info));
00268     PJ_LOG(3,(THIS_FILE, "Processed %3d.%03ds audio",
00269               i / 1000, i % 1000));
00270     PJ_LOG(3,(THIS_FILE, "Completed in %u msec\n", pj_elapsed_msec(&t0, &t1)));
00271 
00272     /* Destroy file port(s) */
00273     status = pjmedia_port_destroy( wav_play );
00274     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00275     status = pjmedia_port_destroy( wav_rec );
00276     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00277     status = pjmedia_port_destroy( wav_out );
00278     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00279 
00280     /* Destroy ec */
00281     pjmedia_echo_destroy(ec);
00282 
00283     /* Release application pool */
00284     pj_pool_release( pool );
00285 
00286     /* Destroy media endpoint. */
00287     pjmedia_endpt_destroy( med_endpt );
00288 
00289     /* Destroy pool factory */
00290     pj_caching_pool_destroy( &cp );
00291 
00292     /* Shutdown PJLIB */
00293     pj_shutdown();
00294 
00295     if (interactive) {
00296         char s[10], *dummy;
00297         puts("ENTER to quit");
00298         dummy = fgets(s, sizeof(s), stdin);
00299     }
00300 
00301     /* Done. */
00302     return 0;
00303 }
00304 

 


PJMEDIA small footprint Open Source media stack
Copyright (C) 2006-2008 Teluu Inc.