Example #1
0
Bool16 StillFlushing(QTSS_Filter_Params* inParams,Bool16 flushing)
{   

    QTSS_Error err = QTSS_NoErr;
    if (flushing) 
    {   
        err = QTSS_Flush(inParams->inRTSPRequest);
        //qtss_printf("Flushing session=%"_U32BITARG_" QTSS_Flush err =%"_S32BITARG_"\n",sSessID,err); 
    }
    if (err == QTSS_WouldBlock) // more to flush later
    {   
        sFlushing = true;
        (void) QTSS_SetValue(inParams->inRTSPRequest, sFlushingID, 0, (void*)&sFlushing, sFlushingLen);
        err = QTSS_RequestEvent(inParams->inRTSPRequest, QTSS_WriteableEvent);
        KeepSession(inParams->inRTSPRequest,true);
        //qtss_printf("Flushing session=%"_U32BITARG_" QTSS_RequestEvent err =%"_S32BITARG_"\n",sSessID,err);
    }
    else 
    {
        sFlushing = false;
        (void) QTSS_SetValue(inParams->inRTSPRequest, sFlushingID, 0, (void*)&sFlushing, sFlushingLen);
        KeepSession(inParams->inRTSPRequest,false);
    
        if (flushing) // we were flushing so reset the LastRequestTime
        {   
            sLastRequestTime = QTSS_Milliseconds();
            //qtss_printf("Done Flushing session=%"_U32BITARG_"\n",sSessID);
            return true;
        }
    }
    
    return sFlushing;
}
Example #2
0
SInt64 ProxyTask::Run()
{
    const UInt32 kMaxRTCPPacketSize = 2048;
    char thePacketBuffer[kMaxRTCPPacketSize];
    QTSS_PacketStruct thePacketStruct;
    thePacketStruct.packetTransmitTime = QTSS_Milliseconds();
    thePacketStruct.packetData = thePacketBuffer;

    (void)this->GetEvents();    

    OSMutexLocker locker(sSocketPool->GetMutex());
    for (OSQueueIter iter(sSocketPool->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++)
        {
            QTSS_WriteFlags theFlags = qtssWriteFlagsNoFlags;
            
            UDPSocket* theSocket = NULL;
            if (x == 0)
            {
                theFlags = qtssWriteFlagsIsRTP;
                theSocket = thePair->GetSocketA();
            }
            else
            {
                theFlags = qtssWriteFlagsIsRTCP;
                theSocket = thePair->GetSocketB();
            }
            
            Assert(theSocket->GetDemuxer() != NULL);
            OSMutexLocker locker(theSocket->GetDemuxer()->GetMutex());
            
            //get all the outstanding packets for this socket
            while (true)
            {
                UInt32 thePacketLen = 0;
                theSocket->RecvFrom(&theRemoteAddr, &theRemotePort, thePacketStruct.packetData, 
                                kMaxRTCPPacketSize, &thePacketLen);
                if (thePacketLen == 0)
                    break;//no more packets on this socket!
                    
                ProxyDemuxerTask* theDemuxerTask = (ProxyDemuxerTask*)theSocket->GetDemuxer()->GetTask(theRemoteAddr, 0);
                if (theDemuxerTask != NULL)
                {
                    QTSS_RTPStreamObject theStream = theDemuxerTask->GetStream();
                    (void)QTSS_Write(theStream, &thePacketStruct, thePacketLen, NULL, theFlags);
                }
            }
        }
    }
    return kProxyTaskPollIntervalMsec;
}
Example #3
0
inline Bool16 InWaitInterval(QTSS_Filter_Params* inParams)
{
    QTSS_TimeVal nextExecuteTime = sLastRequestTime + sRequestTimeIntervalMilli;
    QTSS_TimeVal currentTime = QTSS_Milliseconds();
    SInt32 waitTime = 0;
    if (currentTime < nextExecuteTime)
    {   
        waitTime = (SInt32) (nextExecuteTime - currentTime) + 1;
        //qtss_printf("(currentTime < nextExecuteTime) sSessID = %"_U32BITARG_" waitTime =%"_S32BITARG_" currentTime = %qd nextExecute = %qd interval=%"_U32BITARG_"\n",sSessID, waitTime, currentTime, nextExecuteTime,sRequestTimeIntervalMilli);
        (void)QTSS_SetIdleTimer(waitTime);
        KeepSession(inParams->inRTSPRequest,true);
        
        //qtss_printf("-- call me again after %"_S32BITARG_" millisecs session=%"_U32BITARG_" \n",waitTime,sSessID);
        return true;
    }
    sLastRequestTime = QTSS_Milliseconds();
    //qtss_printf("handle sessID=%"_U32BITARG_" time=%qd \n",sSessID,currentTime);
    return false;
}
void QTSSvrControlThread::HistoryEntry()
{
    //compute how often to run this thread.
    QTSSModuleUtils::GetAttribute(sPrefs, "history_update_interval", qtssAttrDataTypeUInt32,
                                &sHistoryIntervalInSecs, &sDefaultHistoryIntervalInSecs, sizeof(sHistoryIntervalInSecs));
    UInt32 theSampleInterval = (sHistoryIntervalInSecs * 1000) / kNumSamplesPerEntry;
    UInt32 theEntryInterval = sHistoryIntervalInSecs * 1000;
    
    //use local time to figure out when we need move onto a new entry. This
    //will eliminate the possibility that we drift off time.
    
    SInt64 theStartTime = QTSS_Milliseconds();
    Assert(theStartTime > 0);
    
    while (!fDone)
    {
        //sleep for the kHistoryUpdateInterval
        //kHistoryUpdateInterval is in minutes. Convert to msec.
        thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, theSampleInterval);
        
        //if server is doing a graceful shutdown, this thread is used to periodically
        //poll, checking if all connections are complete
        CheckShutdown();
        
        //every time we wake up, first thing we want to do is sample the
        //current state of the server for the history
        AddHistorySample();
    
        SInt64 theCurrentTime = QTSS_Milliseconds();
        Assert(theCurrentTime > 0);

        if ((theCurrentTime - theStartTime) > theEntryInterval)
        {
            UpdateHistoryArray();
            theStartTime += theEntryInterval;
        }
    }
}
QTSS_Error LogRequest(QTSS_ClientSessionObject inClientSession,
	QTSS_RTSPSessionObject inRTSPSession, QTSS_CliSesClosingReason *inCloseReasonPtr)
{
	static StrPtrLen sUnknownStr(sVoidField);
	static StrPtrLen sTCPStr("TCP");
	static StrPtrLen sUDPStr("UDP");

	//Fetch the URL, user agent, movielength & movie bytes to log out of the RTP session
	enum {
		eTempLogItemSize = 256, // must be same or larger than others
		eURLSize = 256,
		eUserAgentSize = 256,
		ePlayerIDSize = 32,
		ePlayerVersionSize = 32,
		ePlayerLangSize = 32,
		ePlayerOSSize = 32,
		ePlayerOSVersSize = 32,
		ePlayerCPUSize = 32
	};

	char tempLogItemBuf[eTempLogItemSize] = { 0 };
	StrPtrLen tempLogStr(tempLogItemBuf, eTempLogItemSize - 1);

	//
	// Check to see if this session is closing because authorization failed. If that's
	// the case, we've logged that already, let's not log it twice

	UInt32 theLen = 0;
	UInt32* authorizationFailed = NULL;
	(void)QTSS_GetValuePtr(inClientSession, sLoggedAuthorizationAttrID, 0, (void**)&authorizationFailed, &theLen);
	if ((authorizationFailed != NULL) && (*authorizationFailed > 0))
		return QTSS_NoErr;

	///inClientSession should never be NULL
	//inRTSPRequest may be NULL if this is a timeout

	OSMutexLocker locker(sLogMutex);
	CheckAccessLogState(false);
	if (sAccessLog == NULL)
		return QTSS_NoErr;

	//if logging is on, then log the request... first construct a timestamp
	char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
	bool result = QTSSRollingLog::FormatDate(theDateBuffer, sLogTimeInGMT);


	//for now, just ignore the error.
	if (!result)
		theDateBuffer[0] = '\0';

	theLen = sizeof(QTSS_RTSPSessionObject);
	QTSS_RTSPSessionObject theRTSPSession = inRTSPSession;
	if (theRTSPSession == NULL)
		(void)QTSS_GetValue(inClientSession, qtssCliSesLastRTSPSession, 0, (void*)&theRTSPSession, &theLen);

	// Get lots of neat info to log from the various dictionaries

	// Each attribute must be copied out to ensure that it is NULL terminated.
	// To ensure NULL termination, just memset the buffers to 0, and make sure that
	// the last byte of each array is untouched.

	Float32* packetLossPercent = NULL;
	Float64* movieDuration = NULL;
	UInt64* movieSizeInBytes = NULL;
	UInt32* movieAverageBitRatePtr = 0;
	UInt32 clientPacketsReceived = 0;
	UInt32 clientPacketsLost = 0;
	StrPtrLen* theTransportType = &sUnknownStr;
	SInt64* theCreateTime = NULL;
	SInt64* thePlayTime = NULL;

	UInt32 startPlayTimeInSecs = 0;

	char localIPAddrBuf[20] = { 0 };
	StrPtrLen localIPAddr(localIPAddrBuf, 19);

	char localDNSBuf[70] = { 0 };
	StrPtrLen localDNS(localDNSBuf, 69);

	char remoteDNSBuf[70] = { 0 };
	StrPtrLen remoteDNS(remoteDNSBuf, 69);

	char remoteAddrBuf[20] = { 0 };
	StrPtrLen remoteAddr(remoteAddrBuf, 19);

	char playerIDBuf[ePlayerIDSize] = { 0 };
	StrPtrLen playerID(playerIDBuf, ePlayerIDSize - 1);

	// First, get networking info from the RTSP session
	(void)QTSS_GetValue(inClientSession, qtssCliRTSPSessLocalAddrStr, 0, localIPAddr.Ptr, &localIPAddr.Len);
	(void)QTSS_GetValue(inClientSession, qtssCliRTSPSessLocalDNS, 0, localDNS.Ptr, &localDNS.Len);
	(void)QTSS_GetValue(inClientSession, qtssCliSesHostName, 0, remoteDNS.Ptr, &remoteDNS.Len);
	(void)QTSS_GetValue(inClientSession, qtssCliRTSPSessRemoteAddrStr, 0, remoteAddr.Ptr, &remoteAddr.Len);
	(void)QTSS_GetValue(inClientSession, qtssCliRTSPSessRemoteAddrStr, 0, playerID.Ptr, &playerID.Len);

	UInt32* rtpBytesSent = NULL;
	UInt32* rtcpBytesRecv = NULL;
	UInt32* rtpPacketsSent = NULL;

	// Second, get networking info from the Client's session.
	// (Including the stats for incoming RTCP packets.)
	char urlBuf[eURLSize] = { 0 };
	StrPtrLen url(urlBuf, eURLSize - 1);
	(void)QTSS_GetValue(inClientSession, qtssCliSesPresentationURL, 0, url.Ptr, &url.Len);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesPacketLossPercent, 0, (void**)&packetLossPercent, &theLen);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesMovieDurationInSecs, 0, (void**)&movieDuration, &theLen);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesMovieSizeInBytes, 0, (void**)&movieSizeInBytes, &theLen);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesMovieAverageBitRate, 0, (void**)&movieAverageBitRatePtr, &theLen);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesCreateTimeInMsec, 0, (void**)&theCreateTime, &theLen);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesFirstPlayTimeInMsec, 0, (void**)&thePlayTime, &theLen);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesRTPBytesSent, 0, (void**)&rtpBytesSent, &theLen);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesRTPPacketsSent, 0, (void**)&rtpPacketsSent, &theLen);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliSesRTCPBytesRecv, 0, (void**)&rtcpBytesRecv, &theLen);

	if (theCreateTime != NULL && thePlayTime != NULL)
		startPlayTimeInSecs = (UInt32)(((*theCreateTime - *thePlayTime) / 1000) + 0.5);


	// We need a value of 'c-bytes' to report as a log entry. This is supposed to be the total number
	// of bytes the client has received during the session. Unfortunately, the QT client does not give
	// us this number. We will use the following heuristic formula to estimate the number of bytes the
	// client has received during the session:
	//
	//     client-bytes-received = bytes-sent * (100.0 - percent-packet-lost) / 100.0
	//
	// The 'percent-packet-lost' value has been calculated internally by QTSS based on the RTCP packets
	// sent to the server from the client. If those values are accurate then the above formula will not 
	// be exactly correct but it will be nearly correct.

	UInt32 clientBytesRecv = (UInt32)((*rtpBytesSent * (100.0 - *packetLossPercent)) / 100.0);

	tempLogStr.Ptr[0] = 0; tempLogStr.Len = eUserAgentSize;
	(void)QTSS_GetValue(inClientSession, qtssCliSesFirstUserAgent, 0, tempLogStr.Ptr, &tempLogStr.Len);

	char userAgentBuf[eUserAgentSize] = { 0 };
	StrPtrLen userAgent(userAgentBuf, eUserAgentSize - 1);
	ReplaceSpaces(&tempLogStr, &userAgent, "%20");

	UserAgentParser userAgentParser(&userAgent);

	//  StrPtrLen* playerID = userAgentParser.GetUserID() ;
	StrPtrLen* playerVersion = userAgentParser.GetUserVersion();
	StrPtrLen* playerLang = userAgentParser.GetUserLanguage();
	StrPtrLen* playerOS = userAgentParser.GetrUserOS();
	StrPtrLen* playerOSVers = userAgentParser.GetUserOSVersion();
	StrPtrLen* playerCPU = userAgentParser.GetUserCPU();

	//  char playerIDBuf[ePlayerIDSize] = {};   
	char playerVersionBuf[ePlayerVersionSize] = { 0 };
	char playerLangBuf[ePlayerLangSize] = { 0 };
	char playerOSBuf[ePlayerOSSize] = { 0 };
	char playerOSVersBuf[ePlayerOSVersSize] = { 0 };
	char playerCPUBuf[ePlayerCPUSize] = { 0 };

	UInt32 size;
	//  (ePlayerIDSize < playerID->Len ) ? size = ePlayerIDSize -1 : size = playerID->Len;
	//  if (playerID->Ptr != NULL) memcpy (playerIDBuf, playerID->Ptr, size);

	(ePlayerVersionSize < playerVersion->Len) ? size = ePlayerVersionSize - 1 : size = playerVersion->Len;
	if (playerVersion->Ptr != NULL) memcpy(playerVersionBuf, playerVersion->Ptr, size);

	(ePlayerLangSize < playerLang->Len) ? size = ePlayerLangSize - 1 : size = playerLang->Len;
	if (playerLang->Ptr != NULL) memcpy(playerLangBuf, playerLang->Ptr, size);

	(ePlayerOSSize < playerOS->Len) ? size = ePlayerOSSize - 1 : size = playerOS->Len;
	if (playerOS->Ptr != NULL)  memcpy(playerOSBuf, playerOS->Ptr, size);

	(ePlayerOSVersSize < playerOSVers->Len) ? size = ePlayerOSVersSize - 1 : size = playerOSVers->Len;
	if (playerOSVers->Ptr != NULL) memcpy(playerOSVersBuf, playerOSVers->Ptr, size);

	(ePlayerCPUSize < playerCPU->Len) ? size = ePlayerCPUSize - 1 : size = playerCPU->Len;
	if (playerCPU->Ptr != NULL) memcpy(playerCPUBuf, playerCPU->Ptr, size);


	// clientPacketsReceived, clientPacketsLost, videoPayloadName and audioPayloadName
	// are all stored on a per-stream basis, so let's iterate through all the streams,
	// finding this information

	char videoPayloadNameBuf[32] = { 0 };
	StrPtrLen videoPayloadName(videoPayloadNameBuf, 31);

	char audioPayloadNameBuf[32] = { 0 };
	StrPtrLen audioPayloadName(audioPayloadNameBuf, 31);

	UInt32 qualityLevel = 0;
	UInt32 clientBufferTime = 0;
	UInt32 theStreamIndex = 0;
	bool* isTCPPtr = NULL;
	QTSS_RTPStreamObject theRTPStreamObject = NULL;

	for (UInt32 theStreamObjectLen = sizeof(theRTPStreamObject);
		QTSS_GetValue(inClientSession, qtssCliSesStreamObjects, theStreamIndex, (void*)&theRTPStreamObject, &theStreamObjectLen) == QTSS_NoErr;
		theStreamIndex++, theStreamObjectLen = sizeof(theRTPStreamObject))
	{

		UInt32* streamPacketsReceived = NULL;
		UInt32* streamPacketsLost = NULL;
		(void)QTSS_GetValuePtr(theRTPStreamObject, qtssRTPStrTotPacketsRecv, 0, (void**)&streamPacketsReceived, &theLen);
		(void)QTSS_GetValuePtr(theRTPStreamObject, qtssRTPStrTotalLostPackets, 0, (void**)&streamPacketsLost, &theLen);

		// Add up packets received and packets lost to come up with a session wide total
		if (streamPacketsReceived != NULL)
			clientPacketsReceived += *streamPacketsReceived;
		if (streamPacketsLost != NULL)
			clientPacketsLost += *streamPacketsLost;

		// Identify the video and audio codec types
		QTSS_RTPPayloadType* thePayloadType = NULL;
		(void)QTSS_GetValuePtr(theRTPStreamObject, qtssRTPStrPayloadType, 0, (void**)&thePayloadType, &theLen);
		if (thePayloadType != NULL)
		{
			if (*thePayloadType == qtssVideoPayloadType)
				(void)QTSS_GetValue(theRTPStreamObject, qtssRTPStrPayloadName, 0, videoPayloadName.Ptr, &videoPayloadName.Len);
			else if (*thePayloadType == qtssAudioPayloadType)
				(void)QTSS_GetValue(theRTPStreamObject, qtssRTPStrPayloadName, 0, audioPayloadName.Ptr, &audioPayloadName.Len);
		}

		// If any one of the streams is being delivered over UDP instead of TCP,
		// report in the log that the transport type for this session was UDP.
		if (isTCPPtr == NULL)
		{
			(void)QTSS_GetValuePtr(theRTPStreamObject, qtssRTPStrIsTCP, 0, (void**)&isTCPPtr, &theLen);
			if (isTCPPtr != NULL)
			{
				if (*isTCPPtr == false)
					theTransportType = &sUDPStr;
				else
					theTransportType = &sTCPStr;
			}
		}

		Float32* clientBufferTimePtr = NULL;
		(void)QTSS_GetValuePtr(theRTPStreamObject, qtssRTPStrBufferDelayInSecs, 0, (void**)&clientBufferTimePtr, &theLen);
		if ((clientBufferTimePtr != NULL) && (*clientBufferTimePtr != 0))
		{
			if (*clientBufferTimePtr > clientBufferTime)
				clientBufferTime = (UInt32)(*clientBufferTimePtr + .5); // round up to full seconds
		}

	}

	// Add the client buffer time to our client start latency (in whole seconds).
	startPlayTimeInSecs += clientBufferTime;

	if (*rtpPacketsSent == 0) // no packets sent
		qualityLevel = 0; // no quality
	else
	{
		if ((clientPacketsReceived == 0) && (clientPacketsLost == 0)) // no info from client 
			qualityLevel = 100; //so assume 100
		else
		{
			float qualityPercent = (float)clientPacketsReceived / (float)(clientPacketsReceived + clientPacketsLost);
			qualityPercent += (float).005; // round up
			qualityLevel = (UInt32)((float) 100.0 * qualityPercent); // average of sum of packet counts for all streams
		}
	}

	//we may not have an RTSP request. Assume that the status code is 504 timeout, if there is an RTSP
	//request, though, we can find out what the real status code of the response is
	static UInt32 sTimeoutCode = 504;
	UInt32* theStatusCode = &sTimeoutCode;
	theLen = sizeof(UInt32);
	(void)QTSS_GetValuePtr(inClientSession, qtssCliRTSPReqRealStatusCode, 0, (void **)&theStatusCode, &theLen);
	//  qtss_printf("qtssCliRTSPReqRealStatusCode = %"   _U32BITARG_   " \n", *theStatusCode);


	if (inCloseReasonPtr) do
	{
		if (*theStatusCode < 300) // it was a succesful RTSP request but...
		{
			if (*inCloseReasonPtr == qtssCliSesCloseTimeout) // there was a timeout
			{
				*theStatusCode = sTimeoutCode;
				//                  qtss_printf(" log timeout ");
				break;
			}

			if (*inCloseReasonPtr == qtssCliSesCloseClientTeardown) // there was a teardown
			{

				static QTSS_CliSesClosingReason sReason = qtssCliSesCloseClientTeardown;
				QTSS_CliSesClosingReason* theReasonPtr = &sReason;
				theLen = sizeof(QTSS_CliSesTeardownReason);
				(void)QTSS_GetValuePtr(inClientSession, qtssCliTeardownReason, 0, (void **)&theReasonPtr, &theLen);
				//              qtss_printf("qtssCliTeardownReason = %"   _U32BITARG_   " \n", *theReasonPtr);

				if (*theReasonPtr == qtssCliSesTearDownClientRequest) //  the client asked for a tear down
				{
					//                  qtss_printf(" client requests teardown  ");
					break;
				}

				if (*theReasonPtr == qtssCliSesTearDownUnsupportedMedia) //  An error occured while streaming the file.
				{
					*theStatusCode = 415;
					//                      qtss_printf(" log UnsupportedMedia ");
					break;
				}
				if (*theReasonPtr == qtssCliSesTearDownBroadcastEnded) //  a broadcaster stopped broadcasting
				{
					*theStatusCode = 452;
					//                      qtss_printf(" log broadcast removed ");
					break;
				}

				*theStatusCode = 500; // some unknown reason for cancelling the connection
			}

			//          qtss_printf("return status ");
						// just use the qtssCliRTSPReqRealStatusCode for the reason
		}

	} while (false);

	//  qtss_printf(" = %"   _U32BITARG_   " \n", *theStatusCode);


		// Find out what time it is
	SInt64 curTime = QTSS_Milliseconds();

	UInt32 numCurClients = 0;
	theLen = sizeof(numCurClients);
	(void)QTSS_GetValue(sServer, qtssRTPSvrCurConn, 0, &numCurClients, &theLen);

	/*
		IMPORTANT!!!!

		Some values such as cpu, #conns, need to be grabbed as the session starts, not when the teardown happened (I think)

	*/

#if TESTUNIXTIME
	char thetestDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes];
	TestUnixTime(QTSS_MilliSecsTo1970Secs(*theCreateTime), thetestDateBuffer);
	qtss_printf("%s\n", thetestDateBuffer);
#endif

	float zeroFloat = 0;
	UInt64 zeroUInt64 = 0;
	Float32 fcpuUtilized = 0;

	theLen = sizeof(fcpuUtilized);
	(void)QTSS_GetValue(sServer, qtssSvrCPULoadPercent, 0, &fcpuUtilized, &theLen);
	UInt32 cpuUtilized = (UInt32)fcpuUtilized;

	char lastUserName[eTempLogItemSize] = { 0 };
	StrPtrLen lastUserNameStr(lastUserName, eTempLogItemSize);

	char lastURLRealm[eTempLogItemSize] = { 0 };
	StrPtrLen lastURLRealmStr(lastURLRealm, eTempLogItemSize);

	//qtss_printf("logging of saved params are in dictionary \n");

	tempLogStr.Ptr[0] = 0; tempLogStr.Len = eTempLogItemSize;
	(void)QTSS_GetValue(inClientSession, qtssCliRTSPSesUserName, 0, tempLogStr.Ptr, &tempLogStr.Len);
	ReplaceSpaces(&tempLogStr, &lastUserNameStr, "%20");
	//qtss_printf("qtssRTSPSesLastUserName dictionary item = %s len = %" _S32BITARG_ "\n",lastUserNameStr.Ptr,lastUserNameStr.Len);

	tempLogStr.Ptr[0] = 0; tempLogStr.Len = eTempLogItemSize;
	(void)QTSS_GetValue(inClientSession, qtssCliRTSPSesURLRealm, 0, tempLogStr.Ptr, &tempLogStr.Len);
	ReplaceSpaces(&tempLogStr, &lastURLRealmStr, "%20");
	//qtss_printf("qtssRTSPSesLastURLRealm dictionary  item = %s len = %" _S32BITARG_ "\n",lastURLRealmStr.Ptr,lastURLRealmStr.Len);  

	char respMsgBuffer[1024] = { 0 };
	StrPtrLen theRespMsg;
	(void)QTSS_GetValuePtr(inClientSession, qtssCliRTSPReqRespMsg, 0, (void**)&theRespMsg.Ptr, &theRespMsg.Len);
	StrPtrLen respMsgEncoded(respMsgBuffer, 1024 - 1);
	SInt32 theErr = StringTranslator::EncodeURL(theRespMsg.Ptr, theRespMsg.Len, respMsgEncoded.Ptr, respMsgEncoded.Len);
	if (theErr <= 0)
		respMsgEncoded.Ptr[0] = '\0';
	else
	{
		respMsgEncoded.Len = theErr;
		respMsgEncoded.Ptr[respMsgEncoded.Len] = '\0';
	}

	//cs-uri-query
	char urlQryBuf[eURLSize] = { 0 };
	StrPtrLen urlQry(urlQryBuf, eURLSize - 1);
	(void)QTSS_GetValue(inClientSession, qtssCliSesReqQueryString, 0, urlQry.Ptr, &urlQry.Len);

	char tempLogBuffer[1024];
	char logBuffer[2048];
	// compatible fields (no respMsgEncoded field)
	::memset(logBuffer, 0, 2048);
	qtss_sprintf(tempLogBuffer, "%s ", (remoteAddr.Ptr[0] == '\0') ? sVoidField : remoteAddr.Ptr); //c-ip*
	::strcpy(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (theDateBuffer[0] == '\0') ? sVoidField : theDateBuffer);   //date* time*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (remoteDNS.Ptr[0] == '\0') ? sVoidField : remoteDNS.Ptr); //c-dns
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (url.Ptr[0] == '\0') ? sVoidField : url.Ptr);   //cs-uri-stem*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", startPlayTimeInSecs);  //c-starttime 
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", theCreateTime == NULL ? (UInt32)0 : (UInt32)(QTSS_MilliSecsTo1970Secs(curTime)
		- QTSS_MilliSecsTo1970Secs(*theCreateTime)));   //x-duration* 
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%" _S32BITARG_ " ", (UInt32)1);  //c-rate
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%" _S32BITARG_ " ", *theStatusCode);   //c-status*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (playerIDBuf[0] == '\0') ? sVoidField : playerIDBuf);   //c-playerid*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (playerVersionBuf[0] == '\0') ? sVoidField : playerVersionBuf); //c-playerversion
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (playerLangBuf[0] == '\0') ? sVoidField : playerLangBuf);   //c-playerlanguage*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (userAgent.Ptr[0] == '\0') ? sVoidField : userAgent.Ptr);   //cs(User-Agent) 
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (playerOSBuf[0] == '\0') ? sVoidField : playerOSBuf);   //c-os*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (playerOSVersBuf[0] == '\0') ? sVoidField : playerOSVersBuf);   //c-osversion
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (playerCPUBuf[0] == '\0') ? sVoidField : playerCPUBuf); //c-cpu*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%0.0f ", movieDuration == NULL ? zeroFloat : *movieDuration); //filelength in secs*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%" _64BITARG_ "d ", movieSizeInBytes == NULL ? zeroUInt64 : *movieSizeInBytes); //filesize in bytes*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", movieAverageBitRatePtr == NULL ? (UInt32)0 : *movieAverageBitRatePtr);    //avgbandwidth in bits per second
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", "RTP"); //protocol
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (theTransportType->Ptr[0] == '\0') ? sVoidField : theTransportType->Ptr);   //transport
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (audioPayloadName.Ptr[0] == '\0') ? sVoidField : audioPayloadName.Ptr); //audiocodec*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (videoPayloadName.Ptr[0] == '\0') ? sVoidField : videoPayloadName.Ptr); //videocodec*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", rtpBytesSent == NULL ? (UInt32)0 : *rtpBytesSent);    //sc-bytes*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", rtcpBytesRecv == NULL ? (UInt32)0 : *rtcpBytesRecv);    //cs-bytes*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", clientBytesRecv);  //c-bytes
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", rtpPacketsSent == NULL ? (UInt32)0 : *rtpPacketsSent);   //s-pkts-sent*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", clientPacketsReceived);    //c-pkts-recieved
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", clientPacketsLost);    //c-pkts-lost-client*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", (UInt32)1);  //c-buffercount 
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", clientBufferTime);     //c-totalbuffertime*
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", qualityLevel); //c-quality 
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (localIPAddr.Ptr[0] == '\0') ? sVoidField : localIPAddr.Ptr);   //s-ip 
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (localDNS.Ptr[0] == '\0') ? sVoidField : localDNS.Ptr); //s-dns
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", numCurClients);    //s-totalclients
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%"   _U32BITARG_   " ", cpuUtilized);  //s-cpu-util
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (urlQry.Ptr[0] == '\0') ? sVoidField : urlQry.Ptr); //cs-uri-query
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (lastUserName[0] == '\0') ? sVoidField : lastUserName); //c-username
	::strcat(logBuffer, tempLogBuffer);
	qtss_sprintf(tempLogBuffer, "%s ", (lastURLRealm[0] == '\0') ? sVoidField : lastURLRealm); //sc(Realm)
	::strcat(logBuffer, tempLogBuffer);

	::strcat(logBuffer, "\n");

	Assert(::strlen(logBuffer) < 2048);

	//finally, write the log message
	sAccessLog->WriteToLog(logBuffer, kAllowLogToRoll);

	return QTSS_NoErr;
}