INET Framework for OMNeT++/OMNEST
RTCP Class Reference

#include <RTCP.h>

List of all members.

Public Member Functions

 RTCP ()

Protected Member Functions

virtual void initialize ()
virtual ~RTCP ()
virtual void handleMessage (cMessage *msg)
virtual void handleMessageFromRTP (cMessage *msg)
virtual void handleMessageFromUDP (cMessage *msg)
virtual void handleSelfMessage (cMessage *msg)
virtual void initializeRTCP (RTPInnerPacket *rinp)
virtual void senderModuleInitialized (RTPInnerPacket *rinp)
virtual void dataOut (RTPInnerPacket *packet)
virtual void dataIn (RTPInnerPacket *rinp)
virtual void leaveSession (RTPInnerPacket *rinp)
virtual void connectRet ()
virtual void readRet (cPacket *sifpIn)
virtual void createSocket ()
virtual void chooseSSRC ()
virtual void scheduleInterval ()
virtual void createPacket ()
virtual void processOutgoingRTPPacket (RTPPacket *packet)
virtual void processIncomingRTPPacket (RTPPacket *packet, IPAddress address, int port)
virtual void processIncomingRTCPPacket (RTCPCompoundPacket *packet, IPAddress address, int port)
virtual RTPParticipantInfofindParticipantInfo (uint32 ssrc)
virtual void calculateAveragePacketSize (int size)

Protected Attributes

int _mtu
int _bandwidth
int _rtcpPercentage
IPAddress _destinationAddress
int _port
bool _ssrcChosen
bool _leaveSession
RTPSenderInfo_senderInfo
cArray * _participantInfos
int _socketFdIn
int _socketFdOut
int _packetsCalculated
double _averagePacketSize
cOutVector * _rtcpIntervalOutVector

Detailed Description

The class RTCP is responsible for creating, receiving and processing of rtcp packets. It also keeps track of this and other rtp end systems.


Constructor & Destructor Documentation

RTCP::RTCP ( )
{
    _participantInfos = NULL;
}
RTCP::~RTCP ( ) [protected, virtual]
{
    delete _participantInfos;
}

Member Function Documentation

void RTCP::calculateAveragePacketSize ( int  size) [protected, virtual]

Recalculates the average size of an RTCPCompoundPacket when one of this size has been sent or received.

Referenced by createPacket(), and processIncomingRTCPPacket().

{
    // add size of ip and udp header to given size before calculating
    _averagePacketSize = ((double)(_packetsCalculated) * _averagePacketSize + (double)(size + 20 + 8)) / (double)(++_packetsCalculated);
}
void RTCP::chooseSSRC ( ) [protected, virtual]

Chooses the ssrc identifier for this end system.

Referenced by handleSelfMessage().

                     {

    uint32 ssrc = 0;
    bool ssrcConflict = false;
    do {
        ssrc = intrand(0x7fffffff);
        ssrcConflict = findParticipantInfo(ssrc) != NULL;
    } while (ssrcConflict);
    ev << "chooseSSRC" << ssrc;
    _senderInfo->setSSRC(ssrc);
    _participantInfos->add(_senderInfo);
    _ssrcChosen = true;
}
void RTCP::connectRet ( ) [protected, virtual]

Called when the socket layer has finished a connect.

Referenced by createSocket().

{
    // schedule first rtcp packet
    double intervalLength = 2.5 * (dblrand() + 0.5);
    cMessage *reminderMessage = new cMessage("Interval");
    scheduleAt(simTime() + intervalLength, reminderMessage);
}
void RTCP::createPacket ( ) [protected, virtual]

Creates and sends an RTCPCompoundPacket.

Referenced by handleSelfMessage().

{
    // first packet in an rtcp compound packet must
    // be a sender or receiver report
    RTCPReceiverReportPacket *reportPacket;

    // if this rtcp end system is a sender (see SenderInformation::isSender() for
    // details) insert a sender report
    if (_senderInfo->isSender()) {
        RTCPSenderReportPacket *senderReportPacket = new RTCPSenderReportPacket("SenderReportPacket");
        senderReportPacket->setSenderReport(_senderInfo->senderReport(simTime()));
        reportPacket = senderReportPacket;
    }
    else
        reportPacket = new RTCPReceiverReportPacket("ReceiverReportPacket");
    reportPacket->setSSRC(_senderInfo->getSSRC());


    // insert receiver reports for packets from other sources
    for (int i = 0; i < _participantInfos->size(); i++) {

        if (_participantInfos->exist(i)) {
            RTPParticipantInfo *participantInfo = (RTPParticipantInfo *)(_participantInfos->get(i));
            if (participantInfo->getSSRC() != _senderInfo->getSSRC()) {
                ReceptionReport *report = ((RTPReceiverInfo *)participantInfo)->receptionReport(simTime());
                if (report != NULL) {
                    reportPacket->addReceptionReport(report);
                }
            }
            participantInfo->nextInterval(simTime());

            if (participantInfo->toBeDeleted(simTime())) {
                _participantInfos->remove(participantInfo);
                delete participantInfo;
                // perhaps inform the profile
            }
        }
    }
    // insert source description items (at least common name)
    RTCPSDESPacket *sdesPacket = new RTCPSDESPacket("SDESPacket");

    SDESChunk *chunk = _senderInfo->getSDESChunk();
    sdesPacket->addSDESChunk(chunk);

    RTCPCompoundPacket *compoundPacket = new RTCPCompoundPacket("RTCPCompoundPacket");

    compoundPacket->addRTCPPacket(reportPacket);
    compoundPacket->addRTCPPacket(sdesPacket);

    // create rtcp app/bye packets if needed
    if (_leaveSession) {
        RTCPByePacket *byePacket = new RTCPByePacket("ByePacket");
        byePacket->setSSRC(_senderInfo->getSSRC());
        compoundPacket->addRTCPPacket(byePacket);
    }

    calculateAveragePacketSize(compoundPacket->getByteLength());

    cPacket *msg = new cPacket("RTCPCompoundPacket");
    msg->encapsulate(compoundPacket);
    msg->setKind(UDP_C_DATA);
    UDPControlInfo *ctrl = new UDPControlInfo();
    ctrl->setSockId(_socketFdOut);
    ctrl->setDestAddr(_destinationAddress);
    ctrl->setDestPort(_port);
    msg->setControlInfo(ctrl);

    send(msg, "udpOut");

    if (_leaveSession) {
        RTPInnerPacket *rinp = new RTPInnerPacket("sessionLeft()");
        rinp->sessionLeft();
        send(rinp, "rtpOut");
    }
}
void RTCP::createSocket ( ) [protected, virtual]

Request a server socket from the socket layer.

Referenced by initializeRTCP().

{
    // TODO UDPAppBase should be ported to use UDPSocket sometime, but for now
    // we just manage the UDP socket by hand...
    if (_socketFdIn == -1) {
        _socketFdIn = UDPSocket::generateSocketId();
        UDPControlInfo *ctrl = new UDPControlInfo();
        IPAddress ipaddr(_destinationAddress);

        if (ipaddr.isMulticast()) {
            ctrl->setSrcAddr(IPAddress(_destinationAddress));
            ctrl->setSrcPort(_port);
        }
        else {
             ctrl->setSrcPort(_port);
             ctrl->setSockId(_socketFdOut);
        }
        ctrl->setSockId((int)_socketFdIn);
        cMessage *msg = new cMessage("UDP_C_BIND", UDP_C_BIND);
        msg->setControlInfo(ctrl);
        send(msg,"udpOut");

        connectRet();
    }
}
void RTCP::dataIn ( RTPInnerPacket rinp) [protected, virtual]

Stores information about an outgoing rtp data packet.

Referenced by handleMessageFromRTP().

{
    RTPPacket *rtpPacket = check_and_cast<RTPPacket *>(rinp->decapsulate());
    //rtpPacket->dump();
    processIncomingRTPPacket(rtpPacket, rinp->getAddress(), rinp->getPort());
}
void RTCP::dataOut ( RTPInnerPacket packet) [protected, virtual]

Stores information about an outgoing rtp data packet.

Referenced by handleMessageFromRTP().

{
    RTPPacket *rtpPacket = check_and_cast<RTPPacket *>(packet->decapsulate());
    processOutgoingRTPPacket(rtpPacket);
}
RTPParticipantInfo * RTCP::findParticipantInfo ( uint32  ssrc) [protected, virtual]

Returns the RTPParticipantInfo object used for storing information about the rtp end system with this ssrc identifier. Returns NULL if this end system is unknown.

Referenced by chooseSSRC(), processIncomingRTCPPacket(), and processIncomingRTPPacket().

{
    char *ssrcString = RTPParticipantInfo::ssrcToName(ssrc);
    int participantIndex = _participantInfos->find(ssrcString);
    if (participantIndex != -1) {
        return (RTPParticipantInfo *)(_participantInfos->get(participantIndex));
    }
    else {
        return NULL;
    }
}
void RTCP::handleMessage ( cMessage *  msg) [protected, virtual]

Message handling. Dispatches messages by arrival gate.

