Add even more of the source
This should be about everything needed to build so far?
This commit is contained in:
parent
af3619d4fa
commit
849723c9cf
547 changed files with 149239 additions and 0 deletions
750
APIModules/QTSSReflectorModule/RTSPSourceInfo.cpp
Normal file
750
APIModules/QTSSReflectorModule/RTSPSourceInfo.cpp
Normal file
|
@ -0,0 +1,750 @@
|
|||
/*
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*
|
||||
*/
|
||||
/*
|
||||
File: RTSPSourceInfo.cpp
|
||||
|
||||
Contains:
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include "RTSPSourceInfo.h"
|
||||
#include "StringParser.h"
|
||||
#include "SDPSourceInfo.h"
|
||||
#include "OSMemory.h"
|
||||
#include "StringFormatter.h"
|
||||
#include "SocketUtils.h"
|
||||
#include "RelayOutput.h"
|
||||
#include "StringTranslator.h"
|
||||
#include "SDPUtils.h"
|
||||
#include "OSArrayObjectDeleter.h"
|
||||
|
||||
StrPtrLen RTSPSourceInfo::sKeyString("rtsp_source");
|
||||
StrPtrLen RTSPSourceInfo::sAnnouncedKeyString("announced_rtsp_source");
|
||||
|
||||
// StrPtrLen's for various keywords on the relay_source & relay_destination lines
|
||||
static StrPtrLen sOutAddr("out_addr");
|
||||
static StrPtrLen sDestAddr("dest_addr");
|
||||
static StrPtrLen sDestPorts("dest_ports");
|
||||
static StrPtrLen sTtl("ttl");
|
||||
|
||||
char* RTSPOutputInfo::CopyString(const char* srcStr)
|
||||
{
|
||||
char* dstStr = NULL;
|
||||
|
||||
if(srcStr != NULL)
|
||||
{
|
||||
UInt32 len = ::strlen(srcStr);
|
||||
dstStr = NEW char[len + 1];
|
||||
::memcpy(dstStr, srcStr, len);
|
||||
dstStr[len] = '\0';
|
||||
}
|
||||
|
||||
return dstStr;
|
||||
}
|
||||
|
||||
void RTSPOutputInfo::Copy(const RTSPOutputInfo& copy)
|
||||
{
|
||||
fIsAnnounced = copy.fIsAnnounced;
|
||||
fAnnouncePort = copy.fAnnouncePort;
|
||||
|
||||
if(copy.fDestURl != NULL)
|
||||
fDestURl = RTSPOutputInfo::CopyString(copy.fDestURl);
|
||||
if(copy.fUserName != NULL)
|
||||
fUserName = RTSPOutputInfo::CopyString(copy.fUserName);
|
||||
if(copy.fPassword != NULL)
|
||||
fPassword = RTSPOutputInfo::CopyString(copy.fPassword);
|
||||
}
|
||||
|
||||
RTSPSourceInfo::RTSPSourceInfo(const RTSPSourceInfo& copy)
|
||||
:RCFSourceInfo(copy),
|
||||
fHostAddr(copy.fHostAddr), fHostPort(copy.fHostPort), fLocalAddr(copy.fLocalAddr),
|
||||
fNumSetupsComplete(copy.fNumSetupsComplete), fDescribeComplete(copy.fDescribeComplete),
|
||||
fAnnounce(copy.fAnnounce), fAnnounceIP(copy.fAnnounceIP), fAnnounceActualIP(copy.fAnnounceIP),fQueueElem()
|
||||
{
|
||||
fQueueElem.SetEnclosingObject(this);
|
||||
fSourceURL = RTSPOutputInfo::CopyString(copy.fSourceURL);
|
||||
fUserName = RTSPOutputInfo::CopyString(copy.fUserName);
|
||||
fPassword = RTSPOutputInfo::CopyString(copy.fPassword);
|
||||
fAnnounceURL = RTSPOutputInfo::CopyString(copy.fAnnounceURL);
|
||||
|
||||
fRTSPInfoArray = NEW RTSPOutputInfo[fNumOutputs];
|
||||
for (UInt32 index=0; index < fNumOutputs; index++)
|
||||
fRTSPInfoArray[index].Copy(copy.fRTSPInfoArray[index]);
|
||||
|
||||
// These aren't set anyway and shouldn't be copied around
|
||||
fClientSocket = NULL;
|
||||
fClient = NULL;
|
||||
fRelaySessionCreatorTask = NULL;
|
||||
fSession = NULL;
|
||||
fSessionQueue = NULL;
|
||||
|
||||
if ((copy.fLocalSDP).Ptr != NULL)
|
||||
fLocalSDP.Set((copy.fLocalSDP).GetAsCString(), (copy.fLocalSDP).Len);
|
||||
|
||||
}
|
||||
|
||||
RTSPSourceInfo::~RTSPSourceInfo()
|
||||
{
|
||||
OSMutexLocker locker(RelayOutput::GetQueueMutex());
|
||||
|
||||
if (fRelaySessionCreatorTask != NULL)
|
||||
fRelaySessionCreatorTask->fInfo = NULL;
|
||||
|
||||
if (fDescribeComplete)
|
||||
{
|
||||
Assert(fClientSocket != NULL);
|
||||
Assert(fClient != NULL);
|
||||
// the task will delete these objects when it is done with the teardown
|
||||
TeardownTask* task = new TeardownTask(fClientSocket, fClient);
|
||||
task->Signal(Task::kStartEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fClientSocket != NULL) delete fClientSocket;
|
||||
if (fClient != NULL) delete fClient;
|
||||
}
|
||||
|
||||
if (fQueueElem.IsMemberOfAnyQueue())
|
||||
fQueueElem.Remove();
|
||||
|
||||
if (fLocalSDP.Ptr != NULL) delete fLocalSDP.Ptr;
|
||||
fLocalSDP.Len = 0;
|
||||
|
||||
if (fSourceURL != NULL) delete fSourceURL;
|
||||
if (fAnnounceURL != NULL) delete fAnnounceURL;
|
||||
|
||||
if (fRTSPInfoArray != NULL) delete [] fRTSPInfoArray;
|
||||
}
|
||||
|
||||
void RTSPSourceInfo::InitClient(UInt32 inSocketType)
|
||||
{
|
||||
fClientSocket = NEW TCPClientSocket(inSocketType);
|
||||
fClient = NEW RTSPClient(fClientSocket, false, RelaySession::sRelayUserAgent);
|
||||
}
|
||||
|
||||
void RTSPSourceInfo::SetClientInfo(UInt32 inAddr, UInt16 inPort, char* inURL, UInt32 inLocalAddr)
|
||||
{
|
||||
if (fClientSocket != NULL)
|
||||
fClientSocket->Set(inAddr, inPort);
|
||||
|
||||
StrPtrLen inURLPtrLen(inURL);
|
||||
|
||||
if (fClient != NULL)
|
||||
fClient->Set(inURLPtrLen);
|
||||
|
||||
if (inLocalAddr != 0)
|
||||
fClientSocket->GetSocket()->Bind(inLocalAddr, 0);
|
||||
}
|
||||
|
||||
QTSS_Error RTSPSourceInfo::ParsePrefs(XMLTag* relayTag, Bool16 inAnnounce)
|
||||
{
|
||||
XMLTag* prefTag;
|
||||
UInt32 localAddr = 0;
|
||||
UInt32 theHostAddr = 0;
|
||||
UInt16 theHostPort = 554;
|
||||
char* userName = NULL;
|
||||
char* password = NULL;
|
||||
StrPtrLen theURL;
|
||||
|
||||
fAnnounce = inAnnounce;
|
||||
|
||||
XMLTag* sourceTag = relayTag->GetEmbeddedTagByNameAndAttr("OBJECT", "CLASS", "source");
|
||||
if (sourceTag == NULL)
|
||||
return QTSS_ValueNotFound;
|
||||
|
||||
prefTag = sourceTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "in_addr");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
char* inAddrStr = prefTag->GetValue();
|
||||
if (inAddrStr != NULL)
|
||||
localAddr = SocketUtils::ConvertStringToAddr(inAddrStr);
|
||||
}
|
||||
prefTag = sourceTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "source_addr");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
char* destAddrStr = prefTag->GetValue();
|
||||
if (destAddrStr != NULL)
|
||||
theHostAddr = SocketUtils::ConvertStringToAddr(destAddrStr);
|
||||
}
|
||||
prefTag = sourceTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "rtsp_port");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
char* portStr = prefTag->GetValue();
|
||||
if (portStr != NULL)
|
||||
theHostPort = atoi(portStr);
|
||||
}
|
||||
prefTag = sourceTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "name");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
userName = prefTag->GetValue();
|
||||
}
|
||||
prefTag = sourceTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "password");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
password = prefTag->GetValue();
|
||||
}
|
||||
prefTag = sourceTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "url");
|
||||
char urlBuff[1024];
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
char* urlString = prefTag->GetValue();
|
||||
StringTranslator::EncodeURL(urlString, strlen(urlString) + 1, urlBuff, sizeof(urlBuff));
|
||||
theURL.Set(urlBuff);
|
||||
}
|
||||
|
||||
if (fAnnounce)
|
||||
{
|
||||
fAnnounceURL = theURL.GetAsCString();
|
||||
fAnnounceIP = theHostAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
fHostAddr = theHostAddr;
|
||||
fHostPort = theHostPort;
|
||||
fSourceURL = theURL.GetAsCString();
|
||||
fUserName = RTSPOutputInfo::CopyString(userName);
|
||||
fPassword = RTSPOutputInfo::CopyString(password);
|
||||
}
|
||||
|
||||
return QTSS_NoErr;
|
||||
}
|
||||
|
||||
QTSS_Error RTSPSourceInfo::Describe()
|
||||
{
|
||||
QTSS_Error theErr = QTSS_NoErr;
|
||||
|
||||
if (!fDescribeComplete)
|
||||
{
|
||||
// Work on the describe
|
||||
theErr = fClient->SendDescribe();
|
||||
if (theErr != QTSS_NoErr)
|
||||
return theErr;
|
||||
if (fClient->GetStatus() != 200)
|
||||
return QTSS_RequestFailed;
|
||||
|
||||
// If the above function returns QTSS_NoErr, we've gotten the describe response,
|
||||
// so process it.
|
||||
SDPSourceInfo theSourceInfo(fClient->GetContentBody(), fClient->GetContentLength());
|
||||
|
||||
// Copy the Source Info into our local SourceInfo.
|
||||
fNumStreams = theSourceInfo.GetNumStreams();
|
||||
fStreamArray = NEW StreamInfo[fNumStreams];
|
||||
|
||||
for (UInt32 x = 0; x < fNumStreams; x++)
|
||||
{
|
||||
// Copy fPayloadType, fPayloadName, fTrackID, fBufferDelay
|
||||
fStreamArray[x].Copy(*theSourceInfo.GetStreamInfo(x));
|
||||
|
||||
// Copy all stream info data. Also set fSrcIPAddr to be the host addr
|
||||
fStreamArray[x].fSrcIPAddr = fClientSocket->GetHostAddr();
|
||||
fStreamArray[x].fDestIPAddr = fClientSocket->GetLocalAddr();
|
||||
fStreamArray[x].fPort = 0;
|
||||
fStreamArray[x].fTimeToLive = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, describe is complete, copy out the SDP information.
|
||||
|
||||
fLocalSDP.Ptr = NEW char[fClient->GetContentLength() + 1];
|
||||
|
||||
// Look for an "a=range" line in the SDP. If there is one, remove it.
|
||||
|
||||
static StrPtrLen sRangeStr("a=range:");
|
||||
StrPtrLen theSDPPtr(fClient->GetContentBody(), fClient->GetContentLength());
|
||||
StringParser theSDPParser(&theSDPPtr);
|
||||
|
||||
do
|
||||
{
|
||||
// Loop until we reach the end of the SDP or hit a a=range line.
|
||||
StrPtrLen theSDPLine(theSDPParser.GetCurrentPosition(), theSDPParser.GetDataRemaining());
|
||||
if ((theSDPLine.Len > sRangeStr.Len) && (theSDPLine.NumEqualIgnoreCase(sRangeStr.Ptr, sRangeStr.Len)))
|
||||
break;
|
||||
|
||||
} while (theSDPParser.GetThruEOL(NULL));
|
||||
|
||||
// Copy what we have so far
|
||||
::memcpy(fLocalSDP.Ptr, fClient->GetContentBody(), theSDPParser.GetDataParsedLen());
|
||||
fLocalSDP.Len = theSDPParser.GetDataParsedLen();
|
||||
|
||||
// Skip over the range (if it exists)
|
||||
(void)theSDPParser.GetThruEOL(NULL);
|
||||
|
||||
// Copy the rest of the SDP
|
||||
::memcpy(fLocalSDP.Ptr + fLocalSDP.Len, theSDPParser.GetCurrentPosition(), theSDPParser.GetDataRemaining());
|
||||
fLocalSDP.Len += theSDPParser.GetDataRemaining();
|
||||
|
||||
#define _WRITE_SDP_ 0
|
||||
|
||||
#if _WRITE_SDP_
|
||||
FILE* outputFile = ::fopen("rtspclient.sdp", "w");
|
||||
if (outputFile != NULL)
|
||||
{
|
||||
fLocalSDP.Ptr[fLocalSDP.Len] = '\0';
|
||||
qtss_fprintf(outputFile, "%s", fLocalSDP.Ptr);
|
||||
::fclose(outputFile);
|
||||
qtss_printf("Wrote sdp to rtspclient.sdp\n");
|
||||
}
|
||||
else
|
||||
qtss_printf("Failed to write sdp\n");
|
||||
#endif
|
||||
fDescribeComplete = true;
|
||||
return QTSS_NoErr;
|
||||
}
|
||||
|
||||
QTSS_Error RTSPSourceInfo::SetupAndPlay()
|
||||
{
|
||||
QTSS_Error theErr = QTSS_NoErr;
|
||||
|
||||
// Do all the setups. This is async, so when a setup doesn't complete
|
||||
// immediately, return an error, and we'll pick up where we left off.
|
||||
while (fNumSetupsComplete < fNumStreams)
|
||||
{
|
||||
theErr = fClient->SendUDPSetup(fStreamArray[fNumSetupsComplete].fTrackID, fStreamArray[fNumSetupsComplete].fPort);
|
||||
if (theErr != QTSS_NoErr)
|
||||
return theErr;
|
||||
else if (fClient->GetStatus() != 200)
|
||||
return QTSS_RequestFailed;
|
||||
else
|
||||
fNumSetupsComplete++;
|
||||
}
|
||||
|
||||
// We've done all the setups. Now send a play.
|
||||
theErr = fClient->SendPlay(0);
|
||||
if (theErr != QTSS_NoErr)
|
||||
return theErr;
|
||||
if (fClient->GetStatus() != 200)
|
||||
return QTSS_RequestFailed;
|
||||
|
||||
return QTSS_NoErr;
|
||||
}
|
||||
|
||||
QTSS_Error RTSPSourceInfo::Teardown()
|
||||
{
|
||||
return (QTSS_Error)fClient->SendTeardown();
|
||||
}
|
||||
|
||||
char* RTSPSourceInfo::GetLocalSDP(UInt32* newSDPLen)
|
||||
{
|
||||
*newSDPLen = fLocalSDP.Len;
|
||||
return fLocalSDP.GetAsCString();
|
||||
}
|
||||
|
||||
char* RTSPSourceInfo::GetAnnounceSDP(UInt32 ipAddr, UInt32* newSDPLen)
|
||||
{
|
||||
char *announceSDP = NEW char[fLocalSDP.Len * 2];
|
||||
StringFormatter announceSDPFormatter(announceSDP, fLocalSDP.Len * 2);
|
||||
|
||||
StrPtrLen sdpLine;
|
||||
StringParser sdpParser(&fLocalSDP);
|
||||
bool added = false;
|
||||
|
||||
while (sdpParser.GetDataRemaining() > 0)
|
||||
{
|
||||
//stop when we reach an empty line.
|
||||
sdpParser.GetThruEOL(&sdpLine);
|
||||
if (sdpLine.Len == 0)
|
||||
continue;
|
||||
|
||||
switch (*sdpLine.Ptr)
|
||||
{
|
||||
case 'c':
|
||||
break; // remove any existing c lines
|
||||
case 'm':
|
||||
{
|
||||
if (!added)
|
||||
{
|
||||
added = true;
|
||||
// add a c line before the first m line
|
||||
char ipStr[50];
|
||||
char buff[50];
|
||||
StrPtrLen temp(buff);
|
||||
|
||||
struct in_addr theIPAddr;
|
||||
theIPAddr.s_addr = htonl(ipAddr);
|
||||
SocketUtils::ConvertAddrToString(theIPAddr, &temp);
|
||||
|
||||
qtss_sprintf(ipStr, "c=IN IP4 %s", buff);
|
||||
StrPtrLen tempLine(ipStr);
|
||||
announceSDPFormatter.Put(tempLine);
|
||||
announceSDPFormatter.PutEOL();
|
||||
}
|
||||
|
||||
announceSDPFormatter.Put(sdpLine);
|
||||
announceSDPFormatter.PutEOL();
|
||||
break;//ignore connection information
|
||||
}
|
||||
default:
|
||||
{
|
||||
announceSDPFormatter.Put(sdpLine);
|
||||
announceSDPFormatter.PutEOL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*newSDPLen = (UInt32)announceSDPFormatter.GetCurrentOffset();
|
||||
announceSDP[*newSDPLen] = 0;
|
||||
|
||||
StrPtrLen theSDPStr(announceSDP);
|
||||
SDPContainer rawSDPContainer;
|
||||
if (!rawSDPContainer.SetSDPBuffer( &theSDPStr ))
|
||||
{ return NULL; // it is screwed up do nothing the sdp will be deleted automatically
|
||||
}
|
||||
|
||||
SDPLineSorter sortedSDP(&rawSDPContainer);
|
||||
return sortedSDP.GetSortedSDPCopy(); // return a new copy of the sorted SDP
|
||||
}
|
||||
|
||||
void RTSPSourceInfo::ParseAnnouncedDestination(XMLTag* destTag, UInt32 index)
|
||||
{
|
||||
XMLTag* prefTag;
|
||||
|
||||
fRTSPInfoArray[index].fIsAnnounced = true;
|
||||
|
||||
prefTag = destTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "out_addr");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
char* outAddrStr = prefTag->GetValue();
|
||||
if (outAddrStr != NULL)
|
||||
fOutputArray[index].fLocalAddr = SocketUtils::ConvertStringToAddr(outAddrStr);
|
||||
}
|
||||
prefTag = destTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "dest_addr");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
char* destAddrStr = prefTag->GetValue();
|
||||
if (destAddrStr != NULL)
|
||||
fOutputArray[index].fDestAddr = SocketUtils::ConvertStringToAddr(destAddrStr);
|
||||
}
|
||||
prefTag = destTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "rtsp_port");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
char* portStr = prefTag->GetValue();
|
||||
if (portStr != NULL)
|
||||
fRTSPInfoArray[index].fAnnouncePort = atoi(portStr);
|
||||
}
|
||||
prefTag = destTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "name");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
StrPtrLen userName(prefTag->GetValue());
|
||||
fRTSPInfoArray[index].fUserName = userName.GetAsCString();
|
||||
}
|
||||
prefTag = destTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "url");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
char urlBuff[1024];
|
||||
char* urlString = prefTag->GetValue();
|
||||
StringTranslator::EncodeURL(urlString, strlen(urlString) + 1, urlBuff, sizeof(urlBuff));
|
||||
StrPtrLen destURL(urlBuff);
|
||||
fRTSPInfoArray[index].fDestURl = destURL.GetAsCString();
|
||||
}
|
||||
prefTag = destTag->GetEmbeddedTagByNameAndAttr("PREF", "NAME", "password");
|
||||
if (prefTag != NULL)
|
||||
{
|
||||
StrPtrLen password(prefTag->GetValue());
|
||||
fRTSPInfoArray[index].fPassword = password.GetAsCString();
|
||||
}
|
||||
}
|
||||
|
||||
void RTSPSourceInfo::AllocateOutputArray(UInt32 numOutputs)
|
||||
{
|
||||
// Allocate the proper number of relay outputs
|
||||
RCFSourceInfo::AllocateOutputArray(numOutputs);
|
||||
fRTSPInfoArray = new RTSPOutputInfo[numOutputs];
|
||||
}
|
||||
|
||||
Bool16 RTSPSourceInfo::Equal(SourceInfo* inInfo)
|
||||
{
|
||||
if (!inInfo->IsRTSPSourceInfo())
|
||||
return false;
|
||||
|
||||
// RTSPSourceInfo* info = dynamic_cast<RTSPSourceInfo *>(inInfo);
|
||||
RTSPSourceInfo* info = (RTSPSourceInfo *)(inInfo);
|
||||
|
||||
// if (info == NULL)
|
||||
// return false;
|
||||
|
||||
if (!fAnnounce)
|
||||
{
|
||||
StrPtrLen source(fSourceURL);
|
||||
if( source.Equal(info->GetSourceURL()) && (fHostAddr == info->GetHostAddr())
|
||||
&& (fHostPort == info->GetHostPort()) )
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
StrPtrLen announceURL(fAnnounceURL);
|
||||
if ((fAnnounceIP == info->GetAnnounceIP()) && announceURL.Equal(info->GetAnnounceURL()))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RTSPSourceInfo::SetSourceParameters(UInt32 inHostAddr, UInt16 inHostPort, StrPtrLen& inURL)
|
||||
{
|
||||
fHostAddr = inHostAddr;
|
||||
fHostPort = inHostPort;
|
||||
fSourceURL = inURL.GetAsCString();
|
||||
}
|
||||
|
||||
void RTSPSourceInfo::StartSessionCreatorTask(OSQueue* inSessionQueue, OSQueue* inSourceQueue)
|
||||
{
|
||||
InitClient(Socket::kNonBlockingSocketType);
|
||||
SetClientInfo(fHostAddr, fHostPort, fSourceURL, fLocalAddr);
|
||||
if (fUserName != NULL)
|
||||
fClient->SetName(fUserName);
|
||||
if (fPassword != NULL)
|
||||
fClient->SetPassword(fPassword);
|
||||
|
||||
fSessionQueue = inSessionQueue;
|
||||
|
||||
if(fAnnounce)
|
||||
inSourceQueue->EnQueue(&fQueueElem);
|
||||
|
||||
fSessionCreationState = kSendingDescribe;
|
||||
fRelaySessionCreatorTask = NEW RelaySessionCreator(this);
|
||||
fRelaySessionCreatorTask->Signal(Task::kStartEvent);
|
||||
}
|
||||
|
||||
SInt64 RTSPSourceInfo::RelaySessionCreator::Run()
|
||||
{
|
||||
OSMutexLocker locker(RelayOutput::GetQueueMutex());
|
||||
SInt64 result = -1;
|
||||
if (fInfo != NULL)
|
||||
result = fInfo->RunCreateSession();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt64 RTSPSourceInfo::RunCreateSession()
|
||||
{
|
||||
OS_Error osErr = OS_NoErr;
|
||||
SInt64 result = 500;
|
||||
|
||||
if (fSessionCreationState == kSendingDescribe)
|
||||
{
|
||||
if (!fDescribeComplete)
|
||||
{
|
||||
osErr = fClient->SendDescribe();
|
||||
|
||||
if (osErr == OS_NoErr)
|
||||
{
|
||||
if (fClient->GetStatus() == 200)
|
||||
{
|
||||
// we've gotten the describe response, so process it.
|
||||
SDPSourceInfo theSourceInfo(fClient->GetContentBody(), fClient->GetContentLength());
|
||||
|
||||
// Copy the Source Info into our local SourceInfo.
|
||||
fNumStreams = theSourceInfo.GetNumStreams();
|
||||
fStreamArray = NEW StreamInfo[fNumStreams];
|
||||
|
||||
for (UInt32 x = 0; x < fNumStreams; x++)
|
||||
{
|
||||
// Copy fPayloadType, fPayloadName, fTrackID, fBufferDelay
|
||||
fStreamArray[x].Copy(*theSourceInfo.GetStreamInfo(x));
|
||||
|
||||
// Copy all stream info data. Also set fSrcIPAddr to be the host addr
|
||||
fStreamArray[x].fSrcIPAddr = fClientSocket->GetHostAddr();
|
||||
fStreamArray[x].fDestIPAddr = fClientSocket->GetLocalAddr();
|
||||
fStreamArray[x].fPort = 0;
|
||||
fStreamArray[x].fTimeToLive = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
osErr = ENOTCONN;
|
||||
}
|
||||
}
|
||||
|
||||
//describe is complete
|
||||
if(osErr == OS_NoErr)
|
||||
{
|
||||
//copy out the SDP information
|
||||
fLocalSDP.Ptr = NEW char[fClient->GetContentLength() + 1];
|
||||
|
||||
// Look for an "a=range" line in the SDP. If there is one, remove it.
|
||||
static StrPtrLen sRangeStr("a=range:");
|
||||
StrPtrLen theSDPPtr(fClient->GetContentBody(), fClient->GetContentLength());
|
||||
StringParser theSDPParser(&theSDPPtr);
|
||||
|
||||
do
|
||||
{
|
||||
// Loop until we reach the end of the SDP or hit a a=range line.
|
||||
StrPtrLen theSDPLine(theSDPParser.GetCurrentPosition(), theSDPParser.GetDataRemaining());
|
||||
if ((theSDPLine.Len > sRangeStr.Len) && (theSDPLine.NumEqualIgnoreCase(sRangeStr.Ptr, sRangeStr.Len)))
|
||||
break;
|
||||
} while (theSDPParser.GetThruEOL(NULL));
|
||||
|
||||
// Copy what we have so far
|
||||
::memcpy(fLocalSDP.Ptr, fClient->GetContentBody(), theSDPParser.GetDataParsedLen());
|
||||
fLocalSDP.Len = theSDPParser.GetDataParsedLen();
|
||||
|
||||
// Skip over the range (if it exists)
|
||||
(void)theSDPParser.GetThruEOL(NULL);
|
||||
|
||||
// Copy the rest of the SDP
|
||||
::memcpy(fLocalSDP.Ptr + fLocalSDP.Len, theSDPParser.GetCurrentPosition(), theSDPParser.GetDataRemaining());
|
||||
fLocalSDP.Len += theSDPParser.GetDataRemaining();
|
||||
|
||||
#define _WRITE_SDP_ 0
|
||||
|
||||
#if _WRITE_SDP_
|
||||
FILE* outputFile = ::fopen("rtspclient.sdp", "w");
|
||||
if (outputFile != NULL)
|
||||
{
|
||||
fLocalSDP.Ptr[fLocalSDP.Len] = '\0';
|
||||
qtss_fprintf(outputFile, "%s", fLocalSDP.Ptr);
|
||||
::fclose(outputFile);
|
||||
qtss_printf("Wrote sdp to rtspclient.sdp\n");
|
||||
}
|
||||
else
|
||||
qtss_printf("Failed to write sdp\n");
|
||||
#endif
|
||||
fDescribeComplete = true;
|
||||
|
||||
fSession = NEW RelaySession(NULL, this);
|
||||
if (fSession->SetupRelaySession(this) == OS_NoErr)
|
||||
{
|
||||
fSessionCreationState = kSendingSetup;
|
||||
}
|
||||
else
|
||||
{
|
||||
osErr = ENOTCONN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ((fSessionCreationState == kSendingSetup) && (osErr == OS_NoErr))
|
||||
{
|
||||
osErr = fClient->SendUDPSetup(fStreamArray[fNumSetupsComplete].fTrackID, fStreamArray[fNumSetupsComplete].fPort);
|
||||
if(osErr == OS_NoErr)
|
||||
{
|
||||
if(fClient->GetStatus() == 200)
|
||||
{
|
||||
fNumSetupsComplete++;
|
||||
if (fNumSetupsComplete == fNumStreams)
|
||||
fSessionCreationState = kSendingPlay;
|
||||
}
|
||||
else
|
||||
osErr = ENOTCONN;
|
||||
}
|
||||
}
|
||||
|
||||
if (fSessionCreationState == kSendingPlay)
|
||||
{
|
||||
osErr = fClient->SendPlay(0);
|
||||
if (osErr == OS_NoErr)
|
||||
{
|
||||
if (fClient->GetStatus() == 200)
|
||||
fSessionCreationState = kDone;
|
||||
else
|
||||
osErr = ENOTCONN;
|
||||
}
|
||||
}
|
||||
|
||||
if (fSessionCreationState == kDone)
|
||||
{
|
||||
// If session was correctly set up,
|
||||
// add the outputs
|
||||
if(fSession != NULL)
|
||||
{
|
||||
// Format SourceInfo HTML for the stats web page
|
||||
fSession->FormatHTML(fClient->GetURL());
|
||||
|
||||
OSMutexLocker locker(RelayOutput::GetQueueMutex());
|
||||
fSessionQueue->EnQueue(fSession->GetQueueElem());
|
||||
|
||||
for (UInt32 x = 0; x < fNumOutputs; x++)
|
||||
{
|
||||
SourceInfo::OutputInfo* theOutputInfo = GetOutputInfo(x);
|
||||
if (theOutputInfo->fAlreadySetup)
|
||||
continue; // shouldn't ever happen
|
||||
|
||||
RelayOutput* theOutput = NEW RelayOutput(this, x, fSession, true);
|
||||
if (theOutput->IsValid())
|
||||
fSession->AddOutput(theOutput, false);
|
||||
else
|
||||
delete theOutput;
|
||||
}
|
||||
}
|
||||
fClientSocket->GetSocket()->SetTask(NULL); //detach the task from the socket
|
||||
result = -1; // let the task die
|
||||
fRelaySessionCreatorTask = NULL;
|
||||
}
|
||||
|
||||
if ((osErr == EINPROGRESS) || (osErr == EAGAIN))
|
||||
{
|
||||
// Request an async event
|
||||
fClientSocket->GetSocket()->SetTask(fRelaySessionCreatorTask);
|
||||
fClientSocket->GetSocket()->RequestEvent(fClientSocket->GetEventMask() );
|
||||
}
|
||||
else if (osErr != OS_NoErr)
|
||||
{
|
||||
// We encountered some fatal error with the socket. Record this as a connection failure
|
||||
// delete the session
|
||||
// delete the session
|
||||
if(fSession != NULL)
|
||||
{
|
||||
delete fSession;
|
||||
fSession = NULL;
|
||||
}
|
||||
|
||||
fClientSocket->GetSocket()->SetTask(NULL); //detach the task from the socket
|
||||
result = -1; // let the task die
|
||||
fRelaySessionCreatorTask = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
RTSPSourceInfo::TeardownTask::TeardownTask(TCPClientSocket* clientSocket, RTSPClient* client)
|
||||
{
|
||||
this->SetTaskName("RTSPSourceInfo::TeardownTask");
|
||||
fClientSocket = clientSocket;
|
||||
fClient = client;
|
||||
}
|
||||
|
||||
RTSPSourceInfo::TeardownTask::~TeardownTask()
|
||||
{
|
||||
delete fClientSocket;
|
||||
delete fClient;
|
||||
}
|
||||
|
||||
SInt64 RTSPSourceInfo::TeardownTask::Run()
|
||||
{
|
||||
OS_Error err = fClient->SendTeardown();
|
||||
|
||||
if ((err == EINPROGRESS) || (err == EAGAIN))
|
||||
{
|
||||
// Request an async event
|
||||
fClientSocket->GetSocket()->SetTask(this);
|
||||
fClientSocket->GetSocket()->RequestEvent(fClientSocket->GetEventMask() );
|
||||
return 250;
|
||||
}
|
||||
fClientSocket->GetSocket()->SetTask(NULL); //detach the task from the socket
|
||||
return -1; // we're out of here, this will cause the destructor to be called
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue