Changeset 653 for pjproject/trunk/pjmedia/src/pjmedia/echo_speex.c
- Timestamp:
- Aug 6, 2006 12:07:13 PM (18 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/echo_speex.c
r652 r653 18 18 */ 19 19 20 #include <pjmedia/ aec.h>20 #include <pjmedia/echo.h> 21 21 #include <pjmedia/errno.h> 22 22 #include <pjmedia/silencedet.h> … … 30 30 31 31 32 #define THIS_FILE " aec_speex.c"32 #define THIS_FILE "echo_speex.c" 33 33 #define BUF_COUNT 8 34 35 /* 36 * Prototypes 37 */ 38 PJ_DECL(pj_status_t) speex_aec_create(pj_pool_t *pool, 39 unsigned clock_rate, 40 unsigned samples_per_frame, 41 unsigned tail_ms, 42 unsigned options, 43 void **p_state ); 44 PJ_DECL(pj_status_t) speex_aec_destroy(void *state ); 45 PJ_DECL(pj_status_t) speex_aec_playback(void *state, 46 pj_int16_t *play_frm ); 47 PJ_DECL(pj_status_t) speex_aec_capture(void *state, 48 pj_int16_t *rec_frm, 49 unsigned options ); 50 PJ_DECL(pj_status_t) speex_aec_cancel_echo(void *state, 51 pj_int16_t *rec_frm, 52 const pj_int16_t *play_frm, 53 unsigned options, 54 void *reserved ); 34 55 35 56 … … 39 60 }; 40 61 41 struct pjmedia_aec62 typedef struct speex_ec 42 63 { 43 64 SpeexEchoState *state; … … 54 75 unsigned wpos; /* Index to put newest frame. */ 55 76 struct frame frames[BUF_COUNT]; /* Playback frame buffers. */ 56 } ;77 } speex_ec; 57 78 58 79 … … 61 82 * Create the AEC. 62 83 */ 63 PJ_DEF(pj_status_t) pjmedia_aec_create(pj_pool_t *pool,64 65 66 67 68 pjmedia_aec **p_aec)69 { 70 pjmedia_aec *aec;84 PJ_DEF(pj_status_t) speex_aec_create(pj_pool_t *pool, 85 unsigned clock_rate, 86 unsigned samples_per_frame, 87 unsigned tail_ms, 88 unsigned options, 89 void **p_echo ) 90 { 91 speex_ec *echo; 71 92 int sampling_rate; 72 93 unsigned i; 94 int disabled; 73 95 pj_status_t status; 74 96 75 *p_aec = NULL; 76 77 aec = pj_pool_zalloc(pool, sizeof(pjmedia_aec)); 78 PJ_ASSERT_RETURN(aec != NULL, PJ_ENOMEM); 79 80 status = pj_lock_create_simple_mutex(pool, "aec%p", &aec->lock); 81 if (status != PJ_SUCCESS) 82 return status; 83 84 aec->samples_per_frame = samples_per_frame; 85 aec->options = options; 86 87 aec->state = speex_echo_state_init(samples_per_frame, 97 *p_echo = NULL; 98 99 echo = pj_pool_zalloc(pool, sizeof(speex_ec)); 100 PJ_ASSERT_RETURN(echo != NULL, PJ_ENOMEM); 101 102 if (options & PJMEDIA_ECHO_NO_LOCK) { 103 status = pj_lock_create_null_mutex(pool, "aec%p", &echo->lock); 104 if (status != PJ_SUCCESS) 105 return status; 106 } else { 107 status = pj_lock_create_simple_mutex(pool, "aec%p", &echo->lock); 108 if (status != PJ_SUCCESS) 109 return status; 110 } 111 112 echo->samples_per_frame = samples_per_frame; 113 echo->options = options; 114 115 echo->state = speex_echo_state_init(samples_per_frame, 88 116 clock_rate * tail_ms / 1000); 89 if ( aec->state == NULL) {90 pj_lock_destroy( aec->lock);117 if (echo->state == NULL) { 118 pj_lock_destroy(echo->lock); 91 119 return PJ_ENOMEM; 92 120 } 93 121 94 aec->preprocess = speex_preprocess_state_init(samples_per_frame,95 clock_rate);96 if ( aec->preprocess == NULL) {97 speex_echo_state_destroy( aec->state);98 pj_lock_destroy( aec->lock);122 echo->preprocess = speex_preprocess_state_init(samples_per_frame, 123 clock_rate); 124 if (echo->preprocess == NULL) { 125 speex_echo_state_destroy(echo->state); 126 pj_lock_destroy(echo->lock); 99 127 return PJ_ENOMEM; 100 128 } 129 130 /* Disable all preprocessing, we only want echo cancellation */ 131 disabled = 0; 132 speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DENOISE, 133 &disabled); 134 speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_AGC, 135 &disabled); 136 speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_VAD, 137 &disabled); 138 speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DEREVERB, 139 &disabled); 101 140 102 141 /* Set sampling rate */ 103 142 sampling_rate = clock_rate; 104 speex_echo_ctl( aec->state, SPEEX_ECHO_SET_SAMPLING_RATE,143 speex_echo_ctl(echo->state, SPEEX_ECHO_SET_SAMPLING_RATE, 105 144 &sampling_rate); 106 145 107 146 /* Create temporary frame for echo cancellation */ 108 aec->tmp_frame = pj_pool_zalloc(pool, 2 * samples_per_frame);109 PJ_ASSERT_RETURN( aec->tmp_frame != NULL, PJ_ENOMEM);147 echo->tmp_frame = pj_pool_zalloc(pool, 2 * samples_per_frame); 148 PJ_ASSERT_RETURN(echo->tmp_frame != NULL, PJ_ENOMEM); 110 149 111 150 /* Create temporary frame to receive residue */ 112 aec->residue = pj_pool_zalloc(pool, sizeof(spx_int32_t) *151 echo->residue = pj_pool_zalloc(pool, sizeof(spx_int32_t) * 113 152 samples_per_frame); 114 PJ_ASSERT_RETURN( aec->residue != NULL, PJ_ENOMEM);153 PJ_ASSERT_RETURN(echo->residue != NULL, PJ_ENOMEM); 115 154 116 155 /* Create internal playback buffers */ 117 156 for (i=0; i<BUF_COUNT; ++i) { 118 aec->frames[i].buf = pj_pool_zalloc(pool, samples_per_frame * 2);119 PJ_ASSERT_RETURN( aec->frames[i].buf != NULL, PJ_ENOMEM);157 echo->frames[i].buf = pj_pool_zalloc(pool, samples_per_frame * 2); 158 PJ_ASSERT_RETURN(echo->frames[i].buf != NULL, PJ_ENOMEM); 120 159 } 121 160 122 161 123 162 /* Done */ 124 *p_ aec = aec;125 126 PJ_LOG(4,(THIS_FILE, " Echo canceller/AEC created, clock_rate=%d, "163 *p_echo = echo; 164 165 PJ_LOG(4,(THIS_FILE, "Speex Echo canceller/AEC created, clock_rate=%d, " 127 166 "samples per frame=%d, tail length=%d ms", 128 167 clock_rate, … … 137 176 * Destroy AEC 138 177 */ 139 PJ_DEF(pj_status_t) pjmedia_aec_destroy(pjmedia_aec *aec ) 140 { 141 PJ_ASSERT_RETURN(aec && aec->state, PJ_EINVAL); 142 143 if (aec->lock) 144 pj_lock_acquire(aec->lock); 145 146 if (aec->state) { 147 speex_echo_state_destroy(aec->state); 148 aec->state = NULL; 149 } 150 151 if (aec->preprocess) { 152 speex_preprocess_state_destroy(aec->preprocess); 153 aec->preprocess = NULL; 154 } 155 156 if (aec->lock) { 157 pj_lock_destroy(aec->lock); 158 aec->lock = NULL; 178 PJ_DEF(pj_status_t) speex_aec_destroy(void *state ) 179 { 180 speex_ec *echo = state; 181 182 PJ_ASSERT_RETURN(echo && echo->state, PJ_EINVAL); 183 184 if (echo->lock) 185 pj_lock_acquire(echo->lock); 186 187 if (echo->state) { 188 speex_echo_state_destroy(echo->state); 189 echo->state = NULL; 190 } 191 192 if (echo->preprocess) { 193 speex_preprocess_state_destroy(echo->preprocess); 194 echo->preprocess = NULL; 195 } 196 197 if (echo->lock) { 198 pj_lock_destroy(echo->lock); 199 echo->lock = NULL; 159 200 } 160 201 … … 166 207 * Let the AEC knows that a frame has been played to the speaker. 167 208 */ 168 PJ_DEF(pj_status_t) pjmedia_aec_playback(pjmedia_aec *aec, 169 pj_int16_t *play_frm ) 170 { 209 PJ_DEF(pj_status_t) speex_aec_playback(void *state, 210 pj_int16_t *play_frm ) 211 { 212 speex_ec *echo = state; 213 171 214 /* Sanity checks */ 172 PJ_ASSERT_RETURN( aec&& play_frm, PJ_EINVAL);215 PJ_ASSERT_RETURN(echo && play_frm, PJ_EINVAL); 173 216 174 217 /* The AEC must be configured to support internal playback buffer */ 175 PJ_ASSERT_RETURN( aec->frames[0].buf != NULL, PJ_EINVALIDOP);176 177 pj_lock_acquire( aec->lock);218 PJ_ASSERT_RETURN(echo->frames[0].buf != NULL, PJ_EINVALIDOP); 219 220 pj_lock_acquire(echo->lock); 178 221 179 222 /* Check for overflows */ 180 if ( aec->wpos == aec->rpos) {181 PJ_LOG(5,(THIS_FILE, " AEC overflow (playback runs faster, "223 if (echo->wpos == echo->rpos) { 224 PJ_LOG(5,(THIS_FILE, "Speex AEC overflow (playback runs faster, " 182 225 "wpos=%d, rpos=%d)", 183 aec->wpos, aec->rpos));184 aec->rpos = (aec->wpos - BUF_COUNT/2) % BUF_COUNT;185 speex_echo_state_reset( aec->state);226 echo->wpos, echo->rpos)); 227 echo->rpos = (echo->wpos - BUF_COUNT/2) % BUF_COUNT; 228 speex_echo_state_reset(echo->state); 186 229 } 187 230 188 231 /* Save fhe frame */ 189 pjmedia_copy_samples( aec->frames[aec->wpos].buf,190 play_frm, aec->samples_per_frame);191 aec->wpos = (aec->wpos+1) % BUF_COUNT;192 193 pj_lock_release( aec->lock);232 pjmedia_copy_samples(echo->frames[echo->wpos].buf, 233 play_frm, echo->samples_per_frame); 234 echo->wpos = (echo->wpos+1) % BUF_COUNT; 235 236 pj_lock_release(echo->lock); 194 237 195 238 return PJ_SUCCESS; … … 200 243 * Let the AEC knows that a frame has been captured from the microphone. 201 244 */ 202 PJ_DEF(pj_status_t) pjmedia_aec_capture( pjmedia_aec *aec, 203 pj_int16_t *rec_frm, 204 unsigned options ) 205 { 245 PJ_DEF(pj_status_t) speex_aec_capture( void *state, 246 pj_int16_t *rec_frm, 247 unsigned options ) 248 { 249 speex_ec *echo = state; 206 250 pj_status_t status; 207 251 208 252 /* Sanity checks */ 209 PJ_ASSERT_RETURN( aec&& rec_frm, PJ_EINVAL);253 PJ_ASSERT_RETURN(echo && rec_frm, PJ_EINVAL); 210 254 211 255 /* The AEC must be configured to support internal playback buffer */ 212 PJ_ASSERT_RETURN( aec->frames[0].buf != NULL, PJ_EINVALIDOP);256 PJ_ASSERT_RETURN(echo->frames[0].buf != NULL, PJ_EINVALIDOP); 213 257 214 258 /* Lock mutex */ 215 pj_lock_acquire( aec->lock);259 pj_lock_acquire(echo->lock); 216 260 217 261 218 262 /* Check for underflow */ 219 if ( aec->rpos == aec->wpos) {263 if (echo->rpos == echo->wpos) { 220 264 /* Return frame as it is */ 221 pj_lock_release( aec->lock);222 223 PJ_LOG(5,(THIS_FILE, " AEC underflow (capture runs faster than "265 pj_lock_release(echo->lock); 266 267 PJ_LOG(5,(THIS_FILE, "Speex AEC underflow (capture runs faster than " 224 268 "playback, wpos=%d, rpos=%d)", 225 aec->wpos, aec->rpos));226 aec->rpos = (aec->wpos - BUF_COUNT/2) % BUF_COUNT;227 speex_echo_state_reset( aec->state);269 echo->wpos, echo->rpos)); 270 echo->rpos = (echo->wpos - BUF_COUNT/2) % BUF_COUNT; 271 speex_echo_state_reset(echo->state); 228 272 229 273 return PJ_SUCCESS; … … 232 276 233 277 /* Cancel echo */ 234 status = pjmedia_aec_cancel_echo(aec, rec_frm,235 aec->frames[aec->rpos].buf, options,236 237 238 aec->rpos = (aec->rpos + 1) % BUF_COUNT;239 240 pj_lock_release( aec->lock);278 status = speex_aec_cancel_echo(echo, rec_frm, 279 echo->frames[echo->rpos].buf, options, 280 NULL); 281 282 echo->rpos = (echo->rpos + 1) % BUF_COUNT; 283 284 pj_lock_release(echo->lock); 241 285 return status; 242 286 } … … 246 290 * Perform echo cancellation. 247 291 */ 248 PJ_DEF(pj_status_t) pjmedia_aec_cancel_echo( pjmedia_aec *aec, 249 pj_int16_t *rec_frm, 250 const pj_int16_t *play_frm, 251 unsigned options, 252 void *reserved ) 253 { 292 PJ_DEF(pj_status_t) speex_aec_cancel_echo( void *state, 293 pj_int16_t *rec_frm, 294 const pj_int16_t *play_frm, 295 unsigned options, 296 void *reserved ) 297 { 298 speex_ec *echo = state; 299 254 300 /* Sanity checks */ 255 PJ_ASSERT_RETURN( aec&& rec_frm && play_frm && options==0 &&301 PJ_ASSERT_RETURN(echo && rec_frm && play_frm && options==0 && 256 302 reserved==NULL, PJ_EINVAL); 257 303 258 304 /* Cancel echo, put output in temporary buffer */ 259 speex_echo_cancel( aec->state, (const spx_int16_t*)rec_frm,305 speex_echo_cancel(echo->state, (const spx_int16_t*)rec_frm, 260 306 (const spx_int16_t*)play_frm, 261 (spx_int16_t*) aec->tmp_frame,262 aec->residue);307 (spx_int16_t*)echo->tmp_frame, 308 echo->residue); 263 309 264 310 265 311 /* Preprocess output */ 266 speex_preprocess( aec->preprocess, (spx_int16_t*)aec->tmp_frame,267 aec->residue);312 speex_preprocess(echo->preprocess, (spx_int16_t*)echo->tmp_frame, 313 echo->residue); 268 314 269 315 /* Copy temporary buffer back to original rec_frm */ 270 pjmedia_copy_samples(rec_frm, aec->tmp_frame, aec->samples_per_frame);316 pjmedia_copy_samples(rec_frm, echo->tmp_frame, echo->samples_per_frame); 271 317 272 318 return PJ_SUCCESS;
Note: See TracChangeset
for help on using the changeset viewer.