Commit 16a200f6 authored by Simon Morlat's avatar Simon Morlat

implement network simulator within oRTP

parent 0a878baa
......@@ -58,6 +58,8 @@ EXPORTS
rtp_session_get_send_payload_type
rtp_session_set_recv_payload_type
rtp_session_get_recv_payload_type
rtp_session_enable_network_simulation
rtp_session_recv_with_ts
rtp_session_recvm_with_ts
......
......@@ -94,8 +94,20 @@ typedef struct _RtpTransport
struct _RtpSession *session;//<back pointer to the owning session, set by oRTP
} RtpTransport;
typedef struct _OrtpNetworkSimulatorParams{
int enabled;
float max_bandwidth; /*IP bandwidth, in bit/s*/
float loss_rate;
}OrtpNetworkSimulatorParams;
typedef struct _OrtpNetworkSimulatorCtx{
OrtpNetworkSimulatorParams params;
int bit_budget;
int qsize;
queue_t q;
struct timeval last_check;
}OrtpNetworkSimulatorCtx;
typedef struct _RtpStream
{
ortp_socket_t socket;
......@@ -224,6 +236,7 @@ struct _RtpSession
unsigned int interarrival_jitter_test_vector;
unsigned int delay_test_vector;
float rtt;/*last round trip delay calculated*/
OrtpNetworkSimulatorCtx *net_sim_ctx;
bool_t symmetric_rtp;
bool_t permissive; /*use the permissive algorithm*/
bool_t use_connect; /* use connect() on the socket */
......@@ -385,6 +398,8 @@ void rtp_session_clear_recv_error_code(RtpSession *session);
float rtp_session_get_round_trip_propagation(RtpSession *session);
void rtp_session_enable_network_simulation(RtpSession *session, const OrtpNetworkSimulatorParams *params);
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 );
......
......@@ -31,7 +31,8 @@ libortp_la_SOURCES= str_utils.c \
stun.c stun_udp.c \
ortp_srtp.c \
b64.c \
zrtp.c
zrtp.c \
netsim.c
if LIBZRTPCPP
AM_CFLAGS+= $(LIBZRTPCPP_CFLAGS)
......
/*
The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
Copyright (C) 2011 Belledonne Communications SARL
Author: Simon MORLAT simon.morlat@linphone.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ortp/ortp.h"
#include "utils.h"
#include "ortp/rtpsession.h"
#include "rtpsession_priv.h"
static OrtpNetworkSimulatorCtx* simulator_ctx_new(void){
OrtpNetworkSimulatorCtx *ctx=(OrtpNetworkSimulatorCtx*)ortp_malloc0(sizeof(OrtpNetworkSimulatorCtx));
qinit(&ctx->q);
return ctx;
}
void ortp_network_simulator_destroy(OrtpNetworkSimulatorCtx *sim){
flushq(&sim->q,0);
ortp_free(sim);
}
void rtp_session_enable_network_simulation(RtpSession *session, const OrtpNetworkSimulatorParams *params){
OrtpNetworkSimulatorCtx *sim=session->net_sim_ctx;
if (params->enabled){
if (sim==NULL) sim=simulator_ctx_new();
sim->params=*params;
session->net_sim_ctx=sim;
}else{
if (sim!=NULL) ortp_network_simulator_destroy(sim);
session->net_sim_ctx=NULL;
}
}
static int64_t elapsed_us(struct timeval *tv1, struct timeval *tv2){
return ((tv2->tv_sec-tv1->tv_sec)*1000000LL)+((tv2->tv_usec-tv1->tv_usec));
}
#define IP_UDP_OVERHEAD (20+8)
#define IP6_UDP_OVERHEAD (40+8)
static mblk_t *simulate_bandwidth_limit(RtpSession *session, mblk_t *input){
OrtpNetworkSimulatorCtx *sim=session->net_sim_ctx;
struct timeval current;
int64_t elapsed;
int bits;
mblk_t *output=NULL;
#ifdef ORTP_INET6
int overhead=(session->rtp.sockfamily==AF_INET6) ? IP6_UDP_OVERHEAD : IP_UDP_OVERHEAD;
#else
int overhead=IP_UDP_OVERHEAD;
#endif
gettimeofday(&current,NULL);
if (sim->last_check.tv_sec==0){
sim->last_check=current;
sim->bit_budget=sim->params.max_bandwidth;
}
/*update the budget */
elapsed=elapsed_us(&sim->last_check,&current);
sim->bit_budget+=(elapsed*(int64_t)sim->params.max_bandwidth)/1000000LL;
if (sim->bit_budget>=sim->params.max_bandwidth)
sim->bit_budget=sim->params.max_bandwidth;
sim->last_check=current;
/* queue the packet for sending*/
if (input){
putq(&sim->q,input);
bits=(msgdsize(input)+overhead)*8;
sim->qsize+=bits;
}
/*flow control*/
while (sim->qsize>=sim->params.max_bandwidth){
ortp_message("rtp_session_network_simulate(): discarding packets.");
output=getq(&sim->q);
if (output){
bits=(msgdsize(output)+overhead)*8;
sim->qsize-=bits;
}
}
output=NULL;
/*see if we can output a packet*/
if (sim->bit_budget>=0){
output=getq(&sim->q);
if (output){
bits=(msgdsize(output)+overhead)*8;
sim->bit_budget-=bits;
sim->qsize-=bits;
}
}
return output;
}
mblk_t * rtp_session_network_simulate(RtpSession *session, mblk_t *input){
OrtpNetworkSimulatorCtx *sim=session->net_sim_ctx;
mblk_t *om=NULL;
if (sim->params.max_bandwidth>0){
om=simulate_bandwidth_limit(session,input);
}
return om;
}
......@@ -1368,6 +1368,9 @@ void rtp_session_uninit (RtpSession * session)
session->signal_tables = o_list_free(session->signal_tables);
msgb_allocator_uninit(&session->allocator);
if (session->net_sim_ctx)
ortp_network_simulator_destroy(session->net_sim_ctx);
#if (_WIN32_WINNT >= 0x0600)
if (session->rtp.QoSFlowID != 0)
{
......
......@@ -837,19 +837,30 @@ static int rtp_sendmsg(int sock,mblk_t *m, struct sockaddr *rem_addr, int addr_l
#endif
#define IP_UDP_OVERHEAD (20+8)
#define IP6_UDP_OVERHEAD (40+8)
static void update_sent_bytes(RtpSession*s, int nbytes){
#ifdef ORTP_INET6
int overhead=(s->rtp.sockfamily==AF_INET6) ? IP6_UDP_OVERHEAD : IP_UDP_OVERHEAD;
#else
int overhead=IP_UDP_OVERHEAD;
#endif
if (s->rtp.sent_bytes==0){
gettimeofday(&s->rtp.send_bw_start,NULL);
}
s->rtp.sent_bytes+=nbytes+IP_UDP_OVERHEAD;
s->rtp.sent_bytes+=nbytes+overhead;
}
static void update_recv_bytes(RtpSession*s, int nbytes){
#ifdef ORTP_INET6
int overhead=(s->rtp.sockfamily==AF_INET6) ? IP6_UDP_OVERHEAD : IP_UDP_OVERHEAD;
#else
int overhead=IP_UDP_OVERHEAD;
#endif
if (s->rtp.recv_bytes==0){
gettimeofday(&s->rtp.recv_bw_start,NULL);
}
s->rtp.recv_bytes+=nbytes+IP_UDP_OVERHEAD;
s->rtp.recv_bytes+=nbytes+overhead;
}
int
......@@ -987,31 +998,39 @@ rtp_session_rtp_recv (RtpSession * session, uint32_t user_ts)
session->flags|=RTP_SOCKET_CONNECTED;
}
}
/* then parse the message and put on queue */
mp->b_wptr+=error;
rtp_session_rtp_parse (session, mp, user_ts, (struct sockaddr*)&remaddr,addrlen);
if (session->net_sim_ctx)
mp=rtp_session_network_simulate(session,mp);
/* then parse the message and put on jitter buffer queue */
if (mp){
rtp_session_rtp_parse(session, mp, user_ts, (struct sockaddr*)&remaddr,addrlen);
update_recv_bytes(session,mp->b_wptr-mp->b_rptr);
}
session->rtp.cached_mp=NULL;
/*for bandwidth measurements:*/
update_recv_bytes(session,error);
}
else
{
int errnum=getSocketErrorCode();
if (error == 0 || (error == -1 && errnum==0)){
/*0 can be returned by RtpTransport functions in case of EWOULDBLOCK*/
/*we ignore it*/
/*ortp_warning
("rtp_recv: strange... recv() returned zero.");*/
/*(error == -1 && errnum==0) for buggy drivers*/
}
else if (!is_would_block_error(errnum))
int errnum;
if (error==-1 && !is_would_block_error((errnum=getSocketErrorCode())) )
{
if (session->on_network_error.count>0){
rtp_signal_table_emit3(&session->on_network_error,(long)"Error receiving RTP packet",INT_TO_POINTER(getSocketErrorCode()));
}else ortp_warning("Error receiving RTP packet: %s, err num [%i],error [%i]",getSocketError(),errnum,error);
}else{
/*EWOULDBLOCK errors or transports returning 0 are ignored.*/
if (session->net_sim_ctx){
/*drain possible packets queued in the network simulator*/
mp=rtp_session_network_simulate(session,NULL);
if (mp){
/* then parse the message and put on jitter buffer queue */
rtp_session_rtp_parse(session, mp, user_ts, (struct sockaddr*)&session->rtp.rem_addr,session->rtp.rem_addrlen);
update_recv_bytes(session,msgdsize(mp));
}
}
}
/* don't free the cached_mp, it will be reused next time */
return -1; /* avoids an infinite loop ! */
return -1;
}
}
return error;
......
......@@ -54,4 +54,7 @@ void rtp_session_rtcp_parse(RtpSession *session, mblk_t *mp);
void rtp_session_dispatch_event(RtpSession *session, OrtpEvent *ev);
mblk_t * rtp_session_network_simulate(RtpSession *session, mblk_t *input);
void ortp_network_simulator_destroy(OrtpNetworkSimulatorCtx *sim);
#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