예제 #1
0
/* 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)));
    }
}
예제 #2
0
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));
    }
예제 #3
0
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;
}