/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 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.
 * -------------------------------------------------------------------
 */
/**
 * @file pvmf_media_input_node_outport.cpp
 * @brief Output port for media io interface wrapper node
 */

#ifndef PVMF_MEDIA_INPUT_NODE_OUTPORT_H_INCLUDED
#include "pvmf_media_input_node_outport.h"
#endif
#ifndef PVMF_MEDIA_INPUT_NODE_H_INCLUDED
#include "pvmf_media_input_node.h"
#endif
#ifndef PVMF_FORMAT_TYPE_H_INCLUDED
#include "pvmf_format_type.h"
#endif

#ifndef PVMF_MEDIA_MSG_FORMAT_IDS_H_INCLUDED
#include "pvmf_media_msg_format_ids.h"
#endif
#ifndef PVMF_MEDIA_CMD_H_INCLUDED
#include "pvmf_media_cmd.h"
#endif

#ifndef OSCL_BIN_STREAM_H_INCLUDED
#include "oscl_bin_stream.h"
#endif
#define PVMIO_MEDIADATA_POOLNUM 9

// Logging macros
#define LOG_STACK_TRACE(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, m);
#define LOG_DEBUG(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, m);
#define LOG_ERR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m);
#define LOGDATATRAFFIC(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iDataPathLogger,PVLOGMSG_INFO,m);

////////////////////////////////////////////////////////////////////////////
PvmfMediaInputNodeOutPort::PvmfMediaInputNodeOutPort(PvmfMediaInputNode* aNode, const char* aName)
        : OsclTimerObject(OsclActiveObject::EPriorityNominal, "PvmfMediaInputNodeOutPort")
        , PvmfPortBaseImpl(PVMF_MEDIAIO_NODE_OUTPUT_PORT_TAG
                           //this port handles its own port activity
                           , this, aName)
        , iNode(aNode)
        , iState(PvmfMediaInputNodeOutPort::PORT_STATE_BUFFERING)
        , inum_text_sample(0)
        , imax_num_sample(0)
{
    iNALType = 0;
    iCmdId = 0;
    iMioInfoErrorCmdId = 0;
    AddToScheduler();
    iFormatType = PVMF_MIME_FORMAT_UNKNOWN;
    iPeer = NULL;
    iWriteState = EWriteOK;
    iMediaDataAllocMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (PVMIO_MEDIADATA_POOLNUM));
    iMediaDataMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (PVMIO_MEDIADATA_POOLNUM));
    iMediaDataAlloc = OSCL_NEW(PvmfMediaInputDataBufferAlloc, (iMediaDataAllocMemPool));
    iDataPathLogger = PVLogger::GetLoggerObject("datapath.sourcenode");
#ifdef _TEST_AE_EROR_HANDLING
    iTimeStampJunk = 0x000FFFFF;
#endif
}

////////////////////////////////////////////////////////////////////////////
PvmfMediaInputNodeOutPort::~PvmfMediaInputNodeOutPort()
{
    PvmfPortBaseImpl::ClearMsgQueues();


    if (iMediaDataAlloc != NULL)
    {
        OSCL_DELETE(iMediaDataAlloc);
    }

    if (iMediaDataAllocMemPool)
    {
        iMediaDataAllocMemPool->removeRef();
    }

    if (iMediaDataMemPool)
    {
        iMediaDataMemPool->removeRef();
    }
    iDataPathLogger = NULL;

    // we need to clear the activity handler, since otherwise the PvmfPortBaseImpl destructor
    // ends up calling back onto our HandlePortActivity method, which no longer exists because
    // this objects's destructor has already been called.
    SetActivityHandler(NULL);
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::Start()
{
    iWriteState = EWriteOK;
#ifdef _TEST_AE_ERROR_HANDLING

    if (iNode->iError_Out_Queue_Busy)
    {
        PvmfPortBaseImpl::SetCapacity(EPVIncomingDataQueue, 0);
        PvmfPortBaseImpl::SetReserve(EPVIncomingDataQueue, 0);
        PvmfPortBaseImpl::SetThreshold(EPVIncomingDataQueue, 0);
        PvmfPortBaseImpl::SetCapacity(EPVOutgoingDataQueue, 1);
        PvmfPortBaseImpl::SetReserve(EPVOutgoingDataQueue, 2);
        PvmfPortBaseImpl::SetThreshold(EPVOutgoingDataQueue, 100);
    }
    else
    {
        PvmfPortBaseImpl::SetCapacity(EPVIncomingDataQueue, 0);
        PvmfPortBaseImpl::SetReserve(EPVIncomingDataQueue, 0);
        PvmfPortBaseImpl::SetThreshold(EPVIncomingDataQueue, 0);
        PvmfPortBaseImpl::SetCapacity(EPVOutgoingDataQueue, 10);
        PvmfPortBaseImpl::SetReserve(EPVOutgoingDataQueue, 10);
        PvmfPortBaseImpl::SetThreshold(EPVOutgoingDataQueue, 70);
    }
#else
    PvmfPortBaseImpl::SetCapacity(EPVIncomingDataQueue, 0);
    PvmfPortBaseImpl::SetReserve(EPVIncomingDataQueue, 0);
    PvmfPortBaseImpl::SetThreshold(EPVIncomingDataQueue, 0);
    PvmfPortBaseImpl::SetCapacity(EPVOutgoingDataQueue, 10);
    PvmfPortBaseImpl::SetReserve(EPVOutgoingDataQueue, 10);
    PvmfPortBaseImpl::SetThreshold(EPVOutgoingDataQueue, 70);

#endif
    iState = PvmfMediaInputNodeOutPort::PORT_STATE_STARTED;
    if (iNode->iMediaIOState == PvmfMediaInputNode::MIO_STATE_STARTED)
    {
        RunIfNotReady();
    }
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::MediaIOStarted()
{
    if (iState == PvmfMediaInputNodeOutPort::PORT_STATE_STARTED)
        RunIfNotReady();
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::Pause()
{
    iState = PvmfMediaInputNodeOutPort::PORT_STATE_BUFFERING;
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::Stop()
{
    iWriteState = EWriteOK;
    PvmfPortBaseImpl::ClearMsgQueues();
    iState = PvmfMediaInputNodeOutPort::PORT_STATE_STOPPED;
}

////////////////////////////////////////////////////////////////////////////
PVMFStatus PvmfMediaInputNodeOutPort::Configure(PVMFFormatType aPortProperty,
        OSCL_String* aMime)
{
    if (iConnectedPort)
    {
        // Must disconnect before changing port properties, so return error
        return PVMFFailure;
    }

    iFormatType = aPortProperty;
    iMimeType = *aMime;
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PvmfMediaInputNodeOutPort::Connect(PVMFPortInterface* aPort)
{
    PVMFStatus status = PvmfPortBaseImpl::Connect(aPort);
    if (status != PVMFSuccess)
        return status;

    iMediaInput = iNode->iMediaIOControl->createMediaTransfer(iNode->iMediaIOSession);
    if (iMediaInput)
        iMediaInput->setPeer(this);
    else
        return PVMFFailure;

    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PvmfMediaInputNodeOutPort::PeerConnect(PVMFPortInterface* aPort)
{
    PVMFStatus status = PvmfPortBaseImpl::PeerConnect(aPort);
    if (status != PVMFSuccess)
        return status;

    iMediaInput = iNode->iMediaIOControl->createMediaTransfer(iNode->iMediaIOSession);
    if (iMediaInput)
        iMediaInput->setPeer(this);
    else
        return PVMFFailure;

    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PvmfMediaInputNodeOutPort::Disconnect()
{
    PVMFStatus status = PvmfPortBaseImpl::Disconnect();
    if (status != PVMFSuccess)
        return status;

    iNode->iMediaIOControl->deleteMediaTransfer(iNode->iMediaIOSession, iMediaInput);
    if (iMediaInput)
        iMediaInput->setPeer(0);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PvmfMediaInputNodeOutPort::PeerDisconnect()
{
    PVMFStatus status = PvmfPortBaseImpl::PeerDisconnect();
    if (status != PVMFSuccess)
        return status;

    if (iMediaInput)
        iMediaInput->setPeer(0);
    iNode->iMediaIOControl->deleteMediaTransfer(iNode->iMediaIOSession, iMediaInput);
    return PVMFSuccess;
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::setPeer(PvmiMediaTransfer *aPeer)
{
    iPeer = aPeer;
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::useMemoryAllocators(OsclMemAllocator* write_alloc)
{
    OSCL_UNUSED_ARG(write_alloc);
    OSCL_LEAVE(OsclErrNotSupported);
}

////////////////////////////////////////////////////////////////////////////
PVMFCommandId PvmfMediaInputNodeOutPort::writeAsync(uint8 format_type, int32 format_index,
        uint8* data, uint32 data_len,
        const PvmiMediaXferHeader& data_header_info,
        OsclAny* context)
{
    if (iState == PvmfMediaInputNodeOutPort::PORT_STATE_STOPPED)
    {
        // In stopped state we are not going to accept any buffers
        OsclError::Leave(OsclErrNotReady);
        LOG_DEBUG((0, "Ignoring PvmfMediaInputNodeOutPort::writeAsync"));
        return -1;
    }
    if (iWriteState == EWriteOK)
    {
        if (PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION == format_type)
        {
            switch (format_index)
            {
                    //added for timed text support
                    //here it handles the configuration information for timed text and passes it to the composernode
                case PVMI_MEDIAXFER_FMT_INDEX_FMT_SPECIFIC_INFO:
                {
                    //we expect media input components to use cap-config to provide
                    //fmt specific info
                    LOG_ERR((0, "Fmt Specific Info over WriteAsync Not Supported"));
                    iNode->ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)NULL);
                    OsclError::Leave(OsclErrGeneral);
                }
                break;
                case PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM:
                {
                    SendEndOfTrackCommand(data_header_info);
                    MediaIOStarted();
                    return iCmdId++;
                }
                break;
                case PVMI_MEDIAXFER_FMT_INDEX_INFO_EVENT:
                case PVMI_MEDIAXFER_FMT_INDEX_ERROR_EVENT:
                {
                    OSCL_ASSERT(iNode);
                    OSCL_ASSERT(iMediaInput);
                    if (!data)
                    {
                        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
                                        (0, "PvmfMediaInputNodeOutPort::writeAsync: Error - data is NULL"));
                        OSCL_LEAVE(OsclErrArgument);
                        return -1;
                    }

                    if (data_len != sizeof(PVMFAsyncEvent))
                    {
                        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
                                        (0, "PvmfMediaInputNodeOutPort::writeAsync: Error - data length is not size of PVMFAsyncEvent"));
                        OSCL_LEAVE(OsclErrArgument);
                        return -1;
                    }

                    PVMFAsyncEvent* event = OSCL_STATIC_CAST(PVMFAsyncEvent*, data);
                    iNode->ReportErrorEvent(event->GetEventType(), event->GetEventData());

                    // Not really processing this asynchronously. Just call writeComplete
                    // synchronously
                    iMediaInput->writeComplete(PVMFSuccess, iMioInfoErrorCmdId, context);
                    return iMioInfoErrorCmdId++;
                }
                break;
                default:
                {
                    LOG_ERR((0, "Ignoring Format Index :%d since not supported\n", format_index));
                    iNode->ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)NULL);
                    OsclError::Leave(OsclErrGeneral);
                }
                break;
            }
        }
        // TODO: Handle incoming data here. Create a media data using PvmiMIOSourceDataBufferAlloc::allocate,
        // save the data there, put the media data to outgoing queue.
        // If the port is started, schedule to send in Run
        else if (PVMI_MEDIAXFER_FMT_TYPE_DATA == format_type)
        {
            //if the outgoing queue is full, we can't accept data
            //now.

            if (IsOutgoingQueueBusy())
            {
                iWriteState = EWriteBusy;
                OsclError::Leave(OsclErrBusy);
            }

            // Create new media data buffer
            PVMFSharedMediaDataPtr mediaData;
            int32 err = 0;

            if (iCmdId == 0x7FFFFFFF)
                iCmdId = 0;
#ifdef _TEST_AE_ERROR_HANDLING

            if (data_header_info.stream_id == iNode->iTrackID)
            {
                uint32 ii = 0;
                while (iNode->iChunkCount > 0)
                {
                    uint32 sz = data_len - 5;

                    for (ii = 0; ii <= sz; ii++)
                    {
                        uint8* ptr = data + ii;
                        *ptr = 0;
                    }

                    iNode->iChunkCount--;
                }

            }
#endif
#ifdef _TEST_AE_ERROR_HANDLING
            if (iNode->iError_No_Memory)
            {
                err = OsclErrBusy;
                if (IsAdded())
                {
                    RunIfNotReady();
                }
            }
            else
            {
                OSCL_TRY(err,
                         OsclSharedPtr<PVMFMediaDataImpl> mediaDataImpl = iMediaDataAlloc->allocate(iMediaInput, data,
                                 data_len, iCmdId, context);
                         mediaData = PVMFMediaData::createMediaData(mediaDataImpl, iMediaDataMemPool););
            }
#else
            OSCL_TRY(err,
                     OsclSharedPtr<PVMFMediaDataImpl> mediaDataImpl = iMediaDataAlloc->allocate(iMediaInput, data,
                             data_len, iCmdId, context);
                     mediaData = PVMFMediaData::createMediaData(mediaDataImpl, iMediaDataMemPool););


#endif
            if (err)
            {
                iMediaDataAllocMemPool->notifyfreechunkavailable(*this);
                iWriteState = EWriteBusy;
                OsclError::Leave(OsclErrBusy);
            }
            // Set timestamp
#ifdef _TEST_AE_ERROR_HANDLING

            if ((data_header_info.stream_id == iNode->iErrorTimeStamp.track_no) && (1 == iNode->iErrorTimeStamp.mode))
            {

                if (iTimeStampJunk == 0)
                {
                    iTimeStampJunk = 0x000FFFFF;
                }

                mediaData->setTimestamp(iTimeStampJunk);
                iTimeStampJunk = iTimeStampJunk - 33;
            }
            else if ((data_header_info.stream_id == iNode->iErrorTimeStamp.track_no) && (2 == iNode->iErrorTimeStamp.mode))
            {
                if (data_header_info.timestamp >= iNode->iErrorTimeStamp.duration)
                {
                    mediaData->setTimestamp(0);
                }
            }
            else if ((data_header_info.stream_id == iNode->iErrorTimeStamp.track_no) && (3 == iNode->iErrorTimeStamp.mode))
            {
                mediaData->setTimestamp(0);
            }
            else
            {
                mediaData->setTimestamp(data_header_info.timestamp);
            }
#else
            mediaData->setTimestamp(data_header_info.timestamp);
#endif
            mediaData->setSeqNum(data_header_info.seq_num);
            mediaData->setMediaFragFilledLen(0, data_len);
            mediaData->setStreamID(data_header_info.stream_id);

            if (data_header_info.flags & PVMF_MEDIA_DATA_MARKER_INFO_DURATION_AVAILABLE_BIT)
                mediaData->setDuration(data_header_info.duration);

            LOGDATATRAFFIC((0, "PvmfMediaInputNodeOutPort::writeAsync:"
                            "StreamID=%d, TS=%d, Len=%d, SN=%d, MimeType=%s",
                            data_header_info.stream_id,  data_header_info.timestamp, data_len,
                            data_header_info.seq_num, iMimeType.get_cstr()));
            if ((0 == data_header_info.seq_num) &&
                    ((oscl_strcmp(PVMF_MIME_M4V, iMimeType.get_cstr()) == 0) ||
                     (oscl_strcmp(PVMF_MIME_MPEG4_AUDIO, iMimeType.get_cstr())) == 0))
            {

                OsclMemAllocDestructDealloc<uint8> my_alloc;
                OsclRefCounter* my_refcnt;
                OsclMemoryFragment memfrag;
                memfrag.len = data_header_info.private_data_length;

                uint aligned_refcnt_size = oscl_mem_aligned_size(sizeof(OsclRefCounterSA< OsclMemAllocDestructDealloc<uint8> >));
                uint8* my_ptr = (uint8*) my_alloc.allocate(aligned_refcnt_size + memfrag.len);
                my_refcnt = OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterSA< OsclMemAllocDestructDealloc<uint8> >(my_ptr));
                my_ptr += aligned_refcnt_size;

                memfrag.ptr = data_header_info.private_data_ptr;

                OsclRefCounterMemFrag configinfo(memfrag, my_refcnt, memfrag.len);
                iFormatSpecificInfo = configinfo;
                mediaData->setFormatSpecificInfo(iFormatSpecificInfo);

            }
            // Convert media data to MediaMsg
            PVMFSharedMediaMsgPtr mediaMsg;
            convertToPVMFMediaMsg(mediaMsg, mediaData);
            PVMFStatus status;
#ifdef _TEST_AE_ERROR_HANDLING

            if ((iNode->iErrorTrackID > 0) && (data_header_info.stream_id == (uint32)iNode->iErrorTrackID))
            {
                status = PVMFSuccess;
            }
            else
            {
                status = QueueOutgoingMsg(mediaMsg);
            }
#else
            status = QueueOutgoingMsg(mediaMsg);

#endif
            if (status != PVMFSuccess)
            {
                iNode->ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)status);
                OsclError::Leave(OsclErrGeneral);
            }

            if (iState == PvmfMediaInputNodeOutPort::PORT_STATE_STARTED)
                RunIfNotReady();


            return iCmdId++;
        }
        else
        {
            LOG_DEBUG((0, "Ignoring Format Type :%d since not supported\n", format_type));
            iNode->ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)NULL);
            OsclError::Leave(OsclErrGeneral);
        }
    }
    else
    {
        OsclError::Leave(OsclErrBusy);
    }

    return 0;

}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::writeComplete(PVMFStatus status, PVMFCommandId write_cmd_id, OsclAny* context)
{
    OSCL_UNUSED_ARG(context);
    OSCL_UNUSED_ARG(status);
    OSCL_UNUSED_ARG(write_cmd_id);
    OSCL_LEAVE(OsclErrNotSupported);
}

