580 lines
22 KiB
C++
580 lines
22 KiB
C++
/*
|
|
*
|
|
* @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: RelayOutput.cpp
|
|
|
|
Contains: Implementation of object described in .h file
|
|
|
|
|
|
|
|
*/
|
|
|
|
#include "RelayOutput.h"
|
|
|
|
#include "OSMemory.h"
|
|
#include "SocketUtils.h"
|
|
#include "RTSPSourceInfo.h"
|
|
|
|
static StrPtrLen sUDPDestStr("udp_destination");
|
|
static StrPtrLen sAnnouncedDestStr("announced_destination");
|
|
|
|
// STATIC DATA
|
|
OSQueue RelayOutput::sRelayOutputQueue;
|
|
OSMutex RelayOutput::sQueueMutex;
|
|
|
|
QTSS_ObjectType RelayOutput::qtssRelayOutputObjectType;
|
|
|
|
QTSS_AttributeID RelayOutput::sOutputType = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputDestAddr = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputLocalAddr = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputUDPPorts = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputRTSPPort = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputURL = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputTTL = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputCurPacketsPerSec = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputCurBitsPerSec = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputTotalPacketsSent = qtssIllegalAttrID;
|
|
QTSS_AttributeID RelayOutput::sOutputTotalBytesSent = qtssIllegalAttrID;
|
|
|
|
static char* sOutputTypeName = "output_type";
|
|
static char* sOutputDestAddrName = "output_dest_addr";
|
|
static char* sOutputLocalAddrName = "output_local_addr";
|
|
static char* sOutputUDPPortsName = "output_udp_ports";
|
|
static char* sOutputRTSPPortName = "output_rtsp_port";
|
|
static char* sOutputURLName = "output_url";
|
|
static char* sOutputTTLName = "output_ttl";
|
|
|
|
static char* sOutputCurPacketsPerSecName = "output_cur_packetspersec";
|
|
static char* sOutputCurBitsPerSecName = "output_cur_bitspersec";
|
|
static char* sOutputTotalPacketsSentName = "output_total_packets_sent";
|
|
static char* sOutputTotalBytesSentName = "output_total_bytes_sent";
|
|
|
|
void RelayOutput::Register()
|
|
{
|
|
// Create the relay output object type
|
|
(void)QTSS_CreateObjectType(&qtssRelayOutputObjectType);
|
|
|
|
// Add the static attributes to the qtssRelayOutputObjectType object
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputTypeName, NULL, qtssAttrDataTypeCharArray);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputTypeName, &sOutputType); // dest type
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputDestAddrName, NULL, qtssAttrDataTypeCharArray);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputDestAddrName, &sOutputDestAddr); // dest addr
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputLocalAddrName, NULL, qtssAttrDataTypeCharArray);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputLocalAddrName, &sOutputLocalAddr); // interface addr
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputUDPPortsName, NULL, qtssAttrDataTypeUInt16);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputUDPPortsName, &sOutputUDPPorts); // udp ports
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputRTSPPortName, NULL, qtssAttrDataTypeUInt16);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputRTSPPortName, &sOutputRTSPPort); // rtsp port
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputURLName, NULL, qtssAttrDataTypeCharArray);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputURLName, &sOutputURL); // url
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputTTLName, NULL, qtssAttrDataTypeUInt16);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputTTLName, &sOutputTTL); // ttl
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputCurPacketsPerSecName, NULL, qtssAttrDataTypeUInt32);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputCurPacketsPerSecName, &sOutputCurPacketsPerSec);// cur packets/sec
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputCurBitsPerSecName, NULL, qtssAttrDataTypeUInt32);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputCurBitsPerSecName, &sOutputCurBitsPerSec); // cur bits/sec
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputTotalPacketsSentName, NULL, qtssAttrDataTypeUInt64);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputTotalPacketsSentName, &sOutputTotalPacketsSent);// total packets
|
|
|
|
(void)QTSS_AddStaticAttribute(qtssRelayOutputObjectType, sOutputTotalBytesSentName, NULL, qtssAttrDataTypeUInt64);
|
|
(void)QTSS_IDForAttr(qtssRelayOutputObjectType, sOutputTotalBytesSentName, &sOutputTotalBytesSent); // total bytes
|
|
|
|
}
|
|
|
|
RelayOutput::RelayOutput(SourceInfo* inInfo, UInt32 inWhichOutput, RelaySession* inRelaySession, Bool16 isRTSPSourceInfo)
|
|
: fRelaySession(inRelaySession),
|
|
fOutputSocket(NULL, Socket::kNonBlockingSocketType),
|
|
fNumStreams(inRelaySession->GetSourceInfo()->GetNumStreams()), // use the reflector session's source info
|
|
fOutputInfo(*inInfo->GetOutputInfo(inWhichOutput)),
|
|
fQueueElem(),
|
|
fFormatter(&fHTMLBuf[0], kMaxHTMLSize),
|
|
fPacketsPerSecond(0),
|
|
fBitsPerSecond(0),
|
|
fLastUpdateTime(0),
|
|
fTotalPacketsSent(0),
|
|
fTotalBytesSent(0),
|
|
fLastPackets(0),
|
|
fLastBytes(0),
|
|
fClientSocket(NULL),
|
|
fClient(NULL),
|
|
fDoingAnnounce(false),
|
|
fValid(true),
|
|
fOutgoingSDP(NULL),
|
|
fAnnounceTask(NULL),
|
|
fRTSPOutputInfo(NULL)
|
|
{
|
|
Assert(fNumStreams > 0);
|
|
|
|
fQueueElem.SetEnclosingObject(this);
|
|
fStreamCookieArray = NEW void*[fNumStreams];
|
|
fTrackIDArray = NEW UInt32[fNumStreams];
|
|
fOutputInfo.fPortArray = NEW UInt16[fNumStreams];//copy constructor doesn't do this
|
|
::memset(fOutputInfo.fPortArray, 0, fNumStreams * sizeof(UInt16));
|
|
|
|
// create a bookmark for each stream we'll reflect
|
|
this->InititializeBookmarks( inRelaySession->GetNumStreams() );
|
|
|
|
// Copy out all the track IDs for each stream
|
|
for (UInt32 x = 0; x < fNumStreams; x++)
|
|
{
|
|
fTrackIDArray[x] = inRelaySession->GetSourceInfo()->GetStreamInfo(x)->fTrackID;
|
|
fStreamCookieArray[x] = inRelaySession->GetStreamCookie(fTrackIDArray[x]);
|
|
}
|
|
|
|
// Copy the contents of the output port array
|
|
|
|
if (inInfo->GetOutputInfo(inWhichOutput)->fPortArray != NULL)
|
|
{
|
|
UInt32 copySize = fNumStreams;
|
|
if (fOutputInfo.fNumPorts < fNumStreams)
|
|
copySize = fOutputInfo.fNumPorts;
|
|
::memcpy(fOutputInfo.fPortArray, inInfo->GetOutputInfo(inWhichOutput)->fPortArray, copySize * sizeof(UInt16));
|
|
}
|
|
else if (fOutputInfo.fBasePort != 0)
|
|
{
|
|
for (UInt32 y = 0; y < fNumStreams; y++)
|
|
fOutputInfo.fPortArray[y] = (UInt16) (fOutputInfo.fBasePort + (y * 2) );
|
|
}
|
|
|
|
OS_Error err = BindSocket();
|
|
if (err != OS_NoErr)
|
|
{
|
|
fValid = false;
|
|
return;
|
|
}
|
|
|
|
RTSPOutputInfo* rtspInfo = NULL;
|
|
if (isRTSPSourceInfo)
|
|
{
|
|
// in the case of the announce source info, the passed in source info will have the new
|
|
// output information, but only the session's source info will have the sdp and url.
|
|
RTSPSourceInfo* rtspSourceInfo = (RTSPSourceInfo *)(inInfo);
|
|
Assert(rtspSourceInfo != NULL);
|
|
RTSPSourceInfo* sessionSourceInfo = (RTSPSourceInfo *)(inRelaySession->GetSourceInfo());
|
|
Assert(sessionSourceInfo != NULL);
|
|
|
|
rtspInfo = rtspSourceInfo->GetRTSPOutputInfo(inWhichOutput);
|
|
if (rtspInfo->fIsAnnounced)
|
|
{
|
|
fRTSPOutputInfo = NEW RTSPOutputInfo();
|
|
fRTSPOutputInfo->Copy(*rtspInfo);
|
|
|
|
fDoingAnnounce = true;
|
|
// set up rtsp socket and client
|
|
fClientSocket = new TCPClientSocket(Socket::kNonBlockingSocketType);
|
|
fClient = new RTSPClient(fClientSocket, false, RelaySession::sRelayUserAgent);
|
|
|
|
// set up the outgoing socket
|
|
fClientSocket->Set(fOutputInfo.fDestAddr, rtspInfo->fAnnouncePort);
|
|
int sndBufSize = 32 * 1024;
|
|
int rcvBufSize=1024;
|
|
fClientSocket->SetOptions(sndBufSize,rcvBufSize);
|
|
|
|
// set up the client object
|
|
StrPtrLen url;
|
|
if ((rtspInfo->fDestURl != NULL) && (strlen(rtspInfo->fDestURl) > 0))
|
|
url.Set(rtspInfo->fDestURl);
|
|
else
|
|
url.Set(sessionSourceInfo->GetSourceURL());
|
|
|
|
fClient->Set(url);
|
|
|
|
fClient->SetTransportMode(RTSPClient::kPushMode);
|
|
fClient->SetName(rtspInfo->fUserName);
|
|
fClient->SetPassword(rtspInfo->fPassword);
|
|
|
|
UInt32 len;
|
|
fOutgoingSDP = sessionSourceInfo->GetAnnounceSDP(fOutputInfo.fDestAddr, &len);
|
|
fAnnounceState = kSendingAnnounce;
|
|
fCurrentSetup = 0;
|
|
fAnnounceTask = new RelayAnnouncer(this); // this will now go and run the async announce
|
|
fAnnounceTask->Signal(Task::kStartEvent);
|
|
}
|
|
}
|
|
|
|
// Write the Output HTML
|
|
// Looks like: Relaying to: 229.49.52.102, Ports: 16898 16900 Time to live: 15
|
|
static StrPtrLen sHTMLStart("Relaying to: ");
|
|
static StrPtrLen sPorts(", Ports: ");
|
|
static StrPtrLen sTimeToLive(" Time to live: ");
|
|
static StrPtrLen sHTMLEnd("<BR>");
|
|
|
|
// First, format the destination addr as a dotted decimal string
|
|
char theIPAddrBuf[20];
|
|
StrPtrLen theIPAddr(theIPAddrBuf, 20);
|
|
struct in_addr theAddr;
|
|
theAddr.s_addr = htonl(fOutputInfo.fDestAddr);
|
|
SocketUtils::ConvertAddrToString(theAddr, &theIPAddr);
|
|
|
|
// Begin writing the HTML
|
|
fFormatter.Put(sHTMLStart);
|
|
fFormatter.Put(theIPAddr);
|
|
fFormatter.Put(sPorts);
|
|
|
|
for (UInt32 y = 0; y < fNumStreams; y++)
|
|
{
|
|
// Write all the destination ports
|
|
fFormatter.Put(fOutputInfo.fPortArray[y]);
|
|
fFormatter.PutSpace();
|
|
}
|
|
|
|
if (SocketUtils::IsMulticastIPAddr(inInfo->GetOutputInfo(inWhichOutput)->fDestAddr))
|
|
{
|
|
// Put the time to live if this is a multicast destination
|
|
fFormatter.Put(sTimeToLive);
|
|
fFormatter.Put(fOutputInfo.fTimeToLive);
|
|
}
|
|
fFormatter.Put(sHTMLEnd);
|
|
|
|
// Setup the StrPtrLen to point to the right stuff
|
|
fOutputInfoHTML.Ptr = fFormatter.GetBufPtr();
|
|
fOutputInfoHTML.Len = fFormatter.GetCurrentOffset();
|
|
|
|
OSMutexLocker locker(&sQueueMutex);
|
|
sRelayOutputQueue.EnQueue(&fQueueElem);
|
|
|
|
SetupRelayOutputObject(rtspInfo);
|
|
}
|
|
|
|
RelayOutput::~RelayOutput()
|
|
{
|
|
OSMutexLocker locker(&sQueueMutex);
|
|
sRelayOutputQueue.Remove(&fQueueElem);
|
|
|
|
if (fClientSocket)
|
|
delete fClientSocket;
|
|
if (fClient)
|
|
delete fClient;
|
|
|
|
delete [] fStreamCookieArray;
|
|
|
|
delete fOutgoingSDP;
|
|
fOutgoingSDP = NULL;
|
|
|
|
if (fAnnounceTask != NULL)
|
|
fAnnounceTask->fOutput = NULL;
|
|
|
|
if (fRTSPOutputInfo != NULL)
|
|
delete fRTSPOutputInfo;
|
|
|
|
QTSS_Object outputObject;
|
|
UInt32 len = sizeof(QTSS_Object);
|
|
|
|
for (int x = 0; QTSS_GetValue(fRelaySessionObject, RelaySession::sRelayOutputObject, x, &outputObject, &len) == QTSS_NoErr; x++)
|
|
{
|
|
Assert(outputObject != NULL);
|
|
Assert(len == sizeof(QTSS_Object));
|
|
|
|
if (outputObject == fRelayOutputObject)
|
|
{
|
|
(void)QTSS_RemoveValue(fRelaySessionObject, RelaySession::sRelayOutputObject, x);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
OS_Error RelayOutput::BindSocket()
|
|
{
|
|
OS_Error theErr = fOutputSocket.Open();
|
|
if (theErr != OS_NoErr)
|
|
return theErr;
|
|
|
|
// We don't care what local port we bind to
|
|
theErr = fOutputSocket.Bind(fOutputInfo.fLocalAddr, 0);
|
|
if (theErr != OS_NoErr)
|
|
return theErr;
|
|
|
|
// Set the ttl to be the proper value
|
|
return fOutputSocket.SetTtl(fOutputInfo.fTimeToLive);
|
|
}
|
|
|
|
Bool16 RelayOutput::Equal(SourceInfo* inInfo)
|
|
{
|
|
// First check if the Source Info matches this RelaySession
|
|
if (!fRelaySession->Equal(inInfo))
|
|
return false;
|
|
for (UInt32 x = 0; x < inInfo->GetNumOutputs(); x++)
|
|
{
|
|
if (inInfo->GetOutputInfo(x)->Equal(fOutputInfo))
|
|
{
|
|
RTSPOutputInfo* rtspOutputInfo = NULL;
|
|
if (inInfo->IsRTSPSourceInfo())
|
|
{
|
|
rtspOutputInfo = ((RTSPSourceInfo*)inInfo)->GetRTSPOutputInfo(x);
|
|
if (!rtspOutputInfo->fIsAnnounced)
|
|
rtspOutputInfo = NULL;
|
|
}
|
|
|
|
if (fRTSPOutputInfo != NULL) // announced output
|
|
{
|
|
if (!fRTSPOutputInfo->Equal(rtspOutputInfo)) // doesn't match the output
|
|
continue;
|
|
}
|
|
else if (rtspOutputInfo != NULL)
|
|
continue;
|
|
|
|
// This is a rather special purpose function... here we set this
|
|
// flag marking this particular output as a duplicate, because
|
|
// we know it is equal to this object.
|
|
// (This is used in QTSSReflectorModule.cpp:RereadRelayPrefs)
|
|
inInfo->GetOutputInfo(x)->fAlreadySetup = true;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QTSS_Error RelayOutput::WritePacket(StrPtrLen* inPacket, void* inStreamCookie, UInt32 inFlags, SInt64 /*packetLatenessInMSec*/, SInt64* /*timeToSendThisPacketAgain*/, UInt64* packetIDPtr, SInt64* /*arrivalTimeMSec*/, Bool16 /*firstPacket */ )
|
|
{
|
|
|
|
if (!fValid || fDoingAnnounce)
|
|
return OS_NoErr; // Not done setting up or we had an error setting up
|
|
|
|
// we don't use packetLateness becuase relays don't need to worry about TCP flow control induced transmit delay
|
|
|
|
// Look for the matching streamID
|
|
for (UInt32 x = 0; x < fNumStreams; x++)
|
|
{
|
|
if (inStreamCookie == fStreamCookieArray[x])
|
|
{
|
|
UInt16 theDestPort = fOutputInfo.fPortArray[x];
|
|
Assert((theDestPort & 1) == 0); //this should always be an RTP port (even)
|
|
if (inFlags & qtssWriteFlagsIsRTCP)
|
|
theDestPort++;
|
|
|
|
(void)fOutputSocket.SendTo(fOutputInfo.fDestAddr, theDestPort,
|
|
inPacket->Ptr, inPacket->Len);
|
|
|
|
// Update our totals
|
|
fTotalPacketsSent++;
|
|
fTotalBytesSent += inPacket->Len;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If it is time to recalculate statistics, do so
|
|
SInt64 curTime = OS::Milliseconds();
|
|
if ((fLastUpdateTime + kStatsIntervalInMilSecs) < curTime)
|
|
{
|
|
// Update packets per second
|
|
Float64 packetsPerSec = (Float64)((SInt64)fTotalPacketsSent - (SInt64)fLastPackets);
|
|
packetsPerSec *= 1000;
|
|
packetsPerSec /= (Float64)(curTime - fLastUpdateTime);
|
|
fPacketsPerSecond = (UInt32)packetsPerSec;
|
|
|
|
// Update bits per second. Win32 doesn't implement UInt64 -> Float64.
|
|
Float64 bitsPerSec = (Float64)((SInt64)fTotalBytesSent - (SInt64)fLastBytes);
|
|
bitsPerSec *= 1000 * 8;//convert from seconds to milsecs, bytes to bits
|
|
bitsPerSec /= (Float64)(curTime - fLastUpdateTime);
|
|
fBitsPerSecond = (UInt32)bitsPerSec;
|
|
|
|
fLastUpdateTime = curTime;
|
|
fLastPackets = fTotalPacketsSent;
|
|
fLastBytes = fTotalBytesSent;
|
|
}
|
|
|
|
return QTSS_NoErr;
|
|
}
|
|
|
|
SInt64 RelayOutput::RelayAnnouncer::Run()
|
|
{
|
|
OSMutexLocker locker(RelayOutput::GetQueueMutex());
|
|
SInt64 result = -1;
|
|
if (fOutput != NULL)
|
|
result = fOutput->RunAnnounce();
|
|
|
|
return result;
|
|
}
|
|
|
|
SInt64 RelayOutput::RunAnnounce()
|
|
{
|
|
OS_Error err = OS_NoErr;
|
|
SInt64 result = 1000;
|
|
|
|
if (fAnnounceState == kSendingAnnounce)
|
|
{
|
|
if (fOutgoingSDP == NULL || ::strlen(fOutgoingSDP) == 0)
|
|
err = ENOTCONN;
|
|
else
|
|
{
|
|
err = fClient->SendAnnounce(fOutgoingSDP);
|
|
if (err == OS_NoErr)
|
|
{
|
|
delete fOutgoingSDP;
|
|
fOutgoingSDP = NULL;
|
|
if (fClient->GetStatus() == 200)
|
|
fAnnounceState = kSendingSetup;
|
|
else
|
|
err = ENOTCONN;
|
|
}
|
|
}
|
|
}
|
|
|
|
while ((fAnnounceState == kSendingSetup) && (err == OS_NoErr))
|
|
{
|
|
err = fClient->SendUDPSetup(fTrackIDArray[fCurrentSetup], 10000);
|
|
if (err == OS_NoErr)
|
|
{
|
|
if (fClient->GetStatus() == 200)
|
|
{
|
|
fOutputInfo.fPortArray[fCurrentSetup] = fClient->GetServerPort(); // this got set from the Setup reply
|
|
fCurrentSetup++;
|
|
if (fCurrentSetup == fNumStreams)
|
|
fAnnounceState = kSendingPlay;
|
|
}
|
|
else
|
|
err = ENOTCONN;
|
|
}
|
|
}
|
|
|
|
if (fAnnounceState == kSendingPlay)
|
|
{
|
|
err = fClient->SendPlay(0);
|
|
if (err == OS_NoErr)
|
|
{
|
|
if (fClient->GetStatus() == 200)
|
|
fAnnounceState = kDone;
|
|
else
|
|
err = ENOTCONN;
|
|
}
|
|
}
|
|
|
|
if (fAnnounceState == kDone)
|
|
{
|
|
for (UInt32 index = 0; index < fNumStreams; index++) // source udp ports
|
|
{
|
|
UInt16 udpPort = fOutputInfo.fPortArray[index];
|
|
err = QTSS_SetValue (fRelayOutputObject, sOutputUDPPorts, index, &udpPort, sizeof(udpPort));
|
|
Assert(err == QTSS_NoErr);
|
|
}
|
|
|
|
fDoingAnnounce = false;
|
|
result = -1; // let the task die
|
|
fAnnounceTask = NULL;
|
|
}
|
|
|
|
if ((err == EINPROGRESS) || (err == EAGAIN))
|
|
{
|
|
// Request an async event
|
|
fClientSocket->GetSocket()->SetTask(fAnnounceTask);
|
|
fClientSocket->GetSocket()->RequestEvent(fClientSocket->GetEventMask() );
|
|
}
|
|
else if (err != OS_NoErr)
|
|
{
|
|
// We encountered some fatal error with the socket. Record this as a connection failure
|
|
fValid = false;
|
|
result = -1; // let the task die
|
|
fAnnounceTask = NULL;
|
|
}
|
|
|
|
if ( (-1 == result) && (NULL != fClientSocket) && (NULL != fClientSocket->GetSocket() ) )
|
|
fClientSocket->GetSocket()->SetTask(NULL); //remove fAnnounceTask from event handling code. The task can be safely deleted after detaching from the socket.
|
|
|
|
return result;
|
|
}
|
|
|
|
void RelayOutput::SetupRelayOutputObject(RTSPOutputInfo* inRTSPInfo)
|
|
{
|
|
fRelaySessionObject = fRelaySession->GetRelaySessionObject();
|
|
QTSS_Error theErr = QTSS_NoErr;
|
|
UInt32 outIndex = 0;
|
|
|
|
theErr = QTSS_LockObject (fRelaySessionObject);
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
theErr = QTSS_CreateObjectValue (fRelaySessionObject , RelaySession::sRelayOutputObject, qtssRelayOutputObjectType, &outIndex, &fRelayOutputObject);
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
if ((inRTSPInfo == NULL) || !inRTSPInfo->fIsAnnounced) // output type
|
|
{
|
|
theErr = QTSS_SetValue (fRelayOutputObject, sOutputType, 0, (void*)sUDPDestStr.Ptr, sUDPDestStr.Len);
|
|
Assert(theErr == QTSS_NoErr);
|
|
}
|
|
else
|
|
{
|
|
theErr = QTSS_SetValue (fRelayOutputObject, sOutputType, 0, (void*)sAnnouncedDestStr.Ptr, sAnnouncedDestStr.Len); // output type
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
theErr = QTSS_SetValue (fRelayOutputObject, sOutputRTSPPort, 0, &inRTSPInfo->fAnnouncePort, sizeof(inRTSPInfo->fAnnouncePort)); // rtsp port
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
theErr = QTSS_SetValue (fRelayOutputObject, sOutputURL, 0, (fClient->GetURL())->Ptr, (fClient->GetURL())->Len); // output url
|
|
Assert(theErr == QTSS_NoErr);
|
|
}
|
|
|
|
char theIPAddrBuf[20];
|
|
StrPtrLen theIPAddr(theIPAddrBuf, 20);
|
|
|
|
struct in_addr theDestAddr; // output destination address
|
|
theDestAddr.s_addr = htonl(fOutputInfo.fDestAddr);
|
|
SocketUtils::ConvertAddrToString(theDestAddr, &theIPAddr);
|
|
|
|
theErr = QTSS_SetValue (fRelayOutputObject, sOutputDestAddr, 0, (void*)theIPAddr.Ptr, theIPAddr.Len);
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
struct in_addr theLocalAddr; // output local address
|
|
theLocalAddr.s_addr = htonl(fOutputInfo.fLocalAddr);
|
|
SocketUtils::ConvertAddrToString(theLocalAddr, &theIPAddr);
|
|
|
|
theErr = QTSS_SetValue (fRelayOutputObject, sOutputLocalAddr, 0, (void*)theIPAddr.Ptr, theIPAddr.Len);
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
|
|
for (UInt32 index = 0; index < fNumStreams; index++) // output udp ports
|
|
{
|
|
UInt16 udpPort = fOutputInfo.fPortArray[index];
|
|
theErr = QTSS_SetValue (fRelayOutputObject, sOutputUDPPorts, index, &udpPort, sizeof(udpPort));
|
|
Assert(theErr == QTSS_NoErr);
|
|
}
|
|
|
|
theErr = QTSS_SetValue (fRelayOutputObject, sOutputTTL, 0, &(fOutputInfo.fTimeToLive), sizeof(fOutputInfo.fTimeToLive));
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
theErr = QTSS_SetValuePtr (fRelayOutputObject, sOutputCurPacketsPerSec, &fPacketsPerSecond, sizeof(fPacketsPerSecond));
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
theErr = QTSS_SetValuePtr (fRelayOutputObject, sOutputCurBitsPerSec, &fBitsPerSecond, sizeof(fBitsPerSecond));
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
theErr = QTSS_SetValuePtr (fRelayOutputObject, sOutputTotalPacketsSent, &fTotalPacketsSent, sizeof(fTotalPacketsSent));
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
theErr = QTSS_SetValuePtr (fRelayOutputObject, sOutputTotalBytesSent, &fTotalBytesSent, sizeof(fTotalBytesSent));
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
theErr = QTSS_UnlockObject (fRelaySessionObject);
|
|
Assert(theErr == QTSS_NoErr);
|
|
|
|
}
|