{

    // first distinguish incoming messages by arrival gate
    if (msg->getArrivalGateId() == findGate("rtpIn")) {
        handleMessageFromRTP(msg);
    }
    else if (msg->getArrivalGateId() == findGate("udpIn")) {
        handleMessageFromUDP(msg);
    }
    else {
        handleSelfMessage(msg);
    }

    delete msg;
}
void RTCP::handleMessageFromRTP ( cMessage *  msg) [protected, virtual]

Handles messages from the rtp module.

Referenced by handleMessage().

{

    // from the rtp module all messages are of type RTPInnerPacket
    RTPInnerPacket *rinp = check_and_cast<RTPInnerPacket *>(msg);

    // distinguish by type
    if (rinp->getType() == RTPInnerPacket::RTP_INP_INITIALIZE_RTCP) {
        initializeRTCP(rinp);
    }
    else if (rinp->getType() == RTPInnerPacket::RTP_INP_SENDER_MODULE_INITIALIZED) {
        senderModuleInitialized(rinp);
    }
    else if (rinp->getType() == RTPInnerPacket::RTP_INP_DATA_OUT) {
        dataOut(rinp);
    }
    else if (rinp->getType() == RTPInnerPacket::RTP_INP_DATA_IN) {
        dataIn(rinp);
    }
    else if (rinp->getType() == RTPInnerPacket::RTP_INP_LEAVE_SESSION) {
        leaveSession(rinp);
    }
    else {
        error("unknown RTPInnerPacket type");
    }
}
void RTCP::handleMessageFromUDP ( cMessage *  msg) [protected, virtual]

Handles messages coming from the socket layer.

Referenced by handleMessage().

{
    // from SocketLayer all message are of type cMessage
    readRet(PK(msg));
}
void RTCP::handleSelfMessage ( cMessage *  msg) [protected, virtual]

Handles self messages.

Referenced by handleMessage().

{
    // it's time to create an rtcp packet
    if (!_ssrcChosen) {
        chooseSSRC();
        RTPInnerPacket *rinp1 = new RTPInnerPacket("rtcpInitialized()");
        rinp1->rtcpInitialized(_senderInfo->getSSRC());
        send(rinp1, "rtpOut");
    }

    createPacket();

    if (!_leaveSession) {
        scheduleInterval();
    }
}
void RTCP::initialize ( ) [protected, virtual]

Initializes variables.

{

    // initialize variables
    _ssrcChosen = false;
    _leaveSession = false;
    _socketFdIn = -1;
    _socketFdOut = -1;

    _packetsCalculated = 0;
    _averagePacketSize = 0.0;

    _participantInfos = new cArray("ParticipantInfos");
}
void RTCP::initializeRTCP ( RTPInnerPacket rinp) [protected, virtual]

Initializes the rtcp module when the session is started.

Referenced by handleMessageFromRTP().

{
    _mtu = rinp->getMTU();
    _bandwidth = rinp->getBandwidth();
    _rtcpPercentage = rinp->getRtcpPercentage();
    _destinationAddress = rinp->getAddress();
    _port = rinp->getPort();

    _senderInfo = new RTPSenderInfo();

    SDESItem *sdesItem = new SDESItem(SDESItem::SDES_CNAME, rinp->getCommonName());
    _senderInfo->addSDESItem(sdesItem);


    // create server socket for receiving rtcp packets
    createSocket();
}
void RTCP::leaveSession ( RTPInnerPacket rinp) [protected, virtual]

Makes the rtcp module send an RTCPByePacket in the next RTCPCompoundPacket to tell other participants in the rtp session that this end system leaves.

Referenced by handleMessageFromRTP().

{
    _leaveSession = true;
}
void RTCP::processIncomingRTCPPacket ( RTCPCompoundPacket packet,
IPAddress  address,
int  port 
) [protected, virtual]

Extracts information of a received RTCPCompoundPacket.

Referenced by readRet().

{
    calculateAveragePacketSize(packet->getByteLength());
    cArray *rtcpPackets = packet->getRtcpPackets();

    simtime_t arrivalTime = packet->getArrivalTime();
    delete packet;

   for (int i = 0; i < rtcpPackets->size(); i++) {
        if (rtcpPackets->exist(i)) {
            // remove the rtcp packet from the rtcp compound packet
            RTCPPacket *rtcpPacket = (RTCPPacket *)(rtcpPackets->remove(i));
            if (rtcpPacket->getPacketType() == RTCPPacket::RTCP_PT_SR) {
                RTCPSenderReportPacket *rtcpSenderReportPacket = (RTCPSenderReportPacket *)rtcpPacket;
                uint32 ssrc = rtcpSenderReportPacket->getSSRC();
                RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);

                if (participantInfo == NULL) {
                    participantInfo = new RTPReceiverInfo(ssrc);
                    participantInfo->setAddress(address);
                    participantInfo->setRTCPPort(port);
                    _participantInfos->add(participantInfo);
                }
                else {
                    if (participantInfo->getAddress() == address) {
                        if (participantInfo->getRTCPPort() == PORT_UNDEF) {
                            participantInfo->setRTCPPort(port);
                        }
                        else {
                            // check for ssrc conflict
                        }
                    }
                    else {
                        // check for ssrc conflict
                    }
                }
                participantInfo->processSenderReport(rtcpSenderReportPacket->getSenderReport(), simTime());

                cArray *receptionReports = rtcpSenderReportPacket->getReceptionReports();
                for (int j = 0; j < receptionReports->size(); j++) {
                    if (receptionReports->exist(j)) {
                        ReceptionReport *receptionReport = (ReceptionReport *)(receptionReports->remove(j));
                        if (_senderInfo) {
                            if (receptionReport->getSSRC() == _senderInfo->getSSRC()) {
                                _senderInfo->processReceptionReport(receptionReport, simTime());
                            }
                        }
                        else
                            //cancelAndDelete(receptionReport);
                            delete receptionReport;
                    }
                }
                delete receptionReports;

            }
            else if (rtcpPacket->getPacketType() == RTCPPacket::RTCP_PT_RR) {
                RTCPReceiverReportPacket *rtcpReceiverReportPacket = (RTCPReceiverReportPacket *)rtcpPacket;
                uint32 ssrc = rtcpReceiverReportPacket->getSSRC();
                RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);
                if (participantInfo == NULL) {
                    participantInfo = new RTPReceiverInfo(ssrc);
                    participantInfo->setAddress(address);
                    participantInfo->setRTCPPort(port);
                    _participantInfos->add(participantInfo);
                }
                else {
                    if (participantInfo->getAddress() == address) {
                        if (participantInfo->getRTCPPort() == PORT_UNDEF) {
                            participantInfo->setRTCPPort(port);
                        }
                        else {
                            // check for ssrc conflict
                        }
                    }
                    else {
                        // check for ssrc conflict
                    }
                }

                cArray *receptionReports = rtcpReceiverReportPacket->getReceptionReports();
                for (int j = 0; j < receptionReports->size(); j++) {
                    if (receptionReports->exist(j)) {
                        ReceptionReport *receptionReport = (ReceptionReport *)(receptionReports->remove(j));
                        if (_senderInfo) {

                            if (receptionReport->getSSRC() == _senderInfo->getSSRC()) {
                                _senderInfo->processReceptionReport(receptionReport, simTime());
                            }
                        }

                         else
                            //cancelAndDelete(receptionReport);
                             delete receptionReport;
                    }
                }
                delete receptionReports;
            }
            else if (rtcpPacket->getPacketType() == RTCPPacket::RTCP_PT_SDES) {
                RTCPSDESPacket *rtcpSDESPacket = (RTCPSDESPacket *)rtcpPacket;
                cArray *sdesChunks = rtcpSDESPacket->getSdesChunks();

                for (int j = 0; j < sdesChunks->size(); j++) {
                    if (sdesChunks->exist(j)) {
                        // remove the sdes chunk from the cArray of sdes chunks
                        SDESChunk *sdesChunk = (SDESChunk *)(sdesChunks->remove(j));
                        // this is needed to avoid seg faults
                        //sdesChunk->setOwner(this);
                        uint32 ssrc = sdesChunk->getSSRC();
                        RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);
                        if (participantInfo == NULL) {
                            participantInfo = new RTPReceiverInfo(ssrc);
                            participantInfo->setAddress(address);
                            participantInfo->setRTCPPort(port);
                            _participantInfos->add(participantInfo);
                        }
                        else {
                            // check for ssrc conflict
                        }
                        participantInfo->processSDESChunk(sdesChunk, arrivalTime);
                    }
                }
                delete sdesChunks;

            }
            else if (rtcpPacket->getPacketType() == RTCPPacket::RTCP_PT_BYE) {
                RTCPByePacket *rtcpByePacket = (RTCPByePacket *)rtcpPacket;
                uint32 ssrc = rtcpByePacket->getSSRC();
                RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);

                if (participantInfo != NULL && participantInfo != _senderInfo) {
                    _participantInfos->remove(participantInfo);

                    delete participantInfo;
                    // perhaps it would be useful to inform
                    // the profile to remove the corresponding
                    // receiver module
                }
            }
            else {
                // app rtcp packets
            }
        delete rtcpPacket;
        }
    }
    delete rtcpPackets;
}
void RTCP::processIncomingRTPPacket ( RTPPacket packet,
IPAddress  address,
int  port 
) [protected, virtual]

