/*
 *
 * @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:		BroadcasterSession.cpp

	Contains:	.  
					
	
	
*/

#include "BroadcasterSession.h"
#include "OSMemory.h"
#include "StrPtrLen.h"
#include "OSMutex.h"

#include <stdlib.h>

#define BROADCAST_SESSION_DEBUG 0

static const SInt64 kMaxWaitTimeInMsec = 1000;
static const SInt64 kIdleTimeoutInMsec = 60 * 1000; // Time out at 60 seconds
static const SInt16 kSanitySeqNumDifference = 300;

UInt32			BroadcasterSession::sActiveConnections = 0;
UInt32			BroadcasterSession::sBroadcastingConnections = 0;
UInt32			BroadcasterSession::sTotalConnectionAttempts = 0;


char *BroadcasterSession::fPacket = NULL;

BroadcasterSession::BroadcasterSession(	UInt32 inAddr, UInt16 inPort, char* inURL,
								BroadcasterType inClientType,
								UInt32 inDurationInSec, UInt32 inStartPlayTimeInSec,
								UInt32 inRTCPIntervalInSec, UInt32 inOptionsIntervalInSec,
								UInt32 inHTTPCookie, Bool16 inAppendJunkData, UInt32 inReadInterval,
								UInt32 inSockRcvBufSize,
								StrPtrLen *sdpSPLPtr,
								char *namePtr,
								char *passwordPtr,
								Bool16	deepDebug)
:	fSocket(NULL),
	fRTSPClient(NULL),
	fTimeoutTask(this, kIdleTimeoutInMsec),

	fDurationInSec(inDurationInSec),
	fStartPlayTimeInSec(inStartPlayTimeInSec),
	fRTCPIntervalInSec(inRTCPIntervalInSec),
	fOptionsIntervalInSec(inOptionsIntervalInSec),
	
	fState(kSendingAnnounce),
	fDeathState(kSendingAnnounce),
	fDeathReason(kDiedNormally),
	fNumSetups(0),
	fUDPSocketArray(NULL),
	
	fPlayTime(0),
	fTotalPlayTime(0),
	fLastRTCPTime(0),
	fTeardownImmediately(false),
	fAppendJunk(inAppendJunkData),
	fReadInterval(inReadInterval),
	fSockRcvBufSize(inSockRcvBufSize),
	fStats(NULL),
	fPacketLen(0),
	fChannel(0)
//	fPacket(NULL)

{
	StrPtrLen theURL(inURL);
	fSDPParser.Parse(sdpSPLPtr->Ptr, sdpSPLPtr->Len);
	
#if BROADCAST_SESSION_DEBUG

	printf("Connecting to: %s, port %d\n", inURL, inPort);

#endif	
	//
	// Construct the appropriate ClientSocket type depending on what type of client we are supposed to be
	switch (inClientType)
	{
		case kRTSPUDPBroadcasterType:
		{
			fControlType = kRawRTSPControlType;
			fTransportType = kUDPTransportType;
			fSocket = NEW TCPClientSocket(Socket::kNonBlockingSocketType);
			break;
		}
		case kRTSPTCPBroadcasterType:
		{
			fControlType = kRawRTSPControlType;
			fTransportType = kTCPTransportType;
			fSocket = NEW TCPClientSocket(Socket::kNonBlockingSocketType);
			break;
		}
		case kRTSPHTTPBroadcasterType:
		{
			fControlType = kRTSPHTTPControlType;
			fTransportType = kTCPTransportType;
			fSocket = NEW HTTPClientSocket(theURL, inHTTPCookie, Socket::kNonBlockingSocketType);
			break;
		}
		case kRTSPHTTPDropPostBroadcasterType:
		{
			fControlType = kRTSPHTTPDropPostControlType;
			fTransportType = kTCPTransportType;
			fSocket = NEW HTTPClientSocket(theURL, inHTTPCookie, Socket::kNonBlockingSocketType);
			break;
		}
		case kRTSPReliableUDPBroadcasterType:
		{
			Assert(0);
			break;
		}
		default:
		{
			printf("BroadcasterSession: Attempt to create unsupported client type.\n");
			::exit(-1);
		}
	}
	
	fSocket->Set(inAddr, inPort);
	fSocket->GetSocket()->SetTask(this);

	int sndBufSize = 32 * 1024;
	int	rcvBufSize=1024;
	((TCPClientSocket*)fSocket)->SetOptions(sndBufSize,rcvBufSize);
	//
	// Construct the client object using this socket.
	bool verbose = deepDebug;
	fRTSPClient = NEW RTSPClient(fSocket, verbose);
	fRTSPClient->Set(theURL);
	fRTSPClient->SetTransportMode(RTSPClient::kPushMode);
	fRTSPClient->SetName(namePtr);
	fRTSPClient->SetPassword(passwordPtr);

	//
	// Start the connection process going
	this->Signal(Task::kStartEvent);
}

