463 lines
23 KiB
C++
463 lines
23 KiB
C++
/*
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
|
* file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
*
|
|
*/
|
|
/*
|
|
File: RTPSessionInterface.h
|
|
|
|
Contains: Implementation of object defined in .h
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
#include "RTPSessionInterface.h"
|
|
#include "QTSServerInterface.h"
|
|
#include "RTSPRequestInterface.h"
|
|
#include "QTSS.h"
|
|
#include "OS.h"
|
|
#include "RTPStream.h"
|
|
#include "md5.h"
|
|
#include "md5digest.h"
|
|
#include "base64.h"
|
|
|
|
unsigned int RTPSessionInterface::sRTPSessionIDCounter = 0;
|
|
|
|
|
|
QTSSAttrInfoDict::AttrInfo RTPSessionInterface::sAttributes[] =
|
|
{ /*fields: fAttrName, fFuncPtr, fAttrDataType, fAttrPermission */
|
|
/* 0 */ { "qtssCliSesStreamObjects", NULL, qtssAttrDataTypeQTSS_Object, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 1 */ { "qtssCliSesCreateTimeInMsec", NULL, qtssAttrDataTypeTimeVal, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 2 */ { "qtssCliSesFirstPlayTimeInMsec", NULL, qtssAttrDataTypeTimeVal, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 3 */ { "qtssCliSesPlayTimeInMsec", NULL, qtssAttrDataTypeTimeVal, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 4 */ { "qtssCliSesAdjustedPlayTimeInMsec", NULL, qtssAttrDataTypeTimeVal, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 5 */ { "qtssCliSesRTPBytesSent", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 6 */ { "qtssCliSesRTPPacketsSent", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 7 */ { "qtssCliSesState", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 8 */ { "qtssCliSesPresentationURL", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 9 */ { "qtssCliSesFirstUserAgent", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 10 */ { "qtssCliStrMovieDurationInSecs", NULL, qtssAttrDataTypeFloat64, qtssAttrModeRead | qtssAttrModePreempSafe | qtssAttrModeWrite },
|
|
/* 11 */ { "qtssCliStrMovieSizeInBytes", NULL, qtssAttrDataTypeUInt64, qtssAttrModeRead | qtssAttrModePreempSafe | qtssAttrModeWrite },
|
|
/* 12 */ { "qtssCliSesMovieAverageBitRate", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe | qtssAttrModeWrite },
|
|
/* 13 */ { "qtssCliSesLastRTSPSession", NULL, qtssAttrDataTypeQTSS_Object, qtssAttrModeRead | qtssAttrModePreempSafe } ,
|
|
/* 14 */ { "qtssCliSesFullURL", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe } ,
|
|
/* 15 */ { "qtssCliSesHostName", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
|
|
/* 16 */ { "qtssCliRTSPSessRemoteAddrStr", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 17 */ { "qtssCliRTSPSessLocalDNS", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 18 */ { "qtssCliRTSPSessLocalAddrStr", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 19 */ { "qtssCliRTSPSesUserName", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 20 */ { "qtssCliRTSPSesUserPassword", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 21 */ { "qtssCliRTSPSesURLRealm", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 22 */ { "qtssCliRTSPReqRealStatusCode", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 23 */ { "qtssCliTeardownReason", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe | qtssAttrModeWrite },
|
|
/* 24 */ { "qtssCliSesReqQueryString", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 25 */ { "qtssCliRTSPReqRespMsg", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
|
|
/* 26 */ { "qtssCliSesCurrentBitRate", CurrentBitRate, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 27 */ { "qtssCliSesPacketLossPercent", PacketLossPercent, qtssAttrDataTypeFloat32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 28 */ { "qtssCliSesTimeConnectedinMsec", TimeConnected, qtssAttrDataTypeSInt64, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 29 */ { "qtssCliSesCounterID", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 30 */ { "qtssCliSesRTSPSessionID", NULL, qtssAttrDataTypeCharArray, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 31 */ { "qtssCliSesFramesSkipped", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },
|
|
/* 32 */ { "qtssCliSesTimeoutMsec", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },
|
|
/* 33 */ { "qtssCliSesOverBufferEnabled", NULL, qtssAttrDataTypeBool16, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },
|
|
/* 34 */ { "qtssCliSesRTCPPacketsRecv", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 35 */ { "qtssCliSesRTCPBytesRecv", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 36 */ { "qtssCliSesStartedThinning", NULL, qtssAttrDataTypeBool16, qtssAttrModeRead | qtssAttrModeWrite | qtssAttrModePreempSafe },
|
|
/* 37 */ { "qtssCliSes3GPPObject", NULL, qtssAttrDataTypeQTSS_Object, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 38 */ { "qtssCliSessLastRTSPBandwidth", NULL, qtssAttrDataTypeUInt32, qtssAttrModeRead | qtssAttrModePreempSafe },
|
|
/* 39 */ { "qtssCliSessIs3GPPSession", NULL, qtssAttrDataTypeBool16, qtssAttrModeRead | qtssAttrModePreempSafe }
|
|
|
|
|
|
};
|
|
|
|
void RTPSessionInterface::Initialize()
|
|
{
|
|
for (UInt32 x = 0; x < qtssCliSesNumParams; x++)
|
|
QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kClientSessionDictIndex)->
|
|
SetAttribute(x, sAttributes[x].fAttrName, sAttributes[x].fFuncPtr,
|
|
sAttributes[x].fAttrDataType, sAttributes[x].fAttrPermission);
|
|
}
|
|
|
|
RTPSessionInterface::RTPSessionInterface()
|
|
: QTSSDictionary(QTSSDictionaryMap::GetMap(QTSSDictionaryMap::kClientSessionDictIndex), NULL),
|
|
Task(),
|
|
fLastQualityCheckTime(0),
|
|
fLastQualityCheckMediaTime(0),
|
|
fStartedThinning(false),
|
|
fIsFirstPlay(true),
|
|
fAllTracksInterleaved(true), // assume true until proven false!
|
|
fFirstPlayTime(0),
|
|
fPlayTime(0),
|
|
fAdjustedPlayTime(0),
|
|
fNTPPlayTime(0),
|
|
fNextSendPacketsTime(0),
|
|
fSessionQualityLevel(0),
|
|
fState(qtssPausedState),
|
|
fPlayFlags(0),
|
|
fLastBitRateBytes(0),
|
|
fLastBitRateUpdateTime(0),
|
|
fMovieCurrentBitRate(0),
|
|
fRTSPSession(NULL),
|
|
fLastRTSPReqRealStatusCode(200),
|
|
fTimeoutTask(NULL, QTSServerInterface::GetServer()->GetPrefs()->GetRTPTimeoutInSecs() * 1000),
|
|
fNumQualityLevels(0),
|
|
fBytesSent(0),
|
|
fPacketsSent(0),
|
|
fPacketLossPercent(0.0),
|
|
fTimeConnected(0),
|
|
fTotalRTCPPacketsRecv(0),
|
|
fTotalRTCPBytesRecv(0),
|
|
fMovieDuration(0),
|
|
fMovieSizeInBytes(0),
|
|
fMovieAverageBitRate(0),
|
|
fTeardownReason(0),
|
|
fUniqueID(0),
|
|
fTracker(QTSServerInterface::GetServer()->GetPrefs()->IsSlowStartEnabled()),
|
|
fOverbufferWindow(QTSServerInterface::GetServer()->GetPrefs()->GetSendIntervalInMsec(),kUInt32_Max, QTSServerInterface::GetServer()->GetPrefs()->GetMaxSendAheadTimeInSecs(),
|
|
QTSServerInterface::GetServer()->GetPrefs()->GetOverbufferRate()),
|
|
fAuthScheme(QTSServerInterface::GetServer()->GetPrefs()->GetAuthScheme()),
|
|
fAuthQop(RTSPSessionInterface::kNoQop),
|
|
fAuthNonceCount(0),
|
|
fFramesSkipped(0),
|
|
fRTPSession3GPP(QTSServerInterface::GetServer()->GetPrefs()->Get3GPPEnabled() ),
|
|
fRTPSession3GPPPtr(&fRTPSession3GPP),
|
|
fLastRTSPBandwidthHeaderBits(0),
|
|
fIs3GPPSession(false)
|
|
{
|
|
//don't actually setup the fTimeoutTask until the session has been bound!
|
|
//(we don't want to get timeouts before the session gets bound)
|
|
|
|
fTimeoutTask.SetTask(this);
|
|
fTimeout = QTSServerInterface::GetServer()->GetPrefs()->GetRTPTimeoutInSecs() * 1000;
|
|
fUniqueID = (UInt32)atomic_add(&sRTPSessionIDCounter, 1);
|
|
|
|
// fQualityUpdate is a counter the starting value is the unique ID so every session starts at a different position
|
|
fQualityUpdate = fUniqueID;
|
|
|
|
//mark the session create time
|
|
fSessionCreateTime = OS::Milliseconds();
|
|
|
|
// Setup all dictionary attribute values
|
|
|
|
// Make sure the dictionary knows about our preallocated memory for the RTP stream array
|
|
this->SetEmptyVal(qtssCliSesFirstUserAgent, &fUserAgentBuffer[0], kUserAgentBufSize);
|
|
this->SetEmptyVal(qtssCliSesStreamObjects, &fStreamBuffer[0], kStreamBufSize);
|
|
this->SetEmptyVal(qtssCliSesPresentationURL, &fPresentationURL[0], kPresentationURLSize);
|
|
this->SetEmptyVal(qtssCliSesFullURL, &fFullRequestURL[0], kRequestHostNameBufferSize);
|
|
this->SetEmptyVal(qtssCliSesHostName, &fRequestHostName[0], kFullRequestURLBufferSize);
|
|
|
|
this->SetVal(qtssCliSesCreateTimeInMsec, &fSessionCreateTime, sizeof(fSessionCreateTime));
|
|
this->SetVal(qtssCliSesFirstPlayTimeInMsec, &fFirstPlayTime, sizeof(fFirstPlayTime));
|
|
this->SetVal(qtssCliSesPlayTimeInMsec, &fPlayTime, sizeof(fPlayTime));
|
|
this->SetVal(qtssCliSesAdjustedPlayTimeInMsec, &fAdjustedPlayTime, sizeof(fAdjustedPlayTime));
|
|
this->SetVal(qtssCliSesRTPBytesSent, &fBytesSent, sizeof(fBytesSent));
|
|
this->SetVal(qtssCliSesRTPPacketsSent, &fPacketsSent, sizeof(fPacketsSent));
|
|
this->SetVal(qtssCliSesState, &fState, sizeof(fState));
|
|
this->SetVal(qtssCliSesMovieDurationInSecs, &fMovieDuration, sizeof(fMovieDuration));
|
|
this->SetVal(qtssCliSesMovieSizeInBytes, &fMovieSizeInBytes, sizeof(fMovieSizeInBytes));
|
|
this->SetVal(qtssCliSesLastRTSPSession, &fRTSPSession, sizeof(fRTSPSession));
|
|
this->SetVal(qtssCliSesMovieAverageBitRate, &fMovieAverageBitRate, sizeof(fMovieAverageBitRate));
|
|
this->SetEmptyVal(qtssCliRTSPSessRemoteAddrStr, &fRTSPSessRemoteAddrStr[0], kIPAddrStrBufSize );
|
|
this->SetEmptyVal(qtssCliRTSPSessLocalDNS, &fRTSPSessLocalDNS[0], kLocalDNSBufSize);
|
|
this->SetEmptyVal(qtssCliRTSPSessLocalAddrStr, &fRTSPSessLocalAddrStr[0], kIPAddrStrBufSize);
|
|
|
|
this->SetEmptyVal(qtssCliRTSPSesUserName, &fUserNameBuf[0],RTSPSessionInterface::kMaxUserNameLen);
|
|
this->SetEmptyVal(qtssCliRTSPSesUserPassword, &fUserPasswordBuf[0], RTSPSessionInterface::kMaxUserPasswordLen);
|
|
this->SetEmptyVal(qtssCliRTSPSesURLRealm, &fUserRealmBuf[0], RTSPSessionInterface::kMaxUserRealmLen);
|
|
|
|
this->SetVal(qtssCliRTSPReqRealStatusCode, &fLastRTSPReqRealStatusCode, sizeof(fLastRTSPReqRealStatusCode));
|
|
|
|
this->SetVal(qtssCliTeardownReason, &fTeardownReason, sizeof(fTeardownReason));
|
|
// this->SetVal(qtssCliSesCurrentBitRate, &fMovieCurrentBitRate, sizeof(fMovieCurrentBitRate));
|
|
this->SetVal(qtssCliSesCounterID, &fUniqueID, sizeof(fUniqueID));
|
|
this->SetEmptyVal(qtssCliSesRTSPSessionID, &fRTSPSessionIDBuf[0], QTSS_MAX_SESSION_ID_LENGTH + 4);
|
|
this->SetVal(qtssCliSesFramesSkipped, &fFramesSkipped, sizeof(fFramesSkipped));
|
|
this->SetVal(qtssCliSesRTCPPacketsRecv, &fTotalRTCPPacketsRecv, sizeof(fTotalRTCPPacketsRecv));
|
|
this->SetVal(qtssCliSesRTCPBytesRecv, &fTotalRTCPBytesRecv, sizeof(fTotalRTCPBytesRecv));
|
|
|
|
this->SetVal(qtssCliSesTimeoutMsec, &fTimeout, sizeof(fTimeout));
|
|
|
|
this->SetVal(qtssCliSesOverBufferEnabled, this->GetOverbufferWindow()->OverbufferingEnabledPtr(), sizeof(Bool16));
|
|
this->SetVal(qtssCliSesStartedThinning, &fStartedThinning, sizeof(Bool16));
|
|
this->SetVal(qtssCliSes3GPPObject, &fRTPSession3GPPPtr, sizeof(fRTPSession3GPPPtr));
|
|
|
|
this->SetVal(qtssCliSessLastRTSPBandwidth, &fLastRTSPBandwidthHeaderBits, sizeof(fLastRTSPBandwidthHeaderBits));
|
|
this->SetVal(qtssCliSessIs3GPPSession, &fIs3GPPSession, sizeof(fIs3GPPSession));
|
|
|
|
|
|
}
|
|
|
|
void RTPSessionInterface::SetValueComplete(UInt32 inAttrIndex, QTSSDictionaryMap* inMap,
|
|
UInt32 inValueIndex, void* inNewValue, UInt32 inNewValueLen)
|
|
{
|
|
if (inAttrIndex == qtssCliSesTimeoutMsec)
|
|
{
|
|
Assert(inNewValueLen == sizeof(UInt32));
|
|
UInt32 newTimeOut = *((UInt32 *) inNewValue);
|
|
fTimeoutTask.SetTimeout((SInt64) newTimeOut);
|
|
}
|
|
}
|
|
|
|
void RTPSessionInterface::UpdateRTSPSession(RTSPSessionInterface* inNewRTSPSession)
|
|
{
|
|
if (inNewRTSPSession != fRTSPSession)
|
|
{
|
|
// If there was an old session, let it know that we are done
|
|
if (fRTSPSession != NULL)
|
|
fRTSPSession->DecrementObjectHolderCount();
|
|
|
|
// Increment this count to prevent the RTSP session from being deleted
|
|
fRTSPSession = inNewRTSPSession;
|
|
fRTSPSession->IncrementObjectHolderCount();
|
|
}
|
|
}
|
|
|
|
char* RTPSessionInterface::GetSRBuffer(UInt32 inSRLen)
|
|
{
|
|
if (fSRBuffer.Len < inSRLen)
|
|
{
|
|
delete [] fSRBuffer.Ptr;
|
|
fSRBuffer.Set(NEW char[2*inSRLen], 2*inSRLen);
|
|
}
|
|
return fSRBuffer.Ptr;
|
|
}
|
|
|
|
QTSS_Error RTPSessionInterface::DoSessionSetupResponse(RTSPRequestInterface* inRequest)
|
|
{
|
|
// This function appends a session header to the SETUP response, and
|
|
// checks to see if it is a 304 Not Modified. If it is, it sends the entire
|
|
// response and returns an error
|
|
if ( QTSServerInterface::GetServer()->GetPrefs()->GetRTSPTimeoutInSecs() > 0 ) // adv the timeout
|
|
inRequest->AppendSessionHeaderWithTimeout( this->GetValue(qtssCliSesRTSPSessionID), QTSServerInterface::GetServer()->GetPrefs()->GetRTSPTimeoutAsString() );
|
|
else
|
|
inRequest->AppendSessionHeaderWithTimeout( this->GetValue(qtssCliSesRTSPSessionID), NULL ); // no timeout in resp.
|
|
|
|
if (inRequest->GetStatus() == qtssRedirectNotModified)
|
|
{
|
|
(void)inRequest->SendHeader();
|
|
return QTSS_RequestFailed;
|
|
}
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
void RTPSessionInterface::UpdateBitRateInternal(const SInt64& curTime)
|
|
{
|
|
if (fState == qtssPausedState)
|
|
{ fMovieCurrentBitRate = 0;
|
|
fLastBitRateUpdateTime = curTime;
|
|
fLastBitRateBytes = fBytesSent;
|
|
}
|
|
else
|
|
{
|
|
UInt32 bitsInInterval = (fBytesSent - fLastBitRateBytes) * 8;
|
|
SInt64 updateTime = (curTime - fLastBitRateUpdateTime) / 1000;
|
|
if (updateTime > 0) // leave Bit Rate the same if updateTime is 0 also don't divide by 0.
|
|
fMovieCurrentBitRate = (UInt32) (bitsInInterval / updateTime);
|
|
fTracker.UpdateAckTimeout(bitsInInterval, curTime - fLastBitRateUpdateTime);
|
|
fLastBitRateBytes = fBytesSent;
|
|
fLastBitRateUpdateTime = curTime;
|
|
}
|
|
//qtss_printf("fMovieCurrentBitRate=%"_U32BITARG_"\n",fMovieCurrentBitRate);
|
|
//qtss_printf("Cur bandwidth: %d. Cur ack timeout: %d.\n",fTracker.GetCurrentBandwidthInBps(), fTracker.RecommendedClientAckTimeout());
|
|
}
|
|
|
|
void* RTPSessionInterface::TimeConnected(QTSSDictionary* inSession, UInt32* outLen)
|
|
{
|
|
RTPSessionInterface* theSession = (RTPSessionInterface*)inSession;
|
|
theSession->fTimeConnected = (OS::Milliseconds() - theSession->GetSessionCreateTime());
|
|
|
|
// Return the result
|
|
*outLen = sizeof(theSession->fTimeConnected);
|
|
return &theSession->fTimeConnected;
|
|
}
|
|
|
|
void* RTPSessionInterface::CurrentBitRate(QTSSDictionary* inSession, UInt32* outLen)
|
|
{
|
|
RTPSessionInterface* theSession = (RTPSessionInterface*)inSession;
|
|
theSession->UpdateBitRateInternal(OS::Milliseconds());
|
|
|
|
// Return the result
|
|
*outLen = sizeof(theSession->fMovieCurrentBitRate);
|
|
return &theSession->fMovieCurrentBitRate;
|
|
}
|
|
|
|
|
|
void* RTPSessionInterface::PacketLossPercent(QTSSDictionary* inSession, UInt32* outLen)
|
|
{
|
|
RTPSessionInterface* theSession = (RTPSessionInterface*)inSession;
|
|
RTPStream* theStream = NULL;
|
|
UInt32 theLen = sizeof(theStream);
|
|
|
|
SInt64 packetsLost = 0;
|
|
SInt64 packetsSent = 0;
|
|
|
|
for (int x = 0; theSession->GetValue(qtssCliSesStreamObjects, x, (void*)&theStream, &theLen) == QTSS_NoErr; x++)
|
|
{
|
|
if (theStream != NULL )
|
|
{
|
|
UInt32 streamCurPacketsLost = 0;
|
|
theLen = sizeof(UInt32);
|
|
(void) theStream->GetValue(qtssRTPStrCurPacketsLostInRTCPInterval,0, &streamCurPacketsLost, &theLen);
|
|
//qtss_printf("stream = %d streamCurPacketsLost = %"_U32BITARG_" \n",x, streamCurPacketsLost);
|
|
|
|
UInt32 streamCurPackets = 0;
|
|
theLen = sizeof(UInt32);
|
|
(void) theStream->GetValue(qtssRTPStrPacketCountInRTCPInterval,0, &streamCurPackets, &theLen);
|
|
//qtss_printf("stream = %d streamCurPackets = %"_U32BITARG_" \n",x, streamCurPackets);
|
|
|
|
packetsSent += (SInt64) streamCurPackets;
|
|
packetsLost += (SInt64) streamCurPacketsLost;
|
|
//qtss_printf("stream calculated loss = %f \n",x, (Float32) streamCurPacketsLost / (Float32) streamCurPackets);
|
|
|
|
}
|
|
|
|
theStream = NULL;
|
|
theLen = sizeof(UInt32);
|
|
}
|
|
|
|
//Assert(packetsLost <= packetsSent);
|
|
if (packetsSent > 0)
|
|
{ if (packetsLost <= packetsSent)
|
|
theSession->fPacketLossPercent =(Float32) (( ((Float32) packetsLost / (Float32) packetsSent) * 100.0) );
|
|
else
|
|
theSession->fPacketLossPercent = 100.0;
|
|
}
|
|
else
|
|
theSession->fPacketLossPercent = 0.0;
|
|
//qtss_printf("Session loss percent packetsLost = %qd packetsSent= %qd theSession->fPacketLossPercent=%f\n",packetsLost,packetsSent,theSession->fPacketLossPercent);
|
|
// Return the result
|
|
*outLen = sizeof(theSession->fPacketLossPercent);
|
|
return &theSession->fPacketLossPercent;
|
|
}
|
|
|
|
void RTPSessionInterface::CreateDigestAuthenticationNonce() {
|
|
|
|
// Calculate nonce: MD5 of sessionid:timestamp
|
|
SInt64 curTime = OS::Milliseconds();
|
|
char* curTimeStr = NEW char[128];
|
|
qtss_sprintf(curTimeStr, "%"_64BITARG_"d", curTime);
|
|
|
|
// Delete old nonce before creating a new one
|
|
if(fAuthNonce.Ptr != NULL)
|
|
delete [] fAuthNonce.Ptr;
|
|
|
|
MD5_CTX ctxt;
|
|
unsigned char nonceStr[16];
|
|
unsigned char colon[] = ":";
|
|
MD5_Init(&ctxt);
|
|
StrPtrLen* sesID = this->GetValue(qtssCliSesRTSPSessionID);
|
|
MD5_Update(&ctxt, (unsigned char *)sesID->Ptr, sesID->Len);
|
|
MD5_Update(&ctxt, (unsigned char *)colon, 1);
|
|
MD5_Update(&ctxt, (unsigned char *)curTimeStr, ::strlen(curTimeStr));
|
|
MD5_Final(nonceStr, &ctxt);
|
|
HashToString(nonceStr, &fAuthNonce);
|
|
|
|
delete [] curTimeStr; // No longer required once nonce is created
|
|
|
|
// Set the nonce count value to zero
|
|
// as a new nonce has been created
|
|
fAuthNonceCount = 0;
|
|
|
|
}
|
|
|
|
void RTPSessionInterface::SetChallengeParams(QTSS_AuthScheme scheme, UInt32 qop, Bool16 newNonce, Bool16 createOpaque)
|
|
{
|
|
// Set challenge params
|
|
// Set authentication scheme
|
|
fAuthScheme = scheme;
|
|
|
|
if(fAuthScheme == qtssAuthDigest) {
|
|
// Set Quality of Protection
|
|
// auth-int (Authentication with integrity) not supported yet
|
|
fAuthQop = qop;
|
|
|
|
if(newNonce || (fAuthNonce.Ptr == NULL))
|
|
this->CreateDigestAuthenticationNonce();
|
|
|
|
if(createOpaque) {
|
|
// Generate a random UInt32 and convert it to a string
|
|
// The base64 encoded form of the string is made the opaque value
|
|
SInt64 theMicroseconds = OS::Microseconds();
|
|
::srand((unsigned int)theMicroseconds);
|
|
UInt32 randomNum = ::rand();
|
|
char* randomNumStr = NEW char[128];
|
|
qtss_sprintf(randomNumStr, "%"_U32BITARG_"", randomNum);
|
|
int len = ::strlen(randomNumStr);
|
|
fAuthOpaque.Len = Base64encode_len(len);
|
|
char *opaqueStr = NEW char[fAuthOpaque.Len];
|
|
(void) Base64encode(opaqueStr, randomNumStr,len);
|
|
delete [] randomNumStr; // Don't need this anymore
|
|
if(fAuthOpaque.Ptr != NULL) // Delete existing pointer before assigning new
|
|
delete [] fAuthOpaque.Ptr; // one
|
|
fAuthOpaque.Ptr = opaqueStr;
|
|
}
|
|
else {
|
|
if(fAuthOpaque.Ptr != NULL)
|
|
delete [] fAuthOpaque.Ptr;
|
|
fAuthOpaque.Len = 0;
|
|
}
|
|
// Increase the Nonce Count by one
|
|
// This number is a count of the next request the server
|
|
// expects with this nonce. (Implies that the server
|
|
// has already received nonce count - 1 requests that
|
|
// sent authorization with this nonce
|
|
fAuthNonceCount ++;
|
|
}
|
|
}
|
|
|
|
void RTPSessionInterface::UpdateDigestAuthChallengeParams(Bool16 newNonce, Bool16 createOpaque, UInt32 qop) {
|
|
if(newNonce || (fAuthNonce.Ptr == NULL))
|
|
this->CreateDigestAuthenticationNonce();
|
|
|
|
|
|
if(createOpaque) {
|
|
// Generate a random UInt32 and convert it to a string
|
|
// The base64 encoded form of the string is made the opaque value
|
|
SInt64 theMicroseconds = OS::Microseconds();
|
|
::srand((unsigned int)theMicroseconds);
|
|
UInt32 randomNum = ::rand();
|
|
char* randomNumStr = NEW char[128];
|
|
qtss_sprintf(randomNumStr, "%"_U32BITARG_"", randomNum);
|
|
int len = ::strlen(randomNumStr);
|
|
fAuthOpaque.Len = Base64encode_len(len);
|
|
char *opaqueStr = NEW char[fAuthOpaque.Len];
|
|
(void) Base64encode(opaqueStr, randomNumStr,len);
|
|
delete [] randomNumStr; // Don't need this anymore
|
|
if(fAuthOpaque.Ptr != NULL) // Delete existing pointer before assigning new
|
|
delete [] fAuthOpaque.Ptr; // one
|
|
fAuthOpaque.Ptr = opaqueStr;
|
|
fAuthOpaque.Len = ::strlen(opaqueStr);
|
|
}
|
|
else {
|
|
if(fAuthOpaque.Ptr != NULL)
|
|
delete [] fAuthOpaque.Ptr;
|
|
fAuthOpaque.Len = 0;
|
|
}
|
|
fAuthNonceCount ++;
|
|
|
|
fAuthQop = qop;
|
|
}
|