/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
#ifndef PVMF_JB_JITTERBUFFERMISC_H_INCLUDED
#include "pvmf_jb_jitterbuffermisc.h"
#endif

#ifndef PVMF_SM_NODE_EVENTS_H_INCLUDED
#include "pvmf_sm_node_events.h"
#endif

#ifndef PVMF_BASIC_ERRORINFOMESSAGE_H_INCLUDED
#include "pvmf_basic_errorinfomessage.h"
#endif

#ifndef MEDIAINFO_H
#include "media_info.h"
#endif

#ifndef PAYLOAD_PARSER_REGISTRY_H_INCLUDED
#include "payload_parser_registry.h"
#endif

#ifndef PAYLOADPARSER_FACTORY_BASE_H_INCLUDED
#include "payload_parser_factory.h"
#endif

OSCL_EXPORT_REF PVMFJitterBufferMisc* PVMFJitterBufferMisc::New(PVMFJitterBufferMiscObserver* aObserver, PVMFMediaClock& aClientPlaybackClock, Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>& aPortParamsQueue)
{
    int32 err = OsclErrNone;
    PVMFJitterBufferMisc* ptr = NULL;
    OSCL_TRY(err, ptr = OSCL_NEW(PVMFJitterBufferMisc, (aObserver, aClientPlaybackClock, aPortParamsQueue));
             ptr->Construct());
    if (err != OsclErrNone)
    {
        ptr = NULL;
    }
    return ptr;
}

void PVMFJitterBufferMisc::Construct()
{
    ipJBEventsClockLogger = PVLogger::GetLoggerObject("jitterbuffernode.eventsclock");
    ipRTCPDataPathLoggerIn = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffer.rtcp.in");
    ipClockLoggerSessionDuration = PVLogger::GetLoggerObject("clock.streaming_manager.sessionduration");
    ipClockLogger = PVLogger::GetLoggerObject("clock.jitterbuffernode");
    ipDataPathLoggerIn = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffer.in");
    ipDataPathLoggerOut = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffer.out");
    ipDataPathLoggerRTCP = PVLogger::GetLoggerObject("datapath.sourcenode.jitterbuffer.rtcp");
    ipLogger = PVLogger::GetLoggerObject("PVMFJitterBufferMisc");
    ipClockLoggerRebuff = PVLogger::GetLoggerObject("sourcenode.clock.rebuff");

    CreateProtocolObjects();

    ResetParams(false);

    //Look for the input ports in the port vect
    //Look for the corresponding input port and the jitter buffer associated with it
    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter_begin = irPortParamsQueue.begin();
    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter_end = irPortParamsQueue.end();
    while (iter_begin != iter_end)
    {
        PVMFJitterBufferPortParams* portParams = *iter_begin;
        if (PVMF_JITTER_BUFFER_PORT_TYPE_INPUT == portParams->iTag)//input port
        {
            PVMFPortInterface* feedbackPort = NULL;
            PVMFJitterBuffer* jitterBuffer = NULL;
            PVRTCPChannelController* rtcpChannelController = NULL;
            if (LookupRTCPChannelParams(&portParams->irPort, feedbackPort, jitterBuffer))
            {
                rtcpChannelController = PVRTCPChannelController::New(ipRTCPProtoImplementator, *jitterBuffer, feedbackPort, irClientPlaybackClock, *ipWallClock);
                ipRTCPProtoImplementator->AddPVRTCPChannelController(rtcpChannelController);
            }
        }
        iter_begin++;
    }
}

bool PVMFJitterBufferMisc::CreateProtocolObjects()
{
    uint32 start = 0;
    bool overflowFlag = false;

    ipEstimatedServerClock = OSCL_NEW(PVMFMediaClock, ());
    ipEstimatedServerClock->SetClockTimebase(iEstimatedServerClockTimeBase);
    if (ipEstimatedServerClock)
    {
        ipEstimatedServerClock->Stop();
        ipEstimatedServerClock->SetStartTime32(start, PVMF_MEDIA_CLOCK_MSEC, overflowFlag);
    }

    ipWallClock = OSCL_NEW(PVMFMediaClock, ());
    ipWallClock->SetClockTimebase(iWallClockTimeBase);
    if (ipWallClock)
    {
        ipWallClock->SetStartTime32(start, PVMF_MEDIA_CLOCK_MSEC, overflowFlag);
    }

    ipNonDecreasingClock = OSCL_NEW(PVMFMediaClock, ());
    ipNonDecreasingClock->SetClockTimebase(iNonDecreasingTimeBase);
    if (ipNonDecreasingClock)
    {
        ipNonDecreasingClock->SetStartTime32(start, PVMF_MEDIA_CLOCK_MSEC, overflowFlag);
    }

    ipEventNotifier = PVMFJBEventNotifier::New(*ipNonDecreasingClock, irClientPlaybackClock, *ipEstimatedServerClock);

    return true;
}

void PVMFJitterBufferMisc::ResetParams(bool aReleaseMemory)
{
    if (ipFireWallPacketExchangerImpl && aReleaseMemory)
    {
        OSCL_DELETE(ipFireWallPacketExchangerImpl);
    }

    ipFireWallPacketExchangerImpl = NULL;

    iSessionDuration = 0;
    iStreamingSessionExpired = false;
    iPlayDurationAvailable = false;
    iBroadcastSession = false;

    iPlayStartTimeInMS = 0;
    iPlayStopTimeInMS = 0;
    iPlayStopTimeAvailable = false;


    iFireWallPacketsExchangeEnabled = true;
    iEstimatedServerClockUpdateCallbackId = 0;
    iEstimatedServerClockUpdateCallbackPending = false;


}