BroadcasterSession::~BroadcasterSession()
{
#if BROADCAST_SESSION_DEBUG
	printf("BroadcasterSession::~BroadcasterSession() \n");
#endif

	if (fUDPSocketArray != NULL)
	{
		for (UInt32 x = 0; x < fSDPParser.GetNumStreams() * 2; x++)
			delete fUDPSocketArray[x];
	}
			
	delete [] fUDPSocketArray;
	delete fRTSPClient;
	delete fSocket;
}

char* 	BroadcasterSession::GetNextPacket(UInt32 *packetLen, UInt8 *channel)
{
	char* thePacketData = NULL;
	*packetLen = 0;
 	*channel = 0;
 	//printf("BroadcasterSession::GetNextPacket Q len=%lu\n",fPacketQueue.GetLength());
	OSQueueElem *thePacketQElemPtr = fPacketQueue.GetHead();
	if(thePacketQElemPtr != NULL)
	{	
		BroadcasterSession::RTPPacket* thePacket = (BroadcasterSession::RTPPacket*) thePacketQElemPtr->GetEnclosingObject();
		fPacketQueue.Remove(thePacketQElemPtr);	
		
		Assert(thePacket != NULL);
		Assert(thePacket->fData != NULL);
		Assert(thePacket->fLen > 0);
		
		if (NULL == thePacket || NULL == thePacket->fData || 0 == thePacket->fLen)
			return NULL;
			
		thePacketData = thePacket->fData;
		*packetLen = thePacket->fLen;
	 	*channel = thePacket->fChannel;
	 	
	 	delete thePacket;
	}
	
	Assert(*packetLen <= RTSPClient::kReqBufSize);
	
	return thePacketData;
}

OS_Error	BroadcasterSession::SendPacket(char* data, UInt32 len,UInt8	channel)
{	
	OS_Error theErr = 0;
	if (fState != kBroadcasting)
	{	
		switch (fState)
		{	case	kSendingAnnounce:
					theErr = kConnectionFailed;
			break;
			
			case	kSendingReceive:
			case	kSendingSetup:
					theErr = kRequestFailed;
			break;
			
			default:
				theErr = kDiedWhileBroadcasting;
		}
		return theErr;
	}
	
	BroadcasterSession::RTPPacket* newPacket = NEW BroadcasterSession::RTPPacket;
	if (newPacket == NULL)
		return kMemoryError;
	
	char *theSendData = NEW char[len];
	memcpy(theSendData,data,len);
	newPacket->fCount = ++fPacketCount;
	newPacket->SetEnclosingObject(newPacket);
	newPacket->SetPacketData(theSendData,len,channel);
	
	fPacketQueue.EnQueue(newPacket->GetQElement());
	return 0;
}	

OS_Error BroadcasterSession::SendWaitingPackets()
{	
	OSMutexLocker locker(this->GetMutex());
	OS_Error theErr = OS_NoErr;
	
	if (fPacket == NULL)
	{	fPacket = this->GetNextPacket(&fPacketLen, &fChannel);
	}
	
	while (fPacket != NULL)
	{	Bool16 getNext = false;
		//printf("BroadcasterSession::Run- Broadcasting SendInterleavedWrite \n");
		Assert(fPacketLen <= RTSPClient::kReqBufSize);
		OSMutexLocker locker(fRTSPClient->GetMutex());
		theErr = fRTSPClient->SendInterleavedWrite(fChannel, fPacketLen, fPacket, &getNext);
		if (getNext)
		{	delete [] fPacket;
			fPacket = this->GetNextPacket(&fPacketLen, &fChannel);
		}
		
		if (theErr != OS_NoErr)
		{
			if (theErr == EAGAIN || theErr == EINPROGRESS)
			{	// keep the packet around and try again
				//printf("BroadcasterSession::SendWaitingPackets- Broadcasting SendInterleavedWrite err=%ld Request Write Event\n",theErr);
				break;		
			}
			// some bad error bail.
			delete [] fPacket;
			fPacket = NULL;
			
			break;
		}
		
		// we sent the packet and may or may not have another packet to send
			
		fTimeoutTask.RefreshTimeout();
		//printf("send channel=%u len=%lu\n",(UInt16)fChannel,fPacketLen);
	}
	
	return theErr;				
}	

SInt64 BroadcasterSession::Run()
{

	EventFlags theEvents = this->GetEvents();
	
	if (theEvents & Task::kStartEvent)
	{
		sActiveConnections++;
		sTotalConnectionAttempts++;
		Assert(theEvents == Task::kStartEvent);
	}
	
	// 
	if (theEvents & Task::kTimeoutEvent)
	{
#if BROADCAST_SESSION_DEBUG
		printf("Session timing out.\n");
#endif
#if __FreeBSD__ || __MacOSX__
		if (fTransportType != kTCPTransportType)
		{
			fTimeoutTask.RefreshTimeout();
			fSocket->GetSocket()->SetTask(this);
			fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask());				
			return 10000;
		}
#else
		if (fTransportType != kTCPTransportType)
		{	fTimeoutTask.RefreshTimeout();
			return 0;
		}
#endif

		fDeathReason = kSessionTimedout;
		fTeardownImmediately = true;
		fState = kSendingTeardown;
	}
				
	//
	// If we've been told to TEARDOWN, do so.
	if (theEvents & BroadcasterSession::kTeardownEvent && fState != kDone)
	{	

#if BROADCAST_SESSION_DEBUG
		printf("Session tearing down immediately.\n");
#endif
		fTeardownImmediately = true;
		fState = kSendingTeardown;
	}
	
	// We have been told to delete ourselves. Do so... NOW!!!!!!!!!!!!!!!
	if (theEvents & Task::kKillEvent || fTeardownImmediately)
	{
#if BROADCAST_SESSION_DEBUG
		printf("Session killed.\n");
#endif
		if (fState != kSendingTeardown )
		{
			
			sActiveConnections--;
			// return -1;
			fTeardownImmediately = true;
			fState = kSendingTeardown;
		}
	}	
	
	// Refresh the timeout. There is some legit activity going on...
	//fTimeoutTask.RefreshTimeout();
	
	OS_Error theErr = OS_NoErr;
	
	while ((theErr == OS_NoErr) && (fState != kDone))
	{
		//
		// Do the appropriate thing depending on our current state
		switch (fState)
		{
			case kSendingAnnounce:
			{
#if BROADCAST_SESSION_DEBUG
				printf("BroadcasterSession::kSendingAnnounce\n");
#endif				
				
				char *theSDP = (fSDPParser.GetSDPData())->Ptr;
				theErr = fRTSPClient->SendAnnounce(theSDP);
				
#if BROADCAST_SESSION_DEBUG
				printf("BroadcasterSession::Run Sending ANNOUNCE. Result = %lu. Response code = %lu\n", theErr, fRTSPClient->GetStatus());
#endif									
				if (theErr == OS_NoErr)
				{
					// Check that the ANNOUNCE response is a 200 OK. If not, bail
					if (fRTSPClient->GetStatus() != 200)
					{
						theErr = ENOTCONN; // Exit the state machine
						break;
					}
					else
					{
						Assert(fControlType != kReliableUDPTransportType);
							
						//							
						//
						// We have valid SDP. If this is a UDP connection, construct a UDP
						// socket array to act as incoming sockets.
						if ((fControlType == kUDPTransportType) && (fTransportType != kTCPTransportType))
							this->SetupUDPSockets();
						//
						// Setup client stats
						fStats = NEW TrackStats[fSDPParser.GetNumStreams()];
						::memset(fStats, 0, sizeof(TrackStats) * fSDPParser.GetNumStreams());
					}
					
					fState = kSendingSetup;
				}
#if BROADCAST_SESSION_DEBUG
				else
				{
					if ( (fRTSPClient->GetStatus() == 0) && ( (theErr == EAGAIN) || (theErr== EINPROGRESS)) )
					{
						printf("BroadcasterSession::Run Sending ANNOUNCE. Result = %lu. Response code = %lu\n", theErr, fRTSPClient->GetStatus());
					}
				}
#endif									
				break;
			}
			case kSendingSetup:
			{
#if BROADCAST_SESSION_DEBUG
				printf("BroadcasterSession::kSendingSetup\n");
#endif				
				// The SETUP request is different depending on whether we are interleaving or not
				if (fTransportType == kUDPTransportType)
				{
					theErr = fRTSPClient->SendUDPSetup(fSDPParser.GetStreamInfo(fNumSetups)->fTrackID,
												fUDPSocketArray[fNumSetups*2]->GetLocalPort());
				}
				else if (fTransportType == kTCPTransportType)
				{	
					theErr = fRTSPClient->SendTCPSetup(fSDPParser.GetStreamInfo(fNumSetups)->fTrackID);					
#if BROADCAST_SESSION_DEBUG
					printf("Sending SETUP #%lu. Result = %lu. Response code = %lu\n", fNumSetups, theErr, fRTSPClient->GetStatus());
					if (theErr == EAGAIN || theErr == EINPROGRESS)
					{	
						if  (theErr == EAGAIN)
							printf("BroadcasterSession::kSendingSetup EAGAIN\n");
						if  (theErr == EINPROGRESS)
							printf("BroadcasterSession::kSendingSetup EINPROGRESS\n");
					
		//				fSocket->GetSocket()->RequestEvent(EV_RE | EV_WR);
		//				return 0;	
					}
#endif				

				}

				// If this SETUP request / response is complete, check for errors, and if
				// it succeeded, move onto the next SETUP. If we're done setting up all tracks,
				// move onto PLAY.
				if (theErr == OS_NoErr)
				{
					if (fRTSPClient->GetStatus() != 200)
					{
						theErr = ENOTCONN; // Exit the state machine
						break;
					}
					else
					{
						// Record the server port for RTCPs.
						
						fStats[fNumSetups].fDestRTPPort = fRTSPClient->GetServerPort();
						fStats[fNumSetups].fDestRTCPPort = fRTSPClient->GetServerPort() + 1;
						fNumSetups++;
						if (fNumSetups == fSDPParser.GetNumStreams())
							fState = kSendingReceive;
					}				
				}
				break;
			}
			case kSendingReceive:
			{					
#if BROADCAST_SESSION_DEBUG
				printf("BroadcasterSession::kSendingReceive\n");
#endif				

				theErr = fRTSPClient->SendReceive(fStartPlayTimeInSec);
				
#if BROADCAST_SESSION_DEBUG
				printf("BroadcasterSession::fRTSPClient->SendReceive. Result = %lu. Response code = %lu\n", theErr, fRTSPClient->GetStatus());
				if  (theErr == EAGAIN)
					printf("BroadcasterSession::SendReceive EAGAIN\n");
				if  (theErr == EINPROGRESS)
					printf("BroadcasterSession::SendReceive EINPROGRESS\n");
#endif				
				// If this PLAY request / response is complete, then we are done with setting
				// up all the client crap. Now all we have to do is send the data until it's
				// time to send the TEARDOWN
				if (theErr == OS_NoErr)
				{
					if (fRTSPClient->GetStatus() != 200)
					{
						theErr = ENOTCONN; // Exit the state machine
						break;
					}
						
					// Mark down the SSRC for each track, if possible. 
					for (UInt32 ssrcCount = 0; ssrcCount < fSDPParser.GetNumStreams(); ssrcCount++)
					{
						fStats[ssrcCount].fSSRC = fRTSPClient->GetSSRCByTrack(fSDPParser.GetStreamInfo(ssrcCount)->fTrackID);
						if (fStats[ssrcCount].fSSRC != 0)
							fStats[ssrcCount].fIsSSRCValid = true;
					}

					fState = kBroadcasting;
					sBroadcastingConnections++;
					
					//
					// Start our duration timer. Use this to figure out when to send a teardown
					fPlayTime = fLastRTCPTime = OS::Milliseconds();		
				}
				break;
			}
#if __FreeBSD__ || __MacOSX__
			case kBroadcasting:
			{	
#if BROADCAST_SESSION_DEBUG
				//printf("BroadcasterSession::kBroadcasting\n");
#endif				
				theErr = OS_NoErr; // Ignore flow control errors here.			
				static char buffer[256];
				UInt32 outRecvLen = 0;
				theErr = fRTSPClient->GetSocket()->Read(buffer, 256, &outRecvLen);
				
				if (fTransportType == kTCPTransportType)
				{	theErr = SendWaitingPackets();

					if (theErr == EAGAIN || theErr == EINPROGRESS || theErr == ETIMEDOUT)
					{   fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(EV_WR);				
						return 0; // important must be 0
					}
							
				}	
				else if (theErr == EAGAIN || theErr == EINPROGRESS || theErr == ETIMEDOUT)
				{   fSocket->GetSocket()->SetTask(this);
					fSocket->GetSocket()->RequestEvent(EV_RE);	
					return 10000;
				}

				if (theErr != OS_NoErr)
				{	
					// we've encountered some fatal error, bail.
					//printf("kBroadcasting FATAL ERROR err=%ld\n",theErr);
					sBroadcastingConnections--;
					break;
				}
				
				// no Err and nothing left to do so got to sleep for awhile.
				return fReadInterval;
			}
			
#else
			case kBroadcasting:
			{	
#if BROADCAST_SESSION_DEBUG
				printf("BroadcasterSession::kBroadcasting\n");
#endif				
				theErr = OS_NoErr; // Ignore flow control errors here.
				
				if (fTransportType == kTCPTransportType)
					theErr = SendWaitingPackets();	
				else
				{	static char buffer[256];
					UInt32 outRecvLen = 0;
					theErr = fRTSPClient->GetSocket()->Read(buffer, 256, &outRecvLen);
					if (theErr == EAGAIN || theErr == EINPROGRESS)
					{	
						fSocket->GetSocket()->SetTask(this);
						fSocket->GetSocket()->RequestEvent(EV_RE);				
						return 0;
					}
				}
			
				if (theErr == EAGAIN || theErr == EINPROGRESS)
				{	
					fSocket->GetSocket()->SetTask(this);
					fSocket->GetSocket()->RequestEvent(EV_WR);				
					return 0;
				}
					
				if (theErr != OS_NoErr)
				{	
					// we've encountered some fatal error, bail.
					//printf("FATAL ERROR err=%ld\n",theErr);
					sBroadcastingConnections--;
					break;
				}
				
				// no Err and nothing left to do so got to sleep for awhile.
				return fReadInterval;
			}

#endif

			case kSendingTeardown:
			{	
#if BROADCAST_SESSION_DEBUG
				printf("BroadcasterSession::kSendingTeardown\n");
#endif				
				UInt16 maxTries = 10;
				do 
				{
					theErr = fRTSPClient->SendTeardown();
					OSThread::Sleep((unsigned int) 100);
					maxTries --;
				}
				while (theErr == EAGAIN && maxTries > 0);
			
				theErr = 2;
			
				sActiveConnections--;
				
#if BROADCAST_SESSION_DEBUG
				printf("Sending TEARDOWN. Result = %lu. Response code = %lu\n", theErr, fRTSPClient->GetStatus());
#endif				
				// Once the TEARDOWN is complete, we are done, so mark ourselves as dead, and wait
				// for the owner of this object to delete us
				fState = kDone;
				//exit (0);
				break;
			}				
		}
	}
		
	if ((theErr == EINPROGRESS) || (theErr == EAGAIN))
	{
#if BROADCAST_SESSION_DEBUG
		if  (theErr == EAGAIN)
			printf("BroadcasterSession::EAGAIN\n");
		if  (theErr == EINPROGRESS)
			printf("BroadcasterSession::EINPROGRESS\n");
#endif				
		//
		// Request an async event
		fSocket->GetSocket()->SetTask(this);
		fSocket->GetSocket()->RequestEvent(fSocket->GetEventMask() );
		return 100; // try again 
	}
	else if (theErr != OS_NoErr)
	{	
		//
#if BROADCAST_SESSION_DEBUG
		printf("BroadCasterSession::RUN FATAL ERROR err=%ld\n",theErr);
#endif				
		// We encountered some fatal error with the socket. Record this as a connection failure
		if (fState == kSendingTeardown)
			fDeathReason = kTeardownFailed;
		else if (fState == kBroadcasting)
			fDeathReason = kConnectionFailed;
		else if (fRTSPClient->GetStatus() >= 300)
			fDeathReason = kRequestFailed;
		else if ((fState == kSendingAnnounce) && (theErr == OS_NotEnoughSpace))
                        fDeathReason = kBadSDP;
                else
			fDeathReason = kConnectionFailed;

		fDeathState = fState;
		fState = kDone;
	}

#if BROADCAST_SESSION_DEBUG
	if (fState == kDone)
		printf("Client connection complete. Death reason = %lu RTSPClientStatus=%ld\n", fDeathReason,fRTSPClient->GetStatus());
#endif				
	
	return 0;
}



void	BroadcasterSession::SetupUDPSockets()
{

	static UInt16 sCurrentRTPPortToUse = 6970;
	static const UInt16 kMinRTPPort = 6970;
	static const UInt16 kMaxRTPPort = 36970;

	OS_Error theErr = OS_NoErr;
	
	//
	// Create a UDP socket pair (RTP, RTCP) for each stream
	fUDPSocketArray = NEW UDPSocket*[fSDPParser.GetNumStreams() * 2];
	for (UInt32 x = 0; x < fSDPParser.GetNumStreams() * 2; x++)
	{
		fUDPSocketArray[x] = NEW UDPSocket(this, Socket::kNonBlockingSocketType);
		theErr = fUDPSocketArray[x]->Open();
		if (theErr != OS_NoErr)
		{
			printf("BroadcasterSession: Failed to open a UDP socket.\n");
			::exit(-1);
		}
	}
	
	for (UInt32 y = 0; y < fSDPParser.GetNumStreams(); y++)
	{	
		for (UInt32 portCheck = 0; true; portCheck++)
		{
			theErr = fUDPSocketArray[y * 2]->Bind(INADDR_ANY, sCurrentRTPPortToUse);
			if (theErr == OS_NoErr)
				theErr = fUDPSocketArray[(y*2)+1]->Bind(INADDR_ANY, sCurrentRTPPortToUse + 1);

			sCurrentRTPPortToUse += 2;
			if (sCurrentRTPPortToUse > 30000)
				sCurrentRTPPortToUse = 6970;
				
			if (theErr == OS_NoErr)
			{
				// This is a good pair. Set the rcv buf on the RTP socket to be really big
				fUDPSocketArray[y * 2]->SetSocketRcvBufSize(fSockRcvBufSize);
				break;
			}
				
			if (sCurrentRTPPortToUse == kMaxRTPPort)
				sCurrentRTPPortToUse = kMinRTPPort;
			if (portCheck == 5000)
			{
				// Make sure we don't loop forever trying to bind a UDP socket. If we can't
				// after a certain point, just bail...
				printf("BroadcasterSession: Failed to bind a UDP socket.\n");
				::exit(-1);
			}
		}
	}						
#if BROADCAST_SESSION_DEBUG
	printf("Opened UDP sockets for %lu streams\n", fSDPParser.GetNumStreams());
#endif				
}

OS_Error	BroadcasterSession::ReadMediaData()
{
	// For iterating over the array of UDP sockets
	UInt32 theUDPSockIndex = 0;
	OS_Error theErr = OS_NoErr;
	
	while (true)
	{
		//
		// If the media data is being interleaved, get it from the control connection
		UInt32 theTrackID = 0;
		UInt32 theLength = 0;
		Bool16 isRTCP = false;
		char* thePacket = NULL;

		if (fTransportType == kTCPTransportType)
		{
			thePacket = NULL;
			theErr = fRTSPClient->GetMediaPacket(&theTrackID, &isRTCP, &thePacket, &theLength);
			if (thePacket == NULL)
				break;
		}
		else
		{
			static const UInt32 kMaxPacketSize = 2048;
			
			UInt32 theRemoteAddr = 0;
			UInt16 theRemotePort = 0;
			char thePacketBuf[kMaxPacketSize];
			
			// Get a packet from one of the UDP sockets.
			theErr = fUDPSocketArray[theUDPSockIndex]->RecvFrom(&theRemoteAddr, &theRemotePort,
																&thePacketBuf[0], kMaxPacketSize,
																&theLength);
			if ((theErr != OS_NoErr) || (theLength == 0))
			{
				
				theUDPSockIndex++;
				if (theUDPSockIndex == fSDPParser.GetNumStreams() * 2)
					break;
				continue;
			}
			
			theTrackID = fSDPParser.GetStreamInfo(theUDPSockIndex >> 1)->fTrackID;
			isRTCP = (theUDPSockIndex & 1);
			thePacket = &thePacketBuf[0];
		}
		
		//
		// We have a valid packet. Invoke the packet handler function
		this->ProcessMediaPacket(thePacket, theLength, theTrackID, isRTCP);
	}
	return theErr;
}

void	BroadcasterSession::ProcessMediaPacket(	char* inPacket, UInt32 inLength,
											UInt32 inTrackID, Bool16 isRTCP)
{
	Assert(inLength > 4);
	
	// Currently we do nothing with RTCPs.
	if (isRTCP)
		return;
	
	UInt16* theSeqNumP = (UInt16*)inPacket;
	UInt16 theSeqNum = ntohs(theSeqNumP[1]);
	
//	UInt32* theSsrcP = (UInt32*)inPacket;
//	UInt32 theSSRC = ntohl(theSsrcP[2]);
	
	for (UInt32 x = 0; x < fSDPParser.GetNumStreams(); x++)
	{
		if (fSDPParser.GetStreamInfo(x)->fTrackID == inTrackID)
		{
			// Check if this packet is even for our stream
			//if (!fStats[x].fIsSSRCValid)
			//	fStats[x].fSSRC = theSSRC; // If we don't know SSRC yet, just use first one we get
			//if (theSSRC != fStats[x].fSSRC)
			//	return;
				
			fStats[x].fNumPacketsReceived++;
			fStats[x].fNumBytesReceived += inLength;
			
			// Check if this packet is out of order
			if (fStats[x].fHighestSeqNumValid)
			{						
				SInt16 theValidationDifference = theSeqNum - fStats[x].fWrapSeqNum;
				if (theValidationDifference < 0)
					theValidationDifference -= 2 * theValidationDifference; // take the absolute value
				if (theValidationDifference > kSanitySeqNumDifference)
				{
					//
					// If this sequence number is really far out of range, then just toss
					// the packet and increment our count of crazy packets
					fStats[x].fNumThrownAwayPackets++;
					return;
				}
			
				SInt16 theSeqNumDifference = theSeqNum - fStats[x].fHighestSeqNum;

				if (theSeqNumDifference > 0)
				{
					fStats[x].fNumOutOfOrderPackets += theSeqNumDifference - 1;
					fStats[x].fHighestSeqNum = theSeqNum;
				}
			}
			else
			{
				fStats[x].fHighestSeqNumValid = true;
				fStats[x].fWrapSeqNum = fStats[x].fHighestSeqNum = theSeqNum;
				fStats[x].fLastAckedSeqNum = theSeqNum - 1;
			}
			
			UInt32 debugblah = 0;
			
			// Put this sequence number into the map to track packet loss
			while ((theSeqNum - fStats[x].fWrapSeqNum) > TrackStats::kSeqNumMapSize)
			{
				debugblah++;
				Assert(debugblah < 10);

				// We've cycled through the entire map. Calculate packet
				// loss on the lowest 50 indexes in the map (don't get too
				// close to where we are lest we mistake out of order packets
				// as packet loss)
				UInt32 halfSeqNumMap = TrackStats::kSeqNumMapSize / 2;
				UInt32 curIndex = (fStats[x].fWrapSeqNum + 1) % TrackStats::kSeqNumMapSize;
				UInt32 numPackets = 0;
				
				for (UInt32 y = 0; y < halfSeqNumMap; y++, curIndex++)
				{
					if (curIndex == TrackStats::kSeqNumMapSize)
						curIndex = 0;
					
					if (fStats[x].fSequenceNumberMap[curIndex] > 0)
						numPackets++;
					fStats[x].fSequenceNumberMap[curIndex] = 0;
				}
				
				// We've figured out how many lost packets there are in the lower
				// half of the map. Increment our counters.
				fStats[x].fNumOutOfOrderPackets -= halfSeqNumMap - numPackets;
				fStats[x].fNumLostPackets += halfSeqNumMap - numPackets;
				fStats[x].fWrapSeqNum += halfSeqNumMap;

#if BROADCAST_SESSION_DEBUG
				printf("Got %lu packets for trackID %lu. %lu packets lost, %lu packets out of order\n", fStats[x].fNumPacketsReceived, inTrackID, fStats[x].fNumLostPackets, fStats[x].fNumOutOfOrderPackets);
#endif				
			}
			
			//
			// Track duplicate packets
			if (fStats[x].fSequenceNumberMap[theSeqNum % 100])
				fStats[x].fNumDuplicates++;
				
			fStats[x].fSequenceNumberMap[theSeqNum % 100] = 1;
			theSeqNum = 0;
		}
	}
	Assert(theSeqNum == 0); // We should always find a track with this track ID
}

