/* ====================================================================
 * The Vovida Software License, Version 1.0 
 * 
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
 *    and "Vovida Open Communication Application Library (VOCAL)" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact vocal@vovida.org.
 *
 * 4. Products derived from this software may not be called "VOCAL", nor
 *    may "VOCAL" appear in their name, without prior written
 *    permission of Vovida Networks, Inc.
 * 
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 * 
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by Vovida
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
 * Inc.  For more information on Vovida Networks, Inc., please see
 * <http://www.vovida.org/>.
 *
 */

static const char* const RtpSession_cxx_Version =
    "$Id: RtpSession.cxx,v 1.57 2002/06/24 20:44:14 sprajpat Exp $";


#include "global.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/types.h>
#include "vtypes.h"
#include "cpLog.h"
#include "vsock.hxx"

#include "rtpTypes.h"
#include "Rtp.hxx"
#include "Rtcp.hxx"
#include "RtpSession.hxx"



/* ----------------------------------------------------------------- */
/* --- rtp session Constructor ------------------------------------- */
/* ----------------------------------------------------------------- */

RtpSession::RtpSession (const char* remoteHost, int remotePort, int localPort,
                        int rtcpRemotePort, int rtcpLocalPort, int portRange,
                        RtpPayloadType apiPayloadType,
                        RtpPayloadType networkPayloadType, int jitterNew)
{
    constructRtpSession (remoteHost, remotePort, localPort, rtcpRemotePort,
                         rtcpLocalPort, portRange, apiPayloadType,
                         networkPayloadType, jitterNew);
}

RtpSession::RtpSession (const char* remoteHost, int remotePort, int localPort,
                        int rtcpRemotePort, int rtcpLocalPort,
                        RtpPayloadType apiPayloadType,
                        RtpPayloadType networkPayloadType, int jitterNew)
{
    constructRtpSession (remoteHost, remotePort, localPort, rtcpRemotePort,
                         rtcpLocalPort, 0, apiPayloadType,
                         networkPayloadType, jitterNew);
}

void RtpSession::constructRtpSession (const char* remoteHost,
                                      int remotePort, int localPort,
                                      int rtcpRemotePort, int rtcpLocalPort,
                                      int portRange, RtpPayloadType apiPayloadType,
                                      RtpPayloadType networkPayloadType,
                                      int jitterNew)
{

    cpLog(LOG_DEBUG, "Creating RTP session.");
    cpLog(LOG_DEBUG, "Listening on port: %d", localPort);
    cpLog(LOG_DEBUG, "Sending to remote host: %s", remoteHost);
    cpLog(LOG_DEBUG, "Sending to remote port: %d", remotePort);

    recv = NULL; tran = NULL;
    rtcpTran = NULL, rtcpRecv = NULL;

    if (localPort != 0)
    {
        if (portRange != 0)
            recv = new RtpReceiver (localPort, localPort + portRange,
                                    apiPayloadType, networkPayloadType,
                                    jitterNew);
        else
            recv = new RtpReceiver (localPort, apiPayloadType,
                                    networkPayloadType, jitterNew);
    }

    if (remotePort != 0)
    {
        if (portRange != 0)
            tran = new RtpTransmitter (remoteHost, remotePort,
                                       remotePort + portRange, apiPayloadType,
                                       networkPayloadType, recv);
        else
            tran = new RtpTransmitter (remoteHost, remotePort, apiPayloadType,
                                       networkPayloadType, recv);
    }

    if (rtcpLocalPort != 0)
    {
        if (portRange != 0)
            rtcpRecv = new RtcpReceiver (rtcpLocalPort,
                                         rtcpLocalPort + portRange);
        else
            rtcpRecv = new RtcpReceiver (rtcpLocalPort);
    }

    if (rtcpRemotePort != 0)
    {
        if (portRange != 0)
            rtcpTran = new RtcpTransmitter (remoteHost, rtcpRemotePort,
                                            rtcpRemotePort + portRange, rtcpRecv);
        else
            rtcpTran = new RtcpTransmitter (remoteHost,
                                            rtcpRemotePort, rtcpRecv);
    }


    // update interlinks
    if (rtcpTran && tran) rtcpTran->setRTPtran (tran);
    if (rtcpTran && recv) rtcpTran->setRTPrecv (recv);
    if (rtcpTran && rtcpRecv) rtcpTran->setRTCPrecv (rtcpRecv);
    if (rtcpRecv && recv) recv->setRTCPrecv(rtcpRecv);


    // SDES infromation for transmitter
    if (rtcpTran && tran)
    {
        char dummy[2] = "";

        rtcpTran->setSdesCname();
        rtcpTran->setSdesName(dummy);
        rtcpTran->setSdesEmail(dummy);
        rtcpTran->setSdesPhone(dummy);
        rtcpTran->setSdesLoc(dummy);
        rtcpTran->setSdesTool(dummy);
        rtcpTran->setSdesNote(dummy);
    }


    // session states
    // Currently the states are for RTP stack only, not for RTCP
    if (tran && recv)
    {
        sessionState = rtp_session_sendrecv;
        recv->getUdpStack()->setMode(sendrecv);
    }
    else if (tran && !recv)
    {
        sessionState = rtp_session_sendonly;
        tran->getUdpStack()->setMode(sendonly);
    }
    else if (recv && !tran)
    {
        sessionState = rtp_session_recvonly;
        recv->getUdpStack()->setMode(recvonly);
    }
    else
    {
        cpLog (LOG_ERR, "Session undefined");
        sessionState = rtp_session_undefined;
    }


    if (tran) cpLog (LOG_DEBUG_STACK, "RTP Tran Port: %d",
                         tran->getUdpStack()->getDestinationPort());
    if (recv) cpLog (LOG_DEBUG_STACK, "RTP Recv Port: %d", recv->getPort());
    if (rtcpTran) cpLog (LOG_DEBUG_STACK, "RTCP Tran Port: %d",
                             rtcpTran->getUdpStack()->getDestinationPort());
    if (rtcpRecv) cpLog (LOG_DEBUG_STACK, "RTCP Recv Port: %d",
                             rtcpRecv->getPort());
}

RtpSession::~RtpSession ()
{
    if( rtcpTran )
    {
        delete rtcpTran;
        rtcpTran = NULL;
    }
    if( rtcpRecv )
    {
        delete rtcpRecv;
        rtcpRecv = NULL;
    }
    if( tran )
    {
        delete tran;
        tran = NULL;
    }
    if( recv )
    {
        delete recv;
        recv = NULL;
    }
}

int
RtpSession::reserveRtpPort(int localMin, int localMax)
{
    int port = 0;

    if ( recv == 0 )
    {
        try
        {
            //let RtpReceiver() automatically generate a port number
            recv = new RtpReceiver(localMin, localMax);
            port = recv->getPort();
        }
        catch ( UdpStackExceptionPortsInUse& )
        {
            if ( localMin == localMax )
                cpLog( LOG_ERR, "port %d is not available", localMin );
            else
                cpLog( LOG_ERR, "No ports between %d and %d are available", localMin, localMax);
            recv = 0;
        }
    }
    else
    {
        port = recv->getPort();
    }

    return port;
}

int
RtpSession::releaseRtpPort()
{
    int port = 0;
    if ( recv != 0 )
    {
        port = recv->getPort();
        delete recv;
        recv = 0;
    }
    return port;
}

int
RtpSession::reserveRtcpPort(int rtcpLocalPort, int portRange)
{
    int port = 0;

    if ( rtcpRecv == 0 )
    {
        try
        {
            if (rtcpLocalPort != 0)
            {
                if (portRange != 0)
                    rtcpRecv = new RtcpReceiver (rtcpLocalPort,
                                                 rtcpLocalPort + portRange);
                else
                    rtcpRecv = new RtcpReceiver (rtcpLocalPort);
            }

            port = rtcpRecv->getPort();
        }
        catch ( UdpStackExceptionPortsInUse& )
        {
            if ( portRange == 0 )
                cpLog( LOG_ERR, "port %d is not available", rtcpLocalPort );
            else
                cpLog( LOG_ERR, "no ports between %d and %d are available", rtcpLocalPort, rtcpLocalPort + portRange );
            rtcpRecv = 0;
        }
    }
    else
    {
        port = rtcpRecv->getPort();
    }

    return port;
}

int
RtpSession::releaseRtcpPort()
{
    int port = 0;
    if ( rtcpRecv != 0 )
    {
        port = rtcpRecv->getPort();
        delete rtcpRecv;
        rtcpRecv = 0;
    }
    return port;
}

/* --- Send and Receive RTP Functions ------------------------------ */
void RtpSession::setNetworkFormat (RtpPayloadType type, int no_samples, int packetSize)
{
    if (tran) tran->setNetworkFormat (type, no_samples, packetSize);
    if (recv) recv->setNetworkFormat (type, no_samples, packetSize);
}

void RtpSession::setApiFormat (RtpPayloadType type, int no_samples, int packetSize)
{
    if (tran) tran->setApiFormat (type, no_samples, packetSize);
    if (recv) recv->setApiFormat (type, no_samples, packetSize);
}

void RtpSession::setCodecString (const char* codecStringInput)
{
    if (tran) tran->setCodecString (codecStringInput);
    if (recv) recv->setCodecString (codecStringInput);
}

void RtpSession::setNetworkPktSize (int no_samples)
{
    setNetworkPktSampleSize (no_samples);
}

void RtpSession::setNetworkPktSampleSize (int no_samples)
{
    if (tran) tran->setNetworkPktSize (no_samples);
    if (recv) recv->setNetworkPktSize (no_samples);
}


void RtpSession::setApiPktSize (int no_samples)
{
    setApiPktSampleSize (no_samples);
}

void RtpSession::setApiPktSampleSize (int no_samples)
{
    if (tran) tran->setApiPktSize (no_samples);
    if (recv) recv->setApiPktSize (no_samples);
}


int RtpSession::getNetworkPktSampleSize ()
{
    if (tran)
        return tran->getNetworkPktSampleSize ();
    else
        return 0;
}

int RtpSession::getApiPktSampleSize ()
{
    if (recv)
        return recv->getApiPktSampleSize();
    else
        return 0;
}

// If there are multiple dests, the return will be the total
// of all dests. - ?
int RtpSession::getPacketSent ()
{
    if (tran)
        return tran->getPacketSent ();
    else
        return 0;
}

// If there are multiple dests, the return will be the total
// of all dests. - ?
int RtpSession::getByteSent ()
{
    if (tran)
        return tran->getPayloadSent ();
    else
        return 0;
}

// If there are multiple srcs, the return will be the total
// of all srcs. - ?
int RtpSession::getPacketReceived ()
{
    if (recv)
        return recv->getPacketReceived ();
    else
        return 0;
}

// If there are multiple srcs, the return will be the total
// of all srcs. - ?
int RtpSession::getByteReceived ()
{
    if (recv)
        return recv->getPayloadReceived ();
    else
        return 0;
}

// If there are multiple srcs, this func returns the packect lost
// for all the srcs
int RtpSession::getPacketLost ()
{
    if (rtcpTran)
    {
        if (rtcpRecv)
        {
            int lost = 0;
            for (int i = 0; i < (rtcpRecv->getTranInfoCount()); i++)
            {
                lost += rtcpTran->calcLostCount(rtcpRecv->getTranInfoList(i));
            }
            return lost;
        }
    }
    return 0;
}

// If there are multiple srcs, this func returns the jitter
// calculation results accumulated by all srcs
int RtpSession::getJitter ()
{
    if (recv)
    {
        return (recv->getJitter() >> 4);
    }
    return 0;
}

// If there are multiple srcs, what this func returns
// is not clear - ?
int RtpSession::getLatency ()
{
    if (rtcpRecv)
    {
        return (rtcpRecv->getAvgOneWayDelay());
        //        return (rtcpRecv->getAvgRoundTripDelay());
    }

    return 0;
}

void RtpSession::setSessionState (RtpSessionState state)
{
    switch (state)
    {
        case (rtp_session_inactive):
                    if (recv) recv->getUdpStack()->setMode(inactive);
            else if (tran) tran->getUdpStack()->setMode(inactive);
        sessionState = state;
        break;
        case (rtp_session_sendonly):
                    if (recv) recv->getUdpStack()->setMode(sendonly);
            else if (tran) tran->getUdpStack()->setMode(sendonly);
        sessionState = state;
        break;
        case (rtp_session_recvonly):
                    if (recv) recv->getUdpStack()->setMode(recvonly);
            else if (tran) tran->getUdpStack()->setMode(recvonly);
        sessionState = state;
        break;
        case (rtp_session_sendrecv):
                    if (recv) recv->getUdpStack()->setMode(sendrecv);
            else if (tran) tran->getUdpStack()->setMode(sendrecv);
        sessionState = state;
        break;
        case (rtp_session_undefined):
                    sessionState = state;
        break;
        default:
        cpLog (LOG_ERR, "Unknown state: %d", (int)state);
        assert (0);
    }

    if (recv) recv->emptyNetwork();
}


RtpSessionState RtpSession::getSessionState ()
{
    return sessionState;
}

int
RtpSession::setReceiver ( int localPort, int rtcpLocalPort, int portRange,
                          RtpPayloadType apiFormat,
                          RtpPayloadType networkFormat,
                          int jitterNew /* = 5 */)
{
    if ( !(sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_recvonly) )
    {
        cpLog(LOG_ERR, "wrong state of RTP stack.");
        return -1;
    }

    if (localPort != 0)
    {
        if (portRange != 0)
        {
            if (recv)
            {
                assert (recv->getUdpStack());
                recv->getUdpStack()->setLocal(localPort, localPort + portRange);
            }
            else if (tran)
            {
                assert (tran->getUdpStack());
                tran->getUdpStack()->setLocal(localPort, localPort + portRange);
                recv = new RtpReceiver(tran->getUdpStack(), apiFormat,
                                       networkFormat, jitterNew);
            }
            else
                recv = new RtpReceiver (localPort, localPort + portRange,
                                        apiFormat, networkFormat,
                                        jitterNew);
        }
        else
            if (recv)
            {
                assert (recv->getUdpStack());
                recv->getUdpStack()->setLocal(localPort, localPort + portRange);
            }
            else if (tran)
            {
                assert (tran->getUdpStack());
                tran->getUdpStack()->setLocal(localPort, localPort + portRange);
                recv = new RtpReceiver(tran->getUdpStack(), apiFormat,
                                       networkFormat, jitterNew);
            }
            else
                recv = new RtpReceiver (localPort, apiFormat,
                                        networkFormat, jitterNew);
    }

    if (rtcpLocalPort != 0)
    {
        if (portRange != 0)
            if (rtcpRecv)
            {
                assert (rtcpRecv->getUdpStack());
                rtcpRecv->getUdpStack()->setLocal(rtcpLocalPort,
                                                  rtcpLocalPort + portRange);
            }
            else if (rtcpTran)
            {
                assert (rtcpTran->getUdpStack());
                rtcpTran->getUdpStack()->setLocal(rtcpLocalPort,
                                                  rtcpLocalPort + portRange);
                rtcpRecv = new RtcpReceiver(rtcpTran->getUdpStack());
            }
            else
                rtcpRecv = new RtcpReceiver (rtcpLocalPort,
                                             rtcpLocalPort + portRange);
        else
            if (rtcpRecv)
            {
                assert(rtcpRecv->getUdpStack());
                rtcpRecv->getUdpStack()->setLocal(rtcpLocalPort);
            }
            else if (rtcpTran)
            {
                assert(rtcpTran->getUdpStack());
                rtcpTran->getUdpStack()->setLocal(rtcpLocalPort);
                rtcpRecv = new RtcpReceiver(rtcpTran->getUdpStack());
            }
            else
                rtcpRecv = new RtcpReceiver (rtcpLocalPort);
    }

    // update interlinks
    if (rtcpTran && recv) rtcpTran->setRTPrecv (recv);
    if (rtcpTran && rtcpRecv) rtcpTran->setRTCPrecv (rtcpRecv);
    if (rtcpRecv && recv) recv->setRTCPrecv(rtcpRecv);

    if (recv) cpLog (LOG_DEBUG_STACK, "RTP Recv Port: %d", recv->getPort());
    if (rtcpRecv) cpLog (LOG_DEBUG_STACK, "RTCP Recv Port: %d",
                             rtcpRecv->getPort());

    return 0;
}