////////////////////////////////////////////////////////////////////////////
PVMFCommandId PvmfMediaInputNodeOutPort::readAsync(uint8* data, uint32 max_data_len, OsclAny* context,
        int32* formats, uint16 num_formats)
{
    OSCL_UNUSED_ARG(data);
    OSCL_UNUSED_ARG(max_data_len);
    OSCL_UNUSED_ARG(context);
    OSCL_UNUSED_ARG(formats);
    OSCL_UNUSED_ARG(num_formats);
    OSCL_LEAVE(OsclErrNotSupported);
    return -1;
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::readComplete(PVMFStatus status, PVMFCommandId read_cmd_id,
        int32 format_index, const PvmiMediaXferHeader& data_header_info,
        OsclAny* context)
{
    OSCL_UNUSED_ARG(status);
    OSCL_UNUSED_ARG(read_cmd_id);
    OSCL_UNUSED_ARG(format_index);
    OSCL_UNUSED_ARG(data_header_info);
    OSCL_UNUSED_ARG(context);
    OSCL_LEAVE(OsclErrNotSupported);
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::statusUpdate(uint32 status_flags)
{
    OSCL_UNUSED_ARG(status_flags);
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::cancelCommand(PVMFCommandId command_id)
{
    OSCL_UNUSED_ARG(command_id);
    OSCL_LEAVE(OsclErrNotSupported);
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::cancelAllCommands()
{
    OSCL_LEAVE(OsclErrNotSupported);
}

////////////////////////////////////////////////////////////////////////////
//                  PvmiCapabilityAndConfig
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PvmfMediaInputNodeOutPort::setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver)
{
    // Not supported
    OSCL_UNUSED_ARG(aObserver);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PvmfMediaInputNodeOutPort::getParametersSync(PvmiMIOSession session,
        PvmiKeyType identifier,
        PvmiKvp*& parameters,
        int& num_parameter_elements,
        PvmiCapabilityContext context)
{
    LOG_STACK_TRACE((0, "PvmfMediaInputNodeOutPort::getParametersSync"));

    if (!iNode || !iNode->iMediaIOConfig)
    {
        LOG_ERR((0, "PvmfMediaInputNodeOutPort::getParametersSync: Error - Config object for media IO not available"));
        return PVMFFailure;

    }

    return iNode->iMediaIOConfig->getParametersSync(session, identifier, parameters,
            num_parameter_elements, context);
}

////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PvmfMediaInputNodeOutPort::releaseParameters(PvmiMIOSession session,
        PvmiKvp* parameters,
        int num_elements)
{
    LOG_STACK_TRACE((0, "PvmfMediaInputNodeOutPort::releaseParameters"));

    if (!iNode || !iNode->iMediaIOConfig)
    {
        LOG_ERR((0, "PvmfMediaInputNodeOutPort::releaseParameters: Error - Config object for media IO not available"));
        return PVMFFailure;

    }

    return iNode->iMediaIOConfig->releaseParameters(session, parameters, num_elements);
}


////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PvmfMediaInputNodeOutPort::setParametersSync(PvmiMIOSession session, PvmiKvp* parameters,
        int num_elements, PvmiKvp*& ret_kvp)
{
    LOG_STACK_TRACE((0, "PvmfMediaInputNodeOutPort::setParametersSync"));

    if (!iNode || !iNode->iMediaIOConfig)
    {
        LOG_ERR((0, "PvmfMediaInputNodeOutPort::setParametersSync: Error - Config object for media IO not available"));
        ret_kvp = parameters;
        OSCL_LEAVE(OsclErrGeneral);
    }

    iNode->iMediaIOConfig->setParametersSync(session, parameters, num_elements, ret_kvp);
}


////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PvmfMediaInputNodeOutPort::verifyParametersSync(PvmiMIOSession session,
        PvmiKvp* parameters, int num_elements)
{
    LOG_STACK_TRACE((0, "PvmfMediaInputNodeOutPort::verifyParametersSync"));

    if (!iNode || !iNode->iMediaIOConfig)
    {
        LOG_ERR((0, "PvmfMediaInputNodeOutPort::verifyParametersSync: Error - Config object for media IO not available"));
        return PVMFFailure;
    }

    return iNode->iMediaIOConfig->verifyParametersSync(session, parameters, num_elements);
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::Run()
{
    if (iState == PvmfMediaInputNodeOutPort::PORT_STATE_BUFFERING)
        return;

#ifdef _TEST_AE_ERROR_HANDLING
    if (iNode->iError_No_Memory)
    {
        if (iMediaInput && iWriteState == EWriteBusy)
        {
            iWriteState = EWriteOK;
            iMediaInput->statusUpdate(PVMI_MEDIAXFER_STATUS_WRITE);
            iNode->iError_No_Memory = false;
        }
    }
#endif
    if ((OutgoingMsgQueueSize() > 0) && (!IsConnectedPortBusy()))
    {
        //transfer data to connected port.
        PVMFStatus status = Send();
        if (status != PVMFSuccess)
            iNode->ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)status);

        //reschedule as long as there's data queued...
        if (OutgoingMsgQueueSize() > 0
                && !IsConnectedPortBusy())
        {
            RunIfNotReady();
        }

        if (iNode->IsFlushPending())
        {
            if (IncomingMsgQueueSize() == 0 && OutgoingMsgQueueSize() == 0)
                iNode->FlushComplete();
        }
    }
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::HandlePortActivity(const PVMFPortActivity& aActivity)
{
    switch (aActivity.iType)
    {
        case PVMF_PORT_ACTIVITY_CONNECT:
        {
            //get the mimetype
            OsclAny* temp = NULL;
            iConnectedPort->QueryInterface(PVMI_CAPABILITY_AND_CONFIG_PVUUID, temp);
            PvmiCapabilityAndConfig *config = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, temp);

            if (config != NULL)
            {
                int numKvp = 0;
                PvmiKvp* kvpPtr = NULL;
                PVMFStatus status =
                    config->getParametersSync(NULL,
                                              (char*)INPUT_FORMATS_CUR_QUERY, kvpPtr, numKvp, NULL);
                if (status == PVMFSuccess)
                {
                    iFormatType = kvpPtr[0].value.pChar_value;
                    iMimeType = iFormatType.getMIMEStrPtr();
                }
                config->releaseParameters(NULL, kvpPtr, numKvp);
            }
        }
        break;

        case PVMF_PORT_ACTIVITY_DISCONNECT:
            break;

        case PVMF_PORT_ACTIVITY_OUTGOING_MSG:
            //wakeup the AO when the first message arrives.
            if (OutgoingMsgQueueSize() == 1)
                RunIfNotReady();
            break;

        case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY:
            //wakeup the AO when the connected port is
            //ready to accept data again.
            RunIfNotReady();
            break;

        case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_READY:
            if (iMediaInput && (iWriteState == EWriteBusy))
            {
                iWriteState = EWriteOK;
                //let the peer know they can try to write again.
                iMediaInput->statusUpdate(PVMI_MEDIAXFER_STATUS_WRITE);
            }
            break;
        case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_BUSY:
        {
            iWriteState = EWriteBusy;
        }
        break;
        case PVMF_PORT_ACTIVITY_CONNECTED_PORT_BUSY:
            break;
        default:
            break;
    }
}

