Ignore:
Timestamp:
Jan 9, 2020 9:05:50 AM (4 years ago)
Author:
ming
Message:

Closed #589: Update Speex AEC to the latest version to get multichannel EC

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/echo_speex.c

    r4981 r6129  
    3636{ 
    3737    SpeexEchoState       *state; 
    38     SpeexPreprocessState *preprocess; 
     38    SpeexDecorrState     *decorr; 
     39    SpeexPreprocessState **preprocess; 
    3940 
    4041    unsigned              samples_per_frame; 
    41     unsigned              prefetch; 
     42    unsigned              channel_count; 
     43    unsigned              spf_per_channel; 
    4244    unsigned              options; 
    4345    pj_int16_t           *tmp_frame; 
     
    5860{ 
    5961    speex_ec *echo; 
    60     int sampling_rate; 
     62    int i, sampling_rate; 
    6163 
    6264    *p_echo = NULL; 
     
    6567    PJ_ASSERT_RETURN(echo != NULL, PJ_ENOMEM); 
    6668 
     69    echo->channel_count = channel_count; 
    6770    echo->samples_per_frame = samples_per_frame; 
     71    echo->spf_per_channel = samples_per_frame / channel_count; 
    6872    echo->options = options; 
    6973 
    70 #if 0 
    71     echo->state = speex_echo_state_init_mc(echo->samples_per_frame, 
     74#if 1 
     75    echo->state = speex_echo_state_init_mc(echo->spf_per_channel, 
    7276                                           clock_rate * tail_ms / 1000, 
    7377                                           channel_count, channel_count); 
     
    8084                                        clock_rate * tail_ms / 1000); 
    8185#endif 
    82     if (echo->state == NULL) { 
     86    if (echo->state == NULL) 
    8387        return PJ_ENOMEM; 
    84     } 
     88 
     89    echo->decorr = speex_decorrelate_new(clock_rate, channel_count, 
     90                                         echo->spf_per_channel); 
     91    if (echo->decorr == NULL) 
     92        return PJ_ENOMEM; 
    8593 
    8694    /* Set sampling rate */ 
     
    8997                   &sampling_rate); 
    9098 
    91     echo->preprocess = speex_preprocess_state_init(echo->samples_per_frame, 
    92                                                    clock_rate); 
    93     if (echo->preprocess == NULL) { 
    94         speex_echo_state_destroy(echo->state); 
     99    /* We need to create one state per channel processed. */ 
     100    echo->preprocess = PJ_POOL_ZALLOC_T(pool, SpeexPreprocessState *); 
     101    for (i = 0; i < channel_count; i++) { 
     102        spx_int32_t enabled; 
     103 
     104        echo->preprocess[i] = speex_preprocess_state_init( 
     105                                  echo->spf_per_channel, clock_rate); 
     106        if (echo->preprocess[i] == NULL) { 
     107            speex_aec_destroy(echo); 
     108            return PJ_ENOMEM; 
     109        } 
     110 
     111        /* Enable/disable AGC & denoise */ 
     112        enabled = PJMEDIA_SPEEX_AEC_USE_AGC; 
     113        speex_preprocess_ctl(echo->preprocess[i], SPEEX_PREPROCESS_SET_AGC, 
     114                             &enabled); 
     115 
     116        enabled = PJMEDIA_SPEEX_AEC_USE_DENOISE; 
     117        speex_preprocess_ctl(echo->preprocess[i], 
     118                             SPEEX_PREPROCESS_SET_DENOISE, &enabled); 
     119 
     120        /* Currently, VAD and dereverb are set at default setting. */ 
     121        /* 
     122        enabled = 1; 
     123        speex_preprocess_ctl(echo->preprocess[i], SPEEX_PREPROCESS_SET_VAD, 
     124                             &enabled); 
     125        speex_preprocess_ctl(echo->preprocess[i], 
     126                             SPEEX_PREPROCESS_SET_DEREVERB, 
     127                             &enabled); 
     128        */ 
     129 
     130        /* Control echo cancellation in the preprocessor */ 
     131        speex_preprocess_ctl(echo->preprocess[i], 
     132                             SPEEX_PREPROCESS_SET_ECHO_STATE, echo->state); 
     133    } 
     134 
     135    /* Create temporary frame for echo cancellation */ 
     136    echo->tmp_frame = (pj_int16_t*) pj_pool_zalloc(pool, sizeof(pj_int16_t) * 
     137                                                   channel_count * 
     138                                                   samples_per_frame); 
     139    if (!echo->tmp_frame) { 
     140        speex_aec_destroy(echo); 
    95141        return PJ_ENOMEM; 
    96142    } 
    97  
    98     /* Disable all preprocessing, we only want echo cancellation */ 
    99 #if 0 
    100     disabled = 0; 
    101     enabled = 1; 
    102     speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DENOISE,  
    103                          &enabled); 
    104     speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_AGC,  
    105                          &disabled); 
    106     speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_VAD,  
    107                          &disabled); 
    108     speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DEREVERB,  
    109                          &enabled); 
    110 #endif 
    111  
    112     /* Enable/disable AGC & denoise */ 
    113     { 
    114         spx_int32_t enabled; 
    115  
    116         enabled = PJMEDIA_SPEEX_AEC_USE_AGC; 
    117         speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_AGC,  
    118                              &enabled); 
    119  
    120         enabled = PJMEDIA_SPEEX_AEC_USE_DENOISE; 
    121         speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DENOISE,  
    122                              &enabled); 
    123     } 
    124  
    125     /* Control echo cancellation in the preprocessor */ 
    126    speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,  
    127                         echo->state); 
    128  
    129  
    130     /* Create temporary frame for echo cancellation */ 
    131     echo->tmp_frame = (pj_int16_t*) pj_pool_zalloc(pool, 2*samples_per_frame); 
    132     PJ_ASSERT_RETURN(echo->tmp_frame != NULL, PJ_ENOMEM); 
    133143 
    134144    /* Done */ 
     
    145155{ 
    146156    speex_ec *echo = (speex_ec*) state; 
     157    unsigned i; 
    147158 
    148159    PJ_ASSERT_RETURN(echo && echo->state, PJ_EINVAL); 
     
    153164    } 
    154165 
     166    if (echo->decorr) { 
     167        speex_decorrelate_destroy(echo->decorr); 
     168        echo->decorr = NULL; 
     169    } 
     170 
    155171    if (echo->preprocess) { 
    156         speex_preprocess_state_destroy(echo->preprocess); 
     172        for (i = 0; i < echo->channel_count; i++) { 
     173            if (echo->preprocess[i]) { 
     174                speex_preprocess_state_destroy(echo->preprocess[i]); 
     175                echo->preprocess[i] = NULL; 
     176            } 
     177        } 
    157178        echo->preprocess = NULL; 
    158179    } 
     
    182203{ 
    183204    speex_ec *echo = (speex_ec*) state; 
     205    unsigned i; 
    184206 
    185207    /* Sanity checks */ 
     
    193215 
    194216 
    195     /* Preprocess output */ 
    196     speex_preprocess_run(echo->preprocess, (spx_int16_t*)echo->tmp_frame); 
     217    /* Preprocess output per channel */ 
     218    for (i = 0; i < echo->channel_count; i++) { 
     219        spx_int16_t *buf = (spx_int16_t*)echo->tmp_frame; 
     220        unsigned j; 
     221 
     222        /* De-interleave each channel. */ 
     223        if (echo->channel_count > 1) { 
     224            for (j = 0; j < echo->spf_per_channel; j++) { 
     225                rec_frm[j] = echo->tmp_frame[j * echo->channel_count + i]; 
     226            } 
     227            buf = (spx_int16_t*)rec_frm; 
     228        } 
     229 
     230        speex_preprocess_run(echo->preprocess[i], buf); 
     231 
     232        if (echo->channel_count > 1) { 
     233            for (j = 0; j < echo->spf_per_channel; j++) { 
     234                echo->tmp_frame[j * echo->channel_count + i] = rec_frm[j]; 
     235            } 
     236        } 
     237    } 
    197238 
    198239    /* Copy temporary buffer back to original rec_frm */ 
     
    213254    /* Sanity checks */ 
    214255    PJ_ASSERT_RETURN(echo && play_frm, PJ_EINVAL); 
     256 
     257    /* Channel decorrelation algorithm is useful for multi-channel echo 
     258     * cancellation only . 
     259     */ 
     260    if (echo->channel_count > 1) { 
     261        pjmedia_copy_samples(echo->tmp_frame, play_frm, echo->samples_per_frame); 
     262        speex_decorrelate(echo->decorr, (spx_int16_t*)echo->tmp_frame, 
     263                          (spx_int16_t*)play_frm, 100); 
     264    } 
    215265 
    216266    speex_echo_playback(echo->state, (spx_int16_t*)play_frm); 
     
    228278{ 
    229279    speex_ec *echo = (speex_ec*) state; 
     280    unsigned i; 
    230281 
    231282    /* Sanity checks */ 
     
    235286 
    236287    /* Cancel echo */ 
    237     pjmedia_copy_samples(echo->tmp_frame, rec_frm, echo->samples_per_frame); 
    238288    speex_echo_capture(echo->state, 
    239                        (spx_int16_t*)echo->tmp_frame, 
    240                        (spx_int16_t*)rec_frm); 
    241  
    242     /* Apply preprocessing */ 
    243     speex_preprocess_run(echo->preprocess, (spx_int16_t*)rec_frm); 
     289                       (spx_int16_t*)rec_frm, 
     290                       (spx_int16_t*)echo->tmp_frame); 
     291 
     292    /* Apply preprocessing per channel. */ 
     293    for (i = 0; i < echo->channel_count; i++) { 
     294        spx_int16_t *buf = (spx_int16_t*)echo->tmp_frame; 
     295        unsigned j; 
     296 
     297        /* De-interleave each channel. */ 
     298        if (echo->channel_count > 1) { 
     299            for (j = 0; j < echo->spf_per_channel; j++) { 
     300                rec_frm[j] = echo->tmp_frame[j * echo->channel_count + i]; 
     301            } 
     302            buf = (spx_int16_t*)rec_frm; 
     303        } 
     304 
     305        speex_preprocess_run(echo->preprocess[i], buf); 
     306 
     307        if (echo->channel_count > 1) { 
     308            for (j = 0; j < echo->spf_per_channel; j++) { 
     309                echo->tmp_frame[j * echo->channel_count + i] = rec_frm[j]; 
     310            } 
     311        } 
     312    } 
     313 
     314    pjmedia_copy_samples(rec_frm, echo->tmp_frame, echo->samples_per_frame); 
    244315 
    245316    return PJ_SUCCESS; 
Note: See TracChangeset for help on using the changeset viewer.