#include "H264LiveServerMediaSession.hh"

/*char *videoSPSData=NULL;
char *videoPPSData=NULL;
int spsSize;
int ppsSize;*/

H264LiveServerMediaSession* H264LiveServerMediaSession::createNew(UsageEnvironment& env, bool reuseFirstSource)
{
    return new H264LiveServerMediaSession(env, reuseFirstSource);
}

H264LiveServerMediaSession::H264LiveServerMediaSession(UsageEnvironment& env, bool reuseFirstSource)
:OnDemandServerMediaSubsession(env,reuseFirstSource),fAuxSDPLine(NULL), fDoneFlag(0), fDummySink(NULL)
{
    mtx.lock();
    liveVideosource = nullptr;
    liveSourceAvailable = 0;
    eventTriggerId = 0;
    eventTriggerId = envir().taskScheduler().createEventTrigger(LiveSourceWithx264::deliverFrame0);
    mtx.unlock();
}

H264LiveServerMediaSession::~H264LiveServerMediaSession(void)
{
    delete[] fAuxSDPLine;
    mtx.lock();
    envir().taskScheduler().deleteEventTrigger(eventTriggerId);
    eventTriggerId = 0;
    mtx.unlock();
}

static void afterPlayingDummy(void* clientData)
{
    H264LiveServerMediaSession *session = (H264LiveServerMediaSession*)clientData;
    session->afterPlayingDummy1();
}

void H264LiveServerMediaSession::afterPlayingDummy1()
{
    envir().taskScheduler().unscheduleDelayedTask(nextTask());
    setDoneFlag();
}

static void checkForAuxSDPLine(void* clientData)
{
    H264LiveServerMediaSession* session = (H264LiveServerMediaSession*)clientData;
    session->checkForAuxSDPLine1();
}

void H264LiveServerMediaSession::checkForAuxSDPLine1() {
    char const* dasl;
    int uSecsToDelay = 100000; // 100 ms
    if (fAuxSDPLine != NULL) {
        // Signal the event loop that we're done:
        setDoneFlag();
    } else if (fDummySink != NULL && (dasl = fDummySink->auxSDPLine()) != NULL) {
        fAuxSDPLine = strDup(dasl);
        fDummySink = NULL;
        // Signal the event loop that we're done:
        setDoneFlag();        
    } else if (!fDoneFlag) {
        // try again after a brief delay:

        nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay,
                                                                 (TaskFunc*)checkForAuxSDPLine, this);
    }
}

char const* H264LiveServerMediaSession::getAuxSDPLine(RTPSink* rtpSink, FramedSource* inputSource) {
    if (fAuxSDPLine != NULL) return fAuxSDPLine; // it's already been set up (for a previous client)
    
    if (fDummySink == NULL) { // we're not already setting it up for another, concurrent stream
        // Note: For H264 video files, the 'config' information ("profile-level-id" and "sprop-parameter-sets") isn't known
        // until we start reading the file.  This means that "rtpSink"s "auxSDPLine()" will be NULL initially,
        // and we need to start reading data from our file until this changes.
        fDummySink = rtpSink;
        
        // Start reading the file:
        fDummySink->startPlaying(*inputSource, afterPlayingDummy, this);
        
        // Check whether the sink's 'auxSDPLine()' is ready:
        checkForAuxSDPLine(this);
    }
    envir().taskScheduler().doEventLoop(&fDoneFlag);
    return fAuxSDPLine;
}

FramedSource* H264LiveServerMediaSession::createNewStreamSource(unsigned clientSessionID, unsigned& estBitRate)
{
    mtx.lock();    
    estBitRate = 500; // kbps, estimate
  
    liveSourceAvailable = 1;
    liveVideosource = LiveSourceWithx264::createNew(envir(),this);
    liveVideosource->m_plive555TaskScheduler = live555TaskScheduler;
    mtx.unlock();
    // are you trying to keep the reference of the source somewhere? you shouldn't.
    // Live555 will create and delete this class object many times. if you store it somewhere
    // you will get memory access violation. instead you should configure you source to always read from your data source
    //return H264VideoStreamDiscreteFramer::createNew(envir(),source);
    return H264VideoStreamDiscreteFramer::createNew(envir(),liveVideosource);
   // return H264VideoStreamFramer::createNew(envir(),liveVideosource);
}

RTPSink* H264LiveServerMediaSession::createNewRTPSink(Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource)
{
    rtpPayloadTypeIfDynamic = 96;
	return H264VideoRTPSink::createNew(envir(), rtpGroupsock, 96,
    		(u_int8_t const*)videoSPSData, spsSize, (u_int8_t const*)videoPPSData, ppsSize);
}

void H264LiveServerMediaSession::LiveStream_cameraFrameData(unsigned char* mFrameByte, unsigned mFrameSize, struct timeval mPresentationTime, uint64_t timeStamp)
{
    mtx.lock();
    if(liveSourceAvailable==0 && liveVideosource==NULL) {
	//	printf("liveSourceAvailable  NULL liveSourceAvailable %d %X\n", liveSourceAvailable, liveVideosource);
        mtx.unlock();
        return;
    }
    
	//printf("liveSourceAvailable NOT NULL liveSourceAvailable %d %X\n", liveSourceAvailable, liveVideosource);
    liveVideosource->LiveStream_cameraFrameData(mFrameByte,mFrameSize,mPresentationTime,timeStamp);
	mtx.unlock();

	return;
}
