pjsip logo pjsip.org
Open source SIP stack and media stack for presence, im/instant messaging, and multimedia communication

HOME

SIP/media Features
High Performance SIP
Small Footprint SIP
Symbian Port

FAQ

Documentation

Licensing

Download

Development (Trac)

Projects using pjsip

Mailing List

Open Source Links


About: PJLIB, PJLIB-UTIL, PJSIP, and PJMEDIA are created by: Benny Prijono
<bennylp@pjsip.org>


 

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

 


PJMEDIA small footprint Open Source media stack
(C)2003-2008 Benny Prijono