Changeset 1833 for pjproject/trunk/pjmedia/src/pjmedia/delaybuf.c
- Timestamp:
- Feb 29, 2008 5:19:42 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/delaybuf.c
r1716 r1833 20 20 #include <pjmedia/delaybuf.h> 21 21 #include <pjmedia/errno.h> 22 #include <pjmedia/wsola.h> 22 23 #include <pj/assert.h> 24 #include <pj/lock.h> 23 25 #include <pj/log.h> 24 26 #include <pj/pool.h> 25 27 28 29 #if 0 30 # define TRACE__(x) PJ_LOG(3,x) 31 #else 32 # define TRACE__(x) 33 #endif 34 35 36 /* Type of states of delay buffer */ 26 37 enum state 27 38 { … … 31 42 }; 32 43 44 /* Type of operation of delay buffer */ 33 45 enum OP 34 46 { … … 38 50 }; 39 51 40 /* The following macros represent cycles of test. */ 41 /* Since there are two operations performed (get & put), */ 42 /* these macros value must be minimum 2 and should be even number */ 52 /* The following macros represent cycles of test. Since there are two 53 * operations performed (get & put), these macros minimum value must be 2 54 * and should be even number. 55 */ 43 56 #define WAITING_COUNT 4 44 57 #define LEARN_COUNT 16 45 58 46 /* Number of buffers to add to learnt level for additional stability */ 59 /* Number of buffers to add to learnt level for additional stability 60 * Please note that wsola_discard() needs minimum 3 frames, so max buffer 61 * count should be minimally 3, setting SAFE_MARGIN to 2 will guarantees 62 * this. 63 */ 47 64 #define SAFE_MARGIN 2 48 65 … … 67 84 struct pjmedia_delay_buf 68 85 { 69 char obj_name[PJ_MAX_OBJ_NAME]; 70 71 pj_int16_t *frame_buf; 72 unsigned put_pos; 73 unsigned get_pos; 74 unsigned buf_cnt; 75 76 unsigned samples_per_frame; 77 unsigned max_cnt; 78 enum state state; 86 char obj_name[PJ_MAX_OBJ_NAME]; 87 88 pj_lock_t *lock; /**< Lock object. */ 89 90 pj_int16_t *frame_buf; 91 enum state state; /**< State of delay buffer */ 92 unsigned samples_per_frame; /**< Number of samples in one frame */ 93 unsigned max_frames; /**< Buffer allocated, in frames */ 94 95 unsigned put_pos; /**< Position for put op, in samples */ 96 unsigned get_pos; /**< Position for get op, in samples */ 97 unsigned buf_cnt; /**< Number of buffered samples */ 98 unsigned max_cnt; /**< Max number of buffered samples */ 79 99 80 100 struct { 81 unsigned level;101 unsigned level; /**< Burst level storage on learning */ 82 102 } op[2]; 83 84 enum OP last_op; 85 unsigned max_level; 86 unsigned state_count; 103 enum OP last_op; /**< Last op (GET or PUT) of learning*/ 104 unsigned state_count; /**< Counter of op cycles of learning*/ 105 106 unsigned max_level; /**< Learning result: burst level */ 107 108 pjmedia_wsola *wsola; /**< Drift handler */ 87 109 }; 88 110 89 111 PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, 90 112 const char *name, 113 unsigned clock_rate, 91 114 unsigned samples_per_frame, 92 unsigned max_ cnt,115 unsigned max_frames, 93 116 int delay, 117 unsigned options, 94 118 pjmedia_delay_buf **p_b) 95 119 { 96 120 pjmedia_delay_buf *b; 97 98 PJ_ASSERT_RETURN(pool && samples_per_frame && max_cnt && p_b, PJ_EINVAL); 121 pj_status_t status; 122 123 PJ_ASSERT_RETURN(pool && samples_per_frame && max_frames && p_b, PJ_EINVAL); 124 PJ_ASSERT_RETURN((int)max_frames >= delay, PJ_EINVAL); 125 PJ_ASSERT_RETURN(options==0, PJ_EINVAL); 126 127 PJ_UNUSED_ARG(options); 99 128 100 129 if (!name) { … … 105 134 106 135 pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1); 136 b->samples_per_frame = samples_per_frame; 137 b->max_frames = max_frames; 138 139 status = pj_lock_create_recursive_mutex(pool, b->obj_name, 140 &b->lock); 141 if (status != PJ_SUCCESS) 142 return status; 143 107 144 b->frame_buf = (pj_int16_t*) 108 pj_pool_zalloc(pool, samples_per_frame * max_cnt * 109 sizeof(pj_int16_t)); 110 b->samples_per_frame = samples_per_frame; 111 b->max_cnt = max_cnt; 145 pj_pool_zalloc(pool, samples_per_frame * max_frames * 146 sizeof(pj_int16_t)); 112 147 113 148 if (delay >= 0) { 114 PJ_ASSERT_RETURN(delay <= (int)max_cnt, PJ_EINVAL); 149 if (delay == 0) 150 delay = 1; 115 151 b->max_level = delay; 152 b->max_cnt = delay * samples_per_frame; 116 153 b->state = STATE_RUNNING; 117 154 } else { 155 b->max_cnt = max_frames * samples_per_frame; 118 156 b->last_op = OP_UNDEFINED; 119 157 b->state = STATE_WAITING; 120 b->buf_cnt = 0; 121 } 158 } 159 160 status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 161 PJMEDIA_WSOLA_NO_PLC, &b->wsola); 162 if (status != PJ_SUCCESS) 163 return status; 122 164 123 165 *p_b = b; 124 166 125 PJ_LOG(5,(b->obj_name,"Delay buffer created"));167 TRACE__((b->obj_name,"Delay buffer created")); 126 168 127 169 return PJ_SUCCESS; 170 } 171 172 PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b) 173 { 174 pj_status_t status; 175 176 PJ_ASSERT_RETURN(b, PJ_EINVAL); 177 178 pj_lock_acquire(b->lock); 179 180 status = pjmedia_wsola_destroy(b->wsola); 181 if (status == PJ_SUCCESS) 182 b->wsola = NULL; 183 184 pj_lock_release(b->lock); 185 pj_lock_destroy(b->lock); 186 b->lock = NULL; 187 188 return status; 189 } 190 191 /* This function will erase samples from delay buffer. 192 * The number of erased samples is guaranteed to be >= erase_cnt. 193 */ 194 static void shrink_buffer(pjmedia_delay_buf *b, unsigned erase_cnt) 195 { 196 unsigned buf1len; 197 unsigned buf2len; 198 pj_status_t status; 199 200 pj_assert(b && erase_cnt); 201 202 if (b->get_pos < b->put_pos) { 203 /* sssss .. sssss 204 * ^ ^ 205 * G P 206 */ 207 buf1len = b->put_pos - b->get_pos; 208 buf2len = 0; 209 } else { 210 /* sssss .. sssss 211 * ^ ^ 212 * P G 213 */ 214 buf1len = b->max_cnt - b->get_pos; 215 buf2len = b->put_pos; 216 } 217 218 /* Consistency checking */ 219 pj_assert((buf1len + buf2len) == b->buf_cnt); 220 221 if (buf1len != 0) 222 status = pjmedia_wsola_discard(b->wsola, 223 &b->frame_buf[b->get_pos], buf1len, 224 b->frame_buf, buf2len, 225 &erase_cnt); 226 else 227 status = pjmedia_wsola_discard(b->wsola, 228 b->frame_buf, buf2len, 229 NULL, 0, 230 &erase_cnt); 231 232 if ((status == PJ_SUCCESS) && (erase_cnt > 0)) { 233 /* WSOLA discard will shrink only the second buffer, but it may 234 * also shrink first buffer if second buffer is 'destroyed', so 235 * it is safe to just set the new put_pos. 236 */ 237 if (b->put_pos >= erase_cnt) 238 b->put_pos -= erase_cnt; 239 else 240 b->put_pos = b->max_cnt - (erase_cnt - b->put_pos); 241 242 b->buf_cnt -= erase_cnt; 243 244 PJ_LOG(5,(b->obj_name,"Successfully shrinking %d samples, " 245 "buf_cnt=%d", erase_cnt, b->buf_cnt)); 246 } 247 248 /* Shrinking failed or erased count is less than requested, 249 * delaybuf needs to drop eldest samples, this is bad since the voice 250 * samples may not have smooth transition. 251 */ 252 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) { 253 erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 254 255 b->buf_cnt -= erase_cnt; 256 257 /* Shift get_pos forward */ 258 b->get_pos = (b->get_pos + erase_cnt) % b->max_cnt; 259 260 PJ_LOG(4,(b->obj_name,"Shrinking failed or insufficient, dropping" 261 " %d eldest samples, buf_cnt=%d", erase_cnt, b->buf_cnt)); 262 } 263 } 264 265 static void set_max_cnt(pjmedia_delay_buf *b, unsigned new_max_cnt) 266 { 267 unsigned old_max_cnt = b->max_cnt; 268 269 /* nothing to adjust */ 270 if (old_max_cnt == new_max_cnt) 271 return; 272 273 /* For now, only support shrinking */ 274 pj_assert(old_max_cnt > new_max_cnt); 275 276 shrink_buffer(b, old_max_cnt - new_max_cnt); 277 278 /* Adjust buffer to accomodate the new max_cnt so the samples is secured. 279 * This is done by make get_pos = 0 280 */ 281 if (b->get_pos <= b->put_pos) { 282 /* sssss .. sssss 283 * ^ ^ 284 * G P 285 */ 286 /* Consistency checking */ 287 pj_assert((b->put_pos - b->get_pos) <= new_max_cnt); 288 pj_assert((b->put_pos - b->get_pos) == b->buf_cnt); 289 290 pjmedia_move_samples(b->frame_buf, &b->frame_buf[b->get_pos], 291 b->get_pos); 292 b->put_pos -= b->get_pos; 293 b->get_pos = 0; 294 } else { 295 /* sssss .. sssss 296 * ^ ^ 297 * P G 298 */ 299 unsigned d = old_max_cnt - b->get_pos; 300 301 /* Consistency checking */ 302 pj_assert((b->get_pos - b->put_pos) >= (old_max_cnt - new_max_cnt)); 303 304 /* Make get_pos = 0, shift right the leftmost block first */ 305 pjmedia_move_samples(&b->frame_buf[d], b->frame_buf, d); 306 pjmedia_copy_samples(b->frame_buf, &b->frame_buf[b->get_pos], d); 307 b->put_pos += d; 308 b->get_pos = 0; 309 } 310 311 b->max_cnt = new_max_cnt; 128 312 } 129 313 … … 158 342 b->max_level += SAFE_MARGIN; 159 343 160 PJ_LOG(5,(b->obj_name,"Delay buffer start running, level=%u",161 b->max_level));162 163 344 /* buffer not enough! */ 164 if (b->max_level > b->max_cnt) { 165 b->max_level = b->max_cnt; 166 PJ_LOG(2,(b->obj_name,"Delay buffer %s learning result " \ 167 "exceeds the maximum delay allowed", 168 b->max_level)); 345 if (b->max_level > b->max_frames) { 346 PJ_LOG(4,(b->obj_name,"Delay buffer learning result (%d)" 347 " exceeds the maximum delay allowed (%d)", 348 b->max_level, 349 b->max_frames)); 350 351 b->max_level = b->max_frames; 169 352 } 170 353 354 /* we need to set new max_cnt & adjust buffer */ 355 set_max_cnt(b, b->max_level * b->samples_per_frame); 356 171 357 b->state = STATE_RUNNING; 358 359 PJ_LOG(4,(b->obj_name,"Delay buffer start running, level=%u", 360 b->max_level)); 172 361 } 173 362 } … … 182 371 pj_int16_t frame[]) 183 372 { 373 pj_status_t status; 374 375 PJ_ASSERT_RETURN(b && frame, PJ_EINVAL); 376 377 pj_lock_acquire(b->lock); 378 184 379 update(b, OP_PUT); 185 380 186 if (b->state != STATE_RUNNING) 187 return PJ_EPENDING; 188 189 pj_memcpy(&b->frame_buf[b->put_pos * b->samples_per_frame], frame, 190 b->samples_per_frame*sizeof(pj_int16_t)); 191 192 /* overflow case */ 193 if (b->put_pos == b->get_pos && b->buf_cnt) { 194 if (++b->get_pos == b->max_level) 195 b->get_pos = 0; 196 197 b->put_pos = b->get_pos; 198 199 PJ_LOG(5,(b->obj_name,"Warning: buffer overflow")); 200 201 return PJ_ETOOMANY; 202 } 203 204 ++b->buf_cnt; 205 206 if (++b->put_pos == b->max_level) 207 b->put_pos = 0; 208 381 status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); 382 if (status != PJ_SUCCESS) { 383 pj_lock_release(b->lock); 384 return status; 385 } 386 387 /* Overflow checking */ 388 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 389 { 390 /* shrink one frame or just the diff? */ 391 //unsigned erase_cnt = b->samples_per_frame; 392 unsigned erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 393 394 shrink_buffer(b, erase_cnt); 395 } 396 397 /* put the frame on put_pos */ 398 if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 399 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 400 b->samples_per_frame); 401 } else { 402 int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 403 404 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 405 b->samples_per_frame - remainder); 406 pjmedia_copy_samples(&b->frame_buf[0], 407 &frame[b->samples_per_frame - remainder], 408 remainder); 409 } 410 411 /* Update put_pos & buf_cnt */ 412 b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 413 b->buf_cnt += b->samples_per_frame; 414 415 pj_lock_release(b->lock); 209 416 return PJ_SUCCESS; 210 417 } 211 418 212 PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,419 PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b, 213 420 pj_int16_t frame[]) 214 421 { 422 pj_status_t status; 423 424 PJ_ASSERT_RETURN(b && frame, PJ_EINVAL); 425 426 pj_lock_acquire(b->lock); 427 215 428 update(b, OP_GET); 216 429 217 if (b->state != STATE_RUNNING || !b->buf_cnt) { 218 if (b->state == STATE_RUNNING) 219 PJ_LOG(5,(b->obj_name,"Warning: delay buffer empty")); 220 221 pj_bzero(frame, b->samples_per_frame*sizeof(pj_int16_t)); 222 return PJ_EPENDING; 223 } 224 225 pj_memcpy(frame, &b->frame_buf[b->get_pos * b->samples_per_frame], 226 b->samples_per_frame*sizeof(pj_int16_t)); 227 228 if (++b->get_pos == b->max_level) 229 b->get_pos = 0; 230 231 --b->buf_cnt; 430 /* Starvation checking */ 431 if (b->buf_cnt < b->samples_per_frame) { 432 433 PJ_LOG(5,(b->obj_name,"Underflow, buf_cnt=%d, will generate 1 frame", 434 b->buf_cnt)); 435 436 status = pjmedia_wsola_generate(b->wsola, frame); 437 438 if (status == PJ_SUCCESS) { 439 TRACE__((b->obj_name,"Successfully generate 1 frame")); 440 if (b->buf_cnt == 0) { 441 pj_lock_release(b->lock); 442 return PJ_SUCCESS; 443 } 444 445 /* Put generated frame into buffer */ 446 if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 447 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 448 b->samples_per_frame); 449 } else { 450 int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 451 452 pjmedia_copy_samples(&b->frame_buf[b->put_pos], &frame[0], 453 b->samples_per_frame - remainder); 454 pjmedia_copy_samples(&b->frame_buf[0], 455 &frame[b->samples_per_frame - remainder], 456 remainder); 457 } 458 459 b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 460 b->buf_cnt += b->samples_per_frame; 461 462 } else { 463 /* Give all what delay buffer has, then pad zeroes */ 464 PJ_LOG(4,(b->obj_name,"Error generating frame, status=%d", 465 status)); 466 467 pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], b->buf_cnt); 468 pjmedia_zero_samples(&frame[b->buf_cnt], 469 b->samples_per_frame - b->buf_cnt); 470 b->get_pos += b->buf_cnt; 471 b->buf_cnt = 0; 472 473 /* Consistency checking */ 474 pj_assert(b->get_pos == b->put_pos); 475 476 pj_lock_release(b->lock); 477 478 return PJ_SUCCESS; 479 } 480 } 481 482 pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], 483 b->samples_per_frame); 484 485 b->get_pos = (b->get_pos + b->samples_per_frame) % b->max_cnt; 486 b->buf_cnt -= b->samples_per_frame; 487 488 pj_lock_release(b->lock); 232 489 233 490 return PJ_SUCCESS; 234 491 } 235 492 236 PJ_DE CL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b)493 PJ_DEF(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b) 237 494 { 238 495 PJ_ASSERT_RETURN(b, PJ_EINVAL); 496 497 pj_lock_acquire(b->lock); 239 498 240 499 b->last_op = OP_UNDEFINED; … … 243 502 b->state_count = 0; 244 503 b->max_level = 0; 504 b->max_cnt = b->max_frames * b->samples_per_frame; 505 506 pjmedia_delay_buf_reset(b); 507 508 pj_lock_release(b->lock); 509 510 PJ_LOG(5,(b->obj_name,"Delay buffer start learning")); 511 512 return PJ_SUCCESS; 513 } 514 515 PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b) 516 { 517 PJ_ASSERT_RETURN(b, PJ_EINVAL); 518 519 pj_lock_acquire(b->lock); 245 520 246 521 /* clean up buffer */ 247 522 b->buf_cnt = 0; 248 523 b->put_pos = b->get_pos = 0; 249 250 PJ_LOG(5,(b->obj_name,"Delay buffer start learning")); 524 pjmedia_wsola_reset(b->wsola, 0); 525 526 pj_lock_release(b->lock); 527 528 PJ_LOG(5,(b->obj_name,"Delay buffer resetted")); 251 529 252 530 return PJ_SUCCESS; 253 531 } 532
Note: See TracChangeset
for help on using the changeset viewer.