/* * 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 <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_PARSE_ERROR -1 // error while parsing rtp packet #define RTP_TIMEOUT -2 // last received packet is too old #define RTP_DTMF -3 // dtmf packet has been received #define RTP_BUFFER_SIZE -4 // buffer overrun #define RTP_UNKNOWN_PL -5 // unknown payload struct amci_payload_t; class AmAudio; class AmSession; struct SdpPayload; typedef std::map<unsigned int, AmRtpPacket*, ts_less> ReceiveBuffer; typedef std::queue<AmRtpPacket*> RtpEventQueue; /** * This provides the memory for the receive buffer. */ struct PacketMem { #define MAX_PACKETS 32 AmRtpPacket packets[MAX_PACKETS]; bool used[MAX_PACKETS]; PacketMem(); inline AmRtpPacket* newPacket(); inline void freePacket(AmRtpPacket* p); inline void clear(); }; /** * \brief RTP implementation * * Rtp stream high level interface. */ class AmRtpStream { protected: /** Remote payload (only different from int_payload if using dynamic payloads) */ int payload; unsigned int sequence; /** Payload of last received packet. Usefull to detect talk spurt, looking for comfort noise packets. */ int last_payload; string r_host; unsigned short r_port; /* local interface */ int l_if; #ifdef SUPPORT_IPV6 struct sockaddr_storage r_saddr; struct sockaddr_storage l_saddr; #else struct sockaddr_in r_saddr; struct sockaddr_in l_saddr; #endif unsigned short l_port; int l_sd; struct timeval last_recv_time; unsigned int l_ssrc; unsigned int r_ssrc; bool r_ssrc_i; /** symmetric RTP */ bool passive; // passive mode ? /** Payload type for telephone event */ auto_ptr<const SdpPayload> telephone_event_pt; PacketMem mem; ReceiveBuffer receive_buf; RtpEventQueue rtp_ev_qu; AmMutex receive_mut; /** if relay_stream is initialized, received RTP is relayed there */ bool relay_enabled; /** pointer to relay stream. NOTE: This may only be accessed in initialization or by the AmRtpReceiver thread while relaying! */ AmRtpStream* relay_stream; /* get next packet in buffer */ int nextPacket(AmRtpPacket*& p); AmSession* session; int compile_and_send(const int payload, bool marker, unsigned int ts, unsigned char* buffer, unsigned int size); void sendDtmfPacket(unsigned int ts); // event, duration std::queue<pair<int, unsigned int> > dtmf_send_queue; AmMutex dtmf_send_queue_mut; enum dtmf_sending_state_t { DTMF_SEND_NONE, // not sending event DTMF_SEND_SENDING, // sending event DTMF_SEND_ENDING // sending end of event } dtmf_sending_state; pair<int, unsigned int> current_send_dtmf; unsigned int current_send_dtmf_ts; int send_dtmf_end_repeat; /** handle symmetric RTP - if in passive mode, update raddr from rp */ void handleSymmetricRtp(AmRtpPacket* rp); void relay(AmRtpPacket* p); public: AmRtpPacket* newPacket(); void freePacket(AmRtpPacket* p); /** Mute */ bool mute; /** mute && port == 0 */ bool hold; /** marker flag */ bool begin_talk; /** do check rtp timeout */ bool monitor_rtp_timeout; /** should we receive packets? if not -> drop */ bool receiving; int send( unsigned int ts, unsigned char* buffer, unsigned int size ); int send_raw( char* packet, unsigned int length ); int receive( unsigned char* buffer, unsigned int size, unsigned int& ts, int& payload); /** ping the remote side, to open NATs and enable symmetric RTP */ int ping(); /** Allocates resources for future use of RTP. */ AmRtpStream(AmSession* _s, int _if); /** Stops the stream and frees all resources. */ virtual ~AmRtpStream(); /** 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 a new random local port, and sets own attributes properly. */ void setLocalPort(); /** * Gets RTP port number. If no RTP port in assigned, assigns a new one. * @return local RTP port. */ int getLocalPort(); /** * 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); /** Symmetric RTP: passive mode ? */ void setPassiveMode(bool p) { passive = p; } bool getPassiveMode() { return passive; } unsigned int get_ssrc() { return l_ssrc; } /** * Set remote telephone event * payload type */ void setTelephoneEventPT(const SdpPayload *pt) { telephone_event_pt.reset(pt); } int getTelephoneEventRate(); /** * 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); /** * Enables RTP stream. * @param sdp_payload payload from the SDP message. * @warning start() must have been called so that play and record work. * @warning It should be called only if the stream has been completly initialized, * @warning and only once per session. Use resume() then. */ virtual void init(const vector<SdpPayload*>& sdp_payloads); /** * Stops RTP stream. */ void pause(); /** * Resume a paused RTP stream. */ void resume(); /** set the RTP stream on hold (mute && port = 0) */ void setOnHold(bool on_hold); /** get the RTP stream 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; } /** * Insert an RTP packet to the buffer. * Note: memory is owned by this instance. */ void bufferPacket(AmRtpPacket* p); /* * clear RTP timeout at time recv_time */ void clearRTPTimeout(struct timeval* recv_time); virtual unsigned int bytes2samples(unsigned int) const; /** set relay stream for RTP relaying */ void setRelayStream(AmRtpStream* stream); /** ensable RTP relaying through relay stream */ void enableRtpRelay(); /** disable RTP relaying through relay stream */ void disableRtpRelay(); }; /** \brief event fired on RTP timeout */ class AmRtpTimeoutEvent : public AmEvent { public: AmRtpTimeoutEvent() : AmEvent(0) { } ~AmRtpTimeoutEvent() { } }; #endif // Local Variables: // mode:C++ // End: