Exemple #1
0
void CheckErrorLogState()
{
    //this function makes sure the logging state is in synch with the preferences.
    //extern variable declared in QTSSPreferences.h

    QTSServerPrefs* thePrefs = QTSServerInterface::GetServer()->GetPrefs();

    //check error log.
    if ((NULL == sErrorLog) && (thePrefs->IsErrorLogEnabled()))
    {
        sErrorLog = NEW QTSSErrorLog();
        sErrorLog->EnableLog();
    }

    if ((NULL != sErrorLog) && (!thePrefs->IsErrorLogEnabled()))
    {
        sErrorLog->Delete(); //sErrorLog is a task object, so don't delete it directly
        sErrorLog = NULL;
    }
}
Exemple #2
0
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;
}
/* 设置好各种参数后发信号开始触发RTPSession和发送SR包.播放影片,下面是设置步骤:(1)记录并设置相应的播放时间;(2)设置播放状态,播放标志,更新播放的RTPSession总数;
(3)根据电影的平均比特率设置Client Windows size,重置过缓冲窗;(4)遍历RTPSession中的每个RTPStream,设置打薄参数,重置打薄延迟参数,清除上个Play中重传类的RTP包;(5)假如获得的movie
平均比特率>0,就灵活调整TCP RTSP Socket缓存大小以适应movie比特率,且介于预设的最大值和最小值之间;(6)发信号启动该RTP Session任务; */
QTSS_Error  RTPSession::Play(RTSPRequestInterface* request, QTSS_PlayFlags inFlags)
{
    //first setup the play associated session interface variables
    Assert(request != NULL);
	/* 假如没有Module数组,立即返回 */
    if (fModule == NULL)
        return QTSS_RequestFailed;//Can't play if there are no associated streams
    
    //what time is this play being issued(触发) at? 记录Play触发的时刻
	fLastBitRateUpdateTime = fNextSendPacketsTime = fPlayTime = OS::Milliseconds();
	/* 假如是第一次播放,同步当前播放时间 */
    if (fIsFirstPlay)
		fFirstPlayTime = fPlayTime;
	/* 获取当前播放时间戳和RTSP Request Header Range中的fStartTime的差值 */
    fAdjustedPlayTime = fPlayTime - ((SInt64)(request->GetStartTime() * 1000));
    //for RTCP SRs(RTCP发送方报告), we also need to store the play time in NTP
    fNTPPlayTime = OS::TimeMilli_To_1900Fixed64Secs(fPlayTime);
    
    //we are definitely playing now, so schedule(调度) the object!
    fState = qtssPlayingState;
    fIsFirstPlay = false;/* 现在不是第一次播放 */
    fPlayFlags = inFlags;/* 是生成SR包还是AppendServerInfo进SR包 */

	/* track how many sessions are playing,see QTSServerInterface.h,使fNumRTPPlayingSessions加1 */
    QTSServerInterface::GetServer()-> AlterRTPPlayingSessions(1);
    
	/* set Client window size according to bitrate,,参见RTPBandwidthTracker::SetWindowSize() */
	//根据电影的平均比特率设置Client Windows size
    UInt32 theWindowSize;
	/* 获取电影的平均比特率 */
    UInt32 bitRate = this->GetMovieAvgBitrate();
	/* 假如电影的平均比特率为0或超过1Mbps,就设置Windowsize 为64Kbytes */
	if ((bitRate == 0) || (bitRate > QTSServerInterface::GetServer()->GetPrefs()->GetWindowSizeMaxThreshold() * 1024))
        theWindowSize = 1024 * QTSServerInterface::GetServer()->GetPrefs()->GetLargeWindowSizeInK();
	/* 假如电影的平均比特率超过200kbps,就设置Windowsize 为48Kbytes */
	else if (bitRate > QTSServerInterface::GetServer()->GetPrefs()->GetWindowSizeThreshold() * 1024)
		theWindowSize = 1024 * QTSServerInterface::GetServer()->GetPrefs()->GetMediumWindowSizeInK();
	/* 否则,,就设置Windowsize 为24Kbytes */
    else
        theWindowSize = 1024 * QTSServerInterface::GetServer()->GetPrefs()->GetSmallWindowSizeInK();

    qtss_printf("bitrate = %d, window size = %d\n", bitRate, theWindowSize);

	/* 设置Client窗口大小,参见RTPBandwidthTracker::SetWindowSize() */
    this->GetBandwidthTracker()->SetWindowSize(theWindowSize);

	/* 重置过缓冲窗 */
	this->GetOverbufferWindow()->ResetOverBufferWindow();

    // Go through all the streams, setting their thinning params
    RTPStream** theStream = NULL;
    UInt32 theLen = 0;
    
	/* 遍历RTPSession中的每个RTPStream,设置打薄参数,重置打薄延迟参数,清除上个Play中重传类的RTP包 */
    for (int x = 0; this->GetValuePtr(qtssCliSesStreamObjects, x, (void**)&theStream, &theLen) == QTSS_NoErr; x++)
    {
        Assert(theStream != NULL);
        Assert(theLen == sizeof(RTPStream*));
        if (*theStream != NULL)
        {   /* 设置打薄参数 */
            (*theStream)->SetThinningParams();
 			(*theStream)->ResetThinningDelayParams();
            
            // If we are using reliable UDP, then make sure to clear all the packets from the previous play spurt out of the resender 
            (*theStream)->GetResender()->ClearOutstandingPackets();
        }
    }

    qtss_printf("movie bitrate = %d, window size = %d\n", this->GetMovieAvgBitrate(), theWindowSize);
    Assert(this->GetBandwidthTracker()->BytesInList() == 0);
    
    // Set the size of the RTSPSession's send buffer to an appropriate max size
    // based on the bitrate of the movie. This has 2 benefits:
    // 1) Each socket normally defaults to 32 K. A smaller buffer prevents the
    // system from getting buffer starved if lots of clients get flow-controlled
    //
    // 2) We may need to scale up buffer sizes for high-bandwidth movies in order
    // to maximize thruput, and we may need to scale down buffer sizes for low-bandwidth
    // movies to prevent us from buffering lots of data that the client can't use
    //
    // If we don't know any better, assume maximum buffer size.

	/* 获取服务器预设值来得到最大TCP缓冲区大小 */
    QTSServerPrefs* thePrefs = QTSServerInterface::GetServer()->GetPrefs();
    UInt32 theBufferSize = thePrefs->GetMaxTCPBufferSizeInBytes();
    
#if RTPSESSION_DEBUGGING
    qtss_printf("RTPSession GetMovieAvgBitrate %li\n",(SInt32)this->GetMovieAvgBitrate() );
#endif

	/* 假如获得的movie平均比特率>0,就灵活调整TCP Socket缓存大小以适应movie比特率,且介于预设的最大值和最小值之间 */
    if (this->GetMovieAvgBitrate() > 0)
    {
        // We have a bit rate... use it.
		/* 由电影比特率和预设的缓存秒数(0.5s),得到实际的缓存大小(字节) */
        Float32 realBufferSize = (Float32)this->GetMovieAvgBitrate() * thePrefs->GetTCPSecondsToBuffer();
        theBufferSize = (UInt32)realBufferSize;
        theBufferSize >>= 3; // Divide by 8 to convert from bits to bytes
        
        // Round down to the next lowest power of 2.
		/* 四舍五入到最接近的小于它的2的幂,该函数定义见下面 */
		/* 将入参变为2的幂的特殊算法:先将入参表示为十六进制,从第29bit位开始从高到底开始走,若遇到值为1的bit位,就返回该bit位值为1,其它31个bit位值全为0的数;若一直没有1,返回0 */
        theBufferSize = this->PowerOf2Floor(theBufferSize);
        
		//下面对缓存大小进行保护,使真实值务必介于预设的最大值和最小值之间

        // This is how much data we should buffer based on the scaling factor... if it is lower than the min, raise to min
        if (theBufferSize < thePrefs->GetMinTCPBufferSizeInBytes())
            theBufferSize = thePrefs->GetMinTCPBufferSizeInBytes();
            
        // Same deal for max buffer size
        if (theBufferSize > thePrefs->GetMaxTCPBufferSizeInBytes())
            theBufferSize = thePrefs->GetMaxTCPBufferSizeInBytes();
    }
Exemple #4
0
QTSS_Error LogError(QTSS_RoleParamPtr inParamBlock)
{
    Assert(NULL != inParamBlock->errorParams.inBuffer);
    if (inParamBlock->errorParams.inBuffer == NULL)
        return QTSS_NoErr;
        
    UInt16 verbLvl = (UInt16) inParamBlock->errorParams.inVerbosity;
    if (verbLvl >= qtssIllegalVerbosity)
    	verbLvl = qtssFatalVerbosity;
        
    QTSServerPrefs* thePrefs = QTSServerInterface::GetServer()->GetPrefs();
        
    OSMutexLocker locker(sLogMutex);
    if (thePrefs->GetErrorLogVerbosity() >= inParamBlock->errorParams.inVerbosity)
    {
         size_t inStringLen = ::strlen(inParamBlock->errorParams.inBuffer);
         size_t lastStringLen = ::strlen(sLastErrorString); 
         Bool16 isDuplicate = true;
         
         if (inStringLen > sizeof(sLastErrorString) -1) //truncate to max char buffer subtract \0 terminator
            inStringLen = sizeof(sLastErrorString) -1;
            
         if (lastStringLen != inStringLen) //same size?
            isDuplicate = false; // different sizes
         else if (::strncmp(inParamBlock->errorParams.inBuffer, sLastErrorString, lastStringLen ) != 0 ) //same chars?
            isDuplicate = false; //different  chars
            
        //is this error message the same as the last one we received?       
        if ( isDuplicate )
        {   //yes?  increment count and bail if it's not the first time we've seen this message (otherwise fall thourhg and write it to the log)
            sDupErrorStringCount++;
            return QTSS_NoErr;
        }
        else 
        {
            //we have a new error message, write a "previous line" message before writing the new log entry
            if ( sDupErrorStringCount >= 1 )
            {
            /***  clean this up - lots of duplicate code ***/
            
                //The error logger is the bottleneck for any and all messages printed by the server.
                //For debugging purposes, these messages can be printed to stdout as well.
                if (thePrefs->IsScreenLoggingEnabled())
                    qtss_printf("--last message repeated %d times\n", sDupErrorStringCount);
            
                CheckErrorLogState();
                
                if (sErrorLog == NULL)
                    return QTSS_NoErr;
                    
                //timestamp the error
                char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
                Bool16 result = QTSSRollingLog::FormatDate(theDateBuffer, false);
                //for now, just ignore the error.
                if (!result)
                    theDateBuffer[0] = '\0';
        
                char tempBuffer[kMaxLogStringLen];
                qtss_snprintf(tempBuffer,sizeof(tempBuffer), "%s: --last message repeated %d times\n", theDateBuffer, sDupErrorStringCount);
                
                sErrorLog->WriteToLog(tempBuffer, kAllowLogToRoll);
    
                sDupErrorStringCount = 0;
            }
            ::strncpy(sLastErrorString, inParamBlock->errorParams.inBuffer, sizeof(sLastErrorString));
            sLastErrorString[sizeof(sLastErrorString)-1] = '\0';
        
        }

        //The error logger is the bottleneck for any and all messages printed by the server.
        //For debugging purposes, these messages can be printed to stdout as well.
        if (thePrefs->IsScreenLoggingEnabled())
            qtss_printf("%s %s\n", sErrorLevel[verbLvl], inParamBlock->errorParams.inBuffer);
        
        CheckErrorLogState();
        
        if (sErrorLog == NULL)
            return QTSS_NoErr;
            
        //timestamp the error
        char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
        Bool16 result = QTSSRollingLog::FormatDate(theDateBuffer, false);
        //for now, just ignore the error.
        if (!result)
            theDateBuffer[0] = '\0';

        char tempBuffer[kMaxLogStringLen];
        qtss_snprintf(tempBuffer,sizeof(tempBuffer), "%s: %s %s\n", theDateBuffer, sErrorLevel[verbLvl], inParamBlock->errorParams.inBuffer);
        tempBuffer[sizeof(tempBuffer)-2] = '\n'; //make sure the entry has a line feed before the \0 terminator
        tempBuffer[sizeof(tempBuffer)-1] = '\0'; //make sure it is 0 terminated.
        
        sErrorLog->WriteToLog(tempBuffer, kAllowLogToRoll);
    }
    return QTSS_NoErr;
}
QTSS_Error  RTPSession::Play(RTSPRequestInterface* request, QTSS_PlayFlags inFlags)
{
    //first setup the play associated session interface variables
    Assert(request != NULL);
    if (fModule == NULL)
        return QTSS_RequestFailed;//Can't play if there are no associated streams
    
    //what time is this play being issued at?
	fLastBitRateUpdateTime = fNextSendPacketsTime = fPlayTime = OS::Milliseconds();
    if (fIsFirstPlay)
		fFirstPlayTime = fPlayTime;
    fAdjustedPlayTime = fPlayTime - ((SInt64)(request->GetStartTime() * 1000));

    //for RTCP SRs, we also need to store the play time in NTP
    fNTPPlayTime = OS::TimeMilli_To_1900Fixed64Secs(fPlayTime);
    
    //we are definitely playing now, so schedule the object!
    fState = qtssPlayingState;
    fIsFirstPlay = false;
    fPlayFlags = inFlags;
    QTSServerInterface::GetServer()-> AlterRTPPlayingSessions(1);
    
    UInt32 theWindowSize;
    UInt32 bitRate = this->GetMovieAvgBitrate();
	if ((bitRate == 0) || (bitRate > QTSServerInterface::GetServer()->GetPrefs()->GetWindowSizeMaxThreshold() * 1024))
        theWindowSize = 1024 * QTSServerInterface::GetServer()->GetPrefs()->GetLargeWindowSizeInK();
	else if (bitRate > QTSServerInterface::GetServer()->GetPrefs()->GetWindowSizeThreshold() * 1024)
		theWindowSize = 1024 * QTSServerInterface::GetServer()->GetPrefs()->GetMediumWindowSizeInK();		
    else
        theWindowSize = 1024 * QTSServerInterface::GetServer()->GetPrefs()->GetSmallWindowSizeInK();

//  qtss_printf("bitrate = %d, window size = %d\n", bitRate, theWindowSize);
    this->GetBandwidthTracker()->SetWindowSize(theWindowSize);
	this->GetOverbufferWindow()->ResetOverBufferWindow();

    //
    // Go through all the streams, setting their thinning params
    RTPStream** theStream = NULL;
    UInt32 theLen = 0;
    
    for (int x = 0; this->GetValuePtr(qtssCliSesStreamObjects, x, (void**)&theStream, &theLen) == QTSS_NoErr; x++)
    {
        Assert(theStream != NULL);
        Assert(theLen == sizeof(RTPStream*));
        if (*theStream != NULL)
        {
            (*theStream)->SetThinningParams();
 			(*theStream)->ResetThinningDelayParams();
            //
            // If we are using reliable UDP, then make sure to clear all the packets
            // from the previous play spurt out of the resender
            (*theStream)->GetResender()->ClearOutstandingPackets();
        }
    }

//  qtss_printf("movie bitrate = %d, window size = %d\n", this->GetMovieAvgBitrate(), theWindowSize);
    Assert(this->GetBandwidthTracker()->BytesInList() == 0);
    
    // Set the size of the RTSPSession's send buffer to an appropriate max size
    // based on the bitrate of the movie. This has 2 benefits:
    // 1) Each socket normally defaults to 32 K. A smaller buffer prevents the
    // system from getting buffer starved if lots of clients get flow-controlled
    //
    // 2) We may need to scale up buffer sizes for high-bandwidth movies in order
    // to maximize thruput, and we may need to scale down buffer sizes for low-bandwidth
    // movies to prevent us from buffering lots of data that the client can't use
    
    // If we don't know any better, assume maximum buffer size.
    QTSServerPrefs* thePrefs = QTSServerInterface::GetServer()->GetPrefs();
    UInt32 theBufferSize = thePrefs->GetMaxTCPBufferSizeInBytes();
    
#if RTPSESSION_DEBUGGING
    qtss_printf("RTPSession GetMovieAvgBitrate %li\n",(SInt32)this->GetMovieAvgBitrate() );
#endif

    if (this->GetMovieAvgBitrate() > 0)
    {
        // We have a bit rate... use it.
        Float32 realBufferSize = (Float32)this->GetMovieAvgBitrate() * thePrefs->GetTCPSecondsToBuffer();
        theBufferSize = (UInt32)realBufferSize;
        theBufferSize >>= 3; // Divide by 8 to convert from bits to bytes
        
        // Round down to the next lowest power of 2.
        theBufferSize = this->PowerOf2Floor(theBufferSize);
        
        // This is how much data we should buffer based on the scaling factor... if it is
        // lower than the min, raise to min
        if (theBufferSize < thePrefs->GetMinTCPBufferSizeInBytes())
            theBufferSize = thePrefs->GetMinTCPBufferSizeInBytes();
            
        // Same deal for max buffer size
        if (theBufferSize > thePrefs->GetMaxTCPBufferSizeInBytes())
            theBufferSize = thePrefs->GetMaxTCPBufferSizeInBytes();
    }