Play a file to speaker, run AEC, and record the microphone input to see if echo is coming.
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00032 #include <pjmedia.h>
00033 #include <pjlib-util.h>
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
00074
00075
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
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
00160 status = pj_init();
00161 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00162
00163
00164 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
00165
00166
00167
00168
00169
00170 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
00171 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
00172
00173
00174 pool = pj_pool_create( &cp.factory,
00175 "wav",
00176 4000,
00177 4000,
00178 NULL
00179 );
00180
00181
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
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
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
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
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
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
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
00256
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
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
00281 pjmedia_echo_destroy(ec);
00282
00283
00284 pj_pool_release( pool );
00285
00286
00287 pjmedia_endpt_destroy( med_endpt );
00288
00289
00290 pj_caching_pool_destroy( &cp );
00291
00292
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
00302 return 0;
00303 }
00304