////////////////////////////////////////////////////////////////////////////
void PvmfMediaInputNodeOutPort::SendEndOfTrackCommand(const PvmiMediaXferHeader& data_header_info)
{
    PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd();

    sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_EOS_FORMAT_ID);

    // Set the timestamp
    sharedMediaCmdPtr->setTimestamp(data_header_info.timestamp);

    // Set the sequence number
    sharedMediaCmdPtr->setSeqNum(data_header_info.seq_num);

    PVMFSharedMediaMsgPtr mediaMsgOut;
    convertToPVMFMediaCmdMsg(mediaMsgOut, sharedMediaCmdPtr);

    PVMFStatus status = QueueOutgoingMsg(mediaMsgOut);
    if (status != PVMFSuccess)
    {
        iNode->ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)status);
        OsclError::Leave(OsclErrGeneral);
    }

    LOGDATATRAFFIC((0, "PvmfMediaInputNodeOutPort::SendEndOfTrackCommand - EOS Sent:"
                    "StreamID=%d, TS=%d, SN=%d, MimeType=%s",
                    data_header_info.stream_id,  data_header_info.timestamp,
                    data_header_info.seq_num, iMimeType.get_cstr()));
}

void PvmfMediaInputNodeOutPort :: freechunkavailable(OsclAny*)
{
    if (iWriteState == EWriteBusy)
    {
        iWriteState = EWriteOK;
        if (IsAdded())
        {
            iMediaInput->statusUpdate(PVMI_MEDIAXFER_STATUS_WRITE);
        }
    }
}
