// Copyright (C) 2001,2002,2004 Federico Montesino Pouzols <fedemp@altern.org>. // // 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. // // This exception applies only to the code released under the name GNU // ccRTP. If you copy code from other releases into a copy of GNU // ccRTP, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for GNU ccRTP, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. // /** * @file cqueue.h * * @short Generic RTCP control queues. **/ #ifndef CCXX_RTP_CQUEUE_H_ #define CCXX_RTP_CQUEUE_H_ #include <ccrtp/ioqueue.h> #ifdef CCXX_NAMESPACES namespace ost { #endif /** * @defgroup cqueue Generic RTCP control queues. * @{ **/ /** * @class QueueRTCPManager * @short Adds generic management of RTCP functions to an RTP data * queue. * * Extends an RTP data i/o queue adding management of RTCP functions: * * Provide feedback on the quality of the data distribution. * * Convey the CNAME (persistent transport-level identifier) for every * RTP source. * * Control the sending rate of RTCP packets * * Convey minimal control information about the participants * * This class implements generic RTCP behaviour (as specified in RFC * 1889/draft-ietf-avt-rtp-new) and may be specialized for specific * profiles (see AVPQueue) or particular RTCP extensions. * * @author Federico Montesino Pouzols <fedemp@altern.org> **/ class __EXPORT QueueRTCPManager : public RTPDataQueue, protected RTCPCompoundHandler { public: /** * Get the most recent sender report received from a * synchronization source. * * @param src Synchronization source of the sender info. * @return Most recent sender info received from src. * @retval NULL when no sender report has been received from * the specified source. **/ RTCPSenderInfo* getMRSenderInfo(SyncSource& src); /** * Ask for the info in the most recent receiver report about * the local source received from the source given as * parameter. * * @param srcFrom Source of the receiver info. * @return most recent receiver info received from src. * @retval NULL when no receiver report has been received from * the specified source. */ RTCPReceiverInfo* getMRReceiverInfo(SyncSource& srcFrom); /** * Set how much time the stack will wait before deleting a * synchronization source that has sent an RTCP BYE packet. * * @param delay delay in microseconds. * * @note The default delay is 1000000 microseconds **/ void setLeavingDelay(microtimeout_t delay) { leavingDelay = delay; } /** * This method sets the maximum end to end delay allowed. If * the processing delay plus the trip time for a packet is * greater than the end to end delay, the packet is discarded, * and the application cannot get it. * * This is a way of setting an upper bound to the end to end * delay, computed as the elapsed time between the packet * timestamping at the sender side, and the picking of the * packet at the receiver side. * * @param t maximum end to end delay allowed. A value of 0 * implies there is no limit and is the default */ inline void setEnd2EndDelay(microtimeout_t t) { end2EndDelay = t; } inline microtimeout_t getDefaultEnd2EndDelay() const { return defaultEnd2EndDelay; } inline microtimeout_t getEnd2EndDelay() const { return end2EndDelay; } /** * Specify the fraction of the total control bandwith to be * dedicated to senders reports. * * @param fraction fraction of bandwidth, must be between 0 an 1. * * This method sets the fraction of the global control * bandwidth that will be dedicated to senders reports. Of * course, <code>1 - fraction</code> will be dedicated to * receivers reports. * * @see setControlBandwidth */ inline void setSendersControlFraction(float fraction) { sendControlBwFract = fraction; recvControlBwFract = 1 - fraction;} /** * Manually set the minimum interval for sending RTP compound * packets * * @param interval minimum interval between RTCP packets, in * microseconds. * * @see computeRTCPInterval() **/ void setMinRTCPInterval(microtimeout_t interval) { rtcpMinInterval = interval; } /** * Get the total number of RTCP packets sent until now **/ inline uint32 getSendRTCPPacketCount() const { return ctrlSendCount; } protected: QueueRTCPManager(uint32 size = RTPDataQueue::defaultMembersHashSize, RTPApplication& app = defaultApplication()); QueueRTCPManager(uint32 ssrc, uint32 size = RTPDataQueue::defaultMembersHashSize, RTPApplication& app = defaultApplication()); virtual ~QueueRTCPManager(); const RTPApplication& getApplication() { return queueApplication; } inline void setControlBandwidth(float fraction) { controlBwFract = fraction; } float getControlBandwidth() const { return controlBwFract; } /** * Build and send RTCP packets following timing rules * (including the "timer reconsideration" algorithm). **/ void controlTransmissionService(); /** * Process incoming RTCP packets pending in the control * reception socket. **/ void controlReceptionService(); /** * Appy collision and loop detection and correction algorithm * when receiving RTCP packets. Follows section 8.2 in * draft-ietf-avp-rtp-new. * * @param sourceLink link to the source object. * @param is_new whether the source has been just recorded. * @param na RTCP packet network address. * @param tp RTCP packet source transport port. * * @return whether the packet must not be discarded. **/ bool checkSSRCInRTCPPkt(SyncSourceLink& sourceLink, bool is_new, InetAddress& na, tpport_t tp); void endQueueRTCPManager(); /** * Plug-in for processing (acquire information carried in) an * incoming RTCP Sender Report. The default implementation in * this class only processes the sender information and the * receiver report blocks about the local source. * * @param source Synchronization source this report comes from. * @param SR Sender report structure. * @param blocks Number of report blocks in the packet. **/ virtual void onGotSR(SyncSource& source, SendReport& SR, uint8 blocks); /** * Plug-in for processing (acquire information carried in) an * incoming RTCP Receiver Report. The default implementation * in this class only processes the receiver report blocks * about the local source. * * @param source Synchronization source this report comes from. * @param RR Receiver report structure * @param blocks Number of report blocks in the packet **/ virtual void onGotRR(SyncSource& source, RecvReport& RR, uint8 blocks); /** * @param source Synchronization source of SDES RTCP packet. * @param pkt SDES RTCP packet received. **/ bool onGotSDES(SyncSource& source, RTCPPacket& pkt); /** * Plug-in for handling of SDES chunks. * * @param source Synchronization source of SDES chunk. * @param chunk SDES chunk structure. * @param len Length of chunk, in octets. * * @return whether there was a CNAME. **/ virtual bool onGotSDESChunk(SyncSource& source, SDESChunk& chunk, size_t len); /** * Plug-in for handling of APP (application specific) RTCP * packets. * * @param - Synchronization source of this packet. * @param - RTCP APP packet struct. * @param - Length of the app data packet, including ssrc. * name and app. specific data. **/ inline virtual void onGotAPP(SyncSource&, RTCPCompoundHandler::APPPacket&, size_t) { return; } inline timeval getRTCPCheckInterval() { return rtcpCheckInterval; } /** * Get the number of data packets sent at the time the last SR * was generated. **/ uint32 getLastSendPacketCount() const { return lastSendPacketCount; } /** * @param n Number of members. **/ inline void setPrevMembersNum(uint32 n) { reconsInfo.rtcpPMembers = n; } inline uint32 getPrevMembersCount() const { return reconsInfo.rtcpPMembers; } /** * This method is used to send an RTCP BYE packet. An RTCP * BYE packet is sent when one of the the following * circumstances occur: * - when leaving the session * - when we have detected that another synchronization source * in the same session is using the same SSRC identifier as * us. * * Try to post a BYE message. It will send a BYE packet as * long as at least one RTP or RTCP packet has been sent * before. If the number of members in the session is more * than 50, the algorithm described in section 6.3.7 of * RFC 3550 is applied in order to avoid a flood * of BYE messages. * * @param reason reason to specify in the BYE packet. **/ size_t dispatchBYE(const std::string& reason); size_t sendControlToDestinations(unsigned char* buffer, size_t len); private: QueueRTCPManager(const QueueRTCPManager &o); QueueRTCPManager& operator=(const QueueRTCPManager &o); /** * Posting of RTCP messages. * * @return std::size_t number of octets sent */ size_t dispatchControlPacket(); /** * For picking up incoming RTCP packets if they are waiting. A * timeout for the maximum interval since the last RTCP packet * had been received is also returned. This is checked every * rtcpCheckInterval seconds. * * This method decomposes all incoming RTCP compound packets * pending in the control socket and processes each RTCP * packet. * **/ void takeInControlPacket(); /** * Computes the interval for sending RTCP compound packets, * based on the average size of RTCP packets sent and * received, and the current estimated number of participants * in the session. * * @note This currently follows the rules in section 6 of * RFC 3550 * @todo make it more flexible as recommended in the draft. For now, * we have setMinRTCPInterval. * * @return interval for sending RTCP compound packets **/ virtual timeval computeRTCPInterval(); /** * Choose which should be the type of the next SDES item * sent. This method is called when packing SDES chunks in a * new RTCP packet. * * @return type of the next SDES item to be sent **/ virtual SDESItemType scheduleSDESItem(); /** * Plug-in for SSRC collision handling. * * @param - previously identified source. **/ inline virtual void onSSRCCollision(const SyncSource&) { } /** * Virtual reimplemented from RTPDataQueue **/ virtual bool end2EndDelayed(IncomingRTPPktLink& p); /** * Plug-in for processing of SR/RR RTCP packet * profile-specific extensions (third part of SR reports or * second part of RR reports). * * @param - Content of the profile extension. * @param - Length of the extension, in octets. **/ inline virtual void onGotRRSRExtension(unsigned char*, size_t) { return; } /** * A plugin point for goodbye message. Called when a BYE RTCP * packet has been received from a valid synchronization * source. * * @param - synchronization source from what a BYE RTCP * packet has been just received. * @param - reason string the source has provided. **/ inline virtual void onGotGoodbye(const SyncSource&, const std::string&) { return; } /** * Process a BYE packet just received and identified. * * @param pkt previously identified RTCP BYE packet * @param pointer octet number in the RTCP reception buffer * where the packet is stored * @param len total length of the compount RTCP packet the BYE * packet to process is contained * * @bug if the bye packet contains several SSRCs, * eventSourceLeaving is only called for the last one **/ bool getBYE(RTCPPacket &pkt, size_t &pointer, size_t len); /** * @return number of Report Blocks packed **/ uint8 packReportBlocks(RRBlock* blocks, uint16& len, uint16& available); /** * Builds an SDES RTCP packet. Each chunk is built following * appendix A.4 in draft-ietf-avt-rtp-new. * * @param len provisionary length of the RTCP compound packet * * @return **/ void packSDES(uint16& len); /** * This must be called in order to update the average RTCP compound * packet size estimation when: * * a compoung RTCP packet is received (6.3.3). * * a compound RTCP packet is transmitted (6.3.6). * * @param len length in octets of the compound RTCP packet * just received/transmitted. **/ void updateAvgRTCPSize(size_t len); /** * Apply reverse reconsideration adjustment to timing * parameters when receiving BYE packets and not waiting to * send a BYE. **/ void reverseReconsideration(); bool timerReconsideration(); /** * Purge sources that do not seem active any more. * * @note MUST be perform at least every RTCP transmission * interval * @todo implement it. It may be dangerous and anyway should * be optional. **/ void expireSSRCs(); /** * To be executed when whe are leaving the session. **/ void getOnlyBye(); /** * Set item value from a string without null termination (as * it is transported in RTCP packets). **/ void setSDESItem(Participant* part, SDESItemType type, const char* const value, size_t len); /** * Set PRIV item previx value from a string without null * termination (as it is transported in RTCP packets). **/ void setPRIVPrefix(Participant* part, const char* const value, size_t len); /** * For certain control calculations in RTCP, the size of the * underlying network and transport protocols is needed. This * method provides the size of the network level header for * the default case of IP (20 octets). In case other protocol * with different header size is used, this method should be * redefined in a new specialized class. * * @return size of the headers of the network level. IP (20) by * default. **/ inline virtual uint16 networkHeaderSize() { return 20; } /** * For certain control calculations in RTCP, the size of the * underlying network and transport protocols is needed. This * method provides the size of the transport level header for * the default case of UDP (8 octets). In case other protocol * with different header size is used, this method should be * redefined in a new specialized class. * * return size of the headers of the transport level. UDP (8) * by default **/ inline virtual uint16 transportHeaderSize() { return 8; } SDESItemType nextSDESType(SDESItemType t); virtual size_t sendControl(const unsigned char* const buffer, size_t len) = 0; virtual size_t recvControl(unsigned char* buffer, size_t len, InetHostAddress& na, tpport_t& tp) = 0; virtual bool isPendingControl(microtimeout_t timeout) = 0; // whether the RTCP service is active volatile bool controlServiceActive; float controlBwFract, sendControlBwFract, recvControlBwFract; // number of RTCP packets sent since the beginning uint32 ctrlSendCount; // Network + transport headers size, typically size of IP + // UDP headers uint16 lowerHeadersSize; SDESItemType nextScheduledSDESItem; static const SDESItemType firstSchedulable; static const SDESItemType lastSchedulable; // state for rtcp timing. Its meaning is defined in // draft-ietf-avt-rtp-new, 6.3. // Parameters for timer reconsideration algorithm struct { timeval rtcpTp, rtcpTc, rtcpTn; uint32 rtcpPMembers; } reconsInfo; bool rtcpWeSent; uint16 rtcpAvgSize; bool rtcpInitial; // last time we checked if there were incoming RTCP packets timeval rtcpLastCheck; // interval to check if there are incoming RTCP packets timeval rtcpCheckInterval; // next time to check if there are incoming RTCP packets timeval rtcpNextCheck; // number of RTP data packets sent at the time of the last // RTCP packet transmission. uint32 lastSendPacketCount; // minimum interval for transmission of RTCP packets. The // result of computeRTCPInterval will always be >= (times a // random number between 0.5 and 1.5). microtimeout_t rtcpMinInterval; microtimeout_t leavingDelay; static const microtimeout_t defaultEnd2EndDelay; // Maximum delay allowed between packet timestamping and // packet availability for the application. microtimeout_t end2EndDelay; // Application this queue is bound to. RTPApplication& queueApplication; // an empty RTPData static const uint16 TIMEOUT_MULTIPLIER; static const double RECONSIDERATION_COMPENSATION; }; /** * This class, an RTP/RTCP queue, adds audio/video profile (AVP) * specific methods to the generic RTCP service queue * (QueueRTCPManager). * * @author Federico Montesino Pouzols <fedemp@altern.org> **/ class AVPQueue : public QueueRTCPManager { public: /** * Specify the bandwith available for control (RTCP) packets. * This method sets the global control bandwidth for both * sender and receiver reports. As recommended in RFC 1890, * 1/4 of the total control bandwidth is dedicated to senders, * whereas 3/4 are dedicated to receivers. * * @param fraction fraction of the session bandwidth, between * 0 and 1 * * @note If this method is not called, it is assumed that the * control bandwidth is equal to 5% of the session * bandwidth. Note also that the RFC RECOMMENDS the 5%. * **/ inline void setControlBandwidth(float fraction) { QueueRTCPManager::setControlBandwidth(fraction); } float getControlBandwidth() const { return QueueRTCPManager::getControlBandwidth(); } protected: AVPQueue(uint32 size = RTPDataQueue::defaultMembersHashSize, RTPApplication& app = defaultApplication()) : QueueRTCPManager(size,app) { } /** * Local SSRC is given instead of computed by the queue. **/ AVPQueue(uint32 ssrc, uint32 size = RTPDataQueue::defaultMembersHashSize, RTPApplication& app = defaultApplication()) : QueueRTCPManager(ssrc,size,app) { } inline virtual ~AVPQueue() { } }; /** @}*/ // cqueue #ifdef CCXX_NAMESPACES } #endif #endif //CCXX_RTP_CQUEUE_H_ /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */