/* This function will erase samples from delay buffer. * The number of erased samples is guaranteed to be >= erase_cnt. */ static void shrink_buffer(pjmedia_delay_buf *b, unsigned erase_cnt) { pj_int16_t *buf1, *buf2; unsigned buf1len; unsigned buf2len; pj_status_t status; pj_assert(b && erase_cnt && pjmedia_circ_buf_get_len(b->circ_buf)); pjmedia_circ_buf_get_read_regions(b->circ_buf, &buf1, &buf1len, &buf2, &buf2len); status = pjmedia_wsola_discard(b->wsola, buf1, buf1len, buf2, buf2len, &erase_cnt); if ((status == PJ_SUCCESS) && (erase_cnt > 0)) { /* WSOLA discard will manage the first buffer to be full, unless * erase_cnt is greater than second buffer length. So it is safe * to just set the circular buffer length. */ pjmedia_circ_buf_set_len(b->circ_buf, pjmedia_circ_buf_get_len(b->circ_buf) - erase_cnt); PJ_LOG(5,(b->obj_name,"%d samples reduced, buf_cnt=%d", erase_cnt, pjmedia_circ_buf_get_len(b->circ_buf))); } }
static void update(pjmedia_delay_buf *b, enum OP op) { /* Sequential operation */ if (op == b->last_op) { ++b->level; return; } /* Switching operation */ if (b->level > b->max_level) b->max_level = b->level; b->recalc_timer -= (b->level * b->ptime) >> 1; b->last_op = op; b->level = 1; /* Recalculate effective count based on max_level */ if (b->recalc_timer <= 0) { unsigned new_eff_cnt = (b->max_level+SAFE_MARGIN)*b->samples_per_frame; /* Smoothening effective count transition */ AGC(b->eff_cnt, new_eff_cnt); /* Make sure the new effective count is multiplication of * channel_count, so let's round it up. */ if (b->eff_cnt % b->channel_count) b->eff_cnt += b->channel_count - (b->eff_cnt % b->channel_count); TRACE__((b->obj_name,"Cur eff_cnt=%d", b->eff_cnt)); b->max_level = 0; b->recalc_timer = RECALC_TIME; } /* See if we need to shrink the buffer to reduce delay */ if (op == OP_PUT && pjmedia_circ_buf_get_len(b->circ_buf) > b->samples_per_frame + b->eff_cnt) { unsigned erase_cnt = b->samples_per_frame >> 1; unsigned old_buf_cnt = pjmedia_circ_buf_get_len(b->circ_buf); shrink_buffer(b, erase_cnt); PJ_LOG(4,(b->obj_name,"Buffer size adjusted from %d to %d (eff_cnt=%d)", old_buf_cnt, pjmedia_circ_buf_get_len(b->circ_buf), b->eff_cnt)); }
static pj_status_t sp_put_frame( pjmedia_port *this_port, const pjmedia_frame *frame) { struct silence_port *sp = (struct silence_port*)this_port; unsigned frame_size = frame->size / sizeof(pj_uint16_t); unsigned samples_per_frame = sp->base.info.samples_per_frame; pj_int16_t tmp_buf[frame_size]; pjmedia_frame tmp_frame; pj_status_t status; PJ_LOG(6, (THIS_FILE, "packet: sz=%d ts=%llu", frame->size/sizeof(pj_uint16_t), frame->timestamp.u64)); PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE, PJ_EINVAL); if (frame->type == PJMEDIA_FRAME_TYPE_NONE ) { PJ_LOG(5, (THIS_FILE, "empty frame passed")); return pjmedia_port_put_frame(sp->dn_port, frame); } if (sp->frames == 0) { PJ_LOG(5, (THIS_FILE, "%u: this is first received frame, " "so just update last timestamp with its " "timestamp + size: %llu + %d", sp->frames, frame->timestamp.u64, samples_per_frame)); sp->last_ts.u64 = frame->timestamp.u64 + samples_per_frame; } else if (frame->timestamp.u64 == 0){ PJ_LOG(5, (THIS_FILE, "%u: frame timestamp is unknown, so increment " "by %d (samples per frame)", sp->frames, samples_per_frame)); sp->last_ts.u64 += samples_per_frame; } else if (frame->timestamp.u64 < sp->last_ts.u64 ){ PJ_LOG(5, (THIS_FILE, "%u: received frame timestamp is lesser than " "latest timestamp (%llu < %llu)", sp->frames, frame->timestamp.u64, sp->last_ts.u64)); sp->last_ts.u64 = frame->timestamp.u64 + samples_per_frame; } else if (frame->timestamp.u64 > sp->last_ts.u64){ unsigned zero_padding_count = frame->timestamp.u64 - sp->last_ts.u64; pj_int16_t zero_buf[zero_padding_count]; PJ_LOG(5, (THIS_FILE, "%u: received frame timestamp is greater than " "latest timestamp (%llu > %llu), fill output buffer with %d " "empty frames", sp->frames, frame->timestamp.u64, sp->last_ts.u64, zero_padding_count)); pj_bzero(zero_buf, sizeof(zero_buf)); pjmedia_circ_buf_write(sp->buf, zero_buf, zero_padding_count); PJ_LOG(6, (THIS_FILE, "write in circ buf %u zeros", zero_padding_count)); sp->last_ts.u64 = frame->timestamp.u64 + samples_per_frame; } else { sp->last_ts.u64 += samples_per_frame; } pjmedia_circ_buf_write(sp->buf, (pj_uint16_t*)frame->buf, frame_size); PJ_LOG(6, (THIS_FILE, "write in circ buf %u bytes", frame_size)); pj_memcpy(&tmp_frame, frame, sizeof(pjmedia_frame)); tmp_frame.buf = (void*)tmp_buf; sp->frames ++; /* put everything saved into buffer FIXME: wrong timestamps. Fortunately, wav writer don't care about timestamps */ while (pjmedia_circ_buf_get_len(sp->buf) >= frame_size){ pjmedia_circ_buf_read(sp->buf, tmp_buf, frame_size); PJ_LOG(6, (THIS_FILE, "read from circ buf %u bytes", frame_size)); status = pjmedia_port_put_frame(sp->dn_port, &tmp_frame); if (status != PJ_SUCCESS) return status; } return PJ_SUCCESS; }