/* ------------------------------------------------------------------
 * Copyright (C) 1998-2010 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
#ifndef PV_2WAY_ENGINE_H_INCLUDED
#define PV_2WAY_ENGINE_H_INCLUDED

#ifndef OSCL_BASE_H_INCLUDED
#include "oscl_base.h"
#endif

#ifndef OSCL_SCHEDULER_AO_H_INCLUDED
#include "oscl_scheduler_ao.h"
#endif

#ifndef OSCL_TIMER_H_INCLUDED
#include "oscl_timer.h"
#endif

#ifndef PVMF_MEDIA_CLOCK_H_INCLUDED
#include "pvmf_media_clock.h"
#endif

#ifndef OSCL_BYTE_ORDER_H_INCLUDED
#include "oscl_byte_order.h"
#endif

#ifndef PV_2WAY_INTERFACE_H_INCLUDED
#include "pv_2way_interface.h"
#endif

#ifndef PV_2WAY_BASIC_INTERFACES_H_INCLUDE
#include "pv_2way_basic_interfaces.h"
#endif

#ifndef PVMF_NODE_INTERFACE_H_INCLUDED
#include "pvmf_node_interface.h"
#endif

#ifndef PVLOGGER_H_INCLUDED
#include "pvlogger.h"
#endif

#ifndef PV_VIDEO_ENCNODE_EXTENSION_H_INCLUDED
#include "pv_video_encnode_extension.h"
#endif

#ifndef PV_2WAY_TEST_EXTENSION_H_INCLUDED
#include "pv_2way_test_extension_interface.h"
#endif

#ifndef OSCL_MUTEX_H_INCLUDED
#include "oscl_mutex.h"
#endif

#ifndef PV_2WAY_CODECSPECIFIER_H_INCLUDED
#include "pv_2way_codecspecifier_interface.h"
#endif




// COMM and Stack related
#ifndef TSCMAIN_H_INCLUDED // Gkl
#include "tscmain.h"
#endif

#define MAX_TX_AUDIO_CODECS_SUPPORTED 2
#define MAX_RX_AUDIO_CODECS_SUPPORTED 2
#define MAX_TX_VIDEO_CODECS_SUPPORTED 3
#define MAX_RX_VIDEO_CODECS_SUPPORTED 3

#define MAX_LOGICAL_CHANNEL_PARAMS 3
#define MAX_PENDING_2WAY_COMMANDS 20
#define MAX_PENDING_2WAY_EVENTS 20 // Gkl
#define MAX_PENDING_2WAY_ERRORS 20 // Gkl
#define MAX_PENDING_2WAY_NODE_COMMANDS 20
#define MAX_2WAY_SOURCESINK 2
#define MAX_SESSION_CHANNELS 4
#define MAX_SESSION_MEDIA_CAPS MAX_SESSION_CHANNELS*2


#if defined (__WINS__)
#define AUDIO_INPUT_FILENAME _STRLIT("c:\\audio_in.if2")
#define AUDIO_OUTPUT_FILENAME _STRLIT("c:\\audio_out.if2")
#else
#define AUDIO_INPUT_FILENAME _STRLIT("e:\\audio_in.if2")
#define AUDIO_OUTPUT_FILENAME _STRLIT("e:\\audio_out.if2")
#endif

#define MAX_AMR_BITRATE 12200
#define MIN_AMR_BITRATE 12200
#define MAX_AUDIO_BITRATE 12200

#define DEFAULT_MIN_IFRAME_REQ_INT 1
#define IFRAME_REQ_TIMERID 1


#define END_SESSION_TIMER_ID 2
#define END_SESSION_TIMER "end_session_timer"
#define END_SESSION_TIMER_FREQUENCY 5
#define END_SESSION_TIMER_VALUE 3
/* End session interval = END_SESSION_TIMER_VALUE * 1000/END_SESSION_TIMER_FREQUENCY */

#define REMOTE_DISCONNECT_TIMER_ID 3
#define REMOTE_DISCONNECT_TIMER "remote_disconnect_timer"
#define REMOTE_DISCONNECT_TIMER_FREQUENCY 5
#define REMOTE_DISCONNECT_TIMER_VALUE 3



#define MAX_VIDEO_BITRATE 40000

#define VIDEO_ENCODER_WIDTH 176
#define VIDEO_ENCODER_HEIGHT 144
#if defined (__WINS__)
#define VIDEO_ENCODER_FRAME_RATE 2
#else
#define VIDEO_ENCODER_FRAME_RATE 7.5
#endif
// TBD ARI: This should be removed when capability exchange between video encoder and video source is implemented
#define VIDEO_INPUT_FRAME_RATE VIDEO_ENCODER_FRAME_RATE
#define VIDEO_ENCODER_BITRATE 42000
#define VIDEO_ENCODER_RVLC 0
#define VIDEO_ENCODER_DATA_PARTITIONING 1
#define VIDEO_ENCODER_I_FRAME_INTERVAL 5
#define VIDEO_ENCODER_RATE_CONTROL PVMFVEN_RATE_CONTROL_CBR
#define VIDEO_ENCODER_INPUT_FORMAT PVMFVEN_INPUT_YUV420
#define VIDEO_ENCODER_SEGMENT_SIZE 256

//Play defaults
#define DEFAULT_PLAY_FROM_FILE_TYPE PVMF_MIME_MPEG4FF
#define DEFAULT_PLAY_FROM_FILE_AUDIO PVMF_MIME_AMR_IETF
#define DEFAULT_PLAY_FROM_FILE_VIDEO PVMF_MIME_YUV420

class CPV2WayDataChannelDatapath;
class PvmfNodesSyncControlInterface;
typedef enum
{
    EPV2WayAudio = 0,
    EPV2WayVideo,
    EPV2WayMuxData
} TPV2WayMediaType;

typedef enum
{
    EPV2WayAudioIn = 0,
    EPV2WayAudioOut,
    EPV2WayVideoIn,
    EPV2WayVideoOut
} TPV2WayPortTagType;


/**
 * TPV2WayCommandType enum
 *
 *  Enumeration of types of commands that can be issued to the pv2way(Used internall by engine).
 *  The comments for each command type specify the possible error codes that can be
 *  returned with the completion of each command.  For details on each command, pls refer the
 *  interface definition
 *
 **/

