/* 用当前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; }