blob: 890a94c5b62bb072d7492e525d72a620991a061b [file] [log] [blame]
/* ------------------------------------------------------------------
* 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.
* -------------------------------------------------------------------
*/
#ifndef OSCL_BYTE_ORDER_H_INCLUDED
#include "oscl_byte_order.h"
#endif
#ifndef OSCL_SOCKET_H_INCLUDED
#include "oscl_socket.h"
#endif
#ifndef OSCL_SOCKET_TYPES_H_INCLUDED
#include "oscl_socket_types.h"
#endif
#ifndef OSCL_STRING_UTILS_H_INCLUDED
#include "oscl_string_utils.h"
#endif
#ifndef OSCL_SNPRINTF_H_INCLUDED
#include "oscl_snprintf.h"
#endif
#ifndef PVRTSP_CLIENT_ENGINE_NODE_H
#include "pvrtsp_client_engine_node.h"
#endif
#ifndef PVRTSP_CLIENT_ENGINE_UTILS_H
#include "pvrtsp_client_engine_utils.h"
#endif
#ifndef PVMF_SIMPLE_MEDIA_BUFFER_H_INCLUDED
#include "pvmf_simple_media_buffer.h"
#endif
#ifndef PVMF_BASIC_ERRORINFOMESSAGE_H_INCLUDED
#include "pvmf_basic_errorinfomessage.h"
#endif
#ifndef PVMF_ERRORINFOMESSAGE_EXTENSION_H_INCLUDED
#include "pvmf_errorinfomessage_extension.h"
#endif
#ifndef PVMF_SM_NODE_EVENTS_H_INCLUDED
#include "pvmf_sm_node_events.h"
#endif
#ifndef PVMF_MEDIA_MSG_HEADER_H_INCLUDED
#include "pvmf_media_msg_header.h"
#endif
#ifndef PVMF_SM_TUNABLES_H_INCLUDED
#include "pvmf_sm_tunables.h"
#endif
#ifndef BASE64_CODEC_H_INCLUDED
#include "base64_codec.h"
#endif
#ifndef PV_STRING_URI_H_INCLUDE
#include "pv_string_uri.h"
#endif
#ifndef PVRTSP_ENGINE_NODE_EXTENSION_INTERFACE_IMPL_H_INCLUDED
#include "pvrtspenginenodeextensioninterface_impl.h"
#endif
/*
#ifndef PV_PLAYER_SDKINFO_H_INCLUDED //\engines\player\src\pv_player_sdkinfo.h
#include "pv_player_sdkinfo.h"
#endif
*/
////////////////////////////////////////////////////////////////////////////////
const int PVRTSPEngineNode::REQ_SEND_SOCKET_ID = 1;
const int PVRTSPEngineNode::REQ_RECV_SOCKET_ID = 2;
OSCL_EXPORT_REF PVRTSPEngineNode::PVRTSPEngineNode(int32 aPriority) :
OsclTimerObject(aPriority, "PVRTSPEngineNode"),
iState(PVRTSP_ENGINE_NODE_STATE_IDLE),
iCurrentCmdId(0),
iSockServ(NULL),
iSocketCleanupState(ESocketCleanup_Idle),
iRTSPParser(NULL),
iRTSPParserState(RTSPParser::WAITING_FOR_DATA),
iOutgoingSeq(0),
bNoRecvPending(false),
bNoSendPending(false),
iTheBusyPort(NULL),
iLogger(NULL),
iExtensionRefCount(0),
iNumRedirectTrials(PVRTSPENGINENODE_DEFAULT_NUMBER_OF_REDIRECT_TRIALS),
iNumHostCallback(0),
iNumConnectCallback(0),
iNumSendCallback(0),
iNumRecvCallback(0),
BASE_REQUEST_ID(0),
REQ_TIMER_WATCHDOG_ID(0),
REQ_TIMER_KEEPALIVE_ID(0),
REQ_DNS_LOOKUP_ID(0),
DEFAULT_RTSP_PORT(554),
DEFAULT_HTTP_PORT(80),
TIMEOUT_CONNECT_AND_DNS_LOOKUP(30000),
TIMEOUT_SEND(3000),
TIMEOUT_RECV(-1),
TIMEOUT_SHUTDOWN(30000),
TIMEOUT_WATCHDOG(20),
TIMEOUT_WATCHDOG_TEARDOWN(2),
TIMEOUT_KEEPALIVE(PVRTSPENGINENODE_DEFAULT_KEEP_ALIVE_INTERVAL),
RECOMMENDED_RTP_BLOCK_SIZE(1400),
setupTrackIndex(0),
bRepositioning(false),// \todo reset the reqplayrange to invalid after get the PLAY resp
iSrvResponse(NULL),
bSrvRespPending(false),
iWatchdogTimer(NULL),
iCurrentErrorCode(PVMFRTSPClientEngineNodeErrorEventStart),
iEventUUID(PVMFRTSPClientEngineNodeEventTypeUUID),
bKeepAliveInPlay(false),
iKeepAliveMethod(METHOD_OPTIONS),
bAddXStrHeader(false),
iErrorRecoveryAttempt(0),
iGetPostCorrelationObject(NULL),
ibIsRealRDT(false),
ipRealChallengeGen(NULL),
ipRdtParser(NULL),
ipFragGroupAllocator(NULL),
ipFragGroupMemPool(NULL),
ibBlockedOnFragGroups(false),
iExtensionInterface(NULL)
{
int32 err;
OSCL_TRY(err,
//Create the input command queue. Use a reserve to avoid lots of
//dynamic memory allocation.
iPendingCmdQueue.Construct(PVMF_RTSP_ENGINE_NODE_COMMAND_ID_START, PVMF_RTSP_ENGINE_NODE_COMMAND_VECTOR_RESERVE);
//Create the "current command" queue. It will only contain one
//command at a time, so use a reserve of 1.
iRunningCmdQueue.Construct(0, 1);
//Create the port vector.
iPortVector.Construct(PVMF_RTSP_NODE_PORT_VECTOR_RESERVE);
iPortActivityQueue.reserve(PVMF_RTSP_ENGINE_NODE_COMMAND_VECTOR_RESERVE);
//Set the node capability data.
//This node can support one duplex port.
iCapability.iCanSupportMultipleInputPorts = false;
iCapability.iCanSupportMultipleOutputPorts = false;
iCapability.iHasMaxNumberOfPorts = true;
iCapability.iMaxNumberOfPorts = 1;
iEntityMemFrag.len = 0;
iEntityMemFrag.ptr = NULL;
iRTSPEngTmpBuf.len = 0;
iRTSPEngTmpBuf.ptr = OSCL_MALLOC(RTSP_MAX_FULL_REQUEST_SIZE);
OsclError::LeaveIfNull(iRTSPEngTmpBuf.ptr);
iRTSPEngTmpBuf.len = RTSP_MAX_FULL_REQUEST_SIZE;
iWatchdogTimer = OSCL_NEW(OsclTimer<PVRTSPEngineNodeAllocator>, ("PVRTSPEngineNodeWatchDog"));
OsclError::LeaveIfNull(iWatchdogTimer);
//TBD
//iMediaDataResizableAlloc =OSCL_NEW(OsclMemPoolResizableAllocator, (RECOMMENDED_RTP_BLOCK_SIZE, 0, 0, &iAlloc));;
iMediaDataResizableAlloc = OSCL_NEW(OsclMemPoolResizableAllocator, (RECOMMENDED_RTP_BLOCK_SIZE));
OsclError::LeaveIfNull(iMediaDataResizableAlloc);
iMediaDataImplAlloc = OSCL_NEW(PVMFSimpleMediaBufferCombinedAlloc, (iMediaDataResizableAlloc));;
OsclError::LeaveIfNull(iMediaDataImplAlloc);
);
if (err != OsclErrNone)
{
//if a leave happened, cleanup and re-throw the error
iPendingCmdQueue.clear();
iRunningCmdQueue.clear();
iPortVector.clear();
iCapability.iInputFormatCapability.clear();
iCapability.iOutputFormatCapability.clear();
OSCL_CLEANUP_BASE_CLASS(PVMFNodeInterface);
OSCL_CLEANUP_BASE_CLASS(OsclTimerObject);
OSCL_LEAVE(err);
}
iWatchdogTimer->SetObserver(this);
iWatchdogTimer->SetFrequency(1);
iInterfaceState = EPVMFNodeCreated;
}
OSCL_EXPORT_REF PVRTSPEngineNode::~PVRTSPEngineNode()
{
Cancel();
if (iExtensionInterface)
{
iExtensionInterface->removeRef();
}
if (iWatchdogTimer)
{
OSCL_DELETE(iWatchdogTimer);
iWatchdogTimer = NULL;
}
if (iRTSPEngTmpBuf.len > 0)
{
OSCL_FREE(iRTSPEngTmpBuf.ptr);
iRTSPEngTmpBuf.len = 0;
iRTSPEngTmpBuf.ptr = NULL;
}
if (iEntityMemFrag.len > 0)
{
OSCL_FREE(iEntityMemFrag.ptr);
iEntityMemFrag.len = 0;
iEntityMemFrag.ptr = NULL;
}
if (iSrvResponse)
{
OSCL_DELETE(iSrvResponse);
iSrvResponse = NULL;
}
if (iRTSPParser)
{
OSCL_DELETE(iRTSPParser);
iRTSPParser = NULL;
}
if (iMediaDataImplAlloc != NULL)
{
OSCL_DELETE(iMediaDataImplAlloc);
}
if (iMediaDataResizableAlloc != NULL)
{
iMediaDataResizableAlloc->removeRef();
}
clearOutgoingMsgQueue();
resetSocket(true);
if (iDNS.iDns)
{
iDNS.iDns->~OsclDNS();
iAlloc.deallocate(iDNS.iDns);
iDNS.iDns = NULL;
}
if (iSockServ)
{
iSockServ->Close();
iSockServ->~OsclSocketServ();
iAlloc.deallocate(iSockServ);
iSockServ = NULL;
}
if (ipFragGroupAllocator != NULL)
OSCL_DELETE(ipFragGroupAllocator);
if (ipFragGroupMemPool != NULL)
OSCL_DELETE(ipFragGroupMemPool);
if (iGetPostCorrelationObject != NULL)
{
OSCL_DELETE(iGetPostCorrelationObject);
iGetPostCorrelationObject = NULL;
}
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::ThreadLogon()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::ThreadLogon() called"));
switch (iInterfaceState)
{
case EPVMFNodeCreated:
if (!IsAdded())
AddToScheduler();
iLogger = PVLogger::GetLoggerObject("PVRTSPEngineNode");
SetState(EPVMFNodeIdle);
return PVMFSuccess;
// break; This break statement was removed to avoid compiler warning for Unreachable Code
default:
return PVMFErrInvalidState;
// break; This break statement was removed to avoid compiler warning for Unreachable Code
}
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::ThreadLogoff()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::ThreadLogoff() called"));
switch (iInterfaceState)
{
case EPVMFNodeIdle:
if (IsAdded())
RemoveFromScheduler();
iLogger = NULL;
SetState(EPVMFNodeCreated);
return PVMFSuccess;
// break; This break statement was removed to avoid compiler warning for Unreachable Code
default:
return PVMFErrInvalidState;
// break; This break statement was removed to avoid compiler warning for Unreachable Code
}
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetCapability(PVMFNodeCapability& aNodeCapability)
{
OSCL_UNUSED_ARG(aNodeCapability);
return PVMFFailure;
}
OSCL_EXPORT_REF PVMFPortIter* PVRTSPEngineNode::GetPorts(const PVMFPortFilter* aFilter)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::GetPorts() called"));
OSCL_UNUSED_ARG(aFilter);
// TODO: Return the currently available ports
return NULL;
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::QueryUUID(PVMFSessionId aSession
, const PvmfMimeString& aMimeType
, Oscl_Vector<PVUuid, PVRTSPEngineNodeAllocator>& aUuids
, bool aExactUuidsOnly
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::QueryUUID() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_QUERYUUID, aMimeType, \
aUuids, aExactUuidsOnly, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF void PVRTSPEngineNode::addRef()
{
}
OSCL_EXPORT_REF void PVRTSPEngineNode::removeRef()
{
}
OSCL_EXPORT_REF bool PVRTSPEngineNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::QueryInterface() In iExtensionInterface %x", iExtensionInterface));
iface = NULL;
if (uuid == KPVRTSPEngineNodeExtensionUuid)
{
if (!iExtensionInterface)
{
iExtensionInterface = OSCL_NEW(PVRTSPEngineNodeExtensionInterfaceImpl, (this));
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::QueryInterface() iExtensionInterface %x", iExtensionInterface));
}
if (iExtensionInterface)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::QueryInterface() Interface existing iExtensionInterface %x", iExtensionInterface));
return (iExtensionInterface->queryInterface(uuid, iface));
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::queryInterface()- ERROR No memory"));
OSCL_LEAVE(OsclErrNoMemory);
return false;
}
}
else
{
return false;
}
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::QueryInterface(PVMFSessionId aSession
, const PVUuid& aUuid
, PVInterface*& aInterfacePtr
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::QueryInterface() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_QUERYINTERFACE, aUuid, aInterfacePtr, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::RequestPort(PVMFSessionId aSession
, int32 aPortTag
, const PvmfMimeString* aPortConfig
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::RequestPort() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_REQUESTPORT, aPortTag, aPortConfig, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::ReleasePort(PVMFSessionId aSession
, PVMFPortInterface& aPort
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::ReleasePort() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_RELEASEPORT, aPort, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::Init(PVMFSessionId aSession
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Init() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_INIT, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::Prepare(PVMFSessionId aSession
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Init() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_PREPARE, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::Start(PVMFSessionId aSession
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Start() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_START, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::Pause(PVMFSessionId aSession
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Pause() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_PAUSE, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::Stop(PVMFSessionId aSession
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Stop() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_STOP, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::Reset(PVMFSessionId aSession
, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Reset() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_RESET, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::Flush(PVMFSessionId aSession, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Flush() called"));
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_FLUSH, aContext);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::CancelCommand(PVMFSessionId aSession
, PVMFCommandId aCmdId
, const OsclAny* aContextData)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::CancelCommand() called"));
//OSCL_LEAVE(OsclErrNotSupported);
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_CANCELCOMMAND, aCmdId, aContextData);
return AddCmdToQueue(cmd);
}
OSCL_EXPORT_REF PVMFCommandId PVRTSPEngineNode::CancelAllCommands(PVMFSessionId aSession
, const OsclAny* aContextData)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::CancelAllCommands() called"));
//OSCL_LEAVE(OsclErrNotSupported);
PVRTSPEngineCommand cmd;
cmd.PVRTSPEngineCommandBase::Construct(aSession, PVMF_GENERIC_NODE_CANCELALLCOMMANDS, aContextData);
return AddCmdToQueue(cmd);
}
//************ end PVMFNodeInterface
//************ begin PVRTSPEngineNodeExtensionInterface
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetStreamingType(PVRTSPStreamingType aType)
{
iSessionInfo.iStreamingType = aType;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetSessionURL(OSCL_wString& aURL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SetSessionURL() called"));
if (iInterfaceState == EPVMFNodeIdle)
{
if (parseURL(aURL))
{
iSessionInfo.bExternalSDP = false;
return PVMFSuccess;
}
}
iSessionInfo.iSessionURL = "";
return PVMFFailure;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetRtspProxy(OSCL_String& aRtspProxyName, uint32 aRtspProxyPort)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SetRtspProxy() aRtspProxy %s %d", aRtspProxyName.get_cstr(), aRtspProxyPort));
//If proxy is in use, both the name and the port have to be set.
if ((0 == aRtspProxyName.get_size())
|| (0 == aRtspProxyPort)
|| (iInterfaceState != EPVMFNodeIdle))
{
return PVMFFailure;
}
{
iSessionInfo.iProxyName = aRtspProxyName;
iSessionInfo.iProxyPort = aRtspProxyPort;
return PVMFSuccess;
}
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetRtspProxy(OSCL_String& aRtspProxyName, uint32& aRtspProxyPort)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::GetRtspProxy() RtspProxy %s %d", iSessionInfo.iProxyName.get_cstr(), iSessionInfo.iProxyPort));
aRtspProxyName = iSessionInfo.iProxyName;
aRtspProxyPort = iSessionInfo.iProxyPort;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetSDPInfo(OsclSharedPtr<SDPInfo>& aSDPinfo, Oscl_Vector<StreamInfo, PVRTSPEngineNodeAllocator> &aSelectedStream)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SetSDPInfo() called"));
if ((iInterfaceState == EPVMFNodePrepared) ||
(iInterfaceState == EPVMFNodeInitialized) ||
(iInterfaceState == EPVMFNodeIdle))
{
if (iState == PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE)
{
iSessionInfo.bExternalSDP = false;
}
else if (iState == PVRTSP_ENGINE_NODE_STATE_IDLE)
{
iSessionInfo.bExternalSDP = true;
}
else
{
return PVMFErrInvalidState;
}
iSessionInfo.iSDPinfo = aSDPinfo;
iSessionInfo.iSelectedStream = aSelectedStream;
if (iSessionInfo.bExternalSDP)
{
//set the server address
const char *servURL = (aSDPinfo->getSessionInfo())->getControlURL();
uint32 servURLLen = oscl_strlen(servURL);
if (servURLLen >= iRTSPEngTmpBuf.len)
{
//we do not support URLs larger than RTSP_MAX_FULL_REQUEST_SIZE
//iRTSPEngTmpBuf.len is initialized to RTSP_MAX_FULL_REQUEST_SIZE
return PVMFFailure;
}
oscl_memset(iRTSPEngTmpBuf.ptr, 0, iRTSPEngTmpBuf.len);
oscl_strncpy((mbchar*)iRTSPEngTmpBuf.ptr, servURL, servURLLen);
if (!parseURL((mbchar*)iRTSPEngTmpBuf.ptr))
{
return PVMFFailure;
}
}
return PVMFSuccess;
}
return PVMFErrInvalidState;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetSDP(OsclRefCounterMemFrag& aSDPMemFrag)
{
aSDPMemFrag = iSessionInfo.pSDPBuf;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetServerInfo(PVRTSPEngineNodeServerInfo& aServerInfo)
{
aServerInfo.iServerName = iSessionInfo.iServerName;
aServerInfo.iIsPVServer = iSessionInfo.pvServerIsSetFlag;
aServerInfo.iRoundTripDelayInMS = iSessionInfo.roundTripDelay;
aServerInfo.iServerVersionNumber = iSessionInfo.iServerVersionNumber;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetStreamInfo(Oscl_Vector<StreamInfo, PVRTSPEngineNodeAllocator> &aSelectedStream)
{
aSelectedStream = iSessionInfo.iSelectedStream;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetUserAgent(OSCL_wString& aUserAgent)
{
uint32 tmpSize = iSessionInfo.iUserAgent.get_size();
tmpSize += 8;
int32 err;
oscl_wchar *tmpBuf = NULL;
OSCL_TRY(err, tmpBuf = OSCL_ARRAY_NEW(oscl_wchar, (tmpSize)););
if ((err != OsclErrNone) || (tmpBuf == NULL))
{
return PVMFFailure;
}
if (0 == oscl_UTF8ToUnicode(iSessionInfo.iUserAgent.get_cstr(), iSessionInfo.iUserAgent.get_size(), (oscl_wchar*)tmpBuf, (tmpSize*sizeof(oscl_wchar))))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
aUserAgent = tmpBuf;
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetClientParameters(OSCL_wString& aUserAgent,
OSCL_wString& aUserNetwork,
OSCL_wString& aDeviceInfo)
{
uint32 tmpSize = aUserAgent.get_size();
if (tmpSize < aUserNetwork.get_size())
{
tmpSize = aUserNetwork.get_size();
}
if (tmpSize < aDeviceInfo.get_size())
{
tmpSize = aDeviceInfo.get_size();
}
tmpSize += 8;
int32 err;
uint8 *tmpBuf = NULL;
OSCL_TRY(err, tmpBuf = OSCL_ARRAY_NEW(uint8, (tmpSize)););
if ((err != OsclErrNone) || (tmpBuf == NULL))
{
return PVMFFailure;
}
if (aUserAgent.get_size() > 0)
{
if (0 == oscl_UnicodeToUTF8(aUserAgent.get_cstr(), aUserAgent.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
//\engines\player\src\pv_player_sdkinfo.h
//#define PVPLAYER_ENGINE_SDKINFO_LABEL "PVPLAYER 04.07.00.01"
//iSessionInfo.iUserAgent = PVPLAYER_ENGINE_SDKINFO_LABEL;
iSessionInfo.iUserAgent += (char*)tmpBuf;
//iSessionInfo.iUserAgent = (char*)tmpBuf;
}
if (aUserNetwork.get_size() > 0)
{
if (0 == oscl_UnicodeToUTF8(aUserNetwork.get_cstr(), aUserNetwork.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
iSessionInfo.iUserNetwork = (char*)tmpBuf;
}
if (aDeviceInfo.get_size() > 0)
{
if (0 == oscl_UnicodeToUTF8(aDeviceInfo.get_cstr(), aDeviceInfo.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
iSessionInfo.iDeviceInfo = (char*)tmpBuf;
}
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFSuccess;
}
OSCL_EXPORT_REF bool PVRTSPEngineNode::IsRdtTransport()
{
return ibIsRealRDT;
}
OSCL_EXPORT_REF void PVRTSPEngineNode::SetPortRdtStreamId(PVMFPortInterface* pPort,
int iRdtStreamId)
{
((PVMFRTSPPort*)pPort)->iRdtStreamId = iRdtStreamId;
}
OSCL_EXPORT_REF void PVRTSPEngineNode::SetRealChallengeCalculator(IRealChallengeGen* pChallengeCalc)
{
ipRealChallengeGen = pChallengeCalc;
}
OSCL_EXPORT_REF void PVRTSPEngineNode::SetRdtParser(IPayloadParser* pRdtParser)
{
ipRdtParser = pRdtParser;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetAuthenticationParameters(OSCL_wString& aUserID,
OSCL_wString& aAuthentication,
OSCL_wString& aExpiration,
OSCL_wString& aApplicationSpecificString,
OSCL_wString& aVerification,
OSCL_wString& aSignature)
{
uint32 tmpSize = aUserID.get_size();
if (tmpSize < aAuthentication.get_size())
{
tmpSize = aAuthentication.get_size();
}
if (tmpSize < aExpiration.get_size())
{
tmpSize = aExpiration.get_size();
}
if (tmpSize < aApplicationSpecificString.get_size())
{
tmpSize = aApplicationSpecificString.get_size();
}
if (tmpSize < aVerification.get_size())
{
tmpSize = aVerification.get_size();
}
if (tmpSize < aSignature.get_size())
{
tmpSize = aSignature.get_size();
}
tmpSize += 8;
int32 err;
uint8 *tmpBuf = NULL;
OSCL_TRY(err, tmpBuf = OSCL_ARRAY_NEW(uint8, (tmpSize)););
if ((err != OsclErrNone) || (tmpBuf == NULL))
{
return PVMFFailure;
}
if (0 == oscl_UnicodeToUTF8(aUserID.get_cstr(), aUserID.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
iSessionInfo.iUserID = (char*)tmpBuf;
if (0 == oscl_UnicodeToUTF8(aAuthentication.get_cstr(), aAuthentication.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
iSessionInfo.iAuthentication = (char*)tmpBuf;
if (0 == oscl_UnicodeToUTF8(aExpiration.get_cstr(), aExpiration.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
iSessionInfo.iExpiration = (char*)tmpBuf;
if (0 == oscl_UnicodeToUTF8(aApplicationSpecificString.get_cstr(), aApplicationSpecificString.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
iSessionInfo.iApplicationSpecificString = (char*)tmpBuf;
if (0 == oscl_UnicodeToUTF8(aVerification.get_cstr(), aVerification.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
iSessionInfo.iVerification = (char*)tmpBuf;
if (0 == oscl_UnicodeToUTF8(aSignature.get_cstr(), aSignature.get_size(), (char*)tmpBuf, tmpSize))
{
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFFailure;
}
iSessionInfo.iSignature = (char*)tmpBuf;
OSCL_ARRAY_DELETE(tmpBuf);
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetRequestPlayRange(const RtspRangeType& aRange)
{
if (aRange.format == RtspRangeType::NPT_RANGE)
{//only accept npt for now.
iSessionInfo.iReqPlayRange = aRange;
iSessionInfo.iActPlayRange.format = RtspRangeType::INVALID_RANGE;
if (PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE == iState)
{
bRepositioning = true;
}
return PVMFSuccess;
}
return PVMFFailure;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetActualPlayRange(RtspRangeType& aRange)
{
aRange = iSessionInfo.iActPlayRange;
if (iSessionInfo.iActPlayRange.format == RtspRangeType::INVALID_RANGE)
{
return PVMFFailure;
}
return PVMFSuccess;
}
//************ end PVRTSPEngineNodeExtensionInterface
//************ begin OsclSocketObserver
OSCL_EXPORT_REF void PVRTSPEngineNode::HandleSocketEvent(int32 aId, TPVSocketFxn aFxn, TPVSocketEvent aEvent, int32 aError)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::HandleSocketEvent() In aId=%d, aFxn=%d, aEvent=%d, aError=%d", aId, aFxn, aEvent, aError));
//update socket container state.
//note we only update iRecvSocket container when it's a unique socket.
SocketContainer* container;
switch (aId)
{
case REQ_RECV_SOCKET_ID:
container = &iRecvSocket;
break;
case REQ_SEND_SOCKET_ID:
container = &iSendSocket;
break;
default:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::HandleSocketEvent() ERROR invalid aId=%d", aId));
return;
}
//clear the appropriate cmd pending & canceled flags.
switch (aFxn)
{
case EPVSocketConnect:
container->iConnectState.Reset();
OSCL_ASSERT(iNumConnectCallback > 0);
iNumConnectCallback--;
break;
case EPVSocketRecv:
container->iRecvState.Reset();
OSCL_ASSERT(iNumRecvCallback > 0);
iNumRecvCallback--;
break;
case EPVSocketSend:
container->iSendState.Reset();
OSCL_ASSERT(iNumSendCallback > 0);
iNumSendCallback--;
break;
case EPVSocketShutdown:
container->iShutdownState.Reset();
break;
default:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::HandleSocketEvent() ERROR invalid aFxn=%d", aFxn));
return;
}
if (!IsAdded())
{//prevent the leave 49. should never get here
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::HandleSocketEvent() ERROR line %d", __LINE__));
return;
}
//For socket cleanup sequence including Stop & Reset command
if (iSocketCleanupState != ESocketCleanup_Idle)
{
RunIfNotReady();
return;
}
//save info
SocketEvent tmpSockEvent;
tmpSockEvent.iSockId = aId;
tmpSockEvent.iSockFxn = aFxn;
tmpSockEvent.iSockEvent = aEvent;
tmpSockEvent.iSockError = aError;
if (aFxn == EPVSocketRecv)
{
bNoRecvPending = true;
if (EPVSocketSuccess == aEvent)
{
int32 incomingMessageLen;
uint8* recvData = iRecvSocket.iSocket->GetRecvData(&incomingMessageLen);
OSCL_UNUSED_ARG(recvData);
#ifdef MY_RTSP_DEBUG
{
const uint32 dbgBufSize = 256;
uint8* dbgBuf = OSCL_ARRAY_NEW(uint8, dbgBufSize);
if (dbgBuf) oscl_memcpy(dbgBuf, recvData, dbgBufSize - 1);
dbgBuf[dbgBufSize-1] = '\0';
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "C <--- S\n%s", dbgBuf));
OSCL_ARRAY_DELETE(dbgBuf);
}
#endif
if (incomingMessageLen > 0)
{
if (!iRTSPParser->registerDataBufferWritten(incomingMessageLen))
{//parser some kind of error on Engine's part, or Parser's internal inconsistency
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::HandleSocketEvent() registerDataBufferWritten() error"));
iRTSPParser->flush();
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::HandleSocketEvent() In incomingMessageLen=%d", incomingMessageLen));
}
RunIfNotReady();
return; // for recv success, process is done
}
}
else if (aFxn == EPVSocketSend)
{
if (aId == REQ_RECV_SOCKET_ID)
{//clear POST msg
iRecvChannelMsg = "";
}
//TBD using send Q
if ((bSrvRespPending) && (EPVSocketSuccess == aEvent))
{//there is one resp waiting on queue because there was a send() pending
bSrvRespPending = false;
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *iSrvResponse))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::HandleSocketEvent() sendSocketOutgoingMsg() error"));
}
}
else
{
bNoSendPending = true;
if (iSrvResponse)
{
OSCL_DELETE(iSrvResponse);
iSrvResponse = NULL;
}
if (iState == PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE)
{//wait first SETUP response before sending the remaining SETUPs
bNoSendPending = false;
return;//handling of this socketevent is done.
}
}
}
iSocketEventQueue.push_back(tmpSockEvent);
RunIfNotReady();
}
//************ end OsclSocketObserver
//************ begin OsclDNSObserver
OSCL_EXPORT_REF void PVRTSPEngineNode::HandleDNSEvent(int32 aId, TPVDNSFxn aFxn, TPVDNSEvent aEvent, int32 aError)
{
OSCL_UNUSED_ARG(aEvent);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::HandleDNSEvent() In aId=%d, aFxn=%d, aEvent=%d, aError=%d", aId, aFxn, aEvent, aError));
//clear the cmd Pending and Canceled flags
iDNS.iState.Reset();
if (aFxn == EPVDNSGetHostByName)
{
OSCL_ASSERT(iNumHostCallback > 0);
iNumHostCallback--;
}
if (!IsAdded())
{//prevent the leave 49. should never get here
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::HandleDNSEvent() ERROR line %d", __LINE__));
return;
}
//For socket cleanup sequence including Stop & Reset command
if (iSocketCleanupState != ESocketCleanup_Idle)
{
RunIfNotReady();
return;
}
if ((aId == REQ_DNS_LOOKUP_ID) && (aFxn == EPVDNSGetHostByName))
{
{//wrap the DNS event as an socket event
SocketEvent tmpSockEvent;
{//TBD type mismatch
tmpSockEvent.iSockId = aId;
tmpSockEvent.iSockFxn = EPVSocketRecv; //aFxn;
tmpSockEvent.iSockEvent = EPVSocketSuccess; //aEvent;
if (oscl_strlen((const char*)iSessionInfo.iSrvAdd.ipAddr.Str()) == 0)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorDNSLookUpError;
tmpSockEvent.iSockEvent = EPVSocketFailure; //aEvent;
}
tmpSockEvent.iSockError = aError;
}
iSocketEventQueue.push_back(tmpSockEvent);
}
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_CONNECT);
RunIfNotReady();
return;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::HandleDNSEvent() unsolicited event"));
}
//************ end OsclDNSObserver
void PVRTSPEngineNode::Run()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Run() In"));
//Drive the reset sequence
if (iSocketCleanupState != ESocketCleanup_Idle)
{
if (resetSocket() == PVMFPending)
return;//keep waiting on callbacks.
}
//Process commands.
if (iPendingCmdQueue.size() > 0)
{
if (ProcessCommand(iPendingCmdQueue.front()))
{
if (IsAdded())
RunIfNotReady();
return;
}
}
if (iRunningCmdQueue.size() > 0)
{
DispatchCommand(iRunningCmdQueue.front());
if ((iPendingCmdQueue.size() > 0) && IsAdded())
{
RunIfNotReady();
}
}
else
{
if (RTSPParser::REQUEST_IS_READY == iRTSPParserState)
{
PVMFStatus iRet = processIncomingMessage(iIncomingMsg);
if ((iRet != PVMFPending) && (iRet != PVMFSuccess))
{//TBD error handling.
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::Run() ERROR processIncomingMessage(). Ln %d", __LINE__));
//ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_INVALID);
}
}
else if (RTSPParser::ENTITY_BODY_IS_READY == iRTSPParserState)
{//Incoming message also has an entity body
PVMFStatus iRet = processEntityBody(iIncomingMsg, iEntityMemFrag);
if ((iRet != PVMFPending) && (iRet != PVMFSuccess))
{//TBD error handling.
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::Run() ERROR processIncomingMessage(). Ln %d", __LINE__));
//ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_INVALID);
}
}
else if (!clearEventQueue())
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::Run() ERROR Ln %d", __LINE__));
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPSocketConnectError;
//TBD PVMFFailure;
if (iErrorRecoveryAttempt-- <= 0)
{
ChangeExternalState(EPVMFNodeError);
ReportInfoEvent(PVMFInfoStateChanged);
}
else
{
int32 err;
PVRTSPErrorContext* errorContext = NULL;
OSCL_TRY(err, errorContext = OSCL_NEW(PVRTSPErrorContext, ()));
if (err || (errorContext == NULL))
{
ChangeExternalState(EPVMFNodeError);
}
else
{//send error info
errorContext->iErrState = iState;
ReportInfoEvent(PVMFInfoErrorHandlingStart);
partialResetSessionInfo();
clearOutgoingMsgQueue();
PVMFStatus status = resetSocket();
PVRTSPEngineCommand cmd;
//const OsclAny* aContext = OSCL_STATIC_CAST(OsclAny*, errorContext);
//cmd.PVRTSPEngineCommandBase::Construct(aCmd.iSession,PVMF_RTSP_NODE_ERROR_RECOVERY,aContext);
cmd.PVRTSPEngineCommandBase::Construct(0, PVMF_RTSP_NODE_ERROR_RECOVERY, NULL);
cmd.iParam1 = OSCL_STATIC_CAST(OsclAny*, errorContext);
iRunningCmdQueue.AddL(cmd);
if (status != PVMFPending)
RunIfNotReady();
}
}
}
}
if (iInterfaceState == EPVMFNodeStarted || FlushPending())
{
while (!iPortActivityQueue.empty())
{
if (!ProcessPortActivity())
{//error
break;
}
}
}
if (FlushPending() && iPortActivityQueue.empty())
{
//If we get here we did not process any ports or commands.
//Check for completion of a flush command...
SetState(EPVMFNodePrepared);
//resume port input so the ports can be re-started.
for (uint32 i = 0; i < iPortVector.size(); i++)
iPortVector[i]->ResumeInput();
CommandComplete(iRunningCmdQueue, iRunningCmdQueue.front(), PVMFSuccess);
RunIfNotReady();
}
if (rtspParserLoop())
{
RunIfNotReady();
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::Run() Out"));
}
/**
//A routine to tell if a flush operation is in progress.
*/
bool PVRTSPEngineNode::FlushPending()
{
return (iRunningCmdQueue.size() > 0
&& iRunningCmdQueue.front().iCmd == PVMF_GENERIC_NODE_FLUSH);
}
bool PVRTSPEngineNode::ProcessPortActivity()
{//called by the AO to process a port activity message
//Pop the queue...
PVMFPortActivity activity(iPortActivityQueue.front());
iPortActivityQueue.erase(&iPortActivityQueue.front());
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "0x%x PVRTSPEngineNode::ProcessPortActivity: port=0x%x, type=%d",
this, activity.iPort, activity.iType));
PVMFStatus status = PVMFSuccess;
switch (activity.iType)
{
case PVMF_PORT_ACTIVITY_OUTGOING_MSG:
if (NULL == iTheBusyPort)
{
if (activity.iPort->OutgoingMsgQueueSize() > 0)
{
status = ProcessOutgoingMsg(activity.iPort);
//if there is still data, queue another port activity event.
if (status == PVMFSuccess
&& activity.iPort->OutgoingMsgQueueSize() > 0)
{
QueuePortActivity(activity);
}
}
}
break;
case PVMF_PORT_ACTIVITY_INCOMING_MSG:
break;
default:
break;
}
//report a failure in port processing...
if (status != PVMFErrBusy && status != PVMFSuccess)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "0x%x PVRTSPEngineNode::ProcessPortActivity() Error - ProcessPortActivity failed. port=0x%x, type=%d",
this, activity.iPort, activity.iType));
ReportErrorEvent(PVMFErrPortProcessing);
return false;
}
//return true if we processed an activity...
//return (status!=PVMFErrBusy);
return true;
}
/////////////////////////////////////////////////////
PVMFStatus PVRTSPEngineNode::ProcessOutgoingMsg(PVMFPortInterface* aPort)
{
//Called by the AO to process one message off the outgoing
//message queue for the given port. This routine will
//try to send the data to the connected port.
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "0x%x PVRTSPEngineNode::ProcessOutgoingMsg: aPort=0x%x", this, aPort));
PVMFStatus status = aPort->Send();
if (status == PVMFErrBusy)
{
//iTheBusyPort = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "0x%x PVRTSPEngineNode::ProcessOutgoingMsg: Connected port busy", this));
}
return status;
}
/**
//Called by the command handler AO to process a command from
//the input queue.
//Return true if a command was processed, false if the command
//processor is busy and can't process another command now.
*/
bool PVRTSPEngineNode::ProcessCommand(PVRTSPEngineCommand& aInCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::ProcessCommand() in"));
//don't interrupt a cancel command
if (!iCancelCmdQueue.empty())
return false;
if (!iRunningCmdQueue.empty()
&& iRunningCmdQueue.front().iCmd == PVMF_RTSP_NODE_CANCELALLRESET)
return false;
//don't interrupt a running command unless this is hi-priority command
//such as a cancel.
if (iRunningCmdQueue.size() > 0 && !aInCmd.hipri())
return false;
{
//move the command from the pending command queue to the
//running command queue, where it will remain until it completes.
int32 err;
OSCL_TRY(err, iRunningCmdQueue.StoreL(aInCmd););
if (err != OsclErrNone)
{
CommandComplete(iPendingCmdQueue, aInCmd, PVMFErrNoMemory);
return PVMFErrNoMemory;
}
iPendingCmdQueue.Erase(&aInCmd);
}
DispatchCommand(iRunningCmdQueue.front());
return true;
}
PVMFStatus PVRTSPEngineNode::DispatchCommand(PVRTSPEngineCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DispatchCommand() in"));
bool bRevertToPreviousStateImpossible = true;
bool bErrorRecoveryImpossible = true;
PVMFStatus iRet = PVMFFailure;
switch (aCmd.iCmd)
{
case PVMF_GENERIC_NODE_QUERYUUID:
iRet = DoQueryUuid(aCmd);
break;
case PVMF_GENERIC_NODE_INIT:
iRet = DoInitNode(aCmd);
if (iRet == PVMFSuccess)
{
ChangeExternalState(EPVMFNodeInitialized);
}
bErrorRecoveryImpossible = false;
break;
case PVMF_GENERIC_NODE_PREPARE:
iRet = DoPrepareNode(aCmd);
if (iRet == PVMFSuccess)
{
ChangeExternalState(EPVMFNodePrepared);
}
bErrorRecoveryImpossible = false;
break;
case PVMF_GENERIC_NODE_START:
iRet = DoStartNode(aCmd);
if (iRet == PVMFSuccess)
{
ChangeExternalState(EPVMFNodeStarted);
if (bKeepAliveInPlay)
{
//setup the timer for sending keep-alive
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::DispatchCommand() start keep-alive timer %d. Ln %d", TIMEOUT_KEEPALIVE, __LINE__));
iWatchdogTimer->Request(REQ_TIMER_KEEPALIVE_ID, 0, TIMEOUT_KEEPALIVE);
}
}
bErrorRecoveryImpossible = false;
break;
case PVMF_GENERIC_NODE_STOP:
iRet = DoStopNode(aCmd);
if (iRet == PVMFSuccess)
{
ChangeExternalState(EPVMFNodePrepared);
}
bRevertToPreviousStateImpossible = false;
bErrorRecoveryImpossible = false;
break;
case PVMF_GENERIC_NODE_PAUSE:
iRet = DoPauseNode(aCmd);
if (iRet == PVMFSuccess)
{
//setup the timer for sending keep-alive
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::DispatchCommand() start keep-alive timer %d. Ln %d", TIMEOUT_KEEPALIVE, __LINE__));
iWatchdogTimer->Request(REQ_TIMER_KEEPALIVE_ID, 0, TIMEOUT_KEEPALIVE);
ChangeExternalState(EPVMFNodePaused);
}
bRevertToPreviousStateImpossible = false;
bErrorRecoveryImpossible = false;
break;
case PVMF_GENERIC_NODE_RESET:
case PVMF_RTSP_NODE_CANCELALLRESET:
iRet = DoResetNode(aCmd);
if (iRet != PVMFPending)
{
OSCL_DELETE(iRTSPParser);
iRTSPParser = NULL;
partialResetSessionInfo();
ResetSessionInfo();
clearOutgoingMsgQueue();
iRet = resetSocket();
}
break;
case PVMF_GENERIC_NODE_QUERYINTERFACE:
iRet = DoQueryInterface(aCmd);
break;
case PVMF_GENERIC_NODE_CANCELALLCOMMANDS:
iRet = DoCancelAllCommands(aCmd);
break;
case PVMF_GENERIC_NODE_FLUSH:
iRet = DoFlush(aCmd);
break;
case PVMF_GENERIC_NODE_REQUESTPORT:
{
PVMFRTSPPort* aPort = NULL;
iRet = DoRequestPort(aCmd, aPort);
if (iRet == PVMFSuccess)
{
//Return the port pointer to the caller.
CommandComplete(iRunningCmdQueue, aCmd, iRet, (OsclAny*)aPort);
return iRet;
}
}
break;
case PVMF_GENERIC_NODE_RELEASEPORT:
iRet = DoReleasePort(aCmd);
break;
case PVMF_RTSP_NODE_ERROR_RECOVERY:
iRet = DoErrorRecovery(aCmd);
if (iRet != PVMFPending)
{
if ((iRet != PVMFSuccess) && (iErrorRecoveryAttempt-- > 0))
{//retry
partialResetSessionInfo();
clearOutgoingMsgQueue();
iRet = resetSocket();
if (iRet != PVMFPending)
RunIfNotReady();
return PVMFPending;
}
if ((iRet == PVMFSuccess) && (iState == PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE))
{
//setup the timer for sending keep-alive
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::DispatchCommand() start keep-alive timer %d. Ln %d", TIMEOUT_KEEPALIVE, __LINE__));
iWatchdogTimer->Request(REQ_TIMER_KEEPALIVE_ID, 0, TIMEOUT_KEEPALIVE);
ChangeExternalState(EPVMFNodePaused);
ReportInfoEvent(PVMFInfoStateChanged);
}
PVRTSPErrorContext* errorContext = OSCL_STATIC_CAST(PVRTSPErrorContext*, aCmd.iParam1);
if (errorContext)
{
OSCL_DELETE(errorContext);
}
//Erase the cmd from iRunningCmdQueue
iRunningCmdQueue.Erase(&aCmd);
if (iRunningCmdQueue.size() > 0)
{//error happened while servicing an reqeust, resume service
//RunIfNotReady();
aCmd = iRunningCmdQueue.front();
if (iRet == PVMFSuccess)
{
iRet = PVMFPending;
//TBD
//this RunIfNotReady() is only needed when no event pending
// like Prepare() fails in PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE state
RunIfNotReady();
}
}
else
{//do report event
if (iRet != PVMFSuccess)
{
ChangeExternalState(EPVMFNodeError);
ReportInfoEvent(PVMFInfoStateChanged);
}
iRet = PVMFPending; ////internal cmd, no CommandComplete needed
}
ReportInfoEvent(PVMFInfoErrorHandlingComplete);
}
break;
default://unknown command type
iRet = PVMFFailure;
break;
}
if (iRet != PVMFPending)
{
if (iRet != PVMFSuccess)
{
if (bRevertToPreviousStateImpossible)
{
///////////////////////////////////////////////////////////////////////////
//
// Added 5/9/2006 to disable error recovery. Error recovery needs to become
// configurable; until then, we'll disable it
//
//bErrorRecoveryImpossible = true;
///////////////////////////////////////////////////////////////////////////
if ((bErrorRecoveryImpossible) || (iErrorRecoveryAttempt-- <= 0))
{
ChangeExternalState(EPVMFNodeError);
ReportInfoEvent(PVMFInfoStateChanged);
}
else
{
int32 err;
PVRTSPErrorContext* errorContext = NULL;
OSCL_TRY(err, errorContext = OSCL_NEW(PVRTSPErrorContext, ()));
if (err || (errorContext == NULL))
{
iRet = PVMFFailure; // reinitialized since it may be clobbered by OSCL_TRY()
ChangeExternalState(EPVMFNodeError);
}
else
{//send error info
errorContext->iErrState = iState;
ReportInfoEvent(PVMFInfoErrorHandlingStart);
partialResetSessionInfo();
clearOutgoingMsgQueue();
PVMFStatus status = resetSocket();
iState = PVRTSP_ENGINE_NODE_STATE_IDLE;
PVRTSPEngineCommand cmd;
//const OsclAny* aContext = OSCL_STATIC_CAST(OsclAny*, errorContext);
//cmd.PVRTSPEngineCommandBase::Construct(aCmd.iSession,PVMF_RTSP_NODE_ERROR_RECOVERY,aContext);
cmd.PVRTSPEngineCommandBase::Construct(aCmd.iSession, PVMF_RTSP_NODE_ERROR_RECOVERY, NULL);
cmd.iParam1 = OSCL_STATIC_CAST(OsclAny*, errorContext);
iRunningCmdQueue.AddL(cmd);
if (status != PVMFPending)
RunIfNotReady();
return PVMFPending;
}
}
}
if (iCurrentErrorCode != PVMFRTSPClientEngineNodeErrorEventStart)
{
CommandComplete(iRunningCmdQueue, aCmd, iRet, NULL, &iEventUUID, &iCurrentErrorCode);
/* Reset error code */
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorEventStart;
return iRet;
}
}
CommandComplete(iRunningCmdQueue, aCmd, iRet);
}
return iRet;
}
/**
//The various command handlers call this when a command is complete.
*/
void PVRTSPEngineNode::CommandComplete(PVRTSPEngineNodeCmdQ& aCmdQ,
PVRTSPEngineCommand& aCmd,
PVMFStatus aStatus,
OsclAny* aEventData,
PVUuid* aEventUUID,
int32* aEventCode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode:CommandComplete Id %d Cmd %d Status %d Context %d Data %d"
, aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));
//Do special handling of some commands.
switch (aCmd.iCmd)
{
case PVMF_RTSP_NODE_CANCELALLRESET:
//restore command ID
aCmd.iCmd = PVMF_GENERIC_NODE_CANCELALLCOMMANDS;
break;
case PVMF_GENERIC_NODE_RESET:
if (aStatus == PVMFSuccess)
ChangeExternalState(EPVMFNodeIdle);
ThreadLogoff();
break;
case PVMF_GENERIC_NODE_CANCELALLCOMMANDS:
//Add a reset sequence to the end of "Cancel all" processing, in order to
//satisfy the expectation of streaming manager node.
{
//change the command type to "cancelallreset"
aCmd.iCmd = PVMF_RTSP_NODE_CANCELALLRESET;
//move command from cancel command queue to running command queue
//if necessary. we do this because this node is only setup to
//continue processing commands in the running queue.
if (&aCmdQ == &iCancelCmdQueue)
{
iRunningCmdQueue.StoreL(aCmd);
aCmdQ.Erase(&aCmd);
}
RunIfNotReady();
return;
}
default:
break;
}
PVInterface* extif = NULL;
PVMFBasicErrorInfoMessage* errormsg = NULL;
if (aEventUUID && aEventCode)
{
errormsg = OSCL_NEW(PVMFBasicErrorInfoMessage, (*aEventCode, *aEventUUID, NULL));
extif = OSCL_STATIC_CAST(PVInterface*, errormsg);
}
//create response
PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, extif, aEventData);
PVMFSessionId session = aCmd.iSession;
//Erase the command from the queue.
aCmdQ.Erase(&aCmd);
//Report completion to the session observer.
ReportCmdCompleteEvent(session, resp);
if (errormsg)
{
errormsg->removeRef();
}
//There may be a cancel command that was just waiting on the running command to finish.
//If so, complete the cancel command now.
if (&aCmdQ == &iRunningCmdQueue
&& !iCancelCmdQueue.empty())
{
CommandComplete(iCancelCmdQueue, iCancelCmdQueue.front(), PVMFSuccess);
}
}
// Handle command and data events
PVMFCommandId PVRTSPEngineNode::AddCmdToQueue(PVRTSPEngineCommand& aCmd)
{
PVMFCommandId id;
id = iPendingCmdQueue.AddL(aCmd);
//wakeup the AO
RunIfNotReady();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::AddCmdToQueue() Cmd Id %d", id));
return id;
}
void PVRTSPEngineNode::ChangeExternalState(TPVMFNodeInterfaceState aNewState)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::ChangeExternalState() Old %d New %d", iInterfaceState, aNewState));
iInterfaceState = aNewState;
}
void PVRTSPEngineNode::ChangeInternalState(PVRTSPEngineState aNewState)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::ChangeInternalState() Old %d New %d", iState, aNewState));
iState = aNewState;
}
PVMFStatus PVRTSPEngineNode::DoInitNode(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoInitNode() In"));
OSCL_UNUSED_ARG(aCmd);
if (iInterfaceState != EPVMFNodeIdle)
{
return PVMFErrInvalidState;
}
if (bAddXStrHeader)
{
// create iGetPostCorrelationObject
if (!iGetPostCorrelationObject)
{
if ((iGetPostCorrelationObject = GetPostCorrelationObject::create()) == NULL) return PVMFFailure;
}
}
return SendRtspDescribe(aCmd);
}
PVMFStatus PVRTSPEngineNode::SendRtspDescribe(PVRTSPEngineCommand &aCmd)
{
OSCL_UNUSED_ARG(aCmd);
PVMFStatus iRet = PVMFPending;
switch (iState)
{
case PVRTSP_ENGINE_NODE_STATE_IDLE:
{
if (iSockServ == NULL)
{
int32 err;
OSCL_TRY(err, iSockServ = OsclSocketServ::NewL(iAlloc););
if (err || (iSockServ == NULL))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketServerError;
iRet = PVMFFailure;
break;
}
if (iSockServ->Connect() != OsclErrNone)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketServerError;
iRet = PVMFFailure;
break;
}
}
if (!iRTSPParser)
{
iRTSPParser = OSCL_NEW(RTSPParser, ());
if (NULL == iRTSPParser)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPParserError;
iRet = PVMFFailure;
break;
}
}
iRTSPParser->flush();
// 1. Do DNS look up if needed.
OSCL_HeapString<PVRTSPEngineNodeAllocator> endPointName = iSessionInfo.iServerName;
if (iSessionInfo.iProxyName.get_size())
{
iSessionInfo.iSrvAdd.port = iSessionInfo.iProxyPort;
endPointName = iSessionInfo.iProxyName;
}
if (OsclValidInetAddr(endPointName.get_cstr()))
{//ip address
iSessionInfo.iSrvAdd.ipAddr.Set(endPointName.get_cstr());
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_CONNECT);
RunIfNotReady();
}
else
{//dns lookup
if (NULL == iDNS.iDns)
{
REQ_DNS_LOOKUP_ID = ++BASE_REQUEST_ID;
iDNS.iDns = OsclDNS::NewL(iAlloc, *iSockServ, *this, REQ_DNS_LOOKUP_ID);
}
if (iDNS.iDns == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorDNSLookUpError;
iRet = PVMFFailure;
break;
}
iDNS.iState.Reset();
iSessionInfo.iSrvAdd.ipAddr.Set("");
if (EPVDNSPending != iDNS.iDns->GetHostByName(endPointName.get_str(), iSessionInfo.iSrvAdd, TIMEOUT_CONNECT_AND_DNS_LOOKUP))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorDNSLookUpError;
iRet = PVMFFailure;
break;
}
iDNS.iState.iPending = true;
iNumHostCallback++;
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_DNS_RESOLVING);
}
break;
}
case PVRTSP_ENGINE_NODE_STATE_DNS_RESOLVING:
{
break;
}
case PVRTSP_ENGINE_NODE_STATE_CONNECT:
{
if (!clearEventQueue())
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorDNSLookUpError;
iRet = PVMFFailure;
break;
}
{
//Allocate 1 TCP socket and set both iSendSocket and iRecvSocket to that socket.
//Note: in this case we only track the status in the "send" container since
//it's really only one socket.
int32 err;
OsclTCPSocket *sock = NULL;
OSCL_TRY(err, sock = OsclTCPSocket::NewL(iAlloc, *iSockServ, this, REQ_SEND_SOCKET_ID););
if (err || (sock == NULL))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPSocketCreateError;
iRet = PVMFFailure;
break;
}
iRecvSocket.Reset(sock);
iSendSocket.Reset(sock);
//proxy support
//OSCL_StackString<64> tmpServerName = _STRLIT_CHAR("172.16.2.145");
//iSessionInfo.iSrvAdd.ipAddr.Set( tmpServerName.get_cstr() );
TPVSocketEvent sendConnect = iSendSocket.iSocket->Connect(iSessionInfo.iSrvAdd, TIMEOUT_CONNECT_AND_DNS_LOOKUP);
if (sendConnect == EPVSocketPending)
iSendSocket.iConnectState.iPending = true;
if (sendConnect != EPVSocketPending)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPSocketConnectError;
iRet = PVMFFailure;
break;
}
iNumConnectCallback++;
}
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_CONNECTING);
break;
}
case PVRTSP_ENGINE_NODE_STATE_CONNECTING:
{
uint32 numSockEvents = (PVRTSP_RM_HTTP == iSessionInfo.iStreamingType) ? 2 : 1;
if (iSocketEventQueue.size() < numSockEvents)
{
break;
}
do
{
SocketEvent tmpSockEvent(iSocketEventQueue.front());
iSocketEventQueue.erase(&iSocketEventQueue.front());
if (tmpSockEvent.iSockEvent != EPVSocketSuccess)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPSocketConnectError;
iRet = PVMFFailure;
break;
}
if (tmpSockEvent.iSockFxn != EPVSocketConnect)
{ //unsolicited socket event
//break;
continue;
}
if (tmpSockEvent.iSockId == REQ_RECV_SOCKET_ID)
{
bNoRecvPending = true;
}
else if (tmpSockEvent.iSockId == REQ_SEND_SOCKET_ID)
{
bNoSendPending = true;
}
if (PVRTSP_RM_HTTP != iSessionInfo.iStreamingType)
{
bNoSendPending = bNoRecvPending = true;
}
}
while (!iSocketEventQueue.empty());
if (!(bNoSendPending && bNoRecvPending))
{
break;
}
REQ_TIMER_WATCHDOG_ID = ++BASE_REQUEST_ID;
REQ_TIMER_KEEPALIVE_ID = ++BASE_REQUEST_ID;
if (iSessionInfo.iSDPinfo.GetRep() != NULL)
{//if sdp is available
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE);
iRet = PVMFSuccess;
break;
}
else
{//if sdp is not available
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_SEND_OPTIONS);
}
//DO NOT break, continue to send DESCRIBE
RunIfNotReady();
break;
}
case PVRTSP_ENGINE_NODE_STATE_HTTP_CLOAKING_SETUP:
{//send the GET and POST requests.
if (!clearEventQueue())
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPSocketConnectError;
iRet = PVMFFailure;
break;
}
if (RTSPParser::REQUEST_IS_READY != iRTSPParserState)
break;
{
iRet = processIncomingMessage(iIncomingMsg);
if (iRet != PVMFPending)
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
}
if (iRet == PVMFSuccess)
{
iRet = PVMFPending;
}
else
{//either pending or error
break;
}
}
if (iSessionInfo.iSDPinfo.GetRep() != NULL)
{//if sdp is available
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE);
iRet = PVMFSuccess;
break;
}
else
{//if sdp is not available
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_SEND_OPTIONS);
//go to next case directly
//RunIfNotReady(); break;
}
}
case PVRTSP_ENGINE_NODE_STATE_SEND_OPTIONS:
{
if (bNoSendPending)
{
// send options
RTSPOutgoingMessage *tmpOutgoingMsg = OSCL_NEW(RTSPOutgoingMessage, ());
if (tmpOutgoingMsg == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
iRet = PVMFFailure;
break;
}
if (PVMFSuccess != composeOptionsRequest(*tmpOutgoingMsg))
{
iCurrentErrorCode =
PVMFRTSPClientEngineNodeErrorRTSPComposeOptionsRequestError;
OSCL_DELETE(tmpOutgoingMsg);
iRet = PVMFFailure;
break;
}
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *tmpOutgoingMsg))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
OSCL_DELETE(tmpOutgoingMsg);
iRet = PVMFFailure;
break;
}
bNoSendPending = false;
iOutgoingMsgQueue.push(tmpOutgoingMsg);
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_SEND_DESCRIBE);
//setup the watch dog for server response
iWatchdogTimer->Request(REQ_TIMER_WATCHDOG_ID, 0, TIMEOUT_WATCHDOG);
}
break;
}
case PVRTSP_ENGINE_NODE_STATE_SEND_DESCRIBE:
{
if (RTSPParser::REQUEST_IS_READY == iRTSPParserState)
{
iRet = processIncomingMessage(iIncomingMsg);
if (iRet == PVMFSuccess)
{
iRet = PVMFPending;
}
else
{//either pending or error
if (iRet != PVMFPending)
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
}
if ((RTSPResponseMsg != iIncomingMsg.msgType) || (iRet != PVMFPending))
{//processIncomingMessage() returns pending if there are unacknowledged
//rtsp msgs
break;
}
}
iRealChallenge1 = "";
const StrPtrLen *tmpRealChallenge = iIncomingMsg.queryField("RealChallenge1");
if (tmpRealChallenge)
{
iRealChallenge1 = OSCL_HeapString<OsclMemAllocator>(tmpRealChallenge->c_str());
}
//ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_DESCRIBE_WAITING);
}
if (bNoSendPending)
{
// send describe
RTSPOutgoingMessage *tmpOutgoingMsg = OSCL_NEW(RTSPOutgoingMessage, ());
if (tmpOutgoingMsg == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
iRet = PVMFFailure;
break;
}
if (PVMFSuccess != composeDescribeRequest(*tmpOutgoingMsg))
{
iCurrentErrorCode =
PVMFRTSPClientEngineNodeErrorRTSPComposeDescribeRequestError;
OSCL_DELETE(tmpOutgoingMsg);
iRet = PVMFFailure;
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
break;
}
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *tmpOutgoingMsg))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
OSCL_DELETE(tmpOutgoingMsg);
iRet = PVMFFailure;
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
break;
}
bNoSendPending = false;
iOutgoingMsgQueue.push(tmpOutgoingMsg);
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_OPTIONS_WAITING);
//RunIfNotReady();
}
break;
}
case PVRTSP_ENGINE_NODE_STATE_OPTIONS_WAITING:
{
if (RTSPParser::REQUEST_IS_READY == iRTSPParserState)
{
iRet = processIncomingMessage(iIncomingMsg);
if (iRet == PVMFSuccess)
{
iRet = PVMFPending;
}
else
{//either pending or error
if (iRet != PVMFPending)
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
}
if ((RTSPResponseMsg != iIncomingMsg.msgType) || (iRet != PVMFPending))
{//processIncomingMessage() returns pending if there are unacknowledged
//rtsp msgs
break;
}
}
iRealChallenge1 = "";
const StrPtrLen *tmpRealChallenge = iIncomingMsg.queryField("RealChallenge1");
if (tmpRealChallenge)
{
iRealChallenge1 = OSCL_HeapString<OsclMemAllocator>(tmpRealChallenge->c_str());
}
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_DESCRIBE_WAITING);
}
else if (!clearEventQueue())
{//sth failed, could be Send, Recv, or server closes
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketError;
iRet = PVMFFailure;
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
}
break;
}
case PVRTSP_ENGINE_NODE_STATE_DESCRIBE_WAITING:
{
if (RTSPParser::REQUEST_IS_READY == iRTSPParserState)
{
iRet = processIncomingMessage(iIncomingMsg);
if (iRet == PVMFSuccess)
{//Init is not done until we get SDP
iRet = PVMFPending;
}
else
{//either pending or error
if (iRet != PVMFPending)
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
}
break;
}
}
else if (RTSPParser::ENTITY_BODY_IS_READY == iRTSPParserState)
{//got sdp
{
OsclRefCounter* my_refcnt = new OsclRefCounterSA< RTSPNodeMemDestructDealloc >(iEntityMemFrag.ptr);
if (my_refcnt == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SendRtspDescribe() Unable to Allocate Memory"));
return PVMFErrNoMemory;
}
iSessionInfo.pSDPBuf = OsclRefCounterMemFrag(iEntityMemFrag, my_refcnt, iEntityMemFrag.len);
{//done with the entity body, change the ownership of the mem
iEntityMemFrag.len = 0;
iEntityMemFrag.ptr = NULL;
}
}
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE);
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
//iWatchdogTimer->Clear();
iRet = PVMFSuccess;
}
else if (!clearEventQueue())
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketError;
iRet = PVMFFailure;
break;
}
break;
}
default:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::SendRtspDescribe() In"));
iRet = PVMFErrInvalidState;
break;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SendRtspDescribe() Out"));
return iRet;
}
PVMFStatus PVRTSPEngineNode::DoPrepareNode(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoPrepareNode() In"));
OSCL_UNUSED_ARG(aCmd);
if (iInterfaceState != EPVMFNodeInitialized)
{
return PVMFErrInvalidState;
}
return SendRtspSetup(aCmd);
}
PVMFStatus PVRTSPEngineNode::SendRtspSetup(PVRTSPEngineCommand &aCmd)
{
OSCL_UNUSED_ARG(aCmd);
PVMFStatus iRet = PVMFPending;
switch (iState)
{
case PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE:
case PVRTSP_ENGINE_NODE_STATE_PROCESS_REST_SETUP:
{
/*
before this, the track selection is done.
Also, the Bind for RTP and RTCP for each channel are done
compose one RTSPOutgoingMessage for each SETUP
push each RTSPOutgoingMessage in the iOutgoingMsgQueue
lump all the SETUPs in one Send
*/
if (RTSPParser::REQUEST_IS_READY == iRTSPParserState)
{
iRet = processIncomingMessage(iIncomingMsg);
if (iRet == PVMFSuccess)
{//The Prepare() not done until all the SETUPs are sent
iRet = PVMFPending;
}
else
{//either pending or error
if (iRet != PVMFPending)
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
}
break;
}
if (iState == PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE)
{//ok, got the resp of 1st SETUP, send the reset SETUPs
bNoSendPending = true;
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_PROCESS_REST_SETUP);
}
//idx = iSessionInfo.trackSelectionList->getNumTracks();
//if(all SETUPs resp are back)
if ((uint32)setupTrackIndex == iSessionInfo.iSelectedStream.size())
{
if (!iOutgoingMsgQueue.empty())
{
RTSPOutgoingMessage* tmpOutgoingMsg = iOutgoingMsgQueue.top();
if (tmpOutgoingMsg->method == METHOD_SETUP)
{//still got some SETUPs of which server has not responded
break;
}
}
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
//iWatchdogTimer->Clear();
if (ibIsRealRDT)
{
// create frag group allocator
ipFragGroupMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (DEFAULT_NUM_MEDIA_MSGS_IN_JITTER_BUFFER));
if (ipFragGroupMemPool == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DoInitNode() Error - Unable to allocate mempool"));
return PVMFErrNoMemory;
}
ipFragGroupAllocator = OSCL_NEW(PVMFMediaFragGroupCombinedAlloc<OsclMemAllocator>, (
DEFAULT_NUM_MEDIA_MSGS_IN_JITTER_BUFFER,
1, ipFragGroupMemPool));
if (ipFragGroupAllocator == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DoInitNode() Error - Unable to create frag group allocator"));
return PVMFErrNoMemory;
}
ipFragGroupAllocator->create();
}
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_SETUP_DONE);
iRet = PVMFSuccess;
break;
//break; //send PLAY back-to-back
}
}
else if (RTSPParser::ENTITY_BODY_IS_READY == iRTSPParserState)
{//got still image
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_SETUP_DONE);
iRet = PVMFSuccess;
break;
}
else if (!iSocketEventQueue.empty())
{//TBD if(!clearEventQueue())
SocketEvent tmpSockEvent(iSocketEventQueue.front());
iSocketEventQueue.erase(&iSocketEventQueue.front());
if (tmpSockEvent.iSockEvent != EPVSocketSuccess)
{//sth failed, could be Send, Recv, or server closes
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketError;
iRet = PVMFFailure;
break;
}
if ((iState == PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE)
&& (tmpSockEvent.iSockFxn == EPVSocketSend))
{//pretend there is a send pending so it waits for the first
//SETUP resp to come back and then sends the rest SETUPs
bNoSendPending = false;
break;
}
}
//The trackID is the index to the SDP media info array.
//Get the first track's index
//int trackID = iSessionInfo.trackSelectionList->getTrackIndex(setupIndex);
//compose and send SETUP
//if( (bNoSendPending) && (NOT all the SETUPs are sent out ) )
if ((bNoSendPending) && ((uint32)setupTrackIndex < iSessionInfo.iSelectedStream.size()))
{
RTSPOutgoingMessage *tmpOutgoingMsg = OSCL_NEW(RTSPOutgoingMessage, ());
if (tmpOutgoingMsg == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
return PVMFFailure;
}
//optimize here: use copy/modify instead of build from scratch
//idx = iSessionInfo.iSDPinfo.getNumMediaObjects();
//idx = iSessionInfo.trackSelectionList->getNumTracks();
//if( PVMFSuccess != composeSetupRequest(*tmpOutgoingMsg, idx))
if (PVMFSuccess != composeSetupRequest(*tmpOutgoingMsg, iSessionInfo.iSelectedStream[setupTrackIndex ]))
{
iCurrentErrorCode =
PVMFRTSPClientEngineNodeErrorRTSPComposeSetupRequestError;
OSCL_DELETE(tmpOutgoingMsg);
return PVMFFailure;
}
setupTrackIndex ++;
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *tmpOutgoingMsg))
{
/* need to pop the msg based on cseq, NOT necessarily the early ones,
although YES in this case.
//for(int idx=0; idx < iSessionInfo.trackSelectionList->getNumTracks(); idx++ )
for(int idx=0; idx < iSessionInfo.iSDPinfo->getNumMediaObjects(); idx++ )
{
//iOutgoingMsgQueue.pop();
}
*/
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
OSCL_DELETE(tmpOutgoingMsg);
iRet = PVMFFailure;
break;
}
bNoSendPending = false;
iOutgoingMsgQueue.push(tmpOutgoingMsg);
//ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_WAIT_FIRST_SETUP);
//setup the watch dog for server response
if (setupTrackIndex == 1)
{//only setup watchdog for the first SETUP, but it monitors all
iWatchdogTimer->Request(REQ_TIMER_WATCHDOG_ID, 0, TIMEOUT_WATCHDOG);
}
}
break;
//RunIfNotReady();
}
default:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::SendRtspSetup() iState=%d Line %d", iState, __LINE__));
iRet = PVMFErrInvalidState;
break;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SendRtspSetup() Out"));
return iRet;
}
bool PVRTSPEngineNode::parseURL(const OSCL_wString& aURL)
//(wchar_t *url)
{
if (0 == oscl_UnicodeToUTF8(aURL.get_cstr(), aURL.get_size(), ((mbchar*)iRTSPEngTmpBuf.ptr), iRTSPEngTmpBuf.len))
{
return false;
}
return parseURL((mbchar*)iRTSPEngTmpBuf.ptr);
}
bool PVRTSPEngineNode::parseURL(const char *aUrl)
{
/* Input: absolute URI
* Output: iSessionInfo.iSessionURL, iSessionInfo.iServerName, and iSessionInfo.iSrvAdd.port
* Connection end point is always iSrvAdd
* if no proxy is used, iSrvAdd.ipAddr is ip of iServerName and iSrvAdd.port is the server port.
* Both derived from an absolute url.
* if proxy is used, iSrvAdd is iProxyName:iProxyPort.
*/
if (aUrl == NULL)
{
return false;
}
uint32 aURLMaxOutLength;
PVStringUri::PersentageToEscapedEncoding((mbchar*) aUrl, aURLMaxOutLength);
PVStringUri::IllegalCharactersToEscapedEncoding((mbchar*) aUrl, aURLMaxOutLength);
iSessionInfo.iSessionURL = ((mbchar*)aUrl);
OSCL_HeapString<PVRTSPEngineNodeAllocator> tmpURL = ((mbchar*)aUrl);
mbchar *server_ip_ptr = OSCL_CONST_CAST(mbchar*, oscl_strstr(((mbchar*)tmpURL.get_cstr()), "//"));
if (server_ip_ptr == NULL)
{
return false;
}
server_ip_ptr += 2;
/* Locate the server name. */
mbchar *server_port_ptr = OSCL_CONST_CAST(mbchar*, oscl_strstr(server_ip_ptr, ":"));
mbchar *clip_name = OSCL_CONST_CAST(mbchar*, oscl_strstr(server_ip_ptr, "/"));
if (clip_name != NULL)
{
*clip_name++ = '\0';
}
/* Locate the port number if provided. */
iSessionInfo.iSrvAdd.port = (iSessionInfo.iStreamingType == PVRTSP_RM_HTTP) ? DEFAULT_HTTP_PORT : DEFAULT_RTSP_PORT;
if ((server_port_ptr != NULL) && (*(server_port_ptr + 1) != '/'))
{
*(server_port_ptr++) = '\0';
uint32 atoi_tmp;
if (PV_atoi(server_port_ptr, 'd', atoi_tmp))
{
iSessionInfo.iSrvAdd.port = atoi_tmp;
}
}
OSCL_HeapString<PVRTSPEngineNodeAllocator> tmpServerName(server_ip_ptr, oscl_strlen(server_ip_ptr));
iSessionInfo.iServerName = tmpServerName;
//iSessionInfo.iSrvAdd.port = 20080;
//iSessionInfo.iServerName = "172.16.2.42";
return true;
}
PVMFStatus
PVRTSPEngineNode::composeOptionsRequest(RTSPOutgoingMessage &iMsg)
{
iMsg.reset();
iMsg.numOfTransportEntries = 0;
iMsg.msgType = RTSPRequestMsg;
iMsg.method = METHOD_OPTIONS;
iMsg.originalURI.setPtrLen(iSessionInfo.iSessionURL.get_cstr(), iSessionInfo.iSessionURL.get_size());
iMsg.cseq = iOutgoingSeq++;
iMsg.cseqIsSet = true;
iMsg.acceptIsSet = false;
iMsg.userAgent = iSessionInfo.iUserAgent.get_cstr();
iMsg.userAgentIsSet = true;
{
// setup parameters for the options command. this is necessary
// for real rdt support.
StrCSumPtrLen ClientChallenge = _STRLIT_CHAR("ClientChallenge");
OSCL_HeapString<PVRTSPEngineNodeAllocator> ClientChallenge_Val("9e26d33f2984236010ef6253fb1887f7");
iMsg.addField(&ClientChallenge, ClientChallenge_Val.get_cstr());
StrCSumPtrLen PlayerStarttime = _STRLIT_CHAR("PlayerStarttime");
OSCL_HeapString<PVRTSPEngineNodeAllocator> PlayerStarttime_Val("[28/03/2003:22:50:23 00:00]");
iMsg.addField(&PlayerStarttime, PlayerStarttime_Val.get_cstr());
StrCSumPtrLen CompanyID = _STRLIT_CHAR("CompanyID");
OSCL_HeapString<PVRTSPEngineNodeAllocator> CompanyID_Val("KnKV4M4I/B2FjJ1TToLycw==");
iMsg.addField(&CompanyID, CompanyID_Val.get_cstr());
StrCSumPtrLen playerGuid = _STRLIT_CHAR("GUID");
OSCL_StackString<64> playerGuidVal = _STRLIT_CHAR("00000000-0000-0000-0000-000000000000");
iMsg.addField(&playerGuid, playerGuidVal.get_cstr());
}
if (iMsg.compose() == false)
{
return PVMFFailure;
}
else
{
return PVMFSuccess;
}
}
/*
* Function : int composeDescribeRequest()
* Date : 09/13/2002
* Purpose : Composes RTSP DESCRIBE request
* In/out :
* Return :
* Modified :
*/
PVMFStatus
PVRTSPEngineNode::composeDescribeRequest(RTSPOutgoingMessage &iMsg)
{
iMsg.reset();
iMsg.numOfTransportEntries = 0;
iMsg.msgType = RTSPRequestMsg;
iMsg.method = METHOD_DESCRIBE;
iMsg.originalURI.setPtrLen(iSessionInfo.iSessionURL.get_cstr(), iSessionInfo.iSessionURL.get_size());
iMsg.cseq = iOutgoingSeq++;
iMsg.cseqIsSet = true;
iMsg.accept = "application/sdp";
iMsg.acceptIsSet = true;
iMsg.userAgent = iSessionInfo.iUserAgent.get_cstr();
iMsg.userAgentIsSet = true;
if (oscl_strlen(iSessionInfo.iUserNetwork.get_cstr()))
{
StrCSumPtrLen UserNetwork = _STRLIT_CHAR("User-Network");
iMsg.addField(&UserNetwork, iSessionInfo.iUserNetwork.get_cstr());
}
if (oscl_strlen(iSessionInfo.iDeviceInfo.get_cstr()))
{
StrCSumPtrLen DeviceInfo = _STRLIT_CHAR("DeviceInfo");
iMsg.addField(&DeviceInfo, iSessionInfo.iDeviceInfo.get_cstr());
}
if (oscl_strlen(iSessionInfo.iUserID.get_cstr()) && oscl_strlen(iSessionInfo.iAuthentication.get_cstr()))
{
OSCL_HeapString<PVRTSPEngineNodeAllocator> myBuf("user=");
myBuf += iSessionInfo.iUserID.get_cstr();
myBuf += ";authentication=";
myBuf += iSessionInfo.iAuthentication.get_cstr();
StrCSumPtrLen User_id = _STRLIT_CHAR("ID");
iMsg.addField(&User_id, myBuf.get_cstr());
}
if (oscl_strlen(iSessionInfo.iExpiration.get_cstr()))
{
StrCSumPtrLen Expiration = _STRLIT_CHAR("Expiration");
iMsg.addField(&Expiration, iSessionInfo.iExpiration.get_cstr());
}
if (oscl_strlen(iSessionInfo.iApplicationSpecificString.get_cstr()))
{
StrCSumPtrLen Application_specific_string = _STRLIT_CHAR("Application-Specific-String");
iMsg.addField(&Application_specific_string, iSessionInfo.iApplicationSpecificString.get_cstr());
}
if (iSessionInfo.iVerification.get_size() && iSessionInfo.iSignature.get_size())
{
OSCL_HeapString<PVRTSPEngineNodeAllocator> myBuf("filler=");
myBuf += iSessionInfo.iVerification.get_cstr();
myBuf += ";signature=";
myBuf += iSessionInfo.iSignature.get_cstr();
StrCSumPtrLen Verification = _STRLIT_CHAR("Verification");
iMsg.addField(&Verification, myBuf.get_cstr());
}
{//If the Accept-Encoding field-value is empty, then only the "identity"
// encoding is acceptable.
StrCSumPtrLen AcceptEncoding = _STRLIT_CHAR("Accept-Encoding");
iMsg.addField(&AcceptEncoding, "");
}
if (iMsg.compose() == false)
{
return PVMFFailure;
}
iSessionInfo.clientServerDelay = 0;
uint32 clock = 0;
bool overflowFlag = false;
iRoundTripClockTimeBase.GetCurrentTime32(clock, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
iSessionInfo.clientServerDelay = clock;
//iSessionInfo.composedMessage = iMsg.retrieveComposedBuffer();
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::processServerRequest(RTSPIncomingMessage &aMsg)
{//input: server request in aMsg;
//just send the response. bingo.
//all S->C are optional, including ANNOUNCE, GET_PARAMETER, SET_PARAMETER, OPTIONS
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::processServerRequest() In"));
if (iSrvResponse == NULL)
{
iSrvResponse = OSCL_NEW(RTSPOutgoingMessage, ());
if (iSrvResponse == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
return PVMFFailure;
}
}
iSrvResponse->reset();
iSrvResponse->msgType = RTSPResponseMsg;
iSrvResponse->numOfTransportEntries = 0;
if (aMsg.method == METHOD_END_OF_STREAM)
{//
iSrvResponse->statusCode = CodeOK;
iSrvResponse->reasonString = "OK";
ReportInfoEvent(PVMFInfoEndOfData);
}
else if (aMsg.method == METHOD_SET_PARAMETER)
{//
iSrvResponse->statusCode = CodeOK;
iSrvResponse->reasonString = "OK";
}
else
{
iSrvResponse->statusCode = CodeNotImplemented;
iSrvResponse->reasonString = "Not Implemented";
}
//iSrvResponse->statusCode = CodeParameterNotUnderstood;
//iSrvResponse->reasonString = "Parameter Not Understood";
iSrvResponse->cseq = aMsg.cseq;
iSrvResponse->cseqIsSet = true;
if (iSessionInfo.iSID.get_size())
{
iSrvResponse->sessionId.setPtrLen(iSessionInfo.iSID.get_cstr(), iSessionInfo.iSID.get_size());
iSrvResponse->sessionIdIsSet = true;
}
if (iSrvResponse->compose() == false)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPCompose501ResponseError;
OSCL_DELETE(iSrvResponse);
iSrvResponse = NULL;
return PVMFFailure;
}
if (bNoSendPending)// bSrvRespPending
{
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *iSrvResponse))
{
/* need to pop the msg based on cseq, NOT necessarily the early ones,
although YES in this case.
//for(int idx=0; idx < iSessionInfo.trackSelectionList->getNumTracks(); idx++ )
for(int idx=0; idx < iSessionInfo.iSDPinfo->getNumMediaObjects(); idx++ )
{
//iOutgoingMsgQueue.pop();
}
*/
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
OSCL_DELETE(iSrvResponse);
iSrvResponse = NULL;
return PVMFFailure;
}
bNoSendPending = false;
}
else
{
bSrvRespPending = true;
}
return PVMFSuccess;
}
/**
* This API processes server requests with entity bodies.
*
* @param aMsg The server request.
* @param aEntityMemFrag The oscl memory fragment which holds the entity body.
* @returns PVMF status.
*/
PVMFStatus PVRTSPEngineNode::processEntityBody(RTSPIncomingMessage &aMsg, OsclMemoryFragment &aEntityMemFrag)
{ //all S->C are optional, including ANNOUNCE, GET_PARAMETER, SET_PARAMETER, OPTIONS
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::processEntityBody() In"));
if (iEntityMemFrag.ptr == NULL)
{//the entity body hasn't come yet.
//return PVMFFailure;
return PVMFPending;
}
if (iSrvResponse == NULL)
{
iSrvResponse = OSCL_NEW(RTSPOutgoingMessage, ());
if (iSrvResponse == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
return PVMFFailure;
}
}
iSrvResponse->reset();
iSrvResponse->msgType = RTSPResponseMsg;
iSrvResponse->numOfTransportEntries = 0;
if (aMsg.method == METHOD_SET_PARAMETER)
{//
iSrvResponse->statusCode = CodeOK;
iSrvResponse->reasonString = "OK";
}
else
{
iSrvResponse->statusCode = CodeNotImplemented;
iSrvResponse->reasonString = "Not Implemented";
}
//iSrvResponse->statusCode = CodeParameterNotUnderstood;
//iSrvResponse->reasonString = "Parameter Not Understood";
iSrvResponse->cseq = aMsg.cseq;
iSrvResponse->cseqIsSet = true;
if (iSessionInfo.iSID.get_size())
{
iSrvResponse->sessionId.setPtrLen(iSessionInfo.iSID.get_cstr(), iSessionInfo.iSID.get_size());
iSrvResponse->sessionIdIsSet = true;
}
if (iSrvResponse->compose() == false)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPCompose501ResponseError;
OSCL_DELETE(iSrvResponse);
iSrvResponse = NULL;
return PVMFFailure;
}
if (bNoSendPending)// bSrvRespPending
{
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *iSrvResponse))
{
/* need to pop the msg based on cseq, NOT necessarily the early ones,
although YES in this case.
//for(int idx=0; idx < iSessionInfo.trackSelectionList->getNumTracks(); idx++ )
for(int idx=0; idx < iSessionInfo.iSDPinfo->getNumMediaObjects(); idx++ )
{
//iOutgoingMsgQueue.pop();
}
*/
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
OSCL_DELETE(iSrvResponse);
iSrvResponse = NULL;
return PVMFFailure;
}
bNoSendPending = false;
}
else
{
bSrvRespPending = true;
}
PVMFStatus tmpRet = PVMFSuccess;
OSCL_UNUSED_ARG(aEntityMemFrag);
return tmpRet;
}
PVMFStatus PVRTSPEngineNode::DoStartNode(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoStartNode() In"));
OSCL_UNUSED_ARG(aCmd);
//If session is completed, then do not send the play command to the server..
if (IsSessionCompleted() && !bRepositioning)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoStartNode() Skipping sending play 'cos of session expiry"));
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_PLAY_DONE);
return PVMFSuccess;
}
if (iInterfaceState != EPVMFNodePrepared &&
iInterfaceState != EPVMFNodePaused)
{
return PVMFErrInvalidState;
}
return SendRtspPlay(aCmd);
}
PVMFStatus PVRTSPEngineNode::SendRtspPlay(PVRTSPEngineCommand &aCmd)
{
OSCL_UNUSED_ARG(aCmd);
PVMFStatus iRet = PVMFPending;
switch (iState)
{
case PVRTSP_ENGINE_NODE_STATE_SETUP_DONE:
case PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE:
{
if (!bNoSendPending)
{
break;
}
//compose and send PLAY
//if ASF streaming, the SET_PARAMETER should be pipelined as well
RTSPOutgoingMessage *tmpOutgoingMsg = OSCL_NEW(RTSPOutgoingMessage, ());
if (tmpOutgoingMsg == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
iRet = PVMFFailure;
break;
}
if (PVMFSuccess != composePlayRequest(*tmpOutgoingMsg))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPComposePlayRequestError;
OSCL_DELETE(tmpOutgoingMsg);
iRet = PVMFFailure;
break;
}
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *tmpOutgoingMsg))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
OSCL_DELETE(tmpOutgoingMsg);
iRet = PVMFFailure;
break;
}
bNoSendPending = false;
iOutgoingMsgQueue.push(tmpOutgoingMsg);
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_WAIT_PLAY);
//setup the watch dog for server response
iWatchdogTimer->Request(REQ_TIMER_WATCHDOG_ID, 0, TIMEOUT_WATCHDOG);
RunIfNotReady();
break;
}
case PVRTSP_ENGINE_NODE_STATE_WAIT_PLAY:
{
if (RTSPParser::REQUEST_IS_READY == iRTSPParserState)
{
iRet = processIncomingMessage(iIncomingMsg);
if (iRet != PVMFPending)
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
if (iRet == PVMFSuccess)
{
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_PLAY_DONE);
}
}
}
else if (RTSPParser::ENTITY_BODY_IS_READY == iRTSPParserState)
{//got MS TCP RTP packets
//processSDP(REINTERPRET_CAST(mbchar*, pSDPBuf.ptr), pSDPBuf.len-1);
//processSDP((mbchar*)pSDPBuf.ptr, pSDPBuf.len-1);
//ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_WAIT_DESCRIBE_DONE);
iRet = processIncomingMessage(iIncomingMsg);
<