Extracts information of a received RTPPacket.

Referenced by dataIn().

{
    uint32 ssrc = packet->getSSRC();
    RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);
    if (participantInfo == NULL) {
        participantInfo = new RTPParticipantInfo(ssrc);
        participantInfo->setAddress(address);
        participantInfo->setRTPPort(port);
        _participantInfos->add(participantInfo);
    }
    else {
        // check for ssrc conflict
        if (participantInfo->getAddress() != address) {
            // we have an address conflict
        }
        if (participantInfo->getRTPPort() == PORT_UNDEF) {
            participantInfo->setRTPPort(port);
        }
        else if (participantInfo->getRTPPort() != port) {
            // we have an rtp port conflict
        }
    }
    participantInfo->processRTPPacket(packet, getId(),  packet->getArrivalTime());
}
void RTCP::processOutgoingRTPPacket ( RTPPacket packet) [protected, virtual]

Extracts information of a sent RTPPacket.

Referenced by dataOut().

{
    _senderInfo->processRTPPacket(packet, getId(), simTime());
}
void RTCP::readRet ( cPacket *  sifpIn) [protected, virtual]

Called when this rtcp module receives data from the socket layer.

Referenced by handleMessageFromUDP().

void RTCP::scheduleInterval ( ) [protected, virtual]

Calculates the length of the next rtcp interval an issues a self message to remind itself.

Referenced by handleSelfMessage().

                           {

    simtime_t intervalLength = _averagePacketSize * (simtime_t)(_participantInfos->size()) / (simtime_t)(_bandwidth * _rtcpPercentage * (_senderInfo->isSender() ? 1.0 : 0.75) / 100.0);

    // interval length must be at least 5 seconds
    if (intervalLength < 5.0)
        intervalLength = 5.0;

    // to avoid rtcp packet bursts multiply calculated interval length
    // with a random number between 0.5 and 1.5
    intervalLength = intervalLength * (0.5 + dblrand());

    intervalLength /= (double) (2.71828-1.5); // [RFC 3550] , by Ahmed ayadi

    cMessage *reminderMessage = new cMessage("Interval");
    scheduleAt(simTime() + intervalLength, reminderMessage);
}
void RTCP::senderModuleInitialized ( RTPInnerPacket rinp) [protected, virtual]

Stores information about the new transmission.

Referenced by handleMessageFromRTP().


Member Data Documentation

double RTCP::_averagePacketSize [protected]
int RTCP::_bandwidth [protected]

The bandwidth for this rtp session.

Referenced by initializeRTCP(), and scheduleInterval().

The destination address.

Referenced by createPacket(), createSocket(), initializeRTCP(), and readRet().

bool RTCP::_leaveSession [protected]

True when this end system is about to leave the session.

Referenced by createPacket(), handleSelfMessage(), initialize(), and leaveSession().

int RTCP::_mtu [protected]

The maximum size an RTCPCompundPacket can have.

Referenced by initializeRTCP().

int RTCP::_packetsCalculated [protected]

The number of packets this rtcp module has calculated.

Referenced by calculateAveragePacketSize(), and initialize().

cArray* RTCP::_participantInfos [protected]

Information about all known rtp end system participating in this rtp session.

Referenced by chooseSSRC(), createPacket(), findParticipantInfo(), initialize(), processIncomingRTCPPacket(), processIncomingRTPPacket(), RTCP(), scheduleInterval(), and ~RTCP().

int RTCP::_port [protected]

The rtcp port.

Referenced by createPacket(), createSocket(), initializeRTCP(), and readRet().

cOutVector* RTCP::_rtcpIntervalOutVector [protected]

The output vector for statistical data about the behaviour of rtcp. Every participant's rtcp module writes its calculated rtcp interval (without variation

int RTCP::_rtcpPercentage [protected]

The percentage of bandwidth for rtcp.

Referenced by initializeRTCP(), and scheduleInterval().

int RTCP::_socketFdIn [protected]

The server socket for receiving rtcp packets.

Referenced by createSocket(), and initialize().

int RTCP::_socketFdOut [protected]

The client socket for sending rtcp packets.

Referenced by createPacket(), createSocket(), and initialize().

bool RTCP::_ssrcChosen [protected]

True when this end system has chosen its ssrc identifier.

Referenced by chooseSSRC(), handleSelfMessage(), and initialize().


The documentation for this class was generated from the following files: