Changeset 822
- Timestamp:
- Nov 23, 2006 7:32:13 AM (18 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/include/pjmedia/echo.h
r690 r822 83 83 * @param samples_per_frame Number of samples per frame. 84 84 * @param tail_ms Tail length, miliseconds. 85 * @param latency_ms Total lacency introduced by playback and 86 * recording device. Set to zero if the latency 87 * is not known. 85 88 * @param options Options. If PJMEDIA_ECHO_SIMPLE is specified, 86 89 * then a simple echo suppressor implementation … … 96 99 unsigned samples_per_frame, 97 100 unsigned tail_ms, 101 unsigned latency_ms, 98 102 unsigned options, 99 103 pjmedia_echo_state **p_echo ); -
pjproject/trunk/pjmedia/include/pjmedia/echo_port.h
r690 r822 47 47 * @param dn_port Downstream port. 48 48 * @param tail_ms Tail length in miliseconds. 49 * @param latency_ms Total lacency introduced by playback and 50 * recording device. Set to zero if the latency 51 * is not known. 49 52 * @param options Options, as in #pjmedia_echo_create(). 50 53 * @param p_port Pointer to receive the port instance. … … 55 58 pjmedia_port *dn_port, 56 59 unsigned tail_ms, 60 unsigned latency_ms, 57 61 unsigned options, 58 62 pjmedia_port **p_port ); -
pjproject/trunk/pjmedia/src/pjmedia/echo_common.c
r655 r822 38 38 unsigned samples_per_frame, 39 39 unsigned tail_ms, 40 unsigned latency_ms, 40 41 unsigned options, 41 42 void **p_state ); … … 62 63 unsigned samples_per_frame, 63 64 unsigned tail_ms, 65 unsigned latency_ms, 64 66 unsigned options, 65 67 void **p_state ); … … 95 97 unsigned samples_per_frame, 96 98 unsigned tail_ms, 99 unsigned latency_ms, 97 100 unsigned options, 98 101 void **p_state ); … … 131 134 unsigned samples_per_frame, 132 135 unsigned tail_ms, 136 unsigned latency_ms, 133 137 unsigned options, 134 138 pjmedia_echo_state **p_echo ) … … 146 150 if (options & PJMEDIA_ECHO_SIMPLE) { 147 151 ec->op = &echo_supp_op; 148 status = (*echo_supp_op.ec_create)(pool, clock_rate, 149 samples_per_frame, 150 tail_ms, options, 152 status = (*echo_supp_op.ec_create)(pool, clock_rate, samples_per_frame, 153 tail_ms, latency_ms, options, 151 154 &ec->state); 152 155 } else { … … 154 157 status = (*aec_op.ec_create)(pool, clock_rate, 155 158 samples_per_frame, 156 tail_ms, options,159 tail_ms, latency_ms, options, 157 160 &ec->state); 158 161 } -
pjproject/trunk/pjmedia/src/pjmedia/echo_port.c
r653 r822 47 47 pjmedia_port *dn_port, 48 48 unsigned tail_ms, 49 unsigned latency_ms, 49 50 unsigned options, 50 51 pjmedia_port **p_port ) … … 69 70 status = pjmedia_echo_create(pool, dn_port->info.clock_rate, 70 71 dn_port->info.samples_per_frame, 71 tail_ms, options, &ec->ec);72 tail_ms, latency_ms, options, &ec->ec); 72 73 if (status != PJ_SUCCESS) 73 74 return status; -
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 -
pjproject/trunk/pjmedia/src/pjmedia/sound_port.c
r744 r822 493 493 status = pjmedia_echo_create(pool, snd_port->clock_rate, 494 494 snd_port->samples_per_frame, 495 tail_ms, options, &snd_port->ec_state); 495 tail_ms, delay_ms, 496 options, &snd_port->ec_state); 496 497 if (status != PJ_SUCCESS) 497 498 snd_port->ec_state = NULL; -
pjproject/trunk/pjsip-apps/src/samples/aectest.c
r815 r822 36 36 #define THIS_FILE "playfile.c" 37 37 #define PTIME 20 38 #define TAIL_LENGTH 800 38 39 39 40 static const char *desc = … … 175 176 176 177 /* Customize AEC */ 177 pjmedia_snd_port_set_ aec(snd, pool, 800);178 pjmedia_snd_port_set_ec(snd, pool, TAIL_LENGTH, 0); 178 179 179 180 /* Connect sound to the port */ -
pjproject/trunk/pjsip-apps/src/samples/debug.c
r693 r822 28 28 * #include "playfile.c" 29 29 */ 30 #include " tonegen.c"30 #include "aectest.c" -
pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
r813 r822 2216 2216 */ 2217 2217 #ifndef PJSUA_MAX_CONF_PORTS 2218 # define PJSUA_MAX_CONF_PORTS 2218 # define PJSUA_MAX_CONF_PORTS 254 2219 2219 #endif 2220 2220 2221 #define PJSUA_DEFAULT_CLOCK_RATE 16000 2222 #define PJSUA_DEFAULT_CODEC_QUALITY 5 2223 #define PJSUA_DEFAULT_ILBC_MODE 20 2224 #define PJSUA_DEFAULT_EC_TAIL_LEN 0 2221 #ifndef PJSUA_DEFAULT_CLOCK_RATE 2222 # define PJSUA_DEFAULT_CLOCK_RATE 16000 2223 #endif 2224 2225 #ifndef PJSUA_DEFAULT_CODEC_QUALITY 2226 # define PJSUA_DEFAULT_CODEC_QUALITY 5 2227 #endif 2228 2229 #ifndef PJSUA_DEFAULT_ILBC_MODE 2230 # define PJSUA_DEFAULT_ILBC_MODE 20 2231 #endif 2232 2233 2234 #ifndef PJSUA_DEFAULT_EC_TAIL_LEN 2235 # define PJSUA_DEFAULT_EC_TAIL_LEN 600 2236 #endif 2225 2237 2226 2238
Note: See TracChangeset
for help on using the changeset viewer.