/* 用当前RTSPSession构造一个OSRef实例, 在RTPSession Map(Hash表)中注册并加入该引用OSRef元(其key值唯一),
同时更新qtssSvrClientSessions的属性,及QTSServerInterface中的总RTPSession数 */
QTSS_Error  RTPSession::Activate(const StrPtrLen& inSessionID)
{
    //Set the session ID for this session

	/* 用入参配置fRTSPSessionIDBuf的值(是C-String) */
    Assert(inSessionID.Len <= QTSS_MAX_SESSION_ID_LENGTH);
    ::memcpy(fRTSPSessionIDBuf, inSessionID.Ptr, inSessionID.Len);
    fRTSPSessionIDBuf[inSessionID.Len] = '\0';

	/* 用C-String的fRTSPSessionIDBuf设置qtssCliSesRTSPSessionID的属性值 */
    this->SetVal(qtssCliSesRTSPSessionID, &fRTSPSessionIDBuf[0], inSessionID.Len);
    
	/* 用qtssCliSesRTSPSessionID的属性值来得到一个RTPSession Map的引用OSRef元 */
    fRTPMapElem.Set(*this->GetValue(qtssCliSesRTSPSessionID), this);
    
	/* 获取服务器接口 */
    QTSServerInterface* theServer = QTSServerInterface::GetServer();
    
    //Activate puts the session into the RTPSession Map
	/* 在RTPSession Map(Hash表)中注册并加入一个引用OSRef,若字符串标识唯一,就能成功返回OS_NoErr;若有一个相同key值的元素,就返回错误EPERM  */
    QTSS_Error err = theServer->GetRTPSessionMap()->Register(&fRTPMapElem);
	//若有同名键值,立即返回
    if (err == EPERM)
        return err;

	/* 确保key值唯一 */
    Assert(err == QTSS_NoErr);
    
    //
    // Adding this session into the qtssSvrClientSessions attr and incrementing the number of sessions must be atomic
	/* 锁定服务器对象 */
    OSMutexLocker locker(theServer->GetMutex()); 

    //
    // Put this session into the qtssSvrClientSessions attribute of the server
#if DEBUG
    Assert(theServer->GetNumValues(qtssSvrClientSessions) == theServer->GetNumRTPSessions());//确保属性qtssSvrClientSessions中的RTPSession个数和服务器中实际的个数相同
#endif
	/* 设置qtssSvrClientSessions的第GetNumRTPSessions()个RTPSession的属性 */
    RTPSession* theSession = this;
    err = theServer->SetValue(qtssSvrClientSessions, theServer->GetNumRTPSessions(), &theSession, sizeof(theSession), QTSSDictionary::kDontObeyReadOnly);
    Assert(err == QTSS_NoErr);
    
#if DEBUG
    fActivateCalled = true;
#endif
	/* 及时更新QTSServerInterface中的总RTPSession数  */
    QTSServerInterface::GetServer()->IncrementTotalRTPSessions();
    return QTSS_NoErr;
}
QTSS_Error  RTPSession::Activate(const StrPtrLen& inSessionID)
{
    //Set the session ID for this session
    Assert(inSessionID.Len <= QTSS_MAX_SESSION_ID_LENGTH);
    ::memcpy(fRTSPSessionIDBuf, inSessionID.Ptr, inSessionID.Len);
    fRTSPSessionIDBuf[inSessionID.Len] = '\0';
    this->SetVal(qtssCliSesRTSPSessionID, &fRTSPSessionIDBuf[0], inSessionID.Len);
    
    fRTPMapElem.Set(*this->GetValue(qtssCliSesRTSPSessionID), this);
    
    QTSServerInterface* theServer = QTSServerInterface::GetServer();
    
    //Activate puts the session into the RTPSession Map
    QTSS_Error err = theServer->GetRTPSessionMap()->Register(&fRTPMapElem);
    if (err == EPERM)
        return err;
    Assert(err == QTSS_NoErr);
    
    //
    // Adding this session into the qtssSvrClientSessions attr and incrementing the number of sessions must be atomic
    OSMutexLocker locker(theServer->GetMutex()); 

    //
    // Put this session into the qtssSvrClientSessions attribute of the server
#if DEBUG
    Assert(theServer->GetNumValues(qtssSvrClientSessions) == theServer->GetNumRTPSessions());
#endif
    RTPSession* theSession = this;
    err = theServer->SetValue(qtssSvrClientSessions, theServer->GetNumRTPSessions(), &theSession, sizeof(theSession), QTSSDictionary::kDontObeyReadOnly);
    Assert(err == QTSS_NoErr);
    
#if DEBUG
    fActivateCalled = true;
#endif
    QTSServerInterface::GetServer()->IncrementTotalRTPSessions();
    return QTSS_NoErr;
}
SInt64 RTPStatsUpdaterTask::Run()
{

    QTSServerInterface* theServer = QTSServerInterface::sServer;
    
    // All of this must happen atomically wrt dictionary values we are manipulating
    OSMutexLocker locker(&theServer->fMutex);
    
    //First update total bytes. This must be done because total bytes is a 64 bit number,
    //so no atomic functions can apply.
    //
    // NOTE: The line below is not thread safe on non-PowerPC platforms. This is
    // because the fPeriodicRTPBytes variable is being manipulated from within an
    // atomic_add. On PowerPC, assignments are atomic, so the assignment below is ok.
    // On a non-PowerPC platform, the following would be thread safe:
    //unsigned int periodicBytes = atomic_add(&theServer->fPeriodicRTPBytes, 0);
    unsigned int periodicBytes = theServer->fPeriodicRTPBytes;
    (void)atomic_sub(&theServer->fPeriodicRTPBytes, periodicBytes);
    theServer->fTotalRTPBytes += periodicBytes;
    
    // Same deal for packet totals
    unsigned int periodicPackets = theServer->fPeriodicRTPPackets;
    (void)atomic_sub(&theServer->fPeriodicRTPPackets, periodicPackets);
    theServer->fTotalRTPPackets += periodicPackets;
    
    // ..and for lost packet totals
    unsigned int periodicPacketsLost = theServer->fPeriodicRTPPacketsLost;
    (void)atomic_sub(&theServer->fPeriodicRTPPacketsLost, periodicPacketsLost);
    theServer->fTotalRTPPacketsLost += periodicPacketsLost;
    
    SInt64 curTime = OS::Milliseconds();
    
    //for cpu percent
        Float32 cpuTimeInSec = GetCPUTimeInSeconds();
    
    //also update current bandwidth statistic
    if (fLastBandwidthTime != 0)
    {
        Assert(curTime > fLastBandwidthTime);
        UInt32 delta = (UInt32)(curTime - fLastBandwidthTime);
        if (delta < 1000)
            WarnV(delta >= 1000, "Timer is off");
        
        //do the bandwidth computation using floating point divides
        //for accuracy and speed.
        Float32 bits = (Float32)(periodicBytes * 8);
        Float32 theTime = (Float32)delta;
        theTime /= 1000;
        bits /= theTime;
        Assert(bits >= 0);
        theServer->fCurrentRTPBandwidthInBits = (UInt32)bits;
        
        // okay let's do it for MP3 bytes now
        bits = (Float32)(((SInt64)theServer->fTotalMP3Bytes - fLastTotalMP3Bytes) * 8);
        bits /= theTime;
        theServer->fCurrentMP3BandwidthInBits = (UInt32)bits;

        //do the same computation for packets per second
        Float32 packetsPerSecond = (Float32)periodicPackets;
        packetsPerSecond /= theTime;
        Assert(packetsPerSecond >= 0);
        theServer->fRTPPacketsPerSecond = (UInt32)packetsPerSecond;
        
        //do the computation for cpu percent
        Float32 diffTime = cpuTimeInSec - theServer->fCPUTimeUsedInSec;
        theServer->fCPUPercent = (diffTime/theTime) * 100;  
		
		UInt32 numProcessors = OS::GetNumProcessors();
		
		if (numProcessors > 1)
			theServer->fCPUPercent /= numProcessors;
    }
    
    fLastTotalMP3Bytes = (SInt64)theServer->fTotalMP3Bytes;
    fLastBandwidthTime = curTime;
    // We use a running average for avg. bandwidth calculations
    theServer->fAvgMP3BandwidthInBits = (theServer->fAvgMP3BandwidthInBits
            + theServer->fCurrentMP3BandwidthInBits)/2; 
    
    //for cpu percent
    theServer->fCPUTimeUsedInSec    = cpuTimeInSec; 
    
    //also compute average bandwidth, a much more smooth value. This is done with
    //the fLastBandwidthAvg, a timestamp of the last time we did an average, and
    //fLastBytesSent, the number of bytes sent when we last did an average.
    if ((fLastBandwidthAvg != 0) && (curTime > (fLastBandwidthAvg +
        (theServer->GetPrefs()->GetAvgBandwidthUpdateTimeInSecs() * 1000))))
    {
        UInt32 delta = (UInt32)(curTime - fLastBandwidthAvg);
        SInt64 bytesSent = theServer->fTotalRTPBytes - fLastBytesSent;
        Assert(bytesSent >= 0);
        
        //do the bandwidth computation using floating point divides
        //for accuracy and speed.
        Float32 bits = (Float32)(bytesSent * 8);
        Float32 theAvgTime = (Float32)delta;
        theAvgTime /= 1000;
        bits /= theAvgTime;
        Assert(bits >= 0);
        theServer->fAvgRTPBandwidthInBits = (UInt32)bits;

        fLastBandwidthAvg = curTime;
        fLastBytesSent = theServer->fTotalRTPBytes;
        
        //if the bandwidth is above the bandwidth setting, disconnect 1 user by sending them
        //a BYE RTCP packet.
        SInt32 maxKBits = theServer->GetPrefs()->GetMaxKBitsBandwidth();
        if ((maxKBits > -1) && (theServer->fAvgRTPBandwidthInBits > ((UInt32)maxKBits * 1024)))
        {
            //we need to make sure that all of this happens atomically wrt the session map
            OSMutexLocker locker(theServer->GetRTPSessionMap()->GetMutex());
            RTPSessionInterface* theSession = this->GetNewestSession(theServer->fRTPMap);
            if (theSession != NULL)
                if ((curTime - theSession->GetSessionCreateTime()) <
                        theServer->GetPrefs()->GetSafePlayDurationInSecs() * 1000)
                    theSession->Signal(Task::kKillEvent);
        }
    }
    else if (fLastBandwidthAvg == 0)
    {
        fLastBandwidthAvg = curTime;
        fLastBytesSent = theServer->fTotalRTPBytes;
    }
    
    (void)this->GetEvents();//we must clear the event mask!
    return theServer->GetPrefs()->GetTotalBytesUpdateTimeInSecs() * 1000;
}