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

    
*/

#ifndef __BROADCASTER_SESSION__
#define __BROADCASTER_SESSION__


#include "Task.h"

#include "TimeoutTask.h"


#include "RTSPClient.h"
#include "ClientSocket.h"
#include "SDPSourceInfo.h"
#include "UDPSocket.h"
#include "StrPtrLen.h"
#include "OSMutex.h"

class BroadcasterSession : public Task
{
    public:
    
        enum
        {
            kRTSPUDPBroadcasterType             = 0,
            kRTSPTCPBroadcasterType             = 1,
            kRTSPHTTPBroadcasterType            = 2,
            kRTSPHTTPDropPostBroadcasterType    = 3,
            kRTSPReliableUDPBroadcasterType     = 4
        };
        typedef UInt32 BroadcasterType;
    
        BroadcasterSession( UInt32 inAddr, UInt16 inPort, char* inURL,
                        BroadcasterType inBroadcasterType,
                        UInt32 inDurationInSec, UInt32 inStartPlayTimeInSec,
                        UInt32 inRTCPIntervalInSec, UInt32 inOptionsIntervalInSec,
                        UInt32 inHTTPCookie, Bool16 inAppendJunkData, UInt32 inReadInterval,
                        UInt32 inSockRcvBufSize, 
                        StrPtrLen *sdpSPLPtr,
                        char *namePtr,
                        char *passwordPtr,
                        Bool16  deepDebug,
                        Bool16 burst);
        virtual ~BroadcasterSession();
        
        //
        // Signals.
        //
        // Send a kKillEvent to delete this object.
        // Send a kTeardownEvent to tell the object to send a TEARDOWN and abort
        
        enum
        {
            kTeardownEvent = 0x00000100
        };
        
        virtual SInt64 Run();
        
        //
        // States. Find out what the object is currently doing
        enum
        {
            kSendingAnnounce    = 0,
            kSendingSetup       = 1,
            kSendingReceive     = 2,
            kBroadcasting       = 3,
            kSendingTeardown    = 4,
            kDone               = 5
        };
        //
        // Why did this session die?
        enum
        {
            kDiedNormally       = 0,    // Session went fine
            kTeardownFailed     = 1,    // Teardown failed, but session stats are all valid
            kRequestFailed      = 2,    // Session couldn't be setup because the server returned an error
            kBadSDP             = 3,    // Server sent back some bad SDP
            kSessionTimedout    = 4,    // Server not responding
            kConnectionFailed   = 5,    // Couldn't connect at all.
            kDiedWhileBroadcasting  = 6,        // Connection was forceably closed while Broadcasting the movie
            kMemoryError        = 7
        };
        
        //
        // Once this client session is completely done with the TEARDOWN and ready to be
        // destructed, this will return true. Until it returns true, this object should not
        // be deleted. When it does return true, this object should be deleted.
        Bool16  IsDone()        { return fState == kDone; }
        
        //
        // ACCESSORS
    
        RTSPClient*             GetBroadcaster()    { return fRTSPClient; }
        ClientSocket*           GetSocket()         { return fSocket; }
        SDPSourceInfo*          GetSDPInfo()        { return &fSDPParser; }
        UInt32                  GetState()          { return fState; }
        UInt32                  GetDeathState()     { return fDeathState; }
        
        // When this object is in the kDone state, this will tell you why the session died.
        UInt32                  GetReasonForDying() { return fDeathReason; }
        UInt32                  GetRequestStatus()  { return fRTSPClient->GetStatus(); }
        
        // Tells you the total time we were receiving packets. You can use this
        // for computing bit rate
        SInt64                  GetTotalPlayTimeInMsec() { return fTotalPlayTime; }
        
        QTSS_RTPPayloadType     GetTrackType(UInt32 inTrackIndex)
                                    { return fSDPParser.GetStreamInfo(inTrackIndex)->fPayloadType; }
        UInt32                  GetNumPacketsReceived(UInt32 inTrackIndex)
                                    { return fStats[inTrackIndex].fNumPacketsReceived; }
        UInt32                  GetNumBytesReceived(UInt32 inTrackIndex)
                                    { return fStats[inTrackIndex].fNumBytesReceived; }
        UInt32                  GetNumPacketsLost(UInt32 inTrackIndex)
                                    { return fStats[inTrackIndex].fNumLostPackets; }
        UInt32                  GetNumPacketsOutOfOrder(UInt32 inTrackIndex)
                                    { return fStats[inTrackIndex].fNumOutOfOrderPackets; }
        UInt32                  GetNumDuplicates(UInt32 inTrackIndex)
                                    { return fStats[inTrackIndex].fNumDuplicates; }
        UInt32                  GetNumAcks(UInt32 inTrackIndex)
                                    { return fStats[inTrackIndex].fNumAcks; }
        UInt32                  GetNumStreams()
                                    { return fSDPParser.GetNumStreams();}
        UInt32                  GetStreamDestPort(UInt32 inIndex)
                                    { return fStats[inIndex].fDestRTPPort;}
        
        void                    TearDownNow() {fTeardownImmediately = true; this->Signal(Task::kKillEvent);}
        //
        // Global stats
        static UInt32   GetActiveConnections()          { return sActiveConnections; }
        static UInt32   GetBroadcastingConnections()    { return sBroadcastingConnections; }
        static UInt32   GetConnectionAttempts()         { return sTotalConnectionAttempts; }
        char*           GetNextPacket(UInt32 *packetLen, UInt8 *channel);
        OS_Error        SendPacket(char* data, UInt32 len,UInt8 channel);
        OS_Error        SendWaitingPackets();
        
        enum
        {
            kUDPTransportType           = 0,
            kReliableUDPTransportType   = 1,
            kTCPTransportType           = 2
        };
        typedef UInt32 TransportType;

        TransportType       GetTransportType()  { return fTransportType; }
        
        UInt32              GetPacketQLen()     { return fPacketQueue.GetLength(); }
        OSMutex*            GetMutex()      { return &fMutex; }
    private:
    
        enum
        {
            kRawRTSPControlType         = 0,
            kRTSPHTTPControlType        = 1,
            kRTSPHTTPDropPostControlType= 2
        };
        typedef UInt32 ControlType;
        
        
        ClientSocket*   fSocket;    // Connection object
        RTSPClient*     fRTSPClient;    // Manages the client connection
        SDPSourceInfo   fSDPParser; // Parses the SDP in the DESCRIBE response
        TimeoutTask     fTimeoutTask; // Kills this connection in the event the server isn't responding
        
        ControlType     fControlType;
        TransportType   fTransportType;
        UInt32          fDurationInSec;
        UInt32          fStartPlayTimeInSec;
        UInt32          fRTCPIntervalInSec;
        UInt32          fOptionsIntervalInSec;
        
        UInt32          fState;     // For managing the state machine
        UInt32          fDeathState; // state at time of death
        UInt32          fDeathReason;
        UInt32          fNumSetups;
        UDPSocket**     fUDPSocketArray;
        
        SInt64          fPlayTime;
        SInt64          fTotalPlayTime;
        SInt64          fLastRTCPTime;
        
        Bool16          fTeardownImmediately;
        Bool16          fAppendJunk;
        UInt32          fReadInterval;
        UInt32          fSockRcvBufSize;
        Bool16          fBurst;
        UInt32          fBurstTime;
        //
        // Broadcaster stats
        struct TrackStats
        {
            enum
            {
                kSeqNumMapSize = 100,
                kHalfSeqNumMap = 50
            };
        
            UInt16          fDestRTPPort;
            UInt16          fDestRTCPPort;
            UInt32          fNumPacketsReceived;
            UInt32          fNumBytesReceived;
            UInt32          fNumLostPackets;
            UInt32          fNumOutOfOrderPackets;
            UInt32          fNumThrownAwayPackets;
            UInt8           fSequenceNumberMap[kSeqNumMapSize];
            UInt16          fWrapSeqNum;
            UInt16          fLastSeqNum;
            UInt32          fSSRC;
            Bool16          fIsSSRCValid;
            
            UInt16          fHighestSeqNum;
            UInt16          fLastAckedSeqNum;
            Bool16          fHighestSeqNumValid;
            
            UInt32          fNumAcks;
            UInt32          fNumDuplicates;
            
        };
        TrackStats*         fStats;
        
        static  char* fPacket;
        //
        // Global stats
        static UInt32           sActiveConnections;
        static UInt32           sBroadcastingConnections;
        static UInt32           sTotalConnectionAttempts;
        
        //
        // Helper functions for Run()
        void        SetupUDPSockets();
        void        ProcessMediaPacket(char* inPacket, UInt32 inLength, UInt32 inTrackID, Bool16 isRTCP);
        OS_Error    ReadMediaData();
        void        SendReceiverReport();
        void        AckPackets(UInt32 inTrackIndex, UInt16 inCurSeqNum, Bool16 inCurSeqNumValid);

        OSMutex             fMutex;//this data structure is shared!

        struct RTPPacket
        {
            RTPPacket() : fQueueElem(NULL), fData(NULL), fLen(0), fChannel(0),fCount(0){}
            ~RTPPacket() { fData = NULL; fLen = 0; fChannel = 0; }
            void SetEnclosingObject(void *obj) {fQueueElem.SetEnclosingObject(obj);}
            void SetPacketData(char* data, UInt32 len,UInt8 channel) { fData = data; fLen = len; fChannel = channel; }
            OSQueueElem *GetQElement() {return &fQueueElem;}
            OSQueueElem fQueueElem;
            char*   fData;
            UInt32  fLen;
            UInt8   fChannel;
            UInt64  fCount;
        };
        UInt64  fPacketCount;
        OSQueue fPacketQueue;
        
        UInt32 fPacketLen;
        UInt8 fChannel;
//      char* fPacket;
        

};

#endif //__BROADCASTER_SESSION__
