Ignore:
Timestamp:
Aug 9, 2008 5:40:22 AM (16 years ago)
Author:
bennylp
Message:

Ticket #588: Improvements to echo cancellation framework

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/samples/aectest.c

    r2039 r2198  
    3333#include <pjlib.h> 
    3434 
    35 /* For logging purpose. */ 
    36 #define THIS_FILE   "playfile.c" 
     35#define THIS_FILE   "aectest.c" 
    3736#define PTIME       20 
    38 #define TAIL_LENGTH 800 
     37#define TAIL_LENGTH 200 
    3938 
    4039static const char *desc =  
     
    4948" USAGE                                                             \n" 
    5049"                                                                   \n" 
    51 "  aectest INPUT.WAV OUTPUT.WAV                                     \n" 
    52 "                                                                   \n" 
    53 "  INPUT.WAV is the file to be played to the speaker.               \n" 
    54 "  OUTPUT.WAV is the output file containing recorded signal from the\n" 
    55 "  microphone."; 
    56  
     50"  aectest [options] <PLAY.WAV> <REC.WAV> <OUTPUT.WAV>              \n" 
     51"                                                                   \n" 
     52"  <PLAY.WAV>   is the signal played to the speaker.                \n" 
     53"  <REC.WAV>    is the signal captured from the microphone.         \n" 
     54"  <OUTPUT.WAV> is the output file to store the test result         \n" 
     55"\n" 
     56" options:\n" 
     57"  -d  The delay between playback and capture in ms. Default is zero.\n" 
     58"  -l  Set the echo tail length in ms. Default is 200 ms            \n" 
     59"  -a  Algorithm: 0=default, 1=speex, 3=echo suppress               \n"; 
     60 
     61/*  
     62 * Sample session: 
     63 * 
     64 * -d 100 -a 1 ../bin/orig8.wav ../bin/echo8.wav ../bin/result8.wav  
     65 */ 
    5766 
    5867static void app_perror(const char *sender, const char *title, pj_status_t st) 
     
    7382    pjmedia_endpt *med_endpt; 
    7483    pj_pool_t     *pool; 
    75     pjmedia_port  *play_port; 
    76     pjmedia_port  *rec_port; 
    77     pjmedia_port  *bidir_port; 
    78     pjmedia_snd_port *snd; 
    79     char tmp[10]; 
     84    pjmedia_port  *wav_play; 
     85    pjmedia_port  *wav_rec; 
     86    pjmedia_port  *wav_out; 
    8087    pj_status_t status; 
    81  
    82  
    83     if (argc != 3) { 
    84         puts("Error: arguments required"); 
     88    pjmedia_echo_state *ec; 
     89    pjmedia_frame play_frame, rec_frame; 
     90    unsigned opt = 0; 
     91    unsigned latency_ms = 0; 
     92    unsigned tail_ms = TAIL_LENGTH; 
     93    pj_timestamp t0, t1; 
     94    int c; 
     95 
     96    pj_optind = 0; 
     97    while ((c=pj_getopt(argc, argv, "d:l:a:")) !=-1) { 
     98        switch (c) { 
     99        case 'd': 
     100            latency_ms = atoi(pj_optarg); 
     101            break; 
     102        case 'l': 
     103            tail_ms = atoi(pj_optarg); 
     104            break; 
     105        case 'a': 
     106            { 
     107                int alg = atoi(pj_optarg); 
     108                switch (alg) { 
     109                case 0: 
     110                    opt = 0; 
     111                case 1: 
     112                    opt = PJMEDIA_ECHO_SPEEX; 
     113                    break; 
     114                case 3: 
     115                    opt = PJMEDIA_ECHO_SIMPLE; 
     116                    break; 
     117                default: 
     118                    puts("Invalid algorithm"); 
     119                    puts(desc); 
     120                    return 1; 
     121                } 
     122            } 
     123            break; 
     124        } 
     125    } 
     126 
     127    if (argc - pj_optind != 3) { 
     128        puts("Error: missing argument(s)"); 
    85129        puts(desc); 
    86130        return 1; 
    87131    } 
    88  
    89132 
    90133    /* Must init PJLIB first: */ 
     
    110153                           ); 
    111154 
    112     /* Create file media port from the WAV file */ 
    113     status = pjmedia_wav_player_port_create(  pool,     /* memory pool      */ 
    114                                               argv[1],  /* file to play     */ 
    115                                               PTIME,    /* ptime.           */ 
    116                                               0,        /* flags            */ 
    117                                               0,        /* default buffer   */ 
    118                                               &play_port); 
    119     if (status != PJ_SUCCESS) { 
    120         app_perror(THIS_FILE, "Unable to open input WAV file", status); 
    121         return 1; 
    122     } 
    123  
    124     if (play_port->info.channel_count != 1) { 
    125         puts("Error: input WAV must have 1 channel audio"); 
    126         return 1; 
    127     } 
    128     if (play_port->info.bits_per_sample != 16) { 
    129         puts("Error: input WAV must be encoded as 16bit PCM"); 
    130         return 1; 
    131     } 
    132  
    133 #ifdef PJ_DARWINOS 
    134     /* Need to force clock rate on MacOS */ 
    135     if (play_port->info.clock_rate != 44100) { 
    136         pjmedia_port *resample_port; 
    137  
    138         status = pjmedia_resample_port_create(pool, play_port, 44100, 0, 
    139                                               &resample_port); 
    140         if (status != PJ_SUCCESS) { 
    141             app_perror(THIS_FILE, "Unable to create resampling port", status); 
    142             return 1; 
    143         } 
    144  
    145         data.play_port = resample_port; 
    146     } 
    147 #endif 
    148  
    149     /* Create WAV output file port */ 
    150     status = pjmedia_wav_writer_port_create(pool, argv[2],  
    151                                             play_port->info.clock_rate, 
    152                                             play_port->info.channel_count, 
    153                                             play_port->info.samples_per_frame, 
    154                                             play_port->info.bits_per_sample, 
    155                                             0, 0, &rec_port); 
    156     if (status != PJ_SUCCESS) { 
    157         app_perror(THIS_FILE, "Unable to open output file", status); 
    158         return 1; 
    159     } 
    160  
    161     /* Create bidirectional port from the WAV ports */ 
    162     pjmedia_bidirectional_port_create(pool, play_port, rec_port, &bidir_port); 
    163  
    164     /* Create sound device. */ 
    165     status = pjmedia_snd_port_create(pool, -1, -1,  
    166                                      play_port->info.clock_rate, 
    167                                      play_port->info.channel_count, 
    168                                      play_port->info.samples_per_frame, 
    169                                      play_port->info.bits_per_sample, 
    170                                      0, &snd); 
    171     if (status != PJ_SUCCESS) { 
    172         app_perror(THIS_FILE, "Unable to open sound device", status); 
    173         return 1; 
    174     } 
    175  
    176  
    177     /* Customize AEC */ 
    178     pjmedia_snd_port_set_ec(snd, pool, TAIL_LENGTH, 0); 
    179  
    180     /* Connect sound to the port */ 
    181     pjmedia_snd_port_connect(snd, bidir_port); 
    182  
    183  
    184     puts(""); 
    185     printf("Playing %s and recording to %s\n", argv[1], argv[2]); 
    186     puts("Press <ENTER> to quit"); 
    187  
    188     fgets(tmp, sizeof(tmp), stdin); 
    189  
     155    /* Open wav_play */ 
     156    status = pjmedia_wav_player_port_create(pool, argv[pj_optind], PTIME,  
     157                                            PJMEDIA_FILE_NO_LOOP, 0,  
     158                                            &wav_play); 
     159    if (status != PJ_SUCCESS) { 
     160        app_perror(THIS_FILE, "Error opening playback WAV file", status); 
     161        return 1; 
     162    } 
    190163     
    191     /* Start deinitialization: */ 
    192  
    193     /* Destroy sound device */ 
    194     status = pjmedia_snd_port_destroy( snd ); 
    195     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    196  
     164    /* Open recorded wav */ 
     165    status = pjmedia_wav_player_port_create(pool, argv[pj_optind+1], PTIME,  
     166                                            PJMEDIA_FILE_NO_LOOP, 0,  
     167                                            &wav_rec); 
     168    if (status != PJ_SUCCESS) { 
     169        app_perror(THIS_FILE, "Error opening recorded WAV file", status); 
     170        return 1; 
     171    } 
     172 
     173    /* play and rec WAVs must have the same clock rate */ 
     174    if (wav_play->info.clock_rate != wav_rec->info.clock_rate) { 
     175        puts("Error: clock rate mismatch in the WAV files"); 
     176        return 1; 
     177    } 
     178 
     179    /* .. and channel count */ 
     180    if (wav_play->info.channel_count != wav_rec->info.channel_count) { 
     181        puts("Error: clock rate mismatch in the WAV files"); 
     182        return 1; 
     183    } 
     184 
     185    /* Create output wav */ 
     186    status = pjmedia_wav_writer_port_create(pool, argv[pj_optind+2], 
     187                                            wav_play->info.clock_rate, 
     188                                            wav_play->info.channel_count, 
     189                                            wav_play->info.samples_per_frame, 
     190                                            wav_play->info.bits_per_sample, 
     191                                            0, 0, &wav_out); 
     192    if (status != PJ_SUCCESS) { 
     193        app_perror(THIS_FILE, "Error opening output WAV file", status); 
     194        return 1; 
     195    } 
     196 
     197    /* Create echo canceller */ 
     198    status = pjmedia_echo_create2(pool, wav_play->info.clock_rate, 
     199                                  wav_play->info.channel_count, 
     200                                  wav_play->info.samples_per_frame, 
     201                                  tail_ms, latency_ms, 
     202                                  opt, &ec); 
     203    if (status != PJ_SUCCESS) { 
     204        app_perror(THIS_FILE, "Error creating EC", status); 
     205        return 1; 
     206    } 
     207 
     208 
     209    /* Processing loop */ 
     210    play_frame.buf = pj_pool_alloc(pool, wav_play->info.samples_per_frame<<1); 
     211    rec_frame.buf = pj_pool_alloc(pool, wav_play->info.samples_per_frame<<1); 
     212    pj_get_timestamp(&t0); 
     213    for (;;) { 
     214        play_frame.size = wav_play->info.samples_per_frame << 1; 
     215        status = pjmedia_port_get_frame(wav_play, &play_frame); 
     216        if (status != PJ_SUCCESS) 
     217            break; 
     218 
     219        status = pjmedia_echo_playback(ec, (short*)play_frame.buf); 
     220 
     221        rec_frame.size = wav_play->info.samples_per_frame << 1; 
     222        status = pjmedia_port_get_frame(wav_rec, &rec_frame); 
     223        if (status != PJ_SUCCESS) 
     224            break; 
     225 
     226        status = pjmedia_echo_capture(ec, (short*)rec_frame.buf, 0); 
     227 
     228        //status = pjmedia_echo_cancel(ec, (short*)rec_frame.buf,  
     229        //                           (short*)play_frame.buf, 0, NULL); 
     230 
     231        pjmedia_port_put_frame(wav_out, &rec_frame); 
     232    } 
     233    pj_get_timestamp(&t1); 
     234 
     235    PJ_LOG(3,(THIS_FILE, "Completed in %u msec\n", pj_elapsed_msec(&t0, &t1))); 
    197236 
    198237    /* Destroy file port(s) */ 
    199     status = pjmedia_port_destroy( play_port ); 
    200     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    201     status = pjmedia_port_destroy( rec_port ); 
    202     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    203  
     238    status = pjmedia_port_destroy( wav_play ); 
     239    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
     240    status = pjmedia_port_destroy( wav_rec ); 
     241    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
     242    status = pjmedia_port_destroy( wav_out ); 
     243    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
     244 
     245    /* Destroy ec */ 
     246    pjmedia_echo_destroy(ec); 
    204247 
    205248    /* Release application pool */ 
Note: See TracChangeset for help on using the changeset viewer.