Beispiel #1
0
static pj_status_t play_cb(void *user_data, pjmedia_frame *frame)
{
    struct test_data *test_data = (struct test_data *)user_data;
    struct stream_data *strm_data = &test_data->playback_data;

    pj_mutex_lock(test_data->mutex);

    /* Skip frames when test is not started or test has finished */
    if (!test_data->running) {
	pj_bzero(frame->buf, frame->size);
	pj_mutex_unlock(test_data->mutex);
	return PJ_SUCCESS;
    }

    /* Save last timestamp seen (to calculate drift) */
    strm_data->last_timestamp = frame->timestamp.u32.lo;

    if (strm_data->last_called.u64 == 0) {
	/* Init vars. */
	pj_get_timestamp(&strm_data->last_called);
	pj_math_stat_init(&strm_data->delay);
	strm_data->first_timestamp = frame->timestamp.u32.lo;
    } else {
	pj_timestamp now;
	unsigned delay;

	/* Calculate frame interval */
	pj_get_timestamp(&now);
	delay = pj_elapsed_usec(&strm_data->last_called, &now);
	strm_data->last_called = now;

	/* Update frame interval statistic */
	pj_math_stat_update(&strm_data->delay, delay);
    }

    pj_bzero(frame->buf, frame->size);

    pj_mutex_unlock(test_data->mutex);

    return PJ_SUCCESS;
}
Beispiel #2
0
PJ_DEF(void) pjmedia_rtcp_rx_rtp2(pjmedia_rtcp_session *sess, 
				  unsigned seq, 
				  unsigned rtp_ts,
				  unsigned payload,
				  pj_bool_t discarded)
{   
    pj_timestamp ts;
    pj_uint32_t arrival;
    pj_int32_t transit;
    pjmedia_rtp_status seq_st;
    unsigned last_seq;

#if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0)
    PJ_UNUSED_ARG(discarded);
#endif

    if (sess->stat.rx.pkt == 0) {
	/* Init sequence for the first time. */
	pjmedia_rtp_seq_init(&sess->seq_ctrl, (pj_uint16_t)seq);
    } 

    sess->stat.rx.pkt++;
    sess->stat.rx.bytes += payload;

    /* Process the RTP packet. */
    last_seq = sess->seq_ctrl.max_seq;
    pjmedia_rtp_seq_update(&sess->seq_ctrl, (pj_uint16_t)seq, &seq_st);

    if (seq_st.status.flag.restart) {
	rtcp_init_seq(sess);
    }
    
    if (seq_st.status.flag.dup) {
	sess->stat.rx.dup++;
	TRACE_((sess->name, "Duplicate packet detected"));
    }

    if (seq_st.status.flag.outorder && !seq_st.status.flag.probation) {
	sess->stat.rx.reorder++;
	TRACE_((sess->name, "Out-of-order packet detected"));
    }

    if (seq_st.status.flag.bad) {
	sess->stat.rx.discard++;

#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
	pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
			       -1,				 /* lost    */
			       (seq_st.status.flag.dup? 1:0),	 /* dup     */
			       (!seq_st.status.flag.dup? 1:-1),  /* discard */
			       -1,				 /* jitter  */
			       -1, 0);				 /* toh	    */
#endif

	TRACE_((sess->name, "Bad packet discarded"));
	return;
    }

    /* Only mark "good" packets */
    ++sess->received;

    /* Calculate loss periods. */
    if (seq_st.diff > 1) {
	unsigned count = seq_st.diff - 1;
	unsigned period;

	period = count * sess->pkt_size * 1000 / sess->clock_rate;
	period *= 1000;

	/* Update packet lost. 
	 * The packet lost number will also be updated when we're sending
	 * outbound RTCP RR.
	 */
	sess->stat.rx.loss += (seq_st.diff - 1);
	TRACE_((sess->name, "%d packet(s) lost", seq_st.diff - 1));

	/* Update loss period stat */
	pj_math_stat_update(&sess->stat.rx.loss_period, period);
    }


    /*
     * Calculate jitter only when sequence is good (see RFC 3550 section A.8),
     * AND only when the timestamp is different than the last packet
     * (see RTP FAQ).
     */
    if (seq_st.diff == 1 && rtp_ts != sess->rtp_last_ts) {
	/* Get arrival time and convert timestamp to samples */
	pj_get_timestamp(&ts);
	ts.u64 = ts.u64 * sess->clock_rate / sess->ts_freq.u64;
	arrival = ts.u32.lo;

	transit = arrival - rtp_ts;
    
	/* Ignore the first N packets as they normally have bad jitter
	 * due to other threads working to establish the call
	 */
	if (sess->transit == 0 || 
	    sess->received < PJMEDIA_RTCP_IGNORE_FIRST_PACKETS) 
	{
	    sess->transit = transit;
	    sess->stat.rx.jitter.min = (unsigned)-1;
	} else {
	    pj_int32_t d;
	    pj_uint32_t jitter;
	    
	    d = transit - sess->transit;
	    sess->transit = transit;
	    if (d < 0) 
		d = -d;
	    
	    sess->jitter += d - ((sess->jitter + 8) >> 4);

	    /* Get jitter in usec */
	    if (d < 4294)
		jitter = d * 1000000 / sess->clock_rate;
	    else {
		jitter = d * 1000 / sess->clock_rate;
		jitter *= 1000;
	    }

	    /* Update jitter stat */
	    pj_math_stat_update(&sess->stat.rx.jitter, jitter);

#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
	    pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
				   0,			    /* lost    */
				   0,			    /* dup     */
				   discarded,		    /* discard */
				   (sess->jitter >> 4),	    /* jitter  */
				   -1, 0);		    /* toh     */
#endif
	}
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
    } else if (seq_st.diff > 1) {
Beispiel #3
0
static void jbuf_calculate_jitter(pjmedia_jbuf *jb)
{
    int diff, cur_size;

    cur_size = jb_framelist_eff_size(&jb->jb_framelist);
    pj_math_stat_update(&jb->jb_burst, jb->jb_level);
    jb->jb_max_hist_level = PJ_MAX(jb->jb_max_hist_level, jb->jb_level);

    /* Burst level is decreasing */
    if (jb->jb_level < jb->jb_eff_level) {

	enum { STABLE_HISTORY_LIMIT = 20 };
        
	jb->jb_stable_hist++;
        
	/* Only update the effective level (and prefetch) if 'stable' 
	 * condition is reached (not just short time impulse)
	 */
	if (jb->jb_stable_hist > STABLE_HISTORY_LIMIT) {
    	
	    diff = (jb->jb_eff_level - jb->jb_max_hist_level) / 3;

	    if (diff < 1)
		diff = 1;

	    /* Update effective burst level */
	    jb->jb_eff_level -= diff;

	    /* Update prefetch based on level */
	    if (jb->jb_init_prefetch) {
		jb->jb_prefetch = jb->jb_eff_level;
		if (jb->jb_prefetch < jb->jb_min_prefetch) 
		    jb->jb_prefetch = jb->jb_min_prefetch;
	    }

	    /* Reset history */
	    jb->jb_max_hist_level = 0;
	    jb->jb_stable_hist = 0;

	    TRACE__((jb->jb_name.ptr,"jb updated(1), lvl=%d pre=%d, size=%d",
		     jb->jb_eff_level, jb->jb_prefetch, cur_size));
	}
    }

    /* Burst level is increasing */
    else if (jb->jb_level > jb->jb_eff_level) {

	/* Instaneous set effective burst level to recent maximum level */
	jb->jb_eff_level = PJ_MIN(jb->jb_max_hist_level,
				  (int)(jb->jb_max_count*4/5));

	/* Update prefetch based on level */
	if (jb->jb_init_prefetch) {
	    jb->jb_prefetch = jb->jb_eff_level;
	    if (jb->jb_prefetch > jb->jb_max_prefetch)
		jb->jb_prefetch = jb->jb_max_prefetch;
	}

	jb->jb_stable_hist = 0;
	/* Do not reset max_hist_level. */
	//jb->jb_max_hist_level = 0;

	TRACE__((jb->jb_name.ptr,"jb updated(2), lvl=%d pre=%d, size=%d", 
		 jb->jb_eff_level, jb->jb_prefetch, cur_size));
    }

    /* Level is unchanged */
    else {
	jb->jb_stable_hist = 0;
    }
}
Beispiel #4
0
/*
 * Get frame from jitter buffer.
 */
PJ_DEF(void) pjmedia_jbuf_get_frame3(pjmedia_jbuf *jb, 
				     void *frame, 
				     pj_size_t *size,
				     char *p_frame_type,
				     pj_uint32_t *bit_info,
				     pj_uint32_t *ts,
				     int *seq)
{
    if (jb->jb_prefetching) {

	/* Can't return frame because jitter buffer is filling up
	 * minimum prefetch.
	 */

	//pj_bzero(frame, jb->jb_frame_size);
	*p_frame_type = PJMEDIA_JB_ZERO_PREFETCH_FRAME;
	if (size)
	    *size = 0;

	TRACE__((jb->jb_name.ptr, "GET prefetch_cnt=%d/%d",
		 jb_framelist_eff_size(&jb->jb_framelist), jb->jb_prefetch));

	jb->jb_empty++;

    } else {

	pjmedia_jb_frame_type ftype = PJMEDIA_JB_NORMAL_FRAME;
	pj_bool_t res;

	/* Try to retrieve a frame from frame list */
	res = jb_framelist_get(&jb->jb_framelist, frame, size, &ftype, 
			       bit_info, ts, seq);
	if (res) {
	    /* We've successfully retrieved a frame from the frame list, but
	     * the frame could be a blank frame!
	     */
	    if (ftype == PJMEDIA_JB_NORMAL_FRAME) {
		*p_frame_type = PJMEDIA_JB_NORMAL_FRAME;
	    } else {
		*p_frame_type = PJMEDIA_JB_MISSING_FRAME;
		jb->jb_lost++;
	    }

	    /* Store delay history at the first GET */
	    if (jb->jb_last_op == JB_OP_PUT) {
		unsigned cur_size;

		/* We've just retrieved one frame, so add one to cur_size */
		cur_size = jb_framelist_eff_size(&jb->jb_framelist) + 1;
		pj_math_stat_update(&jb->jb_delay, 
				    cur_size*jb->jb_frame_ptime);
	    }
	} else {
	    /* Jitter buffer is empty */
	    if (jb->jb_prefetch)
		jb->jb_prefetching = PJ_TRUE;

	    //pj_bzero(frame, jb->jb_frame_size);
	    *p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
	    if (size)
		*size = 0;

	    jb->jb_empty++;
	}
    }

    jb->jb_level++;
    jbuf_update(jb, JB_OP_GET);
}