Commit 8b6bc608 authored by Simon Morlat's avatar Simon Morlat

merge patch bringing new statistics computations, and round trip delay computation.

parent e82ae8b6
......@@ -200,6 +200,7 @@ struct _RtpSession;
void rtp_session_rtcp_process_send(struct _RtpSession *s);
void rtp_session_rtcp_process_recv(struct _RtpSession *s);
#define RTCP_DEFAULT_REPORT_INTERVAL 5
......
......@@ -72,8 +72,16 @@ typedef struct rtp_stats
uint64_t cum_packet_loss; /* cumulative number of packet lost */
uint64_t bad; /* packets that did not appear to be RTP */
uint64_t discarded; /* incoming packets discarded because the queue exceeds its max size */
uint64_t sent_rtcp_packets; /* sent RTCP packets counter (only packets that embed a report block are considered) */
} rtp_stats_t;
typedef struct jitter_stats
{
uint64_t sum_jitter; /* sum of all interarrival jitter (value in stream clock unit) */
uint64_t max_jitter; /* biggest interarrival jitter (value in stream clock unit) */
uint64_t max_jitter_ts; /* date (in ms since Epoch) of the biggest interarrival jitter */
} jitter_stats_t;
#define RTP_TIMESTAMP_IS_NEWER_THAN(ts1,ts2) \
((uint32_t)((uint32_t)(ts1) - (uint32_t)(ts2))< (uint32_t)(1<<31))
......
......@@ -148,6 +148,7 @@ typedef struct _RtpStream
int snd_socket_size;
int rcv_socket_size;
int ssrc_changed_thres;
jitter_stats_t jitter_stats;
}RtpStream;
typedef struct _RtcpStream
......@@ -217,6 +218,10 @@ struct _RtpSession
mblk_t *current_tev; /* the pending telephony events */
mblk_t *sd;
queue_t contributing_sources;
unsigned int lost_packets_test_vector;
unsigned int interarrival_jitter_test_vector;
unsigned int delay_test_vector;
int rtt;/*last round trip delay calculated*/
bool_t symmetric_rtp;
bool_t permissive; /*use the permissive algorithm*/
bool_t use_connect; /* use connect() on the socket */
......@@ -336,6 +341,7 @@ void rtp_session_reset(RtpSession *session);
void rtp_session_destroy(RtpSession *session);
const rtp_stats_t * rtp_session_get_stats(const RtpSession *session);
const jitter_stats_t * rtp_session_get_jitter_stats( const RtpSession *session );
void rtp_session_reset_stats(RtpSession *session);
void rtp_session_set_data(RtpSession *session, void *data);
......@@ -371,6 +377,13 @@ void rtp_session_clear_send_error_code(RtpSession *session);
int rtp_session_get_last_recv_error_code(RtpSession *session);
void rtp_session_clear_recv_error_code(RtpSession *session);
int rtp_session_get_round_trip_propagation(RtpSession *session);
void rtp_session_rtcp_set_lost_packet_value( RtpSession *session, const unsigned int value );
void rtp_session_rtcp_set_jitter_value(RtpSession *session, const unsigned int value );
void rtp_session_rtcp_set_delay_value(RtpSession *session, const unsigned int value );
/*private */
void rtp_session_init(RtpSession *session, int mode);
#define rtp_session_set_flag(session,flag) (session)->flags|=(flag)
......
......@@ -59,14 +59,15 @@ void jitter_control_enable_adaptive(JitterControl *ctl, bool_t val){
void jitter_control_set_payload(JitterControl *ctl, PayloadType *pt){
ctl->jitt_comp_ts =
(int) (((double) ctl->jitt_comp / 1000.0) * (pt->clock_rate));
ctl->corrective_step=(160 * 8000 )/pt->clock_rate; /* This formula got to me after some beers */
/*make correction by not less than 10ms */
ctl->corrective_step=(int) (0.01 * (float)pt->clock_rate);
ctl->adapt_jitt_comp_ts=ctl->jitt_comp_ts;
}
void jitter_control_dump_stats(JitterControl *ctl){
ortp_message("JitterControl:\n\tslide=%g,jitter=%g,count=%i",
(double)ctl->slide,ctl->jitter, ctl->count);
ortp_message("JitterControl:\n\tslide=%g,jitter=%g,adapt_jitt_comp_ts=%i,corrective_slide=%i, count=%i",
(double)ctl->slide,ctl->jitter, ctl->adapt_jitt_comp_ts, ctl->corrective_slide,ctl->count);
}
/*the goal of this method is to compute "corrective_slide": a timestamp unit'd value to be added
......@@ -112,10 +113,9 @@ void jitter_control_new_packet(JitterControl *ctl, uint32_t packet_ts, uint32_t
ctl->olddiff=diff;
ctl->count++;
if (ctl->adaptive){
if (ctl->count%50==0) {
ctl->adapt_jitt_comp_ts=(int) MAX(ctl->jitt_comp_ts,2*ctl->jitter);
/*jitter_control_dump_stats(ctl);*/
//jitter_control_dump_stats(ctl);
}
ctl->slide=slide;
......
......@@ -34,8 +34,9 @@ void jitter_control_new_packet(JitterControl *ctl, uint32_t packet_ts, uint32_t
#define jitter_control_adaptive_enabled(ctl) ((ctl)->adaptive)
void jitter_control_set_payload(JitterControl *ctl, PayloadType *pt);
void jitter_control_update_corrective_slide(JitterControl *ctl);
static inline uint32_t jitter_control_get_compensated_timestamp(JitterControl *obj , uint32_t user_ts){
return user_ts+obj->slide-obj->adapt_jitt_comp_ts;
return (uint32_t)( (int64_t)user_ts+obj->slide-(int64_t)obj->adapt_jitt_comp_ts);
}
#endif
......@@ -300,9 +300,6 @@ void rtp_stats_display(const rtp_stats_t *stats, const char *header)
ortp_log(ORTP_MESSAGE,
" number of incoming rtp bytes successfully delivered to the application=%lld ",
(long long)stats->recv);
ortp_log(ORTP_MESSAGE,
" number of times the application queried a packet that didn't exist=%lld ",
(long long)stats->unavaillable);
ortp_log(ORTP_MESSAGE,
" number of rtp packet lost=%lld",
(long long) stats->cum_packet_loss);
......@@ -334,9 +331,6 @@ void rtp_stats_display(const rtp_stats_t *stats, const char *header)
ortp_log(ORTP_MESSAGE,
" number of incoming rtp bytes successfully delivered to the application=%I64d ",
(uint64_t)stats->recv);
ortp_log(ORTP_MESSAGE,
" number of times the application queried a packet that didn't exist=%I64d ",
(uint64_t)stats->unavaillable);
ortp_log(ORTP_MESSAGE,
" number of rtp packet lost=%I64d",
(uint64_t) stats->cum_packet_loss);
......
......@@ -24,6 +24,9 @@
* Copyright 2004 Simon Morlat
* Email simon dot morlat at linphone dot org
****************************************************************************/
#include <math.h>
#include "ortp/ortp.h"
#include "ortp/rtpsession.h"
#include "ortp/rtcp.h"
......@@ -200,17 +203,21 @@ void rtp_session_remove_contributing_sources(RtpSession *session, uint32_t ssrc)
rtp_session_rtcp_send(session,tmp);
}
uint64_t ortp_timeval_to_ntp(const struct timeval *tv){
uint64_t msw;
uint64_t lsw;
msw=tv->tv_sec + 0x83AA7E80; /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
lsw=(uint32_t)((double)tv->tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6);
return msw<<32 | lsw;
}
static void sender_info_init(sender_info_t *info, RtpSession *session){
struct timeval tv;
uint32_t tmp;
uint64_t ntp;
gettimeofday(&tv,NULL);
info->ntp_timestamp_msw=htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
#if defined(_WIN32_WCE)
tmp=(uint32_t)((double)tv.tv_usec*(double)(((uint64_t)1)<<32)*1.0e-6);
#else
tmp=(uint32_t)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6);
#endif
info->ntp_timestamp_lsw=htonl(tmp);
ntp=ortp_timeval_to_ntp(&tv);
info->ntp_timestamp_msw=htonl(ntp >>32);
info->ntp_timestamp_lsw=htonl(ntp & 0xFFFFFFFF);
info->rtp_timestamp=htonl(session->rtp.snd_last_ts);
info->senders_packet_count=(uint32_t) htonl((u_long) session->rtp.stats.packet_sent);
info->senders_octet_count=(uint32_t) htonl((u_long) session->rtp.sent_payload_bytes);
......@@ -233,11 +240,22 @@ static void report_block_init(report_block_t *b, RtpSession *session){
stream->hwrcv_since_last_SR
);*/
if (stream->hwrcv_seq_at_last_SR!=0){
packet_loss=(stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR) - stream->hwrcv_since_last_SR;
if (packet_loss<0)
packet_loss=0;
stream->stats.cum_packet_loss+=packet_loss;
loss_fraction=(int)(256.0*(float)packet_loss/(float)stream->hwrcv_since_last_SR);
if ( session->flags & RTCP_OVERRIDE_LOST_PACKETS ) {
/* If the test mode is enabled, replace the lost packet field with the test vector value set by rtp_session_rtcp_set_lost_packet_value() */
packet_loss = session->lost_packets_test_vector;
if ( packet_loss < 0 )
packet_loss = 0;
/* The test value is the definite cumulative one, no need to increment it each time a packet is sent */
stream->stats.cum_packet_loss = packet_loss;
}
else {
/* Normal mode */
packet_loss = ( stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR ) - stream->hwrcv_since_last_SR;
if ( packet_loss < 0 )
packet_loss = 0;
stream->stats.cum_packet_loss += packet_loss;
}
loss_fraction=(int)( 256 * packet_loss) / stream->hwrcv_since_last_SR ;
}
/* reset them */
stream->hwrcv_since_last_SR=0;
......@@ -245,22 +263,59 @@ static void report_block_init(report_block_t *b, RtpSession *session){
if (stream->last_rcv_SR_time.tv_sec!=0){
struct timeval now;
float delay;
double delay;
gettimeofday(&now,NULL);
delay=(float) ((now.tv_sec-stream->last_rcv_SR_time.tv_sec)*1e6 ) + (now.tv_usec-stream->last_rcv_SR_time.tv_usec);
delay=(float) (delay*65536*1e-6);
delay= (now.tv_sec-stream->last_rcv_SR_time.tv_sec)+ ((now.tv_usec-stream->last_rcv_SR_time.tv_usec)*1e-6);
delay= (delay*65536);
delay_snc_last_sr=(uint32_t) delay;
}
b->ssrc=htonl(session->rcv.ssrc);
fl_cnpl=((loss_fraction&0xFF)<<24) | (stream->stats.cum_packet_loss & 0xFFFFFF);
b->fl_cnpl=htonl(fl_cnpl);
b->interarrival_jitter=htonl((uint32_t) stream->jittctl.inter_jitter);
if ( session->flags & RTCP_OVERRIDE_JITTER ) {
/* If the test mode is enabled, replace the interarrival jitter field with the test vector value set by rtp_session_rtcp_set_jitter_value() */
b->interarrival_jitter = htonl( session->interarrival_jitter_test_vector );
}
else {
/* Normal mode */
b->interarrival_jitter = htonl( (uint32_t) stream->jittctl.inter_jitter );
}
b->ext_high_seq_num_rec=htonl(stream->hwrcv_extseq);
b->lsr=htonl(stream->last_rcv_SR_ts);
b->delay_snc_last_sr=htonl(delay_snc_last_sr);
if ( session->flags & RTCP_OVERRIDE_DELAY ) {
/* If the test mode is enabled, modifies the returned ts (LSR) so it matches the value of the delay test value */
/* refer to the rtp_session_rtcp_set_delay_value() documentation for further explanations */
double new_ts = ( (double)stream->last_rcv_SR_time.tv_sec + (double)stream->last_rcv_SR_time.tv_usec * 1e-6 ) - ( (double)session->delay_test_vector / 1000.0 );
/* Converting the time format in RFC3550 (par. 4) format */
new_ts += 2208988800.0; /* 2208988800 is the number of seconds from 1900 to 1970 (January 1, Oh TU) */
new_ts = round( 65536.0 * new_ts );
/* This non-elegant way of coding fits with the gcc and the icc compilers */
uint32_t new_ts2 = (uint32_t)( (uint64_t)new_ts & 0xffffffff );
b->lsr = htonl( new_ts2 );
}
else {
/* Normal mode */
b->lsr = htonl( stream->last_rcv_SR_ts );
}
}
static void extended_statistics( RtpSession *session, report_block_t * rb ) {
session->rtp.stats.sent_rtcp_packets ++;
/* the jitter raw value is kept in stream clock units */
uint32_t jitter = ntohl( rb->interarrival_jitter );
session->rtp.jitter_stats.sum_jitter += jitter;
/* stores the biggest jitter for that session and its date (in millisecond) since Epoch */
if ( jitter > session->rtp.jitter_stats.max_jitter ) {
session->rtp.jitter_stats.max_jitter = jitter ;
struct timeval now;
gettimeofday( &now, NULL );
session->rtp.jitter_stats.max_jitter_ts = ( now.tv_sec * 1000 ) + ( now.tv_usec / 1000 );
}
}
static int rtcp_sr_init(RtpSession *session, uint8_t *buf, int size){
......@@ -272,8 +327,10 @@ static int rtcp_sr_init(RtpSession *session, uint8_t *buf, int size){
sr->ssrc=htonl(session->snd.ssrc);
sender_info_init(&sr->si,session);
/*only include a report block if packets were received*/
if (rr)
report_block_init(&sr->rb[0],session);
if (rr) {
report_block_init( &sr->rb[0], session );
extended_statistics( session, &sr->rb[0] );
}
return sr_size;
}
......@@ -283,6 +340,7 @@ static int rtcp_rr_init(RtpSession *session, uint8_t *buf, int size){
rtcp_common_header_init(&rr->ch,session,RTCP_RR,1,sizeof(rtcp_rr_t));
rr->ssrc=htonl(session->snd.ssrc);
report_block_init(&rr->rb[0],session);
extended_statistics( session, &rr->rb[0] );
return sizeof(rtcp_rr_t);
}
......
......@@ -338,204 +338,3 @@ void report_block_parse(RtpSession *session, report_block_t *rb, struct timeval
}
void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp)
{
rtcp_common_header_t *rtcp;
int msgsize;
int rtcp_pk_size;
RtpStream *rtpstream=&session->rtp;
struct timeval rcv_time_tv;
gettimeofday(&rcv_time_tv,NULL);
return_if_fail(mp!=NULL);
msgsize=(int) (mp->b_wptr-mp->b_rptr);
if (msgsize < RTCP_COMMON_HEADER_SIZE)
{
ortp_debug("Receiving too short rtcp packet... discarded");
return;
}
rtcp=(rtcp_common_header_t *)mp->b_rptr;
/* compound rtcp packet can be composed by more than one rtcp message */
while (msgsize >= RTCP_COMMON_HEADER_SIZE)
{
if (rtcp->version!=2)
{
ortp_debug("Receiving rtcp packet with version number !=2...discarded");
return;
}
/* convert header data from network order to host order */
rtcp->length = ntohs(rtcp->length);
/* compute length */
rtcp_pk_size = (rtcp->length + 1) * 4;
/* Sanity check of simple RTCP packet length. */
if (rtcp_pk_size > msgsize)
{
ortp_debug("Receiving rtcp packet shorter than the specified length.. discared");
return;
}
switch (rtcp->packet_type)
{
case RTCP_SR:
{
rtcp_sr_t *sr = (rtcp_sr_t *) rtcp;
report_block_t *rb;
int i;
if ( ntohl(sr->ssrc) != session->rcv.ssrc )
{
ortp_debug("Receiving rtcp sr packet from unknown ssrc.. discarded");
return;
}
if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + RTCP_SENDER_INFO_SIZE + (RTCP_REPORT_BLOCK_SIZE*sr->ch.rc))
{
ortp_debug("Receiving too short rtcp sr packet... discarded");
return;
}
/* parsing RTCP Sender Info */
sr->si.ntp_timestamp_msw = ntohl(sr->si.ntp_timestamp_msw);
sr->si.ntp_timestamp_lsw = ntohl(sr->si.ntp_timestamp_lsw);
sr->si.rtp_timestamp = ntohl(sr->si.rtp_timestamp);
sr->si.senders_packet_count = ntohl(sr->si.senders_packet_count);
sr->si.senders_octet_count = ntohl(sr->si.senders_octet_count);
/* saving data to fill LSR and DLSR field in next RTCP report to be transmitted */
rtpstream->last_rcv_SR_ts = (sr->si.ntp_timestamp_msw << 16) | (sr->si.ntp_timestamp_lsw >> 16);
rtpstream->last_rcv_SR_time.tv_usec = rcv_time_tv.tv_usec;
rtpstream->last_rcv_SR_time.tv_sec = rcv_time_tv.tv_sec;
/* parsing all RTCP report blocks */
for (i=0; i<sr->ch.rc; i++)
{
rb = &(sr->rb[i]);
report_block_parse(session, rb, rcv_time_tv);
}
}
break;
case RTCP_RR:
{
rtcp_rr_t *rr = (rtcp_rr_t *) rtcp;
report_block_t *rb;
int i;
if (session->rcv.ssrc == 0)
{
/* rcv.ssrc is not set, so we adopt the incoming one */
session->rcv.ssrc = ntohl(rr->ssrc);
}
else if ( ntohl(rr->ssrc) != session->rcv.ssrc )
{
ortp_debug("Receiving rtcp rr packet from unknown ssrc.. discarded");
return;
}
if (msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + (RTCP_REPORT_BLOCK_SIZE*rr->ch.rc))
{
ortp_debug("Receiving too short rtcp sr packet... discarded");
return;
}
/* parsing all RTCP report blocks */
for (i=0; i<rr->ch.rc; i++)
{
rb = &(rr->rb[i]);
report_block_parse(session, rb, rcv_time_tv);
}
}
break;
case RTCP_SDES:
/* to be implemented */
break;
case RTCP_BYE:
{
rtcp_bye_t *bye = (rtcp_bye_t *) rtcp;
unsigned sclen = bye->ch.rc * 4;
int reason_space_len = rtcp_pk_size
- sizeof (rtcp_common_header_t)
- sclen;
int i;
char *reason = NULL;
bool_t rcv_ssrc_match = FALSE;
if (reason_space_len < 0) {
ortp_debug("Receiving too short RTCP BYE packet... discarded");
return;
}
for (i = 0; i < bye->ch.rc; i++) {
if (ntohl(bye->ssrc[i]) == session->rcv.ssrc) {
rcv_ssrc_match = TRUE;
break;
}
}
if (rcv_ssrc_match) {
if (session->on_rtcp_bye.count > 0) {
/* Get reason. */
if (reason_space_len > 1) {
uint8_t *reasonbuf = (uint8_t *) rtcp
+ sizeof (rtcp_common_header_t)
+ sclen;
if (reasonbuf[0] <= reason_space_len-1)
reason = ortp_strndup((char *)(reasonbuf+1), reasonbuf[0]);
else
ortp_debug("Incorrect RTCP BYE reason length");
}
rtp_signal_table_emit2(&session->on_rtcp_bye,
(long)reason);
if (reason)
ortp_free(reason);
} else {
ortp_debug("Got RTCP BYE without RTCP BYE handler");
}
} else {
ortp_debug("No SSRC in the BYE packet matched our rcv.ssrc.");
}
break;
}
case RTCP_APP:
/* to be implemented */
break;
default:
ortp_debug("Receiving unknown rtcp packet type... discarded");
return;
}
msgsize -= rtcp_pk_size; /* size of unparsed portion of UDP packet, in octets */
rtcp = (rtcp_common_header_t *) (rtcp_pk_size + (char *) rtcp); /* pointer to next RTCP packet in current UDP packet */
}
/* The function did not failed sanity checks, write down the RTPC/RTCP
reception time. */
session->last_recv_time = rcv_time_tv;
}
......@@ -1439,6 +1439,63 @@ const rtp_stats_t * rtp_session_get_stats(const RtpSession *session){
return &session->rtp.stats;
}
/**
* Retrieves the session's jitter specific statistics.
**/
const jitter_stats_t * rtp_session_get_jitter_stats( const RtpSession *session ) {
return &session->rtp.jitter_stats;
}
/**
* @brief For <b>test purpose only</b>, sets a constant lost packet value within <b>all</b> RTCP output packets.@n
*
* The SR or RR RTCP packet contain a lost packet field. After this procedure is called, the lost packet field will be set to a constant value in all output SR or RR packets. This parameter will overridden the actual number of lost packets in the input RTP stream that the RTCP stack had previously processed.
* @param s : the rtp session.
* @param value : the lost packets test vector value.
**/
void rtp_session_rtcp_set_lost_packet_value( struct _RtpSession *s, const unsigned int value ) {
s->lost_packets_test_vector = value;
s->flags|=RTCP_OVERRIDE_LOST_PACKETS;
}
/**
* @brief For <b>test purpose only</b>, sets a constant interarrival_jitter value within <b>all</b> RTCP output packets.@n
*
* The SR or RR RTCP packet contain an interarrival jitter field. After this procedure is called, the interarrival jitter field will be set to a constant value in all output SR or RR packets. This parameter will overridden the actual interarrival jitter value that was processed by the RTCP stack.
* @param s : the rtp session.
* @param value : the interarrival jitter test vector value.
**/
void rtp_session_rtcp_set_jitter_value( struct _RtpSession *s, const unsigned int value ) {
s->interarrival_jitter_test_vector = value;
s->flags|=RTCP_OVERRIDE_JITTER;
}
/**
* @brief For <b>test purpose only</b>, simulates a constant RTT (Round Trip Time) value by setting the LSR field within <b>all</b> returned RTCP output packets.@n
*
* The RTT processing involves two RTCP packets exchanged between two different devices.@n
* In a <b>normal</b> operation the device 1 issues a SR packets at time T0, hence this packet has a timestamp field set to T0.
* The LSR and DLSR fiels of that packet are not considered here. This packet is received by the Device 2 at T1.
* In response, the Device 2 issues another SR or RR packets at T2 with the following fields;
* - a timestamp set to T2.
* - a LSR (Last SR packet timestamp) field set to T0 ( this value has been extracted from the first packet).
* - a DLSR (Delay since Last SR packet) field set to (T2 - T1).
* .
* This packet is received by The Device 1 at T3. So the Device 1 is now able to process the RTT using the formula :
* RTT = T3 - LSR - DLSR = (T1 - T0) - (T3 - T2).@n
* This way of processing is described in par. 6.4 of the RFC3550 standard.
*
* In the <b>test</b> mode that is enabled by this procedure, the RTCP stack is considered as beeing part of the device 2. For setting the RTT to a constant RTT0 value, the Device 2 artificially sets the LSR field of the second packet to (T1 - RTT0), instead of T0 in normal mode. The two other fields (timestamp and DLSR) are set as in the normal mode. So the Device 1 will process :
* RTT = T3 - LSR - DLSR = RTT0 + (T3 - T2) that is near to RTT0 is T3 - T2 is small enough.
* @note It is impossible to actually make the mesured RTT strictly equal to RTT0, as the packet trip time (T3 - T2) is unknown when this packet is issued by the Device 2.
* @param s : the rtp session.
* @param value : The desired RTT test vector value (RTT0).
**/
void rtp_session_rtcp_set_delay_value( struct _RtpSession *s, const unsigned int value ) {
s->delay_test_vector= value;
s->flags|=RTCP_OVERRIDE_DELAY;
}
void rtp_session_reset_stats(RtpSession *session){
memset(&session->rtp.stats,0,sizeof(rtp_stats_t));
}
......@@ -1536,6 +1593,21 @@ void rtp_session_clear_recv_error_code(RtpSession *session){
session->rtp.send_errno=0;
}
/**
* Returns the last known round trip propagation delay.
*
* This value is known after successful RTCP SR or RR exchanged between a sender and a receiver.
* oRTP automatically takes care of sending SR or RR packets.
* You might want to call this function when you receive an RTCP event (see rtp_session_register_event_queue() ).
* This value might not be known: at the beginning when no RTCP packets have been exchanged yet, or simply because the
* rtcp channel is broken due to firewall problematics, or because the remote implementation does not support RTCP.
*
* @returns the round trip propagation time in milliseconds if known, -1 if unknown.
**/
int rtp_session_get_round_trip_propagation(RtpSession *session){
return session->rtt;
}
/**
* Destroys a rtp session.
* All memory allocated for the RtpSession is freed.
......
......@@ -1027,6 +1027,92 @@ void rtp_session_notify_inc_rtcp(RtpSession *session, mblk_t *m){
else freemsg(m); /* avoid memory leak */
}
static void compute_rtt(RtpSession *session, rtcp_sr_t *sr){
RtpStream * rtpstream = &session->rtp;
uint64_t curntp=ortp_timeval_to_ntp(&rtpstream->last_rcv_SR_time);
uint32_t approx_ntp=(curntp>>16) & 0xFFFFFFFF;
uint32_t last_sr_time=report_block_get_last_SR_time(&sr->rb[0]);
uint32_t sr_delay=report_block_get_last_SR_delay(&sr->rb[0]);
/*ortp_message("rtt curntp=%u, last_sr_time=%u, sr_delay=%u",approx_ntp,last_sr_time,sr_delay);*/
if (last_sr_time!=0 && sr_delay!=0){
double rtt_frac=approx_ntp-last_sr_time-sr_delay;
rtt_frac/=65536.0;
/*express the result in milliseconds*/
session->rtt=rtt_frac/1000.0;
/*ortp_message("rtt estimated to %i ms",session->rtt);*/
}
}
/*
* @brief : for SR packets, retrieves their timestamp, gets the date, and stores these information into the session descriptor. The date values may be used for setting some fields of the report block of the next RTCP packet to be sent.
* @param session : the current session descriptor.
* @param block : the block descriptor that may contain a SR RTCP message.
* @note a basic parsing is done on the block structure. However, if it fails, no error is returned, and the session descriptor is left as is, so it does not induce any change in the caller procedure behaviour.
*/
static void process_rtcp_packet( RtpSession *session, mblk_t *block ) {
rtcp_common_header_t *rtcp;
RtpStream * rtpstream = &session->rtp;
int msgsize = (int) ( block->b_wptr - block->b_rptr );
if ( msgsize < RTCP_COMMON_HEADER_SIZE ) {
ortp_debug( "Receiving a too short RTCP packet" );
return;
}
rtcp = (rtcp_common_header_t *)block->b_rptr;
/* compound rtcp packet can be composed by more than one rtcp message */
while ( msgsize >= RTCP_COMMON_HEADER_SIZE ) {
if ( rtcp->version != 2 ) {
ortp_debug( "Receiving an illegal RTCP packet (version number <> 2)" );
return;
}
/* Convert header data from network order to host order */
rtcp->length = ntohs( rtcp->length );
/* compute length */
int rtcp_pk_size = ( rtcp->length + 1 ) * 4;
/* Sanity check of simple RTCP packet length. */
if ( rtcp_pk_size > msgsize ) {
ortp_debug( "Receiving a RTCP packet shorter than the specified length" );
return;
}
if ( rtcp->packet_type == RTCP_SR ) {
rtcp_sr_t *sr = (rtcp_sr_t *) rtcp;
/* The session descriptor values are reset in case there is an error in the SR block parsing */
rtpstream->last_rcv_SR_ts = 0;
rtpstream->last_rcv_SR_time.tv_usec = 0;
rtpstream->last_rcv_SR_time.tv_sec = 0;
if ( ntohl( sr->ssrc ) != session->rcv.ssrc ) {
ortp_debug( "Receiving a RTCP SR packet from an unknown ssrc" );
return;
}
if ( msgsize < RTCP_COMMON_HEADER_SIZE + RTCP_SSRC_FIELD_SIZE + RTCP_SENDER_INFO_SIZE + ( RTCP_REPORT_BLOCK_SIZE * sr->ch.rc ) ) {
ortp_debug( "Receiving a too short RTCP SR packet" );
return;
}
/* Getting the reception date from the main clock */
struct timeval reception_date;
gettimeofday( &reception_date, NULL );
/* Saving the data to fill LSR and DLSR field in next RTCP report to be transmitted */
/* This value will be the LSR field of the next RTCP report (only the central 32 bits are kept, as described in par.4 of RC3550) */
rtpstream->last_rcv_SR_ts = ( ntohl( sr->si.ntp_timestamp_msw ) << 16 ) | ( ntohl( sr->si.ntp_timestamp_lsw ) >> 16 );
/* This value will help in processing the DLSR of the next RTCP report ( see report_block_init() in rtcp.cc ) */
rtpstream->last_rcv_SR_time.tv_usec = reception_date.tv_usec;
rtpstream->last_rcv_SR_time.tv_sec = reception_date.tv_sec;
compute_rtt(session,sr);
}
}
}
int
rtp_session_rtcp_recv (RtpSession * session)
{
......@@ -1067,6 +1153,7 @@ rtp_session_rtcp_recv (RtpSession * session)
if (error > 0)
{
mp->b_wptr += error;
process_rtcp_packet( session, mp );
/* post an event to notify the application*/
{
rtp_session_notify_inc_rtcp(session,mp);
......
......@@ -33,7 +33,10 @@ typedef enum {
RTP_SESSION_USING_EXT_SOCKETS=1<<7, /* the session is using externaly supplied sockets */
RTP_SOCKET_CONNECTED=1<<8,
RTCP_SOCKET_CONNECTED=1<<9,
RTP_SESSION_USING_TRANSPORT=1<<10
RTP_SESSION_USING_TRANSPORT=1<<10,
RTCP_OVERRIDE_LOST_PACKETS=1<11,
RTCP_OVERRIDE_JITTER=1<<12,
RTCP_OVERRIDE_DELAY=1<<13
}RtpSessionFlags;
#define rtp_session_using_transport(s, stream) (((s)->flags & RTP_SESSION_USING_TRANSPORT) && (s->stream.tr != 0))
......
......@@ -89,4 +89,6 @@ typedef union{
void ortp_ev_queue_put(OrtpEvQueue *q, OrtpEvent *ev);
uint64_t ortp_timeval_to_ntp(const struct timeval *tv);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment