Changeset 822 for pjproject/trunk/pjmedia/src/pjmedia/echo_speex.c
- Timestamp:
- Nov 23, 2006 7:32:13 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/echo_speex.c
r653 r822 30 30 31 31 32 #define THIS_FILE "echo_speex.c" 33 #define BUF_COUNT 8 32 #define THIS_FILE "echo_speex.c" 33 #define BUF_COUNT 20 34 #define MIN_PREFETCH 4 35 #define MAX_PREFETCH 12 36 37 38 39 #if 0 40 # define TRACE_(expr) PJ_LOG(5,expr) 41 #else 42 # define TRACE_(expr) 43 #endif 44 45 46 typedef struct pjmedia_frame_queue pjmedia_frame_queue; 47 48 struct fq_frame 49 { 50 PJ_DECL_LIST_MEMBER(struct fq_frame); 51 void *buf; 52 unsigned size; 53 pj_uint32_t seq; 54 }; 55 56 struct pjmedia_frame_queue 57 { 58 char obj_name[PJ_MAX_OBJ_NAME]; 59 unsigned frame_size; 60 int samples_per_frame; 61 unsigned count; 62 unsigned max_count; 63 struct fq_frame frame_list; 64 struct fq_frame free_list; 65 66 int seq_delay; 67 int prefetch_count; 68 }; 69 70 PJ_DEF(pj_status_t) pjmedia_frame_queue_create( pj_pool_t *pool, 71 const char *name, 72 unsigned frame_size, 73 unsigned samples_per_frame, 74 unsigned max_count, 75 pjmedia_frame_queue **p_fq) 76 { 77 pjmedia_frame_queue *fq; 78 unsigned i; 79 80 fq = pj_pool_zalloc(pool, sizeof(pjmedia_frame_queue)); 81 82 pj_ansi_snprintf(fq->obj_name, sizeof(fq->obj_name), name, fq); 83 fq->obj_name[sizeof(fq->obj_name)-1] = '\0'; 84 85 fq->max_count = max_count; 86 fq->frame_size = frame_size; 87 fq->samples_per_frame = samples_per_frame; 88 fq->count = 0; 89 90 pj_list_init(&fq->frame_list); 91 pj_list_init(&fq->free_list); 92 93 for (i=0; i<max_count; ++i) { 94 struct fq_frame *f; 95 96 f = pj_pool_zalloc(pool, sizeof(struct fq_frame)); 97 f->buf = pj_pool_alloc(pool, frame_size); 98 99 pj_list_push_back(&fq->free_list, f); 100 101 } 102 103 *p_fq = fq; 104 return PJ_SUCCESS; 105 } 106 107 PJ_DEF(pj_status_t) pjmedia_frame_queue_init( pjmedia_frame_queue *fq, 108 int seq_delay, 109 int prefetch_count) 110 { 111 if (prefetch_count > MAX_PREFETCH) 112 prefetch_count = MAX_PREFETCH; 113 114 fq->seq_delay = seq_delay; 115 fq->prefetch_count = prefetch_count; 116 fq->count = 0; 117 pj_list_merge_first(&fq->free_list, &fq->frame_list); 118 119 PJ_LOG(5,(fq->obj_name, "AEC reset, delay=%d, prefetch=%d", 120 fq->seq_delay, fq->prefetch_count)); 121 122 return PJ_SUCCESS; 123 } 124 125 PJ_DEF(pj_bool_t) pjmedia_frame_queue_empty( pjmedia_frame_queue *fq ) 126 { 127 return pj_list_empty(&fq->frame_list); 128 } 129 130 PJ_DEF(int) pjmedia_frame_queue_get_prefetch( pjmedia_frame_queue *fq ) 131 { 132 return fq->prefetch_count; 133 } 134 135 PJ_DEF(pj_status_t) pjmedia_frame_queue_put( pjmedia_frame_queue *fq, 136 const void *framebuf, 137 unsigned size, 138 pj_uint32_t timestamp ) 139 { 140 struct fq_frame *f; 141 142 TRACE_((fq->obj_name, "PUT seq=%d, count=%d", 143 timestamp / fq->samples_per_frame, fq->count)); 144 145 if (pj_list_empty(&fq->free_list)) { 146 PJ_LOG(5,(fq->obj_name, 147 " AEC info: queue is full, frame discarded " 148 "[count=%d, seq=%d]", 149 fq->max_count, timestamp / fq->samples_per_frame)); 150 return PJ_ETOOMANY; 151 } 152 153 PJ_ASSERT_RETURN(size <= fq->frame_size, PJ_ETOOBIG); 154 155 f = fq->free_list.next; 156 pj_list_erase(f); 157 158 pj_memcpy(f->buf, framebuf, size); 159 f->size = size; 160 f->seq = timestamp / fq->samples_per_frame; 161 162 pj_list_push_back(&fq->frame_list, f); 163 ++fq->count; 164 165 return PJ_SUCCESS; 166 } 167 168 PJ_DEF(pj_status_t) pjmedia_frame_queue_get( pjmedia_frame_queue *fq, 169 pj_uint32_t get_timestamp, 170 void **framebuf, 171 unsigned *size ) 172 { 173 pj_uint32_t frame_seq; 174 struct fq_frame *f; 175 176 frame_seq = get_timestamp/fq->samples_per_frame + fq->seq_delay - 177 fq->prefetch_count; 178 179 TRACE_((fq->obj_name, "GET seq=%d for seq=%d delay=%d, prefetch=%d", 180 get_timestamp/fq->samples_per_frame, frame_seq, fq->seq_delay, 181 fq->prefetch_count)); 182 183 *size = 0; 184 185 /* Remove old frames */ 186 for (;!pj_list_empty(&fq->frame_list);) { 187 f = fq->frame_list.next; 188 if (f->seq >= frame_seq) 189 break; 190 191 PJ_LOG(5,(fq->obj_name, 192 " AEC Info: old frame removed (seq=%d, want=%d, count=%d)", 193 f->seq, frame_seq, fq->count)); 194 pj_list_erase(f); 195 --fq->count; 196 pj_list_push_back(&fq->free_list, f); 197 } 198 199 if (pj_list_empty(&fq->frame_list)) { 200 PJ_LOG(5,(fq->obj_name, 201 " AEC Info: empty queue for seq=%d!", 202 frame_seq)); 203 return PJ_ENOTFOUND; 204 } 205 206 f = fq->frame_list.next; 207 208 if (f->seq > frame_seq) { 209 PJ_LOG(5,(fq->obj_name, 210 " AEC Info: prefetching (first seq=%d)", 211 f->seq)); 212 return -1; 213 } 214 215 pj_list_erase(f); 216 --fq->count; 217 218 *framebuf = (void*)f->buf; 219 *size = f->size; 220 221 TRACE_((fq->obj_name, " returning frame with seq=%d, count=%d", 222 f->seq, fq->count)); 223 224 pj_list_push_front(&fq->free_list, f); 225 return PJ_SUCCESS; 226 } 34 227 35 228 /* … … 40 233 unsigned samples_per_frame, 41 234 unsigned tail_ms, 235 unsigned latency_ms, 42 236 unsigned options, 43 237 void **p_state ); … … 55 249 56 250 57 struct frame 58 { 59 pj_int16_t *buf; 251 enum 252 { 253 TS_FLAG_PLAY = 1, 254 TS_FLAG_REC = 2, 255 TS_FLAG_OK = 3, 60 256 }; 61 257 … … 65 261 SpeexPreprocessState *preprocess; 66 262 67 unsigned samples_per_frame; 68 unsigned options; 69 pj_int16_t *tmp_frame; 70 spx_int32_t *residue; 71 72 pj_lock_t *lock; /* To protect buffers, if required */ 73 74 unsigned rpos; /* Index to get oldest frame. */ 75 unsigned wpos; /* Index to put newest frame. */ 76 struct frame frames[BUF_COUNT]; /* Playback frame buffers. */ 263 unsigned samples_per_frame; 264 unsigned prefetch; 265 unsigned options; 266 pj_int16_t *tmp_frame; 267 spx_int32_t *residue; 268 269 pj_uint32_t play_ts, 270 rec_ts, 271 ts_flag; 272 273 pjmedia_frame_queue *frame_queue; 274 pj_lock_t *lock; /* To protect buffers, if required */ 77 275 } speex_ec; 78 276 … … 86 284 unsigned samples_per_frame, 87 285 unsigned tail_ms, 286 unsigned latency_ms, 88 287 unsigned options, 89 288 void **p_echo ) … … 91 290 speex_ec *echo; 92 291 int sampling_rate; 93 unsigned i; 94 int disabled; 292 int disabled, enabled; 95 293 pj_status_t status; 96 294 … … 111 309 112 310 echo->samples_per_frame = samples_per_frame; 311 echo->prefetch = (latency_ms * clock_rate / 1000) / samples_per_frame; 312 if (echo->prefetch < MIN_PREFETCH) 313 echo->prefetch = MIN_PREFETCH; 314 if (echo->prefetch > MAX_PREFETCH) 315 echo->prefetch = MAX_PREFETCH; 113 316 echo->options = options; 114 317 … … 130 333 /* Disable all preprocessing, we only want echo cancellation */ 131 334 disabled = 0; 335 enabled = 1; 132 336 speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_DENOISE, 133 & disabled);337 &enabled); 134 338 speex_preprocess_ctl(echo->preprocess, SPEEX_PREPROCESS_SET_AGC, 135 339 &disabled); … … 150 354 /* Create temporary frame to receive residue */ 151 355 echo->residue = pj_pool_zalloc(pool, sizeof(spx_int32_t) * 152 samples_per_frame);356 (samples_per_frame+1)); 153 357 PJ_ASSERT_RETURN(echo->residue != NULL, PJ_ENOMEM); 154 358 155 /* Create internal playback buffers */ 156 for (i=0; i<BUF_COUNT; ++i) { 157 echo->frames[i].buf = pj_pool_zalloc(pool, samples_per_frame * 2); 158 PJ_ASSERT_RETURN(echo->frames[i].buf != NULL, PJ_ENOMEM); 159 } 160 359 /* Create frame queue */ 360 status = pjmedia_frame_queue_create(pool, "aec%p", samples_per_frame*2, 361 samples_per_frame, BUF_COUNT, 362 &echo->frame_queue); 363 if (status != PJ_SUCCESS) { 364 speex_preprocess_state_destroy(echo->preprocess); 365 speex_echo_state_destroy(echo->state); 366 pj_lock_destroy(echo->lock); 367 return status; 368 } 161 369 162 370 /* Done */ … … 164 372 165 373 PJ_LOG(4,(THIS_FILE, "Speex Echo canceller/AEC created, clock_rate=%d, " 166 "samples per frame=%d, tail length=%d ms", 167 clock_rate, 168 samples_per_frame, 169 tail_ms)); 374 "samples per frame=%d, tail length=%d ms, " 375 "latency=%d ms", 376 clock_rate, samples_per_frame, tail_ms, latency_ms)); 170 377 return PJ_SUCCESS; 171 378 … … 216 423 217 424 /* The AEC must be configured to support internal playback buffer */ 218 PJ_ASSERT_RETURN(echo->frame s[0].buf!= NULL, PJ_EINVALIDOP);425 PJ_ASSERT_RETURN(echo->frame_queue!= NULL, PJ_EINVALIDOP); 219 426 220 427 pj_lock_acquire(echo->lock); 221 428 222 /* Check for overflows */ 223 if (echo->wpos == echo->rpos) { 224 PJ_LOG(5,(THIS_FILE, "Speex AEC overflow (playback runs faster, " 225 "wpos=%d, rpos=%d)", 226 echo->wpos, echo->rpos)); 227 echo->rpos = (echo->wpos - BUF_COUNT/2) % BUF_COUNT; 228 speex_echo_state_reset(echo->state); 229 } 230 231 /* Save fhe frame */ 232 pjmedia_copy_samples(echo->frames[echo->wpos].buf, 233 play_frm, echo->samples_per_frame); 234 echo->wpos = (echo->wpos+1) % BUF_COUNT; 429 /* Inc timestamp */ 430 echo->play_ts += echo->samples_per_frame; 431 432 /* Initialize frame delay. */ 433 if ((echo->ts_flag & TS_FLAG_PLAY) == 0) { 434 echo->ts_flag |= TS_FLAG_PLAY; 435 436 if (echo->ts_flag == TS_FLAG_OK) { 437 int seq_delay; 438 439 seq_delay = ((int)echo->play_ts - (int)echo->rec_ts) / 440 (int)echo->samples_per_frame; 441 pjmedia_frame_queue_init(echo->frame_queue, seq_delay, 442 echo->prefetch); 443 } 444 } 445 446 pjmedia_frame_queue_put(echo->frame_queue, play_frm, 447 echo->samples_per_frame*2, echo->play_ts); 235 448 236 449 pj_lock_release(echo->lock); … … 248 461 { 249 462 speex_ec *echo = state; 250 pj_status_t status ;463 pj_status_t status = PJ_SUCCESS; 251 464 252 465 /* Sanity checks */ … … 254 467 255 468 /* The AEC must be configured to support internal playback buffer */ 256 PJ_ASSERT_RETURN(echo->frame s[0].buf!= NULL, PJ_EINVALIDOP);469 PJ_ASSERT_RETURN(echo->frame_queue!= NULL, PJ_EINVALIDOP); 257 470 258 471 /* Lock mutex */ 259 472 pj_lock_acquire(echo->lock); 260 473 261 262 /* Check for underflow */ 263 if (echo->rpos == echo->wpos) { 264 /* Return frame as it is */ 265 pj_lock_release(echo->lock); 266 267 PJ_LOG(5,(THIS_FILE, "Speex AEC underflow (capture runs faster than " 268 "playback, wpos=%d, rpos=%d)", 269 echo->wpos, echo->rpos)); 270 echo->rpos = (echo->wpos - BUF_COUNT/2) % BUF_COUNT; 271 speex_echo_state_reset(echo->state); 272 273 return PJ_SUCCESS; 274 } 275 474 /* Inc timestamp */ 475 echo->rec_ts += echo->samples_per_frame; 476 477 /* Init frame delay. */ 478 if ((echo->ts_flag & TS_FLAG_REC) == 0) { 479 echo->ts_flag |= TS_FLAG_REC; 480 481 if (echo->ts_flag == TS_FLAG_OK) { 482 int seq_delay; 483 484 seq_delay = ((int)echo->play_ts - (int)echo->rec_ts) / 485 (int)echo->samples_per_frame; 486 pjmedia_frame_queue_init(echo->frame_queue, seq_delay, 487 echo->prefetch); 488 } 489 } 276 490 277 491 /* Cancel echo */ 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; 492 if (echo->ts_flag == TS_FLAG_OK) { 493 void *play_buf; 494 unsigned size = 0; 495 496 if (pjmedia_frame_queue_empty(echo->frame_queue)) { 497 int seq_delay, prefetch; 498 499 seq_delay = ((int)echo->play_ts - (int)echo->rec_ts) / 500 (int)echo->samples_per_frame; 501 prefetch = pjmedia_frame_queue_get_prefetch(echo->frame_queue); 502 //++prefetch; 503 pjmedia_frame_queue_init(echo->frame_queue, seq_delay, prefetch); 504 status = -1; 505 506 } else { 507 status = pjmedia_frame_queue_get(echo->frame_queue, echo->rec_ts, 508 &play_buf, &size); 509 if (size != 0) { 510 speex_aec_cancel_echo(echo, rec_frm, (pj_int16_t*)play_buf, 511 options, NULL); 512 } 513 } 514 515 if (status != PJ_SUCCESS) 516 speex_echo_state_reset(echo->state); 517 } 283 518 284 519 pj_lock_release(echo->lock); 285 return status;520 return PJ_SUCCESS; 286 521 } 287 522 … … 320 555 } 321 556 557
Note: See TracChangeset
for help on using the changeset viewer.