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);
if (iRet != PVMFPending)
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
if (iRet == PVMFSuccess)
{
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_PLAY_DONE);
}
}
}
else if (!clearEventQueue())
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketError;
iRet = PVMFFailure;
}
break;
}
default:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::SendRtspPlay() iState=%d Line %d", iState, __LINE__));
iRet = PVMFErrInvalidState;
break;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SendRtspPlay() Out"));
return iRet;
}
PVMFStatus PVRTSPEngineNode::composeSetupRequest(RTSPOutgoingMessage &iMsg, StreamInfo &aSelected)
{
//Reset the data structure
iMsg.reset();
if (iSessionInfo.iSDPinfo.GetRep() == NULL) return PVMFFailure;
//Here we decide if the selected track is a still image or not
mediaInfo *tmpMediaInfo = iSessionInfo.iSDPinfo->getMediaInfoBasedOnID(aSelected.iSDPStreamId);
if (NULL == tmpMediaInfo)
{
return PVMFFailure;
}
StrCSumPtrLen still_image = "X-MP4V-IMAGE";
if (!oscl_strncmp(tmpMediaInfo->getMIMEType(), still_image.c_str(), still_image.length()))
{
StrPtrLen contentType = "text/parameters";
StrCSumPtrLen image = "Image\r\n";
iMsg.contentType = contentType;
iMsg.contentTypeIsSet = true;
iMsg.contentLength = image.length();
iMsg.contentLengthIsSet = true;
iMsg.accept = "X-MP4V-IMAGE";
iMsg.acceptIsSet = true;
iMsg.method = METHOD_GET_PARAMETER;
iMsg.numOfTransportEntries = 0;
/*
mbchar mediaURL[RTSP_MAX_FULL_REQUEST_SIZE];
mediaURL[0] = '\0';
oscl_strncpy( mediaURL,
( iSessionInfo.contentBaseFlag )? iSessionInfo.contentBaseURL:requestURL,
oscl_strlen(( iSessionInfo.contentBaseFlag )? iSessionInfo.contentBaseURL:requestURL) );
mediaURL[oscl_strlen(( iSessionInfo.contentBaseFlag )? iSessionInfo.contentBaseURL:requestURL)] = '\0';
iMsg.originalURI = mediaURL;
*/
}
else
{
//Set standard fields
iMsg.method = METHOD_SETUP;
iMsg.userAgent = iSessionInfo.iUserAgent.get_cstr();
iMsg.userAgentIsSet = true;
{
iMsg.numOfTransportEntries = 1;
iMsg.transport[0].protocol = RtspTransport::RTP_PROTOCOL;
iMsg.transport[0].protocolIsSet = true;
iMsg.transport[0].profile = RtspTransport::AVP_PROFILE;
iMsg.transport[0].profileIsSet = true;
iMsg.transport[0].delivery = RtspTransport::UNICAST_DELIVERY;
iMsg.transport[0].deliveryIsSet = true;
if ((iSessionInfo.iStreamingType == PVRTSP_3GPP_UDP)
|| (iSessionInfo.iStreamingType == PVRTSP_MS_UDP))
{
iMsg.transport[0].transportType = RtspTransport::UDP_TRANSPORT;
iMsg.transport[0].transportTypeIsSet = true;
iMsg.transport[0].channelIsSet = false;
iMsg.transport[0].client_portIsSet = true;
iMsg.transport[0].client_port1 = OSCL_STATIC_CAST(uint16, aSelected.iCliRTPPort); //dataPort;
iMsg.transport[0].client_port2 = OSCL_STATIC_CAST(uint16, aSelected.iCliRTCPPort); //feedbackPort;
if (iSessionInfo.iStreamingType == PVRTSP_MS_UDP)
{//check here!
iMsg.transport[0].client_port2 = 0;
}
/* Send recommended block size of RTP packet to the server. CJ 09/10/2001 */
StrCSumPtrLen blockSize = "Blocksize";
oscl_snprintf(((mbchar*)iRTSPEngTmpBuf.ptr), iRTSPEngTmpBuf.len, "%d", RECOMMENDED_RTP_BLOCK_SIZE);
iMsg.addField(&blockSize, ((mbchar*)iRTSPEngTmpBuf.ptr));
}
else
{
iMsg.transport[0].transportType = RtspTransport::TCP_TRANSPORT;
iMsg.transport[0].transportTypeIsSet = true;
iMsg.transport[0].client_portIsSet = false;
iMsg.transport[0].channelIsSet = false;
//iMsg.transport[0].channel1 = 8888;//aSelected.iSerRTPPort;
//iMsg.transport[0].channel2 = 9999;//aSelected.iSerRTCPPort;
}
iMsg.transport[0].appendIsSet = false;
iMsg.transport[0].layersIsSet = false;
iMsg.transport[0].modeIsSet = false;
iMsg.transport[0].portIsSet = false;
iMsg.transport[0].server_portIsSet = false;
iMsg.transport[0].ttlIsSet = false;
iMsg.transport[0].ssrcIsSet = false;
}
{/*
StrCSumPtrLen mytransport = "Transport";
iMsg.addField(&mytransport, "x-real-rdt/udp;client_port=6970");
iMsg.numOfTransportEntries = 0;
*/
}
//Compose etag
if (oscl_strlen((iSessionInfo.iSDPinfo->getSessionInfo())->getETag()) != 0)
{
if (oscl_snprintf(((mbchar*)iRTSPEngTmpBuf.ptr), iRTSPEngTmpBuf.len, "\"%s\"", (iSessionInfo.iSDPinfo->getSessionInfo())->getETag()) != 1)
{
StrCSumPtrLen etag = "If-Match";
iMsg.addField(&etag, ((mbchar*)iRTSPEngTmpBuf.ptr));
}
}
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());
}
//Compose the media level URL for use in a RTSP request message.
if (composeMediaURL(aSelected.iSDPStreamId, iMsg.originalURI) != PVMFSuccess)
{
return PVMFFailure;
}
aSelected.iMediaURI = iMsg.originalURI.c_str();
if (aSelected.b3gppAdaptationIsSet)
{// 3GPP release-6 rate adaptation
mbchar buffer[256];
OSCL_HeapString<PVRTSPEngineNodeAllocator> myBuf("url=\"");
myBuf += iMsg.originalURI.c_str();
myBuf += "\";size=";
oscl_snprintf(buffer, 256, "%d", aSelected.iBufSize);
myBuf += buffer;
myBuf += ";target-time=";
oscl_snprintf(buffer, 256, "%d", aSelected.iTargetTime);
myBuf += buffer;
StrCSumPtrLen _3GPPadaptation = "3GPP-Adaptation";
iMsg.addField(&_3GPPadaptation, myBuf.get_str());
}
}
iMsg.msgType = RTSPRequestMsg;
iMsg.cseq = iOutgoingSeq++;
iMsg.cseqIsSet = true;
//OSCL_StackString<32> tmpSID = _STRLIT_CHAR("d5ac74e39ac8d75f");
//iSessionInfo.iSID.set(tmpSID.get_cstr(), tmpSID.get_size());
if (iSessionInfo.iSID.get_size())
{
iMsg.sessionId.setPtrLen(iSessionInfo.iSID.get_cstr(), iSessionInfo.iSID.get_size());
iMsg.sessionIdIsSet = true;
}
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;
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::composePlayRequest(RTSPOutgoingMessage &aMsg)
{
aMsg.reset();
aMsg.numOfTransportEntries = 0;
aMsg.msgType = RTSPRequestMsg;
aMsg.method = METHOD_PLAY;
aMsg.cseq = iOutgoingSeq++;
aMsg.cseqIsSet = true;
if (iSessionInfo.iSID.get_size())
{
aMsg.sessionId.setPtrLen(iSessionInfo.iSID.get_cstr(), iSessionInfo.iSID.get_size());
aMsg.sessionIdIsSet = true;
}
//Add range field only if it is a PLAY request
//if( (iState != EResumeSession) && (!upstreamClient) )
if ((iState != PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE)
|| (bRepositioning)
|| (iInterfaceState == EPVMFNodePrepared))
//if( iState == PVRTSP_ENGINE_NODE_STATE_SETUP_DONE )
{
bRepositioning = false;
OSCL_StackString<8> npt = _STRLIT_CHAR("npt=");
oscl_strncpy(((mbchar*)iRTSPEngTmpBuf.ptr), npt.get_cstr(), npt.get_size());
((mbchar*)iRTSPEngTmpBuf.ptr)[npt.get_size()] = '\0';
if (iSessionInfo.iReqPlayRange.format == RtspRangeType::NPT_RANGE)
{
if (iSessionInfo.iReqPlayRange.start_is_set == true)
{
if (iSessionInfo.iReqPlayRange.npt_start.npt_format == NptTimeFormat::NPT_SEC)
{
oscl_snprintf(((mbchar*)iRTSPEngTmpBuf.ptr) + oscl_strlen(((mbchar*)iRTSPEngTmpBuf.ptr)), \
(64 - oscl_strlen(((mbchar*)iRTSPEngTmpBuf.ptr))), "%d.%03d-", \
iSessionInfo.iReqPlayRange.npt_start.npt_sec.sec, iSessionInfo.iReqPlayRange.npt_start.npt_sec.milli_sec);
}
else if (iSessionInfo.iReqPlayRange.npt_start.npt_format == NptTimeFormat::NOW)
{
oscl_snprintf(((mbchar*)iRTSPEngTmpBuf.ptr) + oscl_strlen(((mbchar*)iRTSPEngTmpBuf.ptr)), \
(64 - oscl_strlen(((mbchar*)iRTSPEngTmpBuf.ptr))), "now-");
}
else
{
return PVMFFailure;
}
}
if (iSessionInfo.iReqPlayRange.end_is_set == true)
{
if (iSessionInfo.iReqPlayRange.npt_end.npt_format == NptTimeFormat::NPT_SEC)
{
if ((iSessionInfo.iReqPlayRange.npt_end.npt_sec.sec != 0)
|| (iSessionInfo.iReqPlayRange.npt_end.npt_sec.milli_sec != 0))
{
oscl_snprintf(((mbchar*)iRTSPEngTmpBuf.ptr) + oscl_strlen(((mbchar*)iRTSPEngTmpBuf.ptr)), \
(64 - oscl_strlen(((mbchar*)iRTSPEngTmpBuf.ptr))), "%d.%03d", \
iSessionInfo.iReqPlayRange.npt_end.npt_sec.sec, iSessionInfo.iReqPlayRange.npt_end.npt_sec.milli_sec);
}
}
else
{
return PVMFFailure;
}
}
StrCSumPtrLen Range = _STRLIT_CHAR("Range");
aMsg.addField(&Range, ((mbchar*)iRTSPEngTmpBuf.ptr));
}
}
{//put user agent in SETUP an PLAY for testing for Real. IOT testing Jun 02, 05
aMsg.userAgent = iSessionInfo.iUserAgent.get_cstr();
aMsg.userAgentIsSet = true;
}
if (composeSessionURL(aMsg) != PVMFSuccess)
{
return PVMFFailure;
}
if (aMsg.compose() == false)
{
return PVMFFailure;
}
//iSessionInfo.composedMessage = aMsg.retrieveComposedBuffer();
iSessionInfo.clientServerDelay = 0;
uint32 clock = 0;
bool overflowFlag = false;
iRoundTripClockTimeBase.GetCurrentTime32(clock, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
iSessionInfo.clientServerDelay = clock;
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::composePauseRequest(RTSPOutgoingMessage &aMsg)
{
aMsg.reset();
aMsg.numOfTransportEntries = 0;
aMsg.msgType = RTSPRequestMsg;
aMsg.method = METHOD_PAUSE;
aMsg.cseq = iOutgoingSeq++;
aMsg.cseqIsSet = true;
if (iSessionInfo.iSID.get_size())
{
aMsg.sessionId.setPtrLen(iSessionInfo.iSID.get_cstr(), iSessionInfo.iSID.get_size());
aMsg.sessionIdIsSet = true;
}
{//put user agent in SETUP an PLAY for testing for Real. IOT testing Jun 02, 05
aMsg.userAgent = iSessionInfo.iUserAgent.get_cstr();
aMsg.userAgentIsSet = true;
}
if (composeSessionURL(aMsg) != PVMFSuccess)
{
return PVMFFailure;
}
if (aMsg.compose() == false)
{
return PVMFFailure;
}
iSessionInfo.clientServerDelay = 0;
uint32 clock = 0;
bool overflowFlag = false;
iRoundTripClockTimeBase.GetCurrentTime32(clock, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
iSessionInfo.clientServerDelay = clock;
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::composeStopRequest(RTSPOutgoingMessage &aMsg)
{
aMsg.reset();
aMsg.numOfTransportEntries = 0;
aMsg.msgType = RTSPRequestMsg;
aMsg.method = METHOD_TEARDOWN;
aMsg.cseq = iOutgoingSeq++;
aMsg.cseqIsSet = true;
aMsg.userAgent = iSessionInfo.iUserAgent.get_cstr();
aMsg.userAgentIsSet = true;
if (iSessionInfo.iSID.get_size())
{
aMsg.sessionId.setPtrLen(iSessionInfo.iSID.get_cstr(), iSessionInfo.iSID.get_size());
aMsg.sessionIdIsSet = true;
}
if (composeSessionURL(aMsg) != PVMFSuccess)
{
return PVMFFailure;
}
StrCSumPtrLen connection = "Connection";
aMsg.addField(&connection, "close");
if (aMsg.compose() == false)
{
return PVMFFailure;
}
iSessionInfo.clientServerDelay = 0;
uint32 clock = 0;
bool overflowFlag = false;
iRoundTripClockTimeBase.GetCurrentTime32(clock, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
iSessionInfo.clientServerDelay = clock;
return PVMFSuccess;
}
/*
* Function : PVMFStatus composeSessionURL()
* Date : 10/30/2002
* Purpose : Composing a session level URL for use in a RTSP request message.
* In/out :
* Return : PVMFSuccess upon succeessful composition. PVMFFailure otherwise.
* Modified :
*/
PVMFStatus PVRTSPEngineNode::composeSessionURL(RTSPOutgoingMessage &aMsg)
{
OSCL_StackString<16> rtsp_str = _STRLIT_CHAR("rtsp");
const char *sdpSessionURL = (iSessionInfo.iSDPinfo->getSessionInfo())->getControlURL();
if (sdpSessionURL == NULL)
{
return PVMFFailure;
}
//1. SDP from DESCRIBE response
if (iSessionInfo.bExternalSDP)
{
if (!oscl_strncmp(sdpSessionURL, rtsp_str.get_cstr(), rtsp_str.get_size()))
{
aMsg.originalURI = sdpSessionURL;
return PVMFSuccess;
}
return PVMFFailure;
}
else
{
char *baseURL;
if (iSessionInfo.iContentBaseURL.get_size())
{
baseURL = iSessionInfo.iContentBaseURL.get_str();
}
else
{
baseURL = iSessionInfo.iSessionURL.get_str();
}
//Case where control url is *
((mbchar*)iRTSPEngTmpBuf.ptr)[0] = '\0';
uint tmpLen = iRTSPEngTmpBuf.len;
mbchar asterisk[] = {"*"};
if (!oscl_strncmp(sdpSessionURL, asterisk, oscl_strlen(asterisk)))
{
oscl_strncpy(((mbchar*)iRTSPEngTmpBuf.ptr), baseURL, oscl_strlen(baseURL));
((mbchar*)iRTSPEngTmpBuf.ptr)[oscl_strlen(baseURL)] = '\0';
if (((mbchar*)iRTSPEngTmpBuf.ptr)[oscl_strlen(((mbchar*)iRTSPEngTmpBuf.ptr)) - 1] == '/')
{
((mbchar*)iRTSPEngTmpBuf.ptr)[oscl_strlen(((mbchar*)iRTSPEngTmpBuf.ptr)) - 1] = '\0';
}
aMsg.originalURI = ((mbchar*)iRTSPEngTmpBuf.ptr);
}
//Case where control url is absolute
else if (!oscl_strncmp(sdpSessionURL, rtsp_str.get_cstr(), rtsp_str.get_size()))
{
aMsg.originalURI = sdpSessionURL;
}
//other cases
else if (composeURL((const char *)baseURL, sdpSessionURL, \
((mbchar*)iRTSPEngTmpBuf.ptr), tmpLen) == true)
{
aMsg.originalURI = ((mbchar*)iRTSPEngTmpBuf.ptr);
}
else
{
return PVMFFailure;
}
}
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::composeMediaURL(int aTrackID, StrPtrLen &aMediaURI)
{
OSCL_StackString<16> rtsp_str = _STRLIT_CHAR("rtsp");
const char *sdpMediaURL = (iSessionInfo.iSDPinfo->getMediaInfoBasedOnID(aTrackID))->getControlURL();
if (sdpMediaURL == NULL)
{
return PVMFFailure;
}
if (!oscl_strncmp(sdpMediaURL, rtsp_str.get_cstr(), rtsp_str.get_size()))
{
{
aMediaURI = sdpMediaURL;
}
}
else
{
const char *sdpSessionURL = (iSessionInfo.iSDPinfo->getSessionInfo())->getControlURL();
if (!oscl_strncmp(sdpSessionURL, rtsp_str.get_cstr(), rtsp_str.get_size()))
{
((mbchar*)iRTSPEngTmpBuf.ptr)[0] = '\0';
uint tmpLen = iRTSPEngTmpBuf.len;
if (composeURL(sdpSessionURL, sdpMediaURL,
((mbchar*)iRTSPEngTmpBuf.ptr), tmpLen) != true)
{
return PVMFFailure;
}
aMediaURI = ((mbchar*)iRTSPEngTmpBuf.ptr);
}
//Compose absolute URL
else
{
char *baseURL;
if (iSessionInfo.iContentBaseURL.get_size())
{
baseURL = iSessionInfo.iContentBaseURL.get_str();
}
else
{
baseURL = iSessionInfo.iSessionURL.get_str();
}
{
uint tmpLen = iRTSPEngTmpBuf.len;
if (composeURL((const char *)baseURL,
sdpMediaURL,
((mbchar*)iRTSPEngTmpBuf.ptr), tmpLen) != true)
{
return PVMFFailure;
}
}
aMediaURI = ((mbchar*)iRTSPEngTmpBuf.ptr);
}
}
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::processCommonResponse(RTSPIncomingMessage &aMsg)
{
/*Parse content base - this is needed to compose URLs for future RTSP requests*/
if (iSessionInfo.iContentBaseURL.get_size() == 0)
{
if (aMsg.contentBase.length())
{
OSCL_HeapString<PVRTSPEngineNodeAllocator> tmpBaseURL(aMsg.contentBase.c_str(), aMsg.contentBase.length());
iSessionInfo.iContentBaseURL = tmpBaseURL;
}
else
{
const StrPtrLen *tmpBaseURLLoc = aMsg.queryField("Content-Location");
if (tmpBaseURLLoc)
{
OSCL_HeapString<PVRTSPEngineNodeAllocator> tmpBaseURL(tmpBaseURLLoc->c_str(), tmpBaseURLLoc->length());
iSessionInfo.iContentBaseURL = tmpBaseURL;
}
}
}
/*Extract session id from the server response. This is done only once per session and the following condition ensures it. */
//might need to check the SID match
if ((aMsg.sessionIdIsSet) && (iSessionInfo.iSID.get_size() == 0))
{
//because the RTSP parser just gives "d2ecb87b0816b4a;timeout=60"
char *timeout_location = OSCL_CONST_CAST(char*, oscl_strstr(aMsg.sessionId.c_str(), ";timeout"));
if (NULL != timeout_location)
{
OSCL_HeapString<PVRTSPEngineNodeAllocator> tmpSID(aMsg.sessionId.c_str(), timeout_location - aMsg.sessionId.c_str());
iSessionInfo.iSID = tmpSID;
//should be timeout-RTT.
int32 tmpTimeout = (aMsg.timeout - 5);
if ((TIMEOUT_KEEPALIVE > tmpTimeout) && (tmpTimeout > 0))
{
TIMEOUT_KEEPALIVE = tmpTimeout;
}
}
else
{
OSCL_HeapString<PVRTSPEngineNodeAllocator> tmpSID(aMsg.sessionId.c_str(), aMsg.sessionId.length());
iSessionInfo.iSID = tmpSID;
}
iSessionInfo.tSIDIsSetFlag = true;
}
/*Parse preroll duration from server response (if available)*/
iSessionInfo.prerollDuration = 0;
const StrPtrLen *tmpBufSize = aMsg.queryField("Buffersize");
if (tmpBufSize != NULL)
{
// pSessionInfo->prerollDuration = atoi( aMsg.queryField(buffer)->getPtr() );
uint32 atoi_tmp;
PV_atoi(tmpBufSize->c_str(), 'd', atoi_tmp);
iSessionInfo.prerollDuration = atoi_tmp;
}
/*
* Check for PVServer - needed to perform firewall port remapping
*/
const StrPtrLen *serverTag = aMsg.queryField("Server");
OSCL_StackString<8> pvServerTag(_STRLIT_CHAR("PVSS"));
if (serverTag != NULL)
{
uint32 minLen = OSCL_MIN((pvServerTag.get_size()), ((uint32)(serverTag->size())));
if (!oscl_strncmp(serverTag->c_str(), pvServerTag.get_cstr(), minLen))
{
iSessionInfo.pvServerIsSetFlag = true;
}
else
{
iSessionInfo.pvServerIsSetFlag = false;
}
}
/*
* Check for PVServer version number
*/
if (NULL != serverTag)
{
if (iSessionInfo.pvServerIsSetFlag)
{
OSCL_StackString<8> pvServerVersionNumberLocator(_STRLIT_CHAR("/"));
const char *versionNumberLocation = oscl_strstr(serverTag->c_str(), pvServerVersionNumberLocator.get_cstr());
if (NULL != versionNumberLocation)
{
uint32 versionNumber = 0;
if (PV_atoi(versionNumberLocation + 1, 'd', 1, versionNumber))
{
iSessionInfo.iServerVersionNumber = versionNumber;
}
}
}
}
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::processIncomingMessage(RTSPIncomingMessage &iIncomingMsg)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::processIncomingMessage() in"));
if (RTSPOk != iIncomingMsg.isMalformed())
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorMalformedRTSPMessage;
return PVMFFailure;
}
if (RTSPRequestMsg == iIncomingMsg.msgType)
{
if (METHOD_BINARY_DATA == iIncomingMsg.method)
{//need to check the rtsp parcom
/*
iIncomingMsg.bufferSize;
iIncomingMsg.contentLength;
iIncomingMsg.fullRequestBuffer;
iIncomingMsg.fullRequestBufferSizeUsed;
*/
//iIncomingMsg.reset();
return PVMFPending;
}
//PVMFStatus tmpRet = ( (iIncomingMsg.contentLengthIsSet) && (iIncomingMsg.contentLength > 0) )
PVMFStatus tmpRet = ((iIncomingMsg.contentLengthIsSet))
? processEntityBody(iIncomingMsg, iEntityMemFrag)
: processServerRequest(iIncomingMsg);
return (tmpRet == PVMFSuccess) ? PVMFPending : tmpRet;
}
if (RTSPResponseMsg != iIncomingMsg.msgType)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorIncorrectRTSPMessageType;
return PVMFFailure;
}
if (iOutgoingMsgQueue.empty())
{
//we don't expect a response at this moment.
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorUnknownRTSPMessage;
return PVMFFailure;
}
//pop the outgoing msg queue and see the match
RTSPOutgoingMessage* tmpOutgoingMsg = iOutgoingMsgQueue.top();
if (tmpOutgoingMsg->cseqIsSet)
{
//we always send seq. But just to be sure
if (!iIncomingMsg.cseqIsSet)
{
//server should reply with seq
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorMissingSeqNumInServerResponse;
return PVMFFailure;
}
if (tmpOutgoingMsg->cseq != iIncomingMsg.cseq)
{
//FIFO server messed up
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPRequestResponseMismatch;
return PVMFFailure;
}
iOutgoingMsgQueue.pop();
}
else if (tmpOutgoingMsg->method == METHOD_GET)
{//TBD varify this is the http GET response
iOutgoingMsgQueue.pop();
}
//check session ID as well
if (200 == iIncomingMsg.statusCode)
{
//OK
processCommonResponse(iIncomingMsg);
//ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_SETUP_DONE);
//break;
if (tmpOutgoingMsg->method == METHOD_SETUP)
{
for (uint32 i = 0; i < iSessionInfo.iSelectedStream.size(); i++)
{
if (!oscl_strncmp(tmpOutgoingMsg->originalURI.c_str(), iSessionInfo.iSelectedStream[i].iMediaURI.get_cstr(), tmpOutgoingMsg->originalURI.length()))
{
if (iIncomingMsg.numOfTransportEntries)
{
{//For transport options, we only let server choose
//between "RTP/AVP/UDP" or "x-pn-tng/tcp"; and for "x-pn-tng/tcp",
//we only do http cloaking. 06/03/21
ibIsRealRDT = false;
if ((iIncomingMsg.transport[0].protocol != RtspTransport::RTP_PROTOCOL)
|| (iIncomingMsg.transport[0].profile != RtspTransport::AVP_PROFILE))
{//PVMFRTSPClientEngineNodeErrorUnsupportedTransport
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorMalformedRTSPMessage;
return PVMFFailure;
}
}
iSessionInfo.iSelectedStream[i].ssrcIsSet = iIncomingMsg.transport[0].ssrcIsSet;
if (iIncomingMsg.transport[0].ssrcIsSet)
{
iSessionInfo.iSelectedStream[i].iSSRC = iIncomingMsg.transport[0].ssrc;
}
if (!(iIncomingMsg.transport[0].server_portIsSet || iIncomingMsg.transport[0].channelIsSet))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorMalformedRTSPMessage;
return PVMFFailure;
}
if (iIncomingMsg.transport[0].server_portIsSet)
{
iSessionInfo.iSelectedStream[i].iSerRTPPort = iIncomingMsg.transport[0].server_port1; //RTP
iSessionInfo.iSelectedStream[i].iSerRTCPPort = iIncomingMsg.transport[0].server_port2; //RTCP
}
if (iIncomingMsg.transport[0].channelIsSet)
{
iSessionInfo.iSelectedStream[i].iSerRTPPort = iIncomingMsg.transport[0].channel1; //RTP
iSessionInfo.iSelectedStream[i].iSerRTCPPort = iIncomingMsg.transport[0].channel2; //RTCP
//since we're here, let's set the channel id for the port as well
for (int32 j = iPortVector.size() - 1; j >= 0; j--)
{
if (((PVMFRTSPPort*)(iPortVector[j]))->iSdpTrackID == iSessionInfo.iSelectedStream[i].iSDPStreamId)
{
PVMFRTSPPort *pvPort = (PVMFRTSPPort*)(iPortVector[j]);
pvPort->iChannelID = (pvPort->bIsMedia)
? iSessionInfo.iSelectedStream[i].iSerRTPPort
: iSessionInfo.iSelectedStream[i].iSerRTCPPort;
pvPort->bIsChannelIDSet = true;
}
}
}
iSessionInfo.iSelectedStream[i].iSerIpAddr.Set(iSessionInfo.iSrvAdd.ipAddr.Str());
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::processIncomingMessage() ERROR iIncomingMsg.numOfTransportEntries = %d Ln %d", iIncomingMsg.numOfTransportEntries, __LINE__));
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorMalformedRTSPMessage;
return PVMFFailure;
}
break;
}
}
if (!iSessionInfo.tSIDIsSetFlag)
{
//server does not send the session ID
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorMissingSessionIdInServerResponse;
return PVMFFailure;
}
uint32 clock = 0;
bool overflowFlag = false;
iRoundTripClockTimeBase.GetCurrentTime32(clock, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
clock -= (uint32)iSessionInfo.clientServerDelay;
iSessionInfo.clientServerDelay = clock;
iSessionInfo.roundTripDelay =
Oscl_Int64_Utils::get_uint64_lower32(iSessionInfo.clientServerDelay);
}
else if (tmpOutgoingMsg->method == METHOD_PLAY)
{
if (iSessionInfo.iActPlayRange.format == RtspRangeType::INVALID_RANGE)
{//play
iSessionInfo.iActPlayRange = iSessionInfo.iReqPlayRange;
}
if (iIncomingMsg.rangeIsSet)
{
if ((iSessionInfo.iActPlayRange.format == iIncomingMsg.range.format)
&& (iIncomingMsg.range.format == RtspRangeType::NPT_RANGE))
{
if (iIncomingMsg.range.start_is_set)
{
iSessionInfo.iActPlayRange.start_is_set = true;
iSessionInfo.iActPlayRange.npt_start = iIncomingMsg.range.npt_start;
}
if (iIncomingMsg.range.end_is_set)
{
iSessionInfo.iActPlayRange.end_is_set = true;
iSessionInfo.iActPlayRange.npt_end = iIncomingMsg.range.npt_end;
}
}
else
{//the server actually changes the range format in one session
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::processIncomingMessage() ERROR iIncomingMsg.range.format = %d Ln %d", iIncomingMsg.range.format, __LINE__));
}
}
for (uint32 idx = 0; idx < iIncomingMsg.numOfRtpInfoEntries; idx++)
{
RTSPRTPInfo *rtpinfo = iIncomingMsg.rtpInfo + idx;
if (!rtpinfo->urlIsSet)
{//error
//break;
}
char *url_temp = (char *) rtpinfo->url.c_str();
//int url_len = rtpinfo->url.length() + 1;//Added to prevent erroneous track selection.
for (uint32 i = 0; i < iSessionInfo.iSelectedStream.size(); i++)
{
int sdp_track_id = iSessionInfo.iSelectedStream[i].iSDPStreamId;
//simplified check here.
if (NULL == oscl_strstr((iSessionInfo.iSDPinfo->getMediaInfoBasedOnID(sdp_track_id))->getControlURL(), url_temp))
{
if (NULL == oscl_strstr(url_temp, (iSessionInfo.iSDPinfo->getMediaInfoBasedOnID(sdp_track_id))->getControlURL()))
{
continue;
}
}
iSessionInfo.iSelectedStream[i].seqIsSet = rtpinfo->seqIsSet;
iSessionInfo.iSelectedStream[i].seq = rtpinfo->seq;
iSessionInfo.iSelectedStream[i].rtptimeIsSet = rtpinfo->rtptimeIsSet;
iSessionInfo.iSelectedStream[i].rtptime = rtpinfo->rtptime;
iSessionInfo.iSelectedStream[i].iSerIpAddr.Set(iSessionInfo.iSrvAdd.ipAddr.Str());
}
}
uint32 clock = 0;
bool overflowFlag = false;
iRoundTripClockTimeBase.GetCurrentTime32(clock, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
clock -= (uint32)iSessionInfo.clientServerDelay;
iSessionInfo.clientServerDelay = clock;
iSessionInfo.roundTripDelay =
Oscl_Int64_Utils::get_uint64_lower32(iSessionInfo.clientServerDelay);
}
else if (tmpOutgoingMsg->method == iKeepAliveMethod)
{
if ((iState == PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE) ||
((bKeepAliveInPlay) && (iState == PVRTSP_ENGINE_NODE_STATE_PLAY_DONE)))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::processIncomingMessage() start keep-alive timer %d. Ln %d", TIMEOUT_KEEPALIVE, __LINE__));
iWatchdogTimer->Request(REQ_TIMER_KEEPALIVE_ID, 0, TIMEOUT_KEEPALIVE);
}
}
if (tmpOutgoingMsg)
OSCL_DELETE(tmpOutgoingMsg);
}
else if ((iIncomingMsg.statusCode >= 300) && (iIncomingMsg.statusCode < 400))
{
//redirect
int32 infocode;
MapRTSPCodeToEventCode(iIncomingMsg.statusCode, infocode);
ReportInfoEvent(PVMFInfoRemoteSourceNotification, NULL, &iEventUUID, &infocode);
OSCL_DELETE(tmpOutgoingMsg);
const StrPtrLen *tmpBaseURLLoc = iIncomingMsg.queryField("Location");
//const StrPtrLen *tmpBaseURLLoc = iIncomingMsg.queryField("Content-Location");
if (tmpBaseURLLoc)
{
if (!parseURL(tmpBaseURLLoc->c_str()))
{
return PVMFFailure;
}
}
else
{
return PVMFFailure; //If Location is not present in response
}
iErrorRecoveryAttempt = iNumRedirectTrials-- ? 1 : 0;
if (iErrorRecoveryAttempt == 0)
{
iCurrentErrorCode = infocode; // Send error to application
return PVMFFailure;
}
return PVMFInfoRemoteSourceNotification;
}
else
{
if (tmpOutgoingMsg)
{
if (tmpOutgoingMsg->method == METHOD_OPTIONS)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::processIncomingMessage() OPTIONS ERROR %d Line %d", iIncomingMsg.statusCode, __LINE__));
OSCL_DELETE(tmpOutgoingMsg);
return iOutgoingMsgQueue.empty() ? PVMFSuccess : PVMFPending;
}
}
//error
MapRTSPCodeToEventCode(iIncomingMsg.statusCode, iCurrentErrorCode);
OSCL_DELETE(tmpOutgoingMsg);
return PVMFFailure;
}
return iOutgoingMsgQueue.empty() ? PVMFSuccess : PVMFPending;
//return PVMFSuccess;
}
void PVRTSPEngineNode::MapRTSPCodeToEventCode(RTSPStatusCode aStatusCode,
int32& aEventCode)
{
switch (aStatusCode)
{
case 300:
//"300" ; Multiple Choices
aEventCode = PVMRTSPClientEngineInfoRTSPRedirectCode300;
break;
case 301:
//"301" ; Moved Permanently
aEventCode = PVMRTSPClientEngineInfoRTSPRedirectCode301;
break;
case 302:
//"302" ; Moved Temporarily
aEventCode = PVMRTSPClientEngineInfoRTSPRedirectCode302;
break;
case 303:
//"303" ; See Other
aEventCode = PVMRTSPClientEngineInfoRTSPRedirectCode303;
break;
case 304:
//"304" ; Not Modified
aEventCode = PVMRTSPClientEngineInfoRTSPRedirectCode304;
break;
case 305:
//"305" ; Use Proxy
aEventCode = PVMRTSPClientEngineInfoRTSPRedirectCode305;
break;
case 400:
//"400" ; Bad Request
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode400;
break;
case 401:
//"401" ; Unauthorized
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode401;
break;
case 402:
//"402" ; Payment Required
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode402;
break;
case 403:
//"403" ; Forbidden
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode403;
break;
case 404:
//"404" ; Not Found
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode404;
break;
case 405:
//"405" ; Method Not Allowed
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode405;
break;
case 406:
//"406" ; Not Acceptable
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode406;
break;
case 407:
//"407" ; Proxy Authentication Required
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode407;
break;
case 408:
//"408" ; Request Time-out
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode408;
break;
case 410:
//"410" ; Gone
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode410;
break;
case 411:
//"411" ; Length Required
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode411;
break;
case 412:
//"412" ; Precondition Failed
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode412;
break;
case 413:
//"413" ; Request Entity Too Large
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode413;
break;
case 414:
//"414" ; Request-URI Too Large
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode414;
break;
case 415:
//"415" ; Unsupported Media Type
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode415;
break;
case 451:
//"451" ; Parameter Not Understood
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode451;
break;
case 452:
//"452" ; Conference Not Found
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode452;
break;
case 453:
//"453" ; Not Enough Bandwidth
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode453;
break;
case 454:
//"454" ; Session Not Found
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode454;
break;
case 455:
//"455" ; Method Not Valid in This State
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode455;
break;
case 456:
//"456" ; Header Field Not Valid for Resource
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode456;
break;
case 457:
//"457" ; Invalid Range
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode457;
break;
case 458:
//"458" ; Parameter Is Read-Only
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode458;
break;
case 459:
//"459" ; Aggregate operation not allowed
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode459;
break;
case 460:
//"460" ; Only aggregate operation allowed
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode460;
break;
case 461:
//"461" ; Unsupported transport
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode461;
break;
case 462:
//"462" ; Destination unreachable
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode462;
break;
case 500:
//"500" ; Internal Server Error
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode500;
break;
case 501:
//"501" ; Not Implemented
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode501;
break;
case 502:
//"502" ; Bad Gateway
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode502;
break;
case 503:
//"503" ; Service Unavailable
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode503;
break;
case 504:
//"504" ; Gateway Time-out
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode504;
break;
case 505:
//"505" ; RTSP Version not supported
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode505;
break;
case 551:
//"551" ; Option not supported
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPErrorCode551;
break;
default:
// Unknown
aEventCode = PVMFRTSPClientEngineNodeErrorRTSPCodeUnknown;
break;
}
}
PVMFStatus PVRTSPEngineNode::DoPauseNode(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoPauseNode() In"));
//If session is completed, then do not send the pause command to the server..
if (IsSessionCompleted())
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoPauseNode() Skipping sending pause 'cos of session expiry"));
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE);
return PVMFSuccess;
}
if (iInterfaceState != EPVMFNodeStarted)
{
return PVMFErrInvalidState;
}
return SendRtspPause(aCmd);
}
PVMFStatus PVRTSPEngineNode::DoStopNode(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoStopNode() In"));
if ((iInterfaceState != EPVMFNodeStarted) && (iInterfaceState != EPVMFNodePaused))
{
if (iInterfaceState == EPVMFNodeError)
{
return PVMFSuccess;
}
return PVMFErrInvalidState;
}
return SendRtspTeardown(aCmd);
}
PVMFStatus PVRTSPEngineNode::SendRtspPause(PVRTSPEngineCommand &aCmd)
{
OSCL_UNUSED_ARG(aCmd);
PVMFStatus iRet = PVMFPending;
switch (iState)
{
case PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE:
{
iRet = PVMFSuccess;
break;
}
case PVRTSP_ENGINE_NODE_STATE_PLAY_DONE:
{
if (bNoSendPending)
{
RTSPOutgoingMessage *tmpOutgoingMsg = OSCL_NEW(RTSPOutgoingMessage, ());
if (tmpOutgoingMsg == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
return PVMFFailure;
}
if (PVMFSuccess != composePauseRequest(*tmpOutgoingMsg))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPComposePauseRequestError;
OSCL_DELETE(tmpOutgoingMsg);
return PVMFFailure;
}
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_PAUSE);
//setup the watch dog for server response
iWatchdogTimer->Request(REQ_TIMER_WATCHDOG_ID, 0, TIMEOUT_WATCHDOG);
}
break;
}
case PVRTSP_ENGINE_NODE_STATE_WAIT_PAUSE:
{
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_PAUSE_DONE);
}
else if ((iRet == PVMFFailure) && (iCurrentErrorCode == PVMFRTSPClientEngineNodeErrorRTSPErrorCode455))
{//"455" ; Method Not Valid in This State
iRet = PVMFSuccess;
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE);
}
else
{ //revert to previous state,
//which means don't change to EPVMFNodeError state
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 = PVMFSuccess;
}
else if (!clearEventQueue())
{
//cancell the watchdog
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketError;
iRet = PVMFFailure;
}
break;
}
default:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::SendRtspPause() iState=%d Line %d", iState, __LINE__));
iRet = PVMFErrInvalidState;
break;
}
}
return iRet;
}
PVMFStatus PVRTSPEngineNode::DoResetNode(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoResetNode() In"));
if (iGetPostCorrelationObject != NULL)
{
OSCL_DELETE(iGetPostCorrelationObject);
iGetPostCorrelationObject = NULL;
}
return SendRtspTeardown(aCmd);
}
PVMFStatus PVRTSPEngineNode::SendRtspTeardown(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SendRtspTeardown() In"));
OSCL_UNUSED_ARG(aCmd);
/* Allow reset from any state */
PVMFStatus iRet = PVMFPending;
switch (iState)
{
case PVRTSP_ENGINE_NODE_STATE_SETUP_DONE:
case PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE:
case PVRTSP_ENGINE_NODE_STATE_PLAY_DONE:
{
if (bNoSendPending)
{
RTSPOutgoingMessage *tmpOutgoingMsg = OSCL_NEW(RTSPOutgoingMessage, ());
if (tmpOutgoingMsg == NULL)
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
return PVMFFailure;
}
if (PVMFSuccess != composeStopRequest(*tmpOutgoingMsg))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPComposeStopRequestError;
OSCL_DELETE(tmpOutgoingMsg);
return PVMFFailure;
}
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *tmpOutgoingMsg))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
OSCL_DELETE(tmpOutgoingMsg);
//maybe server closed the connection or some other errors
bNoRecvPending = false; //prevent doing recv() after the TEARDOWN
iRet = PVMFSuccess;
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_CONNECT);
break;
}
//setup the watchdog for server response
iWatchdogTimer->Request(REQ_TIMER_WATCHDOG_ID, 0, TIMEOUT_WATCHDOG_TEARDOWN);
bNoSendPending = false;
iOutgoingMsgQueue.push(tmpOutgoingMsg);
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_WAIT_STOP);
}
break;
}
case PVRTSP_ENGINE_NODE_STATE_WAIT_CALLBACK:
if ((iNumHostCallback + iNumConnectCallback + iNumSendCallback + iNumRecvCallback) == 0
&& resetSocket() != PVMFPending)
{
iRet = PVMFSuccess;
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_CONNECT);
}
break;
case PVRTSP_ENGINE_NODE_STATE_WAIT_STOP:
if (clearEventQueue() && (RTSPParser::REQUEST_IS_READY != iRTSPParserState))
{//no error and didn't get sth, TEARDOWN response or sth else, doesn't matter
break;
}
//just go to default to cleanup
default:
{
bNoRecvPending = false; //prevent doing recv() after the TEARDOWN
bNoSendPending = false; //prevent doing send() after the TEARDOWN
clearOutgoingMsgQueue();
iSocketEventQueue.clear();
PVMFStatus status = resetSocket();
iWatchdogTimer->Cancel(REQ_TIMER_WATCHDOG_ID);
iWatchdogTimer->Cancel(REQ_TIMER_KEEPALIVE_ID);
REQ_TIMER_WATCHDOG_ID = REQ_TIMER_KEEPALIVE_ID = 0;
if ((iNumHostCallback + iNumConnectCallback + iNumSendCallback + iNumRecvCallback) == 0
&& status != PVMFPending)
{
iRet = PVMFSuccess;
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_CONNECT);
}
else
{
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_WAIT_CALLBACK);
}
break;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SendRtspTeardown() Out"));
return iRet;
}
PVMFStatus PVRTSPEngineNode::DoQueryUuid(PVRTSPEngineCommand &aCmd)
{
//This node supports Query UUID from any state
OSCL_String* mimetype;
Oscl_Vector<PVUuid, PVRTSPEngineNodeAllocator> *uuidvec;
bool exactmatch;
aCmd.PVRTSPEngineCommandBase::Parse(mimetype, uuidvec, exactmatch);
//Try to match the input mimetype against any of
//the custom interfaces for this node
//Match against custom interface1...
if (*mimetype == PVMF_RTSPENGINENODE_CUSTOM1_MIMETYPE
//also match against base mimetypes for custom interface1,
//unless exactmatch is set.
|| (!exactmatch && *mimetype == PVMF_RTSPENGINENODE_MIMETYPE)
|| (!exactmatch && *mimetype == PVMF_RTSPENGINENODE_BASEMIMETYPE))
{
uuidvec->push_back(KPVRTSPEngineNodeExtensionUuid);
}
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::DoQueryInterface(PVRTSPEngineCommand &aCmd)
{
//This node supports Query Interface from any state
PVUuid* uuid;
PVInterface** ptr;
aCmd.PVRTSPEngineCommandBase::Parse(uuid, ptr);
if (*uuid == KPVRTSPEngineNodeExtensionUuid)
{
if (!iExtensionInterface)
{
iExtensionInterface = OSCL_NEW(PVRTSPEngineNodeExtensionInterfaceImpl, (this));
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVRTSPEngineNode:DoQueryInterface iExtensionInterface %x "
, iExtensionInterface));
}
if (iExtensionInterface)
{
if (iExtensionInterface->queryInterface(*uuid, *ptr))
{
return PVMFSuccess;
}
else
{
return PVMFErrNotSupported;
}
}
else
{
return PVMFErrNoMemory;
}
}
else
{//not supported
*ptr = NULL;
return PVMFErrNotSupported;
}
}
void PVRTSPEngineNode::ReportErrorEvent(PVMFEventType aEventType,
OsclAny* aEventData,
PVUuid* aEventUUID,
int32* aEventCode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVRTSPEngineNode:NodeErrorEvent Type %d Data %d"
, aEventType, aEventData));
if (aEventUUID && aEventCode)
{
PVMFBasicErrorInfoMessage* eventmsg =
OSCL_NEW(PVMFBasicErrorInfoMessage, (*aEventCode, *aEventUUID, NULL));
PVMFAsyncEvent asyncevent(PVMFErrorEvent,
aEventType,
NULL,
OSCL_STATIC_CAST(PVInterface*, eventmsg),
aEventData,
NULL,
0);
PVMFNodeInterface::ReportErrorEvent(asyncevent);
eventmsg->removeRef();
}
else
{
PVMFNodeInterface::ReportErrorEvent(aEventType, aEventData);
}
}
void PVRTSPEngineNode::ReportInfoEvent(PVMFEventType aEventType,
OsclAny* aEventData,
PVUuid* aEventUUID,
int32* aEventCode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVRTSPEngineNode:NodeInfoEvent Type %d Data %d"
, aEventType, aEventData));
if (aEventUUID && aEventCode)
{
PVMFBasicErrorInfoMessage* eventmsg =
OSCL_NEW(PVMFBasicErrorInfoMessage, (*aEventCode, *aEventUUID, NULL));
PVMFAsyncEvent asyncevent(PVMFInfoEvent,
aEventType,
NULL,
OSCL_STATIC_CAST(PVInterface*, eventmsg),
aEventData,
NULL,
0);
PVMFNodeInterface::ReportInfoEvent(asyncevent);
eventmsg->removeRef();
}
else
{
PVMFNodeInterface::ReportInfoEvent(aEventType, aEventData);
}
}
/////////////////////////////////////////////////////
// Port Processing routines
/////////////////////////////////////////////////////
void PVRTSPEngineNode::HandlePortActivity(const PVMFPortActivity &aActivity)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "0x%x PVRTSPEngineNode::HandlePortActivity: port=0x%x, type=%d IQ=%d OQ=%d",
this, aActivity.iPort, aActivity.iType, aActivity.iPort->IncomingMsgQueueSize(), aActivity.iPort->OutgoingMsgQueueSize()));
switch (aActivity.iType)
{
case PVMF_PORT_ACTIVITY_OUTGOING_MSG:
//An outgoing message was queued on this port.
//We only need to queue a port activity event on the
//first message. Additional events will be queued during
//the port processing as needed.
if (aActivity.iPort->OutgoingMsgQueueSize() == 1)
QueuePortActivity(aActivity);
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_BUSY:
iTheBusyPort = aActivity.iPort;
break;
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_BUSY:
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_READY:
//iTheBusyPort = iTheBusyPort;
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY:
if (iTheBusyPort == aActivity.iPort)
{
for (int32 i = iPortVector.size() - 1; i >= 0; i--)
{
if (((PVMFRTSPPort*)(iPortVector[i]))->OutgoingMsgQueueSize() > 0)
{
PVMFPortActivity activity(aActivity.iPort, PVMF_PORT_ACTIVITY_OUTGOING_MSG);
QueuePortActivity(activity);
}
}
if (iRTSPParserState == RTSPParser::EMBEDDED_DATA_IS_READY)
{
if (!ibBlockedOnFragGroups)
{
DispatchEmbeddedData(iIncomingMsg.channelID);
}
}
iTheBusyPort = NULL;
}
break;
case PVMF_PORT_ACTIVITY_CONNECT:
default:
break;
}
}
/////////////////////////////////////////////////////
// Port Processing routines
/////////////////////////////////////////////////////
void PVRTSPEngineNode::QueuePortActivity(const PVMFPortActivity &aActivity)
{
//queue a new port activity event
int32 err;
OSCL_TRY(err, iPortActivityQueue.push_back(aActivity););
if (err != OsclErrNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "0x%x PVRTSPEngineNode::QueuePortActivity: Error - iPortActivityQueue.push_back() failed", this));
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aActivity.iPort));
}
else
{
//wake up the AO to process the port activity event.
RunIfNotReady();
}
}
void PVRTSPEngineNode::TimeoutOccurred(int32 timerID, int32 timeoutInfo)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::TimeoutOccurred() in timerID=%d", timerID));
OSCL_UNUSED_ARG(timeoutInfo);
if (!IsAdded())
{//prevent the leave 49. should never get here
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::TimeoutOccurred() ERROR line %d", __LINE__));
return;
}
if ((timerID != REQ_TIMER_WATCHDOG_ID) && (timerID != REQ_TIMER_KEEPALIVE_ID) && (PVRTSP_ENGINE_NODE_STATE_WAIT_CALLBACK == iState))
{//waiting for the callback to finish the Stop() or Reset()
RunIfNotReady();
return;
}
if (timerID == REQ_TIMER_WATCHDOG_ID)
{//watchdog
SocketEvent tmpSockEvent;
tmpSockEvent.iSockId = timerID;
tmpSockEvent.iSockFxn = EPVSocketRecv;
tmpSockEvent.iSockEvent = EPVSocketTimeout;
tmpSockEvent.iSockError = 0;
iSocketEventQueue.push_back(tmpSockEvent);
RunIfNotReady();
}
else if (timerID == REQ_TIMER_KEEPALIVE_ID)
{//keep-alive
if ((bNoSendPending) &&
((iState == PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE)
|| ((bKeepAliveInPlay) && (iState == PVRTSP_ENGINE_NODE_STATE_PLAY_DONE))))
{
RTSPOutgoingMessage *tmpOutgoingMsg = OSCL_NEW(RTSPOutgoingMessage, ());
if (tmpOutgoingMsg == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::TimeoutOccurred ERROR out-of-memory. Ln %d", __LINE__));
//iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
return;
}
if (PVMFSuccess != composeKeepAliveRequest(*tmpOutgoingMsg))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::TimeoutOccurred ERROR composeKeepAliveRequest fail. Ln %d", __LINE__));
OSCL_DELETE(tmpOutgoingMsg);
//iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPComposeStopRequestError;
return;
}
if (PVMFSuccess != sendSocketOutgoingMsg(iSendSocket, *tmpOutgoingMsg))
{
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
OSCL_DELETE(tmpOutgoingMsg);
return;
//iRet = PVMFFailure;
//break;
}
bNoSendPending = false;
iOutgoingMsgQueue.push(tmpOutgoingMsg);
}
}
}
PVMFStatus PVRTSPEngineNode::composeKeepAliveRequest(RTSPOutgoingMessage &aMsg)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::composeKeepAliveRequest() in"));
aMsg.reset();
aMsg.numOfTransportEntries = 0;
aMsg.msgType = RTSPRequestMsg;
aMsg.method = iKeepAliveMethod;
aMsg.cseq = iOutgoingSeq++;
aMsg.cseqIsSet = true;
aMsg.userAgent = iSessionInfo.iUserAgent.get_cstr();
aMsg.userAgentIsSet = true;
if (iSessionInfo.iSID.get_size())
{
aMsg.sessionId.setPtrLen(iSessionInfo.iSID.get_cstr(), iSessionInfo.iSID.get_size());
aMsg.sessionIdIsSet = true;
}
if (composeSessionURL(aMsg) != PVMFSuccess)
{
return PVMFFailure;
}
if (aMsg.compose() == false)
{
return PVMFFailure;
}
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetKeepAliveMethod_timeout(int32 aTimeout)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SetKeepAliveMethod_timeout() in aTimeout=%d", aTimeout));
//user server timeout if aTimeout == 0
aTimeout = aTimeout / 1000; //sec
if (aTimeout)
{
if (aTimeout > 0)//if(aTimeout > 3000)
{
TIMEOUT_KEEPALIVE = aTimeout;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SetKeepAliveMethod() ERROR aTimeout=%d. Ln %d", aTimeout, __LINE__));
return PVMFFailure;
}
}
else
{
TIMEOUT_KEEPALIVE = PVRTSPENGINENODE_DEFAULT_KEEP_ALIVE_INTERVAL;
}
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetKeepAliveMethod_use_SET_PARAMETER(bool aUseSetParameter)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SetKeepAliveMethod_timeout() in aUseSetParameter=%d", aUseSetParameter));
iKeepAliveMethod = aUseSetParameter ? METHOD_SET_PARAMETER : METHOD_OPTIONS;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetKeepAliveMethod_keep_alive_in_play(bool aKeepAliveInPlay)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SetKeepAliveMethod_timeout() in aKeepAliveInPlay=%d", aKeepAliveInPlay));
bKeepAliveInPlay = aKeepAliveInPlay;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetKeepAliveMethod(int32 &aTimeout, bool &aUseSetParameter, bool &aKeepAliveInPlay)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::GetKeepAliveMethod() in"));
aTimeout = TIMEOUT_KEEPALIVE * 1000;
aUseSetParameter = (METHOD_SET_PARAMETER == iKeepAliveMethod);
aKeepAliveInPlay = bKeepAliveInPlay;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::GetRTSPTimeOut(int32 &aTimeout)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::GetRTSPTimeOut() In"));
aTimeout = TIMEOUT_WATCHDOG;
return PVMFSuccess;
}
OSCL_EXPORT_REF PVMFStatus PVRTSPEngineNode::SetRTSPTimeOut(int32 aTimeout)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::SetRTSPTimeOut() In"));
TIMEOUT_WATCHDOG = aTimeout;
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::DoRequestPort(PVRTSPEngineCommand &aCmd, PVMFRTSPPort* &aPort)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoRequestPort() In"));
aPort = NULL;
//retrieve port tag.
int32 tag;
OSCL_String* portconfig;
aCmd.PVRTSPEngineCommandBase::Parse(tag, portconfig);
OSCL_HeapString<PVRTSPEngineNodeAllocator> tmpPortConfig = portconfig->get_cstr();
char *head = tmpPortConfig.get_str();
if ((!head) ||
((tag != PVMF_RTSP_NODE_PORT_TYPE_OUTPUT) && (tag != PVMF_RTSP_NODE_PORT_TYPE_INPUT_OUTPUT)))
{
return PVMFErrArgument;//invalide portconfig.
}
//portconfig should be "sdpTrackIndex=5/media" or "sdpTrackIndex=5/feedback"
bool bIsMedia = true;
OSCL_StackString<128> IsMedia("/media");
char *tmpCh = OSCL_CONST_CAST(char*, oscl_strstr(head, IsMedia.get_cstr()));
if (!tmpCh)
{
OSCL_StackString<128> IsFeedback("/feedback");
tmpCh = OSCL_CONST_CAST(char*, oscl_strstr(head, IsFeedback.get_cstr()));
if (!tmpCh)
{
return PVMFErrArgument;
}
bIsMedia = false;
}
*tmpCh = '\0'; //set the delimiter for atoi
OSCL_StackString<128> sdpTrackIndex("sdpTrackIndex=");
tmpCh = OSCL_CONST_CAST(char*, oscl_strstr(head, sdpTrackIndex.get_cstr()));
if (!tmpCh)
{
return PVMFErrArgument;
}
tmpCh += sdpTrackIndex.get_size();
uint32 atoi_tmp;
int32 tmpId = -1; //invalide sdp track id
if (PV_atoi(tmpCh, 'd', atoi_tmp))
{
tmpId = atoi_tmp;
}
if (tmpId < 0)
{
return PVMFErrArgument;//invalide portconfig.
}
// statements were moved to sep. function to remove compiler warnings caused by OSCL_TRY()
return DoAddPort(tmpId, bIsMedia, tag, aPort);
}
PVMFStatus PVRTSPEngineNode::DoAddPort(int32 id, bool isMedia, int32 tag, PVMFRTSPPort* &aPort)
{
int32 leavecode;
OSCL_TRY(leavecode,
aPort = OSCL_STATIC_CAST(PVMFRTSPPort*, OSCL_NEW(PVMFRTSPPort, (id, isMedia, tag, this)));
iPortVector.AddL(aPort);
);
if (leavecode != OsclErrNone)
{
if (NULL == aPort)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DoAddPort() new port fail ERROR leavecode=%d Ln %d", leavecode, __LINE__));
}
return PVMFErrNoMemory;
}
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::DoReleasePort(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoReleasePort() In"));
//Find the port in the port vector
PVMFPortInterface* port;
aCmd.PVRTSPEngineCommandBase::Parse(port);
return PVMFSuccess;
}
/* allocate aReqBufSize memory for iEmbeddedData
return true if memory is successfully allocated
*/
bool PVRTSPEngineNode::PrepareEmbeddedDataMemory(uint32 aReqBufSize, OsclMemoryFragment &aMemFrag)
{
//PVMFSimpleMediaBufferCombinedAlloc media_data_alloc;
//OsclSharedPtr<PVMFMediaDataImpl> media_data_imp = media_data_alloc.allocate(aReqBufSize);
// Allocator for simple media data buffer impl
OsclSharedPtr<PVMFMediaDataImpl> media_data_imp;
int32 errcode;
OSCL_TRY(errcode, media_data_imp = iMediaDataImplAlloc->allocate(aReqBufSize));
if (errcode != 0)
{
OSCL_ASSERT(false);//there is no limit for the allocator num of buffers for now
ReportErrorEvent(PVMFErrArgument, NULL);
return false;
}
//OsclSharedPtr<PVMFMediaDataImpl> media_data_imp = myAllocate(aReqBufSize);
// create a media data buffer
iEmbeddedDataPtr = PVMFMediaData::createMediaData(media_data_imp, &iAlloc);
iEmbeddedDataPtr->setMediaFragFilledLen(0, aReqBufSize);
OsclRefCounterMemFrag refCtrMemFragOut;
iEmbeddedDataPtr->getMediaFragment(0, refCtrMemFragOut);
aMemFrag = refCtrMemFragOut.getMemFrag();
return (aMemFrag.ptr == NULL) ? false : true;
}
/* dispatch the embedded data in iEmbeddedData to different ports according to channel id
return true if send success
*/
bool PVRTSPEngineNode::DispatchEmbeddedData(uint32 aChannelID)
{
if (iTheBusyPort)
{
return false;
}
if (ibIsRealRDT)
{
return DispatchEmbeddedRdtData();
}
PVMFRTSPPort* pvPort = NULL;
for (int32 i = iPortVector.size() - 1; i >= 0; i--)
{
if ((((PVMFRTSPPort*)(iPortVector[i]))->iChannelID == aChannelID)
&& ((PVMFRTSPPort*)(iPortVector[i]))->bIsChannelIDSet)
{
pvPort = (PVMFRTSPPort*)(iPortVector[i]);
break;
}
}
if (pvPort == NULL)
{//no pvMF port is setup to get this channel, discard the data
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DispatchEmbeddedData() channel:%d data discarded.", aChannelID));
iEmbeddedDataPtr.Unbind();
return true;
}
PVMFSharedMediaMsgPtr aMediaMsgPtr;
convertToPVMFMediaMsg(aMediaMsgPtr, iEmbeddedDataPtr);
PVMFStatus status = pvPort->QueueOutgoingMsg(aMediaMsgPtr);
if (status != PVMFSuccess)
{
if (status == PVMFErrBusy)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVRTSPEngineNode::DispatchEmbeddedData() BUSY:%d, Outgoing queue size=%d.", status, pvPort->OutgoingMsgQueueSize()));
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DispatchEmbeddedData() ERROR:%d, Outgoing queue size=%d. Data discarded!", status, pvPort->OutgoingMsgQueueSize()));
ReportErrorEvent(PVMFErrPortProcessing);
}
return false;
}
return true;
}
bool PVRTSPEngineNode::DispatchEmbeddedRdtData()
{
IPayloadParser::Payload incomingFrag;
Oscl_Vector<IPayloadParser::Payload, OsclMemAllocator> vRdtPackets;
// retrieve the incoming RDT packet mem fragment
OsclRefCounterMemFrag frag;
iEmbeddedDataPtr->getMediaFragment(0, frag);
incomingFrag.vfragments.push_back(frag);
// parse the RDT headers and retrieve the payloads
if (ipRdtParser->Parse(incomingFrag, vRdtPackets) != PayloadParserStatus_Success)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DispatchEmbeddedRdtData() Unable to parse RDT packet!"));
iEmbeddedDataPtr.Unbind();
return true;
}
uint32 i = 0;
for (i = 0; i < vRdtPackets.size(); i++)
{
if (!ipFragGroupAllocator->IsMsgAvailable())
{
// drop this packet
iEmbeddedDataPtr.Unbind();
vRdtPackets.clear();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVRTSPEngineNode::DispatchEmbeddedRdtData() Out of memory! Stopping processing and dropping packet"));
// block processing until we get a callback
ibBlockedOnFragGroups = true;
ipFragGroupAllocator->notifyfreechunkavailable(*this, NULL);
}
OsclSharedPtr<PVMFMediaDataImpl> mediaDataImplOut;
int32 err;
mediaDataImplOut = AllocateMediaData(err);
OSCL_ASSERT(err == OsclErrNone); // we just checked that a message is available
if (err != OsclErrNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DispatchEmbeddedRdtData() Unable to allocate media data impl!"));
return true;
}
IPayloadParser::Payload rdtOut = vRdtPackets[i];
mediaDataImplOut->setMarkerInfo(rdtOut.marker);
mediaDataImplOut->appendMediaFragment(rdtOut.vfragments[0]);
PVMFSharedMediaDataPtr mediaDataOut = PVMFMediaData::createMediaData(mediaDataImplOut);
mediaDataOut->setSeqNum(rdtOut.sequence);
mediaDataOut->setStreamID(rdtOut.stream);
mediaDataOut->setTimestamp(rdtOut.timestamp);
// which port?
PVMFRTSPPort* pvPort = NULL;
for (int p = iPortVector.size() - 1; p >= 0; p--)
{
if ((uint)((PVMFRTSPPort*)(iPortVector[p]))->iRdtStreamId == rdtOut.stream)
{
pvPort = (PVMFRTSPPort*)(iPortVector[p]);
break;
}
}
if (pvPort == NULL)
{//no pvMF port is setup to get this channel, discard the data
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DispatchEmbeddedRdtData() channel:%d data discarded.", rdtOut.stream));
iEmbeddedDataPtr.Unbind();
return true;
}
PVMFSharedMediaMsgPtr mediaMsgPtr;
convertToPVMFMediaMsg(mediaMsgPtr, mediaDataOut);
PVMFStatus status = pvPort->QueueOutgoingMsg(mediaMsgPtr);
if (status != PVMFSuccess)
{
if (status == PVMFErrBusy)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVRTSPEngineNode::DispatchEmbeddedRdtData() BUSY:%d, Outgoing queue size=%d.", status, pvPort->OutgoingMsgQueueSize()));
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::DispatchEmbeddedRdtData() ERROR:%d, Outgoing queue size=%d. Data discarded!", status, pvPort->OutgoingMsgQueueSize()));
ReportErrorEvent(PVMFErrPortProcessing);
}
return false;
}
}
return true;
}
PVMFStatus PVRTSPEngineNode::DoFlush(PVRTSPEngineCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoFlush() In"));
OSCL_UNUSED_ARG(aCmd);
if ((iInterfaceState != EPVMFNodeStarted) && (iInterfaceState != EPVMFNodePaused))
{
return PVMFErrInvalidState;
}
//Notify all ports to suspend their input
{
for (uint32 i = 0; i < iPortVector.size(); i++)
iPortVector[i]->SuspendInput();
}
//the flush is asynchronous. Completion is detected in the Run.
//Make sure the AO is active to finish the flush..
RunIfNotReady();
return PVMFPending;
}
PVMFStatus PVRTSPEngineNode::sendSocketOutgoingMsg(SocketContainer &aSock, RTSPOutgoingMessage &aMsg)
{
StrPtrLen *tmpStrPtrLen = aMsg.retrieveComposedBuffer();
if (NULL == tmpStrPtrLen)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::sendSocketOutgoingMsg() retrieveComposedBuffer() ERROR, line %d", __LINE__));
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPCompose501ResponseError;
return PVMFFailure;
}
//PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"C ---> S\n%s", tmpStrPtrLen->c_str()));
if (aSock.iSocket->Send((const uint8*)tmpStrPtrLen->c_str(), tmpStrPtrLen->length(), TIMEOUT_SEND) != EPVSocketPending)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::sendSocketOutgoingMsg() Send() ERROR, line %d", __LINE__));
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
return PVMFFailure;
}
SetSendPending(aSock);
iNumSendCallback++;
return PVMFSuccess;
}
PVMFStatus PVRTSPEngineNode::sendSocketOutgoingMsg(SocketContainer &aSock, const uint8* aSendBuf, uint32 aSendLen)
{
if (aSock.iSocket->Send(aSendBuf, aSendLen, TIMEOUT_SEND) != EPVSocketPending)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::sendSocketOutgoingMsg() Send() ERROR, line %d", __LINE__));
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorSocketSendError;
return PVMFFailure;
}
SetSendPending(aSock);
iNumSendCallback++;
return PVMFSuccess;
}
//drive the parser, return true if there is a pending event
bool PVRTSPEngineNode::rtspParserLoop(void)
{
if ((iRTSPParser == NULL) || (NULL != iTheBusyPort)
|| (iRecvSocket.iSocket == NULL) || (EPVMFNodeError == iInterfaceState))
{
return false;
}
bool bLoop = true, ret = false;
while (bLoop)
{
iRTSPParserState = iRTSPParser->getState();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVRTSPEngineNode::rtspParserLoop() RTSPParser state %d", iRTSPParserState));
switch (iRTSPParserState)
{
case RTSPParser::WAITING_FOR_DATA:
{
if (bNoRecvPending)
{
TPVSocketEvent tmpEvent = EPVSocketFailure;
const StrPtrLen *tmpbuf = iRTSPParser->getDataBufferSpec();
if (tmpbuf) // unlikely to fail, err rtn from getDataBufferSpec
{
tmpEvent = iRecvSocket.iSocket->Recv((uint8*)tmpbuf->c_str(), tmpbuf->length(), TIMEOUT_RECV);
}
if (tmpEvent != EPVSocketPending)
{
int32 errcode = PVMFRTSPClientEngineNodeErrorSocketRecvError;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::rtspParserLoop() Recv failed"));
ReportErrorEvent(PVMFErrProcessing, NULL, &iEventUUID, &errcode);
ChangeExternalState(EPVMFNodeError);
}
else
{
SetRecvPending(iRecvSocket);
iNumRecvCallback++;
}
bNoRecvPending = false;
}
bLoop = false;
break;
}
case RTSPParser::WAITING_FOR_REQUEST_MEMORY:
{
iIncomingMsg.reset();
if (!iRTSPParser->registerNewRequestStruct(&iIncomingMsg))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::rtspParserLoop() registerNewRequestStruct failed"));
ChangeExternalState(EPVMFNodeError);
}
break;
}
case RTSPParser::ENTITY_BODY_IS_READY:
((uint8*)iEntityMemFrag.ptr)[iEntityMemFrag.len-1] = '\0';
//let the Doxxx() to process the entity body, like sdp, still img, and server msg
case RTSPParser::REQUEST_IS_READY:
{
bLoop = false;
ret = true;
break;
}
case RTSPParser::WAITING_FOR_ENTITY_BODY_MEMORY:
{/*
OsclSharedPtr<PVMFMediaDataImpl> media_data_imp;
int32 errcode;
OSCL_TRY(errcode, media_data_imp = iMediaDataImplAlloc->allocate(iIncomingMsg.contentLength+1));
if (errcode != OsclErrNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0,"PVRTSPEngineNode::rtspParserLoop() registerEntityBody failed"));
OSCL_ASSERT(false);//there is no limit for the allocator num of buffers for now
ChangeExternalState(EPVMFNodeError);
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
ReportErrorEvent(PVMFErrProcessing, NULL, &iEventUUID, &iCurrentErrorCode);
bLoop = false;
ret = true;
break;
}
media_data_imp->getMediaFragment(0, iEntityMemFrag);
(iEntityMemFrag.getMemFrag()).len = iEntityMemFrag.getCapacity();
*/
if ((iEntityMemFrag.len > 0) || (iEntityMemFrag.ptr != NULL))
{
OSCL_FREE(iEntityMemFrag.ptr);
iEntityMemFrag.len = 0;
iEntityMemFrag.ptr = NULL;
}
iEntityMemFrag.len = 0;
iEntityMemFrag.ptr = OSCL_MALLOC(iIncomingMsg.contentLength + 1);
//PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0,"PVRTSPEngineNode::rtspParserLoop() registerEntityBody failed"));
OsclError::LeaveIfNull(iEntityMemFrag.ptr);
iEntityMemFrag.len = (iIncomingMsg.contentLength + 1);
if (!iRTSPParser->registerEntityBody(&iEntityMemFrag))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::rtspParserLoop() registerEntityBody failed"));
//iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorOutOfMemory;
ChangeExternalState(EPVMFNodeError);
iCurrentErrorCode = PVMFRTSPClientEngineNodeErrorRTSPParserError;
ReportErrorEvent(PVMFErrProcessing, NULL, &iEventUUID, &iCurrentErrorCode);
bLoop = false;
ret = true;
}
break;
}
case RTSPParser::WAITING_FOR_EMBEDDED_DATA_MEMORY:
{//TCP streaming
RTSPEntityBody iEmbeddedData;
if (!PrepareEmbeddedDataMemory(iIncomingMsg.contentLength, iEmbeddedData))
{//no memory available TBD
bLoop = false;
break;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVRTSPEngineNode::rtspParserLoop() RTP pkts channelID=%d, len=%d", iIncomingMsg.channelID, iIncomingMsg.contentLength));
iRTSPParser->registerEmbeddedDataMemory(&iEmbeddedData);
break;
}
case RTSPParser::EMBEDDED_DATA_IS_READY:
{//process the data
if (!ibBlockedOnFragGroups)
{
if (! DispatchEmbeddedData(iIncomingMsg.channelID)) //, iEmbeddedData))
{//send busy or fails
bLoop = false;
}
}
break;
}
case RTSPParser::ERROR_REQUEST_TOO_BIG:
{
int32 errcode = PVMFRTSPClientEngineNodeErrorRTSPRequestTooBig;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::rtspParserLoop() registerEntityBody failed"));
ChangeExternalState(EPVMFNodeError);
ReportErrorEvent(PVMFErrProcessing, NULL, &iEventUUID, &errcode);
bLoop = false;
break;
}
case RTSPParser::INTERNAL_ERROR:
default:
{
int32 errcode = PVMFRTSPClientEngineNodeErrorRTSPParserError;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::rtspParserLoop() registerEntityBody failed"));
ChangeExternalState(EPVMFNodeError);
ReportErrorEvent(PVMFErrProcessing, NULL, &iEventUUID, &errcode);
bLoop = false;
break;
}
}
}
return ret;
}
void PVRTSPEngineNode::freechunkavailable(OsclAny*)
{
ibBlockedOnFragGroups = false;
}
PVMFStatus PVRTSPEngineNode::DoErrorRecovery(PVRTSPEngineCommand &aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::DoReleasePort() In"));
//get error context
PVRTSPErrorContext* errorContext = OSCL_STATIC_CAST(PVRTSPErrorContext*, aCmd.iParam1);
if (errorContext == NULL)
{
return PVMFFailure;
}
PVMFStatus myRet = PVMFPending;
{
if (PVRTSP_ENGINE_NODE_STATE_DESCRIBE_DONE > iState)
{
myRet = SendRtspDescribe(aCmd);
}
else if (PVRTSP_ENGINE_NODE_STATE_SETUP_DONE > iState)
{
myRet = SendRtspSetup(aCmd);
if (myRet == PVMFSuccess)
{//send OPTIONS and keep the connection alive
//and wait for new Start() request
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_PAUSE_DONE);
}
}
}
if ((PVMFSuccess != myRet) && (PVMFPending != myRet))
{/*error during error handling
1. decrease the recovery count counter
2. reset the socket
3. change the iState to restart again
*/
if (iErrorRecoveryAttempt-- <= 0)
{
return PVMFFailure;
}
//TBD reset the socket
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_IDLE);
RunIfNotReady();
}
else if (iState >= errorContext->iErrState)
{
return PVMFSuccess;
}
if (PVMFSuccess == myRet)
{
RunIfNotReady();
}
return PVMFPending;
}
//This routine is called repeatedly to drive the socket cleanup sequence.
// Step 1: Cancel DNS & socket operations & wait on completion
// Step 2: Shutdown sockets & wait on completion
// Step 3: Delete sockets
//
// If "Immediate" is set we just delete sockets without shutdown sequence.
PVMFStatus PVRTSPEngineNode::resetSocket(bool aImmediate)
{
//Make sure things aren't already cleaned up.
if (!iDNS.IsBusy()
&& !iSendSocket.iSocket
&& !iRecvSocket.iSocket)
{
//Nothing to do!
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Nothing to do!"));
}
return PVMFSuccess;
}
if (aImmediate)
{
//force immediate cleanup, for use in destructor where we can't wait
//on any async ops.
//see if we have one socket or two.
bool oneSocket = (iSendSocket.iSocket == iRecvSocket.iSocket);
if (iSendSocket.iSocket)
{
iSendSocket.iSocket->~OsclTCPSocket();
iAlloc.deallocate(iSendSocket.iSocket);
iSendSocket.iSocket = NULL;
}
if (iRecvSocket.iSocket)
{
//guard against duplicate destroy/free
if (!oneSocket)
{
iRecvSocket.iSocket->~OsclTCPSocket();
iAlloc.deallocate(iRecvSocket.iSocket);
}
iRecvSocket.iSocket = NULL;
}
return PVMFSuccess;
}
bool waitOnAsyncOp = false;
while (!waitOnAsyncOp)
{
switch (iSocketCleanupState)
{
case ESocketCleanup_Idle:
//Start a new sequence.
iSocketCleanupState = ESocketCleanup_CancelCurrentOp;
break;
case ESocketCleanup_CancelCurrentOp:
//Step 1: Cancel current operations
//Cancel ops on DNS
if (iDNS.iDns)
{
if (iDNS.iState.iPending
&& !iDNS.iState.iCanceled)
{
iDNS.iDns->CancelGetHostByName();
iDNS.iState.iCanceled = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Cancel GetHostByName"));
}
}
}
//Cancel ops on send socket.
if (iSendSocket.iSocket)
{
if (iSendSocket.iConnectState.iPending
&& !iSendSocket.iConnectState.iCanceled)
{
iSendSocket.iSocket->CancelConnect();
iSendSocket.iConnectState.iCanceled = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Cancel Connect"));
}
}
if (iSendSocket.iSendState.iPending
&& !iSendSocket.iSendState.iCanceled)
{
iSendSocket.iSocket->CancelSend();
iSendSocket.iSendState.iCanceled = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Cancel Send"));
}
}
if (iSendSocket.iRecvState.iPending
&& !iSendSocket.iRecvState.iCanceled)
{
iSendSocket.iSocket->CancelRecv();
iSendSocket.iRecvState.iCanceled = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Cancel Recv"));
}
}
OSCL_ASSERT(!iSendSocket.iShutdownState.iPending);
}
//Cancel ops on recv socket only when it's
//a unique socket.
if (iRecvSocket.iSocket
&& iRecvSocket.iSocket != iSendSocket.iSocket)
{
if (iRecvSocket.iConnectState.iPending
&& !iRecvSocket.iConnectState.iCanceled)
{
iRecvSocket.iSocket->CancelConnect();
iRecvSocket.iConnectState.iCanceled = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Cancel Connect (recv sock)"));
}
}
if (iRecvSocket.iSendState.iPending
&& !iRecvSocket.iSendState.iCanceled)
{
iRecvSocket.iSocket->CancelSend();
iRecvSocket.iSendState.iCanceled = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Cancel Send (recv sock)"));
}
}
if (iRecvSocket.iRecvState.iPending
&& !iRecvSocket.iRecvState.iCanceled)
{
iRecvSocket.iSocket->CancelRecv();
iRecvSocket.iRecvState.iCanceled = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Cancel Recv (recv sock)"));
}
}
OSCL_ASSERT(!iRecvSocket.iShutdownState.iPending);
}
if (iDNS.IsBusy()
|| iSendSocket.IsBusy()
|| iRecvSocket.IsBusy())
{
waitOnAsyncOp = true;
}
//Either go to wait state or continue to Step 2.
if (waitOnAsyncOp)
iSocketCleanupState = ESocketCleanup_WaitOnCancel;
else
iSocketCleanupState = ESocketCleanup_Shutdown;
break;
case ESocketCleanup_WaitOnCancel:
//Wait on cancel completion for all.
if (iDNS.IsBusy()
|| iSendSocket.IsBusy()
|| iRecvSocket.IsBusy())
{
waitOnAsyncOp = true;
}
if (!waitOnAsyncOp)
iSocketCleanupState = ESocketCleanup_Shutdown;
break;
case ESocketCleanup_Shutdown:
//Step 2: shutdown both sockets
if (iDNS.iDns)
{
OSCL_ASSERT(!iDNS.IsBusy());
}
if (iSendSocket.iSocket)
{
OSCL_ASSERT(!iSendSocket.IsBusy());
if (iSendSocket.iSocket->Shutdown(EPVSocketBothShutdown, TIMEOUT_SHUTDOWN) == EPVSocketPending)
{
iSendSocket.iShutdownState.iPending = true;
waitOnAsyncOp = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Shutdown"));
}
}
//else shutdown failed, ignore & continue
else
{
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Shutdown Failed"));
}
}
}
//shutown recv socket only when it's a unique socket.
if (iRecvSocket.iSocket
&& iRecvSocket.iSocket != iSendSocket.iSocket)
{
OSCL_ASSERT(!iRecvSocket.IsBusy());
if (iRecvSocket.iSocket->Shutdown(EPVSocketBothShutdown, TIMEOUT_SHUTDOWN) == EPVSocketPending)
{
iRecvSocket.iShutdownState.iPending = true;
waitOnAsyncOp = true;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Shutdown (recv sock)"));
}
}
//else shutdown failed, ignore & continue
else
{
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Shutdown Failed (recv sock)"));
}
}
}
//Either go to wait state or continue to Step 3.
if (waitOnAsyncOp)
iSocketCleanupState = ESocketCleanup_WaitOnShutdown;
else
iSocketCleanupState = ESocketCleanup_Delete;
break;
case ESocketCleanup_WaitOnShutdown:
//Wait on shutdown completion for both sockets.
if (iSendSocket.IsBusy()
|| iRecvSocket.IsBusy())
{
waitOnAsyncOp = true;
}
if (!waitOnAsyncOp)
iSocketCleanupState = ESocketCleanup_Delete;
break;
case ESocketCleanup_Delete:
// Step 3: Delete sockets
// Note: we assume this calling context is not the socket callback, so
// it's safe to delete the OsclSocket object here.
{
//see if we have one socket or two.
bool oneSocket = (iSendSocket.iSocket == iRecvSocket.iSocket);
if (iSendSocket.iSocket)
{
OSCL_ASSERT(!iSendSocket.IsBusy());
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Delete TCP"));
}
iSendSocket.iSocket->~OsclTCPSocket();
iAlloc.deallocate(iSendSocket.iSocket);
iSendSocket.iSocket = NULL;
}
if (iRecvSocket.iSocket)
{
OSCL_ASSERT(!iRecvSocket.IsBusy());
//guard against duplicate destroy/free
if (!oneSocket)
{
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Delete TCP (recv sock)"));
}
iRecvSocket.iSocket->~OsclTCPSocket();
iAlloc.deallocate(iRecvSocket.iSocket);
}
iRecvSocket.iSocket = NULL;
}
bNoSendPending = bNoRecvPending = false;
ChangeInternalState(PVRTSP_ENGINE_NODE_STATE_IDLE);
}
iSocketCleanupState = ESocketCleanup_Idle;
if (iLogger)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::resetSocket() Done!"));
}
return PVMFSuccess; //Done!
default:
OSCL_ASSERT(0);
break;
}
}
return (waitOnAsyncOp) ? PVMFPending : PVMFSuccess;
}
void PVRTSPEngineNode::SetSendPending(SocketContainer& aSock)
{
//Set "send pending" condition on a socket container.
//update recv socket container only when we have a unique recv socket,
//otherwise update send socket container.
if (aSock.iSocket == iRecvSocket.iSocket
&& iRecvSocket.iSocket != iSendSocket.iSocket)
iRecvSocket.iSendState.iPending = true;
else
{
iSendSocket.iSendState.iPending = true;
OSCL_ASSERT(aSock.iSocket == iSendSocket.iSocket);
}
}
void PVRTSPEngineNode::SetRecvPending(SocketContainer& aSock)
{
//Set "recv pending" condition on a socket container.
//update recv socket container only when we have a unique recv socket,
//otherwise update send socket container.
if (aSock.iSocket == iRecvSocket.iSocket
&& iRecvSocket.iSocket != iSendSocket.iSocket)
iRecvSocket.iRecvState.iPending = true;
else
{
iSendSocket.iRecvState.iPending = true;
OSCL_ASSERT(aSock.iSocket == iSendSocket.iSocket);
}
}
OsclLeaveCode PVRTSPEngineNode::RunError(OsclLeaveCode aError)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRTSPEngineNode::RunError() aError=%d", aError));
//return OsclErrNone;
return aError;
}
void PVRTSPEngineNode::clearOutgoingMsgQueue()
{
while (!iOutgoingMsgQueue.empty())
{
//pop the outgoing msg queue and see the match
RTSPOutgoingMessage* tmpOutgoingMsg = iOutgoingMsgQueue.top();
iOutgoingMsgQueue.pop();
if (tmpOutgoingMsg)
OSCL_DELETE(tmpOutgoingMsg);
}
}
void PVRTSPEngineNode::partialResetSessionInfo()
{
iOutgoingSeq = 0;
setupTrackIndex = 0;
iSessionInfo.iSID = "";
iSessionInfo.iReqPlayRange.format = RtspRangeType::INVALID_RANGE;
iSessionInfo.bExternalSDP = false;
iSessionInfo.pvServerIsSetFlag = false;
iSessionInfo.roundTripDelay = 0;
iSessionInfo.iSDPinfo.Unbind();
}
void PVRTSPEngineNode::ResetSessionInfo()
{
iOutgoingSeq = 0;
setupTrackIndex = 0;
iSessionInfo.iSID = "";
iSessionInfo.iReqPlayRange.format = RtspRangeType::INVALID_RANGE;
iSessionInfo.bExternalSDP = false;
iSessionInfo.pvServerIsSetFlag = false;
iSessionInfo.roundTripDelay = 0;
iSessionInfo.iSDPinfo.Unbind();
}
//clear the internal event queue "iSocketEventQueue"
//return false if any of the event indicate failure
bool PVRTSPEngineNode::clearEventQueue(void)
{
bool myRet = true;
while (!iSocketEventQueue.empty())
{
SocketEvent tmpSockEvent(iSocketEventQueue.front());
iSocketEventQueue.erase(&iSocketEventQueue.front());
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::clearEventQueue() In iFxn=%d iSockEvent=%d iSockError=%d ", tmpSockEvent.iSockFxn, tmpSockEvent.iSockEvent, tmpSockEvent.iSockError));
if (tmpSockEvent.iSockEvent != EPVSocketSuccess)
{
myRet = false;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVRTSPEngineNode::clearEventQueue() Socket Error"));
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVRTSPEngineNode::clearEventQueue() Out myRet=%d ", myRet));
return myRet;
}
////////////////////////////////////////////////////////////////////////////////
/// GetPostCorrelationObject Implementation
////////////////////////////////////////////////////////////////////////////////
#define KGetPostCorrelationFile _STRLIT("get_post_correlation_number.dat")
GetPostCorrelationObject* GetPostCorrelationObject::create(OSCL_TCHAR* aFileName)
{
GetPostCorrelationObject *object = OSCL_NEW(GetPostCorrelationObject, ());
if (!object) return NULL;
if (!object->construct(aFileName))
{
OSCL_DELETE(object);
return NULL;
}
return object;
}
bool GetPostCorrelationObject::construct(OSCL_TCHAR* aFileName)
{
iGetPostCorrelation = 1;
iFileCreated = false;
iFs.Connect();
OSCL_TCHAR* aLocalFileName = aFileName;
if (!aLocalFileName) aLocalFileName = (OSCL_TCHAR*)KGetPostCorrelationFile;
if (iGetPostCorrelationFile.Open(aLocalFileName, Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, iFs) == 0)
{
// get the current iGetPostCorrelation
iGetPostCorrelationFile.Read(&iGetPostCorrelation, sizeof(iGetPostCorrelation), 1);
iGetPostCorrelationFile.Close();
}
if (iGetPostCorrelationFile.Open(aLocalFileName, Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY, iFs))
{
iFs.Close();
return false;
}
iFileCreated = true;
return true;
}
GetPostCorrelationObject::~GetPostCorrelationObject()
{
if (iFileCreated) closeFile();
iFileCreated = false;
}
void GetPostCorrelationObject::closeFile()
{
writeToFile();
iGetPostCorrelationFile.Close();
iFs.Close();
}
bool GetPostCorrelationObject::writeToFile()
{
// always write at the beginning
if (iGetPostCorrelationFile.Seek(0, Oscl_File::SEEKSET)) return false;
if (iGetPostCorrelationFile.Write(&iGetPostCorrelation, sizeof(iGetPostCorrelation), 1) != 1)
{
return false;
}
// Flush the data to file
iGetPostCorrelationFile.Flush();
return true;
}
bool GetPostCorrelationObject::update()
{
if (!iFileCreated) return false;
// increase iGetPostCorrelation by 1 within [1, 255]
if (iGetPostCorrelation == 255) iGetPostCorrelation = 1;
else ++iGetPostCorrelation;
return writeToFile();
}
/**
* Called by the command handler AO to do the Cancel All
*/
PVMFStatus PVRTSPEngineNode::DoCancelAllCommands(PVRTSPEngineCommand& aCmd)
{
/* cancel all queued commands */
while (!iPendingCmdQueue.empty())
CommandComplete(iPendingCmdQueue, iPendingCmdQueue[1], PVMFErrCancelled);
if (iRunningCmdQueue.size() > 1)
{
MoveCmdToCancelQueue(aCmd);
return PVMFPending;
}
return PVMFSuccess;
}
void PVRTSPEngineNode::MoveCmdToCancelQueue(PVRTSPEngineCommand& aCmd)
{
/*
* note: the StoreL cannot fail since the queue is never more than 1 deep
* and we reserved space.
*/
iCancelCmdQueue.StoreL(aCmd);
iRunningCmdQueue.Erase(&aCmd);
}
OsclSharedPtr<PVMFMediaDataImpl> PVRTSPEngineNode::AllocateMediaData(int32& errCode)
{
OsclSharedPtr<PVMFMediaDataImpl> mediaDataImplOut;
OSCL_TRY(errCode, mediaDataImplOut = ipFragGroupAllocator->allocate());
return mediaDataImplOut;
}