enum TPV2WayCommandType
{
    /**
     * Indicates completion of the initialization process.   If successful, the terminal
     * should be in the ESetup state.  If failed, the pv2way remains in the
     * Eidle state.  The derived class contains information about which
     * components failed to initialize.
     *
     * The application must wait for this callback after the terminal is instantiated
     * before calling any of the terminal APIs.
     *
     * If it fails, a system-wide error code is returned.
     *
     **/
    PVT_COMMAND_INIT,
    /**
     * Indicates completion of a GetSDKInfoL call. If successful, the reference to the
     * TPVSDKInfo struct passed in will be populated with version information pertaining
     * to the pv2way SDK
     * If it fails, a system-wide error code is returned.
     *
     **/
    PVT_COMMAND_GET_SDK_INFO,
    /**
     * Indicates completion of a GetSDKModuleInfoL call. If successful, the reference to the
     * TPVSDKModuleInfo struct passed in will be populated with version information pertaining
     * to the currently loaded modules
     * If it fails, a system-wide error code is returned.
     *
     **/
    PVT_COMMAND_GET_SDK_MODULE_INFO,
    /**
     * Indicates completion of a GetPV2WayStateL call. If successful, the reference to the
     * TPV2WayState struct passed in will be populated with current state information.
     * If it fails, a system-wide error code is returned.
     *
     **/
    PVT_COMMAND_GET_PV2WAY_STATE,
    /**
     * Indicates that the terminal has released all resources and is in the EIdle
     * state.  It is now ok to de-allocate the terminal.
     * If it fails, a system-wide error code is returned.
     **/
    PVT_COMMAND_RESET,
    /**
     * This indicates the completion status of a previously issued
     * AddDataSourceL command.
     *
     * If successful, the engine will start the source and either start demuxing (COMM source)
     * or, sending media data from the source (mic, camera etc).
     *
     * On failure, a system-wide error code is returned.
     * The application may either re-try AddDataSourceL, or disconnect
     * the call.   The application does not have to call RemoveDataSourceL.
     *
     * Information about the track - codec, bitrate etc.  are provided via the derived
     * class
     **/
    PVT_COMMAND_ADD_DATA_SOURCE,

    /**
     * This  indicates the completion status of a previously issued RemoveMediaSource command.
     *
     * If successful, the track is closed and all resources associated with the track
     * have been released.
     *
     * Once this callback is invoked for a track, the pointer to CPVTrackInfo
     * for the track will be invalid.
     *
     * If it fails, a system-wide error code is returned.
     *
     **/
    PVT_COMMAND_REMOVE_DATA_SOURCE,
    /**
     * This indicates the completion status of a previously issued
     * AddDataSinkL command.  It also provides track information.
     *
     * If successful, the engine will start sending media data to the sink.
     *
     * If it fails, a system-wide error code is returned.
     * The application may either re-try AddDataSinkL, or disconnect
     * the call.   The application does not have to call RemoveMediaSink.
     *
     * Information about the track - codec, bitrate etc.  are provided via the derived
     * class
     **/
    PVT_COMMAND_ADD_DATA_SINK,
    /**
     * Similar to RemoveMediaSource
     **/
    PVT_COMMAND_REMOVE_DATA_SINK,
    /**
     * Indicates completion of a pending Connect command.  If successful,
     * the application can open the media tracks using the AddMediaSource API.
     *
     * If Connnect fails, a system-wide error code is returned.
     * The application can either re-try Connect or de-allocate the terminal.
     * The Phone application does not have to call Disconnect if ConnectComplete is
     * called with a status that indicates failure.
     *
     **/
    PVT_COMMAND_CONNECT,
    /**
     * Indicates completion of a pending Disconnect command.   The terminal
     * transitions from EDisconnecting back to the ESetup state.   The Phone
     * application may now call Connect again or reset and de-allocate the terminal.
     * If it fails, a system-wide error code is returned.
     *
     **/
    PVT_COMMAND_DISCONNECT,

    /**
     * Indicates completion of a pending Pause command.
     *
     **/
    PVT_COMMAND_PAUSE,
    /**
     * Indicates completion of a pending Resume command.
     *
     **/
    PVT_COMMAND_RESUME,
    /**
     * Indicates completion of a pending SetLogAppenderL command.
     *
     **/
    PVT_COMMAND_SET_LOG_APPENDER,
    /**
     * Indicates completion of a pending RemoveLogAppenderL command.
     *
     **/
    PVT_COMMAND_REMOVE_LOG_APPENDER,
    /**
     * Indicates completion of a pending SetLogLevel command.
     *
     **/
    PVT_COMMAND_SET_LOG_LEVEL,
    /**
     * Indicates completion of a pending GetLogLevel command.
     *
     **/
    PVT_COMMAND_GET_LOG_LEVEL,
    /**
     * Indicates completion of QueryInterfaceL command
     *
     **/
    PVT_COMMAND_QUERY_INTERFACE,
    /**
     * Indicates pending Init or Connect commands were cancelled
     *
     **/
    PVT_COMMAND_CANCEL_ALL_COMMANDS,

    /**
     * Indicates TSC stack is reporting that channel is established
     *
     **/
    PVT_ESTABLISH_CHANNEL,
    /**
     * Indicates TSC stack is requesting a frame update
     *
     **/
    PVT_REQUEST_FRAME_UPDATE,
    /**
     * Indicates TSC stack found channel is closed
     *
     **/
    PVT_CHANNEL_CLOSED,
    PVT_LAST_COMMAND
};

class PV2WayChannelData : public HeapBase, PVInterface
{
    public:
        PV2WayChannelData(TPVDirection aDir,
                          TPVChannelId aId,
                          PVCodecType_t aCodec,
                          uint8* aFormatSpecificInfo,
                          uint32 aFormatSpecificInfoLen):
                iDir(aDir),
                iId(aId),
                iCodec(aCodec),
                iFormatSpecificInfoLen(aFormatSpecificInfoLen),
                iRefCounter(1)
        {
            iFormatSpecificInfo = OSCL_ARRAY_NEW(uint8, aFormatSpecificInfoLen);
            for (uint32 ii = 0; ii < aFormatSpecificInfoLen; ++ii)
            {
                iFormatSpecificInfo[ii] = aFormatSpecificInfo[ii];
            }
        }

        ~PV2WayChannelData()
        {
            OSCL_ARRAY_DELETE(iFormatSpecificInfo);
        }
        void addRef()
        {
            iRefCounter++;
        }
        void removeRef()
        {
            if (iRefCounter)
            {
                iRefCounter--;
                if (iRefCounter == 0)
                {
                    OSCL_DELETE(this);
                }
            }
        }
        bool queryInterface(const PVUuid& uuid, PVInterface*& iface)
        {
            OSCL_UNUSED_ARG(uuid);
            OSCL_UNUSED_ARG(iface);
            return false;
        }

        TPVDirection iDir;
        TPVChannelId iId;
        PVCodecType_t iCodec;
        uint8* iFormatSpecificInfo;
        uint32 iFormatSpecificInfoLen;
    private:
        uint32 iRefCounter;
};

class TPV2WayNotificationInfo
{
    public:
        enum TPV2WayNotificationInfoType
        {
            EPV2WayCommandType,
            EPV2WayEventType
        };

        TPV2WayNotificationInfo(TPV2WayNotificationInfoType aType) : notificationType(aType) {};
        virtual ~TPV2WayNotificationInfo() {};

        TPV2WayNotificationInfoType notificationType;
};

class TPV2WayCmdInfo : public TPV2WayNotificationInfo
{
    public:
        TPV2WayCmdInfo() : TPV2WayNotificationInfo(EPV2WayCommandType),
                type(PVT_COMMAND_INIT),
                id(0),
                contextData(NULL),
                status(PVMFSuccess),
                responseData(NULL),
                responseDataSize(0),
                iPvtCmdData(0),
                iPvtCmdDataExt(0)
        {};

        ~TPV2WayCmdInfo() {};

        void Clear()
        {
            type = PVT_COMMAND_INIT;
            id = 0;
            contextData = NULL;
            status = PVMFSuccess;
            responseData = NULL;
            responseDataSize = 0;
            iPvtCmdData = 0;
            iPvtCmdDataExt = 0;
        }

        TPV2WayCommandType type;
        PVCommandId id;
        void *contextData;
        TPVCmnCommandStatus status;
        void* responseData;
        int32 responseDataSize;
        uint32 iPvtCmdData;
        uint32 iPvtCmdDataExt;
};

class TPV2WayEventInfo : public TPV2WayNotificationInfo
{
    public:
        TPV2WayEventInfo() : TPV2WayNotificationInfo(EPV2WayEventType),
                type(PVT_INDICATION_INCOMING_TRACK),
                exclusivePtr(NULL),
                localBufferSize(0)

        {
            oscl_memset(localBuffer, 0, PV_COMMON_ASYNC_EVENT_LOCAL_BUF_SIZE);
        };

        ~TPV2WayEventInfo() {};

        void Clear()
        {
            type = PVT_INDICATION_INCOMING_TRACK;
            exclusivePtr = NULL;
            localBufferSize = 0;
            oscl_memset(localBuffer, 0, PV_COMMON_ASYNC_EVENT_LOCAL_BUF_SIZE);
        }

        TPVTIndicationType type;
        TPVCmnExclusivePtr exclusivePtr;
        uint32 localBufferSize;
        uint8 localBuffer[PV_COMMON_ASYNC_EVENT_LOCAL_BUF_SIZE];
};

/**
 * TPV2WayPortStatus
 *
 * An enumeration of port status
 **/
typedef enum
{
    ENoPort = 0,
    ERequestPort,
    EHasPort,
    EReleasePort
} TPV2WayPortStatus;

typedef enum
{
    START_FUNCTION,
    LEAVE_FUNCTION
} TFunctionLocation;

typedef enum
{
    EA_ADD_DATA_SOURCE,
    EA_REMOVE_DATA_SOURCE,
    EA_ADD_DATA_SINK,
    EA_REMOVE_DATA_SINK,
    EA_PAUSE,
    EA_RESUME

} PV2WayAction;

class CPV2WayPort
{
    public:
        CPV2WayPort() : iPort(NULL),
                iPortStatus(ENoPort),
                iPortCmdId(0)
        {};

        ~CPV2WayPort() {};

        PVMFPortInterface *GetPort()
        {
            return iPort;
        }
        TPV2WayPortStatus GetStatus()
        {
            return iPortStatus;
        }
        PVCommandId GetCmdId()
        {
            return iPortCmdId;
        }

        void SetPort(PVMFPortInterface *aPort)
        {
            if (aPort)
            {
                iPortStatus = EHasPort;
            }
            else
            {
                iPortStatus = ENoPort;
            }
            iPort = aPort;
        }
        void SetStatus(TPV2WayPortStatus aStatus)
        {
            iPortStatus = aStatus;
        }
        void SetCmdId(PVCommandId aId)
        {
            iPortCmdId = aId;
        }

    private:
        PVMFPortInterface *iPort;
        TPV2WayPortStatus iPortStatus;
        PVCommandId iPortCmdId;
};


typedef enum
{
    PV2WAY_NODE_CMD_QUERY_INTERFACE,
    PV2WAY_NODE_CMD_INIT,
    PV2WAY_NODE_CMD_REQUESTPORT,
    PV2WAY_NODE_CMD_PREPARE,
    PV2WAY_NODE_CMD_START,
    PV2WAY_NODE_CMD_PAUSE,
    PV2WAY_NODE_CMD_STOP,
    PV2WAY_NODE_CMD_RELEASEPORT,
    PV2WAY_NODE_CMD_RESET,
    PV2WAY_NODE_CMD_CANCELCMD,
    PV2WAY_NODE_CMD_CANCELALL,
    PV2WAY_NODE_CMD_INVALID,
    PV2WAY_NODE_CMD_SKIP_MEDIA_DATA
}  PV2WayNodeCmdType;

class TPV2WayNodeQueryInterfaceParams
{
    public:
        PVUuid *iUuid;
        PVInterface **iInterfacePtr;
};

class PV2WayNodeInterface
{
    public:
        typedef enum
        {
            NoInterface,
            QueryInterface,
            HasInterface
        } InterfaceState;

        PV2WayNodeInterface() : iState(NoInterface),
                iInterface(NULL),
                iId(0)
        {};

        ~PV2WayNodeInterface() {};

        void Reset()
        {
            iState = NoInterface;
            iInterface = NULL;
            iId = 0;
        }

        InterfaceState iState;
        PVInterface *iInterface;
        PVMFCommandId iId;
};

class MPV2WayNodeCommandObserver
{
    public:
        virtual ~MPV2WayNodeCommandObserver() {};
        virtual void CommandHandler(PV2WayNodeCmdType aType, const PVMFCmdResp& aResponse) = 0;

};

class CPV2WayNodeContextData
{
    public:
        CPV2WayNodeContextData() : iObserver(NULL),
                iNode(NULL),
                iContextData(NULL)
        {};

        void Clear()
        {
            iObserver = NULL;
            iNode = NULL;
            iContextData = NULL;
        }

        MPV2WayNodeCommandObserver *iObserver;
        PVMFNodeInterface   *iNode;
        void *iContextData;
};

class TPV2WayNodeCmdInfo
{
    public:
        TPV2WayNodeCmdInfo() : type(PV2WAY_NODE_CMD_INIT),
                id(0),
                engineCmdInfo(NULL)
        {};

        ~TPV2WayNodeCmdInfo() {};

        void Clear()
        {
            type = PV2WAY_NODE_CMD_INIT;
            id = 0;
            context.Clear();
            engineCmdInfo = NULL;
        }

        PV2WayNodeCmdType type;
        PVMFCommandId id;
        CPV2WayNodeContextData context;
        TPV2WayCmdInfo *engineCmdInfo;
};

class TPV2WayNodeRequestPortParams
{
    public:
        TPV2WayNodeRequestPortParams() : portTag(-1),
                format(PVMF_MIME_FORMAT_UNKNOWN)
        {};

        int32 portTag;
        PVMFFormatType format;
};

class TPV2WayNode
{
    public:
        TPV2WayNode() : iNode(NULL),
                iSessionId(0)
        {};

        TPV2WayNode(PVMFNodeInterface *aNode) : iNode(aNode), iSessionId(0)
        {};


        TPV2WayNode(const TPV2WayNode &aNode) : iNode(aNode.iNode),
                iSessionId(aNode.iSessionId)
        {};

        TPV2WayNode& operator=(const TPV2WayNode& a)
        {
            iNode = a.iNode;
            iSessionId = a.iSessionId;
            return *this;
        }

        void Clear()
        {
            iNode = NULL;
            iSessionId = 0;
        }

        operator PVMFNodeInterface *()
        {
            return iNode;
        }

        PVMFSessionId GetSessionId()
        {
            return iSessionId;
        }

        PVMFNodeInterface *iNode;
        PVMFSessionId iSessionId;
};

class SinkNodeIFList
{
    public:

        SinkNodeIFList() : iSinkNode(NULL)
                , iNodeInterface()

        {};

        ~SinkNodeIFList()
        {};

        SinkNodeIFList(const SinkNodeIFList& aList)
        {
            iSinkNode = aList.iSinkNode;
            iNodeInterface = aList.iNodeInterface;
        };

        void Clear()
        {
            iSinkNode = NULL;
            iNodeInterface.Reset();
        }

        TPV2WayNode* iSinkNode;
        PV2WayNodeInterface iNodeInterface;
};

class PlayFromFileNode;
class CPVDatapathNode;
class CPV2WayDecDataChannelDatapath;
class CPV2WayEncDataChannelDatapath;
class CPV2WayMuxDatapath;
class CPV2WayPreviewDatapath;
class CPV2WayRecDatapath;
class CPV2WayInitDatapath;
class PVCommandStatusObserver;
class PVInformationalEventObserver;
class PVErrorEventObserver;

class MPV2WayNodeConfigurationObserver
{
    public:
        virtual ~MPV2WayNodeConfigurationObserver() {};
        virtual PVMFStatus ConfigureNode(CPVDatapathNode *aNode) = 0;
};

class CPV324m2Way : OsclActiveObject,
        public CPV2WayInterface,
        public PVMFNodeCmdStatusObserver,
        public PVMFNodeInfoEventObserver,
        public PVMFNodeErrorEventObserver,
        public MPV2WayNodeCommandObserver,
        public MPV2WayNodeConfigurationObserver,
        public TSCObserver,
        public OsclTimerObserver,
        public PV2WayTestExtensionInterface
{
    public:
        OSCL_IMPORT_REF static CPV324m2Way *NewL(PVMFNodeInterface* aTsc,
                TPVTerminalType aTerminalType,
                PVCommandStatusObserver* aCmdStatusObserver,
                PVInformationalEventObserver *aInfoEventObserver,
                PVErrorEventObserver *aErrorEventObserver);

        OSCL_IMPORT_REF static void Delete(CPV324m2Way *aTerminal);

        OSCL_IMPORT_REF void LogFunction(const char* aFunctionName,
                                         TFunctionLocation aFunctionLocation, PVMFStatus aStatus = PVMFNotSet);


        PVCommandId GetSDKInfo(PVSDKInfo &aSDKInfo, OsclAny* aContextData = NULL);
        PVCommandId GetSDKModuleInfo(PVSDKModuleInfo &aSDKModuleInfo, OsclAny* aContextData = NULL);
        PVCommandId Init(PV2WayInitInfo& aInitInfo, OsclAny* aContextData = NULL);
        PVCommandId Reset(OsclAny* aContextData = NULL);
        PVCommandId AddDataSource(PVTrackId aChannelId, PVMFNodeInterface& aDataSource, OsclAny* aContextData = NULL);
        PVCommandId RemoveDataSource(PVMFNodeInterface& aDataSource, OsclAny* aContextData = NULL);
        PVCommandId AddDataSink(PVTrackId aChannelId, PVMFNodeInterface& aDataSink, OsclAny* aContextData = NULL);
        PVCommandId RemoveDataSink(PVMFNodeInterface& aDataSink, OsclAny* aContextData = NULL);
        PVCommandId Connect(const PV2WayConnectOptions& aOptions, PVMFNodeInterface* aCommServer = NULL, OsclAny* aContextData = NULL);
        PVCommandId Disconnect(OsclAny* aContextData = NULL);
        PVCommandId GetState(PV2WayState& aState, OsclAny* aContextData = NULL);
        PVCommandId SetLatencyQualityTradeoff(PVMFNodeInterface& aTrack, int32 aTradeoff, OsclAny* aContextData = NULL);
        PVCommandId Pause(PV2WayDirection aDirection, PVTrackId aTrackId, OsclAny* aContextData = NULL);
        PVCommandId Resume(PV2WayDirection aDirection, PVTrackId aTrackId, OsclAny* aContextData = NULL);
        PVCommandId SetLogAppender(const char* aTag, OsclSharedPtr<PVLoggerAppender>& aAppender, OsclAny* aContextData = NULL);
        PVCommandId RemoveLogAppender(const char* aTag, OsclSharedPtr<PVLoggerAppender>& aAppender, OsclAny* aContextData = NULL);
        PVCommandId SetLogLevel(const char* aTag, int32 aLevel, bool aSetSubtree = false, OsclAny* aContextData = NULL);
        PVCommandId GetLogLevel(const char* aTag, int32& aLogInfo, OsclAny* aContextData = NULL);
        PVCommandId QueryInterface(const PVUuid& aUuid, PVInterface*& aInterfacePtr, OsclAny* aContext = NULL);
        PVCommandId CancelAllCommands(OsclAny* aContextData = NULL);

        // from PVMFNodeCmdEventObserver
        void NodeCommandCompleted(const PVMFCmdResp& aResponse);

        // from PVMFNodeInfoEventObserver
        void HandleNodeInformationalEvent(const PVMFAsyncEvent& aEvent);

        // from PVMFNodeErrorEventObserver
        void HandleNodeErrorEvent(const PVMFAsyncEvent& aEvent);

        // from CPV2WayNodeCommandObserver
        void CommandHandler(PV2WayNodeCmdType aType, const PVMFCmdResp& aResponse);

        // from CPV2WayNodeConfigurationObserver
        PVMFStatus ConfigureNode(CPVDatapathNode *aNode);

        //TSC Observer Virtuals
        /* Responses to commands */
        void OutgoingChannelEstablished(TPVChannelId id, PVCodecType_t codec, uint8* fsi, uint32 fsi_len);
        /* Unsolicited indications */
        void ConnectComplete(PVMFStatus status);
        void InternalError();
        /* Requests engine to stop av codecs.  TSC will clean up logical channels by itself */
        void DisconnectRequestReceived();
        OSCL_IMPORT_REF TPVStatusCode IncomingChannel(TPVChannelId aId,
                PVCodecType_t aCodec,
                uint8* aFormatSpecificInfo = NULL, uint32 aFormatSpecificInfoLen = 0);
        void ChannelClosed(TPVDirection direction, TPVChannelId id, PVCodecType_t codec, PVMFStatus status = PVMFSuccess);
        void FinishChannelClosed(TPVDirection direction, TPVChannelId id, PVCodecType_t codec);
        void RequestFrameUpdate(PVMFPortInterface *port);

        // OsclTimerObserver virtuals
        void TimeoutOccurred(int32 timerID, int32 timeoutInfo);
        CPV2WayDataChannelDatapath* GetDataPath(PV2WayDirection Direction,
                                                PVTrackId TrackId);
        CPV2WayDataChannelDatapath* GetDataPath(PV2WayDirection aDirection,
                                                PVMFFormatType aFormatType);
        CPV2WayDataChannelDatapath* GetDataPath(PVMFNodeInterface& aEndPt);
        CPV2WayDataChannelDatapath* GetDataPath(PV2WayDirection aDirection,
                                                PV2WayMediaType aMediaType);

        bool AllChannelsOpened();
        bool Supports(PVMFNodeCapability &capability, PVMFFormatType aFormat, bool isInput = true);
#ifdef MEM_TRACK
        void MemStats();
#endif


        // test extension interface
        bool NegotiatedFormatsMatch(
            Oscl_Vector<FormatCapabilityInfo, OsclMemAllocator>& iInAudFormatCapability,
            Oscl_Vector<FormatCapabilityInfo, OsclMemAllocator>& iOutAudFormatCapability,
            Oscl_Vector<FormatCapabilityInfo, OsclMemAllocator>& iInVidFormatCapability,
            Oscl_Vector<FormatCapabilityInfo, OsclMemAllocator>& iOutVidFormatCapability);
        void addRef();
        void removeRef();
        bool queryInterface(const PVUuid& uuid, PVInterface*& iface);
        bool UsingExternalVideoDecBuffers()
        {
            return iUsingExternalVideoDecBuffers;
        }
        bool UsingExternalAudioDecBuffers()
        {
            return iUsingExternalAudioDecBuffers;
        }


    private:
        CPV324m2Way();
        ~CPV324m2Way();

        void ConstructL(PVMFNodeInterface* aTsc,
                        TPVTerminalType aType,
                        PVCommandStatusObserver* aCmdStatusObserver,
                        PVInformationalEventObserver *aInfoEventObserver,
                        PVErrorEventObserver *aErrorEventObserver);
        void SetDefaults();

        void CreateTSCNode();

        void SetInitInfo(OsclAny* aContextData);
        void SetCancelInfo(OsclAny* aContextData);
        void SetResetInfo(OsclAny* aContextData);

        bool AnyNodeStillAdded(Oscl_Vector<TPV2WayNode*, OsclMemAllocator> aNodes);
        bool ProperStateForAction(PV2WayAction aAction);

        void PreInit();
        // OsclActiveObject virtuals
        void DoCancel();
        void Run();
        void Dispatch(TPV2WayCmdInfo* aCmdInfo);
        void Dispatch(TPV2WayEventInfo* aEventInfo);
        void SetState(PV2WayState aState)
        {
            iLastState = iState;
            iState = aState;
        }
        bool ChannelClosed(CPV2WayDataChannelDatapath* aDatapath,
                           TPVChannelId aId);

        void InitiateDisconnect();
        void InitiateReset();
        void CheckState();
        void CheckInit();
        void CheckConnect();
        void CheckDisconnect();
        void CheckReset();

        void RemoveAudioDecPath();
        void RemoveAudioEncPath();
        void RemoveVideoDecPath();
        void RemoveVideoEncPath();

        void HandleCommNodeCmd(PV2WayNodeCmdType aType, const PVMFCmdResp& aResponse);
        void HandleTscNodeCmd(PV2WayNodeCmdType aType, const PVMFCmdResp& aResponse);
        void HandleVideoDecNodeCmd(PV2WayNodeCmdType aType, const PVMFCmdResp& aResponse);
        void HandleVideoEncNodeCmd(PV2WayNodeCmdType aType, const PVMFCmdResp& aResponse);
        void HandleAudioEncNodeCmd(PV2WayNodeCmdType aType, const PVMFCmdResp& aResponse);
        void HandleSinkNodeCmd(PV2WayNodeCmdType aType, const PVMFCmdResp& aResponse, TPV2WayNode* aNode);
        void GenerateIFrame(PVMFPortInterface *aPort);
        void RequestRemoteIFrame(PVMFPortInterface *aPort);

        /**
         * Allows setting pause/resume to logical channel.
         *
         * @param apPort Port that defines the logical channel
         * @param aPause true channel is to be paused, false if resumed
         *
         * @return void
         **/
        void SetChannelPause(PVMFPortInterface *apPort, bool aPause);

        TPV2WayCmdInfo *GetCmdInfoL();
        void FreeCmdInfo(TPV2WayCmdInfo *info);

        TPV2WayEventInfo *GetEventInfoL();
        void FreeEventInfo(TPV2WayEventInfo *info);

        PVMFCommandId SendNodeCmdL(PV2WayNodeCmdType aCmd, TPV2WayNode *aNode,
                                   MPV2WayNodeCommandObserver *aObserver,
                                   void *aParam = NULL, TPV2WayCmdInfo *a2WayCmdInfo = NULL);

        TPV2WayNodeCmdInfo *FindPendingNodeCmd(PVMFNodeInterface *aNode, PVMFCommandId aId);
        void RemovePendingNodeCmd(PVMFNodeInterface *aNode, PVMFCommandId aId, bool aAllCmds = false);

        void FillSDKInfo(PVSDKInfo &aSDKInfo);



        int32 GetStackNodePortTag(TPV2WayPortTagType portType);

        bool CheckMandatoryCodecs(const PVMFFormatType *aMandatoryList, uint32 aMandatorySize, Oscl_Vector<PVMFFormatType, OsclMemAllocator> &aCodecList);

        void InitiateSession(TPV2WayNode& aNode);

        void SetPreferredCodecs(PV2WayInitInfo& aInitInfo);

        void SelectPreferredCodecs(TPVDirection aDir,
                                   Oscl_Vector<PVMFFormatType, OsclMemAllocator>& aAppAudioFormats,
                                   Oscl_Vector<PVMFFormatType, OsclMemAllocator>& aAppVideoFormats);


        PVMFFormatType FindFormatType(PVMFFormatType aFormatType,
                                      Oscl_Vector<PVMFFormatType, OsclMemAllocator>& aAudioFormats,
                                      Oscl_Vector<PVMFFormatType, OsclMemAllocator>& aVideoFormats);
        bool IsSupported(const PVMFFormatType& aInputFmtType,
                         const PVMFFormatType& aOutputFmtType);

        const char* CanConvertFormat(TPVDirection aDir,
                                     PVMFFormatType aThisFmtType,
                                     Oscl_Vector<PVMFFormatType, OsclMemAllocator>& aThatFormatList);
        void CreateVideoOutgoingDatapath(TPV2WayCmdInfo* apCmd,
                                         TPV2WayNode& aNode,
                                         CPVDatapathNode aDatapathnode,
                                         CPV2WayDataChannelDatapath* apDatapath);
        void CreateAudioOutgoingDatapath(TPV2WayCmdInfo* apCmd,
                                         TPV2WayNode& aNode,
                                         CPVDatapathNode aDatapathnode,
                                         CPV2WayDataChannelDatapath* apDatapath);
        void CreateVideoIncomingDatapath(TPV2WayCmdInfo* apCmd,
                                         TPV2WayNode& aNode,
                                         CPVDatapathNode aDatapathnode,
                                         CPV2WayDataChannelDatapath* apDatapath);
        void CreateAudioIncomingDatapath(TPV2WayCmdInfo* apCmd,
                                         TPV2WayNode& aNode,
                                         CPVDatapathNode aDatapathnode,
                                         CPV2WayDataChannelDatapath* apDatapath);

        void DoSelectFormat(TPVDirection aDir,
                            PVMFFormatType aFormatType,
                            const char* aFormatStr,
                            TPVPriority aPriority,
                            PVMFFormatType aFormatApp = PVMF_MIME_FORMAT_UNKNOWN);

        void DoAddDataSource(TPV2WayNode& aNode, const PVMFCmdResp& aResponse);

        void DoAddDataSourceTscNode(CPVDatapathNode& datapathnode,
                                    CPV2WayDataChannelDatapath* datapath,
                                    TPV2WayCmdInfo *cmd);
        void DoAddDataSourceNode(TPV2WayNode& aNode,
                                 CPVDatapathNode& datapathnode,
                                 CPV2WayDataChannelDatapath* datapath);

        void DoAddAudioEncNode(CPVDatapathNode& datapathnode,
                               CPV2WayDataChannelDatapath* datapath);
        void DoAddVideoEncNode(CPVDatapathNode& datapathnode,
                               CPV2WayDataChannelDatapath* datapath);

        void DoAddDataSink(TPV2WayNode& aNode, const PVMFCmdResp& aResponse);
        void DoAddDataSinkTscNode(CPVDatapathNode& datapathnode,
                                  CPV2WayDataChannelDatapath* datapath,
                                  TPV2WayCmdInfo *cmd);
        void DoAddDataSinkNodeForH263_M4V(TPV2WayNode& aNode,
                                          CPVDatapathNode& datapathnode,
                                          CPV2WayDataChannelDatapath* datapath);
        void DoAddDataSinkNodeForAVC(TPV2WayNode& arNode,
                                     CPVDatapathNode& arDatapathnode,
                                     CPV2WayDataChannelDatapath* datapath);
        void DoAddDataSinkGeneric(TPV2WayNode& aNode,
                                  CPVDatapathNode& datapathnode,
                                  CPV2WayDataChannelDatapath* apDatapath);
        void DoAddVideoDecNode(CPVDatapathNode& datapathnode,
                               CPV2WayDataChannelDatapath* apDatapath);
        void DoAddAudioDecNode(CPVDatapathNode& datapathnode,
                               CPV2WayDataChannelDatapath* apDatapath);

        PVCommandId DoRemoveDataSourceSink(PVMFNodeInterface& aEndPt, OsclAny* aContextData);

        bool IsFormatSupported(Oscl_Vector<PVMFFormatType, OsclMemAllocator> aCapability,
                               CPV2WayDataChannelDatapath& aDatapath);
        bool IsNodeInList(Oscl_Vector<TPV2WayNode*, OsclMemAllocator>& aList, PVMFNodeInterface* aNode);

        bool IsSourceNode(PVMFNodeInterface* aNode);

        bool IsSinkNode(PVMFNodeInterface* aNode);
        bool IsDecDatapath(CPV2WayDataChannelDatapath* apDatapath);
        bool IsEncDatapath(CPV2WayDataChannelDatapath* apDatapath);
        bool IsVideoDatapath(CPV2WayDataChannelDatapath* apDatapath);
        bool IsAudioDatapath(CPV2WayDataChannelDatapath* apDatapath);
        TPV2WayCmdInfo* GetAndSetCmdInfo(TPV2WayCommandType aType,
                                         PV2WayDirection aDirection,
                                         PVTrackId aTrackId,
                                         OsclAny* apContextData);
        TPV2WayCmdInfo* GetAndSetCmdInfo(TPV2WayCommandType aType,
                                         PVTrackId aTrackId,
                                         OsclAny* apContextData);
        TPV2WayCmdInfo* GetAndSetCmdInfo(TPV2WayCommandType aType,
                                         OsclAny* apContextData);


        TPV2WayNode* GetTPV2WayNode(Oscl_Vector<TPV2WayNode*, OsclMemAllocator>& aList, PVMFNodeInterface* aNode);

        TPV2WayNode* RemoveTPV2WayNode(Oscl_Vector<TPV2WayNode*, OsclMemAllocator>& aList, PVMFNodeInterface* aNode);

        bool IsNodeReset(PVMFNodeInterface& aNode);

        void SupportedSinkNodeInterfaces(TPV2WayNode* aNode);
        typedef PV2WayRegFormatTypeCompare<OsclMemAllocator> pvmf_format_type_key_compare_class;

        bool NegotiatedFormatsMatch(
            Oscl_Vector<FormatCapabilityInfo, OsclMemAllocator>& aInFormatCapability,
            Oscl_Map < PVMFFormatType, FormatCapabilityInfo,
            OsclMemAllocator, pvmf_format_type_key_compare_class > & aFormats);

        void ConvertMapToVector(Oscl_Map<PVMFFormatType, FormatCapabilityInfo, OsclMemAllocator, pvmf_format_type_key_compare_class>& aCodecs, Oscl_Vector<FormatCapabilityInfo, OsclMemAllocator>& aFormatCapability);

        void AddVideoEncoderNode();
        void AddAudioEncoderNode();
        void AddVideoDecoderNode();
        void AddAudioDecoderNode();

        /**
         * This function configures the video encoder node.
         * Setting for the video encoder are fetched from the channel.
         *
         * @return PVMFStatus returns PVMFSuccess if succesful.
         **/
        PVMFStatus ConfigureVideoEncoderNode();

        void ClearVideoEncoderNode();
        void CloseDatapathTSCPorts();

        void SendClosingTrackIndication(TPVDirection aDirection,
                                        TPVChannelId aId);
        void SendClosedTrackIndication(TPVDirection aDirection,
                                       TPVChannelId aId);

        bool GetEventInfo(TPV2WayEventInfo*& aprEvent);
        static int32 Construct(CPV324m2Way* aRet,
                               PVMFNodeInterface* aTsc,
                               TPVTerminalType aTerminalType,
                               PVCommandStatusObserver* aCmdStatusObserver,
                               PVInformationalEventObserver *aInfoEventObserver,
                               PVErrorEventObserver *aErrorEventObserver);

        void GetStackSupportedFormats();
        PVMFStatus EstablishChannel(TPVDirection aDir,
                                    TPVChannelId aId,
                                    PVCodecType_t aCodec,
                                    uint8* fsi, uint32 fsi_len);

        void StartClock();
        void StartTscClock();
        int32 SkipMediaData(PvmfNodesSyncControlInterface& aNodeSyncCtrl,
                            TPV2WayNode* aNode,
                            TPV2WayNodeCmdInfo& aInfo);

#ifdef PV_USE_DSP_AMR_CODECS
        void InitializeDsp();
        void ReleaseDsp();
        CPVDsp* iDsp; // owned.
#endif // PV_USE_DSP_AMR_CODECS

        // Loopback mode
        TPVLoopbackMode iLoopbackMode;

        // Current state
        PV2WayState iState;
        PV2WayState iLastState;

        // Command status observer
        PVCommandStatusObserver* iCmdStatusObserver;

        // Observer for informational messages
        PVInformationalEventObserver *iInfoEventObserver;

        // Observer for errors
        PVErrorEventObserver *iErrorEventObserver;

        /* For milestone 2, we will not use the proxy framework.  This will be replaced for Milestone 3 */
        Oscl_Vector<TPV2WayNotificationInfo*, BasicAlloc> iPendingNotifications;

        PVCommandId iCommandId;

        PVUuid iCapConfigPVUuid;

        Oscl_Vector<PVUuid, OsclMemAllocator> iSipMgrNodeUuidVec;

        // Video data path
        CPV2WayEncDataChannelDatapath *iVideoEncDatapath;
        CPV2WayDecDataChannelDatapath *iVideoDecDatapath;

        // Audio data path
        CPV2WayEncDataChannelDatapath *iAudioEncDatapath;
        CPV2WayDecDataChannelDatapath *iAudioDecDatapath;

        // COMM Datapath
        bool iIsStackConnected;
        CPV2WayMuxDatapath *iMuxDatapath;
        TPV2WayNode iTscNode;
        TSC* iTscNodePtr;
        TPV2WayNode iCommNode;

        TPV2WayNode iAudioSinkNode;
        TPV2WayNode iAudioSrcNode;


        TPV2WayNode iVideoEncNode;
        PV2WayNodeInterface iVideoEncNodeInterface;

        TPV2WayNode iVideoDecNode;


        TPV2WayNode iAudioEncNode;
        TPV2WayNode iAudioDecNode;
        PV2WayNodeInterface iAudioEncNodeInterface;

        PV2WayNodeInterface iClockSyncInterface;

        Oscl_Vector<SinkNodeIFList, OsclMemAllocator> iSinkNodeList;

        Oscl_Vector<TPV2WayNode*, OsclMemAllocator> iSourceNodes;
        Oscl_Vector<TPV2WayNode*, OsclMemAllocator> iSinkNodes;

        PVUuid iSyncControlPVUuid;

        Oscl_Vector<TPV2WayCmdInfo *, BasicAlloc> iFreeCmdInfo;
        TPV2WayCmdInfo iCmdInfo[MAX_PENDING_2WAY_COMMANDS];

        Oscl_Vector<TPV2WayEventInfo *, BasicAlloc> iFreeEventInfo;
        TPV2WayEventInfo iEventInfo[MAX_PENDING_2WAY_EVENTS];

        Oscl_Vector<TPV2WayNodeCmdInfo *, BasicAlloc> iFreeNodeCmdInfo;
        Oscl_Vector<TPV2WayNodeCmdInfo *, BasicAlloc> iPendingNodeCmdInfo;
        TPV2WayNodeCmdInfo iNodeCmdInfo[MAX_PENDING_2WAY_NODE_COMMANDS];

        // pending Init info
        TPV2WayCmdInfo *iInitInfo;

        // pending Connect info
        TPV2WayCmdInfo *iConnectInfo;

        // Is a disconnect pending ?
        TPV2WayCmdInfo *iDisconnectInfo;

        // Is a reset pending ?
        TPV2WayCmdInfo *iResetInfo;

        // Is a cancel pending ?
        TPV2WayCmdInfo *iCancelInfo;

        // Is a get session params call pending ?
        TPV2WayCmdInfo *iSessionParamsInfo;

        PVLogger *iLogger;


        //Minimum time between making successive I frame requests (sec).
        uint32 iMinIFrameRequestInterval;
        OsclTimer<OsclMemAllocator> iIFrameReqTimer;
        OsclTimer<OsclMemAllocator>* iEndSessionTimer;
        OsclTimer<OsclMemAllocator>* iRemoteDisconnectTimer;
        bool isIFrameReqTimerActive;

        Oscl_Vector<H324ChannelParameters, PVMFTscAlloc> iIncomingChannelParams;
        Oscl_Map < PVMFFormatType, FormatCapabilityInfo,
        OsclMemAllocator, pvmf_format_type_key_compare_class > iIncomingAudioCodecs;
        Oscl_Map < PVMFFormatType, FormatCapabilityInfo,
        OsclMemAllocator, pvmf_format_type_key_compare_class > iIncomingVideoCodecs;
        Oscl_Map < PVMFFormatType, FormatCapabilityInfo,
        OsclMemAllocator, pvmf_format_type_key_compare_class > iOutgoingAudioCodecs;
        Oscl_Map < PVMFFormatType, FormatCapabilityInfo,
        OsclMemAllocator, pvmf_format_type_key_compare_class > iOutgoingVideoCodecs;

        Oscl_Vector<FormatCapabilityInfo, OsclMemAllocator> iFormatCapability;

        /* A list of formats supported by the stack in a certain order of priority.  This list should ideally come from the stack but
        for now we can generate it internally in the engine and later we will have an API for the stack to return it.
        For the current version, the list would look like this:
        {AMR, Mpeg-4, H.263}
        */
        Oscl_Map<PVMFFormatType, CPvtMediaCapability*, OsclMemAllocator, pvmf_format_type_key_compare_class> iStackSupportedFormats;
        /* App Format is the format of the Node/MIO that the application needs to pass in for an incoming/outgoing datapath.
           These maps track which application formats are expected by the engine for formats(codecs) supported by the engine
           for the current call.
           */
        Oscl_Map<PVMFFormatType, PVMFFormatType, OsclMemAllocator, pvmf_format_type_key_compare_class> iAppFormatForEngineFormatIncoming;
        Oscl_Map<PVMFFormatType, PVMFFormatType, OsclMemAllocator, pvmf_format_type_key_compare_class> iAppFormatForEngineFormatOutgoing;

        Oscl_Vector<FormatCapabilityInfo, OsclMemAllocator> iIncomingUserInputFormats;
        Oscl_Vector<H324ChannelParameters, PVMFTscAlloc> iOutgoingChannelParams;
        int32 iIncomingAudioTrackTag;
        int32 iIncomingVideoTrackTag;
        int32 iOutgoingAudioTrackTag;
        int32 iOutgoingVideoTrackTag;
        PVUuid iVideoEncPVUuid;
        PVUuid iVideoEncCCPVUudd;
        PVUuid iAudioEncPVUuid;
        PVMFCommandId iVideoEncQueryIntCmdId;
        PVMFCommandId iOmxEncQueryIntCmdId;

        typedef enum
        {
            File2WayIdle,
            File2WayInitializing,
            File2WayInitialized,
            File2WayResetting
        } File2WayState;



        /* Common clock to be shared with nodes that support the PvmfNodesSyncControlInterface interface */
        PVMFMediaClock iClock;
        PVMFMediaClock iMuxClock;
        PVMFTimebase_Tickcount iTickCountTimeBase;

        friend class CPV2WayCmdControlDatapath;
        friend class CPV2WayDatapath;
        friend class CPV2WayDataChannelDatapath;
        friend class CPV2WayDecDataChannelDatapath;
        friend class CPV2WayEncDataChannelDatapath;
        friend class CPV2WayMuxDatapath;

        TSC *iTSCInterface;
        TSC_324m *iTSC324mInterface;

        TPVTerminalType iTerminalType;

        int32 iPendingTscReset;
        int32 iPendingAudioEncReset;
        int32 iPendingVideoEncReset;

        /* The AddDataSource command for video will be pending untill the extension interface for the encoder is queried and the
            encoder is configured */
        TPV2WayCmdInfo *iAddDataSourceVideoCmd;

        int32 iReferenceCount;

        // this mutex is used to lock all of the data when writing to it
        // and also locked when attempting to read the data through the
        // test interface (which will be another thread)
        OsclMutex iReadDataLock;

        // interface for omx enc node capability and config
        PvmiCapabilityAndConfig* ipEncNodeCapabilityAndConfig;
        PVInterface* ipEncNodeCapConfigInterface;

        bool iUsingExternalVideoDecBuffers;
        bool iUsingExternalAudioDecBuffers;
};

#endif