int
RtpSession::setTransmiter ( const char* remoteHost, int remotePort,
                            int rtcpRemotePort,
                            RtpPayloadType apiFormat,
                            RtpPayloadType networkFormat )
{
    if ( !(sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_sendonly) )
    {
        cpLog(LOG_ERR, "wrong state of RTP stack.");
        return -1;
    }

    if (remotePort != 0)
    {
        if (tran)
        {
            tran->getUdpStack()->setDestination(remoteHost, remotePort);
            NetworkAddress netAddress;
            if ( remoteHost )
            {
                netAddress.setPort(remotePort);
                netAddress.setHostName(remoteHost);
            }
            tran->setRemoteAddr(netAddress);
        }
        else
            tran = new RtpTransmitter ( remoteHost, remotePort, apiFormat,
                                        networkFormat, recv);
    }

    if (rtcpRemotePort != 0)
    {
        if (rtcpTran)
        {
            rtcpTran->getUdpStack()->setDestination( remoteHost,
                    rtcpRemotePort);
            NetworkAddress netAddress1;
            if ( remoteHost )
            {
                netAddress1.setPort(rtcpRemotePort);
                netAddress1.setHostName(remoteHost);
            }
            rtcpTran->setRemoteAddr(netAddress1);
        }
        else
            rtcpTran = new RtcpTransmitter ( remoteHost,
                                             rtcpRemotePort, rtcpRecv);
    }

    // update interlinks
    if (rtcpTran && tran) rtcpTran->setRTPtran (tran);
    if (rtcpTran && recv) rtcpTran->setRTPrecv (recv);
    if (rtcpTran && rtcpRecv) rtcpTran->setRTCPrecv (rtcpRecv);

    // SDES infromation for transmitter
    if (rtcpTran && tran)
    {
        char dummy[2]= "";

        rtcpTran->setSdesCname();
        rtcpTran->setSdesEmail(dummy);
        rtcpTran->setSdesPhone(dummy);
        rtcpTran->setSdesLoc(dummy);
        rtcpTran->setSdesTool(dummy);
        rtcpTran->setSdesNote(dummy);
    }

    if (tran) cpLog (LOG_DEBUG_STACK, "RTP Tran Port: %d",
                         tran->getUdpStack()->getDestinationPort());
    if (rtcpTran) cpLog (LOG_DEBUG_STACK, "RTCP Tran Port: %d",
                             rtcpTran->getUdpStack()->getDestinationPort());

    return 0;
}


/* --- Send and Receive RTP Functions ------------------------------ */

RtpPacket* RtpSession::createPacket (int npadSize, int csrcCount)
{
    assert (tran);
    if (npadSize != 0)
        cpLog(LOG_DEBUG, "Nonzero npadSize not supported");
    return tran->createPacket(npadSize, csrcCount);
}



RtpSeqNumber RtpSession::getPrevSequence ()
{
    assert (tran);
    return tran->getPrevSequence ();
}



RtpTime RtpSession::getPrevRtpTime ()
{
    assert (tran);
    return tran->getPrevRtpTime();
}



void RtpSession::setMarkerOnce()
{
    if( tran )
    {
        tran->setMarkerOnce();
    }
}


int RtpSession::transmit (RtpPacket* p)
{
    if ( !( sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_sendonly ) )
    {
        sessionError = session_wrongState;
        cpLog (LOG_ERR, "RTP stack can't transmit. Wrong state");
        return -1;
    }

    assert (tran);
    sessionError = session_success;
    return tran->transmit(p);
}


int RtpSession::transmitRaw (char* inbuffer, int len)
{
    if ( !( sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_sendonly ) )
    {
        sessionError = session_wrongState;
        cpLog (LOG_ERR, "RTP stack can't transmit. Wrong state");
        return -1;
    }

    assert (tran);
    sessionError = session_success;
    return tran->transmitRaw(inbuffer, len);
}


int RtpSession::transmitEvent( int event )
{
    if ( !( sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_sendonly ) )
    {
        sessionError = session_wrongState;
        cpLog (LOG_ERR, "RTP stack can't transmit event. Wrong state");
        return -1;
    }

    cpLog( LOG_DEBUG_STACK,"Sending DTMF event %d in RTP stream", event );
    assert (tran);
    sessionError = session_success;
    RtpPacket* eventPacket = createPacket(0, 0);
    eventPacket->setPayloadType( rtpPayloadDTMF_RFC2833 );
    eventPacket->setPayloadUsage( sizeof( RtpEventDTMFRFC2833 ) );
    RtpEventDTMFRFC2833* eventPayload = reinterpret_cast<RtpEventDTMFRFC2833*>
                                        ( eventPacket->getPayloadLoc() );

    // reset event payload
    eventPayload->event = event; 
    eventPayload->volume = 0x0A;
    eventPayload->reserved = 0;
    eventPayload->edge = 0;
    eventPayload->duration = 0x00A0;

    // send onedge packet
    tran->transmit( eventPacket, true );

    // send on packet
    eventPayload->edge = 1;
    tran->transmit( eventPacket, true );

    // send offedge packet
    eventPacket->setPayloadUsage( 0 );
    tran->transmit( eventPacket, true );

    if( eventPacket )
        delete eventPacket; eventPacket = NULL;

    return 0;
}


