Added support for sending periodic RTCP reports and the final RTCP bye.
git-svn-id: http://voip.null.ro/svn/yate@3248 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
bf6b1d43c2
commit
da2cd240d0
|
@ -30,6 +30,9 @@
|
|||
; rtcp: bool: Allocate socket for the RTCP protocol by default
|
||||
;rtcp=enabled
|
||||
|
||||
; rtcp_interval: int: RTCP report interval in ms (500-60000), zero disables
|
||||
;rtcp_interval=4500
|
||||
|
||||
; drillhole: bool: Attempt to drill a hole through a firewall or NAT
|
||||
;drillhole=disable in server mode, enable in client mode
|
||||
|
||||
|
|
|
@ -379,7 +379,7 @@ bool RTPReceiver::rtpCheckIntegrity(const unsigned char* data, int len, const vo
|
|||
|
||||
|
||||
RTPSender::RTPSender(RTPSession* session, bool randomTs)
|
||||
: RTPBaseIO(session), m_evTime(0), m_tsLast(0), m_padding(0)
|
||||
: RTPBaseIO(session), m_evTime(0), m_padding(0)
|
||||
{
|
||||
if (randomTs) {
|
||||
m_ts = ::random() & ~1;
|
||||
|
@ -635,7 +635,8 @@ void UDPSession::setTimeout(int interval)
|
|||
|
||||
RTPSession::RTPSession()
|
||||
: m_direction(FullStop),
|
||||
m_send(0), m_recv(0), m_secure(0)
|
||||
m_send(0), m_recv(0), m_secure(0),
|
||||
m_reportTime(0), m_reportInterval(0)
|
||||
{
|
||||
DDebug(DebugInfo,"RTPSession::RTPSession() [%p]",this);
|
||||
}
|
||||
|
@ -668,6 +669,12 @@ void RTPSession::timerTick(const Time& when)
|
|||
else
|
||||
m_timeoutTime = when + m_timeoutInterval;
|
||||
}
|
||||
if (m_reportInterval) {
|
||||
if (when >= m_reportTime) {
|
||||
m_reportTime = when + m_reportInterval;
|
||||
sendRtcpReport(when);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RTPSession::rtpData(const void* data, int len)
|
||||
|
@ -738,6 +745,8 @@ bool RTPSession::checkCipher(const String& name)
|
|||
|
||||
void RTPSession::transport(RTPTransport* trans)
|
||||
{
|
||||
if (!trans)
|
||||
sendRtcpBye();
|
||||
UDPSession::transport(trans);
|
||||
if (!m_transport)
|
||||
m_direction = FullStop;
|
||||
|
@ -748,6 +757,7 @@ void RTPSession::sender(RTPSender* send)
|
|||
DDebug(DebugInfo,"RTPSession::sender(%p) old=%p [%p]",send,m_send,this);
|
||||
if (send == m_send)
|
||||
return;
|
||||
sendRtcpBye();
|
||||
RTPSender* tmp = m_send;
|
||||
m_send = send;
|
||||
if (tmp)
|
||||
|
@ -848,6 +858,93 @@ void RTPSession::getStats(String& stats) const
|
|||
}
|
||||
}
|
||||
|
||||
void RTPSession::setReports(int interval)
|
||||
{
|
||||
if (interval > 0 && m_transport && m_transport->rtcpSock()->valid()) {
|
||||
if (interval < 500)
|
||||
interval = 500;
|
||||
else if (interval > 60000)
|
||||
interval = 60000;
|
||||
m_reportInterval = interval * (u_int64_t)1000 + (::random() % 20000);
|
||||
}
|
||||
else
|
||||
m_reportInterval = 0;
|
||||
m_reportTime = 0;
|
||||
}
|
||||
|
||||
static void store32(unsigned char* buf, unsigned int& len, u_int32_t val)
|
||||
{
|
||||
buf[len++] = (unsigned char)(val >> 24);
|
||||
buf[len++] = (unsigned char)(val >> 16);
|
||||
buf[len++] = (unsigned char)(val >> 8);
|
||||
buf[len++] = (unsigned char)(val & 0xff);
|
||||
}
|
||||
|
||||
void RTPSession::sendRtcpReport(const Time& when)
|
||||
{
|
||||
if (!((m_send || m_recv) && m_transport && m_transport->rtcpSock()->valid()))
|
||||
return;
|
||||
unsigned char buf[52];
|
||||
buf[0] = 0x80; // RC=0
|
||||
buf[1] = 0xc9; // RR
|
||||
buf[2] = 0;
|
||||
unsigned int len = 8;
|
||||
if (m_send && m_send->ioPackets()) {
|
||||
// Include a sender report
|
||||
buf[1] = 0xc8; // SR
|
||||
// NTP timestamp
|
||||
store32(buf,len,2208988800 + (when.usec() / 1000000));
|
||||
store32(buf,len,((when.usec() % 1000000) << 32) / 1000000);
|
||||
// RTP timestamp
|
||||
store32(buf,len,m_send->tsLast());
|
||||
// Packet and octet counters
|
||||
store32(buf,len,m_send->ioPackets());
|
||||
store32(buf,len,m_send->ioOctets());
|
||||
}
|
||||
if (m_recv && m_recv->ioPackets()) {
|
||||
// Add a single receiver report
|
||||
buf[0] |= 0x01; // RC=1
|
||||
store32(buf,len,m_recv->ssrc());
|
||||
u_int32_t lost = m_recv->ioPacketsLost();
|
||||
u_int32_t lostf = 0xff & (lost * 255 / (lost + m_recv->ioPackets()));
|
||||
store32(buf,len,(lost & 0xffffff) | (lostf << 24));
|
||||
store32(buf,len,m_recv->fullSeq());
|
||||
// TODO: Compute and store Jitter, LSR and DLSR
|
||||
store32(buf,len,0);
|
||||
store32(buf,len,0);
|
||||
store32(buf,len,0);
|
||||
}
|
||||
// Don't send a RR with no receiver report blocks...
|
||||
if (len <= 8)
|
||||
return;
|
||||
DDebug(DebugInfo,"RTPSession sending RTCP Report [%p]",this);
|
||||
unsigned int lptr = 4;
|
||||
store32(buf,lptr,(m_send ? m_send->ssrcInit() : 0));
|
||||
buf[3] = (len - 1) / 4; // same as ((len + 3) / 4) - 1
|
||||
static_cast<RTPProcessor*>(m_transport)->rtcpData(buf,len);
|
||||
}
|
||||
|
||||
void RTPSession::sendRtcpBye()
|
||||
{
|
||||
if (!(m_send && m_transport && m_transport->rtcpSock()->valid()))
|
||||
return;
|
||||
u_int32_t ssrc = m_send->ssrc();
|
||||
if (!ssrc)
|
||||
return;
|
||||
DDebug(DebugInfo,"RTPSession sending RTCP Bye [%p]",this);
|
||||
// SSRC was initialized if we sent at least one RTP or RTCP packet
|
||||
unsigned char buf[8];
|
||||
buf[0] = 0x81;
|
||||
buf[1] = 0xcb;
|
||||
buf[2] = 0;
|
||||
buf[3] = 1; // len = 2 x 32bit
|
||||
buf[4] = (unsigned char)(ssrc >> 24);
|
||||
buf[5] = (unsigned char)(ssrc >> 16);
|
||||
buf[6] = (unsigned char)(ssrc >> 8);
|
||||
buf[7] = (unsigned char)(0xff & ssrc);
|
||||
static_cast<RTPProcessor*>(m_transport)->rtcpData(buf,8);
|
||||
}
|
||||
|
||||
|
||||
UDPTLSession::UDPTLSession(u_int16_t maxLen, u_int8_t maxSec)
|
||||
: m_rxSeq(0xffff), m_txSeq(0xffff),
|
||||
|
|
|
@ -271,6 +271,13 @@ public:
|
|||
inline Socket* rtpSock()
|
||||
{ return &m_rtpSock; }
|
||||
|
||||
/**
|
||||
* Get the RTCP socket used by this transport
|
||||
* @return Pointer to the RTCP socket
|
||||
*/
|
||||
inline Socket* rtcpSock()
|
||||
{ return &m_rtcpSock; }
|
||||
|
||||
/**
|
||||
* Drill a hole in a firewall or NAT for the RTP and RTCP sockets
|
||||
* @return True if at least a packet was sent for the RTP socket
|
||||
|
@ -378,7 +385,7 @@ public:
|
|||
m_ssrcInit(true), m_ssrc(0), m_ts(0),
|
||||
m_seq(0), m_rollover(0), m_secLen(0), m_mkiLen(0),
|
||||
m_evTs(0), m_evNum(-1), m_evVol(-1),
|
||||
m_ioPackets(), m_ioOctets(0),
|
||||
m_ioPackets(), m_ioOctets(0), m_tsLast(0),
|
||||
m_dataType(-1), m_eventType(-1), m_silenceType(-1)
|
||||
{ }
|
||||
|
||||
|
@ -490,6 +497,13 @@ public:
|
|||
inline u_int32_t ioOctets() const
|
||||
{ return m_ioOctets; }
|
||||
|
||||
/**
|
||||
* Get the timestamp of the last packet as transmitted over the wire
|
||||
* @return Timestamp of last packet sent or received
|
||||
*/
|
||||
inline unsigned int tsLast() const
|
||||
{ return m_ts + m_tsLast; }
|
||||
|
||||
/**
|
||||
* Get the session this object belongs to
|
||||
* @return Pointer to RTP session or NULL
|
||||
|
@ -539,6 +553,7 @@ protected:
|
|||
int m_evVol;
|
||||
u_int32_t m_ioPackets;
|
||||
u_int32_t m_ioOctets;
|
||||
unsigned int m_tsLast;
|
||||
|
||||
private:
|
||||
int m_dataType;
|
||||
|
@ -559,7 +574,7 @@ public:
|
|||
*/
|
||||
inline RTPReceiver(RTPSession* session = 0)
|
||||
: RTPBaseIO(session),
|
||||
m_ioLostPkt(0), m_dejitter(0), m_tsLast(0),
|
||||
m_ioLostPkt(0), m_dejitter(0),
|
||||
m_seqSync(0), m_seqCount(0), m_warn(true)
|
||||
{ }
|
||||
|
||||
|
@ -685,7 +700,6 @@ private:
|
|||
void finishEvent(unsigned int timestamp);
|
||||
bool pushEvent(int event, int duration, int volume, unsigned int timestamp);
|
||||
RTPDejitter* m_dejitter;
|
||||
unsigned int m_tsLast;
|
||||
u_int16_t m_seqSync;
|
||||
u_int16_t m_seqCount;
|
||||
bool m_warn;
|
||||
|
@ -796,7 +810,6 @@ protected:
|
|||
|
||||
private:
|
||||
int m_evTime;
|
||||
unsigned int m_tsLast;
|
||||
unsigned char m_padding;
|
||||
bool sendEventData(unsigned int timestamp);
|
||||
};
|
||||
|
@ -1196,6 +1209,12 @@ public:
|
|||
*/
|
||||
void security(RTPSecure* secure);
|
||||
|
||||
/**
|
||||
* Set the RTCP report interval
|
||||
* @param interval Average interval between reports in msec, zero to disable
|
||||
*/
|
||||
void setReports(int interval);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Method called periodically to push any asynchronous data or statistics
|
||||
|
@ -1203,11 +1222,24 @@ protected:
|
|||
*/
|
||||
virtual void timerTick(const Time& when);
|
||||
|
||||
/**
|
||||
* Send a RTCP report
|
||||
* @param when Time to use as base for timestamps
|
||||
*/
|
||||
void sendRtcpReport(const Time& when);
|
||||
|
||||
/**
|
||||
* Send a RTCP BYE when the sender is stopped or replaced
|
||||
*/
|
||||
void sendRtcpBye();
|
||||
|
||||
private:
|
||||
Direction m_direction;
|
||||
RTPSender* m_send;
|
||||
RTPReceiver* m_recv;
|
||||
RTPSecure* m_secure;
|
||||
u_int64_t m_reportTime;
|
||||
u_int64_t m_reportInterval;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -99,7 +99,9 @@ static bool s_drill = false;
|
|||
static Thread::Priority s_priority = Thread::Normal;
|
||||
static int s_tos = 0;
|
||||
static int s_sleep = 5;
|
||||
static int s_interval= 0;
|
||||
static int s_timeout = 0;
|
||||
|
||||
static int s_minjitter = 0;
|
||||
static int s_maxjitter = 0;
|
||||
|
||||
|
@ -700,6 +702,7 @@ bool YRTPWrapper::startRTP(const char* raddr, unsigned int rport, Message& msg)
|
|||
(ok ? "opened" : "failed to open"),this);
|
||||
}
|
||||
setTimeout(msg,s_timeout);
|
||||
m_rtp->setReports(msg.getIntValue("rtcp_interval",s_interval));
|
||||
// if (maxJitter > 0)
|
||||
// m_rtp->setDejitter(minJitter*1000,maxJitter*1000);
|
||||
m_bufsize = s_bufsize;
|
||||
|
@ -1737,6 +1740,7 @@ void YRTPPlugin::initialize()
|
|||
s_anyssrc = cfg.getBoolValue("general","anyssrc",false);
|
||||
s_padding = cfg.getIntValue("general","padding",0);
|
||||
s_rtcp = cfg.getBoolValue("general","rtcp",true);
|
||||
s_interval = cfg.getIntValue("general","rtcp_interval",4500);
|
||||
s_drill = cfg.getBoolValue("general","drillhole",Engine::clientMode());
|
||||
s_sleep = cfg.getIntValue("general","defsleep",5);
|
||||
RTPGroup::setMinSleep(cfg.getIntValue("general","minsleep"));
|
||||
|
|
Loading…
Reference in New Issue