void BroadcasterSession::AckPackets(UInt32 inTrackIndex, UInt16 inCurSeqNum, Bool16 inCurSeqNumValid)
{
#if 0
	char theRRBuffer[256];
	UInt32	*theWriterStart = (UInt32*)theRRBuffer;
	UInt32	*theWriter = (UInt32*)theRRBuffer;

	// APP PACKET - QoS info
	*(theWriter++) = htonl(0x80CC0000);	
	//*(ia++) = htonl(trk[i].TrackSSRC);
	*(theWriter++) = htonl(0);
	*(theWriter++) = htonl('ack ');
	*(theWriter++) = htonl(0);
	
	SInt16 theSeqNumDifference = inCurSeqNum - fStats[inTrackIndex].fHighestSeqNum;
	
	if (!inCurSeqNumValid)
	{
		theSeqNumDifference = 1;
		inCurSeqNum = fStats[inTrackIndex].fHighestSeqNum;
	}
#if BROADCAST_SESSION_DEBUG
	printf("Highest seq num: %d\n", inCurSeqNum);
#endif
		
	if (theSeqNumDifference > 0)
	{
		*(theWriter++) = htonl(fStats[inTrackIndex].fLastAckedSeqNum + 1);
#if BROADCAST_SESSION_DEBUG
		printf("TrackID: %d Acking: %d\n", fSDPParser.GetStreamInfo(inTrackIndex)->fTrackID, fStats[inTrackIndex].fLastAckedSeqNum + 1);
#endif

		UInt16 maskPosition = fStats[inTrackIndex].fLastAckedSeqNum + 2;
		SInt16 numPacketsInMask = inCurSeqNum - (fStats[inTrackIndex].fLastAckedSeqNum + 2);
		
#if BROADCAST_SESSION_DEBUG
		printf("NumPacketsInMask: %d\n", numPacketsInMask);
#endif
		for (SInt32 y = 0; y < numPacketsInMask; y+=32)
		{
			UInt32 mask = 0;
			for (UInt32 x = 0; x < 32; x++)
			{
				SInt16 offsetFromHighest = fStats[inTrackIndex].fHighestSeqNum - maskPosition;
				mask <<= 1;
	
				if (offsetFromHighest >= 0)
				{
#if BROADCAST_SESSION_DEBUG
					printf("TrackID: %d Acking in mask: %d\n", fSDPParser.GetStreamInfo(inTrackIndex)->fTrackID, maskPosition);
#endif
					mask |= 1;
				}
				else if (maskPosition == inCurSeqNum)
				{
#if BROADCAST_SESSION_DEBUG
					printf("TrackID: %d Acking in mask: %d\n", fSDPParser.GetStreamInfo(inTrackIndex)->fTrackID, inCurSeqNum);
#endif
					mask |= 1;
				}

				maskPosition++;
			}
			
			// We have 1 completed mask. Add it to the packet
			*(theWriter++) = htonl(mask);
		}
		fStats[inTrackIndex].fLastAckedSeqNum = inCurSeqNum;
	}
	else
	{
		// Just ack cur seq num, this is an out of order packet
		*(theWriter++) = htonl(inCurSeqNum);
	}

	//
	// Set the packet length
	UInt16* lenP = (UInt16*)theRRBuffer;
	lenP[1] = htons((theWriter - theWriterStart) - 1); //length in octets - 1
	
	// Send the packet
	Assert(fStats[inTrackIndex].fDestRTCPPort != 0);
	fUDPSocketArray[(inTrackIndex*2)+1]->SendTo(fSocket->GetHostAddr(), fStats[inTrackIndex].fDestRTCPPort, theRRBuffer,
												(theWriter - theWriterStart) * sizeof(UInt32));

	//
	// Update the stats for this track
	fStats[inTrackIndex].fNumAcks++;
#endif
}


