/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2001 Apple Computer, Inc.  All Rights Reserved. The
 * contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License.  Please
 * obtain a copy of the License at http://www.apple.com/publicsource and
 * read it before using this file.
 *
 * This 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:		RTPSession.h

	Contains:	RTPSession represents an, well, an RTP session. The server creates
				one of these when a new client connects, and it lives for the duration
				of an RTP presentation. It contains all the resources associated with
				that presentation, such as RTPStream objects. It also provides an
				API for manipulating a session (playing it, pausing it, stopping it, etc) 
				
				It is also the active element, ie. it is the object that gets scheduled
				to send out & receive RTP & RTCP packets
				
	Change History (most recent first):

	
	

*/


#ifndef _RTPSESSION_H_
#define _RTPSESSION_H_

#include "RTPSessionInterface.h"
#include "RTSPRequestInterface.h"
#include "RTPStream.h"
#include "QTSSModule.h"


class RTPSession : public RTPSessionInterface
{
	public:
	
		RTPSession();
		virtual ~RTPSession();
		
		//
		//ACCESS FUNCTIONS
		
		QTSSModule*	GetPacketSendingModule()						{ return fModule; }
		Bool16		HasAnRTPStream()								{ return fHasAnRTPStream; }
		
		RTPStream*	FindRTPStreamForChannelNum(UInt8 inChannelNum);
		
		//
		// MODIFIERS
		
		//This puts this session into the session map (called by the server! not the module!)
		//If this function fails (it can return QTSS_DupName), it means that there is already
		//a session with this session ID in the map.
		QTSS_Error	Activate(const StrPtrLen& inSessionID);
				
		// The way this object is implemented currently, only one module can send the
		// packets for a session.
		void		SetPacketSendingModule(QTSSModule* inModule)	{ fModule = inModule; }

		//Once the session is bound, a module can add streams to it.
		//It must pass in a trackID that uniquely identifies this stream.
		//This call can only be made during an RTSP Setup request, and the
		//RTSPRequestInterface must be provided.
		//You may also opt to attach a codec name and type to this stream.
		QTSS_Error	AddStream(	RTSPRequestInterface* request, RTPStream** outStream,
									QTSS_AddStreamFlags inFlags);
		
		//Reset the thinning params for all streams using the late tolerance value
		void SetStreamThinningParams(Float32 inLateTolerance);
		
		//Begins playing all streams. Currently must be associated with an RTSP Play
		//request, and the request interface must be provided.
		QTSS_Error	Play(RTSPRequestInterface* request, QTSS_PlayFlags inFlags);
		
		//Pauses all streams.
		void			Pause() { fState = qtssPausedState; }
		
		// Tears down the session. This will cause QTSS_SessionClosing_Role to run
		void			Teardown();

		//Utility functions. Modules aren't required to use these, but can be useful
		void			SendDescribeResponse(RTSPRequestInterface* request);
		void			SendAnnounceResponse(RTSPRequestInterface* request);
		void			SendPlayResponse(RTSPRequestInterface* request, UInt32 inFlags);
		void			SendPauseResponse(RTSPRequestInterface* request)
																{ request->SendHeader(); }
		void			SendTeardownResponse(RTSPRequestInterface* request)
									{ request->SetKeepAlive(false); request->SendHeader(); }
									
		SInt32			GetQualityLevel();
		void			SetQualityLevel(SInt32 level);
	
	private:
#if RTP_STREAM_THINNING_TIMING_LOG
		void			LogClientInfo(UInt32 inBandwidth);
		void			LogPlayInfo(Float64 inPlayTime);
		void			LogLateTolerance(Float32 inLateTolerance);
#endif

		//where timeouts, deletion conditions get processed
		virtual SInt64	Run();
		
		// Utility function used by Play
		UInt32 PowerOf2Floor(UInt32 inNumToFloor);
		
		//overbuffer logging function
		void LogOverbufferStats();
	
		enum
		{
			kRTPStreamArraySize		= 20,
			kCantGetMutexIdleTime	= 10
		};

		QTSSModule*			fModule;
		Bool16				fHasAnRTPStream;
		SInt32				fSessionQualityLevel;
		
		char		fRTPStreamArray[kRTPStreamArraySize];
		
		// Module invocation and module state.
		// This info keeps track of our current state so that
		// the state machine works properly.
		enum
		{
			kStart			 		= 0,
			kSendingPackets 		= 1
		};
		
		UInt32 fCurrentModuleIndex;
		UInt32 fCurrentState;
		
		QTSS_ModuleState	fModuleState;
		QTSS_CliSesClosingReason fClosingReason;
		
		UInt32				fCurrentModule;
		// This is here to give the ability to the ClientSessionClosing role to
		// do asynchronous I/O
		Bool16				fModuleDoingAsyncStuff;
		
#if DEBUG
		Bool16 fActivateCalled;
#endif
		SInt64				fLastBandwidthTrackerStatsUpdate;

};

#endif //_RTPSESSION_H_