OSCL_EXPORT_REF PVMFJitterBufferMisc::~PVMFJitterBufferMisc()
{
    ResetParams(true);
    if (ipRTCPProtoImplementator)
    {
        ipRTCPProtoImplementator->RemoveAllRTCPChannelControllers();
        OSCL_DELETE(ipRTCPProtoImplementator);
    }

    if (ipEventNotifier)
    {
        OSCL_DELETE(ipEventNotifier);
    }

    if (ipSessionDurationTimer)
    {
        OSCL_DELETE(ipSessionDurationTimer);
    }

    if (ipEstimatedServerClock)
    {
        OSCL_DELETE(ipEstimatedServerClock);
    }

    if (ipWallClock)
    {
        OSCL_DELETE(ipWallClock);
    }

    if (ipNonDecreasingClock)
    {
        OSCL_DELETE(ipNonDecreasingClock);
    }
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::StreamingSessionStarted()
{
    //if not already started...
    if (ipNonDecreasingClock)
    {
        ipNonDecreasingClock->Start();
    }

    if (ipWallClock)
    {
        //Starts if not already running, check for state
        ipWallClock->Start();
    }

    //Estimated server is to be updated only by the jitter buffer.
    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
    for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; iter++)
    {
        PVMFJitterBufferPortParams* pPortParam = *iter;
        if (pPortParam)
        {
            PVMFJitterBuffer* jitterBuffer = pPortParam->ipJitterBuffer;
            if (jitterBuffer)
            {
                jitterBuffer->StreamingSessionStarted();
            }
        }
    }
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::StreamingSessionStopped()
{
    Reset();
    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
    for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; iter++)
    {
        PVMFJitterBufferPortParams* pPortParam = *iter;
        if (pPortParam)
        {
            PVMFJitterBuffer* jitterBuffer = pPortParam->ipJitterBuffer;
            if (jitterBuffer)
            {
                jitterBuffer->StreamingSessionStopped();
            }
        }
    }
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::StreamingSessionPaused()
{
    ipNonDecreasingClock->Pause();
    ipEstimatedServerClock->Pause();
    if (ipSessionDurationTimer)
        ipSessionDurationTimer->Cancel();

    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
    for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; iter++)
    {
        PVMFJitterBufferPortParams* pPortParam = *iter;
        if (pPortParam)
        {
            PVMFJitterBuffer* jitterBuffer = pPortParam->ipJitterBuffer;
            if (jitterBuffer)
            {
                jitterBuffer->StreamingSessionPaused();
            }
        }
    }
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::StreamingSessionBufferingStart()
{
    if (ipSessionDurationTimer)
        ipSessionDurationTimer->Cancel();
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::StreamingSessionBufferingEnd()
{
    if (ipSessionDurationTimer)
    {
        ComputeCurrentSessionDurationMonitoringInterval();
        ipSessionDurationTimer->Start();
    }
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::SetBroadcastSession()
{
    iBroadcastSession = true;
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::ResetEstimatedServerClock()
{
    if (ipEstimatedServerClock)
    {
        uint32 start = 0;
        ipEstimatedServerClock->Stop();
        bool overflowFlag = false;
        ipEstimatedServerClock->SetStartTime32(start, PVMF_MEDIA_CLOCK_MSEC, overflowFlag);
    }
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::PrepareForRepositioning(bool oUseExpectedClientClockVal, uint32 aExpectedClientClockVal)
{
    bool overflowFlag = false;

    //A session will have three things
    //Media channel     :   Valid for any type of streaming
    //Feedback Channel  :   Valid for RTSP based streaming
    //Session Info  :   Valid for any type of streaming

    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
    for (it = irPortParamsQueue.begin();
            it != irPortParamsQueue.end();
            it++)
    {
        PVMFJitterBufferPortParams* pPortParam = *it;
        if (pPortParam->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
        {
            pPortParam->ipJitterBuffer->PrepareForRepositioning();
        }
    }

    PVMFTimestamp ts = 0;
    if (oUseExpectedClientClockVal)
    {
        ts = aExpectedClientClockVal;
    }
    else
    {
        //reset player clock
        ts = GetActualMediaDataTSAfterSeek();
    }

    irClientPlaybackClock.Stop();
    irClientPlaybackClock.SetStartTime32(ts,
                                         PVMF_MEDIA_CLOCK_MSEC, overflowFlag);

    LOGCLIENTANDESTIMATEDSERVCLK_DATAPATH;
    LOGCLIENTANDESTIMATEDSERVCLK_DATAPATH_OUT;
    LOGCLIENTANDESTIMATEDSERVCLK_REBUFF;

    if (ipRTCPProtoImplementator)
        ipRTCPProtoImplementator->Prepare(true);
    iStreamingSessionExpired = false;

    return true;
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::PurgeElementsWithNPTLessThan(NptTimeFormat &aNPTTime)
{
    if (aNPTTime.npt_format != NptTimeFormat::NPT_SEC)
    {
        return false;
    }

    uint32 i;
    for (i = 0; i < irPortParamsQueue.size(); i++)
    {
        PVMFJitterBufferPortParams* portParams = irPortParamsQueue[i];
        portParams->irPort.ClearMsgQueues();
    }

    for (i = 0; i < irPortParamsQueue.size(); i++)
    {
        PVMFJitterBufferPortParams* portParams = irPortParamsQueue[i];
        if (portParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
        {
            if (portParams->ipJitterBuffer != NULL)
            {
                //portParams.iJitterBuffer->FlushJitterBuffer();
                PVMFTimestamp baseTS = 1000 * aNPTTime.npt_sec.sec + aNPTTime.npt_sec.milli_sec;

                portParams->iMediaClockConverter.set_clock_other_timescale(baseTS, 1000);
                baseTS = portParams->iMediaClockConverter.get_current_timestamp();
                portParams->ipJitterBuffer->PurgeElementsWithTimestampLessThan(baseTS);
            }
        }
    }

    // Update client clock here to avoid premature buffer fullness
    PVMFTimestamp ts = 1000 * aNPTTime.npt_sec.sec + aNPTTime.npt_sec.milli_sec;
    bool overflowFlag = false;
    irClientPlaybackClock.Stop();
    irClientPlaybackClock.SetStartTime32(ts, PVMF_MEDIA_CLOCK_MSEC, overflowFlag);
    return true;
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::IsSessionExpired()
{
    return iStreamingSessionExpired;
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::Prepare()
{
    if (ipNonDecreasingClock)
    {
        ipNonDecreasingClock->Start();
    }

    if (ipWallClock)
    {
        //Starts if not already running, check for state
        ipWallClock->Start();
    }

    if (UseSessionDurationTimerForEOS())
    {
        ipSessionDurationTimer = OSCL_NEW(PvmfJBSessionDurationTimer, (this));
        if (ipSessionDurationTimer && ipEstimatedServerClock)
        {
            ipSessionDurationTimer->SetEstimatedServerClock(ipEstimatedServerClock);
        }
    }
    if (RTCPProtocolImplementorRequired())
    {
        ipRTCPProtoImplementator = PVRTCPProtoImplementor::New(irClientPlaybackClock, *ipWallClock, this);
        ipRTCPProtoImplementator->EnableRTCPbasedAVSync(true);
        //Set the rate adaptaton parmas if not already set
        PVMFPortInterface* feedbackPort = NULL;
        PVMFJitterBuffer* jitterBuffer = NULL;
        Oscl_Vector<RateAdapatationInfo, OsclMemAllocator>::iterator iter;
        for (iter = iRateAdaptationInfos.begin(); iter < iRateAdaptationInfos.end(); iter++)
        {
            RateAdapatationInfo rateAdaptationInfo = *iter;
            feedbackPort = NULL;
            jitterBuffer = NULL;
            if (LookupRTCPChannelParams(rateAdaptationInfo.iPort, feedbackPort, jitterBuffer))
            {
                PVRTCPChannelController* rtcpChannelController = ipRTCPProtoImplementator->GetRTCPChannelController(feedbackPort);
                if (rtcpChannelController)
                {
                    rtcpChannelController->SetRateAdaptation(rateAdaptationInfo.iRateAdapatationInfo.iRateAdaptation, rateAdaptationInfo.iRateAdapatationInfo.iRateAdaptationFeedBackFrequency, rateAdaptationInfo.iRateAdapatationInfo.iRateAdaptationFreeBufferSpaceInBytes);

                }
                else
                {
                    PVMFJitterBufferPort* rtpDataPort = OSCL_STATIC_CAST(PVMFJitterBufferPort*, rateAdaptationInfo.iPort);
                    jitterBuffer = rtpDataPort->GetPortParams()->ipJitterBuffer;
                    PVMFJitterBufferPortParams* rtpPortParams = rtpDataPort->GetPortParams();
                    PVMFJitterBufferPortParams* feedbackPortParams = NULL;
                    LocateFeedBackPort(rtpPortParams, feedbackPortParams);
                    if (feedbackPortParams)
                    {
                        feedbackPort = &feedbackPortParams->irPort;
                    }
                    rtcpChannelController = PVRTCPChannelController::New(ipRTCPProtoImplementator, *jitterBuffer, feedbackPort, irClientPlaybackClock, *ipWallClock);
                    rtcpChannelController->SetRateAdaptation(rateAdaptationInfo.iRateAdapatationInfo.iRateAdaptation, rateAdaptationInfo.iRateAdapatationInfo.iRateAdaptationFeedBackFrequency, rateAdaptationInfo.iRateAdapatationInfo.iRateAdaptationFreeBufferSpaceInBytes);
                    ipRTCPProtoImplementator->AddPVRTCPChannelController(rtcpChannelController);
                }
            }
        }

        Oscl_Vector<RTCPParams, OsclMemAllocator>::iterator rtcpParamIter;
        for (rtcpParamIter = iRTCPParamsVect.begin(); rtcpParamIter < iRTCPParamsVect.end(); rtcpParamIter++)
        {
            RTCPParams rtcpParams = *rtcpParamIter;
            ipRTCPProtoImplementator->SetPortRTCPParams(rtcpParams.iFeedbackPort, rtcpParams.iNumSenders, rtcpParams.iRR, rtcpParams.iRS);
        }

        {
            //Provide media clcok converter
            Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
            for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; iter++)
            {
                PVMFJitterBufferPortParams* pPortParams = *iter;
                if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
                {

                    SetMediaClockConverter(&pPortParams->irPort, &pPortParams->iMediaClockConverter);
                }
            }
        }
    }

    iRateAdaptationInfos.clear();
    iRTCPParamsVect.clear();
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::Reset()
{
    if (ipEventNotifier)
    {
        ipEventNotifier->CancelAllPendingCallbacks();
    }
    if (ipSessionDurationTimer)
    {
        ipSessionDurationTimer->Stop();
    }
    if (ipRTCPProtoImplementator)
    {
        ipRTCPProtoImplementator->Reset();
    }
    if (ipFireWallPacketExchangerImpl)
    {
        ipFireWallPacketExchangerImpl->CancelFirewallPacketExchange();
    }
    if (ipEstimatedServerClock)
    {
        ipEstimatedServerClock->Stop();
    }
    if (ipWallClock)
    {
        ipWallClock->Stop();
    }
    if (ipNonDecreasingClock)
    {
        ipNonDecreasingClock->Stop();
    }

    iSessionDuration = 0;
    iStreamingSessionExpired = true;
    iPlayDurationAvailable = false;
    iBroadcastSession = false;
    iFireWallPacketsExchangeEnabled = true;
}

OSCL_EXPORT_REF PVMFStatus PVMFJitterBufferMisc::PrepareMediaReceivingChannel()
{
    if (ipFireWallPacketExchangerImpl && iFireWallPacketsExchangeEnabled)
    {
        ipFireWallPacketExchangerImpl->InitiateFirewallPacketExchange();
        return PVMFPending;
    }
    else
    {
        if (!iFireWallPacketsExchangeEnabled)
        {
            ipObserver->MediaReceivingChannelPrepared(true);
            return PVMFSuccess;
        }
        return PVMFPending; //Wait for the SetServerInfo call
    }
}

OSCL_EXPORT_REF PVMFStatus PVMFJitterBufferMisc::CancelMediaReceivingChannelPreparation()
{
    if (ipFireWallPacketExchangerImpl)
        ipFireWallPacketExchangerImpl->CancelFirewallPacketExchange();
    return PVMFSuccess;
}

bool PVMFJitterBufferMisc::FirewallPacketExchangerRequired() const
{
    if (iFireWallPacketsExchangeEnabled)
    {
        char mimeRequiredForFirewallPacketExchange[] = "rtp";
        char mediaChannelMimeType[255] = {'0'};
        Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
        for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end(); iter++)
        {
            PVMFJitterBufferPortParams* pPortParams = *iter;
            if (pPortParams && (pPortParams->ipJitterBuffer))
            {
                oscl_memset(mediaChannelMimeType, 0, sizeof(mediaChannelMimeType));
                const char* tmpMediaChannelMimeType = pPortParams->ipJitterBuffer->GetMimeType();
                const int32 mediaChannelMimeLen =  oscl_strlen(tmpMediaChannelMimeType);
                if (tmpMediaChannelMimeType)
                {
                    for (int ii = 0; ii < mediaChannelMimeLen; ii++)
                    {
                        mediaChannelMimeType[ii] = oscl_tolower(tmpMediaChannelMimeType[ii]);
                    }
                    mediaChannelMimeType[mediaChannelMimeLen] = '\0';
                }

                if (oscl_strstr(mediaChannelMimeType, mimeRequiredForFirewallPacketExchange))
                {
                    return true;
                }
            }
        }
    }
    return false;
}

bool PVMFJitterBufferMisc::RTCPProtocolImplementorRequired() const
{
    char mimeRequiredForRTCPSupport[] = "rtp";
    char mediaChannelMimeType[255] = {'0'};
    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
    for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end(); iter++)
    {
        PVMFJitterBufferPortParams* pPortParams = *iter;
        if (pPortParams && (pPortParams->ipJitterBuffer))
        {
            oscl_memset(mediaChannelMimeType, 0, sizeof(mediaChannelMimeType));
            const char* tmpMediaChannelMimeType = pPortParams->ipJitterBuffer->GetMimeType();
            const int32 mediaChannelMimeLen =  oscl_strlen(tmpMediaChannelMimeType);
            if (tmpMediaChannelMimeType)
            {
                for (int ii = 0; ii < mediaChannelMimeLen; ii++)
                {
                    mediaChannelMimeType[ii] = oscl_tolower(tmpMediaChannelMimeType[ii]);
                }
                mediaChannelMimeType[mediaChannelMimeLen] = '\0';
            }

            if (oscl_strstr(mediaChannelMimeType, mimeRequiredForRTCPSupport))
            {
                return true;
            }
        }
    }
    return false;//based on mime type
}

OSCL_EXPORT_REF PVMFStatus PVMFJitterBufferMisc::ProcessFeedbackMessage(PVMFJitterBufferPortParams& aParam, PVMFSharedMediaMsgPtr aMsg)
{
    PVMFStatus status = PVMFSuccess;
    if (ipRTCPProtoImplementator)
    {
        status = ipRTCPProtoImplementator->ProcessRTCPReport(&aParam.irPort, aMsg);
    }
    else
    {
        status = PVMFFailure;
    }
    return status;
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::SetRateAdaptationInfo(PVMFPortInterface* aPort, bool aRateAdaptation, uint32 aRateAdaptationFeedBackFrequency, uint32 aRateAdaptationFreeBufferSpaceInBytes)
{
    //Persist it: We'll update it when RTCP controller will be prepared
    RateAdapatationInfo rateAdadpatatinInfo;
    rateAdadpatatinInfo.iPort = aPort;
    rateAdadpatatinInfo.iRateAdapatationInfo.iRateAdaptation = aRateAdaptation;
    rateAdadpatatinInfo.iRateAdapatationInfo.iRateAdaptationFeedBackFrequency = aRateAdaptationFeedBackFrequency;
    rateAdadpatatinInfo.iRateAdapatationInfo.iRateAdaptationFreeBufferSpaceInBytes = aRateAdaptationFreeBufferSpaceInBytes;
    iRateAdaptationInfos.push_back(rateAdadpatatinInfo);
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::SetRTCPIntervalInMicroSecs(uint32 aRTCPInterval)
{
    if (ipRTCPProtoImplementator)
        ipRTCPProtoImplementator->SetRTCPIntervalInMicroSecs(aRTCPInterval);
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::SetPortRTCPParams(PVMFPortInterface* aPort, int aNumSenders, uint32 aRR, uint32 aRS)
{
    bool retval = false;
    if (ipRTCPProtoImplementator)
        retval = ipRTCPProtoImplementator->SetPortRTCPParams(aPort, aNumSenders, aRR, aRS);
    //retval eq to false implies rtcp controller doesnt exist as fo now for the port "aPort"
    if (!retval)
    {
        RTCPParams rtcpParams;
        rtcpParams.iFeedbackPort = aPort;
        rtcpParams.iNumSenders = aNumSenders;
        rtcpParams.iRR = aRR;
        rtcpParams.iRS = aRS;
        iRTCPParamsVect.push_back(rtcpParams);
        retval = true;
    }
    return retval;
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::ResetSession()
{
    iStreamingSessionExpired = false;
    if (ipSessionDurationTimer)
    {
        ipSessionDurationTimer->Cancel();
        ipSessionDurationTimer->Stop();
    }
    return true;
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::SetSessionDurationExpired()
{
    iStreamingSessionExpired = true;
    if (ipSessionDurationTimer)
    {
        ipSessionDurationTimer->Cancel();
        ipSessionDurationTimer->Stop();
    }

    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
    for (it = irPortParamsQueue.begin(); it != irPortParamsQueue.end(); it++)
    {
        PVMFJitterBufferPortParams* pPortParams = *it;

        if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
        {
            pPortParams->ipJitterBuffer->SetEOS(true);
        }
    }


    uint32 timebase32 = 0;
    uint32 clientClock32 = 0;
    bool overflowFlag = false;
    irClientPlaybackClock.GetCurrentTime32(clientClock32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, timebase32);
    timebase32 = 0;
    uint32 estServClock32 = 0;
    ipEstimatedServerClock->GetCurrentTime32(estServClock32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, timebase32);

    PVMF_JB_LOGDATATRAFFIC_OUT((0, "PVMFJitterBufferMisc::SetSessionDurationExpired- Estimated Server Clock [%d] Client Clock[%d]", estServClock32, clientClock32));
    PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferMisc::SetSessionDurationExpired- Estimated Server Clock [%d] Client Clock[%d]", estServClock32, clientClock32));

    return true;
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::MediaReceivingChannelPreparationRequired(bool aRequired)
{
    iFireWallPacketsExchangeEnabled = aRequired;
}

OSCL_EXPORT_REF PVMFMediaClock& PVMFJitterBufferMisc::GetEstimatedServerClock()
{
    return *ipEstimatedServerClock;
}

OSCL_EXPORT_REF PVMFJBEventNotifier* PVMFJitterBufferMisc::GetEventNotifier()
{
    return ipEventNotifier;
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::SetPlayRange(int32 aStartTimeInMS, int32 aStopTimeInMS, bool aPlayAfterASeek, bool aStopTimeAvailable)
{
    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
    for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; iter++)
    {
        PVMFJitterBufferPortParams* pPortParam = *iter;
        if (pPortParam && (PVMF_JITTER_BUFFER_PORT_TYPE_INPUT == pPortParam->iTag))
        {
            PVMFJitterBuffer* jitterBuffer = pPortParam->ipJitterBuffer;
            if (jitterBuffer)
            {
                jitterBuffer->SetPlayRange(aStartTimeInMS, aPlayAfterASeek, aStopTimeAvailable, aStopTimeInMS);
            }
        }
    }

    //Configure the RTCP timer stuff
    if (ipRTCPProtoImplementator)
    {
        ipRTCPProtoImplementator->Prepare(aPlayAfterASeek);
        ipRTCPProtoImplementator->StartRTCPMessageExchange();
    }

    iPlayStartTimeInMS = aStartTimeInMS;
    iPlayStopTimeInMS = aStopTimeInMS;
    iPlayStopTimeAvailable = aStopTimeAvailable;

    if (iPlayStopTimeAvailable == true)
    {
        /* Start Session Duration Timer only if stop duration is set */
        if ((ipSessionDurationTimer) && (!iStreamingSessionExpired || (aPlayAfterASeek)))
        {
            ipSessionDurationTimer->Stop();
            iStreamingSessionExpired = false;
            ipSessionDurationTimer->setSessionDurationInMS(((iPlayStopTimeInMS - iPlayStartTimeInMS) + PVMF_EOS_TIMER_GAURD_BAND_IN_MS));
            ComputeCurrentSessionDurationMonitoringInterval();
            ipSessionDurationTimer->Start();
        }
    }

    if (aPlayAfterASeek)
    {
        //Will eventually update the estimated server clock
        //This call to "GetActualMediaDataTSAfterSeek" will normalize the ts's across the jitter buffers
        //associated with the streaming session
        GetActualMediaDataTSAfterSeek();
        Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
        for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; iter++)
        {
            PVMFJitterBufferPortParams* pPortParams = *iter;
            if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
            {
                if (pPortParams->ipJitterBuffer != NULL)
                {
                    pPortParams->ipJitterBuffer->AdjustRTPTimeStamp();
                }
            }
        }
    }
    return true;
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::SetPortSSRC(PVMFPortInterface* aPort, uint32 aSSRC, bool a3GPPFCSSwitch)
{
    bool isUpdateRequest = false;

    for (uint32 ii = 0; ii < iRTPExchangeInfosForFirewallExchange.size(); ii++)
    {
        if (aPort == iRTPExchangeInfosForFirewallExchange[ii].ipRTPDataJitterBufferPort)
        {
            isUpdateRequest = true;
            iRTPExchangeInfosForFirewallExchange[ii].iSSRC = aSSRC;
            ipFireWallPacketExchangerImpl->SetRTPSessionInfoForFirewallExchange(iRTPExchangeInfosForFirewallExchange[ii]);
            break;
        }
    }

    if (!isUpdateRequest || a3GPPFCSSwitch)
    {
        //Update with the JB
        Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::const_iterator iter;
        for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; ++iter)
        {
            if (iter && (*iter) && (&((*iter)->irPort) == aPort))
            {
                if ((*iter)->ipJitterBuffer)
                {
                    (*iter)->ipJitterBuffer->setSSRC(aSSRC);
                }
                break;
            }
        }
        //update port's ssrc with the Firewall controller
        RTPSessionInfoForFirewallExchange rtpSessioninfo(aPort, aSSRC);
        iRTPExchangeInfosForFirewallExchange.push_back(rtpSessioninfo);
    }
}

OSCL_EXPORT_REF uint32 PVMFJitterBufferMisc::GetEstimatedServerClockValue()
{
    uint32 serverClock32 = 0;
    bool overflowFlag = false;
    ipEstimatedServerClock->GetCurrentTime32(serverClock32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
    return serverClock32;
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::PlayStopTimeAvailable() const
{
    return iPlayStopTimeAvailable;
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::SetServerInfo(PVMFJitterBufferFireWallPacketInfo& aServerInfo)
{
    if (iFireWallPacketsExchangeEnabled)
    {
        if (!ipFireWallPacketExchangerImpl)
        {
            if (iRTPExchangeInfosForFirewallExchange.size() == 0)//We haven't got the exchange info for the firewall pkts yet, lets assume ssrc to be zero for all the feedback ports
            {
                Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
                for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end(); ++iter)
                {
                    PVMFJitterBufferPortParams* portParams = *iter;
                    if (portParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
                    {
                        RTPSessionInfoForFirewallExchange rtpSessioninfo(&portParams->irPort, 0);
                        iRTPExchangeInfosForFirewallExchange.push_back(rtpSessioninfo);
                    }
                }
            }

            //create it and start firewall packet exchange
            ipFireWallPacketExchangerImpl = PVFirewallPacketExchangeImpl::New(aServerInfo, *ipEventNotifier, ipObserver);
            Oscl_Vector<RTPSessionInfoForFirewallExchange, OsclMemAllocator>::iterator iter;

            for (iter = iRTPExchangeInfosForFirewallExchange.begin(); iter != iRTPExchangeInfosForFirewallExchange.end(); iter++)
            {
                ipFireWallPacketExchangerImpl->SetRTPSessionInfoForFirewallExchange(*iter);
            }

            ipFireWallPacketExchangerImpl->InitiateFirewallPacketExchange();
        }
        else
        {
            OSCL_ASSERT(false);
        }
    }
}

OSCL_EXPORT_REF PVMFTimestamp PVMFJitterBufferMisc::GetMaxMediaDataTS()
{
    PVMFTimestamp mediaTS = 0;
    uint32 in_wrap_count = 0;
    uint32 i;

    uint32 numOfJitterBuffers = 0;
    for (i = 0; i < irPortParamsQueue.size(); i++)
    {
        PVMFJitterBufferPortParams* pPortParams = irPortParamsQueue[i];

        if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
        {
            if (pPortParams->ipJitterBuffer != NULL)
            {
                PVMFTimestamp ts =
                    pPortParams->ipJitterBuffer->peekNextElementTimeStamp();
                ++numOfJitterBuffers;
                /*
                 * Convert Time stamp to milliseconds
                 */
                pPortParams->iMediaClockConverter.set_clock(ts, in_wrap_count);
                PVMFTimestamp converted_ts =
                    pPortParams->iMediaClockConverter.get_converted_ts(1000);
                if (converted_ts > mediaTS)
                {
                    mediaTS = converted_ts;
                }
            }
        }
    }

    if (numOfJitterBuffers > 1) //Need to normalize ts across jb's with the session (E.g. RTSP based streaming).
    {
        for (i = 0; i < irPortParamsQueue.size(); i++)
        {
            PVMFJitterBufferPortParams* pPortParams = irPortParamsQueue[i];

            if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
            {
                if (pPortParams->ipJitterBuffer != NULL)
                {
                    pPortParams->ipJitterBuffer->SetAdjustedTSInMS(mediaTS);
                }
            }
        }
    }

    return mediaTS;
}

/* computes the max next ts of all tracks */
OSCL_EXPORT_REF PVMFTimestamp PVMFJitterBufferMisc::GetActualMediaDataTSAfterSeek()
{
    PVMFTimestamp mediaTS = 0;
    uint32 in_wrap_count = 0;
    uint32 i;

    uint32 numOfJitterBuffers = 0;
    for (i = 0; i < irPortParamsQueue.size(); i++)
    {
        PVMFJitterBufferPortParams* pPortParams = irPortParamsQueue[i];

        if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
        {
            if (pPortParams->ipJitterBuffer != NULL)
            {
                PVMFTimestamp ts =
                    pPortParams->ipJitterBuffer->peekNextElementTimeStamp();
                ++numOfJitterBuffers;
                /*
                 * Convert Time stamp to milliseconds
                 */
                pPortParams->iMediaClockConverter.set_clock(ts, in_wrap_count);
                PVMFTimestamp converted_ts =
                    pPortParams->iMediaClockConverter.get_converted_ts(1000);
                if (converted_ts > mediaTS)
                {
                    mediaTS = converted_ts;
                }
            }
        }
    }

    if (numOfJitterBuffers > 1) //Need to normalize ts across jb's with the session (E.g. RTSP based streaming).
    {
        for (i = 0; i < irPortParamsQueue.size(); i++)
        {
            PVMFJitterBufferPortParams* pPortParams = irPortParamsQueue[i];

            if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
            {
                if (pPortParams->ipJitterBuffer != NULL)
                {
                    pPortParams->ipJitterBuffer->SetAdjustedTSInMS(mediaTS);
                }
            }
        }
    }

    return mediaTS;
}

OSCL_EXPORT_REF bool PVMFJitterBufferMisc::setPortMediaParams(PVMFPortInterface* aPort,
        mediaInfo* aMediaInfo)
{
    bool retval = false;

    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
    for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; ++iter)
    {
        if (iter && ((*iter)->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT) && (aPort == &((*iter)->irPort)))
        {
            if ((*iter)->ipJitterBuffer != NULL)
            {
                retval = (*iter)->ipJitterBuffer->setPortMediaParams(aMediaInfo);
                break;
            }
        }
    }

    return retval;
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::SetMediaClockConverter(PVMFPortInterface* apPort, MediaClockConverter* apMediaClockConverter)
{
    PVMFPortInterface* feedbackPort = NULL;
    PVMFJitterBuffer* jitterBuffer = NULL;
    if (LookupRTCPChannelParams(apPort, feedbackPort, jitterBuffer))
    {
        PVRTCPChannelController* rtcpChannelController = ipRTCPProtoImplementator->GetRTCPChannelController(feedbackPort);
        if (rtcpChannelController)
        {
            rtcpChannelController->SetMediaClockConverter(apMediaClockConverter);
        }
    }
}

OSCL_EXPORT_REF void PVMFJitterBufferMisc::ProcessFirstPacketAfterSeek()
{
    //This call to "GetActualMediaDataTSAfterSeek" will normalize the ts's across the jitter buffers
    //associated with the streaming session
    GetActualMediaDataTSAfterSeek();
    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
    for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end() ; iter++)
    {
        PVMFJitterBufferPortParams* pPortParams = *iter;
        if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
        {
            if (pPortParams->ipJitterBuffer != NULL)
            {
                pPortParams->ipJitterBuffer->AdjustRTPTimeStamp();
            }
        }
    }
}

PVMFStatus PVMFJitterBufferMisc::RTCPPacketReceived(RTCPPacketType aPacketType, PVRTCPChannelController* aController)
{
    PVMF_JB_LOG_RTCPDATATRAFFIC_IN_E((0, "PVMFJitterBufferMisc::RTCPPacketReceived -- iPlayStopTimeAvailable[%d]", iPlayStopTimeAvailable));
    if (BYE_RTCP_PACKET == aPacketType && aController)
    {
        //for live streams, treat RTCP BYE as EOS
        if (iPlayStopTimeAvailable == false)
        {
            PVMF_JB_LOGDATATRAFFIC_IN((0, "USING RTCP_BYE TO TRIGGER EOS: Mime=%s", aController->GetJitterBuffer().GetMimeType()));
            PVMF_JB_LOGDATATRAFFIC_OUT((0, "USING RTCP_BYE TO TRIGGER EOS: Mime=%s", aController->GetJitterBuffer().GetMimeType()));
            PVMF_JB_LOG_RTCPDATATRAFFIC_IN((0, "USING RTCP_BYE TO TRIGGER EOS: Mime=%s", aController->GetJitterBuffer().GetMimeType()));
            SetSessionDurationExpired();
            ipEstimatedServerClock->Pause();
            ipWallClock->Pause();
        }

        if (ipRTCPProtoImplementator->RTCPByeReceivedOnAllControllers())
        {
            SetSessionDurationExpired();
            ipEstimatedServerClock->Pause();
            ipWallClock->Pause();
        }

        PVUuid eventuuid = PVMFJitterBufferNodeEventTypeUUID;
        int32 infocode = PVMFJitterBufferNodeRTCPBYERecvd;

        PVMFBasicErrorInfoMessage* eventmsg;
        eventmsg = OSCL_NEW(PVMFBasicErrorInfoMessage, (infocode, eventuuid, NULL));
        PVMFErrorInfoMessageInterface* interimPtr =
            OSCL_STATIC_CAST(PVMFErrorInfoMessageInterface*, eventmsg);
        PVMFAsyncEvent asyncevent(PVMFInfoEvent,
                                  PVMFInfoRemoteSourceNotification,
                                  NULL,
                                  OSCL_STATIC_CAST(PVInterface*, interimPtr),
                                  (OsclAny*)(aController->GetJitterBuffer().GetMimeType()),
                                  NULL,
                                  0);
        ipObserver->ProcessRTCPControllerEvent(asyncevent);
        eventmsg->removeRef();
    }
    return PVMFSuccess;
}

PVMFStatus PVMFJitterBufferMisc::RTCPReportReadyToSend(PVMFPortInterface*& aPort, PVMFSharedMediaMsgPtr& aMessage)
{
    ipObserver->MessageReadyToSend(aPort, aMessage);
    return PVMFSuccess;
}

PVMFStatus PVMFJitterBufferMisc::ProcessInfoEvent(PVMFAsyncEvent& aEvent)
{
    ipObserver->ProcessRTCPControllerEvent(aEvent);
    return PVMFSuccess;
}

void PVMFJitterBufferMisc::PVMFJBSessionDurationTimerEvent()
{
    PVMF_JB_LOGCLOCK((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - Session Duration Timer Expired"));
    PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - Session Duration Timer Expired"));
    /* Check if the estimated server clock is past the expected value */
    uint32 expectedEstServClockVal =
        ipSessionDurationTimer->GetExpectedEstimatedServClockValAtSessionEnd();
    uint32 timebase32 = 0;
    uint32 estServClock = 0;
    bool overflowFlag = false;


    ipEstimatedServerClock->GetCurrentTime32(estServClock, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, timebase32);
    PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - CurrEstServClock = %2d", estServClock));
    PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - ExpectedEstServClock = %2d", expectedEstServClockVal));
    if (estServClock >= expectedEstServClockVal)
    {
        PVMF_JB_LOG_EVENTS_CLOCK((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent estServClock[%d] expectedEstServClockVal[%d]", estServClock, expectedEstServClockVal));
        PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - Session Duration Has Elapsed"));
        iStreamingSessionExpired = true;
        ipObserver->SessionSessionExpired();
        /* Cancel clock update notifications */
        Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;
        for (it = irPortParamsQueue.begin(); it != irPortParamsQueue.end(); it++)
        {
            PVMFJitterBufferPortParams* pPortParams = *it;

            if (pPortParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_INPUT)
            {
                pPortParams->ipJitterBuffer->SetEOS(true);
            }
        }
        /* Pause Estimated server clock & RTCP Clock */
        ipEstimatedServerClock->Pause();
        ipWallClock->Pause();
    }
    else
    {
        /*
         * Since we monitor the session duration in intervals, it is possible that this call back
         * happens when one such interval expires
         */
        uint64 elapsedTime = ipSessionDurationTimer->GetMonitoringIntervalElapsed();
        uint32 elapsedTime32 = Oscl_Int64_Utils::get_uint64_lower32(elapsedTime);
        ipSessionDurationTimer->UpdateElapsedSessionDuration(elapsedTime32);
        uint32 totalSessionDuration = ipSessionDurationTimer->getSessionDurationInMS();
        uint32 elapsedSessionDurationInMS = ipSessionDurationTimer->GetElapsedSessionDurationInMS();
        if (elapsedSessionDurationInMS < totalSessionDuration)
        {
            uint32 interval = (totalSessionDuration - elapsedSessionDurationInMS);
            if (interval > PVMF_JITTER_BUFFER_NODE_SESSION_DURATION_MONITORING_INTERVAL_MAX_IN_MS)
            {
                interval = PVMF_JITTER_BUFFER_NODE_SESSION_DURATION_MONITORING_INTERVAL_MAX_IN_MS;
            }
            ipSessionDurationTimer->setCurrentMonitoringIntervalInMS(interval);
            ipSessionDurationTimer->ResetEstimatedServClockValAtLastCancel();
            PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - TotalDuration=%d, ElapsedDuration=%d, CurrMonitoringInterval=%d", totalSessionDuration, elapsedSessionDurationInMS, interval));
        }
        else
        {
            /*
             * 1) Register for est serv clock update notifications on all jitter buffers
             * 2) Reschedule the session duration timer
             */
            PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - Past Session End Time - Starting to monitor Estimated Server Clock expectedEstServClockVal%d estServClock %d", expectedEstServClockVal, estServClock));

            uint64 diff = (expectedEstServClockVal - estServClock);
            uint32 diff32 = Oscl_Int64_Utils::get_uint64_lower32(diff);

            PVMFJBEventNotificationRequestInfo requestInfo(CLOCK_NOTIFICATION_INTF_TYPE_ESTIMATEDSERVER, this, NULL);

            if (iEstimatedServerClockUpdateCallbackPending)
            {
                ipEventNotifier->CancelCallBack(requestInfo, iEstimatedServerClockUpdateCallbackId);
                iEstimatedServerClockUpdateCallbackPending = false;
            }

            ipEventNotifier->RequestAbsoluteTimeCallBack(requestInfo, expectedEstServClockVal, iEstimatedServerClockUpdateCallbackId);
            iEstimatedServerClockUpdateCallbackPending = true;

            /*
             * This is intentional. We do not expect the session duration and monitoring
             * intervals to exceed the max timer limit of 32 mins
             */
            ipSessionDurationTimer->setSessionDurationInMS(diff32);
            ipSessionDurationTimer->setCurrentMonitoringIntervalInMS(diff32);
            ipSessionDurationTimer->ResetEstimatedServClockValAtLastCancel();
            PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - ExpectedEstServClock=%d EstServClock=%d", Oscl_Int64_Utils::get_uint64_lower32(expectedEstServClockVal), Oscl_Int64_Utils::get_uint64_lower32(estServClock)));
            PVMF_JB_LOGCLOCK_SESSION_DURATION((0, "PVMFJitterBufferNode::PVMFJBSessionDurationTimerEvent - TotalDuration=%d, Interval=%d", diff32, diff32));
        }
        ipSessionDurationTimer->Start();
    }
    return;
}

void PVMFJitterBufferMisc::ProcessCallback(CLOCK_NOTIFICATION_INTF_TYPE aClockNotificationInterfaceType, uint32 aCallBkId, const OsclAny* aContext, PVMFStatus aStatus)
{
    OSCL_UNUSED_ARG(aClockNotificationInterfaceType);
    OSCL_UNUSED_ARG(aContext);
    if (aCallBkId == iEstimatedServerClockUpdateCallbackId && (PVMFSuccess == aStatus))
    {
        ipSessionDurationTimer->EstimatedServerClockUpdated();
    }
}

bool PVMFJitterBufferMisc::UseSessionDurationTimerForEOS()
{
    char mimeForSessioDurationTmrNecessity[] = "rtp";
    char mediaChannelMimeType[255] = {'0'};
    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator iter;
    for (iter = irPortParamsQueue.begin(); iter != irPortParamsQueue.end(); iter++)
    {
        PVMFJitterBufferPortParams* pPortParams = *iter;
        if (pPortParams && (pPortParams->ipJitterBuffer))
        {
            oscl_memset(mediaChannelMimeType, 0, sizeof(mediaChannelMimeType));
            const char* tmpMediaChannelMimeType = pPortParams->ipJitterBuffer->GetMimeType();
            const int32 mediaChannelMimeLen =  oscl_strlen(tmpMediaChannelMimeType);
            if (tmpMediaChannelMimeType)
            {
                for (int ii = 0; ii < mediaChannelMimeLen; ii++)
                {
                    mediaChannelMimeType[ii] = oscl_tolower(tmpMediaChannelMimeType[ii]);
                }
                mediaChannelMimeType[mediaChannelMimeLen] = '\0';
            }

            if (oscl_strstr(mediaChannelMimeType, mimeForSessioDurationTmrNecessity))
            {
                return true;
            }
        }
    }
    return false;//based on mime type
}

void PVMFJitterBufferMisc::LogClientAndEstimatedServerClock(PVLogger* aLogger)
{
    uint32 timebase32 = 0;
    uint32 clientClock32 = 0;
    uint32 serverClock32 = 0;
    bool overflowFlag = false;
    irClientPlaybackClock.GetCurrentTime32(clientClock32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, timebase32);

    if (ipEstimatedServerClock)
        ipEstimatedServerClock->GetCurrentTime32(serverClock32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, timebase32);

    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, aLogger, PVLOGMSG_INFO, (0, "Value of Client Clock %d and value of Estimated Sever Clock %d", clientClock32, serverClock32));
}

bool PVMFJitterBufferMisc::LookupRTCPChannelParams(PVMFPortInterface* rtpPort, PVMFPortInterface*& rtcpPort, PVMFJitterBuffer*& rtpPktJitterBuffer)
{
    bool retval = false;
    PVMFJitterBufferPort* jbInputPort = OSCL_STATIC_CAST(PVMFJitterBufferPort*, rtpPort);
    PVMFJitterBufferPortParams* inputPortParams = jbInputPort->GetPortParams();
    PVMFJitterBufferPortParams* feedbackPortParams = NULL;

    if (LocateFeedBackPort(inputPortParams, feedbackPortParams))
    {
        rtcpPort =  &feedbackPortParams->irPort;
        rtpPktJitterBuffer = inputPortParams->ipJitterBuffer;
        retval = true;
    }
    return retval;
}

bool PVMFJitterBufferMisc::LocateFeedBackPort(PVMFJitterBufferPortParams*& aInputPortParamsPtr, PVMFJitterBufferPortParams*& aFeedBackPortParamsPtr)
{
    uint32 inputPortId = aInputPortParamsPtr->iId;

    /* Feedback port id must be inputPortId + 2 */

    Oscl_Vector<PVMFJitterBufferPortParams*, OsclMemAllocator>::iterator it;

    for (it = irPortParamsQueue.begin(); it != irPortParamsQueue.end(); it++)
    {
        PVMFJitterBufferPortParams* portParams = *it;
        if ((portParams->iTag == PVMF_JITTER_BUFFER_PORT_TYPE_FEEDBACK) &&
                ((int32)portParams->iId == (int32)inputPortId + 2))
        {
            aFeedBackPortParamsPtr = portParams;
            return true;
        }
    }
    return false;
}

OSCL_EXPORT_REF IPayloadParser* PVMFJitterBufferMisc::CreatePayloadParser(PayloadParserRegistry* aPayLoadParserRegistry, const char* aMimeStr)
{
    if (!aMimeStr)
    {
        return NULL;
    }

    char* const mimeStrToCompare = OSCL_ARRAY_NEW(char, oscl_strlen(aMimeStr) + 1);
    {
        uint32 ii = 0;
        for (ii = 0; ii < oscl_strlen(aMimeStr); ii++)
        {
            mimeStrToCompare[ii] = oscl_tolower(aMimeStr[ii]);
        }
        mimeStrToCompare[ii] = '\0';
    }

    //aMimeStr may include prefix rtp/
    const char* possiblePrefixToNeglect = "rtp/";
    char* mimeStr = NULL;
    char* prefixIndexPtr = oscl_strstr(mimeStrToCompare, possiblePrefixToNeglect);
    if (prefixIndexPtr)
    {
        mimeStr = prefixIndexPtr + oscl_strlen(possiblePrefixToNeglect);
    }
    else
    {
        mimeStr = OSCL_CONST_CAST(char*, aMimeStr);
    }

    IPayloadParser* retval = NULL;
    if (aPayLoadParserRegistry)
    {
        OsclMemoryFragment memFrag;
        memFrag.ptr = (OsclAny*)(mimeStr);
        memFrag.len = oscl_strlen(mimeStr);
        IPayloadParserFactory* factory = aPayLoadParserRegistry->lookupPayloadParserFactory(memFrag);
        if (factory == NULL)
        {
#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
            PVLogger* logger = PVLogger::GetLoggerObject("PVMFJitterBufferMisc");
            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, logger, PVLOGMSG_ERR, (0, "PVMFJitterBufferMisc::GetPayloadParserRegistry: Error - Invalid Factory Mime %s ", mimeStr));
#endif
        }
        else
        {
            retval = factory->createPayloadParser();
        }
    }
    OSCL_ARRAY_DELETE(mimeStrToCompare);
    return retval;
}

OSCL_EXPORT_REF PVMFStatus PVMFJitterBufferMisc::DestroyPayloadParser(PayloadParserRegistry* aPayLoadParserRegistry, const char* aMimeStr, IPayloadParser* aPayloadParser)
{
    PVMFStatus status = PVMFSuccess;

    if (!aMimeStr)
    {
        return PVMFFailure;
    }

    char* const mimeStrToCompare = OSCL_ARRAY_NEW(char, oscl_strlen(aMimeStr) + 1);
    {
        uint32 ii = 0;
        for (ii = 0; ii < oscl_strlen(aMimeStr); ii++)
        {
            mimeStrToCompare[ii] = oscl_tolower(aMimeStr[ii]);
        }
        mimeStrToCompare[ii] = '\0';
    }

    //aMimeStr may include prefix rtp/
    const char* possiblePrefixToNeglect = "rtp/";
    char* mimeStr = NULL;
    char* prefixIndexPtr = oscl_strstr(mimeStrToCompare, possiblePrefixToNeglect);
    if (prefixIndexPtr)
    {
        mimeStr = prefixIndexPtr + oscl_strlen(possiblePrefixToNeglect);
    }
    else
    {
        mimeStr = OSCL_CONST_CAST(char*, aMimeStr);
    }

    if (aPayLoadParserRegistry)
    {
        OsclMemoryFragment memFrag;
        memFrag.ptr = (OsclAny*)(mimeStr);
        memFrag.len = oscl_strlen(mimeStr);
        IPayloadParserFactory* factory =
            aPayLoadParserRegistry->lookupPayloadParserFactory(memFrag);
        if (factory == NULL)
        {
#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
            PVLogger* logger = PVLogger::GetLoggerObject("PVMFJitterBufferMisc");
            PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, logger, PVLOGMSG_ERR, (0, "PVMFJitterBufferMisc::DestroyPayloadParser: Error - Invalid Factory %s", mimeStr));
#endif
            status = PVMFFailure;
        }
        if (aPayloadParser)
            factory->destroyPayloadParser(aPayloadParser);
    }
    OSCL_ARRAY_DELETE(mimeStrToCompare);
    return status;
}
