353 lines
15 KiB
C++
353 lines
15 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@
|
|
*
|
|
*/
|
|
/*
|
|
Contains: API interface for objects to use to get access to attributes,
|
|
data items, whatever, specific to RTP sessions (see RTPSession.h
|
|
for more details on what that object is). This object
|
|
implements the RTP Session Dictionary.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
#ifndef _RTPSESSIONINTERFACE_H_
|
|
#define _RTPSESSIONINTERFACE_H_
|
|
|
|
#include "QTSSDictionary.h"
|
|
|
|
#include "RTCPSRPacket.h"
|
|
#include "RTSPSessionInterface.h"
|
|
#include "TimeoutTask.h"
|
|
#include "Task.h"
|
|
#include "RTPBandwidthTracker.h"
|
|
#include "RTPOverbufferWindow.h"
|
|
#include "QTSServerInterface.h"
|
|
#include "OSMutex.h"
|
|
#include "atomic.h"
|
|
#include "RTPSession3GPP.h"
|
|
|
|
class RTSPRequestInterface;
|
|
|
|
class RTPSessionInterface : public QTSSDictionary, public Task
|
|
{
|
|
public:
|
|
|
|
// Initializes dictionary resources
|
|
static void Initialize();
|
|
|
|
//
|
|
// CONSTRUCTOR / DESTRUCTOR
|
|
|
|
RTPSessionInterface();
|
|
virtual ~RTPSessionInterface()
|
|
{
|
|
if (GetQualityLevel() != 0)
|
|
QTSServerInterface::GetServer()->IncrementNumThinned(-1);
|
|
if (fRTSPSession != NULL)
|
|
fRTSPSession->DecrementObjectHolderCount();
|
|
delete [] fSRBuffer.Ptr;
|
|
delete [] fAuthNonce.Ptr;
|
|
delete [] fAuthOpaque.Ptr;
|
|
}
|
|
|
|
virtual void SetValueComplete(UInt32 inAttrIndex, QTSSDictionaryMap* inMap,
|
|
UInt32 inValueIndex, void* inNewValue, UInt32 inNewValueLen);
|
|
|
|
//Timeouts. This allows clients to refresh the timeout on this session
|
|
void RefreshTimeout() { fTimeoutTask.RefreshTimeout(); }
|
|
void RefreshRTSPTimeout() { if (fRTSPSession != NULL) fRTSPSession->RefreshTimeout(); }
|
|
void RefreshTimeouts() { RefreshTimeout(); RefreshRTSPTimeout();}
|
|
|
|
//
|
|
// ACCESSORS
|
|
|
|
Bool16 IsFirstPlay() { return fIsFirstPlay; }
|
|
SInt64 GetFirstPlayTime() { return fFirstPlayTime; }
|
|
//Time (msec) most recent play was issued
|
|
SInt64 GetPlayTime() { return fPlayTime; }
|
|
SInt64 GetNTPPlayTime() { return fNTPPlayTime; }
|
|
SInt64 GetSessionCreateTime() { return fSessionCreateTime; }
|
|
//Time (msec) most recent play, adjusted for start time of the movie
|
|
//ex: PlayTime() == 20,000. Client said start 10 sec into the movie,
|
|
//so AdjustedPlayTime() == 10,000
|
|
QTSS_PlayFlags GetPlayFlags() { return fPlayFlags; }
|
|
OSMutex* GetSessionMutex() { return &fSessionMutex; }
|
|
UInt32 GetPacketsSent() { return fPacketsSent; }
|
|
UInt32 GetBytesSent() { return fBytesSent; }
|
|
OSRef* GetRef() { return &fRTPMapElem; }
|
|
RTSPSessionInterface* GetRTSPSession() { return fRTSPSession; }
|
|
UInt32 GetMovieAvgBitrate(){ return fMovieAverageBitRate; }
|
|
QTSS_CliSesTeardownReason GetTeardownReason() { return fTeardownReason; }
|
|
QTSS_RTPSessionState GetSessionState() { return fState; }
|
|
void SetUniqueID(UInt32 theID) {fUniqueID = theID;}
|
|
UInt32 GetUniqueID() { return fUniqueID; }
|
|
RTPBandwidthTracker* GetBandwidthTracker() { return &fTracker; }
|
|
RTPOverbufferWindow* GetOverbufferWindow() { return &fOverbufferWindow; }
|
|
UInt32 GetFramesSkipped() { return fFramesSkipped; }
|
|
|
|
//
|
|
// MEMORY FOR RTCP PACKETS
|
|
|
|
//
|
|
// Class for easily building a standard RTCP SR
|
|
RTCPSRPacket* GetSRPacket() { return &fRTCPSRPacket; }
|
|
|
|
//
|
|
// Memory if you want to build your own
|
|
char* GetSRBuffer(UInt32 inSRLen);
|
|
|
|
//
|
|
// STATISTICS UPDATING
|
|
|
|
//The session tracks the total number of bytes sent during the session.
|
|
//Streams can update that value by calling this function
|
|
void UpdateBytesSent(UInt32 bytesSent) { fBytesSent += bytesSent; }
|
|
|
|
//The session tracks the total number of packets sent during the session.
|
|
//Streams can update that value by calling this function
|
|
void UpdatePacketsSent(UInt32 packetsSent) { fPacketsSent += packetsSent; }
|
|
|
|
void UpdateCurrentBitRate(const SInt64& curTime)
|
|
{ if (curTime > (fLastBitRateUpdateTime + 3000)) this->UpdateBitRateInternal(curTime); }
|
|
|
|
void SetAllTracksInterleaved(Bool16 newValue) { fAllTracksInterleaved = newValue; }
|
|
//
|
|
// RTSP RESPONSES
|
|
|
|
// 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
|
|
QTSS_Error DoSessionSetupResponse(RTSPRequestInterface* inRequest);
|
|
|
|
//
|
|
// RTSP SESSION
|
|
|
|
// This object has a current RTSP session. This may change over the
|
|
// life of the RTSPSession, so update it. It keeps an RTSP session in
|
|
// case interleaved data or commands need to be sent back to the client.
|
|
void UpdateRTSPSession(RTSPSessionInterface* inNewRTSPSession);
|
|
|
|
// let's RTSP Session pass along it's query string
|
|
void SetQueryString( StrPtrLen* queryString );
|
|
|
|
// SETTERS and ACCESSORS for auth information
|
|
// Authentication information that needs to be kept around
|
|
// for the duration of the session
|
|
QTSS_AuthScheme GetAuthScheme() { return fAuthScheme; }
|
|
StrPtrLen* GetAuthNonce() { return &fAuthNonce; }
|
|
UInt32 GetAuthQop() { return fAuthQop; }
|
|
UInt32 GetAuthNonceCount() { return fAuthNonceCount; }
|
|
StrPtrLen* GetAuthOpaque() { return &fAuthOpaque; }
|
|
void SetAuthScheme(QTSS_AuthScheme scheme) { fAuthScheme = scheme; }
|
|
// Use this if the auth scheme or the qop has to be changed from the defaults
|
|
// of scheme = Digest, and qop = auth
|
|
void SetChallengeParams(QTSS_AuthScheme scheme, UInt32 qop, Bool16 newNonce, Bool16 createOpaque);
|
|
// Use this otherwise...if newNonce == true, it will create a new nonce
|
|
// and reset nonce count. If newNonce == false but nonce was never created earlier
|
|
// a nonce will be created. If newNonce == false, and there is an existing nonce,
|
|
// the nounce count will be incremented.
|
|
void UpdateDigestAuthChallengeParams(Bool16 newNonce, Bool16 createOpaque, UInt32 qop);
|
|
|
|
Float32* GetPacketLossPercent() { UInt32 outLen;return (Float32*) this->PacketLossPercent(this, &outLen);}
|
|
|
|
SInt32 GetQualityLevel() { return fSessionQualityLevel; }
|
|
SInt32* GetQualityLevelPtr() { return &fSessionQualityLevel; }
|
|
void SetQualityLevel(SInt32 level) { if (fSessionQualityLevel == 0 && level != 0)
|
|
QTSServerInterface::GetServer()->IncrementNumThinned(1);
|
|
else if (fSessionQualityLevel != 0 && level == 0)
|
|
QTSServerInterface::GetServer()->IncrementNumThinned(-1);
|
|
fSessionQualityLevel = level;
|
|
}
|
|
SInt64 fLastQualityCheckTime;
|
|
SInt64 fLastQualityCheckMediaTime;
|
|
Bool16 fStartedThinning;
|
|
|
|
// Used by RTPStream to increment the RTCP packet and byte counts.
|
|
void IncrTotalRTCPPacketsRecv() { fTotalRTCPPacketsRecv++; }
|
|
UInt32 GetTotalRTCPPacketsRecv() { return fTotalRTCPPacketsRecv; }
|
|
void IncrTotalRTCPBytesRecv(UInt16 cnt) { fTotalRTCPBytesRecv += cnt; }
|
|
UInt32 GetTotalRTCPBytesRecv() { return fTotalRTCPBytesRecv; }
|
|
|
|
UInt32 GetLastRTSPBandwithBits() { return fLastRTSPBandwidthHeaderBits; }
|
|
UInt32 GetCurrentMovieBitRate() { return fMovieCurrentBitRate; }
|
|
|
|
UInt32 GetMaxBandwidthBits() { UInt32 maxRTSP = GetLastRTSPBandwithBits(); UInt32 maxLink = fRTPSession3GPP.GetLinkCharMaxKBits()* 1000; return (maxRTSP > maxLink) ? maxRTSP : maxLink; }
|
|
|
|
void SetIs3GPPSession(Bool16 is3GPP) { fIs3GPPSession = is3GPP; }
|
|
|
|
protected:
|
|
|
|
RTPSession3GPP* Get3GPPSessPtr() { return fRTPSession3GPPPtr; }
|
|
|
|
// These variables are setup by the derived RTPSession object when
|
|
// Play and Pause get called
|
|
|
|
//Some stream related information that is shared amongst all streams
|
|
Bool16 fIsFirstPlay;
|
|
Bool16 fAllTracksInterleaved;
|
|
SInt64 fFirstPlayTime;//in milliseconds
|
|
SInt64 fPlayTime;
|
|
SInt64 fAdjustedPlayTime;
|
|
SInt64 fNTPPlayTime;
|
|
SInt64 fNextSendPacketsTime;
|
|
|
|
SInt32 fSessionQualityLevel;
|
|
|
|
//keeps track of whether we are playing or not
|
|
QTSS_RTPSessionState fState;
|
|
|
|
// If we are playing, this are the play flags that were set on play
|
|
QTSS_PlayFlags fPlayFlags;
|
|
|
|
//Session mutex. This mutex should be grabbed before invoking the module
|
|
//responsible for managing this session. This allows the module to be
|
|
//non-preemptive-safe with respect to a session
|
|
OSMutex fSessionMutex;
|
|
|
|
//Stores the session ID
|
|
OSRef fRTPMapElem;
|
|
char fRTSPSessionIDBuf[QTSS_MAX_SESSION_ID_LENGTH + 4];
|
|
|
|
UInt32 fLastBitRateBytes;
|
|
SInt64 fLastBitRateUpdateTime;
|
|
UInt32 fMovieCurrentBitRate;
|
|
|
|
// In order to facilitate sending data over the RTSP channel from
|
|
// an RTP session, we store a pointer to the RTSP session used in
|
|
// the last RTSP request.
|
|
RTSPSessionInterface* fRTSPSession;
|
|
|
|
|
|
|
|
private:
|
|
|
|
//
|
|
// Utility function for calculating current bit rate
|
|
void UpdateBitRateInternal(const SInt64& curTime);
|
|
|
|
static void* PacketLossPercent(QTSSDictionary* inSession, UInt32* outLen);
|
|
static void* TimeConnected(QTSSDictionary* inSession, UInt32* outLen);
|
|
static void* CurrentBitRate(QTSSDictionary* inSession, UInt32* outLen);
|
|
|
|
// Create nonce
|
|
void CreateDigestAuthenticationNonce();
|
|
|
|
// One of the RTP session attributes is an iterated list of all streams.
|
|
// As an optimization, we preallocate a "large" buffer of stream pointers,
|
|
// even though we don't know how many streams we need at first.
|
|
enum
|
|
{
|
|
kStreamBufSize = 4,
|
|
kUserAgentBufSize = 256,
|
|
kPresentationURLSize = 256,
|
|
kFullRequestURLBufferSize = 256,
|
|
kRequestHostNameBufferSize = 80,
|
|
|
|
kIPAddrStrBufSize = 20,
|
|
kLocalDNSBufSize = 80,
|
|
|
|
kAuthNonceBufSize = 32,
|
|
kAuthOpaqueBufSize = 32,
|
|
|
|
};
|
|
|
|
void* fStreamBuffer[kStreamBufSize];
|
|
|
|
|
|
// theses are dictionary items picked up by the RTSPSession
|
|
// but we need to store copies of them for logging purposes.
|
|
char fUserAgentBuffer[kUserAgentBufSize];
|
|
char fPresentationURL[kPresentationURLSize]; // eg /foo/bar.mov
|
|
char fFullRequestURL[kFullRequestURLBufferSize]; // eg rtsp://yourdomain.com/foo/bar.mov
|
|
char fRequestHostName[kRequestHostNameBufferSize]; // eg yourdomain.com
|
|
|
|
char fRTSPSessRemoteAddrStr[kIPAddrStrBufSize];
|
|
char fRTSPSessLocalDNS[kLocalDNSBufSize];
|
|
char fRTSPSessLocalAddrStr[kIPAddrStrBufSize];
|
|
|
|
char fUserNameBuf[RTSPSessionInterface::kMaxUserNameLen];
|
|
char fUserPasswordBuf[RTSPSessionInterface::kMaxUserPasswordLen];
|
|
char fUserRealmBuf[RTSPSessionInterface::kMaxUserRealmLen];
|
|
UInt32 fLastRTSPReqRealStatusCode;
|
|
|
|
//for timing out this session
|
|
TimeoutTask fTimeoutTask;
|
|
UInt32 fTimeout;
|
|
|
|
// Time when this session got created
|
|
SInt64 fSessionCreateTime;
|
|
|
|
//Packet priority levels. Each stream has a current level, and
|
|
//the module that owns this session sets what the number of levels is.
|
|
UInt32 fNumQualityLevels;
|
|
|
|
//Statistics
|
|
UInt32 fBytesSent;
|
|
UInt32 fPacketsSent;
|
|
Float32 fPacketLossPercent;
|
|
SInt64 fTimeConnected;
|
|
UInt32 fTotalRTCPPacketsRecv;
|
|
UInt32 fTotalRTCPBytesRecv;
|
|
// Movie size & movie duration. It may not be so good to associate these
|
|
// statistics with the movie, for a session MAY have multiple movies...
|
|
// however, the 1 movie assumption is in too many subsystems at this point
|
|
Float64 fMovieDuration;
|
|
UInt64 fMovieSizeInBytes;
|
|
UInt32 fMovieAverageBitRate;
|
|
|
|
QTSS_CliSesTeardownReason fTeardownReason;
|
|
// So the streams can send sender reports
|
|
UInt32 fUniqueID;
|
|
|
|
RTCPSRPacket fRTCPSRPacket;
|
|
StrPtrLen fSRBuffer;
|
|
|
|
RTPBandwidthTracker fTracker;
|
|
RTPOverbufferWindow fOverbufferWindow;
|
|
|
|
// Built in dictionary attributes
|
|
static QTSSAttrInfoDict::AttrInfo sAttributes[];
|
|
static unsigned int sRTPSessionIDCounter;
|
|
|
|
// Authentication information that needs to be kept around
|
|
// for the duration of the session
|
|
QTSS_AuthScheme fAuthScheme;
|
|
StrPtrLen fAuthNonce;
|
|
UInt32 fAuthQop;
|
|
UInt32 fAuthNonceCount;
|
|
StrPtrLen fAuthOpaque;
|
|
UInt32 fQualityUpdate;
|
|
|
|
UInt32 fFramesSkipped;
|
|
|
|
RTPSession3GPP fRTPSession3GPP;
|
|
RTPSession3GPP* fRTPSession3GPPPtr;
|
|
UInt32 fLastRTSPBandwidthHeaderBits;
|
|
Bool16 fIs3GPPSession;
|
|
|
|
};
|
|
|
|
#endif //_RTPSESSIONINTERFACE_H_
|