mirror of https://github.com/sipwise/sems.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
528 lines
14 KiB
528 lines
14 KiB
/*
|
|
* Copyright (C) 2002-2003 Fhg Fokus
|
|
*
|
|
* This file is part of SEMS, a free SIP media server.
|
|
*
|
|
* SEMS 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 released under
|
|
* the GPL with the additional exemption that compiling, linking,
|
|
* and/or using OpenSSL is allowed.
|
|
*
|
|
* For a license to use the SEMS software under conditions
|
|
* other than those described here, or to purchase support for this
|
|
* software, please contact iptel.org by e-mail at the following addresses:
|
|
* info@iptel.org
|
|
*
|
|
* SEMS 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
/** @file AmRtpStream.h */
|
|
#ifndef _RtpStream_h_
|
|
#define _RtpStream_h_
|
|
|
|
|
|
#include "AmSdp.h"
|
|
#include "AmThread.h"
|
|
#include "SampleArray.h"
|
|
#include "AmRtpPacket.h"
|
|
#include "AmEvent.h"
|
|
#include "AmDtmfSender.h"
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <string>
|
|
#include <map>
|
|
#include <queue>
|
|
#include <memory>
|
|
using std::string;
|
|
using std::auto_ptr;
|
|
using std::pair;
|
|
|
|
// return values of AmRtpStream::receive
|
|
#define RTP_EMPTY 0 // no rtp packet available
|
|
#define RTP_ERROR -1 // generic error
|
|
#define RTP_PARSE_ERROR -2 // error while parsing rtp packet
|
|
#define RTP_TIMEOUT -3 // last received packet is too old
|
|
#define RTP_DTMF -4 // dtmf packet has been received
|
|
#define RTP_BUFFER_SIZE -5 // buffer overrun
|
|
#define RTP_UNKNOWN_PL -6 // unknown payload
|
|
|
|
|
|
/**
|
|
* Forward declarations
|
|
*/
|
|
class AmAudio;
|
|
class AmSession;
|
|
struct SdpPayload;
|
|
struct amci_payload_t;
|
|
class msg_logger;
|
|
|
|
/**
|
|
* This provides the memory for the receive buffer.
|
|
*/
|
|
struct PacketMem {
|
|
#define MAX_PACKETS_BITS 5
|
|
#define MAX_PACKETS (1<<MAX_PACKETS_BITS)
|
|
#define MAX_PACKETS_MASK (MAX_PACKETS-1)
|
|
|
|
AmRtpPacket packets[MAX_PACKETS];
|
|
bool used[MAX_PACKETS];
|
|
|
|
PacketMem();
|
|
|
|
inline AmRtpPacket* newPacket();
|
|
inline void freePacket(AmRtpPacket* p);
|
|
inline void clear();
|
|
|
|
private:
|
|
unsigned int cur_idx;
|
|
unsigned int n_used;
|
|
};
|
|
|
|
/** \brief event fired on RTP timeout */
|
|
class AmRtpTimeoutEvent
|
|
: public AmEvent
|
|
{
|
|
|
|
public:
|
|
AmRtpTimeoutEvent()
|
|
: AmEvent(0) { }
|
|
~AmRtpTimeoutEvent() { }
|
|
};
|
|
|
|
/** helper class for assigning boolean floag to a payload ID
|
|
* it is used to check if the payload should be relayed or not */
|
|
class PayloadMask
|
|
{
|
|
private:
|
|
unsigned char bits[16];
|
|
|
|
public:
|
|
// clear flag for all payloads
|
|
void clear();
|
|
|
|
// set given flag (TODO: once it shows to be working, change / and % to >> and &)
|
|
void set(unsigned char payload_id) { if (payload_id < 128) bits[payload_id / 8] |= 1 << (payload_id % 8); }
|
|
|
|
// set all flags to 'true'
|
|
void set_all();
|
|
|
|
// invert all flags
|
|
void invert();
|
|
|
|
// get given flag
|
|
bool get(unsigned char payload_id) { if (payload_id > 127) { ERROR("BUG: payload_id out of range\n"); return false; } return (bits[payload_id / 8] & (1 << (payload_id % 8))); }
|
|
|
|
PayloadMask() { clear(); }
|
|
PayloadMask(bool _set_all) { if (_set_all) set_all(); else clear(); }
|
|
PayloadMask(const PayloadMask &src);
|
|
};
|
|
|
|
/**
|
|
* \brief represents one admissible payload type
|
|
*
|
|
*
|
|
*/
|
|
struct Payload {
|
|
unsigned char pt;
|
|
string name;
|
|
unsigned int clock_rate;
|
|
unsigned int advertised_clock_rate; // differs for G722
|
|
int codec_id;
|
|
string format_parameters;
|
|
};
|
|
|
|
/**
|
|
* \brief RTP implementation
|
|
*
|
|
* Rtp stream high level interface.
|
|
*/
|
|
class AmRtpStream
|
|
: public AmObject
|
|
{
|
|
protected:
|
|
|
|
// payload collection
|
|
typedef std::vector<Payload> PayloadCollection;
|
|
|
|
// list of locally supported payloads
|
|
PayloadCollection payloads;
|
|
|
|
// current payload (index into @payloads)
|
|
int payload;
|
|
|
|
struct PayloadMapping {
|
|
// remote payload type
|
|
int8_t remote_pt;
|
|
|
|
// index in payloads vector
|
|
uint8_t index;
|
|
};
|
|
|
|
typedef std::map<unsigned int, AmRtpPacket*, ts_less> ReceiveBuffer;
|
|
typedef std::queue<AmRtpPacket*> RtpEventQueue;
|
|
typedef std::map<unsigned char, PayloadMapping> PayloadMappingTable;
|
|
|
|
// mapping from local payload type to PayloadMapping
|
|
PayloadMappingTable pl_map;
|
|
|
|
/** SDP media slot number (n-th media line) */
|
|
int sdp_media_index;
|
|
|
|
/** RTP sequence number */
|
|
unsigned int sequence;
|
|
|
|
/**
|
|
Payload of last received packet.
|
|
Usefull to detect talk spurt, looking
|
|
for comfort noise packets.
|
|
*/
|
|
int last_payload;
|
|
|
|
/** Remote host information */
|
|
string r_host;
|
|
unsigned short r_port;
|
|
unsigned short r_rtcp_port;
|
|
|
|
/**
|
|
* Local interface used for this stream
|
|
* (index into @AmConfig::Ifs)
|
|
*/
|
|
int l_if;
|
|
|
|
/**
|
|
* Local and remote host addresses
|
|
*/
|
|
struct sockaddr_storage r_saddr;
|
|
struct sockaddr_storage l_saddr;
|
|
struct sockaddr_storage l_rtcp_saddr;
|
|
|
|
/** Local port */
|
|
unsigned short l_port;
|
|
|
|
/** Local socket */
|
|
int l_sd;
|
|
|
|
/** Local RTCP port */
|
|
unsigned int l_rtcp_port;
|
|
|
|
/** Local RTCP socket */
|
|
int l_rtcp_sd;
|
|
|
|
/** Timestamp of the last received RTP packet */
|
|
struct timeval last_recv_time;
|
|
|
|
/** Local and remote SSRC information */
|
|
unsigned int l_ssrc;
|
|
unsigned int r_ssrc;
|
|
bool r_ssrc_i;
|
|
|
|
/** symmetric RTP & RTCP */
|
|
bool passive;
|
|
bool passive_rtcp;
|
|
|
|
/** mute && port == 0 */
|
|
bool hold;
|
|
|
|
/** marker flag */
|
|
bool begin_talk;
|
|
|
|
/** do check rtp timeout */
|
|
bool monitor_rtp_timeout;
|
|
|
|
/** Payload type for telephone event */
|
|
auto_ptr<const SdpPayload> remote_telephone_event_pt;
|
|
auto_ptr<const SdpPayload> local_telephone_event_pt;
|
|
|
|
/** DTMF sender */
|
|
AmDtmfSender dtmf_sender;
|
|
|
|
/**
|
|
* Receive buffer, queue and mutex
|
|
*/
|
|
PacketMem mem;
|
|
ReceiveBuffer receive_buf;
|
|
RtpEventQueue rtp_ev_qu;
|
|
AmMutex receive_mut;
|
|
|
|
/** should we receive packets? if not -> drop */
|
|
bool receiving;
|
|
|
|
/** if relay_stream is initialized, received RTP is relayed there */
|
|
bool relay_enabled;
|
|
/** if true, packets are note parsed or checked */
|
|
bool relay_raw;
|
|
/** pointer to relay stream.
|
|
NOTE: This may only be accessed in initialization
|
|
or by the AmRtpReceiver thread while relaying! */
|
|
AmRtpStream* relay_stream;
|
|
/** control transparency for RTP seqno in RTP relay mode */
|
|
bool relay_transparent_seqno;
|
|
/** control transparency for RTP ssrc in RTP relay mode */
|
|
bool relay_transparent_ssrc;
|
|
/** filter RTP DTMF (2833 / 4733) in relaying */
|
|
bool relay_filter_dtmf;
|
|
|
|
/** Session owning this stream */
|
|
AmSession* session;
|
|
|
|
msg_logger *logger;
|
|
|
|
/** Payload provider */
|
|
AmPayloadProvider* payload_provider;
|
|
|
|
/** insert packet in DTMF queue if correct payload */
|
|
void recvDtmfPacket(AmRtpPacket* p);
|
|
|
|
/** Insert an RTP packet to the buffer queue */
|
|
void bufferPacket(AmRtpPacket* p);
|
|
/* Get next packet from the buffer queue */
|
|
int nextPacket(AmRtpPacket*& p);
|
|
|
|
/** Try to reuse oldest buffered packet for newly coming packet */
|
|
AmRtpPacket *reuseBufferedPacket();
|
|
|
|
/** handle symmetric RTP/RTCP - if in passive mode, update raddr from rp */
|
|
void handleSymmetricRtp(struct sockaddr_storage* recv_addr, bool rtcp);
|
|
|
|
void relay(AmRtpPacket* p);
|
|
|
|
/** Sets generic parameters on SDP media */
|
|
void getSdp(SdpMedia& m);
|
|
|
|
/** Clear RTP timeout at time recv_time */
|
|
void clearRTPTimeout(struct timeval* recv_time);
|
|
|
|
PayloadMask relay_payloads;
|
|
bool offer_answer_used;
|
|
|
|
/** set to true if any data received */
|
|
bool active;
|
|
|
|
/**
|
|
* Select a compatible default payload
|
|
* @return -1 if none available.
|
|
*/
|
|
int getDefaultPT();
|
|
|
|
public:
|
|
|
|
/**
|
|
* Set whether RTP stream will receive RTP packets internally (received packets will be dropped or not).
|
|
*/
|
|
void setReceiving(bool r);
|
|
|
|
/**
|
|
* Stops RTP stream receiving RTP packets internally (received packets will be dropped).
|
|
*/
|
|
void pause();
|
|
|
|
/**
|
|
* Resume a paused RTP stream internally (received packets will be processed).
|
|
*/
|
|
void resume();
|
|
|
|
/** Mute */
|
|
bool mute;
|
|
|
|
/** should we receive RFC-2833-style DTMF even when receiving is disabled? */
|
|
bool force_receive_dtmf;
|
|
|
|
/** Allocates resources for future use of RTP. */
|
|
AmRtpStream(AmSession* _s, int _if);
|
|
|
|
/** Stops the stream and frees all resources. */
|
|
virtual ~AmRtpStream();
|
|
|
|
int send( unsigned int ts,
|
|
unsigned char* buffer,
|
|
unsigned int size );
|
|
|
|
int send_raw( char* packet, unsigned int length );
|
|
|
|
int compile_and_send( const int payload, bool marker,
|
|
unsigned int ts, unsigned char* buffer,
|
|
unsigned int size );
|
|
|
|
int receive( unsigned char* buffer, unsigned int size,
|
|
unsigned int& ts, int& payload );
|
|
|
|
void recvPacket(int fd);
|
|
|
|
void recvRtcpPacket();
|
|
|
|
/** ping the remote side, to open NATs and enable symmetric RTP */
|
|
int ping();
|
|
|
|
/** returns the socket descriptor for local socket (initialized or not) */
|
|
int hasLocalSocket();
|
|
|
|
/** initializes and gets the socket descriptor for local socket */
|
|
int getLocalSocket();
|
|
|
|
/**
|
|
* This function must be called before setLocalPort, because
|
|
* setLocalPort will bind the socket and it will be not
|
|
* possible to change the IP later
|
|
*/
|
|
void setLocalIP(const string& ip);
|
|
|
|
/**
|
|
* Initializes with a new random local port if 'p' is 0,
|
|
* else binds the given port, and sets own attributes properly.
|
|
*/
|
|
void setLocalPort(unsigned short p = 0);
|
|
|
|
/**
|
|
* Gets RTP port number. If no RTP port in assigned, assigns a new one.
|
|
* @return local RTP port.
|
|
*/
|
|
int getLocalPort();
|
|
|
|
/**
|
|
* Gets RTCP port number. If no RTP/RTCP port in assigned, assigns a new one.
|
|
* @return local RTCP port.
|
|
*/
|
|
int getLocalRtcpPort();
|
|
|
|
/**
|
|
* Gets remote RTP port.
|
|
* @return remote RTP port.
|
|
*/
|
|
int getRPort();
|
|
|
|
/**
|
|
* Gets remote host IP.
|
|
* @return remote host IP.
|
|
*/
|
|
string getRHost();
|
|
|
|
/**
|
|
* Set remote IP & port.
|
|
*/
|
|
void setRAddr(const string& addr, unsigned short port,
|
|
unsigned short rtcp_port = 0);
|
|
|
|
/** Symmetric RTP & RTCP: passive mode ? */
|
|
void setPassiveMode(bool p);
|
|
bool getPassiveMode() { return passive || passive_rtcp; }
|
|
|
|
unsigned int get_ssrc() { return l_ssrc; }
|
|
|
|
int getLocalTelephoneEventPT();
|
|
int getLocalTelephoneEventRate();
|
|
|
|
void setPayloadProvider(AmPayloadProvider* pl_prov);
|
|
|
|
int getSdpMediaIndex() { return sdp_media_index; }
|
|
void forceSdpMediaIndex(int idx) { sdp_media_index = idx; offer_answer_used = false; }
|
|
int getPayloadType() { return payload; }
|
|
int getLastPayload() { return last_payload; }
|
|
string getPayloadName(int payload_type);
|
|
|
|
/**
|
|
* send a DTMF as RTP payload (RFC4733)
|
|
* @param event event ID (e.g. key press), see rfc
|
|
* @param duration_ms duration in milliseconds
|
|
*/
|
|
void sendDtmf(int event, unsigned int duration_ms);
|
|
|
|
/**
|
|
* Generate an SDP offer based on the stream capabilities.
|
|
* @param index index of the SDP media within the SDP.
|
|
* @param offer the local offer to be filled/completed.
|
|
*/
|
|
virtual void getSdpOffer(unsigned int index, SdpMedia& offer);
|
|
|
|
/**
|
|
* Generate an answer for the given SDP media based on the stream capabilities.
|
|
* @param index index of the SDP media within the SDP.
|
|
* @param offer the remote offer.
|
|
* @param answer the local answer to be filled/completed.
|
|
*/
|
|
virtual void getSdpAnswer(unsigned int index, const SdpMedia& offer, SdpMedia& answer);
|
|
|
|
/**
|
|
* Enables RTP stream.
|
|
* @param local the SDP message generated by the local UA.
|
|
* @param remote the SDP message generated by the remote UA.
|
|
* @warning It is necessary to call getSdpOffer/getSdpAnswer prior to init(...)
|
|
* @warning so that the internal SDP media line index is set properly.
|
|
*/
|
|
virtual int init(const AmSdp& local, const AmSdp& remote, bool force_passive_mode = false);
|
|
|
|
/** set the RTP stream on hold */
|
|
void setOnHold(bool on_hold);
|
|
|
|
/** get whether RTP stream is on hold */
|
|
bool getOnHold();
|
|
|
|
/** setter for monitor_rtp_timeout */
|
|
void setMonitorRTPTimeout(bool m) { monitor_rtp_timeout = m; }
|
|
/** getter for monitor_rtp_timeout */
|
|
bool getMonitorRTPTimeout() { return monitor_rtp_timeout; }
|
|
|
|
/*
|
|
* clear RTP timeout to current time
|
|
*/
|
|
void clearRTPTimeout();
|
|
|
|
/** set relay stream for RTP relaying */
|
|
void setRelayStream(AmRtpStream* stream);
|
|
|
|
/** set relay payloads for RTP relaying */
|
|
void setRelayPayloads(const PayloadMask &_relay_payloads);
|
|
|
|
/** ensable RTP relaying through relay stream */
|
|
void enableRtpRelay();
|
|
|
|
/** disable RTP relaying through relay stream */
|
|
void disableRtpRelay();
|
|
|
|
/** enable raw UDP relaying through relay stream */
|
|
void enableRawRelay();
|
|
|
|
/** disable raw UDP relaying through relay stream */
|
|
void disableRawRelay();
|
|
|
|
/** enable or disable transparent RTP seqno for relay */
|
|
void setRtpRelayTransparentSeqno(bool transparent);
|
|
|
|
/** enable or disable transparent SSRC seqno for relay */
|
|
void setRtpRelayTransparentSSRC(bool transparent);
|
|
|
|
/** enable or disable filtering of RTP DTMF for relay */
|
|
void setRtpRelayFilterRtpDtmf(bool filter);
|
|
|
|
/** remove from RTP receiver */
|
|
void stopReceiving();
|
|
|
|
/** (re-)insert into RTP receiver */
|
|
void resumeReceiving();
|
|
|
|
/** Quick hack to assign existing stream to another session. The stream should
|
|
* not be reinitialised implicitly (it might be used for media traffic
|
|
* already). */
|
|
void changeSession(AmSession *_s) { session = _s; }
|
|
|
|
/** set destination for logging all received/sent RTP and RTCP packets */
|
|
void setLogger(msg_logger *_logger);
|
|
|
|
void debug();
|
|
};
|
|
|
|
#endif
|
|
|
|
// Local Variables:
|
|
// mode:C++
|
|
// End:
|
|
|