void BroadcasterSession::SendReceiverReport()
{
#if 0
	if (fUDPSocketArray == NULL)
		return;
		
	//
	// build the RTCP receiver report.
	char theRRBuffer[256];
	UInt32	*theWriterStart = (UInt32*)theRRBuffer;
	UInt32	*theWriter = (UInt32*)theRRBuffer;

	// RECEIVER REPORT
	*(theWriter++) = htonl(0x81c90007);		// 1 src RR packet
	//*(theWriter++) = htonl(trk[i].rcvrSSRC);
	*(theWriter++) = htonl(0);
	//*(theWriter++) = htonl(trk[i].TrackSSRC);
	*(theWriter++) = htonl(0);
	//if (trk[i].rtp_num_received > 0)
	//	t = ((float)trk[i].rtp_num_lost / (float)trk[i].rtp_num_received) * 256;
	//else
	//	t = 0.0;
	//temp = t;
	//temp = (temp & 0xff) << 24;
	//temp |= (trk[i].rtp_num_received & 0x00ffffff);
	*(theWriter++) = htonl(0);
	//temp = (trk[i].seq_num_cycles & 0xffff0000) | (trk[i].last_seq_num & 0x0000ffff);
	//*(ia++) = toBigEndian_ulong(temp);
	*(theWriter++) = htonl(0);
	*(theWriter++) = 0;							// don't do jitter yet.
	*(theWriter++) = 0;							// don't do last SR timestamp
	*(theWriter++) = 0;							// don't do delay since last SR

	// APP PACKET - QoS info
	*(theWriter++) = htonl(0x80CC000C);	
	//*(ia++) = htonl(trk[i].TrackSSRC);
	*(theWriter++) = htonl(0);
// this QTSS changes after beta to 'qtss'
	*(theWriter++) = htonl('QTSS');
	//*(ia++) = toBigEndian_ulong(trk[i].rcvrSSRC);
	*(theWriter++) = htonl(0);
	*(theWriter++) = htonl(8);			// eight 4-byte quants below
#define RR 0x72720004
#define PR 0x70720004
#define PD 0x70640002
#define PL 0x706C0004
	*(theWriter++) = htonl(RR);
	//unsigned int now, secs;
	//now = microseconds();
	//secs = now - trk[i].last_rtcp_packet_sent_us / USEC_PER_SEC;
	//if (secs)
	//	temp = trk[i].bytes_received_since_last_rtcp / secs;
	//else
	//	temp = 0;
	//*(ia++) = htonl(temp);
	*(theWriter++) = htonl(0);
	*(theWriter++) = htonl(PR);
	//*(ia++) = htonl(trk[i].rtp_num_received);
	*(theWriter++) = htonl(0);
	*(theWriter++) = htonl(PL);
	//*(ia++) = htonl(trk[i].rtp_num_lost);
	*(theWriter++) = htonl(0);
	*(theWriter++) = htonl(PD);
	*(theWriter++) = htonl(0);		// should be a short, but we need to pad to a long for the entire RTCP app packet

#if BROADCAST_SESSION_DEBUG
	printf("Sending receiver reports.\n");
#endif				
	// Send the packet
	for (UInt32 x = 0; x < fSDPParser.GetNumStreams(); x++)
	{
		Assert(fStats[x].fDestRTCPPort != 0);
		fUDPSocketArray[(x*2)+1]->SendTo(fSocket->GetHostAddr(), fStats[x].fDestRTCPPort, theRRBuffer,
															(theWriter - theWriterStart) * sizeof(UInt32));
	}

#endif
}
