Very rough first start, not even everything added
This commit is contained in:
commit
af3619d4fa
88 changed files with 24251 additions and 0 deletions
874
PlaylistBroadcaster.tproj/playlist_elements.cpp
Normal file
874
PlaylistBroadcaster.tproj/playlist_elements.cpp
Normal file
|
@ -0,0 +1,874 @@
|
|||
/*
|
||||
*
|
||||
* @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@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "playlist_elements.h"
|
||||
#include "playlist_utils.h"
|
||||
#include "OS.h"
|
||||
#include "SocketUtils.h"
|
||||
#ifndef __Win32__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// ************************
|
||||
//
|
||||
// MediaStream
|
||||
//
|
||||
// ************************
|
||||
#define DROP_RTCP_TEST 0
|
||||
#define DROPCOUNT 1// drop count RTCPs
|
||||
|
||||
MediaStream::MediaStream(void)
|
||||
{
|
||||
memset( (char *)&fData, '\0', sizeof(fData));
|
||||
fSend = true;
|
||||
fData.fSenderReportReady = true;
|
||||
}
|
||||
MediaStream::~MediaStream()
|
||||
{
|
||||
if (fData.fSoundDescriptionBuffer) delete[] fData.fSoundDescriptionBuffer;
|
||||
}
|
||||
|
||||
|
||||
UInt32 MediaStream::GetACName(char* ioCNameBuffer)
|
||||
{
|
||||
//clear out the whole buffer
|
||||
::memset(ioCNameBuffer, 0, kMaxCNameLen);
|
||||
|
||||
//cName identifier
|
||||
ioCNameBuffer[0] = 1;
|
||||
|
||||
//Unique cname is constructed from the base name and the current time
|
||||
qtss_sprintf(&ioCNameBuffer[2], " %s%"_64BITARG_"d", "QTSS", OS::Milliseconds() / 1000);
|
||||
UInt32 cNameLen = ::strlen(&ioCNameBuffer[2]);
|
||||
//2nd byte of CName should be length
|
||||
ioCNameBuffer[1] = (UInt8) cNameLen ;//doesn't count indicator or length byte
|
||||
cNameLen += 2; // add the identifier and len bytes to the result len
|
||||
//pad length to a 4 byte boundary
|
||||
UInt32 padLength = cNameLen % 4;
|
||||
if (padLength > 0)
|
||||
cNameLen += 4 - padLength;
|
||||
|
||||
return cNameLen;
|
||||
}
|
||||
|
||||
void MediaStream::TestAndIncSoundDescriptor(RTpPacket *packetPtr)
|
||||
{ // currently not executed
|
||||
SInt16 test = 0;
|
||||
do
|
||||
{
|
||||
if (!fData.fIsSoundStream) break;
|
||||
if (!packetPtr->HasSoundDescription()) break;
|
||||
if (!fData.fSoundDescriptionBuffer) break;
|
||||
|
||||
SoundDescription *packetSDPtr = NULL;
|
||||
SoundDescription *savedSDPtr = (SoundDescription *) fData.fSoundDescriptionBuffer;
|
||||
(void) packetPtr->GetSoundDescriptionRef(&packetSDPtr);
|
||||
SInt32 descSize = packetPtr->fSoundDescriptionLen;
|
||||
|
||||
if (descSize == 0) break;
|
||||
if (descSize > eMaxSoundDescriptionSize) break;
|
||||
|
||||
if (fData.fSavedSoundDescSize == descSize)
|
||||
{ test = ::memcmp(packetSDPtr, fData.fSoundDescriptionBuffer, descSize);
|
||||
}
|
||||
else test = 1; // they are different sizes so it is a new sample description
|
||||
|
||||
if (test != 0) // they are different
|
||||
{ ::memcpy(savedSDPtr, packetSDPtr, descSize);
|
||||
fData.fSavedSoundDescSize = descSize;
|
||||
fData.fSavedDataRefIndex ++ ; // it is different than saved so change the index
|
||||
}
|
||||
packetSDPtr->dataRefIndex = htons(fData.fSavedDataRefIndex);
|
||||
|
||||
} while (false);
|
||||
}
|
||||
|
||||
|
||||
void MediaStream::UpdatePacketInStream(RTpPacket *packetPtr)
|
||||
{
|
||||
UInt32 curSSRC = 0;
|
||||
UInt32 curRTpTimeStamp = 0;
|
||||
UInt16 curRTpSequenceNumber = 0;
|
||||
UInt32 newRTpTimeStamp = 0;
|
||||
UInt16 newRTpSequenceNumber = 0;
|
||||
UInt32 newSSRC = 0;
|
||||
unsigned char curPayload;
|
||||
unsigned char newPayload;
|
||||
packetPtr->GetHeaderInfo(&curRTpTimeStamp, &curRTpSequenceNumber, &curSSRC, &curPayload);
|
||||
|
||||
newSSRC = fData.fInitSSRC;
|
||||
MapToStream(curRTpTimeStamp, curRTpSequenceNumber, curPayload, &newRTpTimeStamp, &newRTpSequenceNumber, &newPayload);
|
||||
|
||||
if (fData.fIsVideoStream) { LogStr("video "); }
|
||||
if (fData.fIsSoundStream) { LogStr("audio "); }
|
||||
|
||||
packetPtr->SetHeaderInfo(newRTpTimeStamp, newRTpSequenceNumber,newSSRC,newPayload);
|
||||
|
||||
//TestAndIncSoundDescriptor(packetPtr); // put in to track QuickTime format sound descriptors and flag change in sample types
|
||||
}
|
||||
|
||||
void MediaStream::MapToStream(UInt32 curRTpTimeStamp, UInt16 curRTpSequenceNumber, unsigned char curPayload, UInt32 *outRTpTimeStampPtr, UInt16 *outRTpSequenceNumberPtr, unsigned char *outPayloadPtr)
|
||||
{
|
||||
|
||||
if (fData.fNewMovieStarted == true) // this is the first packet in a new movie
|
||||
{
|
||||
fData.fNewMovieStarted = false;
|
||||
}
|
||||
|
||||
fData.fCurStreamRTpSequenceNumber++; // the stream sequence number
|
||||
|
||||
UInt64 curSequenceNumber = (UInt64) fData.fCurStreamRTpSequenceNumber + (UInt64) fData.fSeqRandomOffset;
|
||||
UInt64 curTimeStamp = (UInt64) curRTpTimeStamp + (UInt64) fData.fMediaStartOffsetMediaScale + (UInt64) fData.fRTpRandomOffset;
|
||||
|
||||
UInt32 outTime = (UInt32) ( (UInt64) curTimeStamp & (UInt64) 0xFFFFFFFF );
|
||||
UInt16 outSeq = (UInt16) ( (UInt64) curSequenceNumber & (UInt64) 0xFFFF );
|
||||
unsigned char outPayload = curPayload;
|
||||
Assert (fData.fMovieMediaTypePtr != NULL);// should always be valid
|
||||
PayLoad *firstPayLoadPtr = (fData.fMovieMediaTypePtr)->fPayLoadTypes.Begin(); // potential problem; assumes first payload per track is this payload
|
||||
if (firstPayLoadPtr)
|
||||
{
|
||||
outPayload = (unsigned char) ( 0x7F & firstPayLoadPtr->payloadID);
|
||||
outPayload |= (curPayload & 0x80);// the movie payload marker
|
||||
}
|
||||
|
||||
// qtss_printf("MediaStream::MapToStream outTime = %"_U32BITARG_"\n", outTime);
|
||||
// qtss_printf("MediaStream::MapToStream calculated time = %"_U32BITARG_"\n",(UInt32) curTimeInScale);
|
||||
|
||||
if (outRTpTimeStampPtr) *outRTpTimeStampPtr = outTime;
|
||||
if (outRTpSequenceNumberPtr) *outRTpSequenceNumberPtr = outSeq;
|
||||
if (outPayloadPtr) *outPayloadPtr = outPayload;
|
||||
}
|
||||
|
||||
void MediaStream::BuildStaticRTCpReport()
|
||||
{
|
||||
char theTempCName[kMaxCNameLen];
|
||||
UInt32 cNameLen = GetACName(theTempCName);
|
||||
|
||||
//write the SR & SDES headers
|
||||
UInt32* theSRWriter = (UInt32*)&fData.fSenderReportBuffer;
|
||||
*theSRWriter = htonl(0x80c80006);
|
||||
theSRWriter += 7;
|
||||
//SDES length is the length of the CName, plus 2 32bit words
|
||||
*theSRWriter = htonl(0x81ca0000 + (cNameLen >> 2) + 1);
|
||||
::memcpy(&fData.fSenderReportBuffer[kSenderReportSizeInBytes], theTempCName, cNameLen);
|
||||
fData.fSenderReportSize = kSenderReportSizeInBytes + cNameLen;
|
||||
}
|
||||
|
||||
void MediaStream::InitIfAudio()
|
||||
{
|
||||
if (fData.fStreamMediaTypePtr)
|
||||
{
|
||||
SimpleString audioStr("audio");
|
||||
fData.fIsSoundStream = SimpleParser::Compare(&audioStr, &(fData.fStreamMediaTypePtr->fTheTypeStr), false );
|
||||
if (fData.fIsSoundStream)
|
||||
{
|
||||
fData.fSoundDescriptionBuffer = new char[eMaxSoundDescriptionSize];
|
||||
::memset(fData.fSoundDescriptionBuffer, 0, eMaxSoundDescriptionSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleString videoStr("video");
|
||||
fData.fIsVideoStream = SimpleParser::Compare(&videoStr, &(fData.fStreamMediaTypePtr->fTheTypeStr), false );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MediaStream::StreamStart(SInt64 startTime)
|
||||
{
|
||||
|
||||
fData.fStreamStartTime = startTime;
|
||||
fData.fMovieEndTime = startTime;
|
||||
fData.fLastSenderReportTime = 0;
|
||||
|
||||
//for RTCp SRs, we also need to store the play time in NTP
|
||||
// fData.fNTPPlayTime = OS::TimeMilli_To_1900Fixed64Secs(startTime);
|
||||
fData.fNTPPlayTime = PlayListUtils::TimeMilli_To_1900Fixed64Secs(startTime);
|
||||
fData.fCurStreamRTpSequenceNumber = 0;
|
||||
fData.fMovieStartOffset = 0;
|
||||
|
||||
fData.fNewStreamStarted = true;
|
||||
fData.fSeqRandomOffset = PlayListUtils::Random();
|
||||
fData.fRTpRandomOffset = PlayListUtils::Random();
|
||||
|
||||
|
||||
// fData.fSeqRandomOffset = -1000; // test roll over
|
||||
// fData.fRTpRandomOffset = -100000; // test roll over
|
||||
|
||||
InitIfAudio();
|
||||
|
||||
//Build a static RTCp sender report (this way, only the info that changes
|
||||
//on the fly will have to be written)
|
||||
BuildStaticRTCpReport();
|
||||
}
|
||||
|
||||
void MediaStream::MovieStart(SInt64 startTime)
|
||||
{
|
||||
fData.fNewMovieStarted = true;
|
||||
fData.fMovieStartTime = startTime;
|
||||
|
||||
if (fData.fMovieMediaTypePtr && fData.fRTPFilePtr)
|
||||
{ UInt32 trackID = fData.fMovieMediaTypePtr->fTrackID;
|
||||
fData.fMovieMediaTypePtr->fTimeScale = fData.fRTPFilePtr->GetTrackTimeScale(trackID);
|
||||
|
||||
UInt64 lastMovieduration = (UInt64) ( (Float64) (fData.fLastMovieDurationSecs * (Float64) PlayListUtils::eMilli) ) ; // add the length of the last movie
|
||||
fData.fMovieStartOffset += lastMovieduration;
|
||||
|
||||
if (fData.fNewStreamStarted)
|
||||
{ fData.fNewStreamStarted = false;
|
||||
fData.fMovieEndTime = startTime; // first movie in stream has 0 movieInterval time.
|
||||
}
|
||||
|
||||
Float64 mediaOffSet = (Float64) (SInt64)fData.fMovieStartOffset / (Float64) PlayListUtils::eMilli; // convert to float seconds
|
||||
mediaOffSet = mediaOffSet * (Float64) fData.fMovieMediaTypePtr->fTimeScale; // mediaOffset in media time scale
|
||||
fData.fMediaStartOffsetMediaScale = (UInt64) mediaOffSet; // convert float time units to UInt64
|
||||
|
||||
fData.fLastMovieDurationSecs = fData.fRTPFilePtr->GetMovieDuration();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void MediaStream::MovieEnd(SInt64 endTime)
|
||||
{
|
||||
fData.fMovieEndTime = endTime;
|
||||
fData.fMovieMediaTypePtr = NULL;
|
||||
fData.fRTPFilePtr = NULL;
|
||||
}
|
||||
|
||||
SInt16 MediaStream::Accounting(RTpPacket *packetPtr)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
fData.fBytesSent += packetPtr->fLength;
|
||||
fData.fPacketsSent ++;
|
||||
|
||||
UInt32 lastTime = fData.fTimeStamp;
|
||||
unsigned char payload;
|
||||
packetPtr->GetHeaderInfo(&fData.fTimeStamp, &fData.fLastSequenceNumber, &fData.fSsrc, &payload);
|
||||
|
||||
fData.fLastTimeStampOffset = fData.fTimeStamp - lastTime;
|
||||
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 MediaStream::Send(RTpPacket *packetPtr)
|
||||
{
|
||||
|
||||
SInt16 result = -1;
|
||||
|
||||
do
|
||||
{
|
||||
if (fData.fMovieMediaTypePtr == NULL) break;
|
||||
|
||||
UpdatePacketInStream(packetPtr);
|
||||
|
||||
result = Accounting(packetPtr);
|
||||
if (result) break;
|
||||
|
||||
if (fSend)
|
||||
{ result = fData.fSocketPair->SendRTp(packetPtr->fThePacket, packetPtr->fLength);
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MediaStream::ReceiveOnPorts()
|
||||
{
|
||||
fData.fSocketPair->RecvRTp(fData.fPortRTpReadBuff.fReadBuffer, ReceiveBuffer::kReadBufferSize, &fData.fPortRTpReadBuff.fReceiveLen);
|
||||
fData.fSocketPair->RecvRTCp(fData.fPortRTCpReadBuff.fReadBuffer, ReceiveBuffer::kReadBufferSize, &fData.fPortRTCpReadBuff.fReceiveLen);
|
||||
}
|
||||
|
||||
#if DROP_RTCP_TEST
|
||||
static int numRTCPPackets = 0;
|
||||
static int numStartDropPackets = 0;
|
||||
#endif
|
||||
|
||||
int MediaStream::UpdateSenderReport(SInt64 theTime)
|
||||
{
|
||||
|
||||
if (NULL == fData.fMovieMediaTypePtr)
|
||||
return 0;
|
||||
|
||||
int result = 0;
|
||||
|
||||
SInt64 timeToSend = fData.fLastSenderReportTime + (kSenderReportIntervalInSecs * PlayListUtils::eMilli);
|
||||
|
||||
#if DROP_RTCP_TEST
|
||||
if (theTime > timeToSend )
|
||||
{
|
||||
if (fData.fIsSoundStream)
|
||||
{ numRTCPPackets ++;
|
||||
if ( (numRTCPPackets <= numStartDropPackets + DROPCOUNT) )
|
||||
{ qtss_printf("skip sound RTCP #%d time=%qd\n",numRTCPPackets, theTime / PlayListUtils::eMilli);
|
||||
fData.fLastSenderReportTime = theTime;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{ qtss_printf("send sound RTCP #%d time=%qd\n",numRTCPPackets, theTime / PlayListUtils::eMilli);
|
||||
numStartDropPackets = numRTCPPackets;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (theTime > timeToSend)
|
||||
{
|
||||
fData.fLastSenderReportTime = theTime;
|
||||
UInt32* theReport = (UInt32*) fData.fSenderReportBuffer;
|
||||
|
||||
theReport++;
|
||||
*theReport = htonl(fData.fSsrc);
|
||||
|
||||
theReport++;
|
||||
SInt64* theNTPTimestampP = (SInt64*)theReport;
|
||||
*theNTPTimestampP = OS::HostToNetworkSInt64(fData.fNTPPlayTime +
|
||||
PlayListUtils::TimeMilli_To_Fixed64Secs(theTime - fData.fStreamStartTime));
|
||||
|
||||
theReport += 2;
|
||||
*theReport = htonl(fData.fTimeStamp);
|
||||
|
||||
Float64 curTimeInScale = (Float64) (SInt64) PlayListUtils::Milliseconds() / (Float64) PlayListUtils::eMilli; // convert to float seconds
|
||||
curTimeInScale = curTimeInScale * (Float64) fData.fMovieMediaTypePtr->fTimeScale; // curTime in media time scale
|
||||
curTimeInScale +=(Float64) fData.fRTpRandomOffset;
|
||||
curTimeInScale = (UInt32) ( (UInt64) curTimeInScale & (UInt64) 0xFFFFFFFF );
|
||||
|
||||
//qtss_printf("MediaStream::UpdateSenderReport RTCP timestamp = %"_U32BITARG_"\n",(UInt32) curTimeInScale);
|
||||
*theReport = htonl((UInt32) curTimeInScale);
|
||||
|
||||
theReport++;
|
||||
fData.fPacketCount = (UInt32) fData.fPacketsSent;
|
||||
*theReport = htonl(fData.fPacketCount);
|
||||
|
||||
theReport++;
|
||||
fData.fByteCount = (UInt32) fData.fBytesSent;
|
||||
*theReport = htonl(fData.fByteCount);
|
||||
|
||||
theReport += 2;
|
||||
*theReport = htonl(fData.fSsrc);
|
||||
|
||||
LogStr("Sender Report\n");
|
||||
LogUInt("NTP ",(UInt32) ((*theNTPTimestampP) >> 32)," ");
|
||||
LogUInt(" ",(UInt32) ((*theNTPTimestampP) & 0xFFFFFFFF), "\n" );
|
||||
LogUInt("time stamp = ", fData.fTimeStamp, "\n");
|
||||
LogInt("SSRC = ", fData.fSsrc, "\n");
|
||||
LogUInt("Packets sent = ", fData.fPacketCount, "\n");
|
||||
LogUInt("Bytes sent = ", fData.fByteCount, "\n");
|
||||
LogBuffer();
|
||||
result = fData.fSocketPair->SendRTCp(fData.fSenderReportBuffer, fData.fSenderReportSize);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ************************
|
||||
//
|
||||
// UDPSOCKETPAIR
|
||||
//
|
||||
// ************************
|
||||
|
||||
|
||||
void UDPSocketPair::Close()
|
||||
{
|
||||
if (fMultiCastJoined)
|
||||
this->LeaveMulticast();
|
||||
|
||||
#ifdef __Win32__
|
||||
if (fSocketRTp != 0) ::closesocket(fSocketRTp);
|
||||
if (fSocketRTCp != 0) ::closesocket(fSocketRTCp);
|
||||
#else
|
||||
if (fSocketRTp != 0) ::close(fSocketRTp);
|
||||
if (fSocketRTCp != 0) ::close(fSocketRTCp);
|
||||
#endif
|
||||
fSocketRTp = 0;
|
||||
fSocketRTCp = 0;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::Open()
|
||||
{
|
||||
SInt16 result = 0;
|
||||
do
|
||||
{
|
||||
Close();
|
||||
|
||||
fSocketRTp = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fSocketRTp == kInvalidSocket)
|
||||
{ result = kInvalidSocket;
|
||||
break;
|
||||
}
|
||||
|
||||
fSocketRTCp = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fSocketRTCp == kInvalidSocket)
|
||||
{ result = kInvalidSocket;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __Win32__
|
||||
u_long one = 1;
|
||||
(void)::ioctlsocket(fSocketRTp, FIONBIO, &one);
|
||||
(void)::ioctlsocket(fSocketRTCp, FIONBIO, &one);
|
||||
#else
|
||||
int flag;
|
||||
int val;
|
||||
flag = ::fcntl(fSocketRTp, F_GETFL, 0);
|
||||
val = ::fcntl(fSocketRTp, F_SETFL, flag | O_NONBLOCK);
|
||||
if( val < 0 ) { result = -1; break; }
|
||||
|
||||
|
||||
flag = ::fcntl(fSocketRTCp, F_GETFL, 0);
|
||||
val = ::fcntl(fSocketRTCp, F_SETFL, flag | O_NONBLOCK);
|
||||
if( val < 0 ) { result = -1; break; }
|
||||
#endif
|
||||
} while (false);
|
||||
|
||||
if (result != 0)
|
||||
{ if (fSocketRTp != 0) ::close(fSocketRTp);
|
||||
if (fSocketRTCp != 0) ::close(fSocketRTCp);
|
||||
fSocketRTp = 0;
|
||||
fSocketRTCp = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void UDPSocketPair::InitPorts(UInt32 addr)
|
||||
{
|
||||
::memset(&fLocalAddrRTp, 0, sizeof(fLocalAddrRTp));
|
||||
fLocalAddrRTp.sin_family = PF_INET;
|
||||
fLocalAddrRTp.sin_port = htons(0);
|
||||
fLocalAddrRTp.sin_addr.s_addr = htonl(addr);
|
||||
|
||||
::memset(&fLocalAddrRTCp, 0, sizeof(fLocalAddrRTCp));
|
||||
fLocalAddrRTCp.sin_family = PF_INET;
|
||||
fLocalAddrRTCp.sin_port = htons(0);
|
||||
fLocalAddrRTCp.sin_addr.s_addr = htonl(addr);
|
||||
|
||||
::memset(&fDestAddrRTp, 0, sizeof(fDestAddrRTp));
|
||||
fDestAddrRTp.sin_family = PF_INET;
|
||||
fDestAddrRTp.sin_port = htons(0);
|
||||
fDestAddrRTp.sin_addr.s_addr = htonl(addr);
|
||||
|
||||
::memset(&fDestAddrRTCp, 0, sizeof(fDestAddrRTCp));
|
||||
fDestAddrRTCp.sin_family = PF_INET;
|
||||
fDestAddrRTCp.sin_port = htons(0);
|
||||
fDestAddrRTCp.sin_addr.s_addr = htonl(addr);
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::Bind(UInt32 addr)
|
||||
{
|
||||
int err = -1;
|
||||
|
||||
if ( (fSocketRTp == kInvalidSocket) || (fSocketRTCp == kInvalidSocket) )
|
||||
return -1;
|
||||
|
||||
InitPorts(addr);
|
||||
|
||||
UInt32 PortRTp = eSourcePortStart;
|
||||
UInt32 PortRTCp = PortRTp + 1; // keep them together for clarity
|
||||
|
||||
for (int count = eSourcePortStart; count < eSourcePortRange; count ++)
|
||||
{
|
||||
PortRTp = count;
|
||||
Assert( (PortRTp & 1) == 0); // must be even
|
||||
count += 1;
|
||||
PortRTCp = count;
|
||||
Assert( (PortRTCp & 1) == 1);// must be odd and one more than rtp port
|
||||
|
||||
fLocalAddrRTp.sin_port = htons( (UInt16) PortRTp);
|
||||
fLocalAddrRTCp.sin_port = htons( (UInt16) PortRTCp);
|
||||
|
||||
//qtss_printf("Attempting to bind to rtp port %d \n",PortRTp);
|
||||
|
||||
err = ::bind(fSocketRTp, (sockaddr *)&fLocalAddrRTp, sizeof(fLocalAddrRTp));
|
||||
if (err != 0)
|
||||
{
|
||||
//qtss_printf("UDPSocketPair::Bind Error binding to rtp port %d \n",PortRTp);
|
||||
InitPorts(addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
err = ::bind(fSocketRTCp, (sockaddr *)&fLocalAddrRTCp, sizeof(fLocalAddrRTCp));
|
||||
if (err != 0)
|
||||
{
|
||||
//qtss_printf("UDPSocketPair::Bind Error binding to rtcp port %d \n",PortRTp);
|
||||
Close();
|
||||
Open();
|
||||
InitPorts(addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
{
|
||||
//qtss_printf("Bound to rtp port = %d, rtcp port = %d \n",PortRTp, PortRTCp);
|
||||
fState |= kBound;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
SInt16 UDPSocketPair::SendTo(int socket, sockaddr *destAddrPtr, char* inBuffer, UInt32 inLength )
|
||||
{
|
||||
SInt16 result = -1;
|
||||
do
|
||||
{
|
||||
if (inBuffer == NULL) break;
|
||||
if (destAddrPtr == NULL) break;
|
||||
if (socket == kInvalidSocket) break;
|
||||
|
||||
//qtss_printf("Sending data to %d. Addr = %d inLength = %d\n", ntohs(theAddr->sin_port), ntohl(theAddr->sin_addr.s_addr), inLength);
|
||||
::sendto(socket, inBuffer, inLength, 0, destAddrPtr, sizeof(sockaddr));
|
||||
|
||||
result = 0;
|
||||
} while (false);
|
||||
|
||||
//if (result != 0) qtss_printf("UDP SENDTO ERROR!\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SInt16 UDPSocketPair::SendRTp(char* inBuffer, UInt32 inLength)
|
||||
{
|
||||
if (fBroadcasterSession != NULL)
|
||||
{ OSMutexLocker locker(fBroadcasterSession->GetMutex());
|
||||
return (SInt16) fBroadcasterSession->SendPacket(inBuffer,inLength,fChannel);
|
||||
}
|
||||
else
|
||||
return SendTo(fSocketRTp, (sockaddr*)&fDestAddrRTp, inBuffer, inLength );
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::SendRTCp(char* inBuffer, UInt32 inLength)
|
||||
{
|
||||
if (fBroadcasterSession != NULL)
|
||||
{ OSMutexLocker locker(fBroadcasterSession->GetMutex());
|
||||
return (SInt16) fBroadcasterSession->SendPacket(inBuffer,inLength,fChannel+1);
|
||||
}
|
||||
else
|
||||
return SendTo(fSocketRTCp, (sockaddr*)&fDestAddrRTCp, inBuffer, inLength );
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::SetDestination (char *destAddress,UInt16 destPortRTp, UInt16 destPortRTCp)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
if (destAddress != NULL)
|
||||
{ UInt32 netAddress = inet_addr(destAddress);
|
||||
|
||||
fDestAddrRTp = fLocalAddrRTp;
|
||||
fDestAddrRTp.sin_port = htons(destPortRTp);
|
||||
fDestAddrRTp.sin_addr.s_addr = netAddress;
|
||||
|
||||
fDestAddrRTCp = fLocalAddrRTCp;
|
||||
fDestAddrRTCp.sin_port = htons(destPortRTCp);
|
||||
fDestAddrRTCp.sin_addr.s_addr = netAddress;
|
||||
|
||||
fIsMultiCast = SocketUtils::IsMulticastIPAddr(ntohl(netAddress));
|
||||
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::SetMulticastInterface()
|
||||
{
|
||||
// set the outgoing interface for multicast datagrams on this socket
|
||||
in_addr theLocalAddr;
|
||||
::memset(&theLocalAddr, 0, sizeof(theLocalAddr));
|
||||
|
||||
theLocalAddr.s_addr = fLocalAddrRTp.sin_addr.s_addr;
|
||||
int err = setsockopt(fSocketRTp, IPPROTO_IP, IP_MULTICAST_IF, (char*)&theLocalAddr, sizeof(theLocalAddr));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::JoinMulticast()
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
|
||||
UInt32 localAddr = fLocalAddrRTp.sin_addr.s_addr; // Already in network byte order
|
||||
|
||||
#if __solaris__
|
||||
if( localAddr == htonl(INADDR_ANY) )
|
||||
localAddr = htonl(SocketUtils::GetIPAddr(0));
|
||||
#endif
|
||||
|
||||
struct ip_mreq theMulti;
|
||||
::memset(&theMulti, 0, sizeof(theMulti));
|
||||
|
||||
theMulti.imr_multiaddr.s_addr = fDestAddrRTp.sin_addr.s_addr;
|
||||
theMulti.imr_interface.s_addr = localAddr;
|
||||
err = setsockopt(fSocketRTp, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
|
||||
(void) setsockopt(fSocketRTCp, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
|
||||
|
||||
if (err == 0)
|
||||
fMultiCastJoined = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
SInt16 UDPSocketPair::SetTTL(SInt16 timeToLive)
|
||||
{
|
||||
// set the ttl
|
||||
int nOptVal = (int)timeToLive;
|
||||
int err = 0;
|
||||
|
||||
err = setsockopt(fSocketRTp, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&nOptVal, sizeof(nOptVal));
|
||||
if (err != 0) return err;
|
||||
|
||||
err = setsockopt(fSocketRTCp, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&nOptVal, sizeof(nOptVal));
|
||||
return err;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::LeaveMulticast()
|
||||
{
|
||||
UInt32 localAddr = fLocalAddrRTp.sin_addr.s_addr; // Already in network byte order
|
||||
|
||||
#if __solaris__
|
||||
if( localAddr == htonl(INADDR_ANY) )
|
||||
localAddr = htonl(SocketUtils::GetIPAddr(0));
|
||||
#endif
|
||||
|
||||
struct ip_mreq theMulti;
|
||||
::memset(&theMulti, 0, sizeof(theMulti));
|
||||
|
||||
theMulti.imr_multiaddr.s_addr = fDestAddrRTp.sin_addr.s_addr;
|
||||
theMulti.imr_interface.s_addr = localAddr;
|
||||
|
||||
int err = setsockopt(fSocketRTp, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
|
||||
(void) setsockopt(fSocketRTCp, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
|
||||
return err;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::RecvFrom(sockaddr *RecvRTpddrPtr, int socket, char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
do
|
||||
{
|
||||
if (ioBuffer == NULL) break;
|
||||
if (RecvRTpddrPtr == NULL) break;
|
||||
if (socket == kInvalidSocket) break;
|
||||
|
||||
sockaddr_in theAddr;
|
||||
#if __Win32__ || __osf__ || __sgi__ || __hpux__
|
||||
int addrLen = sizeof(theAddr);
|
||||
#else
|
||||
socklen_t addrLen = sizeof(theAddr);
|
||||
#endif
|
||||
|
||||
SInt32 theRecvLen = ::recvfrom(socket, ioBuffer, inBufLen, 0, (sockaddr*)&theAddr, &addrLen);
|
||||
if (theRecvLen == -1) break;
|
||||
|
||||
if (outRecvLen) *outRecvLen = (UInt32)theRecvLen;
|
||||
} while (false);
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::RecvRTp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
|
||||
{
|
||||
return RecvFrom( (sockaddr *)&fDestAddrRTp, fSocketRTp, ioBuffer, inBufLen, outRecvLen);
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::RecvRTCp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
|
||||
{
|
||||
return RecvFrom( (sockaddr *)&fDestAddrRTCp, fSocketRTCp, ioBuffer, inBufLen, outRecvLen);
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::SetMultiCastOptions(SInt16 ttl)
|
||||
{
|
||||
SInt16 err = 0;
|
||||
|
||||
if (this->fIsMultiCast) do// set by SetDestination
|
||||
{
|
||||
err = this->SetTTL(ttl);
|
||||
WarnV(err == 0 , "failed to set ttl");
|
||||
if (err != 0) break;
|
||||
|
||||
err = this->SetMulticastInterface();
|
||||
WarnV(err == 0 , "failed to set multicast socket option");
|
||||
if (err != 0) break;
|
||||
|
||||
err = this->JoinMulticast();
|
||||
WarnV(err == 0 , "failed to join multicast");
|
||||
if (err != 0) break;
|
||||
|
||||
} while (false);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::OpenAndBind( UInt16 rtpPort,UInt16 rtcpPort,char *destAddress)
|
||||
{
|
||||
SInt16 err = -1;
|
||||
|
||||
do
|
||||
{
|
||||
err = this->Open();
|
||||
if (err != 0) break;
|
||||
|
||||
err = this->Bind(INADDR_ANY);
|
||||
if (err != 0) break;
|
||||
|
||||
err = this->SetDestination (destAddress, rtpPort, rtcpPort);
|
||||
if (err != 0) break;
|
||||
|
||||
} while (false);
|
||||
|
||||
if (err)
|
||||
{
|
||||
this->Close();
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
// ************************
|
||||
//
|
||||
// RTpPacket
|
||||
//
|
||||
// ************************
|
||||
|
||||
SInt16 RTpPacket::GetSoundDescriptionRef(SoundDescription **soundDescriptionPtr)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
if (fThePacket && soundDescriptionPtr)
|
||||
{
|
||||
SInt32 minSoundLength = sizeof(SoundHeader) + sizeof(SoundDescription) + kRTpHeaderSize;
|
||||
if ( fLength >= minSoundLength )
|
||||
{
|
||||
char *offsetPtr = fThePacket + kRTpHeaderSize + sizeof(SoundHeader);
|
||||
*soundDescriptionPtr = (SoundDescription *) offsetPtr;
|
||||
SInt32 descSize = ntohl( (**soundDescriptionPtr).descSize);
|
||||
fSoundDescriptionLen = descSize;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RTpPacket::HasSoundDescription()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (fThePacket)
|
||||
{
|
||||
|
||||
// WritePacketToLog(fThePacket, fLength);
|
||||
SInt32 minSoundLength = sizeof(SoundHeader) + sizeof(SoundDescription) + kRTpHeaderSize;
|
||||
if (fLength >= minSoundLength )
|
||||
{
|
||||
char *offsetPtr = fThePacket + kRTpHeaderSize;
|
||||
SoundHeader* testHeaderPtr = (SoundHeader*) offsetPtr;
|
||||
do
|
||||
{
|
||||
if (testHeaderPtr->bytes[0] != 0x17) break;
|
||||
if (testHeaderPtr->sndtype[0] != 's') break;
|
||||
if (testHeaderPtr->sndtype[1] != 'o') break;
|
||||
if (testHeaderPtr->sndtype[2] != 'u') break;
|
||||
if (testHeaderPtr->sndtype[3] != 'n') break;
|
||||
|
||||
fHasSoundDescription = result = true;
|
||||
|
||||
} while (false);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
LogStr("has sound description soun\n");
|
||||
}
|
||||
PrintLogBuffer(true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 RTpPacket::GetHeaderInfo(UInt32 *timeStampPtr, UInt16 *sequencePtr,UInt32 *SSRCPtr, unsigned char*payloadTypeAndMarkPtr)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
|
||||
unsigned char *header8Ptr = (unsigned char *) fThePacket;
|
||||
UInt16* header16Ptr = (UInt16*)fThePacket;
|
||||
UInt32* header32Ptr = (UInt32*)fThePacket;
|
||||
|
||||
if (fThePacket && timeStampPtr && sequencePtr && SSRCPtr && payloadTypeAndMarkPtr)
|
||||
{
|
||||
*payloadTypeAndMarkPtr = header8Ptr[cPayloadType];
|
||||
*sequencePtr = ntohs(header16Ptr[cSequenceNumber]);
|
||||
*timeStampPtr = ntohl(header32Ptr[cTimeStamp]);
|
||||
*SSRCPtr = ntohl(header32Ptr[cSSRC]);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SInt16 RTpPacket::SetHeaderInfo(UInt32 timeStamp, UInt16 sequence, UInt32 SSRC, unsigned char payloadTypeAndMark)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
unsigned char *header8Ptr = (unsigned char *) fThePacket;
|
||||
UInt16* header16Ptr = (UInt16*)fThePacket;
|
||||
UInt32* header32Ptr = (UInt32*)fThePacket;
|
||||
|
||||
|
||||
if (fThePacket)
|
||||
{
|
||||
LogInt("sequence = ", sequence, " ");
|
||||
LogUInt("time = ", timeStamp, " ");
|
||||
// LogUInt("old payload = ",( UInt32 ) (header8Ptr[cPayloadType] & 0x7F)," ");
|
||||
LogUInt("payload = ",( UInt32 ) (payloadTypeAndMark & 0x7F) ," ");
|
||||
// LogUInt("old marker = ", ( UInt32 ) (header8Ptr[cPayloadType] & 0x80) ," ");
|
||||
// LogUInt("marker = ", ( UInt32 ) (payloadTypeAndMark & 0x80) ," ");
|
||||
LogUInt("ssrc = ", SSRC, "\n");
|
||||
|
||||
header8Ptr[cPayloadType] = payloadTypeAndMark;
|
||||
header16Ptr[cSequenceNumber] = htons(sequence);
|
||||
header32Ptr[cTimeStamp] = htonl(timeStamp);
|
||||
header32Ptr[cSSRC] = htonl(SSRC);
|
||||
result = 0;
|
||||
|
||||
LogBuffer();
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue