yate/libs/yrtp/yatertp.h

1545 lines
47 KiB
C++

/*
* yatertp.h
* Yet Another RTP Stack
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2006 Null Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __YATERTP_H
#define __YATERTP_H
#include <yateclass.h>
#ifdef _WINDOWS
#ifdef LIBYRTP_EXPORTS
#define YRTP_API __declspec(dllexport)
#else
#ifndef LIBYRTP_STATIC
#define YRTP_API __declspec(dllimport)
#endif
#endif
#endif /* _WINDOWS */
#ifndef YRTP_API
#define YRTP_API
#endif
/**
* Holds all Telephony Engine related classes.
*/
namespace TelEngine {
class RTPGroup;
class RTPTransport;
class RTPSession;
class RTPSender;
class RTPReceiver;
class RTPSecure;
/**
* A base class that contains just placeholders to process raw RTP and RTCP packets.
* @short Base class to ease creation of RTP forwarders
*/
class YRTP_API RTPProcessor : public GenObject
{
friend class UDPSession;
friend class UDPTLSession;
friend class RTPGroup;
friend class RTPTransport;
friend class RTPSender;
friend class RTPReceiver;
public:
/**
* Constructor - processor should be later inserted in a RTP group
*/
RTPProcessor();
/**
* Destructor - removes itself from the RTP group
*/
virtual ~RTPProcessor();
/**
* Get the RTP group to which this processor belongs
* @return Pointer to the RTP group this processor has joined
*/
inline RTPGroup* group() const
{ return m_group; }
/**
* This method is called to send or process a RTP packet
* @param data Pointer to raw RTP data
* @param len Length of the data packet
*/
virtual void rtpData(const void* data, int len);
/**
* This method is called to send or process a RTCP packet
* @param data Pointer to raw RTCP data
* @param len Length of the data packet
*/
virtual void rtcpData(const void* data, int len);
/**
* Retrieve MGCP P: style comma separated session parameters
* @param stats String to append parameters to
*/
virtual void getStats(String& stats) const;
/**
* Increase the counter for number of RTP packets received from a wrong source
*/
virtual inline void incWrongSrc()
{ }
/**
* Get the number of RTP packets that were received from a wrong source
* @return Number of RTP packets received from a wrong source
*/
inline unsigned int wrongSrc()
{ return m_wrongSrc; }
protected:
/**
* Set a new RTP group for this processor
* @param newgrp New group to join this processor, the old one will be left
*/
void group(RTPGroup* newgrp);
/**
* Method called periodically to keep the data flowing
* @param when Time to use as base in all computing
*/
virtual void timerTick(const Time& when) = 0;
unsigned int m_wrongSrc;
private:
RTPGroup* m_group;
};
/**
* Several possibly related RTP processors share the same RTP group which
* holds the thread that keeps them running.
* @short A group of RTP processors handled by the same thread
*/
class YRTP_API RTPGroup : public GenObject, public Mutex, public Thread
{
friend class RTPProcessor;
public:
/**
* Constructor
* @param msec Minimum time to sleep in loop in milliseconds
* @param prio Thread priority to run this group
*/
RTPGroup(int msec = 0, Priority prio = Normal);
/**
* Group destructor, removes itself from all remaining processors
*/
virtual ~RTPGroup();
/**
* Inherited thread cleanup
*/
virtual void cleanup();
/**
* Inherited thread run method
*/
virtual void run();
/**
* Set the system global minimum time to sleep in loop
* @param msec Minimum time to sleep in loop in milliseconds
*/
static void setMinSleep(int msec);
/**
* Add a RTP processor to this group
* @param proc Pointer to the RTP processor to add
*/
void join(RTPProcessor* proc);
/**
* Remove a RTP processor from this group
* @param proc Pointer to the RTP processor to remove
*/
void part(RTPProcessor* proc);
private:
ObjList m_processors;
bool m_listChanged;
unsigned long m_sleep;
};
/**
* Class that holds sockets and addresses for transporting RTP and RTCP packets.
* @short Low level transport for RTP and RTCP
*/
class YRTP_API RTPTransport : public RTPProcessor
{
public:
/**
* Activation status of the transport
*/
enum Activation {
Inactive,
Bound,
Active
};
/**
* Type of transported data
*/
enum Type {
Unknown,
RTP,
UDPTL
};
/**
* Constructor, creates an unconnected transport
* @param type Type of check to apply to the data
*/
RTPTransport(Type type = RTP);
/**
* Destructor
*/
virtual ~RTPTransport();
/**
* Set the RTP/RTCP processor of data received by this transport
* @param processor A pointer to the RTPProcessor for this transport
*/
void setProcessor(RTPProcessor* processor = 0);
/**
* Set the RTP/RTCP monitor of data received by this transport
* @param monitor A pointer to a second RTPProcessor for this transport
*/
void setMonitor(RTPProcessor* monitor = 0);
/**
* Get the local network address of the RTP transport
* @return Reference to the local RTP transport address
*/
inline const SocketAddr& localAddr() const
{ return m_localAddr; }
/**
* Get the remote network address of the RTP transport
* @return Reference to the remote RTP transport address
*/
inline const SocketAddr& remoteAddr() const
{ return m_remoteAddr; }
/**
* Set the local network address of the RTP transport
* @param addr New local RTP transport address
* @param rtcp Enable RTCP transport
* @return True if address set, false if a failure occured
*/
bool localAddr(SocketAddr& addr, bool rtcp = true);
/**
* Set the remote network address of the RTP transport
* @param addr New remote RTP transport address
* @param sniff Automatically adjust the address from the first incoming packet
* @return True if address set, false if a failure occured
*/
bool remoteAddr(SocketAddr& addr, bool sniff = false);
/**
* Set the Type Of Service for the RTP socket
* @param tos Type Of Service bits to set
* @return True if operation was successfull, false if an error occured
*/
inline bool setTOS(int tos)
{ return m_rtpSock.setTOS(tos); }
/**
* Get the RTP socket used by this transport
* @return Pointer to the RTP socket
*/
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
*/
bool drillHole();
protected:
/**
* Method called periodically to read data out of sockets
* @param when Time to use as base in all computing
*/
virtual void timerTick(const Time& when);
/**
* This method is called to send a RTP packet
* @param data Pointer to raw RTP data
* @param len Length of the data packet
*/
virtual void rtpData(const void* data, int len);
/**
* This method is called to send a RTCP packet
* @param data Pointer to raw RTCP data
* @param len Length of the data packet
*/
virtual void rtcpData(const void* data, int len);
private:
Type m_type;
RTPProcessor* m_processor;
RTPProcessor* m_monitor;
Socket m_rtpSock;
Socket m_rtcpSock;
SocketAddr m_localAddr;
SocketAddr m_remoteAddr;
SocketAddr m_remoteRTCP;
SocketAddr m_remotePref;
SocketAddr m_rxAddrRTP;
SocketAddr m_rxAddrRTCP;
bool m_autoRemote;
};
/**
* A dejitter buffer that can be inserted in the receive data path to
* absorb variations in packet arrival time. Incoming packets are stored
* and forwarded at fixed intervals.
* @short Dejitter buffer for incoming data packets
*/
class YRTP_API RTPDejitter : public RTPProcessor
{
public:
/**
* Constructor of a new jitter attenuator
* @param receiver RTP receiver which gets the delayed packets
* @param mindelay Minimum length of the dejitter buffer in microseconds
* @param maxdelay Maximum length of the dejitter buffer in microseconds
*/
RTPDejitter(RTPReceiver* receiver, unsigned int mindelay, unsigned int maxdelay);
/**
* Destructor - drops the packets and shows statistics
*/
virtual ~RTPDejitter();
/**
* Process and store one RTP data packet
* @param marker True if the marker bit is set in data packet
* @param payload Payload number
* @param timestamp Sampling instant of the packet data
* @param data Pointer to data block to process
* @param len Length of the data block in bytes
* @return True if the data packet was queued
*/
virtual bool rtpRecv(bool marker, int payload, unsigned int timestamp,
const void* data, int len);
/**
* Clear the delayed packets queue and all variables
*/
void clear();
protected:
/**
* Method called periodically to keep the data flowing
* @param when Time to use as base in all computing
*/
virtual void timerTick(const Time& when);
private:
ObjList m_packets;
RTPReceiver* m_receiver;
unsigned int m_minDelay;
unsigned int m_maxDelay;
unsigned int m_headStamp;
unsigned int m_tailStamp;
u_int64_t m_headTime;
u_int64_t m_sampRate;
unsigned char m_fastRate;
};
/**
* Base class that holds common sender and receiver methods
* @short Common send/recv variables holder
*/
class YRTP_API RTPBaseIO
{
friend class RTPSession;
friend class RTPSecure;
public:
/**
* Default constructor.
*/
inline RTPBaseIO(RTPSession* session = 0)
: m_session(session), m_secure(0),
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_tsLast(0),
m_dataType(-1), m_eventType(-1), m_silenceType(-1)
{ }
/**
* Destructor
*/
virtual ~RTPBaseIO();
/**
* Get the payload type for data packets
* @return Payload type, -1 if not set
*/
inline int dataPayload() const
{ return m_dataType; }
/**
* Set the payload type for data packets
* @param type Payload type, -1 to disable
* @return True if changed, false if invalid payload type
*/
bool dataPayload(int type);
/**
* Get the payload type for event packets
* @return Payload type, -1 if not set
*/
inline int eventPayload() const
{ return m_eventType; }
/**
* Set the payload type for event packets
* @param type Payload type, -1 to disable
* @return True if changed, false if invalid payload type
*/
bool eventPayload(int type);
/**
* Get the payload type for Silence event packets
* @return Payload type, -1 if not set
*/
inline int silencePayload() const
{ return m_silenceType; }
/**
* Set the payload type for Silence event packets.
* Thanks, Silence, for a new and incompatible way of sending events.
* @param type Payload type, -1 to disable
* @return True if changed, false if invalid payload type
*/
bool silencePayload(int type);
/**
* Return SSRC value, initialize to a new, random value if needed
* @return Current value of SSRC
*/
unsigned int ssrcInit();
/**
* Requesting generation/grabbing of a new SSRC
*/
inline void reset()
{ m_ssrcInit = true; }
/**
* Get the value of the current SSRC, zero if not initialized yet
* @return Value of SSRC, zero if not initialized
*/
inline unsigned int ssrc() const
{ return m_ssrcInit ? 0 : m_ssrc; }
/**
* Force a new known SSRC for all further packets
*/
inline void ssrc(unsigned int src)
{ m_ssrc = src; m_ssrcInit = false; }
/**
* Get the current sequence number
* @return Sequence number
*/
inline u_int16_t seq() const
{ return m_seq; }
/**
* Get the value of the rollover counter
* @return How many times the seqeunce has rolled over since SSRC changed
*/
inline u_int32_t rollover() const
{ return m_rollover; }
/**
* Get the full current sequence number including rollovers
* @return Full 48 bit current sequence number
*/
inline u_int64_t fullSeq() const
{ return m_seq | (((u_int64_t)m_rollover) << 16); }
/**
* Retrieve the number of packets exchanged on current session
* @return Number of packets exchanged
*/
inline u_int32_t ioPackets() const
{ return m_ioPackets; }
/**
* Retrieve the number of payload octets exchanged on current session
* @return Number of octets exchanged except headers and padding
*/
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
*/
inline RTPSession* session() const
{ return m_session; }
/**
* Get the security provider of this sender or receiver
* @return A pointer to the RTPSecure or NULL
*/
inline RTPSecure* security() const
{ return m_secure; }
/**
* Set the security provider of this sender or receiver
* @param secure Pointer to the new RTPSecure or NULL
*/
void security(RTPSecure* secure);
protected:
/**
* Method called periodically to keep the data flowing
* @param when Time to use as base in all computing
*/
virtual void timerTick(const Time& when) = 0;
/**
* Set the length of the added / expected security info block
* @param len Length of security information portion
* @param key Length of master key identifier
*/
inline void secLength(u_int32_t len, u_int32_t key = 0)
{ m_secLen = len; m_mkiLen = key; }
RTPSession* m_session;
RTPSecure* m_secure;
bool m_ssrcInit;
u_int32_t m_ssrc;
u_int32_t m_ts;
u_int16_t m_seq;
u_int32_t m_rollover;
u_int16_t m_secLen;
u_int16_t m_mkiLen;
u_int32_t m_evTs;
int m_evNum;
int m_evVol;
u_int32_t m_ioPackets;
u_int32_t m_ioOctets;
unsigned int m_tsLast;
private:
int m_dataType;
int m_eventType;
int m_silenceType;
};
/**
* Class that handles incoming RTP and RTCP packets
* @short RTP/RTCP packet receiver
*/
class YRTP_API RTPReceiver : public RTPBaseIO
{
friend class RTPSession;
friend class RTPDejitter;
public:
/**
* Constructor
*/
inline RTPReceiver(RTPSession* session = 0)
: RTPBaseIO(session),
m_ioLostPkt(0), m_dejitter(0),
m_seqSync(0), m_seqCount(0), m_warn(true),
m_seqLost(0), m_wrongSSRC(0), m_syncLost(0)
{ }
/**
* Destructor - gets rid of the jitter buffer if present
*/
virtual ~RTPReceiver();
/**
* Retrieve the number of lost packets in current session
* @return Number of packets in sequence gaps
*/
inline u_int32_t ioPacketsLost() const
{ return m_ioLostPkt; }
/**
* Set a new dejitter buffer in this receiver
* @param dejitter New dejitter buffer to set, NULL to remove
*/
void setDejitter(RTPDejitter* dejitter);
/**
* Allocate and set a new dejitter buffer in this receiver
* @param mindelay Minimum length of the dejitter buffer in microseconds
* @param maxdelay Maximum length of the dejitter buffer in microseconds
*/
inline void setDejitter(unsigned int mindelay, unsigned int maxdelay)
{ setDejitter(new RTPDejitter(this,mindelay,maxdelay)); }
/**
* Process one RTP payload packet.
* Default behaviour is to call rtpRecvData() or rtpRecvEvent().
* @param marker Set to true if the marker bit is set
* @param payload Payload number
* @param timestamp Sampling instant of the packet data
* @param data Pointer to data block to process
* @param len Length of the data block in bytes
* @return True if data was handled
*/
virtual bool rtpRecv(bool marker, int payload, unsigned int timestamp,
const void* data, int len);
/**
* Process one RTP data packet
* @param marker Set to true if the marker bit is set
* @param timestamp Sampling instant of the packet data
* @param data Pointer to data block to process
* @param len Length of the data block in bytes
* @return True if data was handled
*/
virtual bool rtpRecvData(bool marker, unsigned int timestamp,
const void* data, int len);
/**
* Process one RTP event
* @param event Received event code
* @param key Received key (for events 0-16) or zero
* @param duration Duration of the event as number of samples
* @param volume Attenuation of the tone, zero for don't care
* @param timestamp Sampling instant of the initial packet data
* @return True if data was handled
*/
virtual bool rtpRecvEvent(int event, char key, int duration,
int volume, unsigned int timestamp);
/**
* Method called for unknown payload types just before attempting
* to call rtpRecvData(). This is a good opportunity to change the
* payload type and continue.
* @param payload Payload number
* @param timestamp Sampling instant of the unexpected packet data
*/
virtual void rtpNewPayload(int payload, unsigned int timestamp);
/**
* Method called when a packet with an unexpected SSRC is received
* just before processing further. This is a good opportunity to
* change the SSRC and continue
* @param newSsrc SSRC received in packet
* @param marker True if marker bit is set in the RTP packet
*/
virtual void rtpNewSSRC(u_int32_t newSsrc, bool marker);
/**
* Retrieve the statistical data from this receiver in a NamedList. Reset all the data.
* @param stat NamedList to populate with the values for different counters
*/
virtual void stats(NamedList& stat) const;
protected:
/**
* Method called periodically to finish lingering events
* @param when Time to use as base in all computing
*/
virtual void timerTick(const Time& when);
/**
* Method called to decipher RTP data in-place.
* The default implementation calls session's @ref RTPSecure::rtpDecipher()
* @param data Pointer to data block to decipher
* @param len Length of data including any padding
* @param secData Pointer to security data if applicable
* @param ssrc SSRC of the packet to decipher
* @param seq Full (48 bit) seqence number of the packet including rollovers
* @return True is the packet was deciphered correctly or can't tell
*/
virtual bool rtpDecipher(unsigned char* data, int len, const void* secData, u_int32_t ssrc, u_int64_t seq);
/**
* Method called to check the integrity of the RTP packet.
* The default implementation calls session's @ref RTPSecure::rtpCheckIntegrity()
* @param data Pointer to RTP header and data
* @param len Length of header, data and padding
* @param authData Pointer to authentication data
* @param ssrc SSRC of the packet to validate
* @param seq Full (48 bit) seqence number of the packet including rollovers
* @return True is the packet passed integrity checks
*/
virtual bool rtpCheckIntegrity(const unsigned char* data, int len, const void* authData, u_int32_t ssrc, u_int64_t seq);
u_int32_t m_ioLostPkt;
private:
void rtpData(const void* data, int len);
void rtcpData(const void* data, int len);
bool decodeEvent(bool marker, unsigned int timestamp, const void* data, int len);
bool decodeSilence(bool marker, unsigned int timestamp, const void* data, int len);
void finishEvent(unsigned int timestamp);
bool pushEvent(int event, int duration, int volume, unsigned int timestamp);
RTPDejitter* m_dejitter;
u_int16_t m_seqSync;
u_int16_t m_seqCount;
bool m_warn;
unsigned int m_seqLost;
unsigned int m_wrongSSRC;
unsigned int m_syncLost;
};
/**
* Class that builds and sends RTP and RTCP packets
* @short RTP/RTCP packet sender
*/
class YRTP_API RTPSender : public RTPBaseIO
{
public:
/**
* Constructor
* @param session RTP session the sender belongs
* @param randomTs Initialize a random timestamp offset
*/
RTPSender(RTPSession* session = 0, bool randomTs = true);
/**
* Do-nothing destructor
*/
virtual ~RTPSender()
{ }
/**
* Send one RTP payload packet
* @param marker Set to true if the marker bit must be set
* @param payload Payload number
* @param timestamp Sampling instant of the packet data
* @param data Pointer to data block to send
* @param len Length of the data block
* @return True if data sending was attempted
*/
bool rtpSend(bool marker, int payload, unsigned int timestamp,
const void* data, int len);
/**
* Send one RTP data packet
* @param marker Set to true if the marker bit must be set
* @param timestamp Sampling instant of the packet data
* @param data Pointer to data block to send
* @param len Length of the data block
* @return True if data sending was attempted
*/
bool rtpSendData(bool marker, unsigned int timestamp,
const void* data, int len);
/**
* Send one RTP event
* @param event Event code to send
* @param duration Duration of the event as number of samples
* @param volume Attenuation of the tone, zero for don't care
* @param timestamp Sampling instant of the packet data, zero to use current
* @return True if data sending was attempted
*/
bool rtpSendEvent(int event, int duration, int volume = 0, unsigned int timestamp = 0);
/**
* Send one RTP key event
* @param key Key to send
* @param duration Duration of the event as number of samples
* @param volume Attenuation of the tone, zero for don't care
* @param timestamp Sampling instant of the packet data, zero to use current
* @return True if data sending was attempted
*/
bool rtpSendKey(char key, int duration, int volume = 0, unsigned int timestamp = 0);
/**
* Get the payload padding size
* @return Chunk size to pad the payload to a multiple of
*/
inline int padding() const
{ return m_padding; }
/**
* Set the padding to a multiple of a data chunk
* @param chunk Size to pad the payload to a multiple of
* @return True if the new chunk size is valid
*/
bool padding(int chunk);
/**
* Retrieve the statistical data from this receiver in a NamedList. Reset all the data.
* @param stat NamedList to populate with the values for different counters
*/
virtual void stats(NamedList& stat) const;
protected:
/**
* Method called periodically to send events and buffered data
* @param when Time to use as base in all computing
*/
virtual void timerTick(const Time& when);
/**
* Method called to encipher RTP payload data in-place.
* The default implementation calls session's @ref RTPSecure::rtpEncipher()
* @param data Pointer to data block to encipher
* @param len Length of payload data to be encrypted including any padding
*/
virtual void rtpEncipher(unsigned char* data, int len);
/**
* Method called to add integrity information to the RTP packet.
* The default implementation calls session's @ref RTPSecure::rtpAddIntegrity()
* @param data Pointer to the RTP packet to protect
* @param len Length of RTP data to be encrypted including header and padding
* @param authData Address to write the integrity data to
*/
virtual void rtpAddIntegrity(const unsigned char* data, int len, unsigned char* authData);
private:
int m_evTime;
unsigned char m_padding;
DataBlock m_buffer;
bool sendEventData(unsigned int timestamp);
};
/**
* A base class for RTP, SRTP or UDPTL sessions
* @short RTP or UDPTL session
*/
class YRTP_API UDPSession : public RTPProcessor
{
public:
/**
* Destructor - cleans up any remaining resources
*/
virtual ~UDPSession();
/**
* Create a new RTP or UDP transport for this session.
* Override this method to create objects derived from RTPTransport.
* @return Pointer to the new transport or NULL on failure
*/
virtual RTPTransport* createTransport();
/**
* Initialize the RTP session, attach a transport if there is none
* @return True if initialized, false on some failure
*/
bool initTransport();
/**
* Initialize the RTP session, attach a group if none is present
* @param msec Minimum time to sleep in group loop in milliseconds
* @param prio Thread priority to run the new group
* @return True if initialized, false on some failure
*/
bool initGroup(int msec = 0, Thread::Priority prio = Thread::Normal);
/**
* Set the remote network address of the RTP transport of this session
* @param addr New remote RTP transport address
* @param sniff Automatically adjust the address from the first incoming packet
* @return True if address set, false if a failure occured
*/
inline bool remoteAddr(SocketAddr& addr, bool sniff = false)
{ return m_transport && m_transport->remoteAddr(addr,sniff); }
/**
* Set the Type Of Service for the RTP transport socket
* @param tos Type Of Service bits to set
* @return True if operation was successfull, false if an error occured
*/
inline bool setTOS(int tos)
{ return m_transport && m_transport->setTOS(tos); }
/**
* Get the main transport socket used by this session
* @return Pointer to the RTP or UDPTL socket, NULL if no transport exists
*/
inline Socket* rtpSock()
{ return m_transport ? m_transport->rtpSock() : 0; }
/**
* 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
*/
inline bool drillHole()
{ return m_transport && m_transport->drillHole(); }
/**
* Set the interval until receiver timeout is detected
* @param interval Milliseconds until receiver times out, zero to disable
*/
void setTimeout(int interval);
/**
* Get the RTP/RTCP transport of data handled by this session.
* @return A pointer to the RTPTransport of this session
*/
inline RTPTransport* transport() const
{ return m_transport; }
/**
* Set the UDP transport of data handled by this session
* @param trans A pointer to the new RTPTransport for this session
*/
virtual void transport(RTPTransport* trans);
protected:
/**
* Default constructor
*/
UDPSession();
/**
* Method called when the receiver timed out
* @param initial True if no packet was ever received in this session
*/
virtual void timeout(bool initial);
RTPTransport* m_transport;
u_int64_t m_timeoutTime;
u_int64_t m_timeoutInterval;
};
/**
* An unidirectional or bidirectional RTP session
* @short Full RTP session
*/
class YRTP_API RTPSession : public UDPSession, public Mutex
{
public:
/**
* Direction of the session
*/
enum Direction {
FullStop = 0,
RecvOnly = 1,
SendOnly = 2,
SendRecv = 3
};
/**
* Default constructor, creates a detached session
*/
RTPSession();
/**
* Destructor - shuts down the session and destroys the transport
*/
virtual ~RTPSession();
/**
* Retrieve MGCP P: style comma separated session parameters
* @param stats String to append parameters to
*/
virtual void getStats(String& stats) const;
/**
* This method is called to process a RTP packet.
* @param data Pointer to raw RTP data
* @param len Length of the data packet
*/
virtual void rtpData(const void* data, int len);
/**
* This method is called to process a RTCP packet.
* @param data Pointer to raw RTCP data
* @param len Length of the data packet
*/
virtual void rtcpData(const void* data, int len);
/**
* Process one RTP data packet
* @param marker Set to true if the marker bit is set
* @param timestamp Sampling instant of the packet data
* @param data Pointer to data block to process
* @param len Length of the data block in bytes
* @return True if data was handled
*/
virtual bool rtpRecvData(bool marker, unsigned int timestamp,
const void* data, int len);
/**
* Process one RTP event
* @param event Received event code
* @param key Received key (for events 0-16) or zero
* @param duration Duration of the event as number of samples
* @param volume Attenuation of the tone, zero for don't care
* @param timestamp Sampling instant of the initial packet data
* @return True if data was handled
*/
virtual bool rtpRecvEvent(int event, char key, int duration,
int volume, unsigned int timestamp);
/**
* Method called for unknown payload types just before attempting
* to call rtpRecvData(). This is a good opportunity to change the
* payload type and continue.
* @param payload Payload number
* @param timestamp Sampling instant of the unexpected packet data
*/
virtual void rtpNewPayload(int payload, unsigned int timestamp);
/**
* Method called when a packet with an unexpected SSRC is received
* just before processing further. This is a good opportunity to
* change the SSRC and continue
* @param newSsrc SSRC received in packet
* @param marker True if marker bit is set in the RTP packet
*/
virtual void rtpNewSSRC(u_int32_t newSsrc, bool marker);
/**
* Create a new RTP sender for this session.
* Override this method to create objects derived from RTPSender.
* @return Pointer to the new sender or NULL on failure
*/
virtual RTPSender* createSender();
/**
* Create a new RTP receiver for this session.
* Override this method to create objects derived from RTPReceiver.
* @return Pointer to the new receiver or NULL on failure
*/
virtual RTPReceiver* createReceiver();
/**
* Create a cipher when required for SRTP
* @param name Name of the cipher to create
* @param dir Direction the cipher must be able to handle
* @return Pointer to newly allocated Cipher or NULL
*/
virtual Cipher* createCipher(const String& name, Cipher::Direction dir);
/**
* Check if a cipher is supported for SRTP
* @param name Name of the cipher to check
* @return True if the specified cipher is supported
*/
virtual bool checkCipher(const String& name);
/**
* Send one RTP payload packet
* @param marker Set to true if the marker bit must be set
* @param payload Payload number
* @param timestamp Sampling instant of the packet data
* @param data Pointer to data block to send
* @param len Length of the data block
* @return True if data sending was attempted
*/
inline bool rtpSend(bool marker, int payload, unsigned int timestamp,
const void* data, int len)
{ Lock lck(this); return m_send && m_send->rtpSend(marker,payload,timestamp,data,len); }
/**
* Send one RTP data packet
* @param marker Set to true if the marker bit must be set
* @param timestamp Sampling instant of the packet data
* @param data Pointer to data block to send
* @param len Length of the data block
* @return True if data sending was attempted
*/
inline bool rtpSendData(bool marker, unsigned int timestamp,
const void* data, int len)
{ Lock lck(this); return m_send && m_send->rtpSendData(marker,timestamp,data,len); }
/**
* Send one RTP event
* @param event Event code to send
* @param duration Duration of the event as number of samples
* @param volume Attenuation of the tone, zero for don't care
* @param timestamp Sampling instant of the packet data, zero to use current
* @return True if data sending was attempted
*/
inline bool rtpSendEvent(int event, int duration, int volume = 0, unsigned int timestamp = 0)
{ Lock lck(this); return m_send && m_send->rtpSendEvent(event,duration,volume,timestamp); }
/**
* Send one RTP key event
* @param key Key to send
* @param duration Duration of the event as number of samples
* @param volume Attenuation of the tone, zero for don't care
* @param timestamp Sampling instant of the packet data, zero to use current
* @return True if data sending was attempted
*/
inline bool rtpSendKey(char key, int duration, int volume = 0, unsigned int timestamp = 0)
{ Lock lck(this); return m_send && m_send->rtpSendKey(key,duration,volume,timestamp); }
/**
* Retrieve the number of lost packets in current received
* @return Number of packets in sequence gaps
*/
inline u_int32_t ioPacketsLost() const
{ return m_recv ? m_recv->ioPacketsLost() : 0; }
/**
* Get the payload padding size
* @return Chunk size to pad the payload to a multiple of
*/
inline int padding() const
{ return m_send ? m_send->padding() : 0; }
/**
* Set the padding to a multiple of a data chunk
* @param chunk Size to pad the payload to a multiple of
* @return True if the new chunk size is valid
*/
inline bool padding(int chunk)
{ return m_send && m_send->padding(chunk); }
/**
* Allocate and set a new dejitter buffer for the receiver in the session
* @param mindelay Minimum length of the dejitter buffer in microseconds
* @param maxdelay Maximum length of the dejitter buffer in microseconds
*/
inline void setDejitter(unsigned int mindelay = 20, unsigned int maxdelay = 50)
{ if (m_recv) m_recv->setDejitter(mindelay,maxdelay); }
/**
* Set the RTP/RTCP transport of data handled by this session
* @param trans A pointer to the new RTPTransport for this session
*/
virtual void transport(RTPTransport* trans);
/**
* Get the RTP/RTCP sender of this session
* @return A pointer to the RTPSender of this session
*/
inline RTPSender* sender() const
{ return m_send; }
/**
* Set the RTP/RTCP sender of this session
* @param send A pointer to the new RTPSender of this session or NULL
*/
void sender(RTPSender* send);
/**
* Get the RTP/RTCP receiver of this session
* @return A pointer to the RTPReceiver of this session
*/
inline RTPReceiver* receiver() const
{ return m_recv; }
/**
* Set the RTP/RTCP receiver of this session
* @param recv A pointer to the new RTPReceiver of this session or NULL
*/
void receiver(RTPReceiver* recv);
/**
* Get the direction of this session
* @return Session's direction as a Direction enum
*/
inline Direction direction() const
{ return m_direction; }
/**
* Set the direction of this session. A transport must exist for this
* method to succeed.
* @param dir New Direction for this session
* @return True if direction was set, false if a failure occured
*/
bool direction(Direction dir);
/**
* Add a direction of this session. A transport must exist for this
* method to succeed.
* @param dir New Direction to add for this session
* @return True if direction was set, false if a failure occured
*/
inline bool addDirection(Direction dir)
{ return direction((Direction)(m_direction | dir)); }
/**
* Delete a direction of this session. A transport must exist for this
* method to succeed.
* @param dir Direction to remove for this session
* @return True if direction was set, false if a failure occured
*/
inline bool delDirection(Direction dir)
{ return direction((Direction)(m_direction & ~dir)); }
/**
* Set the data payload type for both receiver and sender.
* @param type Payload type, -1 to disable
* @return True if changed, false if invalid payload type
*/
bool dataPayload(int type);
/**
* Set the event payload type for both receiver and sender.
* @param type Payload type, -1 to disable
* @return True if changed, false if invalid payload type
*/
bool eventPayload(int type);
/**
* Set the silence payload type for both receiver and sender.
* @param type Payload type, -1 to disable
* @return True if changed, false if invalid payload type
*/
bool silencePayload(int type);
/**
* Set the local network address of the RTP transport of this session
* @param addr New local RTP transport address
* @param rtcp Enable RTCP in this session
* @return True if address set, false if a failure occured
*/
inline bool localAddr(SocketAddr& addr, bool rtcp = true)
{ Lock lck(this); return m_transport && m_transport->localAddr(addr,rtcp); }
/**
* Get the stored security provider or of the sender
* @return A pointer to the RTPSecure or NULL
*/
inline RTPSecure* security() const
{ return m_send ? m_send->security() : m_secure; }
/**
* Store a security provider for the sender
* @param secure Pointer to the new RTPSecure or NULL
*/
void security(RTPSecure* secure);
/**
* Set the RTCP report interval
* @param interval Average interval between reports in msec, zero to disable
*/
void setReports(int interval);
/**
* Put the collected statistical data
* @param stats NamedList to populate with the data
*/
virtual void getStats(NamedList& stats) const;
/**
* Increase the counter for number of RTP packets received from a wrong source
*/
virtual void incWrongSrc();
protected:
/**
* Method called periodically to push any asynchronous data or statistics
* @param when Time to use as base in all computing
*/
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;
};
/**
* A bidirectional UDPTL session usable for T.38
* @short UDPTL session
*/
class YRTP_API UDPTLSession : public UDPSession, public Mutex
{
public:
/**
* Destructor
*/
~UDPTLSession();
/**
* Set the local network address of the RTP transport of this session
* @param addr New local RTP transport address
* @return True if address set, false if a failure occured
*/
inline bool localAddr(SocketAddr& addr)
{ Lock lck(this); return m_transport && m_transport->localAddr(addr,false); }
/**
* Get the maximum UDPTL packet length
* @return Maximum length of UDPTL packet length in bytes
*/
inline u_int16_t maxLen() const
{ return m_maxLen; }
/**
* Get the maximum number of UDPTL secondary IFPs
* @return Maximum number of secondary IFPs, zero if disabled
*/
inline u_int8_t maxSec() const
{ return m_maxSec; }
/**
* This method is called to send or process an UDPTL packet
* @param data Pointer to raw UDPTL data
* @param len Length of the data packet
*/
virtual void rtpData(const void* data, int len);
/**
* Send UDPTL data over the transport, add older blocks for error recovery
* @param data Pointer to IFP block to send as primary
* @param len Length of primary IFP block
* @param seq Sequence number to incorporate in message
* @return True if data block was sent, false if an error occured
*/
bool udptlSend(const void* data, int len, u_int16_t seq);
protected:
/**
* UDPTL Session constructor
* @param maxLen Maximum length of UDPTL packet, at least longest primary IFP + 5 bytes
* @param maxSec Maximum number of secondary IFPs, set to zero to disable
*/
UDPTLSession(u_int16_t maxLen = 250, u_int8_t maxSec = 2);
/**
* Method called periodically to push any asynchronous data or statistics
* @param when Time to use as base in all computing
*/
virtual void timerTick(const Time& when);
/**
* Create a new UDPTL transport for this session.
* Override this method to create objects derived from RTPTransport.
* @return Pointer to the new transport or NULL on failure
*/
virtual RTPTransport* createTransport();
/**
* Method called when UDPTL data is received
* @param data Pointer to IFP block
* @param len Length of the IFP block
* @param seq Sequence number of the block
* @param recovered True if the IFP block was recovered after data loss
*/
virtual void udptlRecv(const void* data, int len, u_int16_t seq, bool recovered) = 0;
private:
void recoverSec(const unsigned char* data, int len, u_int16_t seq, int nSec);
u_int16_t m_rxSeq;
u_int16_t m_txSeq;
u_int16_t m_maxLen;
u_int8_t m_maxSec;
bool m_warn;
ObjList m_txQueue;
};
/**
* Security and integrity implementation
* @short SRTP implementation
*/
class YRTP_API RTPSecure : public GenObject
{
friend class RTPReceiver;
friend class RTPSender;
friend class RTPSession;
public:
/**
* Default constructor, builds an inactive implementation
*/
RTPSecure();
/**
* Constructor that creates an active implementation
* @param suite Cryptographic suite to use by default
*/
RTPSecure(const String& suite);
/**
* Constructor that copies the basic crypto lengths
* @param other Security provider to copy parameters from
*/
RTPSecure(const RTPSecure& other);
/**
* Destructor
*/
virtual ~RTPSecure();
/**
* Get the owner of this security instance
* @return Pointer to RTPBaseIO or NULL
*/
inline RTPBaseIO* owner() const
{ return m_owner; }
/**
* Set the owner of this security instance
* @param newOwner Pointer to new RTPBaseIO owning this security instance
*/
void owner(RTPBaseIO* newOwner);
/**
* Get the current RTP cipher if set
* @return Pointer to current RTP cipher or NULL
*/
inline Cipher* rtpCipher() const
{ return m_rtpCipher; }
/**
* Check if the systems supports requirements for activating SRTP
* @param session RTP session to use for cipher checking, NULL to use owner session
* @return True if it looks like SRTP can be activated later
*/
virtual bool supported(RTPSession* session = 0) const;
/**
* Set up the cryptographic parameters
* @param suite Descriptor of the encryption and authentication algorithms
* @param keyParams Keying material and related parameters
* @param paramList Optional session parameters as list of Strings
* @return True if the session parameters were applied successfully
*/
virtual bool setup(const String& suite, const String& keyParams, const ObjList* paramList = 0);
/**
* Create a set of cryptographic parameters
* @param suite Reference of returned cryptographic suite description
* @param keyParams Reference to returned keying material
* @param buildMaster Create random master key and salt if not already set
* @return True if security instance is valid and ready
*/
virtual bool create(String& suite, String& keyParams, bool buildMaster = true);
protected:
/**
* Initialize security related variables in the RTP session
*/
virtual void init();
/**
* Method called to encipher RTP payload data in-place
* @param data Pointer to data block to encipher
* @param len Length of payload data to be encrypted including any padding
*/
virtual void rtpEncipher(unsigned char* data, int len);
/**
* Method called to add integrity information to the RTP packet
* @param data Pointer to the RTP packet to protect
* @param len Length of RTP data to be encrypted including header and padding
* @param authData Address to write the integrity data to
*/
virtual void rtpAddIntegrity(const unsigned char* data, int len, unsigned char* authData);
/**
* Method called to decipher RTP data in-place
* @param data Pointer to data block to decipher
* @param len Length of data including any padding
* @param secData Pointer to security data if applicable
* @param ssrc SSRC of the packet to decipher
* @param seq Full (48 bit) seqence number of the packet including rollovers
* @return True is the packet was deciphered correctly or can't tell
*/
virtual bool rtpDecipher(unsigned char* data, int len, const void* secData, u_int32_t ssrc, u_int64_t seq);
/**
* Method called to check the integrity of the RTP packet
* @param data Pointer to RTP header and data
* @param len Length of header, data and padding
* @param authData Pointer to authentication data
* @param ssrc SSRC of the packet to validate
* @param seq Full (48 bit) seqence number of the packet including rollovers
* @return True is the packet passed integrity checks
*/
virtual bool rtpCheckIntegrity(const unsigned char* data, int len, const void* authData, u_int32_t ssrc, u_int64_t seq);
/**
* Internal method implementing key derivation
* @param cipher Cipher used for key derivation
* @param key Reference to derived key output
* @param len Desired length of the key, should be at most cipher block length
* @param label Derived key type
* @param index Packet index after being divided by KDR
* @return True if success, false if invalid parameters or missing cipher
*/
bool deriveKey(Cipher& cipher, DataBlock& key, unsigned int len, unsigned char label, u_int64_t index = 0);
private:
RTPBaseIO* m_owner;
Cipher* m_rtpCipher;
DataBlock m_masterKey;
DataBlock m_masterSalt;
DataBlock m_cipherKey;
DataBlock m_cipherSalt;
SHA1 m_authIpad;
SHA1 m_authOpad;
u_int32_t m_rtpAuthLen;
bool m_rtpEncrypted;
};
}
#endif /* __YATERTP_H */
/* vi: set ts=8 sw=4 sts=4 noet: */