/*
 * simulate_lost() is called to simulate packet lost
 */
static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
        pjmedia_dir dir,
        unsigned pct_lost)
{
    struct tp_adapter *adapter = (struct tp_adapter*)tp;
    return pjmedia_transport_simulate_lost(adapter->slave_tp, dir, pct_lost);
}
Exemple #2
0
static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
					   pjmedia_dir dir,
					   unsigned pct_lost)
{
    transport_srtp *srtp = (transport_srtp *) tp;

    return pjmedia_transport_simulate_lost(srtp->member_tp, dir, pct_lost);
}
Exemple #3
0
static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
					   pjmedia_dir dir,
					   unsigned pct_lost)
{
    transport_srtp *srtp = (transport_srtp *) tp;
    
    PJ_ASSERT_RETURN(tp, PJ_EINVAL);

    return pjmedia_transport_simulate_lost(srtp->member_tp, dir, pct_lost);
}
Exemple #4
0
/*
 * simulate_lost() is called to simulate packet lost
 */
static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
        pjmedia_dir dir,
        unsigned pct_lost)
{
    struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;

    PJ_ASSERT_RETURN(tp, PJ_EINVAL);

    return pjmedia_transport_simulate_lost(zrtp->slave_tp, dir, pct_lost);
}
Exemple #5
0
/* This is the transmission "tick".
 * This function is called periodically every "tick" milliseconds, and
 * it will determine whether to transmit packet(s) (or to drop it).
 */
static void tx_tick(const pj_time_val *t)
{
    struct stream *strm = g_app.tx;
    static char log_msg[120];
    pjmedia_port *port = g_app.tx->port;
    long pkt_interval; 

    /* packet interval, without jitter */
    pkt_interval = PJMEDIA_PIA_SPF(&port->info) * 1000 /
		   PJMEDIA_PIA_SRATE(&port->info);

    while (PJ_TIME_VAL_GTE(*t, strm->state.tx.next_schedule)) {
	struct log_entry entry;
	pj_bool_t drop_this_pkt = PJ_FALSE;
	int jitter;

	/* Init log entry */
	pj_bzero(&entry, sizeof(entry));
	entry.wall_clock = *t;

	/* 
	 * Determine whether to drop this packet 
	 */
	if (strm->state.tx.cur_lost_burst) {
	    /* We are currently dropping packet */

	    /* Make it comply to minimum lost burst */
	    if (strm->state.tx.cur_lost_burst < g_app.cfg.tx_min_lost_burst) {
		drop_this_pkt = PJ_TRUE;
	    }

	    /* Correlate the next packet loss */
	    if (!drop_this_pkt && 
		strm->state.tx.cur_lost_burst < g_app.cfg.tx_max_lost_burst &&
		MAX(strm->state.tx.total_lost-LOSS_EXTRA,0) * 100 / MAX(strm->state.tx.total_tx,1) < g_app.cfg.tx_pct_avg_lost
	       ) 
	    {
		strm->state.tx.drop_prob = ((g_app.cfg.tx_pct_loss_corr * strm->state.tx.drop_prob) +
					     ((100-g_app.cfg.tx_pct_loss_corr) * (pj_rand()%100))
					   ) / 100;
		if (strm->state.tx.drop_prob >= 100)
		    strm->state.tx.drop_prob = 99;

		if (strm->state.tx.drop_prob >= 100 - g_app.cfg.tx_pct_avg_lost)
		    drop_this_pkt = PJ_TRUE;
	    }
	}

	/* If we're not dropping packet then use randomly distributed loss */
	if (!drop_this_pkt &&
	    MAX(strm->state.tx.total_lost-LOSS_EXTRA,0) * 100 / MAX(strm->state.tx.total_tx,1) < g_app.cfg.tx_pct_avg_lost)
	{
	    strm->state.tx.drop_prob = pj_rand() % 100;

	    if (strm->state.tx.drop_prob >= 100 - g_app.cfg.tx_pct_avg_lost)
		drop_this_pkt = PJ_TRUE;
	}

	if (drop_this_pkt) {
	    /* Drop the frame */
	    pjmedia_transport_simulate_lost(g_app.loop, PJMEDIA_DIR_ENCODING, 100);
	    run_one_frame(g_app.tx_wav, g_app.tx->port, NULL);
	    pjmedia_transport_simulate_lost(g_app.loop, PJMEDIA_DIR_ENCODING, 0);

	    entry.event = EVENT_TX_DROP;
	    entry.log = "** This packet was lost **";

	    ++strm->state.tx.total_lost;
	    ++strm->state.tx.cur_lost_burst;

	} else {
	    pjmedia_rtcp_stat stat;
	    pjmedia_jb_state jstate;
	    unsigned last_discard;

	    pjmedia_stream_get_stat_jbuf(g_app.rx->strm, &jstate);
	    last_discard = jstate.discard;

	    run_one_frame(g_app.tx_wav, g_app.tx->port, NULL);

	    pjmedia_stream_get_stat(g_app.rx->strm, &stat);
	    pjmedia_stream_get_stat_jbuf(g_app.rx->strm, &jstate);

	    entry.event = EVENT_TX;
	    entry.jb_state = &jstate;
	    entry.stat = &stat;
	    entry.log = log_msg;

	    if (jstate.discard > last_discard)
		strcat(log_msg, "** Note: packet was discarded by jitter buffer **");

	    strm->state.tx.cur_lost_burst = 0;
	}

	write_log(&entry, PJ_TRUE);

	++strm->state.tx.total_tx;

	/* Calculate next schedule */
	strm->state.tx.next_schedule.sec = 0;
	strm->state.tx.next_schedule.msec = (strm->state.tx.total_tx + 1) * pkt_interval;

	/* Apply jitter */
	if (g_app.cfg.tx_max_jitter || g_app.cfg.tx_min_jitter) {

	    if (g_app.cfg.tx_max_jitter == g_app.cfg.tx_min_jitter) {
		/* Fixed jitter */
		switch (pj_rand() % 3) {
		case 0:
		    jitter = 0 - g_app.cfg.tx_min_jitter;
		    break;
		case 2:
		    jitter = g_app.cfg.tx_min_jitter;
		    break;
		default:
		    jitter = 0;
		    break;
		}
	    } else {
		int jitter_range;
		jitter_range = (g_app.cfg.tx_max_jitter-g_app.cfg.tx_min_jitter)*2;
		jitter = pj_rand() % jitter_range;
		if (jitter < jitter_range/2) {
		    jitter = 0 - g_app.cfg.tx_min_jitter - (jitter/2);
		} else {
		    jitter = g_app.cfg.tx_min_jitter + (jitter/2);
		}
	    }

	} else {
	    jitter = 0;
	}

	pj_time_val_normalize(&strm->state.tx.next_schedule);

	sprintf(log_msg, "** Packet #%u tick is at %d.%03d, %d ms jitter applied **", 
		strm->state.tx.total_tx+1,
		(int)strm->state.tx.next_schedule.sec, (int)strm->state.tx.next_schedule.msec,
		jitter);

	strm->state.tx.next_schedule.msec += jitter;
	pj_time_val_normalize(&strm->state.tx.next_schedule);

    } /* while */
}