/*
#  $Id$
# -----------------------------------------------------------------------------
#  The part of 'VideoNEXT MediaClient SDK'
# -----------------------------------------------------------------------------
#  Author: Petrov Maxim, 06/11/2014
#  Edited by:
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
*/
#include <sys/time.h>
#include "RTPSource.hh"
#include "StreamStats.h"

namespace videonext { namespace media {

        StreamStats::StreamStats(UsageEnvironment& env, RTPSource &rtpSource, StreamInfo &streamInfo,
                                 MediaStreamHandler &mediaStreamHandler)
            : fEnv(env), fRtpSource(rtpSource), fStreamInfo(streamInfo), fMediaStreamHandler(mediaStreamHandler)
            , fUpdateStatsTask(0)
            , fPrevNumPacketsReceived(0), fPrevNumPacketsLost(0), fPrevNumKBytesReceived(0)
{
    fPrevStatsTime.tv_sec = fPrevStatsTime.tv_usec = 0;
    
    fUpdateStatsTask = fEnv.taskScheduler()
        .scheduleDelayedTask(10*1000000,
                             (TaskFunc*)updateStatsTask, this);  
}

/*virtual*/ StreamStats::~StreamStats()
{
    if (fUpdateStatsTask)
        fEnv.taskScheduler().unscheduleDelayedTask(fUpdateStatsTask);   
}

/*static*/ void StreamStats::updateStatsTask(void *clientData)
{
    StreamStats *ss = (StreamStats*)clientData;
    ss->updateStats();
}

void StreamStats::updateStats()
{
    RTPReceptionStatsDB &statDB = fRtpSource.receptionStatsDB();
    RTPReceptionStatsDB::Iterator iter(statDB);
    
    RTPReceptionStats *stat = iter.next();
    if (stat == NULL)
        return;
    
    // fprintf(stderr, "RTP stats: totNumPacketsReceived: %d, totNumPacketsLost: %d, totNumKBytesReceived: %f\n",
    //         stat->totNumPacketsReceived(), stat->totNumPacketsLost(), stat->totNumKBytesReceived());

    Report report;
    report.streamInfo = &fStreamInfo;
    report.jitter = (int64_t)stat->jitter() * 1000000 / 90000;
    
    if (fPrevStatsTime.tv_sec == 0)
    {
        report.bandwith = stat->totNumKBytesReceived() / 10;
        report.qfactor = 1;
        if (report.bandwith)
            fMediaStreamHandler.newReport(report);
    }
    else
    {
        struct timeval now;
        gettimeofday(&now, 0);
    
//        int numUsecsFromLastReport = (((now.tv_sec - fPrevStatsTime.tv_sec) * 1000000) + 
//                                           (now.tv_usec - fPrevStatsTime.tv_usec));
        
        int numPacketsReceivedSinceLastReport = stat->totNumPacketsReceived() - fPrevNumPacketsReceived;
        int numPacketsLostSinceLastReport     = stat->totNumPacketsLost()     - fPrevNumPacketsLost;
//        float numKBytesReceivedSinceLastReport  = stat->totNumKBytesReceived()  -  fPrevNumKBytesReceived;

//        unsigned bandwithKBperSec = (1000000 * numKBytesReceivedSinceLastReport)/numUsecsFromLastReport;
        
        // fprintf(stderr, "Instantaneous RTP stats: usecsFromLastReport: %d, numPacketsReceived: %d, numPacketsLost: %d, numKBytesReceived: %f, bandwith: %d KB/s\n",
        //         numUsecsFromLastReport,
        //         numPacketsReceivedSinceLastReport, numPacketsLostSinceLastReport, numKBytesReceivedSinceLastReport,
        //         bandwithKBperSec
        //     );

        if (numPacketsReceivedSinceLastReport)
        {
            float lostFraction = (float)numPacketsLostSinceLastReport / numPacketsReceivedSinceLastReport;

            if (lostFraction > 0.07)
                report.qfactor = 0;
            else
                report.qfactor = 1;

                
            fMediaStreamHandler.newReport(report);
        }
        
    }

    
    gettimeofday(&fPrevStatsTime, 0);
    fPrevNumPacketsReceived = stat->totNumPacketsReceived();
    fPrevNumPacketsLost     = stat->totNumPacketsLost();
    fPrevNumKBytesReceived  = stat->totNumKBytesReceived();
    
    
    fUpdateStatsTask = fEnv.taskScheduler()
        .scheduleDelayedTask(8*1000000,
                             (TaskFunc*)updateStatsTask, this);  

}

}}

