/* 用当前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; }
void WINAPI ServiceControl(DWORD inControlCode) { QTSS_ServerState theState; QTSServerInterface* theServer = QTSServerInterface::GetServer(); DWORD theStatusReport = SERVICE_START_PENDING; if (theServer != NULL) theState = theServer->GetServerState(); else theState = qtssStartingUpState; switch (inControlCode) { // Stop the service. // case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: { if (theState == qtssStartingUpState) break; // // Signal the server to shut down. theState = qtssShuttingDownState; if (theServer != NULL) theServer->SetValue(qtssSvrState, 0, &theState, sizeof(theState)); break; } case SERVICE_CONTROL_PAUSE: { if (theState != qtssRunningState) break; // // Signal the server to refuse new connections. theState = qtssRefusingConnectionsState; if (theServer != NULL) theServer->SetValue(qtssSvrState, 0, &theState, sizeof(theState)); break; } case SERVICE_CONTROL_CONTINUE: { if (theState != qtssRefusingConnectionsState) break; // // Signal the server to refuse new connections. theState = qtssRefusingConnectionsState; if (theServer != NULL) theServer->SetValue(qtssSvrState, 0, &theState, sizeof(theState)); break; } case SERVICE_CONTROL_INTERROGATE: break; // Just update our status default: break; } if (theServer != NULL) { theState = theServer->GetServerState(); // // Convert a QTSS state to a Win32 Service state switch (theState) { case qtssStartingUpState: theStatusReport = SERVICE_START_PENDING; break; case qtssRunningState: theStatusReport = SERVICE_RUNNING; break; case qtssRefusingConnectionsState: theStatusReport = SERVICE_PAUSED; break; case qtssFatalErrorState: theStatusReport = SERVICE_STOP_PENDING; break; case qtssShuttingDownState: theStatusReport = SERVICE_STOP_PENDING; break; default: theStatusReport = SERVICE_RUNNING; break; } } else theStatusReport = SERVICE_START_PENDING; qtss_printf("Reporting status from ServiceControl function\n"); ::ReportStatus(theStatusReport, NO_ERROR); }
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; }
QTSS_Error QTSServer::RereadPrefsService(QTSS_ServiceFunctionArgsPtr /*inArgs*/) { // // This function can only be called safely when the server is completely running. // Ensuring this is a bit complicated because of preemption. Here's how it's done... QTSServerInterface* theServer = QTSServerInterface::GetServer(); // This is to make sure this function isn't being called before the server is // completely started up. if ((theServer == NULL) || (theServer->GetServerState() != qtssRunningState)) return QTSS_OutOfState; // Because the server must have started up, and because this object always stays // around (until the process dies), we can now safely get this object. QTSServerPrefs* thePrefs = theServer->GetPrefs(); // Grab the prefs mutex. We want to make sure that calls to RereadPrefsService // are serialized. This also prevents the server from shutting down while in // this function, because the QTSServer destructor grabs this mutex as well. OSMutexLocker locker(thePrefs->GetMutex()); // Finally, check the server state again. The state may have changed // to qtssShuttingDownState or qtssFatalErrorState in this time, though // at this point we have the prefs mutex, so we are guarenteed that the // server can't actually shut down anymore if (theServer->GetServerState() != qtssRunningState) return QTSS_OutOfState; // Ok, we're ready to reread preferences now. // // Reread preferences sPrefsSource->Parse(); thePrefs->RereadServerPreferences(true); // Delete all the streams QTSSModule** theModule = NULL; UInt32 theLen = 0; for (int y = 0; QTSServerInterface::GetServer()->GetValuePtr(qtssSvrModuleObjects, y, (void**)&theModule, &theLen) == QTSS_NoErr; y++) { Assert(theModule != NULL); Assert(theLen == sizeof(QTSSModule*)); (*theModule)->GetPrefsDict()->RereadPreferences(); #if DEBUG theModule = NULL; theLen = 0; #endif } // // Go through each module's prefs object and have those reread as well // // Now that we are done rereading the prefs, invoke all modules in the RereadPrefs // role so they can update their internal prefs caches. for (UInt32 x = 0; x < QTSServerInterface::GetNumModulesInRole(QTSSModule::kRereadPrefsRole); x++) { QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kRereadPrefsRole, x); (void)theModule->CallDispatch(QTSS_RereadPrefs_Role, NULL); } return QTSS_NoErr; }
QTSS_Error RTSPRequest::SendDigestChallenge(UInt32 qop, StrPtrLen *nonce, StrPtrLen* opaque) { QTSS_Error theErr = QTSS_NoErr; char challengeBuf[kAuthChallengeHeaderBufSize]; ResizeableStringFormatter challengeFormatter(challengeBuf, kAuthChallengeHeaderBufSize); StrPtrLen realm; char *prefRealmPtr = NULL; StrPtrLen *realmPtr = this->GetValue(qtssRTSPReqURLRealm); // Get auth realm set by the module if(realmPtr->Len > 0) { realm = *realmPtr; } else { // If module hasn't set the realm QTSServerInterface* theServer = QTSServerInterface::GetServer(); // get the realm from prefs prefRealmPtr = theServer->GetPrefs()->GetAuthorizationRealm(); // allocates memory Assert(prefRealmPtr != NULL); if (prefRealmPtr != NULL){ realm.Set(prefRealmPtr, strlen(prefRealmPtr)); } else { realm = sDefaultRealm; } } // Creating the Challenge header challengeFormatter.Put(sAuthDigestStr); // [Digest] challengeFormatter.PutSpace(); // [Digest ] challengeFormatter.Put(sRealmStr); // [Digest realm] challengeFormatter.Put(sEqualQuote); // [Digest realm="] challengeFormatter.Put(realm); // [Digest realm="somerealm] challengeFormatter.Put(sQuoteCommaSpace); // [Digest realm="somerealm", ] if(this->GetStale()) { challengeFormatter.Put(sStaleTrue); // [Digest realm="somerealm", stale="true", ] } challengeFormatter.Put(sNonceStr); // [Digest realm="somerealm", nonce] challengeFormatter.Put(sEqualQuote); // [Digest realm="somerealm", nonce="] challengeFormatter.Put(*nonce); // [Digest realm="somerealm", nonce="19723343a9fd75e019723343a9fd75e0] challengeFormatter.PutChar('"'); // [Digest realm="somerealm", nonce="19723343a9fd75e019723343a9fd75e0"] challengeFormatter.PutTerminator(); // [Digest realm="somerealm", nonce="19723343a9fd75e019723343a9fd75e0"\0] StrPtrLen challengePtr(challengeFormatter.GetBufPtr(), challengeFormatter.GetBytesWritten() - 1); this->SetValue(qtssRTSPReqDigestChallenge, 0, challengePtr.Ptr, challengePtr.Len, QTSSDictionary::kDontObeyReadOnly); RTSPSessionInterface* thisRTSPSession = this->GetSession(); if (thisRTSPSession) { (void)thisRTSPSession->SetValue(qtssRTSPSesLastDigestChallenge, 0, challengePtr.Ptr, challengePtr.Len,QTSSDictionary::kDontObeyReadOnly); } fStatus = qtssClientUnAuthorized; this->SetResponseKeepAlive(true); this->AppendHeader(qtssWWWAuthenticateHeader, &challengePtr); this->SendHeader(); // deleting the memory that was allocated in GetPrefs call above if (prefRealmPtr != NULL) { delete[] prefRealmPtr; } return theErr; }
QTSS_Error RTSPRequest::SendBasicChallenge(void) { QTSS_Error theErr = QTSS_NoErr; char *prefRealmPtr = NULL; do { char realmBuff[kRealmBuffSize] = "Basic realm=\""; StrPtrLen challenge(realmBuff); StrPtrLen whichRealm; // Get the module's realm StrPtrLen moduleRealm; theErr = this->GetValuePtr(qtssRTSPReqURLRealm, 0, (void **) &moduleRealm.Ptr, &moduleRealm.Len); if ( (QTSS_NoErr == theErr) && (moduleRealm.Len > 0) ) { whichRealm = moduleRealm; } else { theErr = QTSS_NoErr; // Get the default realm from the config file or use the static default if config realm is not found QTSServerInterface* theServer = QTSServerInterface::GetServer(); prefRealmPtr = theServer->GetPrefs()->GetAuthorizationRealm(); // allocates memory Assert(prefRealmPtr != NULL); if (prefRealmPtr != NULL) { whichRealm.Set(prefRealmPtr, strlen(prefRealmPtr)); } else { whichRealm = sDefaultRealm; } } int realmLen = whichRealm.Len + challenge.Len + 2; // add 2 based on double quote char + end of string 0x00 if (realmLen > kRealmBuffSize) // The realm is too big so use the default realm { Assert(0); whichRealm = sDefaultRealm; } memcpy(&challenge.Ptr[challenge.Len],whichRealm.Ptr,whichRealm.Len); int newLen = challenge.Len + whichRealm.Len; challenge.Ptr[newLen] = '"'; // add the terminating "" this was accounted for with the size check above challenge.Ptr[newLen + 1] = 0;// add the 0 terminator this was accounted for with the size check above challenge.Len = newLen +1; // set the real size of the string excluding the 0. #if (0) { // test code char test[256]; memcpy(test,sDefaultRealm.Ptr,sDefaultRealm.Len); test[sDefaultRealm.Len] = 0; qtss_printf("the static realm =%s \n",test); OSCharArrayDeleter prefDeleter(QTSServerInterface::GetServer()->GetPrefs()->GetAuthorizationRealm()); memcpy(test,prefDeleter.GetObject(),strlen(prefDeleter.GetObject())); test[strlen(prefDeleter.GetObject())] = 0; qtss_printf("the Pref realm =%s \n",test); memcpy(test,moduleRealm.Ptr,moduleRealm.Len); test[moduleRealm.Len] = 0; qtss_printf("the moduleRealm =%s \n",test); memcpy(test,whichRealm.Ptr,whichRealm.Len); test[whichRealm.Len] = 0; qtss_printf("the challenge realm =%s \n",test); memcpy(test,challenge.Ptr,challenge.Len); test[challenge.Len] = 0; qtss_printf("the challenge string =%s len = %"_S32BITARG_"\n",test, challenge.Len); } #endif fStatus = qtssClientUnAuthorized; this->SetResponseKeepAlive(true); this->AppendHeader(qtssWWWAuthenticateHeader, &challenge); this->SendHeader(); } while (false); if (prefRealmPtr != NULL) { delete[] prefRealmPtr; } return theErr; }
RTPSession::~RTPSession() { // Delete all the streams RTPStream** theStream = NULL; UInt32 theLen = 0; /* 假如预设值能打印RUDP信息 */ if (QTSServerInterface::GetServer()->GetPrefs()->GetReliableUDPPrintfsEnabled()) { SInt32 theNumLatePacketsDropped = 0;/* 丢弃延迟包个数 */ SInt32 theNumResends = 0; /* 重传包个数 */ /* 遍历该RTPSession的每个RTPStream,计算丢弃的过时包总数和重传包总数 */ for (int x = 0; this->GetValuePtr(qtssCliSesStreamObjects, x, (void**)&theStream, &theLen) == QTSS_NoErr; x++) { Assert(theStream != NULL); Assert(theLen == sizeof(RTPStream*)); if (*theStream != NULL) { /* 计算丢弃的过时包总数 */ theNumLatePacketsDropped += (*theStream)->GetStalePacketsDropped(); /* 得到重传包总数 */ theNumResends += (*theStream)->GetResender()->GetNumResends(); } } /* 得到客户端请求播放文件的Full URL */ char* theURL = NULL; (void)this->GetValueAsString(qtssCliSesFullURL, 0, &theURL); Assert(theURL != NULL); /* 获得RTPBandwidthTracker类 */ RTPBandwidthTracker* tracker = this->GetBandwidthTracker(); qtss_printf("Client complete. URL: %s.\n",theURL); qtss_printf("Max congestion window: %ld. Min congestion window: %ld. Avg congestion window: %ld\n", tracker->GetMaxCongestionWindowSize(), tracker->GetMinCongestionWindowSize(), tracker->GetAvgCongestionWindowSize()); qtss_printf("Max RTT: %ld. Min RTT: %ld. Avg RTT: %ld\n", tracker->GetMaxRTO(), tracker->GetMinRTO(), tracker->GetAvgRTO()); qtss_printf("Num resends: %ld. Num skipped frames: %ld. Num late packets dropped: %ld\n", theNumResends, this->GetFramesSkipped(), theNumLatePacketsDropped); delete [] theURL; } /* 遍历该RTPSession的每个RTPStream,逐一删除它们 */ for (int x = 0; this->GetValuePtr(qtssCliSesStreamObjects, x, (void**)&theStream, &theLen) == QTSS_NoErr; x++) { Assert(theStream != NULL); Assert(theLen == sizeof(RTPStream*)); if (*theStream != NULL) delete *theStream; } /* 获取服务器接口类,逐一将该RTPSession从qtssSvrClientSessions属性中删去 */ QTSServerInterface* theServer = QTSServerInterface::GetServer(); { OSMutexLocker theLocker(theServer->GetMutex()); RTPSession** theSession = NULL; // Remove this session from the qtssSvrClientSessions attribute UInt32 y = 0; for ( ; y < theServer->GetNumRTPSessions(); y++) { QTSS_Error theErr = theServer->GetValuePtr(qtssSvrClientSessions, y, (void**)&theSession, &theLen, true); Assert(theErr == QTSS_NoErr); if (*theSession == this) { theErr = theServer->RemoveValue(qtssSvrClientSessions, y, QTSSDictionary::kDontObeyReadOnly); break; } } Assert(y < theServer->GetNumRTPSessions()); theServer->AlterCurrentRTPSessionCount(-1); if (!fIsFirstPlay) // The session was started playing (the counter ignores additional pause-play changes while session is active) theServer->AlterRTPPlayingSessions(-1); } //we better not be in the RTPSessionMap anymore! #if DEBUG Assert(!fRTPMapElem.IsInTable()); StrPtrLen theRTSPSessionID(fRTSPSessionIDBuf,sizeof(fRTSPSessionIDBuf)); /* 从RTPSession Map中删去它们 */ OSRef* theRef = QTSServerInterface::GetServer()->GetRTPSessionMap()->Resolve(&theRTSPSessionID); Assert(theRef == NULL); #endif }
SInt64 RTCPTask::Run() { const UInt32 kMaxRTCPPacketSize = 2048; char thePacketBuffer[kMaxRTCPPacketSize]; StrPtrLen thePacket(thePacketBuffer, 0); QTSServerInterface* theServer = QTSServerInterface::GetServer(); //This task goes through all the UDPSockets in the RTPSocketPool, checking to see //if they have data. If they do, it demuxes the packets and sends the packet onto //the proper RTP session. EventFlags events = this->GetEvents(); // get and clear events if ( (events & Task::kReadEvent) || (events & Task::kIdleEvent) ) { //Must be done atomically wrt the socket pool. OSMutexLocker locker(theServer->GetSocketPool()->GetMutex()); for (OSQueueIter iter(theServer->GetSocketPool()->GetSocketQueue()); !iter.IsDone(); iter.Next()) { UInt32 theRemoteAddr = 0; UInt16 theRemotePort = 0; UDPSocketPair* thePair = (UDPSocketPair*)iter.GetCurrent()->GetEnclosingObject(); Assert(thePair != NULL); for (UInt32 x = 0; x < 2; x++) { UDPSocket* theSocket = NULL; if (x == 0) theSocket = thePair->GetSocketA(); else theSocket = thePair->GetSocketB(); UDPDemuxer* theDemuxer = theSocket->GetDemuxer(); if (theDemuxer == NULL) continue; else { theDemuxer->GetMutex()->Lock(); while (true) //get all the outstanding packets for this socket { thePacket.Len = 0; theSocket->RecvFrom(&theRemoteAddr, &theRemotePort, thePacket.Ptr, kMaxRTCPPacketSize, &thePacket.Len); if (thePacket.Len == 0) { theSocket->RequestEvent(EV_RE); break;//no more packets on this socket! } //if this socket has a demuxer, find the target RTPStream if (theDemuxer != NULL) { RTPStream* theStream = (RTPStream*)theDemuxer->GetTask(theRemoteAddr, theRemotePort); if (theStream != NULL) theStream->ProcessIncomingRTCPPacket(&thePacket); } } theDemuxer->GetMutex()->Unlock(); } } } } return 0; /* Fix for 4004432 */ /* SInt64 result = 0; if (theServer->GetNumRTPSessions() > 0) result = theServer->GetPrefs()->GetRTCPPollIntervalInMsec(); return result; */ }