RtpPacket* RtpSession::receive ()
{
    if ( !( sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_recvonly ) )
    {
        if (recv) recv->receive();
        sessionError = session_wrongState;
        cpLog (LOG_ERR, "RTP stack can't receive. Wrong state");
        return NULL;
    }

    assert (recv);
    sessionError = session_success;
    return recv->receive();
}


RtpPacket* RtpSession::getPacket()
{
    if ( !( sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_recvonly ) )
    {
        if (recv) recv->getPacket();
        sessionError = session_wrongState;
        cpLog (LOG_ERR, "RTP stack can't receive. Wrong state");
        return NULL;
    }

    assert (recv);
    sessionError = session_success;
    return recv->getPacket();
}



/* --- Send and Receive RTCP Functions ----------------------------- */

void RtpSession::processRTCP ()
{
    if (rtcpTran)
    {
        if (checkIntervalRTCP()) transmitRTCP();
    }
    if (rtcpRecv)
    {
        receiveRTCP();
    }
    return ;
}


int RtpSession::transmitRTCP ()
{
    if ( !( sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_sendonly ) )
    {
        sessionError = session_wrongState;
        cpLog (LOG_ERR, "RTCP stack can't transmit. Wrong state");
        return -1;
    }

    assert (rtcpTran);

    // generate compound packet
    RtcpPacket* p = new RtcpPacket();

    // load with report packet
    rtcpTran->addSR(p);

    // load with SDES information
    // currently only sender sends SDES, recv only receiver doesn't
    if (tran) rtcpTran->addSDES(p);

    // transmit packet
    int ret = rtcpTran->transmit(p);

    if (p) delete p;
    return ret;
}



int RtpSession::transmitRTCPBYE ()
{
    assert (rtcpTran);

    // generate compound packet
    RtcpPacket* p = new RtcpPacket();

    // load with report packet
    rtcpTran->addSR(p);

    // load with SDES CNAME
    if (tran) rtcpTran->addSDES(p, rtcpSdesCname);

    // load with BYE packet
    if (tran)
    {
        char reason[] = "Program Ended.";
        rtcpTran->addBYE(p, reason);
    }

    // transmit packet
    int ret = rtcpTran->transmit(p);

    if (p) delete p;
    return ret;
}



int RtpSession::receiveRTCP ()
{
    if ( !( sessionState == rtp_session_sendrecv
            || sessionState == rtp_session_recvonly ) )
    {
        RtcpPacket* p1 = rtcpRecv->getPacket();
        if (p1) delete p1;
        sessionError = session_wrongState;
        cpLog (LOG_ERR, "RTCP stack can't receive. Wrong state");
        return -1;
    }

    assert (rtcpRecv);

    // generate compound packet
    RtcpPacket* p = rtcpRecv->getPacket();
    if (p == NULL) return -1;

    int ret = 0;

    // read compound packet
    if (rtcpRecv->readRTCP(p) == 1)
    {
       ret = 1;
    }

    if (p) delete p;
    return ret;
}



int RtpSession::checkIntervalRTCP ()
{
    assert (rtcpTran);
    return rtcpTran->checkInterval();
}




/* --- DTMF Callback functions ------------------------------------- */
void RtpSession::setDTMFInterface( DTMFInterface* t )
{
    if ( !recv )
        cpLog(LOG_ERR, "RTP receiver not set, can't set DTMF Interface");
    else
        recv->setDTMFInterface( t );
}

void RtpSession::unsetDTMFInterface( DTMFInterface* t )
{
    if ( !recv )
        cpLog(LOG_ERR, "RTP receiver not set, can't unset DTMF Interface");
    else
        recv->unsetDTMFInterface( t );
}


syntax highlighted by Code2HTML, v. 0.9.1