Ticket #438: scomb-dbuf3.patch
File scomb-dbuf3.patch, 23.3 KB (added by bennylp, 17 years ago) |
---|
-
pjmedia/src/pjmedia/delaybuf.c
38 38 { 39 39 STATE_WAITING, 40 40 STATE_LEARNING, 41 STATE_PAUSED, 41 42 STATE_RUNNING 42 43 }; 43 44 … … 63 64 */ 64 65 #define SAFE_MARGIN 2 65 66 67 /* Delay buf will continuously detect activity of operations. If only one 68 * operation is called sequentially (bursting) for more than max_level + 69 * IDLE_MARGIN, delay buffer will assume the other operation is idle and 70 * delay buffer will automatically change its state to STATE_PAUSED. 71 */ 72 #define IDLE_MARGIN 2 73 66 74 /* 67 75 * Some experimental data (with SAFE_MARGIN=1): 68 76 * … … 97 105 unsigned buf_cnt; /**< Number of buffered samples */ 98 106 unsigned max_cnt; /**< Max number of buffered samples */ 99 107 100 struct { 101 unsigned level; /**< Burst level storage on learning */ 102 } op[2]; 108 unsigned level; /**< Burst level storage on learning */ 103 109 enum OP last_op; /**< Last op (GET or PUT) of learning*/ 104 110 unsigned state_count; /**< Counter of op cycles of learning*/ 105 111 106 112 unsigned max_level; /**< Learning result: burst level */ 107 113 108 114 pjmedia_wsola *wsola; /**< Drift handler */ 115 116 unsigned max_burst; /**< Maximum burst before media flow 117 is suspended */ 109 118 }; 110 119 111 120 PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, … … 135 144 pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1); 136 145 b->samples_per_frame = samples_per_frame; 137 146 b->max_frames = max_frames; 147 b->max_burst = max_frames + IDLE_MARGIN; 138 148 139 149 status = pj_lock_create_recursive_mutex(pool, b->obj_name, 140 150 &b->lock); … … 145 155 pj_pool_zalloc(pool, samples_per_frame * max_frames * 146 156 sizeof(pj_int16_t)); 147 157 158 status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 159 PJMEDIA_WSOLA_NO_PLC, &b->wsola); 160 if (status != PJ_SUCCESS) 161 return status; 162 148 163 if (delay >= 0) { 164 /* Fixed delay */ 149 165 if (delay == 0) 150 166 delay = 1; 151 167 b->max_level = delay; 152 168 b->max_cnt = delay * samples_per_frame; 153 169 b->state = STATE_RUNNING; 154 170 } else { 171 /* Learning the best delay */ 155 172 b->max_cnt = max_frames * samples_per_frame; 156 b->last_op = OP_UNDEFINED;157 173 b->state = STATE_WAITING; 158 174 } 175 b->last_op = OP_UNDEFINED; 159 176 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;164 165 177 *p_b = b; 166 178 167 179 TRACE__((b->obj_name,"Delay buffer created")); … … 241 253 242 254 b->buf_cnt -= erase_cnt; 243 255 244 PJ_LOG(5,(b->obj_name," Successfully shrinking %d samples, "256 PJ_LOG(5,(b->obj_name,"Overflow, %d samples reduced, " 245 257 "buf_cnt=%d", erase_cnt, b->buf_cnt)); 246 258 } 247 259 … … 280 292 return; 281 293 } 282 294 283 shrink_buffer(b, old_max_cnt - new_max_cnt); 295 /* If current samples number is more than new max cnt, 296 * we need to shrink buffer first */ 297 if (b->buf_cnt > new_max_cnt) 298 shrink_buffer(b, b->buf_cnt - new_max_cnt); 284 299 285 300 /* Adjust buffer to accomodate the new max_cnt so the samples is secured. 286 301 * This is done by make get_pos = 0 … … 320 335 321 336 static void update(pjmedia_delay_buf *b, enum OP op) 322 337 { 323 enum OP other = (enum OP) !op;338 switch (b->state) { 324 339 325 switch (b->state) {326 340 case STATE_RUNNING: 341 if (op != b->last_op) { 342 b->last_op = op; 343 b->level = 1; 344 break; 345 } 346 ++b->level; 347 348 if (b->level > b->max_burst) { 349 b->state = STATE_PAUSED; 350 pjmedia_delay_buf_reset(b); 351 PJ_LOG(5,(b->obj_name, "Delay buffer suspended")); 352 } 353 327 354 break; 355 356 case STATE_PAUSED: 357 if (op != b->last_op) { 358 b->last_op = op; 359 b->level = 1; 360 b->state = STATE_RUNNING; 361 PJ_LOG(5,(b->obj_name, "Delay buffer resumed")); 362 } 363 break; 364 328 365 case STATE_WAITING: 329 ++b->op[op].level; 330 if (b->op[other].level != 0) { 331 ++b->state_count; 332 if (b->state_count == WAITING_COUNT) { 366 if (op != b->last_op) { 367 b->last_op = op; 368 if (++b->state_count == WAITING_COUNT) { 333 369 /* Start learning */ 334 370 pjmedia_delay_buf_learn(b); 371 break; 335 372 } 336 373 } 337 b->last_op = op;338 374 break; 375 339 376 case STATE_LEARNING: 340 ++b->op[op].level; 341 if (b->last_op == other) { 342 unsigned last_level = b->op[other].level; 343 if (last_level > b->max_level) 344 b->max_level = last_level; 345 b->op[other].level = 0; 346 b->state_count++; 347 if (b->state_count == LEARN_COUNT) { 377 if (op != b->last_op) { 378 b->last_op = op; 379 if (b->level > b->max_level) 380 b->max_level = b->level; 381 b->level = 1; 382 383 if (++b->state_count == LEARN_COUNT) { 348 384 /* give SAFE_MARGIN compensation for added stability */ 349 385 b->max_level += SAFE_MARGIN; 386 b->max_burst = b->max_level + IDLE_MARGIN; 350 387 351 388 /* buffer not enough! */ 352 389 if (b->max_level > b->max_frames) { … … 366 403 PJ_LOG(4,(b->obj_name,"Delay buffer start running, level=%u", 367 404 b->max_level)); 368 405 } 406 407 break; 369 408 } 370 b->last_op = op; 409 410 ++b->level; 371 411 break; 372 412 } 373 413 … … 391 431 return status; 392 432 } 393 433 434 if (b->state == STATE_PAUSED) { 435 pj_lock_release(b->lock); 436 return PJ_SUCCESS; 437 } 438 394 439 /* Overflow checking */ 395 440 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 396 441 { … … 434 479 435 480 update(b, OP_GET); 436 481 482 if (b->state == STATE_PAUSED) { 483 pjmedia_zero_samples(frame, b->samples_per_frame); 484 pj_lock_release(b->lock); 485 return PJ_SUCCESS; 486 } 487 437 488 /* Starvation checking */ 438 489 if (b->buf_cnt < b->samples_per_frame) { 439 490 … … 504 555 pj_lock_acquire(b->lock); 505 556 506 557 b->last_op = OP_UNDEFINED; 507 b-> op[OP_GET].level = b->op[OP_PUT].level = 0;558 b->level = 1; 508 559 b->state = STATE_LEARNING; 509 560 b->state_count = 0; 510 b->max_level = 0;561 b->max_level = 1; 511 562 b->max_cnt = b->max_frames * b->samples_per_frame; 512 563 513 564 pjmedia_delay_buf_reset(b); … … 532 583 533 584 pj_lock_release(b->lock); 534 585 535 PJ_LOG(5,(b->obj_name,"Delay buffer resetted"));586 PJ_LOG(5,(b->obj_name,"Delay buffer is reset")); 536 587 537 588 return PJ_SUCCESS; 538 589 } -
pjmedia/src/pjmedia/splitcomb.c
17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 */ 19 19 #include <pjmedia/splitcomb.h> 20 #include <pjmedia/delaybuf.h> 20 21 #include <pjmedia/errno.h> 21 22 #include <pj/assert.h> 22 23 #include <pj/log.h> … … 28 29 #define THIS_FILE "splitcomb.c" 29 30 #define TMP_SAMP_TYPE pj_int16_t 30 31 31 /* When delay buffer is used, we only need 1 frame buffering */ 32 #if defined(PJMEDIA_SOUND_USE_DELAYBUF) && PJMEDIA_SOUND_USE_DELAYBUF!=0 33 # define MAX_BUF_CNT 1 34 #else 35 # define MAX_BUF_CNT PJMEDIA_SOUND_BUFFER_COUNT 36 #endif 32 /* Maximum number of channels. */ 33 #define MAX_CHANNELS 16 37 34 35 #define MAX_BUF_CNT PJMEDIA_SOUND_BUFFER_COUNT 36 37 /* Operations */ 38 #define OP_PUT (1) 39 #define OP_GET (-1) 40 41 /* Media flow directions */ 42 enum sc_dir 43 { 44 /* This is the direction from the splitcomb to the downstream 45 * port(s), or when put_frame() is called to the splitcomb. 46 */ 47 DIR_DOWNSTREAM, 48 49 /* This is the direction from the downstream port to the splitcomb, 50 * or when get_frame() is called to the splitcomb. 51 */ 52 DIR_UPSTREAM 53 }; 54 55 56 38 57 #if 0 39 58 # define TRACE_UP_(x) PJ_LOG(5,x) 40 59 # define TRACE_DN_(x) PJ_LOG(5,x) … … 43 62 # define TRACE_DN_(x) 44 63 #endif 45 64 46 #if 147 # define LOG_UP_(x) PJ_LOG(5,x)48 # define LOG_DN_(x) PJ_LOG(5,x)49 #else50 # define LOG_UP_(x)51 # define LOG_DN_(x)52 #endif53 65 54 66 /* 55 67 * This structure describes the splitter/combiner. … … 64 76 struct { 65 77 pjmedia_port *port; 66 78 pj_bool_t reversed; 67 } port_desc[ 64];79 } port_desc[MAX_CHANNELS]; 68 80 69 81 /* Temporary buffers needed to extract mono frame from 70 82 * multichannel frame. We could use stack for this, but this … … 84 96 struct splitcomb*parent; 85 97 unsigned ch_num; 86 98 99 /* Maximum burst before media flow is suspended */ 100 int max_burst; 101 87 102 /* A reverse port need a temporary buffer to store frame 88 103 * (because of the different phase, see splitcomb.h for details). 89 104 * Since we can not expect get_frame() and put_frame() to be 90 * called evenly one after another, we use circular buffers to 91 * accomodate the "jitter". 105 * called evenly one after another, we use delay buffers to 106 * accomodate the burst. 107 * 108 * We maintain state for each direction, hence the array. The 109 * array is indexed by direction (sc_dir). 92 110 */ 93 unsigned buf_cnt;111 struct { 94 112 95 /* Downstream is the direction when get_frame() is called to the 96 * splitter/combiner port. 97 */ 98 unsigned dn_read_pos, dn_write_pos, 99 dn_overflow_pos, dn_underflow_pos; 100 pj_int16_t *dnstream_buf[MAX_BUF_CNT]; 113 /* The delay buffer where frames will be stored */ 114 pjmedia_delay_buf *dbuf; 101 115 102 /* Upstream is the direction when put_frame() is called to the 103 * splitter/combiner port. 116 /* Flag to indicate that audio flow on this direction 117 * is currently being suspended (perhaps because nothing 118 * is processing the frame on the other end). 119 */ 120 pj_bool_t paused; 121 122 /* Operation level. When the level exceeds a maximum value, 123 * the media flow on this direction will be paused. 124 */ 125 int level; 126 127 /* Timestamp. */ 128 pj_timestamp ts; 129 130 } buf[2]; 131 132 /* Must have temporary put buffer for the delay buf, 133 * unfortunately. 104 134 */ 105 unsigned up_read_pos, up_write_pos, 106 up_overflow_pos, up_underflow_pos; 107 pj_int16_t *upstream_buf[MAX_BUF_CNT]; 135 pj_int16_t *tmp_up_buf; 108 136 }; 109 137 110 138 … … 228 256 unsigned options, 229 257 pjmedia_port **p_chport) 230 258 { 231 const pj_str_t name = pj_str("s plitcomb-ch");259 const pj_str_t name = pj_str("scomb-rev"); 232 260 struct splitcomb *sc = (struct splitcomb*) splitcomb; 233 261 struct reverse_port *rport; 234 unsigned i;262 unsigned buf_cnt; 235 263 pjmedia_port *port; 264 pj_status_t status; 236 265 237 266 /* Sanity check */ 238 267 PJ_ASSERT_RETURN(pool && splitcomb, PJ_EINVAL); … … 265 294 port->on_destroy = &rport_on_destroy; 266 295 267 296 268 rport->buf_cnt = options & 0xFF;269 if ( rport->buf_cnt == 0)270 rport->buf_cnt = MAX_BUF_CNT;297 buf_cnt = options & 0xFF; 298 if (buf_cnt == 0) 299 buf_cnt = MAX_BUF_CNT; 271 300 272 /* Create put buffers */ 273 for (i=0; i<rport->buf_cnt; ++i) { 274 rport->dnstream_buf[i]=(pj_int16_t*) 275 pj_pool_zalloc(pool, port->info.bytes_per_frame); 276 PJ_ASSERT_RETURN(rport->dnstream_buf[i], PJ_ENOMEM); 301 rport->max_burst = buf_cnt + 4; 302 303 /* Create downstream/put buffers */ 304 status = pjmedia_delay_buf_create(pool, "scomb-down", 305 port->info.clock_rate, 306 port->info.samples_per_frame, 307 buf_cnt, -1, 0, 308 &rport->buf[DIR_DOWNSTREAM].dbuf); 309 if (status != PJ_SUCCESS) { 310 return status; 277 311 } 278 rport->dn_write_pos = rport->buf_cnt/2;279 312 280 /* Create get buffers */ 281 for (i=0; i<rport->buf_cnt; ++i) { 282 rport->upstream_buf[i] = (pj_int16_t*) 283 pj_pool_zalloc(pool, 284 port->info.bytes_per_frame); 285 PJ_ASSERT_RETURN(rport->upstream_buf[i], PJ_ENOMEM); 313 /* Create upstream/get buffers */ 314 status = pjmedia_delay_buf_create(pool, "scomb-up", 315 port->info.clock_rate, 316 port->info.samples_per_frame, 317 buf_cnt, -1, 0, 318 &rport->buf[DIR_UPSTREAM].dbuf); 319 if (status != PJ_SUCCESS) { 320 pjmedia_delay_buf_destroy(rport->buf[DIR_DOWNSTREAM].dbuf); 321 return status; 286 322 } 287 rport->up_write_pos = rport->buf_cnt/2;288 323 324 /* And temporary upstream/get buffer */ 325 rport->tmp_up_buf = (pj_int16_t*) 326 pj_pool_alloc(pool, port->info.bytes_per_frame); 289 327 290 328 /* Save port in the splitcomb */ 291 329 sc->port_desc[ch_num].port = &rport->base; … … 294 332 295 333 /* Done */ 296 334 *p_chport = port; 297 return PJ_SUCCESS;335 return status; 298 336 } 299 337 300 338 … … 335 373 } 336 374 } 337 375 376 /* Update operation on the specified direction */ 377 static void op_update(struct reverse_port *rport, int dir, int op) 378 { 379 char *dir_name[2] = {"downstream", "upstream"}; 338 380 381 rport->buf[dir].level += op; 382 383 if (op == OP_PUT) { 384 rport->buf[dir].ts.u64 += rport->base.info.samples_per_frame; 385 } 386 387 if (rport->buf[dir].paused) { 388 if (rport->buf[dir].level < -rport->max_burst) { 389 rport->buf[dir].level = -rport->max_burst; 390 } else if (rport->buf[dir].level > rport->max_burst) { 391 rport->buf[dir].level = rport->max_burst; 392 } else { 393 /* Level has fallen below max level, we can resume 394 * media flow. 395 */ 396 PJ_LOG(5,(rport->base.info.name.ptr, 397 "Resuming media flow on %s direction", dir_name[dir])); 398 rport->buf[dir].level = 0; 399 pjmedia_delay_buf_learn(rport->buf[dir].dbuf); 400 rport->buf[dir].paused = PJ_FALSE; 401 } 402 } else { 403 if (rport->buf[dir].level >= rport->max_burst || 404 rport->buf[dir].level <= -rport->max_burst) 405 { 406 /* Level has reached maximum level, the other side of 407 * rport is not sending/retrieving frames. Pause the 408 * rport on this direction. 409 */ 410 PJ_LOG(5,(rport->base.info.name.ptr, 411 "Pausing media flow on %s direction", dir_name[dir])); 412 rport->buf[dir].paused = PJ_TRUE; 413 } 414 } 415 } 416 417 339 418 /* 340 419 * "Write" a multichannel frame. This would split the multichannel frame 341 420 * into individual mono channel, and write it to the appropriate port. … … 373 452 if (!port) 374 453 continue; 375 454 455 /* Extract the mono frame to temporary buffer */ 456 extract_mono_frame((const pj_int16_t*)frame->buf, sc->put_buf, ch, 457 this_port->info.channel_count, 458 frame->size * 8 / 459 this_port->info.bits_per_sample / 460 this_port->info.channel_count); 461 376 462 if (!sc->port_desc[ch].reversed) { 377 463 /* Write to normal port */ 378 464 pjmedia_frame mono_frame; 379 465 380 /* Extract the mono frame */381 extract_mono_frame((const pj_int16_t*)frame->buf, sc->put_buf, ch,382 this_port->info.channel_count,383 frame->size * 8 /384 this_port->info.bits_per_sample /385 this_port->info.channel_count);386 387 466 mono_frame.buf = sc->put_buf; 388 467 mono_frame.size = frame->size / this_port->info.channel_count; 389 468 mono_frame.type = frame->type; … … 395 474 } else { 396 475 /* Write to reversed phase port */ 397 476 struct reverse_port *rport = (struct reverse_port*)port; 398 399 if (rport->dn_write_pos == rport->dn_read_pos) {400 477 401 /* Only report overflow if the frame is constantly read 402 * by the 'consumer' of the reverse port. 403 * It is possible that nobody reads the buffer, so causing 404 * overflow to happen rapidly, and writing log message this 405 * way does not seem to be wise. 406 */ 407 if (rport->dn_read_pos != rport->dn_overflow_pos) { 408 rport->dn_overflow_pos = rport->dn_read_pos; 409 LOG_DN_((THIS_FILE, "Overflow in downstream direction")); 410 } 478 /* Update rport state. */ 479 op_update(rport, DIR_DOWNSTREAM, OP_PUT); 411 480 412 /* Adjust write position */ 413 rport->dn_write_pos = 414 (rport->dn_write_pos + rport->buf_cnt/2) % 415 rport->buf_cnt; 481 if (!rport->buf[DIR_DOWNSTREAM].paused) { 482 pjmedia_delay_buf_put(rport->buf[DIR_DOWNSTREAM].dbuf, 483 sc->put_buf); 416 484 } 417 418 /* Extract mono-frame and put it in downstream buffer */419 extract_mono_frame((const pj_int16_t*)frame->buf,420 rport->dnstream_buf[rport->dn_write_pos],421 ch, this_port->info.channel_count,422 frame->size * 8 /423 this_port->info.bits_per_sample /424 this_port->info.channel_count);425 426 rport->dn_write_pos = (rport->dn_write_pos + 1) %427 rport->buf_cnt;428 485 } 429 486 } 430 487 … … 444 501 unsigned ch; 445 502 pj_bool_t has_frame = PJ_FALSE; 446 503 447 /* Clear output frame */448 pjmedia_zero_samples((pj_int16_t*)frame->buf,449 this_port->info.samples_per_frame);450 451 504 /* Read frame from each port */ 452 505 for (ch=0; ch < this_port->info.channel_count; ++ch) { 453 506 pjmedia_port *port = sc->port_desc[ch].port; 454 507 pjmedia_frame mono_frame; 455 508 pj_status_t status; 456 509 457 if (!port) 458 continue; 510 if (!port) { 511 pjmedia_zero_samples(sc->get_buf, 512 this_port->info.samples_per_frame / 513 this_port->info.channel_count); 459 514 460 /* Read from the port */ 461 if (sc->port_desc[ch].reversed == PJ_FALSE) { 515 } else if (sc->port_desc[ch].reversed == PJ_FALSE) { 462 516 /* Read from normal port */ 463 517 mono_frame.buf = sc->get_buf; 464 518 mono_frame.size = port->info.bytes_per_frame; … … 468 522 if (status != PJ_SUCCESS || 469 523 mono_frame.type != PJMEDIA_FRAME_TYPE_AUDIO) 470 524 { 471 continue; 525 pjmedia_zero_samples(sc->get_buf, 526 port->info.samples_per_frame); 472 527 } 473 528 474 /* Combine the mono frame into multichannel frame */475 store_mono_frame((const pj_int16_t*)mono_frame.buf,476 (pj_int16_t*)frame->buf, ch,477 this_port->info.channel_count,478 mono_frame.size * 8 /479 this_port->info.bits_per_sample);480 481 529 frame->timestamp.u64 = mono_frame.timestamp.u64; 482 530 483 531 } else { 484 532 /* Read from temporary buffer for reverse port */ 485 533 struct reverse_port *rport = (struct reverse_port*)port; 486 534 487 /* Check for underflows*/488 if (rport->up_read_pos == rport->up_write_pos) {535 /* Update rport state. */ 536 op_update(rport, DIR_UPSTREAM, OP_GET); 489 537 490 /* Only report underflow if the buffer is constantly filled 491 * up at the other side. 492 * It is possible that nobody writes the buffer, so causing 493 * underflow to happen rapidly, and writing log message this 494 * way does not seem to be wise. 495 */ 496 if (rport->up_write_pos != rport->up_underflow_pos) { 497 rport->up_underflow_pos = rport->up_write_pos; 498 LOG_UP_((THIS_FILE, "Underflow in upstream direction")); 499 } 538 if (!rport->buf[DIR_UPSTREAM].paused) { 539 pjmedia_delay_buf_get(rport->buf[DIR_UPSTREAM].dbuf, 540 sc->get_buf); 500 541 501 /* Adjust read position */ 502 rport->up_read_pos = 503 (rport->up_write_pos - rport->buf_cnt/2) % 504 rport->buf_cnt; 542 } else { 543 pjmedia_zero_samples(sc->get_buf, 544 rport->base.info.samples_per_frame); 505 545 } 506 546 507 TRACE_UP_((THIS_FILE, "Upstream read at buffer pos %d",508 rport->up_read_pos));547 frame->timestamp.u64 = rport->buf[DIR_UPSTREAM].ts.u64; 548 } 509 549 510 511 store_mono_frame((const pj_int16_t*)rport->upstream_buf[rport->up_read_pos],512 513 514 550 /* Combine the mono frame into multichannel frame */ 551 store_mono_frame(sc->get_buf, 552 (pj_int16_t*)frame->buf, ch, 553 this_port->info.channel_count, 554 this_port->info.samples_per_frame); 515 555 516 rport->up_read_pos = (rport->up_read_pos + 1) %517 rport->buf_cnt;518 }519 556 520 557 521 558 has_frame = PJ_TRUE; … … 548 585 const pjmedia_frame *frame) 549 586 { 550 587 struct reverse_port *rport = (struct reverse_port*) this_port; 551 unsigned count;552 588 553 589 pj_assert(frame->size <= rport->base.info.bytes_per_frame); 554 590 555 /* Check for overflows */556 if (rport->up_write_pos == rport->up_read_pos) {557 558 /* Only report overflow if the frame is constantly read559 * at the other end of the buffer (the multichannel side).560 * It is possible that nobody reads the buffer, so causing561 * overflow to happen rapidly, and writing log message this562 * way does not seem to be wise.563 */564 if (rport->up_read_pos != rport->up_overflow_pos) {565 rport->up_overflow_pos = rport->up_read_pos;566 LOG_UP_((THIS_FILE, "Overflow in upstream direction"));567 }568 569 /* Adjust the write position */570 rport->up_write_pos = (rport->up_read_pos + rport->buf_cnt/2) %571 rport->buf_cnt;572 }573 574 591 /* Handle NULL frame */ 575 592 if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO) { 576 593 TRACE_UP_((THIS_FILE, "Upstream write %d null samples at buf pos %d", 577 594 this_port->info.samples_per_frame, rport->up_write_pos)); 578 pjmedia_zero_samples(rport->upstream_buf[rport->up_write_pos], 579 this_port->info.samples_per_frame); 580 rport->up_write_pos = (rport->up_write_pos+1) % rport->buf_cnt; 595 /* Should write zero frame to delaybuf? */ 581 596 return PJ_SUCCESS; 582 597 } 583 598 … … 585 600 PJ_ASSERT_RETURN(frame->size == this_port->info.bytes_per_frame, 586 601 PJ_EINVAL); 587 602 588 /* Copy normal frame to curcular buffer*/589 count = frame->size * 8 / this_port->info.bits_per_sample;603 /* Update rport state. */ 604 op_update(rport, DIR_UPSTREAM, OP_PUT); 590 605 591 TRACE_UP_((THIS_FILE, "Upstream write %d samples at buf pos %d", 592 count, rport->up_write_pos)); 606 /* Discard frame if rport is paused on this direction */ 607 if (rport->buf[DIR_UPSTREAM].paused) 608 return PJ_SUCCESS; 593 609 610 /* Unfortunately must copy to temporary buffer since delay buf 611 * modifies the frame content. 612 */ 613 pjmedia_copy_samples(rport->tmp_up_buf, (const pj_int16_t*)frame->buf, 614 this_port->info.samples_per_frame); 594 615 595 pjmedia_copy_samples(rport->upstream_buf[rport->up_write_pos], 596 (const pj_int16_t*) frame->buf, count); 597 rport->up_write_pos = (rport->up_write_pos+1) % rport->buf_cnt; 598 599 return PJ_SUCCESS; 616 /* Put frame to delay buffer */ 617 return pjmedia_delay_buf_put(rport->buf[DIR_UPSTREAM].dbuf, 618 rport->tmp_up_buf); 600 619 } 601 620 602 621 … … 607 626 pjmedia_frame *frame) 608 627 { 609 628 struct reverse_port *rport = (struct reverse_port*) this_port; 610 unsigned count;611 629 612 count = rport->base.info.samples_per_frame; 630 /* Update state */ 631 op_update(rport, DIR_DOWNSTREAM, OP_GET); 613 632 633 /* Return no frame if media flow on this direction is being 634 * paused. 635 */ 636 if (rport->buf[DIR_DOWNSTREAM].paused) { 637 frame->type = PJMEDIA_FRAME_TYPE_NONE; 638 return PJ_SUCCESS; 639 } 640 641 /* Get frame from delay buffer */ 614 642 frame->size = this_port->info.bytes_per_frame; 615 643 frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 644 frame->timestamp.u64 = rport->buf[DIR_DOWNSTREAM].ts.u64; 616 645 617 /* Check for underflows */ 618 if (rport->dn_read_pos == rport->dn_write_pos) { 619 620 /* Only report underflow if the buffer is constantly filled 621 * up at the other side. 622 * It is possible that nobody writes the buffer, so causing 623 * underflow to happen rapidly, and writing log message this 624 * way does not seem to be wise. 625 */ 626 if (rport->dn_write_pos != rport->dn_underflow_pos) { 627 rport->dn_underflow_pos = rport->dn_write_pos; 628 LOG_DN_((THIS_FILE, "Underflow in downstream direction")); 629 } 630 631 /* Adjust read position */ 632 rport->dn_read_pos = 633 (rport->dn_write_pos - rport->buf_cnt/2) % rport->buf_cnt; 634 635 } 636 637 /* Get the samples from the circular buffer */ 638 pjmedia_copy_samples((pj_int16_t*)frame->buf, 639 rport->dnstream_buf[rport->dn_read_pos], 640 count); 641 rport->dn_read_pos = (rport->dn_read_pos+1) % rport->buf_cnt; 642 643 return PJ_SUCCESS; 646 return pjmedia_delay_buf_get(rport->buf[DIR_DOWNSTREAM].dbuf, 647 (short*)frame->buf); 644 648 } 645 649 646 650 647 651 static pj_status_t rport_on_destroy(pjmedia_port *this_port) 648 652 { 649 /* Nothing to do */ 650 PJ_UNUSED_ARG(this_port); 653 struct reverse_port *rport = (struct reverse_port*) this_port; 651 654 655 pjmedia_delay_buf_destroy(rport->buf[DIR_DOWNSTREAM].dbuf); 656 pjmedia_delay_buf_destroy(rport->buf[DIR_UPSTREAM].dbuf); 657 652 658 return PJ_SUCCESS; 653 659 } 654 660