/*
 *
 * @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@
 *
 */
#ifndef playlist_elements_H
#define playlist_elements_H
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#if (! __MACOS__)
#ifndef __Win32__
	#include <sys/types.h>
	#include <sys/time.h>
	#include <sys/stat.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <arpa/inet.h>
	
	#include <fcntl.h>
#endif
#endif

#if (__MACOS__)
	#include "bogusdefs.h"
#endif

#include "playlist_array.h"
#include "OSHeaders.h"
#include "playlist_SimpleParse.h"
#include "QTRTPFile.h"
#include "BroadcasterSession.h"

class MediaStream;

struct SoundDescription {
	long 							descSize;					/* total size of SoundDescription including extra data */
	long 							dataFormat;					/* sound format */
	long 							resvd1;						/* reserved for apple use. set to zero */
	short 							resvd2;						/* reserved for apple use. set to zero */
	short 							dataRefIndex;
	short 							version;					/* which version is this data */
	short 							revlevel;					/* what version of that codec did this */
	long 							vendor;						/* whose  codec compressed this data */
	short 							numChannels;				/* number of channels of sound */
	short 							sampleSize;					/* number of bits per sample */
	short 							compressionID;				/* unused. set to zero. */
	short 							packetSize;					/* unused. set to zero. */
	unsigned long 					sampleRate;					/* sample rate sound is captured at */
};


class PayLoad {
	public:
	PayLoad(void) : payloadID(0), timeScale(1) {};
	int				payloadID;
	SimpleString 	payLoadString;
	UInt32			timeScale;
};


class TypeMap {
	public:
		TypeMap(void) : fMediaStreamPtr(0), fTrackID(0), fPort(0), fTimeScale(1) {};
		~TypeMap() { } ;
		
		MediaStream 				*fMediaStreamPtr;
		int 						fTrackID;
		int							fPort;
		UInt32						fTimeScale;
		SimpleString 				fTheTypeStr;
		SimpleString				fProtocolStr;
		ArrayList<PayLoad> 			fPayLoadTypes;
		ArrayList<short> 			fPayLoads;
	
};


class RTpPacket 
{
		

struct SoundHeader {
	char bytes[4];
	long skip1;
	char sndtype[4];
	long skip2;
	char test[4];
};


	public:
		enum 	{ kRTpHeaderSize = 12 };
		char 	*fThePacket;
		int 	fLength;
		bool	fHasSoundDescription;
		long    fSoundDescriptionLen;

		RTpPacket()  : fThePacket(NULL), fLength(0), fHasSoundDescription(false), fSoundDescriptionLen(0) {};
		 
		void	SetPacketData(char *thePacket, int length)  {fThePacket = thePacket; fLength = length; };
		SInt16 	SetHeaderInfo( UInt32 timeStamp, UInt16 sequence,UInt32 SSRC,unsigned char payloadType);
		SInt16 	GetHeaderInfo( UInt32 *timeStampPtr, UInt16 *sequencePtr,UInt32 *SSRCPtr,unsigned char*payloadType);
		
		bool	HasSoundDescription();
		SInt16  GetSoundDescriptionRef(SoundDescription **soundDescriptionPtr);
		
	protected: 
	
		enum { cSequenceNumber = 1, cTimeStamp = 1, cSSRC = 2, cPayloadType = 1};
		
};



class UDPSocketPair
{
	public:
	enum
	{
		kBound		= 1L << 0,
		kConnected 	= 1L << 1
	};

	enum 	{ 	eBindMaxTries = 100,
				eSourcePortStart = 49152, // rtp + rtcp
				eSourcePortRange =  65535 // 49152,49153 - 65534,65535
			};

	enum
	{
		kInvalidSocket = -1,	//int
		kPortRTCpufSizeInBytes = 8,	//UInt32
		kMaxIPAddrSizeInBytes = 20	//UInt32
	};

	int					fMaxBindAttempts;
	int					fState;
	int					fSocketRTp;
	struct sockaddr_in	fLocalAddrRTp;
	struct sockaddr_in	fDestAddrRTp;
	
	int					fSocketRTCp;
	struct sockaddr_in	fLocalAddrRTCp;
	struct sockaddr_in	fDestAddrRTCp;
	BroadcasterSession *fBroadcasterSession;
	UInt8 				fChannel;
	Bool16				fIsMultiCast;
	Bool16				fMultiCastJoined;
	
	UDPSocketPair() : 	fMaxBindAttempts(eBindMaxTries), 
						fState(0),  
						fSocketRTp(0), 
						fSocketRTCp(0),
						fBroadcasterSession(NULL),
						fChannel(0),
						fIsMultiCast(false),
						fMultiCastJoined(false)
						{};  
	~UDPSocketPair() { Close(); };
	
	SInt16	Open();
	void 	Close();
	void	InitPorts(UInt32 addr);
	SInt16 	Bind(UInt32 addr);
	SInt16  OpenAndBind( UInt16 rtpPort,UInt16 rtcpPort,char *destAddress);

	SInt16  SetDestination (char *destAddress,UInt16 destPortRTp, UInt16 destPortRTCp);
	SInt16 	SetTTL(SInt16 timeToLive);
	SInt16 	JoinMulticast();
	SInt16 	LeaveMulticast();
	SInt16	SetMulticastInterface();
	SInt16 	SetMultiCastOptions(SInt16 ttl);

	SInt16  SendTo(int socket, sockaddr *destAddrPtr, char* inBuffer, UInt32 inLength );
	SInt16	SendRTp(char* inBuffer, UInt32 inLength);
	SInt16	SendRTCp(char* inBuffer, UInt32 inLength);
	
	SInt16 	RecvFrom(sockaddr *recvAddrPtr, int socket, char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
	SInt16 	RecvRTp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
	SInt16 	RecvRTCp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);

	void	SetRTSPSession(BroadcasterSession *theSession,UInt8 channel) {fBroadcasterSession = theSession, fChannel=channel;}
};

class ReceiveBuffer
{
	public:
			enum { kReadBufferSize = 256 }; //UInt32
			char			fReadBuffer[kReadBufferSize];
			UInt32			fReceiveLen;	

};

class MediaStream
{		  
	protected:

		int				SendRTp(RTpPacket *packet);
		int				CalcRTCps();
		int				SendRTCp_SenderReport();
		static UInt32	GetACName(char* ioCNameBuffer);
		
		void MapToStream(UInt32 curRTpTimeStamp, UInt16 curRTpSequenceNumber, unsigned char curPayload, UInt32 *outRTpTimeStampPtr, UInt16 *outRTpSequenceNumberPtr, unsigned char *outPayloadPtr);
		void 			UpdatePacketInStream(RTpPacket *packetPtr);
		SInt16			Accounting(RTpPacket *packetPtr);
		void 			BuildStaticRTCpReport();
		void 			InitIfAudio();
		void			TestAndIncSoundDescriptor(RTpPacket *packetPtr);
	public:
		enum { kMaxCNameLen = 20 }; //UInt32
		enum { eMaxSoundDescriptionSize = 1024};
		enum {
				kSenderReportSizeInBytes = 36,	//UInt32
				kMaxRTCpPacketSizeInBytes = 1024,	//All are UInt32s
				kMaxSsrcSizeInBytes = 25,
				kSenderReportIntervalInSecs = 5
			 };
			 

		enum { 	
				eSocketNotOpen,
				eSocketFailed 
			  };
	
		struct MemberData {
			ReceiveBuffer	fPortRTpReadBuff;
			ReceiveBuffer	fPortRTCpReadBuff;
			
			UInt64			fRTCpTimer;
			SInt16			fState;
			
			
			UInt64			fBytesSent;
			UInt64			fPacketsSent;
			
			SInt64			fStreamStartTime;
			SInt64			fNTPPlayTime;
			
			char			fSenderReportBuffer[kSenderReportSizeInBytes + kMaxCNameLen];
			UInt32			fSenderReportSize;
			
			//who am i sending to?
			UInt16			fRemoteRTpPort;
			UInt16			fRemoteRTCpPort;
			
			//RTCp stuff 
			SInt64			fLastSenderReportTime;
			UInt32			fPacketCount;
			UInt32			fByteCount;
			
			Bool16			fSenderReportReady;
			UInt32			fLastTimeStamp;

			// current RTP packet info
			UInt32			fLastTimeStampOffset;

			UInt32			fTimeStamp;
			UInt32			fSsrc;
			
			UInt16			fLastSequenceNumber;
					
			UInt32 			fInitSSRC; // initial SSRC
			UInt64			fCurStreamRTpSequenceNumber; // now
			
			TypeMap			*fStreamMediaTypePtr;
			TypeMap 		*fMovieMediaTypePtr;
			SInt64			fMovieStartTime;
			SInt64			fMovieEndTime;
			
			Float64			fLastMovieDurationSecs;
			UInt64			fMediaStartOffsetMediaScale;
			UInt64			fMovieStartOffset;
			
			UInt32			fSeqRandomOffset;
			UInt32			fRTpRandomOffset;
			
			bool			fNewMovieStarted;	
			bool			fNewStreamStarted;
			
			bool			fIsSoundStream;
			bool			fIsVideoStream;
			
			char 			*fSoundDescriptionBuffer;
			long			fSavedSoundDescSize;
			short			fSavedDataRefIndex;
			UDPSocketPair 	*fSocketPair;
			QTRTPFile		*fRTPFilePtr;
		};
		  
		MemberData		fData;
		bool			fSend;
				~MediaStream();
				MediaStream();
		char*	GetRTCpSR()				{ return fData.fSenderReportBuffer; }
		UInt32	GetRTCpSRLen()			{ return fData.fSenderReportSize;   }
		SInt64	GetPlayTime()			{ return fData.fStreamStartTime; }
		SInt64	GetNTPPlayTime()		{ return fData.fNTPPlayTime; }
		SInt16	Send(RTpPacket *packetPtr);
		void	ReceiveOnPorts();
		int		UpdateSenderReport(SInt64 theTime);
		void	StreamStart(SInt64 startTime);
		void	MovieStart(SInt64 startTime);
		void	MovieEnd(SInt64 endTime);
};






#endif // playlist_elements_H
