Very rough first start, not even everything added

This commit is contained in:
Darren VanBuren 2017-03-07 14:51:44 -08:00
commit af3619d4fa
88 changed files with 24251 additions and 0 deletions

View file

@ -0,0 +1,578 @@
/*
*
* @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@
*
*/
/*
8.30.99 - changes for linux version
- IsProcessRunning changed
- fputs difference.
8.2.99 rt
- changed BCasterTracker::BCasterTracker to 5 second open timer.
- no longer lists broadcasts that are not running. file is
cleaned up on next "stop"
*/
#include "BCasterTracker.h"
#include "MyAssert.h"
#include "Trim.h"
#include "GetWord.h"
#include "OSThread.h"
#include <stdlib.h>
#include "SafeStdLib.h"
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#if !(defined(__solaris__) || defined(__osf__) || defined(__hpux__))
#include <sys/sysctl.h>
#endif
#include <sys/time.h>
#include <signal.h>
char gTrackerFileTempDataPath[256];
void TestBCasterTracker(int x )
{
BCasterTracker tracker( "trackerfile" );
if ( tracker.IsOpen() )
{
if ( x > - 1 )
{ int error;
error = tracker.Remove( x );
if ( error ) // remove the xth item from the list.
qtss_printf( "Playlist Broadcast (%li) not found.\n", (SInt32)x );
else
tracker.Save();
}
else
{
tracker.Show();
}
}
else
qtss_printf("PlaylistBroadcaster trackerfile open FAILED.\n");
}
static void ShowElement( PLDoubleLinkedListNode<TrackingElement>* ten, void* userData)
{
int* showIndex = (int*)userData;
char *info;
if ( BCasterTracker::IsProcessRunning( ten->fElement->mPID ) )
info = "";
else
info = ", (not running)";
//qtss_printf( "[%li] %li %s%s\n", (SInt32)*showIndex, (SInt32)ten->fElement->mPID, ten->fElement->mName, info );
qtss_printf( "[%3li] %s; pid: %li%s\n", (SInt32)*showIndex, ten->fElement->mName, (SInt32)ten->fElement->mPID, info );
*(int*)userData = *showIndex + 1;
}
void BCasterTracker::Show()
{
int showIndex = 1;
if ( mTrackingList.GetNumNodes() )
{
qtss_printf( "\n" );
qtss_printf( "Current Playlist Broadcasts\n" );
qtss_printf( " ID Description file; Process ID\n" );
qtss_printf( "----------------------------------\n" );
// display the elements in the list
mTrackingList.ForEach( ShowElement, &showIndex );
}
else
{ qtss_printf( "\n" );
qtss_printf( "- PlaylistBroadcaster: No Broadcasts running.\n" );
}
}
bool BCasterTracker::IsProcessRunning( pid_t pid )
{
bool isRunning=false;
/*
// Generic unix code
char procPath[256];
qtss_sprintf( procPath, "ps -p%li | grep %li > %s ",(SInt32)pid,(SInt32)pid,gTrackerFileTempDataPath);
int result = system(procPath);
if (0 == result)
{ isRunning = true;
}
*/
// a no-grep version to find the pid
char pidStr[32];
qtss_sprintf( pidStr, "%li",(SInt32)pid);
char procPath[64] = "ps -p";
::strcat( procPath, pidStr);
FILE *inPipe = ::popen(procPath, "r");
if (NULL == inPipe)
return false;
char inBuff[256] = "";
while (!isRunning && ::fgets(inBuff, sizeof(inBuff), inPipe) != 0)
{ if (::strstr(inBuff,pidStr) != NULL)
{ isRunning = true;
break;
}
}
(void) ::pclose(inPipe);
return isRunning;
}
bool IsProcessID( PLDoubleLinkedListNode<TrackingElement>*ten, void* userData)
{
/*
used by ForEachUntil to find a TrackingElement with a given Process ID
userData is a pointer to the process id we want find in our list.
*/
pid_t pid;
bool isProcID = false;
pid = *(pid_t*)userData;
if ( pid == ten->fElement->mPID )
isProcID = true;
return isProcID;
}
int BCasterTracker::RemoveByProcessID( pid_t pid )
{
int error = -1;
// remove the element with the given process ID
// from the tracking list.
// called by the app when it is going away.
// DO NOT kill the pid being passed in.
PLDoubleLinkedListNode<TrackingElement> *te;
te = mTrackingList.ForEachUntil( IsProcessID, &pid );
// remove that element
if ( te )
{
mTrackingList.RemoveNode(te);
error = 0;
}
return error;
}
static bool IsElementID( PLDoubleLinkedListNode<TrackingElement> */*ten*/, void* userData)
{
/*
used by ForEachUntil to find a TrackingElement with a given index number
userData is a pointer to the counter, initialized to the index we want
to find.
we decrement it until is reaches zero.
*/
UInt32* showIndex = (UInt32*)userData;
bool isItemId = false;
// when the counter reduces to zero, return true.
if ( *showIndex == 0 )
isItemId = true;
else
*(int*)userData = *showIndex - 1;
return isItemId;
}
int BCasterTracker::Remove( UInt32 itemID )
{
int error = -1;
UInt32 itemIDIndex = itemID;
// KILL the process that is associated with the item
// id in our list.
// remove the element with the given index in the list
// from the tracking list.
// itemID is zero based
// set the index to the item number we want to find. Use ForEachUntil with IsElementID
// to count down through the elements until we get to the Nth element.
PLDoubleLinkedListNode<TrackingElement> *te;
te = mTrackingList.ForEachUntil( IsElementID, &itemIDIndex );
// remove that element, and kill the process
if ( te )
{
if ( ::kill( te->fElement->mPID, SIGTERM ) == 0 )
{
error = 0;
}
else
{
error = OSThread::GetErrno();
if ( error != ESRCH ) // no such process
{
// we probably cannot kill this process because it is not ours
}
else
{ // this process already died, or was killed by other means.
error = 0;
}
}
if ( !error )
{
mTrackingList.RemoveNode(te);
}
}
return error;
}
int BCasterTracker::Add( pid_t pid, const char* bcastList )
{
/*
add an entry to our tracking list
*/
int addErr = -1;
TrackingElement* te = new TrackingElement( pid, bcastList );
Assert( te );
if ( te )
{
PLDoubleLinkedListNode<TrackingElement>* ten = new PLDoubleLinkedListNode<TrackingElement>( te );
Assert( ten );
if ( ten )
{ mTrackingList.AddNodeToTail( ten );
addErr = 0;
}
else
delete te;
}
return addErr;
}
BCasterTracker::~BCasterTracker()
{
// truncate the file to the desired size and close.
if ( mTrackerFile != NULL )
{
int err = OSThread::GetErrno();
if ( ::fseek( mTrackerFile, mEofPos, SEEK_SET ) < 0 )
qtss_printf( "fseek at close eof(%li), err(%li), fileno(%li)\n", mEofPos, (SInt32)err, (SInt32)fileno(mTrackerFile) );
if ( ::fflush( mTrackerFile ) )
qtss_printf( "fflush at close eof(%li), err(%li), fileno(%li)\n", mEofPos, (SInt32)err, (SInt32)fileno(mTrackerFile) );
if ( ::ftruncate( fileno(mTrackerFile), (off_t)mEofPos ) )
{
qtss_printf( "ftruncate at close eof(%li), err(%li), fileno(%li)\n", mEofPos, (SInt32)err, (SInt32)fileno(mTrackerFile) );
}
(void)::fclose( mTrackerFile );
}
}
static bool SaveElement( PLDoubleLinkedListNode<TrackingElement>* ten, void* userData)
{
FILE* fp = (FILE*) userData;
char buff[512];
/*
used by ForEachUntil to find a SaveElement each element to the tracking file.
userData is a pointer to the FILE of our open tracking file.
*/
qtss_sprintf( buff, "%li \"%s\"\n", (SInt32)ten->fElement->mPID, ten->fElement->mName );
// linux version of fputs returns <0 for err, or num bytes written
// mac os X version of fputs returns <0 for err, or 0 for no err
if (::fputs( buff, fp ) < 0 )
return true;
return false;
}
int BCasterTracker::Save()
{
/*
save each record in the the tracker to disk.
return 0 on success, < 0 otherwise.
*/
int error = -1;
mEofPos = 0;
if ( mTrackerFile != NULL )
{
if ( !::fseek( mTrackerFile, 0, SEEK_SET ) )
{
if ( !mTrackingList.ForEachUntil( SaveElement, mTrackerFile ) )
{
mEofPos = ::ftell( mTrackerFile );
error = 0;
}
}
}
return error;
}
bool BCasterTracker::IsOpen()
{
// return false if the file is not open,
// true if the file is open.
if ( mTrackerFile == NULL )
return false;
else
return true;
}
BCasterTracker::BCasterTracker( const char* name )
{
mEofPos = 0;
mTrackerFile = NULL;
time_t calendarTime = 0;
calendarTime = ::time(NULL) + 10;
// wait a SInt32 time for access to the file.
// 2 possible loops one to try to open ( and possible create ) the file
// the second to obtain an exclusive lock on the file.
// the app should probably fail if this cannot be done within the alloted time
//qtss_printf("time=%"_S32BITARG_"\n",calendarTime);
while ( mTrackerFile == NULL && calendarTime > ::time(NULL) )
{ mTrackerFile = ::fopen( name, "r+" );
if ( !mTrackerFile )
{ // try and create
mTrackerFile = ::fopen( name, "a+" );
if ( mTrackerFile )
{
// let "everyone" read and write this file so that we can track
// all the broadcasters no matter which user starts them
(void)::chmod( name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
(void)::fclose( mTrackerFile );
}
mTrackerFile = NULL;
}
::sleep(1);
}
::strcpy(gTrackerFileTempDataPath,name);
::strcat( gTrackerFileTempDataPath, "_tmp" );
FILE * tempFile = NULL;
calendarTime = ::time(NULL) + 10;
while ( tempFile == NULL && calendarTime > ::time(NULL) )
{ tempFile = ::fopen( gTrackerFileTempDataPath, "r+" );
if ( !tempFile )
{ // try and create
tempFile = ::fopen( gTrackerFileTempDataPath, "a+" );
if ( tempFile )
{
// let "everyone" read and write this file so that we can track
// all the broadcasters no matter which user starts them
(void)::chmod( gTrackerFileTempDataPath, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
}
}
}
if (tempFile)
(void)::fclose( tempFile );
if ( mTrackerFile )
{
bool haveLock = false;
while ( !haveLock && calendarTime > ::time(NULL) )
{
struct flock lock_params;
lock_params.l_start = 0; /* starting offset */
lock_params.l_len = 0; /* len = 0 means until end of file */
lock_params.l_pid = getpid(); /* lock owner */
lock_params.l_type = F_WRLCK; /* lock type: read/write, etc. */
lock_params.l_whence = 0; /* type of l_start */
if ( !::fcntl( fileno(mTrackerFile), F_SETLK, &lock_params ) )
haveLock = true;
}
// if can't lock it, close it.
if ( !haveLock )
{ (void)::fclose( mTrackerFile );
mTrackerFile = NULL;
}
}
if ( mTrackerFile )
{
SInt32 lineBuffSize = kTrackerLineBuffSize;
SInt32 wordBuffSize = kTrackerLineBuffSize;
char lineBuff[kTrackerLineBuffSize];
char wordBuff[kTrackerLineBuffSize];
char *next;
UInt32 pid;
int error = 0;
error = ::fseek( mTrackerFile, 0, SEEK_SET );
Assert(error == 0);
do
{
// get a line ( fgets adds \n+ 0x00 )
if ( ::fgets( lineBuff, lineBuffSize, mTrackerFile ) == NULL )
break;
// trim the leading whitespace
next = ::TrimLeft( lineBuff );
if (*next)
{
// grab the pid
next = ::GetWord( wordBuff, next, wordBuffSize );
Assert( *wordBuff );
pid = ::atoi( wordBuff );
if (*next)
next = ::TrimLeft( next );
// grab the broadcast list string
if (*next)
{
next = ::TrimLeft( next );
if (*next == '"' )
next = ::GetQuotedWord( wordBuff, next, wordBuffSize );
else
next = ::GetWord( wordBuff, next, wordBuffSize );
if ( this->IsProcessRunning( pid ) )
{
if (*wordBuff)
{ error = this->Add( pid, wordBuff );
}
}
}
}
} while ( feof( mTrackerFile ) == 0 && error == 0 );
mEofPos = ::ftell( mTrackerFile );
}
// dtor closes file...
}

View file

@ -0,0 +1,61 @@
/*
*
* @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@
*
*/
#ifndef __BCASTERTRACKER__
#define __BCASTERTRACKER__
#include <stdio.h>
#include "TrackingElement.h"
#include "PLDoubleLinkedList.h"
class BCasterTracker
{
public:
BCasterTracker( const char* fName );
virtual ~BCasterTracker();
int RemoveByProcessID( pid_t pid );
int Remove( UInt32 itemID );
int Add( pid_t pid, const char* bcastList );
int Save();
void Show();
static bool IsProcessRunning( pid_t pid );
bool IsOpen();
protected:
enum { kTrackerLineBuffSize = 512 };
FILE* mTrackerFile;
SInt32 mEofPos;
PLDoubleLinkedList<TrackingElement> mTrackingList;
};
void TestBCasterTracker(int x);
#endif

View file

@ -0,0 +1,302 @@
/*
*
* @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@
*
*/
#ifndef kVersionString
#include "../revision.h"
#endif
#include "BroadcastLog.h"
static Bool16 sLogTimeInGMT = false;
static char* sLogHeader = "#Software: %s\n"
"#Version: %s\n" //%s == version
"#Date: %s\n" //%s == date/time
"#Remark: All date values are in %s.\n" //%s == "GMT" or "local time"
"#Fields: date time filepath title copyright comment author artist album duration result\n";
BroadcastLog::BroadcastLog( PLBroadcastDef* broadcastParms, StrPtrLen* defaultPathPtr )
: QTSSRollingLog()
{
*mDirPath = 0;
*mLogFileName = 0;
mWantsLogging = false;
if (broadcastParms->mLogging)
{
if (!::strcmp( broadcastParms->mLogging, "enabled" ) )
{
mWantsLogging = true;
::strcpy( mDirPath, broadcastParms->mLogFile );
char* nameBegins = ::strrchr( mDirPath, kPathDelimiterChar );
if ( nameBegins )
{
*nameBegins = 0; // terminate mDirPath at the last PathDelimeter
nameBegins++;
::strcpy( mLogFileName, nameBegins );
}
else
{ // it was just a file name, no dir spec'd
memcpy(mDirPath,defaultPathPtr->Ptr,defaultPathPtr->Len);
mDirPath[defaultPathPtr->Len] = 0;
::strcpy( mLogFileName, broadcastParms->mLogFile );
}
}
}
this->SetLoggingEnabled(mWantsLogging);
}
time_t BroadcastLog::WriteLogHeader(FILE *inFile)
{
// Write a W3C compatable log header
time_t calendarTime = ::time(NULL);
Assert(-1 != calendarTime);
if (-1 == calendarTime)
return -1;
struct tm timeResult;
struct tm* theLocalTime = qtss_localtime(&calendarTime, &timeResult);
Assert(NULL != theLocalTime);
if (NULL == theLocalTime)
return -1;
char tempBuffer[1024] = { 0 };
qtss_strftime(tempBuffer, sizeof(tempBuffer), "#Log File Created On: %m/%d/%Y %H:%M:%S\n", theLocalTime);
this->WriteToLog(tempBuffer, !kAllowLogToRoll);
tempBuffer[0] = '\0';
// format a date for the startup time
char theDateBuffer[QTSSRollingLog::kMaxDateBufferSizeInBytes] = { 0 };
Bool16 result = QTSSRollingLog::FormatDate(theDateBuffer, false);
if (result)
{
qtss_sprintf(tempBuffer, sLogHeader, "PlaylistBroadcaster" , kVersionString,
theDateBuffer, sLogTimeInGMT ? "GMT" : "local time");
this->WriteToLog(tempBuffer, !kAllowLogToRoll);
}
return calendarTime;
}
void BroadcastLog::LogInfo( const char* infoStr )
{
// log a generic comment
char strBuff[1024] = "# ";
char dateBuff[80] = "";
if ( this->FormatDate( dateBuff, false ) )
{
if ( (NULL != infoStr)
&& ( ( strlen(infoStr) + strlen(strBuff) + strlen(dateBuff) ) < 800)
)
{
qtss_sprintf(strBuff,"#Remark: %s %s\n",dateBuff, infoStr);
this->WriteToLog( strBuff, kAllowLogToRoll );
}
else
{
::strcat(strBuff,dateBuff);
::strcat(strBuff," internal error in LogInfo\n");
this->WriteToLog( strBuff, kAllowLogToRoll );
}
}
}
void BroadcastLog::LogMediaError( const char* path, const char* errStr , const char* messageStr)
{
// log movie play info
char strBuff[1024] = "";
char dateBuff[80] = "";
if ( this->FormatDate( dateBuff, false ) )
{
if ( (NULL != path)
&& ( (strlen(path) + strlen(dateBuff) ) < 800)
)
{
qtss_sprintf(strBuff,"#Remark: %s %s ",dateBuff, path);
if ( errStr )
{ if ( (strlen(strBuff) + strlen(errStr) ) < 1000 )
{
::strcat(strBuff,"Error:");
::strcat(strBuff,errStr);
}
}
else
if ( (NULL != messageStr)
&&
( (strlen(strBuff) + strlen(messageStr) ) < 1000 )
)
{ ::strcat(strBuff,messageStr);
}
else
::strcat(strBuff,"OK");
::strcat(strBuff,"\n");
this->WriteToLog(strBuff, kAllowLogToRoll );
}
else
{
::strcat(strBuff,dateBuff);
::strcat(strBuff," internal error in LogMediaError\n");
this->WriteToLog( strBuff, kAllowLogToRoll );
}
}
}
void BroadcastLog::LogMediaData( const char* path, const char* title, const char* copyright,
const char* comment, const char* author, const char* artist,
const char* album, UInt32 duration, SInt16 result)
{
// log movie play info
char strBuff[1024] = "";
char dateBuff[80] = "";
if ( this->FormatDate( dateBuff, false ) )
{
if ( (NULL != path)
&& ( (strlen(path) + strlen(dateBuff) ) < 800)
)
{
qtss_sprintf(strBuff,"%s '%s'",dateBuff, path);
if ( title || title[0] != 0)
{ if ( (strlen(strBuff) + strlen(title) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, title);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( copyright || copyright[0] != 0)
{ if ( (strlen(strBuff) + strlen(copyright) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, copyright);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( comment || comment[0] != 0)
{ if ( (strlen(strBuff) + strlen(comment) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, comment);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( author || author[0] != 0)
{ if ( (strlen(strBuff) + strlen(author) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, author);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( artist || artist[0] != 0)
{ if ( (strlen(strBuff) + strlen(artist) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, artist);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
if ( album || album[0] != 0)
{ if ( (strlen(strBuff) + strlen(album) ) < 1000 )
{
::strcat(strBuff," '");
::strcat(strBuff, album);
::strcat(strBuff,"'");
}
}
else
{
::strcat(strBuff," -");
}
// add the duration in seconds
qtss_sprintf(dateBuff, " %"_S32BITARG_" ", duration);
::strcat(strBuff,dateBuff);
// add the result code
qtss_sprintf(dateBuff, " %d\n", result);
::strcat(strBuff,dateBuff);
this->WriteToLog(strBuff, kAllowLogToRoll );
}
else
{
::strcat(strBuff,dateBuff);
::strcat(strBuff," internal error in LogMediaData\n");
this->WriteToLog( strBuff, kAllowLogToRoll );
}
}
}

View file

@ -0,0 +1,90 @@
#ifndef __BroadcastLog__
#define __BroadcastLog__
/*
*
* @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 "QTSSRollingLog.h"
#include "PLBroadcastDef.h"
#include "StrPtrLen.h"
#include <string.h>
class BroadcastLog : public QTSSRollingLog
{
enum { eLogMaxBytes = 0, eLogMaxDays = 0 };
public:
BroadcastLog( PLBroadcastDef* broadcastParms, StrPtrLen* defaultPathPtr);
virtual ~BroadcastLog() {}
virtual char* GetLogName()
{ // RTSPRollingLog wants to see a "new'd" copy of the file name
char* name = new char[strlen( mLogFileName ) + 1 ];
if ( name )
::strcpy( name, mLogFileName );
return name;
}
virtual char* GetLogDir()
{ // RTSPRollingLog wants to see a "new'd" copy of the file name
char *name = new char[strlen( mDirPath ) + 1 ];
if ( name )
::strcpy( name, mDirPath );
return name;
}
virtual UInt32 GetRollIntervalInDays() { return eLogMaxDays; /* we dont' roll*/ }
virtual UInt32 GetMaxLogBytes() { return eLogMaxBytes; /* we dont' roll*/ }
void LogInfo( const char* infoStr );
void LogMediaError( const char* path, const char* errStr, const char* messageStr);
void LogMediaData( const char* path, const char* title, const char* copyright,
const char* comment, const char* author, const char* artist,
const char* album, UInt32 duration, SInt16 result);
bool WantsLogging() { return mWantsLogging; }
const char* LogFileName() { return mLogFileName; }
const char* LogDirName() { return mDirPath; }
virtual time_t WriteLogHeader(FILE *inFile);
protected:
char mDirPath[256];
char mLogFileName[256];
bool mWantsLogging;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,288 @@
/*
*
* @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: BroadcasterSession.h
*/
#ifndef __BROADCASTER_SESSION__
#define __BROADCASTER_SESSION__
#include "Task.h"
#include "TimeoutTask.h"
#include "RTSPClient.h"
#include "ClientSocket.h"
#include "SDPSourceInfo.h"
#include "UDPSocket.h"
#include "StrPtrLen.h"
#include "OSMutex.h"
class BroadcasterSession : public Task
{
public:
enum
{
kRTSPUDPBroadcasterType = 0,
kRTSPTCPBroadcasterType = 1,
kRTSPHTTPBroadcasterType = 2,
kRTSPHTTPDropPostBroadcasterType = 3,
kRTSPReliableUDPBroadcasterType = 4
};
typedef UInt32 BroadcasterType;
BroadcasterSession( UInt32 inAddr, UInt16 inPort, char* inURL,
BroadcasterType inBroadcasterType,
UInt32 inDurationInSec, UInt32 inStartPlayTimeInSec,
UInt32 inRTCPIntervalInSec, UInt32 inOptionsIntervalInSec,
UInt32 inHTTPCookie, Bool16 inAppendJunkData, UInt32 inReadInterval,
UInt32 inSockRcvBufSize,
StrPtrLen *sdpSPLPtr,
char *namePtr,
char *passwordPtr,
Bool16 deepDebug,
Bool16 burst);
virtual ~BroadcasterSession();
//
// Signals.
//
// Send a kKillEvent to delete this object.
// Send a kTeardownEvent to tell the object to send a TEARDOWN and abort
enum
{
kTeardownEvent = 0x00000100
};
virtual SInt64 Run();
//
// States. Find out what the object is currently doing
enum
{
kSendingAnnounce = 0,
kSendingSetup = 1,
kSendingReceive = 2,
kBroadcasting = 3,
kSendingTeardown = 4,
kDone = 5
};
//
// Why did this session die?
enum
{
kDiedNormally = 0, // Session went fine
kTeardownFailed = 1, // Teardown failed, but session stats are all valid
kRequestFailed = 2, // Session couldn't be setup because the server returned an error
kBadSDP = 3, // Server sent back some bad SDP
kSessionTimedout = 4, // Server not responding
kConnectionFailed = 5, // Couldn't connect at all.
kDiedWhileBroadcasting = 6, // Connection was forceably closed while Broadcasting the movie
kMemoryError = 7
};
//
// Once this client session is completely done with the TEARDOWN and ready to be
// destructed, this will return true. Until it returns true, this object should not
// be deleted. When it does return true, this object should be deleted.
Bool16 IsDone() { return fState == kDone; }
//
// ACCESSORS
RTSPClient* GetBroadcaster() { return fRTSPClient; }
ClientSocket* GetSocket() { return fSocket; }
SDPSourceInfo* GetSDPInfo() { return &fSDPParser; }
UInt32 GetState() { return fState; }
UInt32 GetDeathState() { return fDeathState; }
// When this object is in the kDone state, this will tell you why the session died.
UInt32 GetReasonForDying() { return fDeathReason; }
UInt32 GetRequestStatus() { return fRTSPClient->GetStatus(); }
// Tells you the total time we were receiving packets. You can use this
// for computing bit rate
SInt64 GetTotalPlayTimeInMsec() { return fTotalPlayTime; }
QTSS_RTPPayloadType GetTrackType(UInt32 inTrackIndex)
{ return fSDPParser.GetStreamInfo(inTrackIndex)->fPayloadType; }
UInt32 GetNumPacketsReceived(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumPacketsReceived; }
UInt32 GetNumBytesReceived(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumBytesReceived; }
UInt32 GetNumPacketsLost(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumLostPackets; }
UInt32 GetNumPacketsOutOfOrder(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumOutOfOrderPackets; }
UInt32 GetNumDuplicates(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumDuplicates; }
UInt32 GetNumAcks(UInt32 inTrackIndex)
{ return fStats[inTrackIndex].fNumAcks; }
UInt32 GetNumStreams()
{ return fSDPParser.GetNumStreams();}
UInt32 GetStreamDestPort(UInt32 inIndex)
{ return fStats[inIndex].fDestRTPPort;}
void TearDownNow() {fTeardownImmediately = true; this->Signal(Task::kKillEvent);}
//
// Global stats
static UInt32 GetActiveConnections() { return sActiveConnections; }
static UInt32 GetBroadcastingConnections() { return sBroadcastingConnections; }
static UInt32 GetConnectionAttempts() { return sTotalConnectionAttempts; }
char* GetNextPacket(UInt32 *packetLen, UInt8 *channel);
OS_Error SendPacket(char* data, UInt32 len,UInt8 channel);
OS_Error SendWaitingPackets();
enum
{
kUDPTransportType = 0,
kReliableUDPTransportType = 1,
kTCPTransportType = 2
};
typedef UInt32 TransportType;
TransportType GetTransportType() { return fTransportType; }
UInt32 GetPacketQLen() { return fPacketQueue.GetLength(); }
OSMutex* GetMutex() { return &fMutex; }
private:
enum
{
kRawRTSPControlType = 0,
kRTSPHTTPControlType = 1,
kRTSPHTTPDropPostControlType= 2
};
typedef UInt32 ControlType;
ClientSocket* fSocket; // Connection object
RTSPClient* fRTSPClient; // Manages the client connection
SDPSourceInfo fSDPParser; // Parses the SDP in the DESCRIBE response
TimeoutTask fTimeoutTask; // Kills this connection in the event the server isn't responding
ControlType fControlType;
TransportType fTransportType;
UInt32 fDurationInSec;
UInt32 fStartPlayTimeInSec;
UInt32 fRTCPIntervalInSec;
UInt32 fOptionsIntervalInSec;
UInt32 fState; // For managing the state machine
UInt32 fDeathState; // state at time of death
UInt32 fDeathReason;
UInt32 fNumSetups;
UDPSocket** fUDPSocketArray;
SInt64 fPlayTime;
SInt64 fTotalPlayTime;
SInt64 fLastRTCPTime;
Bool16 fTeardownImmediately;
Bool16 fAppendJunk;
UInt32 fReadInterval;
UInt32 fSockRcvBufSize;
Bool16 fBurst;
UInt32 fBurstTime;
//
// Broadcaster stats
struct TrackStats
{
enum
{
kSeqNumMapSize = 100,
kHalfSeqNumMap = 50
};
UInt16 fDestRTPPort;
UInt16 fDestRTCPPort;
UInt32 fNumPacketsReceived;
UInt32 fNumBytesReceived;
UInt32 fNumLostPackets;
UInt32 fNumOutOfOrderPackets;
UInt32 fNumThrownAwayPackets;
UInt8 fSequenceNumberMap[kSeqNumMapSize];
UInt16 fWrapSeqNum;
UInt16 fLastSeqNum;
UInt32 fSSRC;
Bool16 fIsSSRCValid;
UInt16 fHighestSeqNum;
UInt16 fLastAckedSeqNum;
Bool16 fHighestSeqNumValid;
UInt32 fNumAcks;
UInt32 fNumDuplicates;
};
TrackStats* fStats;
static char* fPacket;
//
// Global stats
static UInt32 sActiveConnections;
static UInt32 sBroadcastingConnections;
static UInt32 sTotalConnectionAttempts;
//
// Helper functions for Run()
void SetupUDPSockets();
void ProcessMediaPacket(char* inPacket, UInt32 inLength, UInt32 inTrackID, Bool16 isRTCP);
OS_Error ReadMediaData();
void SendReceiverReport();
void AckPackets(UInt32 inTrackIndex, UInt16 inCurSeqNum, Bool16 inCurSeqNumValid);
OSMutex fMutex;//this data structure is shared!
struct RTPPacket
{
RTPPacket() : fQueueElem(NULL), fData(NULL), fLen(0), fChannel(0),fCount(0){}
~RTPPacket() { fData = NULL; fLen = 0; fChannel = 0; }
void SetEnclosingObject(void *obj) {fQueueElem.SetEnclosingObject(obj);}
void SetPacketData(char* data, UInt32 len,UInt8 channel) { fData = data; fLen = len; fChannel = channel; }
OSQueueElem *GetQElement() {return &fQueueElem;}
OSQueueElem fQueueElem;
char* fData;
UInt32 fLen;
UInt8 fChannel;
UInt64 fCount;
};
UInt64 fPacketCount;
OSQueue fPacketQueue;
UInt32 fPacketLen;
UInt8 fChannel;
// char* fPacket;
};
#endif //__BROADCASTER_SESSION__

View file

@ -0,0 +1,165 @@
/*
*
* @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 "GetLocalIPAddressString.h"
#ifdef __MACOS__
#include "BogusDefs.h"
#else
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <unistd.h>
#include <string.h>
#if __solaris__ || __sgi__
#include <sys/sockio.h>
#include <stropts.h>
#endif
short GetLocalIPAddressString(char *returnStr, short maxSize)
{
short result = 0;
int err = -1;
char defaultAddress[] = "255.255.255.255";
char* addr = defaultAddress;
do
{
//Most of this code is similar to the SIOCGIFCONF code presented in Stevens,
//Unix Network Programming, section 16.6
//Use the SIOCGIFCONF ioctl call to iterate through the network interfaces
static const UInt32 kMaxAddrBufferSize = 2048;
char* ifReqIter = NULL;
struct ifconf ifc;
struct ifreq* ifr;
char buffer[kMaxAddrBufferSize];
int tempSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (tempSocket == -1) break;
ifc.ifc_len = kMaxAddrBufferSize;
ifc.ifc_buf = buffer;
#if (__linux__ || __MacOSX__ || __MACOS__ || __linuxppc__ || __solaris__ || __sgi__)
err = ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc);
#elif __FreeBSD__
err = ioctl(tempSocket, OSIOCGIFCONF, (char*)&ifc);
#else
#error
#endif
if (err == -1) break;
#if __FreeBSD__
{
int netdev1, netdev2;
struct ifreq *netdevifr;
netdevifr = ifc.ifc_req;
netdev1 = ifc.ifc_len / sizeof(struct ifreq);
for (netdev2=netdev1-1; netdev2>=0; netdev2--)
{
if (ioctl(tempSocket, SIOCGIFADDR, &netdevifr[netdev2]) != 0)
continue;
}
}
#endif
close(tempSocket);
tempSocket = -1;
// int numIPAddrs = 0;
for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);)
{
ifr = (struct ifreq*)ifReqIter;
#if __MacOSX__
ifReqIter += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
if (ifr->ifr_addr.sa_len == 0)
{
switch (ifr->ifr_addr.sa_family)
{
case AF_INET:
ifReqIter += sizeof(struct sockaddr_in);
break;
default:
ifReqIter += sizeof(struct sockaddr);
}
}
#else
ifReqIter += sizeof(ifr->ifr_name) + 0;
switch (ifr->ifr_addr.sa_family)
{
case AF_INET:
ifReqIter += sizeof(struct sockaddr_in);
break;
default:
ifReqIter += sizeof(struct sockaddr);
}
#endif
//Only count interfaces in the AF_INET family.
//And don't count localhost, loopback interfaces
if ((ifr->ifr_addr.sa_family == AF_INET) && (strncmp(ifr->ifr_name, "lo", 2) != 0))
{
struct sockaddr_in* addrPtr = (struct sockaddr_in*)&ifr->ifr_addr;
addr = inet_ntoa(addrPtr->sin_addr);
//qtss_printf("found local address: %s\n", addr);
err = 0;
break;
}
}
} while (0);
result = strlen(addr);
if (maxSize < result)
{ err = -1;
}
else
strcpy(returnStr, addr);
return err;
}

View file

@ -0,0 +1,44 @@
#ifndef __getlocalipaddressstring__
#define __getlocalipaddressstring__
/*
*
* @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@
*
*/
#ifdef __cplusplus
extern "C" {
#endif
short GetLocalIPAddressString(char *returnStr, short maxSize);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,118 @@
/*
*
* @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 <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include "NoRepeat.h"
NoRepeat::NoRepeat ( UInt32 numNoRepeats )
: PLDoubleLinkedList<SimplePlayListElement>()
{
mMaxElements = numNoRepeats;
}
NoRepeat::~NoRepeat()
{
// we have nothing to do, just let the PLDoubleLinkedList clear itself
}
bool NoRepeat::CompareNameToElement( PLDoubleLinkedListNode<SimplePlayListElement>* node, void* name )
{
if ( !::strcmp( node->fElement->mElementName, (const char*)name ) )
return true;
return false;
}
bool NoRepeat::IsInList( char* name )
{
PLDoubleLinkedListNode<SimplePlayListElement>* whichElement;
whichElement = ForEachUntil( CompareNameToElement, (void*)name );
if ( whichElement )
return true;
return false;
}
PLDoubleLinkedListNode<SimplePlayListElement>* NoRepeat::AddToList( PLDoubleLinkedListNode<SimplePlayListElement>* node )
{
AddNode(node);
PLDoubleLinkedListNode<SimplePlayListElement>* oldTail = NULL;
if ( fNumNodes > mMaxElements )
{ oldTail = fTail;
this->RemoveNode( fTail );
}
return oldTail;
}
bool NoRepeat::AddToList( char* name )
{
Assert( false );
bool addedSuccesfully = false;
if ( !this->IsInList( name ) )
{
SimplePlayListElement* element;
PLDoubleLinkedListNode<SimplePlayListElement>* node = NULL;
element = new SimplePlayListElement(name);
Assert( element );
if ( element )
node = new PLDoubleLinkedListNode<SimplePlayListElement>(element);
Assert( node );
if ( node )
{
PLDoubleLinkedListNode<SimplePlayListElement>* deadNode;
deadNode = this->AddToList(node);
delete deadNode;
addedSuccesfully = true;
}
}
return addedSuccesfully;
}

View file

@ -0,0 +1,52 @@
#ifndef __no_repeat__
#define __no_repeat__
/*
*
* @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 "PLDoubleLinkedList.h"
#include "SimplePlayListElement.h"
#include "OSHeaders.h"
class NoRepeat : public PLDoubleLinkedList<SimplePlayListElement> {
public:
NoRepeat( UInt32 numNoRepeats );
virtual ~NoRepeat();
bool IsInList( char* name ); // return true if name is in list, false if not
bool AddToList( char* name );// return true if could be added to list, no dupes allowd
PLDoubleLinkedListNode<SimplePlayListElement>* AddToList( PLDoubleLinkedListNode<SimplePlayListElement>* node );
protected:
static bool CompareNameToElement( PLDoubleLinkedListNode<SimplePlayListElement>*node, void *name );
UInt32 mMaxElements;
};
#endif

View file

@ -0,0 +1,630 @@
/*
*
* @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@
*
*/
/*
8.2.99 - rt updated ShowSettings() to display user names for fields instead of C++ member names.
*/
#include "PLBroadcastDef.h"
#include "MyAssert.h"
#include "SocketUtils.h"
#include "ConfParser.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#ifndef __Win32__
#include <netdb.h>
#endif
#include "BroadcasterSession.h"
Bool16 PLBroadcastDef::ConfigSetter( const char* paramName, const char* paramValue[], void* userData )
{
// return true if set fails
PLBroadcastDef* broadcastParms = (PLBroadcastDef*)userData;
if (!::strcmp( "destination_ip_address", paramName) )
{
broadcastParms->SetValue( &broadcastParms->mOrigDestAddress, paramValue[0] );
if (broadcastParms->mIgnoreFileIP)
return false;
else
return broadcastParms->SetValue( &broadcastParms->mDestAddress, paramValue[0] );
}
else if (!::strcmp( "destination_base_port", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mBasePort, paramValue[0] );
}
else if (!::strcmp( "max_upcoming_list_size", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mMaxUpcomingMovieListSize, paramValue[0] );
}
else if (!::strcmp( "play_mode", paramName) )
{
if ( ::strcmp( "sequential", paramValue[0])
&& ::strcmp( "sequential_looped", paramValue[0])
&& ::strcmp( "weighted_random", paramValue[0])
)
return true;
return broadcastParms->SetValue( &broadcastParms->mPlayMode, paramValue[0] );
}
/*
rt- rremoved for buld 12
else if (!::strcmp( "limit_play", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mLimitPlay, paramValue[0] );
}
*/
// changed at bulid 12 else if (!::strcmp( "repeats_queue_size", paramName) )
else if (!::strcmp( "recent_movies_list_size", paramName) )
{
if ( ::atoi( paramValue[0] ) < 0 )
return true;
broadcastParms->mLimitPlayQueueLength = atoi(paramValue[0]);
return false;
}
else if (!::strcmp( "playlist_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mPlayListFile, paramValue[0] );
}
else if (!::strcmp( "sdp_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mSDPFile, paramValue[0] );
}
else if (!::strcmp( "destination_sdp_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mDestSDPFile, paramValue[0] );
}
else if (!::strcmp( "logging", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mLogging, paramValue[0] );
}
else if (!::strcmp( "log_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mLogFile, paramValue[0] );
}
else if (!::strcmp( "sdp_reference_movie", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mSDPReferenceMovie, paramValue[0] );
}
else if (!::strcmp( "show_current", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mShowCurrent, paramValue[0] );
}
else if (!::strcmp( "show_upcoming", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mShowUpcoming, paramValue[0] );
}
else if (!::strcmp( "broadcast_start_time", paramName) )
{
const char* theValue = paramValue[0];
if ('*' == theValue[0])
{
UInt32 startTime = time(NULL) + 2208988800LU + (time_t) ::strtol(&theValue[1], NULL, 10);
char startTimeStr[20] = "";
qtss_sprintf(startTimeStr,"%"_U32BITARG_"", startTime); // current time
return broadcastParms->SetValue( &broadcastParms->mStartTime, startTimeStr );
}
return broadcastParms->SetValue( &broadcastParms->mStartTime, paramValue[0] );
}
else if (!::strcmp( "broadcast_end_time", paramName) )
{
UInt32 endTime = 0;
const char* theValue = paramValue[0];
if ('*' == theValue[0])
endTime = time(NULL) + 2208988800LU + (SInt32) ::strtol(&theValue[1], NULL, 10);
else
endTime = ::strtoul(theValue, NULL, 10);
if ( (endTime > 0) && endTime < 2208988800LU) // not a valid time
return true;
char endTimeStr[20] = "";
qtss_sprintf(endTimeStr,"%"_U32BITARG_"", endTime); // current time + offset time
return broadcastParms->SetValue( &broadcastParms->mEndTime, endTimeStr );
}
else if (!::strcmp( "broadcast_SDP_is_dynamic", paramName) )
{
if ( ::strcmp( "enabled", paramValue[0]) && ::strcmp( "disabled", paramValue[0]) )
return true;
return broadcastParms->SetValue( &broadcastParms->mIsDynamic, paramValue[0] );
}
else if (!::strcmp( "broadcaster_name", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mName, paramValue[0] );
}
else if (!::strcmp( "broadcaster_password", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mPassword, paramValue[0] );
}
else if (!::strcmp( "multicast_ttl", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mTTL, paramValue[0] );
}
else if (!::strcmp( "rtsp_port", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mRTSPPort, paramValue[0] );
}
else if (!::strcmp( "pid_file", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mPIDFile, paramValue[0] );
}
else if (!::strcmp( "client_buffer_delay", paramName) )
{
return broadcastParms->SetValue( &broadcastParms->mClientBufferDelay, paramValue[0] );
}
else if (!::strcmp( "max_err_file_k_size", paramName) )
{
if ( !paramValue[0] || !strlen(paramValue[0]) )
return true;
UInt32 setvalue = kSInt32_Max;
int maxValue = ::atoi( paramValue[0] );
if (maxValue >= 0)
setvalue = (UInt32) maxValue;
qtss_setmaxprintfcharsinK( (UInt32) setvalue);
return false;
}
return true;
}
Bool16 PLBroadcastDef::SetValue( char** dest, const char* value)
{
Bool16 didFail = false;
// if same param occurs more than once in file, delete
// initial occurance and override with second.
if ( *dest )
delete [] *dest;
*dest = new char[ strlen(value) + 1 ];
Assert( *dest );
if ( *dest )
::strcpy( *dest, value );
else
didFail = true;
return didFail;
}
Bool16 PLBroadcastDef::SetDefaults( const char* setupFileName )
{
Bool16 didFail = false;
if (mDestAddress != NULL)
mIgnoreFileIP = true;
if ( !didFail && !mIgnoreFileIP)
didFail = this->SetValue( &mDestAddress, SocketUtils::GetIPAddrStr(0)->Ptr );
if ( !didFail )
didFail = this->SetValue( &mBasePort, "5004" );
if ( !didFail )
didFail = this->SetValue( &mPlayMode, "sequential_looped" );
if ( !didFail )
didFail = this->SetValue( &mMaxUpcomingMovieListSize, "7" );
if ( !didFail )
didFail = this->SetValue( &mLogging, "enabled" );
if ( !didFail )
didFail = this->SetValue( &mRTSPPort, "554" );
char nameBuff[kBufferLen];
int maxNameLen = kMaxBufferStringLen; //maxNameLen = 492
nameBuff[ sizeof(nameBuff) -1] = 0; //term buffer
::strncpy( nameBuff, "broadcast" , maxNameLen);
if (setupFileName)
::strncpy( nameBuff, setupFileName , maxNameLen);
nameBuff[maxNameLen] = '\0'; //zero term the name
int baseLen = ::strlen(nameBuff); //maxNameLen max
//add .log to the base name of the description file with the .ext stripped
char *ext = NULL;
ext = ::strrchr( nameBuff, '.' );
if ( ext )
{
*ext = 0;
baseLen = ::strlen(nameBuff);
}
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".log",sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mLogFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".ply" ,sizeof(nameBuff) - strlen(nameBuff) - 1);
if ( !didFail )
didFail = this->SetValue( &mPlayListFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".sdp" ,sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mSDPFile, nameBuff );
if ( !didFail )
didFail = this->SetValue( &mDestSDPFile, "no_name" );
/* current, upcoming, and replacelist created by emil@popwire.com */
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".current" ,sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mCurrentFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".upcoming" ,sizeof(nameBuff) - strlen(nameBuff) - 1);
if ( !didFail )
didFail = this->SetValue( &mUpcomingFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".replacelist" ,sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mReplaceFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".stoplist" ,sizeof(nameBuff) - strlen(nameBuff) - 1);
if ( !didFail )
didFail = this->SetValue( &mStopFile, nameBuff );
nameBuff[baseLen] = 0;
::strncat( nameBuff, ".insertlist" ,sizeof(nameBuff) - strlen(nameBuff) - 1 );
if ( !didFail )
didFail = this->SetValue( &mInsertFile, nameBuff );
if ( !didFail )
didFail = this->SetValue( &mShowCurrent, "enabled" );
if ( !didFail )
didFail = this->SetValue( &mShowUpcoming, "enabled" );
if ( !didFail )
didFail = this->SetValue( &mStartTime, "0" );
if ( !didFail )
didFail = this->SetValue( &mEndTime, "0" );
if ( !didFail )
didFail = this->SetValue( &mIsDynamic, "disabled" );
if ( !didFail )
didFail = this->SetValue( &mName, "" );
if ( !didFail )
didFail = this->SetValue( &mPassword, "" );
if ( !didFail )
didFail = this->SetValue( &mTTL, "1" );
if ( !didFail )
didFail = this->SetValue( &mClientBufferDelay, "0" );
//see if there is a defaults File.
//if there is one load it and over-ride the other defaults
if (NULL != setupFileName)
{
int len = ::strlen(setupFileName) + 10;
char *defaultFileName = new char[len];
qtss_snprintf(defaultFileName, len, "%s%s", setupFileName, ".def");
(void) ::ParseConfigFile( false, defaultFileName, ConfigSetter, this ); //ignore if no defaults file
delete [] defaultFileName;
}
/* ***************************************************** */
return didFail;
}
PLBroadcastDef::PLBroadcastDef( const char* setupFileName, char *destinationIP, Bool16 debug )
: mDestAddress(destinationIP)
, mOrigDestAddress(NULL)
, mBasePort(NULL)
, mPlayMode(NULL)
// removed at build 12 , mLimitPlay(NULL)
, mLimitPlayQueueLength(0)
, mPlayListFile(NULL)
, mSDPFile(NULL)
, mLogging(NULL)
, mLogFile(NULL)
, mSDPReferenceMovie( NULL )
, mCurrentFile( NULL )
, mUpcomingFile( NULL )
, mReplaceFile( NULL )
, mStopFile( NULL )
, mInsertFile( NULL )
, mShowCurrent( NULL )
, mShowUpcoming( NULL )
, mTheSession( NULL )
, mIgnoreFileIP(false)
, mMaxUpcomingMovieListSize(NULL)
, mDestSDPFile(NULL)
, mStartTime(NULL)
, mEndTime(NULL)
, mIsDynamic(NULL)
, mName( NULL)
, mPassword( NULL)
, mTTL(NULL)
, mRTSPPort(NULL)
, mPIDFile(NULL)
, mClientBufferDelay(NULL)
, mParamsAreValid(false)
, mInvalidParamFlags(kInvalidNone)
{
if (!setupFileName && !destinationIP)
{ this->SetDefaults( NULL );
qtss_printf( "default settings\n" );
this->ShowSettings();
return;
}
fDebug = debug;
if (destinationIP != NULL) //we were given an IP to use
mIgnoreFileIP = true;
Assert( setupFileName );
if (setupFileName )
{
int err = -1;
if ( !this->SetDefaults( setupFileName ) )
{ err = ::ParseConfigFile( false, setupFileName, ConfigSetter, this );
}
if ( !err )
{ mParamsAreValid = true;
}
ValidateSettings();
}
}
void PLBroadcastDef::ValidateSettings()
{
// For now it just validates the destination ip address
UInt32 inAddr = 0;
inAddr = SocketUtils::ConvertStringToAddr(mDestAddress);
if(inAddr == INADDR_NONE)
{
struct hostent* theHostent = ::gethostbyname(mDestAddress);
if (theHostent != NULL)
{
inAddr = ntohl(*(UInt32*)(theHostent->h_addr_list[0]));
struct in_addr inAddrStruct;
char buffer[50];
StrPtrLen temp(buffer);
inAddrStruct.s_addr = *(UInt32*)(theHostent->h_addr_list[0]);
SocketUtils::ConvertAddrToString(inAddrStruct, &temp);
SetValue( &mDestAddress, buffer );
}
}
if(inAddr == INADDR_NONE)
mInvalidParamFlags |= kInvalidDestAddress;
// If mInvalidParamFlags is set, set mParamsAreValid to false
if ( mInvalidParamFlags | kInvalidNone )
mParamsAreValid = false;
}
void PLBroadcastDef::ShowErrorParams()
{
if( mInvalidParamFlags & kInvalidDestAddress )
qtss_printf( "destination_ip_address \"%s\" is Invalid\n", mOrigDestAddress );
}
void PLBroadcastDef::ShowSettings()
{
qtss_printf( "\n" );
qtss_printf( "Description File Settings\n" );
qtss_printf( "----------------------------\n" );
qtss_printf( "destination_ip_address %s\n", mOrigDestAddress );
qtss_printf( "destination_sdp_file %s\n", mDestSDPFile );
qtss_printf( "destination_base_port %s\n", mBasePort );
qtss_printf( "play_mode %s\n", mPlayMode );
qtss_printf( "recent_movies_list_size %d\n", mLimitPlayQueueLength );
qtss_printf( "playlist_file %s\n", mPlayListFile );
qtss_printf( "logging %s\n", mLogging );
qtss_printf( "log_file %s\n", mLogFile );
if (mSDPReferenceMovie != NULL)
qtss_printf( "sdp_reference_movie %s\n", mSDPReferenceMovie );
qtss_printf( "sdp_file %s\n", mSDPFile );
qtss_printf( "max_upcoming_list_size %s\n", mMaxUpcomingMovieListSize );
qtss_printf( "show_current %s\n", mShowCurrent );
qtss_printf( "show_upcoming %s\n", mShowUpcoming );
qtss_printf( "broadcaster_name \"%s\"\n", mName);
qtss_printf( "broadcaster_password \"XXXXX\"\n");
qtss_printf( "multicast_ttl %s\n",mTTL);
qtss_printf( "rtsp_port %s\n",mRTSPPort);
Float32 bufferDelay = 0.0;
::sscanf(mClientBufferDelay, "%f", &bufferDelay);
if (bufferDelay != 0.0)
qtss_printf( "client_buffer_delay %.2f\n",bufferDelay);
else
qtss_printf( "client_buffer_delay default\n");
if (mPIDFile != NULL)
qtss_printf( "pid_file %s\n",mPIDFile);
qtss_printf( "broadcast_SDP_is_dynamic %s\n", mIsDynamic );
UInt32 startTime = (UInt32) ::strtoul(mStartTime, NULL, 10);
if ( startTime > 2208988800LU)
{
qtss_printf( "broadcast_start_time %s (NTP seconds)\n",mStartTime);
startTime -= 2208988800LU; //1970 - 1900 secs
qtss_printf( "-->broadcast_start_time = %"_U32BITARG_" (unix seconds)\n",startTime);
time_t tmpTime;
tmpTime = (time_t) startTime;
struct tm timeResult;
struct tm *localTM = qtss_localtime(&tmpTime, &timeResult);
char timeBuffer[kTimeStrSize];
char *theTime = qtss_asctime(localTM,timeBuffer, sizeof(timeBuffer));
if (theTime[0] != 0)
theTime[::strlen(theTime) -1] = 0;
qtss_printf( "-->broadcast_start_time = %s (local time)\n",theTime);
tmpTime = (time_t) startTime;
struct tm *gmTM = qtss_gmtime(&tmpTime, &timeResult);
theTime = qtss_asctime(gmTM, timeBuffer, sizeof(timeBuffer));
if (theTime[0] != 0)
theTime[::strlen(theTime) -1] = 0;
qtss_printf( "-->broadcast_start_time = %s (UTC/GM time)\n",theTime);
}
else if (0 == startTime)
qtss_printf( "broadcast_start_time 0 (allow all)\n");
else
qtss_printf( "broadcast_start_time %s (NTPseconds allow all)\n", mStartTime);
UInt32 endTime = strtoul(mEndTime, NULL, 10);
if (endTime > 2208988800LU)
{
qtss_printf( "broadcast_end_time %s (NTP seconds)\n",mEndTime);
endTime -= 2208988800LU;//convert to 1970 secs
qtss_printf( "-->broadcast_end_time = %"_U32BITARG_" (unix seconds)\n",endTime);
time_t tmpTime = (time_t) endTime;
struct tm timeResult;
struct tm *localTM = qtss_localtime(&tmpTime, &timeResult);
char timeBuffer[kTimeStrSize];
char *theTime = qtss_asctime(localTM,timeBuffer, sizeof(timeBuffer));
if (theTime[0] != 0)
theTime[::strlen(theTime) -1] = 0;
qtss_printf( "-->broadcast_end_time = %s (local time)\n",theTime);
tmpTime = (time_t) endTime;
struct tm *gmTM = qtss_gmtime(&tmpTime, &timeResult);
theTime = qtss_asctime(gmTM, timeBuffer, sizeof(timeBuffer));
if (theTime[0] != 0)
theTime[::strlen(theTime) -1] = 0;
qtss_printf( "-->broadcast_end_time = %s (UTC/GM time)\n",theTime);
}
else if (0 == endTime)
qtss_printf( "broadcast_end_time 0 (unbounded)\n");
else
qtss_printf( "broadcast_end_time 1900 + %s seconds (looks invalid)\n", mEndTime);
qtss_printf( "max_err_file_k_size %"_U32BITARG_"\n", qtss_getmaxprintfcharsinK());
qtss_printf( "============================\n" );
}
PLBroadcastDef::~PLBroadcastDef()
{
delete [] mDestAddress;
delete [] mOrigDestAddress;
delete [] mBasePort;
delete [] mPlayMode;
// removed at build 12 delete [] mLimitPlay;
delete [] mPlayListFile;
delete [] mSDPFile;
delete [] mLogging;
delete [] mLogFile;
if (mSDPReferenceMovie != NULL)
delete [] mSDPReferenceMovie;
delete [] mMaxUpcomingMovieListSize;
delete [] mTTL;
delete [] mName;
delete [] mShowUpcoming;
delete [] mShowCurrent;
delete [] mPassword;
delete [] mIsDynamic;
delete [] mStartTime;
delete [] mEndTime;
}

View file

@ -0,0 +1,129 @@
#ifndef __PLBroadcastDef__
#define __PLBroadcastDef__
/*
*
* @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@
*
*/
/*
#example (1) A FULL 1.0 DECLARED FILE
#Lines beginning with "#" characters are comments
#The order of the following entries is unimportant
#Quotes are optional for values
destination_ip_address 225.225.225.225
destination_base_port 5004
play_mode [sequential, sequential_looped, weighted]
limit_play enabled
limit_seq_length 10
play_list_file /path/file
sdp_file /path/file
log_file /path/file
*/
#include "OSHeaders.h"
#include "BroadcasterSession.h"
class PLBroadcastDef {
public:
PLBroadcastDef( const char* setupFileName, char *destinationIP, Bool16 debug );
virtual ~PLBroadcastDef();
Bool16 ParamsAreValid() { return mParamsAreValid; }
void ValidateSettings();
void ShowErrorParams();
void ShowSettings();
static Bool16 ConfigSetter( const char* paramName, const char* paramValue[], void * userData );
// * == default value, <r> required input
char* mDestAddress; // set by PLB to be resolved address
char* mOrigDestAddress; // [0.0.0.0 | domain name?] *127.0.0.1 ( self )
char* mBasePort; // [ 0...32k?] *5004
char* mPlayMode; // [sequential | *sequential_looped | weighted]
// removed at build 12 char* mLimitPlay; // [*enabled | disabled]
int mLimitPlayQueueLength; // [ 0...32k?] *20
//char* mLimitPlayQueueLength; // [ 0...32k?] *20
char* mPlayListFile; // [os file path] *<PLBroadcastDef-name>.ply
char* mSDPFile; // [os file path] <r>
char* mLogging; // [*enabled | disabled]
char* mLogFile; // [os file path] *<PLBroadcastDef-name>.log
char* mSDPReferenceMovie; // [os file path]
char* mCurrentFile; // [os file path] *<PLBroadcastDef-name>.current
char* mUpcomingFile; // [os file path] *<PLBroadcastDef-name>.upcoming
char* mReplaceFile; // [os file path] *<PLBroadcastDef-name>.replacelist
char* mStopFile; // [os file path] *<PLBroadcastDef-name>.stoplist
char* mInsertFile; // [os file path] *<PLBroadcastDef-name>.insertlist
char* mShowCurrent; // [*enabled | disabled]
char* mShowUpcoming; // [*enabled | disabled]
BroadcasterSession *mTheSession;// a broadcaster RTSP/RTP session with the server.
bool mIgnoreFileIP;
char* mMaxUpcomingMovieListSize; // [ 2^31] *7
char* mDestSDPFile; // [movies folder relative file path]
char* mStartTime; // NTP start time
char* mEndTime; // NTP end time
char* mIsDynamic; // true
char* mName; // Authentication name
char* mPassword; // Authentication password
char * mTTL; // TTL for multicast [1..15] *1
char * mRTSPPort;
char * mPIDFile;
char * mClientBufferDelay; // sdp option a=x-bufferdelay: float
enum {
kInvalidNone = 0x00000000,
kInvalidDestAddress = 0x00000001,
kBufferLen = 512,
kExtensionLen = 20,
kMaxBufferStringLen = kBufferLen - kExtensionLen
};
protected:
Bool16 mParamsAreValid;
UInt32 mInvalidParamFlags;
Bool16 SetValue( char** dest, const char* value);
Bool16 SetDefaults( const char* setupFileName );
Bool16 fDebug;
};
#endif

View file

@ -0,0 +1,483 @@
/*
*
* @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 "PickerFromFile.h"
#include <stdlib.h>
#include "GetWord.h"
#include "Trim.h"
#include "MyAssert.h"
#include <sys/stat.h>
#ifndef __Win32__
#include <dirent.h>
#endif
#ifdef __hpux__
#include <sys/types.h>
#endif
#define kMaxPickerPath 512
#include <stdio.h>
static bool CompareNameToElement( PLDoubleLinkedListNode<LoopDetectionListElement>* node, void* name );
static void DisplayPickerErr( int pickErr, const char *message, const char*fname, int lineCount, const char*lineBuff );
static bool CompareNameToElement( PLDoubleLinkedListNode<LoopDetectionListElement>* node, void* name )
{
if ( !::strcmp( node->fElement->mPathName, (const char*)name ) )
return true;
return false;
}
static bool IsDir(char* path);
static bool IsDir(char* path)
{
struct stat data;
int err = stat(path, &data);
if (err == -1)
return false;
return ((data.st_mode & S_IFDIR) == S_IFDIR );
}
static void DisplayPickerErr( int pickErr, const char *message, const char*fname, int lineCount, const char*lineBuff )
{
char *errMessage;
qtss_printf( "- %s:\n", message );
if ( lineCount )
qtss_printf( " Playlist: %s, line# %i\n", fname, lineCount );
else
qtss_printf( " Playlist: %s\n", fname );
if ( lineBuff )
qtss_printf( " Playlist text: %s", lineBuff ); // lineBuff already includes a \n
switch ( pickErr )
{
case kPickerPopulateLoopDetected:
errMessage = "Include would create a loop.\n";
break;
case kPickerPopulateBadFormat:
errMessage = "Playlist file is missing *PLAY-LIST* identifier.\n";
break;
case kPickerPopulateFileError:
errMessage = "Playlist file could not be opened.\n";
break;
case kPickerPopulateNoMem:
default:
errMessage = "Internal error occurred.\n";
break;
}
qtss_printf( " Reason: %s\n", errMessage);
}
bool PathIsAbsolute(char *pathPtr)
{
bool result = false;
#ifdef __Win32__
if ( (pathPtr[1] == ':') && ( pathPtr[2] == kPathDelimiterChar ) )
result = true;
#else
if ( *pathPtr == kPathDelimiterChar )
result = true;
#endif
return result;
}
int PopulatePickerFromFile( PlaylistPicker* picker, char* fname, const char* basePath, LoopDetectionList *ldList )
{
Assert( picker );
Assert( fname );
FILE* weightings = NULL;
LoopDetectionListElement* ldElement = NULL;
LoopDetectionNode* ldNode = NULL;
int lineCount = 0;
int pickErr = kPickerPopulateNoErr;
char path[kMaxPickerPath];
#if kPartialPathBeginsWithDelimiter
if (PathIsAbsolute(fname))
{
if ( *basePath )
fname++;
#else
if ( !PathIsAbsolute(fname) )
{
#endif
// it's a partial path, expand it to include all
// previously traversed paths
::strncpy( path, basePath, kMaxPickerPath-1 );
::strncat( path, fname, kMaxPickerPath-1 );
}
else
{
// it's an absolute reference. use the path
// part of this for the new basePath
::strncpy( path, fname, kMaxPickerPath-1 );
}
// path is now either an absolute or working directory
// referenced partial path to the playlist file.
int len = strlen(path);
char lastChar = path[len-1];
if (lastChar == '\n' || lastChar == '\r' || lastChar == ' ')
path[len-1] = '\0';
// ldList is passed as NULL by the initial caller. recursive calls
// pass along the ldList we create hre
if ( ldList == NULL )
ldList = new LoopDetectionList;
Assert( ldList );
if ( !ldList )
pickErr = kPickerPopulateNoMem;
if ( !pickErr )
{
if ( ldList->ForEachUntil( CompareNameToElement, path ) )
{
// we're already in the include chain, this is a loop
// print a warning (error?) and continue past the loop.
//qtss_printf("- Playlists include loop at file: %s\n", path );
pickErr = kPickerPopulateLoopDetected;
}
}
if ( !pickErr )
{
ldElement = new LoopDetectionListElement( path );
Assert( ldElement );
if ( ldElement )
{ ldNode = new LoopDetectionNode( ldElement );
Assert( ldNode );
if ( !ldNode )
pickErr = kPickerPopulateNoMem;
}
else
pickErr = kPickerPopulateNoMem;
}
if (::IsDir(path))
return ::PopulatePickerFromDir(picker, path);
if ( !pickErr )
{
weightings = ::fopen( path, "r" );
if (!weightings)
{
qtss_printf("- Playlist picker failed opening list file %s\n", path);
pickErr = kPickerPopulateFileError;
}
}
if ( !pickErr )
{
SInt32 lineBuffSize = (kMaxPickerPath *2) - 1;
SInt32 wordBuffSize = kMaxPickerPath - 1;
char lineBuff[kMaxPickerPath * 2];
char wordBuff[kMaxPickerPath];
char* next;
char* pathEnd;
char* thisLine;
// add ourselves to the list
ldList->AddNode( ldNode );
// trim off the file name to get just the path part
pathEnd = ::strrchr( path, kPathDelimiterChar );
if ( pathEnd )
{
pathEnd++;
*pathEnd = 0;
}
else
*path = 0;
thisLine = lineBuff;
if ( ::fgets( lineBuff, lineBuffSize, weightings ) != NULL )
{
lineCount++;
thisLine = ::TrimLeft( lineBuff );
if ( 0 != ::strncmp(thisLine,"*PLAY-LIST*",11) )
{
//qtss_printf("- Playlist file missing *PLAY-LIST* identifier as first line:\n");
//qtss_printf(" %s%s\n", basePath, fname);
pickErr = kPickerPopulateBadFormat;
}
}
if ( !pickErr )
{
do
{
next = lineBuff;
if ( ::fgets( lineBuff, lineBuffSize, weightings ) == NULL )
break;
// qtss_printf("line = %s\n", lineBuff);
lineCount++;
next = ::TrimLeft( lineBuff );
if ( *next == '#' )
{
// it's a comment - just toss
//if ( *next )
// qtss_printf( "comment: %s" , &lineBuff[1] );
}
else if (*next == '+') // a list
{
next = ::TrimLeft( next+1 ); // skip past + include
if ( *next == '"' ) // get the name from the next part of the buff
next = ::GetQuotedWord( wordBuff, next, wordBuffSize );
else
next = ::GetWord( wordBuff, next, wordBuffSize );
// recusively populate from the include file.
pickErr = PopulatePickerFromFile( picker, wordBuff, path, ldList );
if ( pickErr )
{
DisplayPickerErr( pickErr, "Playlist Include failed", fname, lineCount, lineBuff );
pickErr = kPickerPopulateNoErr;
}
}
else if ( *next )
{
char numBuff[32];
char expandedFileName[kMaxPickerPath];
int weight = 10; // default weight is 10
// get the movie file name
if ( *next == '"' )
next = ::GetQuotedWord( wordBuff, next, wordBuffSize );
else
next = ::GetWord( wordBuff, next, wordBuffSize );
if (*wordBuff)
{
#if kPartialPathBeginsWithDelimiter
if ( PathIsAbsolute(wordBuff) )
{
char *wordStart = wordBuff;
if ( *path )
wordStart++;
// full or partial path to the movie
::strcpy( expandedFileName, path );
::strcat( expandedFileName, wordStart );
}
#else
if ( !PathIsAbsolute(wordBuff) )
{
// it's a partial path..
// cat the path and fname to form the
// full or partial path to the movie
::strcpy( expandedFileName, path );
::strcat( expandedFileName, wordBuff );
}
#endif
else
{ // it's an absolute path..
::strcpy( expandedFileName, wordBuff );
}
// then get the weighting ( if supplied )
next = ::GetWord( numBuff, next, 32 );
if ( *numBuff )
weight = ::atoi(numBuff);
// qtss_printf("expanded file name = %s\n", expandedFileName);
if (::IsDir(expandedFileName))
pickErr = ::PopulatePickerFromDir(picker, expandedFileName, weight);
else if ( !picker->AddToList( expandedFileName, weight ) )
pickErr = kPickerPopulateNoMem;
}
}
} while ( feof( weightings ) == 0 && pickErr == kPickerPopulateNoErr );
}
// remove ourselves from the list
ldList->RemoveNode( ldNode );
}
// only report unreported errors.
if ( ldList && ldList->GetNumNodes() == 0 && pickErr )
::DisplayPickerErr( pickErr, "Playlist error", fname, lineCount, NULL );
if ( ldNode )
delete ldNode; // node deletes element
else if ( ldElement )
delete ldElement;
if ( weightings )
(void)::fclose( weightings );
if ( ldList && ldList->GetNumNodes() == 0 )
{
// all done now!
delete ldList;
ldList = NULL;
}
return pickErr;
}
int PopulatePickerFromDir( PlaylistPicker* picker, char* dirPath, int weight )
{
static char expandedFileName[kMaxPickerPath]; // static so we don't build up the stack frame on recursion
int pickErr = 0;
if (dirPath != NULL)
strcpy(expandedFileName, dirPath);
#ifdef __Win32__
WIN32_FIND_DATA findData;
HANDLE findResultHandle;
Bool16 keepSearching = true;
int len = strlen(expandedFileName);
if (expandedFileName[len - 1] != kPathDelimiterChar)
{
expandedFileName[len] = kPathDelimiterChar;
expandedFileName[len+1] = 0;
len++;
}
strcat(expandedFileName, "*");
findResultHandle = ::FindFirstFile( expandedFileName, &findData);
if ( NULL == findResultHandle || INVALID_HANDLE_VALUE == findResultHandle )
{
//qtss_printf( "FindFirstFile( \"%s\" ): gle = %"_U32BITARG_"\n", searchPath, GetLastError() );
return 0;
}
while ( (pickErr == 0) && keepSearching )
{
expandedFileName[len] = 0; // retruncate name
if (findData.cFileName[0] != '.') // ignore anything beginning with a "."
{
strcat(expandedFileName, findData.cFileName);
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
pickErr = PopulatePickerFromDir(picker, NULL, weight);
else if ( !picker->AddToList( expandedFileName, weight ) )
pickErr = kPickerPopulateNoMem;
}
keepSearching = FindNextFile( findResultHandle, &findData );
}
#else
DIR* dir;
struct dirent* entry;
int len = strlen(expandedFileName);
if (expandedFileName[len - 1] != kPathDelimiterChar)
{
expandedFileName[len] = kPathDelimiterChar;
expandedFileName[len+1] = 0;
len++;
}
dir = opendir(expandedFileName);
if (dir == NULL)
return kPickerPopulateFileError;
do {
entry = readdir(dir);
if (entry == NULL) break;
if (entry->d_name[0] == '.') // ignore anything beginning with a "."
continue;
if (len + strlen(entry->d_name) < kMaxPickerPath)
{
strcat(expandedFileName, entry->d_name);
#if __solaris__ || __sgi__ || __osf__ || __hpux__
if (::IsDir(expandedFileName))
#else
if ((entry->d_type & DT_DIR) != 0)
#endif
pickErr = PopulatePickerFromDir(picker, NULL, weight);
else if ( !picker->AddToList( expandedFileName, weight ) )
pickErr = kPickerPopulateNoMem;
}
expandedFileName[len] = 0; // retruncate name
} while (pickErr == 0);
//close the directory back up
(void)::closedir(dir);
#endif
return pickErr;
}

View file

@ -0,0 +1,77 @@
#ifndef __picker_from_file__
#define __picker_from_file__
/*
*
* @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 "PlaylistPicker.h"
#include "PLDoubleLinkedList.h"
#include <string.h>
class LoopDetectionListElement {
public:
LoopDetectionListElement( const char * name )
{
mPathName = new char[ strlen(name) + 1 ];
Assert( mPathName );
if( mPathName )
::strcpy( mPathName, name );
}
virtual ~LoopDetectionListElement()
{
if ( mPathName )
delete [] mPathName;
}
char *mPathName;
};
typedef PLDoubleLinkedList<LoopDetectionListElement> LoopDetectionList;
typedef PLDoubleLinkedListNode<LoopDetectionListElement> LoopDetectionNode;
enum PickerPopulationErrors {
kPickerPopulateLoopDetected = 1000
, kPickerPopulateBadFormat
, kPickerPopulateFileError
, kPickerPopulateNoMem
, kPickerPopulateNoErr = 0
};
int PopulatePickerFromFile( PlaylistPicker* picker, char* fname, const char* basePath, LoopDetectionList *ldList );
int PopulatePickerFromDir( PlaylistPicker* picker, char* dirPath, int weight = 10 );
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,430 @@
/*
*
* @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 <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <stdio.h>
#include "MyAssert.h"
#include "OS.h"
#include "PlaylistPicker.h"
/*
PlaylistPicker has 3 modes
- sequential looping through the items in the play list(s)
in the order they are entered.
- above w/ looping
- weighted picking "randomly" from weighted buckets
*/
PlaylistPicker::PlaylistPicker( UInt32 numBuckets, UInt32 numNoRepeats )
{
// weighted random ctor
mFirstElement = NULL;
mNumToPickFrom = 0;
mBuckets = numBuckets;
mIsSequentialPicker = false;
mRecentMoviesListSize = numNoRepeats;
/* changed by emil@popwire.com (see relaod.txt for info) */
mRemoveFlag = false;
mStopFlag = false;
/* ***************************************************** */
mLastResult = (UInt32) OS::Milliseconds();
mPickCounts = new SInt32[numBuckets];
UInt32 x;
for ( x = 0; x < mBuckets; x++ )
{ mPickCounts[x] = 0;
mElementLists[x] = new PLDoubleLinkedList<SimplePlayListElement>;
Assert( mElementLists[x] );
}
mUsedElements = new NoRepeat( numNoRepeats );
Assert( mUsedElements );
}
PlaylistPicker::PlaylistPicker(bool doLoop)
{
// sequential ctor
mFirstElement = NULL;
mIsSequentialLooping = doLoop;
mIsSequentialPicker = true;
mWhichSequentialBucket = 0;
mRecentMoviesListSize = 0;
mNumToPickFrom = 0;
mBuckets = 2; // alternating used/remaining pick buckets
/* changed by emil@popwire.com (see relaod.txt for info) */
mRemoveFlag = false;
mStopFlag = false;
fLastPick = NULL;
/* ***************************************************** */
mPickCounts = new SInt32[mBuckets];
UInt32 bucketIndex;
for ( bucketIndex = 0; bucketIndex < mBuckets; bucketIndex++ )
{
mPickCounts[bucketIndex] = 0;
mElementLists[bucketIndex] = new PLDoubleLinkedList<SimplePlayListElement>;
Assert( mElementLists[bucketIndex] );
}
mUsedElements = NULL;
}
PlaylistPicker::~PlaylistPicker()
{
UInt32 bucketIndex;
delete mUsedElements;
for ( bucketIndex = 0; bucketIndex < mBuckets; bucketIndex++ )
{
delete mElementLists[bucketIndex] ;
}
delete [] mPickCounts;
}
UInt32 PlaylistPicker::Random()
{
UInt32 seed = 1664525L * mLastResult + 1013904223L; //1013904223 is prime .. Knuth D.E.
::srand( seed );
UInt32 result = ::rand();
mLastResult = result;
return result;
}
char* PlaylistPicker::PickOne()
{
char* foundName = NULL; // pointer to name of pick we find, caller deletes.
if ( mIsSequentialPicker )
{
if ( mElementLists[mWhichSequentialBucket]->GetNumNodes() == 0 && mIsSequentialLooping )
{ // ran out of items switch to other list.
if ( mWhichSequentialBucket == 0 )
mWhichSequentialBucket = 1;
else
mWhichSequentialBucket = 0;
}
if ( mElementLists[mWhichSequentialBucket]->GetNumNodes() > 0 )
{
PLDoubleLinkedListNode<SimplePlayListElement>* node;
node = mElementLists[mWhichSequentialBucket]->GetFirst();
Assert( node );
int nameLen = ::strlen( node->fElement->mElementName );
foundName = new char[ nameLen +1 ];
Assert( foundName );
if ( foundName )
{
int usedBucketIndex;
::strcpy( foundName, node->fElement->mElementName );
// take him out of the bucket since he's now in play
mElementLists[mWhichSequentialBucket]->RemoveNode( node );
if ( mWhichSequentialBucket == 0 )
usedBucketIndex = 1;
else
usedBucketIndex = 0;
/* changed by emil@popwire.com (see relaod.txt for info) */
if(!mRemoveFlag)
/* ***************************************************** */
mElementLists[usedBucketIndex]->AddNodeToTail( node );
/* changed by emil@popwire.com (see relaod.txt for info) */
else
mNumToPickFrom--;
/* ***************************************************** */
}
}
}
else
{
SInt32 bucketIndex;
UInt32 minimumBucket = 0;
UInt32 avaiableToPick;
UInt32 theOneToPick;
SInt32 topBucket;
// find the highest bucket with some elements.
bucketIndex = this->GetNumBuckets() - 1;
while ( bucketIndex >= 0 && mElementLists[bucketIndex]->GetNumNodes() == 0 )
{
bucketIndex--;
}
// adjust to 1 based so we can use MOD
topBucket = bucketIndex + 1;
//qtss_printf( "topBucket %li \n", topBucket );
if (topBucket > 0)
minimumBucket = this->Random() % topBucket; // find our minimum bucket
//qtss_printf( "minimumBucket %li \n", minimumBucket );
// pick randomly from the movies in this and higher buckets
// sum the available elements, then pick randomly from them.
avaiableToPick = 0;
bucketIndex = minimumBucket;
while ( bucketIndex < topBucket )
{
avaiableToPick += mElementLists[bucketIndex]->GetNumNodes();
bucketIndex++;
}
//qtss_printf( "avaiableToPick %li \n", avaiableToPick );
// was anyone left??
if ( avaiableToPick )
{
theOneToPick = this->Random() % avaiableToPick;
//qtss_printf( "theOneToPick %li \n", theOneToPick );
// now walk through the lists unitl we get to the list
// that contains our pick, then pick that one.
bucketIndex = minimumBucket;
while ( bucketIndex < topBucket && foundName == NULL )
{
//qtss_printf( "theOneToPick %li, index %li numelements %li\n", theOneToPick , bucketIndex, mElementLists[bucketIndex]->GetNumNodes());
if ( theOneToPick >= mElementLists[bucketIndex]->GetNumNodes() )
theOneToPick -= mElementLists[bucketIndex]->GetNumNodes();
else
{ //qtss_printf( "will pick theOneToPick %li, index %li \n", theOneToPick, bucketIndex);
foundName = this->PickFromList( mElementLists[bucketIndex], theOneToPick );
if ( foundName )
mPickCounts[bucketIndex]++;
}
bucketIndex++;
}
// we messed up if we don't have a name at this point.
Assert( foundName );
}
}
fLastPick = foundName;
return foundName;
}
void PlaylistPicker::CleanList()
{
mFirstElement = NULL;
mNumToPickFrom = 0;
delete mUsedElements;
mUsedElements = new NoRepeat( mRecentMoviesListSize );
delete [] mPickCounts;
mPickCounts = new SInt32[mBuckets];
UInt32 x;
for ( x = 0; x < mBuckets; x++ )
{
mPickCounts[x] = 0;
delete mElementLists[x];
mElementLists[x] = new PLDoubleLinkedList<SimplePlayListElement>;
Assert( mElementLists[x] );
}
};
char* PlaylistPicker::PickFromList( PLDoubleLinkedList<SimplePlayListElement>* list, UInt32 elementIndex )
{
PLDoubleLinkedListNode<SimplePlayListElement>* plNode;
char* foundName = NULL;
plNode = list->GetNthNode( elementIndex );
if ( plNode )
{
int nameLen = ::strlen(plNode->fElement->mElementName );
foundName = new char[ nameLen +1 ];
Assert( foundName );
if ( foundName )
{
::strcpy( foundName, plNode->fElement->mElementName );
// take him out of the bucket since he's now in play
list->RemoveNode( plNode );
mNumToPickFrom--;
// add him to our used list, and possibly
// get an older one to put back into play
PLDoubleLinkedListNode<SimplePlayListElement>* recycleNode = mUsedElements->AddToList( plNode );
// if we got an old one to recycle, do so.
if ( recycleNode )
this->AddNode( recycleNode );
}
}
return foundName;
}
bool PlaylistPicker::AddToList( const char* name, int weight )
{
bool addedSuccesfully;
PLDoubleLinkedListNode<SimplePlayListElement>* node;
SimplePlayListElement* element;
node = NULL;
addedSuccesfully = false;
element = new SimplePlayListElement(name);
if (mFirstElement == NULL)
mFirstElement = element->mElementName;
Assert( element );
if ( element )
{ element->mElementWeight = weight;
node = new PLDoubleLinkedListNode<SimplePlayListElement>(element);
Assert( node );
}
if ( node )
addedSuccesfully = AddNode(node);
return addedSuccesfully;
}
bool PlaylistPicker::AddNode( PLDoubleLinkedListNode<SimplePlayListElement>* node )
{
bool addSucceeded = false;
Assert( node );
Assert( node->fElement );
if ( mIsSequentialPicker ) // make picks in sequential order, not weighted random
{
// add all to bucket 0
mElementLists[0]->AddNodeToTail( node );
addSucceeded = true;
mNumToPickFrom++;
}
else
{
int weight;
weight = node->fElement->mElementWeight;
// weights are 1 based, correct to zero based for use as array myIndex
weight--;
Assert( weight >= 0 );
Assert( (UInt32)weight < mBuckets );
if ( (UInt32)weight < mBuckets )
{
// the elements weighting defines the list it is in.
mElementLists[weight]->AddNode( node );
addSucceeded = true;
mNumToPickFrom++;
}
}
return addSucceeded;
}

View file

@ -0,0 +1,86 @@
#ifndef __playlist_picker__
#define __playlist_picker__
/*
*
* @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 "PLDoubleLinkedList.h"
#include "SimplePlayListElement.h"
#include "OSHeaders.h"
#include "NoRepeat.h"
class PlaylistPicker
{
public:
enum { kMaxBuckets = 10 };
PlaylistPicker(bool doLoop);
PlaylistPicker( UInt32 numBuckets, UInt32 numNoRepeats );
virtual ~PlaylistPicker();
void CleanList();
bool AddToList( const char *name, int weight );
bool AddNode( PLDoubleLinkedListNode<SimplePlayListElement> *node );
char* PickOne();
char* LastPick() { return fLastPick; }
UInt32 GetNumBuckets() { return mBuckets; }
/* changed by emil@popwire.com (see relaod.txt for info) */
UInt32 GetNumMovies() { return mNumToPickFrom; }
bool mRemoveFlag;
bool mStopFlag;
/* ***************************************************** */
SInt32* mPickCounts;
SInt32 mNumToPickFrom;
UInt32 mRecentMoviesListSize;
char* fLastPick;
PLDoubleLinkedList<SimplePlayListElement>* GetBucket( UInt32 myIndex ) { return mElementLists[myIndex]; }
char* GetFirstFile() { return mFirstElement; }
protected:
bool mIsSequentialPicker; // picker picks sequentially?
bool mIsSequentialLooping; // loop over and over?
int mWhichSequentialBucket; // sequential picker picks from list0 or list1?
UInt32 Random();
UInt32 mLastResult;
char* PickFromList( PLDoubleLinkedList<SimplePlayListElement>* list, UInt32 elementIndex );
PLDoubleLinkedList<SimplePlayListElement>* mElementLists[kMaxBuckets];
UInt32 mBuckets;
NoRepeat *mUsedElements;
char* mFirstElement;
};
#endif

View file

@ -0,0 +1,60 @@
/*
*
* @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@
*
*/
#ifndef __SimplePlayListElement__
#define __SimplePlayListElement__
#include <string.h>
#include "MyAssert.h"
class SimplePlayListElement {
public:
SimplePlayListElement( const char * name )
{
mElementName = new char[ strlen(name) + 1 ];
Assert( mElementName );
if( mElementName )
strcpy( mElementName, name );
mElementWeight = -1;
mWasPlayed = false;
}
virtual ~SimplePlayListElement()
{
if ( mElementName )
delete [] mElementName;
}
int mElementWeight;
bool mWasPlayed;
char *mElementName;
};
#endif

View file

@ -0,0 +1,56 @@
/*
*
* @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@
*
*/
#ifndef __StSmartArrayPointer__
#define __StSmartArrayPointer__
template <class T>
class StSmartArrayPointer
{
public:
StSmartArrayPointer(T* victim) : fT(victim) {}
~StSmartArrayPointer() { delete [] fT; }
void SetObject(T* victim)
{
//can't use a normal assert here because "Assert.h" eventually includes this file....
#ifdef ASSERT
//char s[65];
if (fT != NULL) qtss_printf ("_Assert: StSmartArrayPointer::SetObject() %s, %d\n", __FILE__, __LINE__);
#endif
fT = victim;
}
T* GetObject() { return fT; }
operator T*() { return fT; }
private:
T* fT;
};
typedef StSmartArrayPointer<char> OSCharArrayDeleter;
#endif

View file

@ -0,0 +1,59 @@
/*
*
* @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@
*
*/
#ifndef __tracking_element__
#define __tracking_element__
#include <unistd.h>
#include <string.h>
#include "OSHeaders.h"
#include "MyAssert.h"
class TrackingElement {
public:
TrackingElement( pid_t pid, const char * name )
{
mName = new char[ strlen(name) + 1 ];
Assert( mName );
if( mName )
strcpy( mName, name );
mPID = pid;
}
virtual ~TrackingElement()
{
if ( mName )
delete [] mName;
}
char *mName;
pid_t mPID;
};
#endif

View file

@ -0,0 +1,209 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @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@
*/
#if 0
todo
v12 --
- changed PlayListBroadcaster to PlaylistBroadcaster
- don't strip ext from Descr filename before adding .log in a default file name.
- play_list_file becomes playlist_file
- repeats_queue_size becomes recent_movies_list_size
- limit_play is not used anymore
v11--
- changed a bunch of error messages
- fixed: In my broadcast description file, I left off any keyword after "logging"
and both the preflight and the regular run of the file caused a Bus error.
- added descriptive messages about setup file errors.
- changed name from /tmp/trackerfile to /tmp/broadcastlist
- chdir to location of Setup file ( means that paths in Setup file are
relative to locaation of setup file, not PlayListBroadcaster
v10
-- writes message that SDP file was generated in debug or preflight? 2365986
-- fixed pathname display bug for log file name errors. ... "the.log", or else "./the.log", or else
the full path should have been displayed...
-- added "PlayListBroadcaster preflight finished.\n" at end of prefilght ( already logged ).
-- err desc is logged, not err #
Error:#
as in these samples
# 1999-08-04 13:36:25 PlayListBroadcaster started
1999-08-04 13:44:53 /Beamer/projects/Servers/TimeShare/PlayListBroadcaster/pl_files/lists/3movie3.mov Error:12
1999-08-04 13:44:55 /Beamer/projects/Servers/TimeShare/PlaylistBroadcaster/pl_files/lists/test1.mov OK
# 1999-08-04 14:57:49 PlaylistBroadcaster finished
to
Error:"errstring"
where "errstring" is one of the following:
Movie file not found
Movie file has no hinted tracks
Movie file does not match SDP
Movie file is invalid
Movie file name is missing or too long
8.6.99 build 9
- PLB logs preflights, # movie problems
- cleaned up code in PlayListBroadcaster.cpp
- only complains about lack of tracker and logfile access when necessary
- "Setup File Name".los is the default logfile name
- changed display occurances of PlaylistBroadcaster to PlayListBroadcaster
- report permission to stop denied error, not just "not running"
8.5.99 build 8
- chanegd track match error to warning and reworded
- added check for tracker access.
- added Lock to log file
- fixed problems when running in background ( loss of tracking and logging )
8.4.99 build 7
- added Error message "- PlayListBroadcaster: Error, unsupported Play Mode (%s)\n"
- uses Setup supplied logfile name, doed not append .log 2364223
- added error messages about not being able to open the log file
- added error messages about not being able to open the Broadcast setup file.
- added playError messages to log file:
# 1999-08-04 13:36:25 PlayListBroadcaster started
1999-08-04 13:44:53 /Beamer/projects/Servers/TimeShare/PlayListBroadcaster/pl_files/lists/3movie3.mov Error:12
1999-08-04 13:44:55 /Beamer/projects/Servers/TimeShare/PlaylistBroadcaster/pl_files/lists/test1.mov OK
# 1999-08-04 14:57:49 PlaylistBroadcaster finished
- will not ignore ^C's when there is an initial problem with the tracker file.
8.2.99 -- build 6
- gen error messages from broadcaster
- changed to all verbose options
- removed -c option, just list file the name at end of command.
- destination ip now defaults to machine's primary address
- changed BCasterTracker::BCasterTracker to 5 second open timer.
- changed reference to "channel setup" to "PlaylistBroadcaster Description"
- changed &d's in qtss_printf's to %d in Broadcaster error messages
- only print errors when walking the play list
- only show Setup options in Preflight mode
- changed display of setup options to show user names, not C++ names.
- the -list option no longer lists broadcasts that are not running. file is
cleaned up on next "stop"
- multiple options per command line are now supported, exits on first error.
- command line options uses "getopt"'s long form that allows -fullword options
and partial ( down to one char ) options as long as they are unambiguous.
8.3.99
- fixed include loops
- better error reporting from building the picklist
- chmod's the "trackerfile" to 666 so that all users can run broadcasts
and track them.
- Shows permission error if that is the reason a "stop" fails.
- fixes problems with fully qualified paths in both Playlist and "play_list_file"
Setup file option
7.30.99 - build 5
- Movie file and SDP parsing now includes "user" error reporting ( not using Assert ).
So the program should continue past recoverable errors and stop only on non recoverable
errors.
- Playlists no longer require weights, non - weighted files in a random playlist
default to a weight of 10.
- + symbol introduces an "included" play list
- play list files MUST have "*PLAY-LIST*" as the first line ( exactly ).
Else they will be treated as an invalid play list file.
- new "-prefilght" option displays Setup, SDP, and walks the movie list to check
files for correctness.
- removed debug options from command line options.
7.27.99 - build 4
- removed license from about display
- updated credit names
- fixed mapping of --stop to 's' from 'l'
- added -a (about) to help
- builds from libQTRTPFile.a
- added ppc only instructions to make.preamble
- uses a well known place to keep the tracker file, was kept is same dir
as PlaylistBroadcaster ( now uses /tmp/ )
- better error message on "stop" with bad parameters.
- removed Assert on playlist "includes"
- added default destination adddress ( 127.0.0.1 "localhost" )
- changed "weighted" mode parameter to "weighted_random" as per docs
- changes picking algorithm to provide better weighting
- fixes the "count5.mov" crash
- fixes the "can't play more than 8 movies without losing audio" bug
7.26.99 -- build 3 Notes and Errata
not documented: uses "sdp_reference_movie" option (mSDPReferenceMovie) to bulid SDP file.
Add this option to the config file. It's a required field.
Use the -g file.config option to cause PlaylistBroadcaster to parse and display the
settings in a config file.
SDP generation displays the raw SDP of the reference file, not the generated
file.
If you set the config "limit_seq_length" to a value greater than the number of
movies available for play in random mode, the movies will play once and the
broadcast will stop.
The executable is incorrectly named BroadcastPlaylist, instead of PlaylistBroacaster.
The installer read me references v1.0.1, not v1.0.2.
The broadcast will lose audio after 7 or 8 movies play. You can restore audio
by pausing the client and then restarting.
#endif

View file

@ -0,0 +1,70 @@
/*
*
* @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@
*
*/
// $Id: playlist_QTRTPBroadcastFile.cpp,v 1.1 2006/01/05 13:20:36 murata Exp $
//
// QTRTPBroadcastFile:
// An interface to QTFile for TimeShare.
// -------------------------------------
// Includes
//
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
//#include "OSMutex.h"
//#include "QTFile.h"
//#include "QTTrack.h"
//#include "QTHintTrack.h"
#include "playlist_QTRTPBroadcastFile.h"
bool QTRTPBroadcastFile::FindTrackSSRC( UInt32 SSRC)
{
// General vars
RTPTrackListEntry *ListEntry;
//
// Find the specified track.
for( ListEntry = fFirstTrack; ListEntry != NULL; ListEntry = ListEntry->NextTrack )
{
// Check for matches.
if( ListEntry->SSRC == SSRC )
{ return true;
}
}
// The search failed.
return false;
}

View file

@ -0,0 +1,56 @@
/*
*
* @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@
*
*/
// $Id: playlist_QTRTPBroadcastFile.h,v 1.1 2006/01/05 13:20:36 murata Exp $
//
// QTRTPFile:
// An interface to QTFile for TimeShare.
#ifndef QTRTPBroadcastFile_H
#define QTRTPBroadcastFile_H
//
// Includes
#include "OSHeaders.h"
#include "QTRTPFile.h"
#ifndef __Win32__
#include <sys/stat.h>
#endif
class QTRTPBroadcastFile : public QTRTPFile {
public:
bool FindTrackSSRC( UInt32 SSRC);
};
#endif // QTRTPBroadcastFile

View file

@ -0,0 +1,450 @@
/*
*
* @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_utils.h"
#include "playlist_SDPGen.h"
#include "playlist_broadcaster.h"
#include "QTRTPFile.h"
#include "OS.h"
#include "SocketUtils.h"
#include "SDPUtils.h"
#include "OSArrayObjectDeleter.h"
short SDPGen::AddToBuff(char *aSDPFile, short currentFilePos, char *chars)
{
short charLen = strlen(chars);
short newPos = currentFilePos + charLen;
if (newPos <= eMaxSDPFileSize)
{ memcpy(&aSDPFile[currentFilePos],chars,charLen); // only the chars not the \0
aSDPFile[currentFilePos +charLen] = '\0';
}
else
{ newPos = (-newPos);
}
currentFilePos = newPos;
return currentFilePos;
}
UInt32 SDPGen::RandomTime(void)
{
SInt64 curTime = 0;
curTime = PlayListUtils::Milliseconds();
curTime += rand() ;
return (UInt32) curTime;
}
short SDPGen::GetNoExtensionFileName(char *pathName, char *result, short maxResult)
{
char *start;
char *end;
char *sdpPath = pathName;
short pathNameLen = strlen(pathName);
short copyLen = 0;
do
{
start = strrchr(sdpPath, ePath_Separator);
if(start == NULL ) // no path separator
{ start = sdpPath;
copyLen = pathNameLen;
break;
}
start ++; // move start to one past the separator
end = strrchr(sdpPath, eExtension_Separator);
if (end == NULL) // no extension
{ copyLen = strlen(start) + 1;
break;
}
// both path separator and an extension
short startLen = strlen(start);
short endLen = strlen(end);
copyLen = startLen - endLen;
} while (false);
if (copyLen > maxResult)
copyLen = maxResult;
memcpy(result, start, copyLen);
result[copyLen] = '\0';
return copyLen;
}
char *SDPGen::Process( char *sdpFileName,
char * basePort,
char *ipAddress,
char *anSDPBuffer,
char *startTime,
char *endTime,
char *isDynamic,
char *ttl,
int *error
)
{
char *resultBuf = NULL;
short currentPos = 0;
short trackID = 1;
*error = -1;
do
{
fSDPFileContentsBuf = new char[eMaxSDPFileSize];
// SDP required RFC 2327
// v= (protocol version)
// o=<username> <session id = random time> <version = random time *> <network type = IN> <address type = IP4> <local address>
// s= (session name)
// c=IN IP4 (destinatin ip address)
// * see RFC for recommended Network Time Stamp (NTP implementation not required)
// v= (protocol version)
{ char version[] = "v=0\r\n";
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, version);
if (currentPos < 0) break;
}
// o=<username> <session id = random time> <version = random time *> <network type = IN> <address type = IP4> <address>
{ char *userName = "QTSS_Play_List";
UInt32 sessIDAsRandomTime = RandomTime();
UInt32 versAsRandomTime = RandomTime();
char ownerLine[255];
Assert(SocketUtils::GetIPAddrStr(0) != NULL);
Assert(SocketUtils::GetIPAddrStr(0)->Ptr != NULL);
qtss_sprintf(ownerLine, "o=%s %"_U32BITARG_" %"_U32BITARG_" IN IP4 %s\r\n",userName ,sessIDAsRandomTime,versAsRandomTime,SocketUtils::GetIPAddrStr(0)->Ptr);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, ownerLine);
if (currentPos < 0) break;
}
// s= (session name)
{ enum { eMaxSessionName = 64};
char newSessionName[eMaxSessionName];
short nameSize = 0;
char sessionLine[255];
nameSize = GetNoExtensionFileName(sdpFileName, newSessionName, eMaxSessionName);
if (nameSize < 0) break;
qtss_sprintf(sessionLine, "s=%s\r\n", newSessionName);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, sessionLine);
if (currentPos < 0) break;
}
// c=IN IP4 (destinatin ip address)
{
char sdpLine[255];
if (SocketUtils::IsMulticastIPAddr(ntohl(inet_addr(ipAddress))))
qtss_sprintf(sdpLine, "c=IN IP4 %s/%s\r\n", ipAddress,ttl);
else
qtss_sprintf(sdpLine, "c=IN IP4 %s\r\n", ipAddress);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, sdpLine);
if (currentPos < 0) break;
}
{
char controlLine[255];
if ( 0 == ::strcmp( "enabled", isDynamic) )
qtss_sprintf(controlLine, "a=x-broadcastcontrol:RTSP\r\n");
else
qtss_sprintf(controlLine, "a=x-broadcastcontrol:TIME\r\n");
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, controlLine);
if (currentPos < 0) break;
}
{
char timeLine[255];
UInt32 startTimeNTPSecs = strtoul(startTime, NULL, 10);
UInt32 endTimeNTPSecs = strtoul(endTime, NULL, 10);
qtss_sprintf(timeLine, "t=%"_U32BITARG_" %"_U32BITARG_"\r\n", startTimeNTPSecs, endTimeNTPSecs);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, timeLine);
if (currentPos < 0) break;
}
{
SimpleString resultString;
SimpleString sdpBuffString(anSDPBuffer);
short numLines = 0;
char *found = NULL;
enum {eMaxLineLen = 1024};
char aLine[eMaxLineLen +1];
::memset(aLine, 0, sizeof(aLine));
int portCount = atoi(basePort);
SimpleParser sdpParser;
while ( sdpParser.GetLine(&sdpBuffString,&resultString) )
{
numLines ++;
if (resultString.fLen > eMaxLineLen) continue;
memcpy(aLine,resultString.fTheString,resultString.fLen);
aLine[resultString.fLen] = '\0';
int newBuffSize = sdpBuffString.fLen - (resultString.fLen);
char *newBuffPtr = &resultString.fTheString[resultString.fLen];
sdpBuffString.SetString(newBuffPtr, newBuffSize);
char firstChar = aLine[0];
{ // we are setting these so ignore any defined
if (firstChar == 'v') continue;// (protocol version)
if (firstChar == 'o') continue; //(owner/creator and session identifier).
if (firstChar == 's') continue; //(session name)
if (firstChar == 'c') continue; //(connection information - optional if included at session-level)
}
{ // no longer important as a play list broadcast
// there may be others that should go here.......
if (firstChar == 't') continue;// (time the session is active)
if (firstChar == 'r') continue;// (zero or more repeat times)
// found = strstr(aLine, "a=cliprect"); // turn this off
// if (found != NULL) continue;
found = strstr(aLine, "a=control:trackID"); // turn this off
if (!fKeepTracks)
{
if (fAddIndexTracks)
{
if (found != NULL)
{ char mediaLine[eMaxLineLen];
qtss_sprintf(mediaLine,"a=control:trackID=%d\r\n",trackID);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, mediaLine); // copy rest of line starting with the transport protocol
trackID ++;
}
}
if (found != NULL) continue;
}
found = strstr(aLine, "a=range"); // turn this off
if (found != NULL) continue;
// found = strstr(aLine, "a=x"); // turn this off -
// if (found != NULL) continue;
}
{ // handle the media line and put in the port value past the media type
found = strstr(aLine,"m="); //(media name and transport address)
if (found != NULL)
{
char *startToPortVal = strtok(aLine," ");
strtok(NULL," "); // step past the current port value we put it in below
if (found != NULL)
{ char mediaLine[eMaxLineLen];
char *protocol = strtok(NULL,"\r\n"); // the transport protocol
qtss_sprintf(mediaLine,"%s %d %s\r\n",startToPortVal,portCount,protocol);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, mediaLine); // copy rest of line starting with the transport protocol
if (portCount != 0)
portCount += 2; // set the next port value ( this port + 1 is the RTCP port for this port so we skip by 2)
continue;
}
}
}
{ // this line looks ok so just get it and make sure it has a carriage return + new line at the end
// also remove any garbage that might be there
// this is a defensive measure because the hinter may have bad line endings like a single \n or \r or
// there might also be chars after the last line delimeter and before a \0 so we get rid of it.
short lineLen = strlen(aLine);
// get rid of trailing characters
while (lineLen > 0 && (NULL == strchr("\r\n",aLine[lineLen])) )
{ aLine[lineLen] = '\0';
lineLen --;
}
// get rid of any line feeds and carriage returns
while (lineLen > 0 && (NULL != strchr("\r\n",aLine[lineLen])) )
{ aLine[lineLen] = '\0';
lineLen --;
}
aLine[lineLen + 1] = '\r';
aLine[lineLen + 2] = '\n';
aLine[lineLen + 3] = 0;
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, aLine); // copy this line
}
}
// buffer delay
if (fClientBufferDelay > 0.0)
{
char delayLine[255];
qtss_sprintf(delayLine, "a=x-bufferdelay:%.2f\r\n", fClientBufferDelay);
currentPos = AddToBuff(fSDPFileContentsBuf, currentPos, delayLine);
if (currentPos < 0) break;
}
}
StrPtrLen theSDPStr(fSDPFileContentsBuf);
SDPContainer rawSDPContainer;
if (!rawSDPContainer.SetSDPBuffer( &theSDPStr ))
{ delete [] fSDPFileContentsBuf;
fSDPFileContentsBuf = NULL;
return NULL;
}
SDPLineSorter sortedSDP(&rawSDPContainer);
resultBuf = sortedSDP.GetSortedSDPCopy(); // return a new copy of the sorted SDP
delete [] fSDPFileContentsBuf; // this has to happen after GetSortedSDPCopy
fSDPFileContentsBuf = resultBuf;
*error = 0;
} while (false);
return resultBuf;
}
int SDPGen::Run( char *movieFilename
, char *sdpFilename
, char *basePort
, char *ipAddress
, char *buff
, short buffSize
, bool overWriteSDP
, bool forceNewSDP
, char *startTime
, char *endTime
, char *isDynamic
, char *ttl
)
{
int result = -1;
int fdsdp = -1;
bool sdpExists = false;
do
{
if (!movieFilename) break;
if (!sdpFilename) break;
if (buff && buffSize > 0) // set buff to 0 length string
buff[0] = 0;
fdsdp = open(sdpFilename, O_RDONLY, 0);
if (fdsdp != -1)
sdpExists = true;
if (sdpExists && !forceNewSDP)
{
if (!overWriteSDP)
{
if (buff && (buffSize > 0))
{ int count = ::read(fdsdp,buff, buffSize -1);
if (count > 0)
buff[count] = 0;
}
}
close(fdsdp);
fdsdp = -1;
if (!overWriteSDP)
{ result = 0;
break; // leave nothing to do
}
}
QTRTPFile::ErrorCode err = fRTPFile.Initialize(movieFilename);
result = QTFileBroadcaster::EvalErrorCode(err);
if( result != QTRTPFile::errNoError )
break;
// Get the file
int sdpFileLength=0;
int processedSize=0;
char *theSDPText = fRTPFile.GetSDPFile(&sdpFileLength);
if( theSDPText == NULL || sdpFileLength <= 0)
{ break;
}
char *processedSDP = NULL;
processedSDP = Process(sdpFilename, basePort, ipAddress, theSDPText,startTime,endTime,isDynamic, ttl, &result);
if (result != 0) break;
processedSize = strlen(processedSDP);
if (buff != NULL)
{ if (buffSize > processedSize )
{
buffSize = processedSize;
}
memcpy(buff,processedSDP,buffSize);
buff[buffSize] = 0;
}
if (!overWriteSDP && sdpExists)
{
break;
}
// Create our SDP file and write out the data
#ifdef __Win32__
fdsdp = open(sdpFilename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0664);
#else
fdsdp = open(sdpFilename, O_CREAT | O_TRUNC | O_WRONLY, 0664);
#endif
if( fdsdp == -1 )
{
//result = -1;
result = -2;
break;
}
write(fdsdp, processedSDP, processedSize);
result = 0;
// report that we made a file
fSDPFileCreated = true;
} while (false);
if (fdsdp != -1)
{ result = 0;
close(fdsdp);
fdsdp = -1;
}
return result;
}

View file

@ -0,0 +1,106 @@
/*
*
* @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@
*
*/
// SimpleParse:
#ifndef SDPGen_H
#define SDPGen_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <fcntl.h>
#include <string.h>
#ifndef __Win32__
#include <sys/types.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <net/if.h>
#endif
#include "playlist_SimpleParse.h"
#include "QTRTPFile.h"
class SDPGen
{
enum {eMaxSDPFileSize = 10240};
enum {ePath_Separator = '/', eExtension_Separator = '.'};
private:
char *fSDPFileContentsBuf;
protected:
QTRTPFile fRTPFile;
bool fKeepTracks;
bool fAddIndexTracks;
short AddToBuff(char *aSDPFile, short currentFilePos, char *chars);
UInt32 RandomTime(void);
short GetNoExtensionFileName(char *pathName, char *result, short maxResult);
char *Process( char *sdpFileName,
char * basePort,
char *ipAddress,
char *anSDPBuffer,
char *startTime,
char *endTime,
char *isDynamic,
char *ttl,
int *error
);
public:
SDPGen() : fSDPFileContentsBuf(NULL), fKeepTracks(false),fAddIndexTracks(false), fSDPFileCreated(false),fClientBufferDelay(0.0) { QTRTPFile::Initialize(); };
~SDPGen() { if (fSDPFileContentsBuf) delete fSDPFileContentsBuf; };
void KeepSDPTracks(bool enabled) { fKeepTracks = enabled;} ;
void AddIndexTracks(bool enabled) { fAddIndexTracks = enabled;} ;
void SetClientBufferDelay(Float32 bufferDelay) { fClientBufferDelay = bufferDelay;} ;
int Run( char *movieFilename
, char *sdpFilename
, char *basePort
, char *ipAddress
, char *buff
, short buffSize
, bool overWriteSDP
, bool forceNewSDP
, char *startTime
, char *endTime
, char *isDynamic
, char *ttl
);
bool fSDPFileCreated;
Float32 fClientBufferDelay;
};
#endif

View file

@ -0,0 +1,357 @@
/*
*
* @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 <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include "playlist_SimpleParse.h"
SimpleString::SimpleString(char *theString)
{
fTheString = theString;
if (theString == NULL)
fLen = 0;
else
fLen = strlen(theString);
}
void SimpleString::Init()
{
fTheString = NULL;
fLen = 0;
}
void SimpleString::SetString(char *theString, SInt32 len)
{
fTheString = theString;
fLen = len;
}
SInt32 SimpleString::GetString(char *theString, SInt32 len)
{
SInt32 copyLen = fLen + 1;
if (len < copyLen ) copyLen = len;
if (copyLen > 0)
{ memcpy(theString,fTheString,copyLen);
theString[copyLen -1] = 0;
}
return copyLen;
}
SInt32 SimpleString::GetInt()
{
SInt32 result = 0;
if (fTheString == NULL|| fLen == 0 || fLen > 32)
return result;
char* buff = new char[fLen +1];
memcpy (buff, fTheString,fLen);
buff[fLen] = 0;
result = strtol(buff, NULL, 0);
delete [] buff;
return result;
}
void SimpleString::Print()
{
char* buff = new char[fLen +1];
memcpy (buff, fTheString,fLen);
buff[fLen] = 0;
printf("SimpleString( len=%"_S32BITARG_" str=>%s< )\n",fLen,buff);
delete [] buff;
}
char SimpleParser::sWordDelimeters[] = "=:/\t \r\n";
char SimpleParser::sLineDelimeters[] = "\r\n";
bool SimpleParser::Compare(SimpleString *str1Ptr, SimpleString *str2Ptr, bool caseSensitive)
{
bool result = false;
do
{
if (NULL == str1Ptr) break;
if (NULL == str2Ptr) break;
if (NULL == str1Ptr->fTheString) break;
if (NULL == str2Ptr->fTheString) break;
if (str1Ptr->fLen != str2Ptr->fLen)
break;
int test = 0;
if (caseSensitive)
test = strncmp(str1Ptr->fTheString, str2Ptr->fTheString,str1Ptr->fLen);
else
#if __Win32__
test = _strnicmp(str1Ptr->fTheString, str2Ptr->fTheString,str1Ptr->fLen);
#else
test = strncasecmp(str1Ptr->fTheString, str2Ptr->fTheString,str1Ptr->fLen);
#endif
if (test != 0) break;
result = true;
} while (false);
return result;
}
bool SimpleParser::FindString( SimpleString *sourcePtr, SimpleString *findPtr, SimpleString *resultStringPtr)
{
bool result = false;
do
{
if (NULL == sourcePtr) break;
if (NULL == findPtr) break;
if (NULL == sourcePtr->fTheString) break;
if (NULL == findPtr->fTheString) break;
if (findPtr->fLen > sourcePtr->fLen)
break;
char *start = strstr(sourcePtr->fTheString, findPtr->fTheString);
if (start == NULL) break;
if (NULL != resultStringPtr)
{
SInt32 len = (PointerSizedInt) start - (PointerSizedInt) sourcePtr->fTheString;
if (len > sourcePtr->fLen) break;
resultStringPtr->SetString(start, findPtr->fLen);
}
result = true;
} while (false);
return result;
}
bool SimpleParser::FindNextString( SimpleString *sourcePtr, SimpleString *currentPtr, SimpleString *findPtr, SimpleString *resultStringPtr)
{
bool result = false;
SInt32 length = 0;
do
{
if (NULL == sourcePtr) break;
if (NULL == currentPtr) break;
if (NULL == findPtr) break;
if (NULL == sourcePtr->fTheString) break;
if (NULL == currentPtr->fTheString) break;
SimpleString tempSource(NULL);
length = currentPtr->fTheString - sourcePtr->fTheString;
if (length < 0) break;
if (length > sourcePtr->fLen) break;
length = sourcePtr->fLen - (length + currentPtr->fLen); // the remaining length to search
tempSource.SetString(&currentPtr->fTheString[currentPtr->fLen], length); // step past the end of current with remaining length
result = FindString(&tempSource, findPtr, resultStringPtr);
} while (false);
return result;
}
bool SimpleParser::GetString( SimpleString *sourcePtr, SimpleString *findPtr, SimpleString *resultStringPtr)
{
bool result = false;
result = FindString(sourcePtr, findPtr, resultStringPtr);
if (result)
{ resultStringPtr->fLen = (PointerSizedInt) resultStringPtr->fTheString -(PointerSizedInt) sourcePtr->fTheString;
resultStringPtr->fTheString = sourcePtr->fTheString;
}
return result;
}
bool SimpleParser::FindDelimeter( SimpleString *sourcePtr, char *findChars, SimpleString *resultStringPtr)
{
bool result = false;
do
{
if (NULL == sourcePtr) break;
if (NULL == findChars) break;
if (NULL == resultStringPtr) break;
SInt32 charCount = 0;
char* charOffset = sourcePtr->fTheString;
char* foundChar = NULL;
if ( (NULL == sourcePtr->fTheString) || (0 == sourcePtr->fLen) )
{ //qtss_printf("NULL string in FindDelimeter \n");
break;
}
// skip past any delimeters
while ( (*charOffset != 0) && (charCount <= sourcePtr->fLen) )
{ foundChar = strchr(findChars, *charOffset);
if (NULL == foundChar) break; // found non delimeter char
charOffset ++; charCount ++;
}
char *theChar = charOffset; // start past delimeters
while ( (*theChar != 0) && (charCount <= sourcePtr->fLen) )
{
foundChar = strchr(findChars, *theChar);
if (NULL != foundChar) break; // found delimeter
charCount++;
theChar++;
}
if (NULL == foundChar) break; // we didn't find a delimeter;
if (NULL != resultStringPtr)
{ UInt32 theLen = ((PointerSizedInt) theChar - (PointerSizedInt)charOffset);
resultStringPtr->SetString(charOffset, theLen); // start is charOffset
if (theLen == 0) break;
}
result = true;
} while (false);
if (!result)
resultStringPtr->SetString(NULL, 0); // start is charOffset
return result;
}
int SimpleParser::CountDelimeters( SimpleString *sourcePtr, char *delimeters)
{
short count = 0;
if (sourcePtr && delimeters)
{
SimpleString currentString = *sourcePtr;
currentString.fLen = 0;
while (GetNextThing(sourcePtr,&currentString, delimeters, &currentString))
{ count ++;
}
}
return count;
}
bool SimpleParser::GetWord( SimpleString *sourcePtr, SimpleString *resultStringPtr)
{
bool result = false;
char delimeter[] = " :/"; // space or colon or /
result = FindDelimeter(sourcePtr, delimeter,resultStringPtr);
return result;
}
bool SimpleParser::GetLine(SimpleString *sourcePtr, SimpleString *resultStringPtr)
{
bool result = false;
char delimeter[] = "\r\n";
result = FindDelimeter(sourcePtr, delimeter,resultStringPtr);
return result;
}
bool SimpleParser::GetNextThing(SimpleString *sourcePtr, SimpleString *currentPtr, char *findChars, SimpleString *resultStringPtr)
{
bool result = false;
do
{
if (NULL == sourcePtr) break;
if (NULL == currentPtr) break;
if (NULL == findChars) break;
if ( (PointerSizedInt) currentPtr->fTheString < (PointerSizedInt) sourcePtr->fTheString)
break;
if (NULL == sourcePtr->fTheString)
{ //qtss_printf("NULL sourcePtr->fTheString in GetNextThing \n");
break;
}
if (NULL == currentPtr->fTheString)
{ //qtss_printf("NULL currentPtr->fTheString in GetNextThing \n");
break;
}
PointerSizedInt endSource = (PointerSizedInt) &sourcePtr->fTheString[sourcePtr->fLen];
PointerSizedInt endCurrent = (PointerSizedInt) &currentPtr->fTheString[currentPtr->fLen];
if (endCurrent > endSource) break;
SimpleString tempSource(NULL);
UInt32 searchLen = endSource - endCurrent;
tempSource.SetString(&currentPtr->fTheString[currentPtr->fLen], searchLen); // step past the end of current with remaining length
result = FindDelimeter(&tempSource, findChars,resultStringPtr);
} while (false);
return result;
}
bool SimpleParser::GetNextWord( SimpleString *sourcePtr, SimpleString *currentWord, SimpleString *resultStringPtr)
{
bool result = false;
char *findChars = sWordDelimeters;//
result = GetNextThing(sourcePtr,currentWord, findChars, resultStringPtr);
return result;
}
bool SimpleParser::GetNextLine( SimpleString *sourcePtr, SimpleString *currentLine, SimpleString *resultStringPtr)
{
bool result = false;
char *findChars = sLineDelimeters;//"\r\n";
result = GetNextThing(sourcePtr,currentLine, findChars, resultStringPtr);
return result;
}

View file

@ -0,0 +1,96 @@
/*
*
* @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@
*
*/
#ifndef SimpleParser_H
#define SimpleParser_H
#include "OSHeaders.h"
class SimpleString {
public:
SInt32 fLen;
char *fTheString;
SimpleString(char *theString = NULL);
void Init();
void SetString(char *theString, SInt32 len);
SInt32 GetString(char *theString, SInt32 len);
SInt32 GetInt();
void Print();
};
class SimpleParser {
protected:
SimpleString fSource;
public:
SimpleParser() : fSource(NULL) {} ;
SimpleParser(SimpleString *source) : fSource(*source) {} ;
~SimpleParser() {};
static char sWordDelimeters[];
static char sLineDelimeters[];
void SetSource(SimpleString *source) {fSource = *source;};
static int CountDelimeters( SimpleString *source, char *delimeters);
static bool Compare(SimpleString *str1, SimpleString*str2, bool caseSensitive);
bool Compare(SimpleString *str1Ptr, char *str, bool caseSensitive)
{
if (str == NULL) return false;
SimpleString string(str);
return Compare(str1Ptr, &string, caseSensitive);
}
static bool FindString( SimpleString *source, SimpleString *find, SimpleString *resultString);
static bool FindNextString( SimpleString *sourcePtr, SimpleString *currentPtr, SimpleString *findPtr, SimpleString *resultStringPtr);
static bool GetString( SimpleString *source, SimpleString *find, SimpleString *resultString);
static bool FindDelimeter( SimpleString *source, char *delimeter, SimpleString *resultString);
static bool GetLine( SimpleString *sourcePtr, SimpleString *resultStringPtr);
static bool GetWord( SimpleString *sourcePtr, SimpleString *resultStringPtr);
static bool GetNextThing( SimpleString *sourcePtr, SimpleString *currentPtr, char *findChars, SimpleString *resultStringPtr);
static bool GetNextLine( SimpleString *sourcePtr, SimpleString *currentLine, SimpleString *resultStringPtr);
static bool GetNextWord( SimpleString *sourcePtr, SimpleString *currentWord, SimpleString *resultStringPtr);
};
#endif

View file

@ -0,0 +1,139 @@
/*
*
* @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@
*
*/
#ifndef playlist_array_H
#define playlist_array_H
// ************************
//
// TEMPLATE ARRAYLIST
//
// ************************
template <class T> class ArrayList
{
public:
T *fDataArray;
short fSize;
short fCurrent;
ArrayList()
{ fDataArray = NULL;
fSize = 0;
fCurrent = 0;
}
~ArrayList()
{ delete [] fDataArray;
};
T *SetSize(short size)
{ if (fDataArray != NULL) delete [] fDataArray;
fDataArray = new T[size];
if (fDataArray)
{ fSize = size;
}
return fDataArray;
}
T *Get()
{
T *resultPtr = NULL;
if (fDataArray != NULL)
{
if ( (fCurrent >= 0) && (fCurrent < fSize ) )
{ resultPtr = &fDataArray[fCurrent];
}
}
return resultPtr;
}
T *OffsetPos(short offset)
{
T *resultPtr = NULL;
do
{
if (fDataArray == NULL) break;
short temp = fCurrent + offset;
if (temp < 0)
{
fCurrent = 0; // peg at begin and return NULL
break;
}
if (temp < fSize)
{
resultPtr = &fDataArray[temp];
fCurrent = temp;
break;
}
fCurrent = fSize -1; // peg at end and return NULL
} while (false);
return resultPtr;
}
T *SetPos(short current)
{
T *resultPtr = NULL;
do
{
if (fDataArray == NULL) break;
if (current < 0)
{
fCurrent = 0; // peg at begin and return NULL
break;
}
if (current < fSize)
{
resultPtr = &fDataArray[current];
fCurrent = current;
break;
}
fCurrent = fSize -1; // peg at end and return NULL
} while (false);
return resultPtr;
}
short GetPos() { return fCurrent; };
T *Next() { return OffsetPos(1); };
T *Begin() { return SetPos(0); };
short Size() { return fSize;};
};
#endif

View file

@ -0,0 +1,765 @@
/*
*
* @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_broadcaster.h"
#include "OS.h"
#include "OSThread.h"
#include "BroadcasterSession.h"
#include <string.h>
QTFileBroadcaster::QTFileBroadcaster()
{
fRTPFilePtr = NULL;
fMovieSDPParser = NULL;
fBasePort = 0;
fDebug = false;
fDeepDebug = false;
fQuitImmediatePtr = NULL;
// transmit time trackers
fLastTransmitTime = 0.0;
fStreamStartTime = 0;
fMovieStartTime = 0;
fMovieEndTime = 0;
fMovieIntervalTime = 0;
fMovieTimeDiffMilli = 0;
fMovieStart = false;
fSendTimeOffset = 0.0;
fMovieDuration = 0.0;
fMovieTracks = 0;
fMappedMovieTracks = 0;
fNumMoviesPlayed = 0;
fPlay = true;
fSend = true;
fBroadcastDefPtr = NULL;
// current movie parameters parsed from SDP
::strcpy(fCurrentMovieName, "-");
::strcpy(fCurrentMovieCopyright, "-");
::strcpy(fCurrentMovieComment, "-");
::strcpy(fCurrentMovieAuthor, "-");
::strcpy(fCurrentMovieArtist, "-");
::strcpy(fCurrentMovieAlbum, "-");
}
QTFileBroadcaster::~QTFileBroadcaster()
{
LogFileClose();
if (fRTPFilePtr != NULL)
{ delete fRTPFilePtr;
}
}
int QTFileBroadcaster::SetUp(PLBroadcastDef *broadcastDefPtr, bool *quitImmediatePtr)
{
int result = -1;
int numStreams = 0;
fQuitImmediatePtr = quitImmediatePtr;
PlayListUtils::Initialize();
do
{
if (! broadcastDefPtr)
{ result = eParam; break; };
if (!broadcastDefPtr->mSDPFile || 0 == broadcastDefPtr->mSDPFile[0] )
{ result = eSDPFileInvalidName; break; };
int nameLen = strlen(broadcastDefPtr->mSDPFile);
if (nameLen > 255)
{ result = eSDPFileInvalidName; break; };
if (0 == nameLen)
{ result = eSDPFileInvalidName; break; };
if (broadcastDefPtr->mTheSession)
{ if (!broadcastDefPtr->mDestSDPFile)
{ result = eNetworkSDPFileNameInvalidMissing; break; };
if (!broadcastDefPtr->mDestSDPFile[0])
{ result = eNetworkSDPFileNameInvalidMissing; break; };
if (!::strcmp(broadcastDefPtr->mDestSDPFile, "no_name"))
{ result = eNetworkSDPFileNameInvalidMissing; break; };
// if ('/' == broadcastDefPtr->mDestSDPFile[0])
// { result = eNetworkSDPFileNameInvalidBadPath; break; };
}
result = fStreamSDPParser.ReadSDP(broadcastDefPtr->mSDPFile);
if (result != 0)
{ if (result < 0) { result = eSDPFileNotFound; break; };
if (result > 0) { result = eSDPFileInvalid; break; };
}
fBroadcastDefPtr = broadcastDefPtr;
if (broadcastDefPtr->mTheSession == NULL)
{ if (!broadcastDefPtr->mBasePort) { result = eSDPFileNoPorts; break; };
int portLen = strlen(broadcastDefPtr->mBasePort);
if (0 == portLen) { result = eDescriptionInvalidDestPort; break; };
if (portLen > 5 ) { result = eDescriptionInvalidDestPort; break; };
int basePort = atoi(broadcastDefPtr->mBasePort);
if ( basePort > 65531 ) { result = eDescriptionInvalidDestPort; break; };
if ( basePort < 5004 ) { result = eDescriptionInvalidDestPort; break; };
}
numStreams = fStreamSDPParser.GetNumTracks();
if (numStreams == 0) { result = eSDPFileNoMedia; break; };
UDPSocketPair *socketArrayPtr = fSocketlist.SetSize(numStreams);
if (socketArrayPtr == NULL) { result = eMem; break; };
// Bind SDP file defined ports to active stream ports
{
UInt16 streamIndex = 0;
UInt16 rtpPort = 0;
UInt16 rtcpPort = 0;
TypeMap* mediaTypePtr;
char sdpIPAddress[32];
SimpleString* ipStringPtr = fStreamSDPParser.GetIPString();
if ( (NULL == ipStringPtr) || (ipStringPtr->fLen >= 32) )
{
result = eSDPFileInvalid;
break;
}
memcpy(sdpIPAddress,ipStringPtr->fTheString,ipStringPtr->fLen);
sdpIPAddress[ipStringPtr->fLen] = '\0';
UDPSocketPair *aSocketPair = fSocketlist.Begin();
Bool16 setupUDP = true;
while (aSocketPair != NULL)
{
mediaTypePtr = fStreamSDPParser.fSDPMediaList.SetPos(streamIndex);
if (mediaTypePtr == NULL)
{ result = eSDPFileInvalid;
break;
}
if (broadcastDefPtr->mTheSession != NULL)
{
mediaTypePtr->fPort = broadcastDefPtr->mTheSession->GetStreamDestPort(streamIndex);
//qtss_printf("QTFileBroadcaster::SetUp streamIndex=%u port=%d\n",streamIndex,mediaTypePtr->fPort);
if (BroadcasterSession::kTCPTransportType == broadcastDefPtr->mTheSession->GetTransportType())
{ aSocketPair->SetRTSPSession(broadcastDefPtr->mTheSession, (UInt8) streamIndex * 2);
setupUDP = false;
}
else
{ setupUDP = true;
}
}
if (setupUDP)
{
SInt16 ttl = (SInt16) atoi(broadcastDefPtr->mTTL);
if ( ( ttl > 255 ) || ( ttl < 1 ) )
{ result = eSDPFileInvalidTTL; break;
};
if (mediaTypePtr->fPort == 0)
{
result = eSDPFileInvalidPort;
break;
}
rtpPort = mediaTypePtr->fPort;
rtcpPort = rtpPort + 1;
result = aSocketPair->OpenAndBind(rtpPort,rtcpPort,sdpIPAddress);
if (result != 0)
{
result = eFailedBind;
break;
}
(void) aSocketPair->SetMultiCastOptions(ttl);
}
aSocketPair = fSocketlist.Next();
streamIndex++;
}
if (result != 0)
break;
}
MediaStream *mediaArrayPtr = fMediaStreamList.SetSize(numStreams);
if (mediaArrayPtr == NULL)
{
result = eMem;
break;
}
for (int i = 0; i < numStreams; i ++)
{ UDPSocketPair *socketPairPtr = fSocketlist.SetPos(i);
MediaStream *mediaStreamPtr = fMediaStreamList.SetPos(i);
TypeMap *streamMediaTypePtr = fStreamSDPParser.fSDPMediaList.SetPos(i);
if (socketPairPtr && mediaStreamPtr && streamMediaTypePtr)
{
mediaStreamPtr->fData.fSocketPair = socketPairPtr;
streamMediaTypePtr->fMediaStreamPtr = mediaStreamPtr;
mediaStreamPtr->fData.fStreamMediaTypePtr = streamMediaTypePtr;
}
else
{
result = eMem;
break;
}
}
fMediaStreamList.SetUpStreamSSRCs();
fStreamStartTime = PlayListUtils::Milliseconds();
fMediaStreamList.StreamStarted(fStreamStartTime);
result = 0;
LogFileOpen();
} while (false);
return result;
}
PayLoad * QTFileBroadcaster::FindPayLoad(short id, ArrayList<PayLoad> *PayLoadListPtr)
{
PayLoad *thePayLoadPtr = PayLoadListPtr->Begin();
while (thePayLoadPtr)
{
if (thePayLoadPtr->payloadID == id)
break;
thePayLoadPtr = PayLoadListPtr->Next();
}
return thePayLoadPtr;
}
bool QTFileBroadcaster::CompareRTPMaps(TypeMap *movieMediaTypePtr, TypeMap *streamMediaTypePtr, short moviePayLoadID)
{
bool found = false;
do
{
PayLoad *moviePayLoadPtr = FindPayLoad(moviePayLoadID, &movieMediaTypePtr->fPayLoadTypes);
if (!moviePayLoadPtr) break;
PayLoad *streamPayLoadPtr = streamMediaTypePtr->fPayLoadTypes.Begin();
while (streamPayLoadPtr)
{
if (moviePayLoadPtr->timeScale == streamPayLoadPtr->timeScale)
{ found = SimpleParser::Compare(&moviePayLoadPtr->payLoadString,&streamPayLoadPtr->payLoadString, false );
}
if (found)
{ moviePayLoadPtr->payloadID = streamPayLoadPtr->payloadID; // map movie ID to match stream id
break;
}
streamPayLoadPtr = streamMediaTypePtr->fPayLoadTypes.Next();
}
} while (false);
return found;
}
bool QTFileBroadcaster::CompareMediaTypes(TypeMap *movieMediaTypePtr, TypeMap *streamMediaTypePtr)
{
bool found = false;
found = SimpleParser::Compare(&movieMediaTypePtr->fTheTypeStr,&streamMediaTypePtr->fTheTypeStr, false);
if (found)
{
found = false;
short *movieIDPtr = movieMediaTypePtr->fPayLoads.Begin();
while (movieIDPtr && !found)
{
short *streamIDPtr = streamMediaTypePtr->fPayLoads.Begin();
while (streamIDPtr && !found)
{
if (*movieIDPtr >= 96)
found = CompareRTPMaps(movieMediaTypePtr, streamMediaTypePtr, *movieIDPtr);
else
found = (*streamIDPtr == *movieIDPtr) ? true : false;
streamIDPtr = streamMediaTypePtr->fPayLoads.Next();
}
movieIDPtr = movieMediaTypePtr->fPayLoads.Next();
}
}
return found;
}
int QTFileBroadcaster::MapMovieToStream()
{
int result = -1;
bool matches = false;
ArrayList<bool> map;
bool *isMappedPtr;
int masterPos = 0;
int mappedTracks = 0;
map.SetSize(fStreamSDPParser.fSDPMediaList.Size());
isMappedPtr = map.Begin();
while (isMappedPtr)
{ *isMappedPtr = false;
isMappedPtr = map.Next();
}
TypeMap *movieMediaTypePtr = fMovieSDPParser->fSDPMediaList.Begin();
while (movieMediaTypePtr)
{
TypeMap *streamMediaTypePtr = fStreamSDPParser.fSDPMediaList.Begin();
while (streamMediaTypePtr)
{
matches = CompareMediaTypes(movieMediaTypePtr, streamMediaTypePtr);
if (matches)
{
masterPos = fStreamSDPParser.fSDPMediaList.GetPos();
isMappedPtr = map.SetPos(masterPos);
if (isMappedPtr == NULL)
break;
if (false == *isMappedPtr)
{
movieMediaTypePtr->fMediaStreamPtr = streamMediaTypePtr->fMediaStreamPtr;
*isMappedPtr = true;
mappedTracks++;
break;
}
}
streamMediaTypePtr = fStreamSDPParser.fSDPMediaList.Next();
}
movieMediaTypePtr = fMovieSDPParser->fSDPMediaList.Next();
}
result = mappedTracks;
return result;
}
UInt32 QTFileBroadcaster::GetSDPTracks(QTRTPFile *newRTPFilePtr)
{
char* sdpBuffer;
int bufferLen = 0;
UInt32 result = 0;
sdpBuffer = newRTPFilePtr->GetSDPFile(&bufferLen);
fMovieSDPParser->ParseSDP(sdpBuffer);
result = fMovieSDPParser->GetNumTracks();
return result;
}
int QTFileBroadcaster::AddTrackAndStream(QTRTPFile *newRTPFilePtr)
{
TypeMap* movieMediaTypePtr = fMovieSDPParser->fSDPMediaList.Begin();
UInt32 trackID;
char* cookie;
int err = -1;
while (movieMediaTypePtr)
{
if (movieMediaTypePtr->fMediaStreamPtr != NULL)
{
trackID = movieMediaTypePtr->fTrackID;
if (trackID == 0) break;
movieMediaTypePtr->fMediaStreamPtr->fData.fMovieMediaTypePtr = movieMediaTypePtr;
movieMediaTypePtr->fMediaStreamPtr->fData.fRTPFilePtr = newRTPFilePtr;
movieMediaTypePtr->fMediaStreamPtr->fSend = fSend;
cookie = (char *) movieMediaTypePtr->fMediaStreamPtr;
err = newRTPFilePtr->AddTrack(trackID, false);
if (err != 0)
break;
newRTPFilePtr->SetTrackCookies(trackID, cookie, 0);
newRTPFilePtr->SetTrackSSRC(trackID, (UInt32) 0); // set later
err = newRTPFilePtr->Seek(0.0);
if (err != QTRTPFile::errNoError)
break;
}
movieMediaTypePtr = fMovieSDPParser->fSDPMediaList.Next();
}
return err;
}
int QTFileBroadcaster::SetUpAMovie(char *theMovieFileName)
{
int err = -1;
QTRTPFile *newRTPFilePtr = NULL;
do {
fMovieTracks = 0;
fMappedMovieTracks = 0;
if (fMovieSDPParser != NULL) delete fMovieSDPParser;
if (fRTPFilePtr != NULL) delete fRTPFilePtr;
fMovieSDPParser = NULL;
fRTPFilePtr = NULL;
if (!theMovieFileName) { err = eMovieFileInvalidName; break; }
int nameLen = strlen(theMovieFileName);
if (nameLen > 255) { err = eMovieFileInvalidName; break; }
if (0 == nameLen) { err = eMovieFileInvalidName; break; }
fMovieSDPParser = new SDPFileParser;
if (NULL == fMovieSDPParser) { err = eMem; break;}
newRTPFilePtr = new QTRTPFile();
if (NULL == newRTPFilePtr) { err = eMem; break;}
QTRTPFile::ErrorCode result = newRTPFilePtr->Initialize(theMovieFileName);
err = EvalErrorCode(result);
if (err) break;
fMovieTracks = GetSDPTracks(newRTPFilePtr);
if (fMovieTracks < 1) { err = eMovieFileNoHintedTracks; break; }
fMappedMovieTracks = MapMovieToStream();
if (fMappedMovieTracks < 1) { err = eMovieFileNoSDPMatches; break; }
err = AddTrackAndStream(newRTPFilePtr);
if (err != 0) { err = eMovieFileInvalid; break; }
} while (false);
if (err)
{ if (newRTPFilePtr)
delete newRTPFilePtr;
newRTPFilePtr = NULL;
}
fRTPFilePtr = newRTPFilePtr;
return err;
}
void QTFileBroadcaster::MilliSleep(SInt32 sleepTimeMilli)
{
if (sleepTimeMilli > 0)
{
#if __solaris__
struct timeval tv;
::memset(&tv,0,sizeof(tv));
tv.tv_usec = sleepTimeMilli * 1000;
::select(0,NULL,NULL,NULL,&tv);
#else
OSThread::Sleep( (UInt32) sleepTimeMilli);
#endif
}
}
Float64 QTFileBroadcaster::Sleep(Float64 transmitTimeMilli)
{
Float64 sleepTime;
Float64 timeToSend;
Float64 currentTime = (Float64) PlayListUtils::Milliseconds();
if (fMovieStart)
{
fMovieStart = false;
}
timeToSend = fMovieStartTime + transmitTimeMilli;
sleepTime = timeToSend - currentTime;
const Float64 maxSleepIntervalMilli = 100.0;
const Float64 minSleepIntervalMilli = 1.0;
Float64 intervalTime = sleepTime;
SInt32 sleepMilli = 0;
if (intervalTime > maxSleepIntervalMilli)
{ while (intervalTime >= maxSleepIntervalMilli)
{
intervalTime -= maxSleepIntervalMilli;
sleepMilli = (SInt32) maxSleepIntervalMilli;
MilliSleep(sleepMilli);
fMediaStreamList.UpdateSenderReportsOnStreams();
//qtss_printf("sleepIntervalMilli %u \n",sleepMilli);
}
}
if (intervalTime >= minSleepIntervalMilli)
{ sleepMilli = (SInt32) intervalTime;
MilliSleep(sleepMilli);
//qtss_printf("sleepMilli %u \n",sleepMilli);
}
fMediaStreamList.UpdateSenderReportsOnStreams();
return sleepTime;
}
/* changed by emil@popwire.com (see relaod.txt for info) */
int QTFileBroadcaster::Play(char *mTimeFile)
/* ***************************************************** */
{
SInt16 err = 0;
Float64 transmitTime = 0;
MediaStream *theStreamPtr = NULL;
RTpPacket rtpPacket;
unsigned int sleptTime;
SInt32 movieStartOffset = 0; //z
Bool16 negativeTime = false;
fMovieDuration = fRTPFilePtr->GetMovieDuration();
fSendTimeOffset = 0.0;
fMovieStart = true;
fNumMoviesPlayed ++;
if (fMovieEndTime > 0) // take into account the movie load time as well as the last movie early end.
{ UInt64 timeNow = PlayListUtils::Milliseconds();
fMovieIntervalTime = timeNow - fMovieEndTime;
SInt32 earlySleepTimeMilli = (SInt32)(fMovieTimeDiffMilli - fMovieIntervalTime);
earlySleepTimeMilli -= 40; // Don't sleep the entire time we need some time to execute or else we will be late
if (earlySleepTimeMilli > 0)
{ OSThread::Sleep( earlySleepTimeMilli);
}
}
fMovieStartTime = PlayListUtils::Milliseconds();
fMediaStreamList.MovieStarted(fMovieStartTime);
/* changed by emil@popwire.com (see relaod.txt for info) */
if(mTimeFile!=NULL)
{
FILE *fTimeFile = NULL;
struct timeval start, dur, end;
struct tm tm_start, tm_dur, tm_end, timeResult;
memset (&start,0, sizeof(start));
SInt64 timenow = OS::Milliseconds();
start.tv_sec = (SInt32) OS::TimeMilli_To_UnixTimeSecs(timenow);
start.tv_usec = (SInt32) ((OS::TimeMilli_To_UnixTimeMilli(timenow) - (start.tv_sec * 1000)) * 1000);
dur.tv_sec = (SInt32)fMovieDuration;
dur.tv_usec = (SInt32)((fMovieDuration - dur.tv_sec) * 1000000);
end.tv_sec = start.tv_sec + dur.tv_sec + (SInt32)((start.tv_usec + dur.tv_usec) / 1000000);
end.tv_usec = (start.tv_usec + dur.tv_usec) % 1000000;
time_t startSecs = start.tv_sec;
time_t endSecs = end.tv_sec;
memcpy(&tm_start, qtss_localtime(&startSecs, &timeResult), sizeof(struct tm));
memcpy(&tm_end, qtss_localtime(&endSecs, &timeResult), sizeof(struct tm));
tm_dur.tm_hour = dur.tv_sec / 3600;
tm_dur.tm_min = (dur.tv_sec % 3600) / 60;
tm_dur.tm_sec = (dur.tv_sec % 3600) % 60;
// initialize all current movie parameters to unkown ("-").
::strcpy(fCurrentMovieName, "-");
::strcpy(fCurrentMovieCopyright, "-");
::strcpy(fCurrentMovieComment, "-");
::strcpy(fCurrentMovieAuthor, "-");
::strcpy(fCurrentMovieArtist, "-");
::strcpy(fCurrentMovieAlbum, "-");
/* save start time, stop time and length of currently playing song to .current file */
fTimeFile = fopen(mTimeFile, "a");
if(fTimeFile)
{
SimpleString *theQTTextPtr = fMovieSDPParser->fQTTextLines.Begin();
while (theQTTextPtr != NULL)
{
char tmp[256];
::memcpy(tmp, theQTTextPtr->fTheString, theQTTextPtr->fLen);
tmp[theQTTextPtr->fLen] = 0;
// if this SDP parameter is needed for logging then cache it here so
// we can log it later.
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-nam:")!=NULL)
::strcpy(fCurrentMovieName, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-cpy:")!=NULL)
::strcpy(fCurrentMovieCopyright, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-cmt:")!=NULL)
::strcpy(fCurrentMovieComment, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-aut:")!=NULL)
::strcpy(fCurrentMovieAuthor, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-ART:")!=NULL)
::strcpy(fCurrentMovieArtist, &tmp[16]);
if (::strstr(theQTTextPtr->fTheString, "a=x-qt-text-alb:")!=NULL)
::strcpy(fCurrentMovieAlbum, &tmp[16]);
fwrite(theQTTextPtr->fTheString,theQTTextPtr->fLen, sizeof(char),fTimeFile);
qtss_fprintf(fTimeFile,"\n");
theQTTextPtr = fMovieSDPParser->fQTTextLines.Next();
}
time_t startTime = (time_t) start.tv_sec;
time_t endTime = (time_t) end.tv_sec;
char buffer[kTimeStrSize];
char *timestringStart = qtss_ctime(&startTime, buffer, sizeof(buffer));
qtss_fprintf(fTimeFile,"b=%02d:%02d:%02d:%06d %"_S32BITARG_" %s", (int) tm_start.tm_hour, (int) tm_start.tm_min, (int) tm_start.tm_sec, (int)start.tv_usec, (SInt32) startTime, timestringStart);
char *timestringEnd = qtss_ctime(&endTime, buffer, sizeof(buffer));
qtss_fprintf(fTimeFile,"e=%02d:%02d:%02d:%06d %"_S32BITARG_" %s", (int)tm_end.tm_hour, (int) tm_end.tm_min,(int) tm_end.tm_sec, (int) end.tv_usec,(SInt32) endTime, timestringEnd);
qtss_fprintf(fTimeFile,"d=%02d:%02d:%02d:%06d %d \n", (int) tm_dur.tm_hour, (int) tm_dur.tm_min,(int) tm_dur.tm_sec, (int) dur.tv_usec, (int)dur.tv_sec);
fclose(fTimeFile);
}
}
while (true)
{
if (fQuitImmediatePtr && *fQuitImmediatePtr){err = 0; break; } // quit now not an error
if (fBroadcastDefPtr->mTheSession)
{ UInt32 thePacketQLen = 0;
thePacketQLen = fBroadcastDefPtr->mTheSession->GetPacketQLen();
SInt64 maxSleep = PlayListUtils::Milliseconds() + 1000;
if (thePacketQLen > eMaxPacketQLen)
{ //qtss_printf("PacketQ too big = %"_U32BITARG_" \n", (UInt32) thePacketQLen);
while ( (eMaxPacketQLen/2) < fBroadcastDefPtr->mTheSession->GetPacketQLen())
{ this->SleepInterval(100.0);
if (maxSleep < PlayListUtils::Milliseconds())
break;
}
//qtss_printf("PacketQ after sleep = %"_U32BITARG_" \n", (UInt32) fBroadcastDefPtr->mTheSession->GetPacketQLen());
continue;
}
}
transmitTime = fRTPFilePtr->GetNextPacket(&rtpPacket.fThePacket, &rtpPacket.fLength);
theStreamPtr = (MediaStream*)fRTPFilePtr->GetLastPacketTrack()->Cookie1;
err = fRTPFilePtr->Error();
if (err != QTRTPFile::errNoError) {err = eMovieFileInvalid; break; } // error getting packet
if (NULL == rtpPacket.fThePacket) {err = 0; break; } // end of movie not an error
if (NULL == theStreamPtr) {err = eMovieFileInvalid; break; }// an error
transmitTime *= (Float64) PlayListUtils::eMilli; // convert to milliseconds
if (transmitTime < 0.0 && negativeTime == false) // Deal with negative transmission times
{ movieStartOffset += (SInt32) (transmitTime / 15.0);
negativeTime = true;
}
sleptTime = (unsigned int) Sleep(transmitTime);
err = theStreamPtr->Send(&rtpPacket);
if (err != 0) { break; }
err = fMediaStreamList.UpdateStreams();
if (err != 0) { break; }
if ( (fBroadcastDefPtr != NULL)
&& (fBroadcastDefPtr->mTheSession != NULL)
&& (fBroadcastDefPtr->mTheSession->GetReasonForDying() != BroadcasterSession::kDiedNormally)
)
{ break; }
};
fMovieEndTime = (SInt64) PlayListUtils::Milliseconds();
fMediaStreamList.MovieEnded(fMovieEndTime);
// see if the movie duration is greater than the time it took to send the packets.
// the difference is a delay that we insert before playing the next movie.
SInt64 playDurationMilli = (SInt64) fMovieEndTime - (SInt64) fMovieStartTime;
fMovieTimeDiffMilli = ((SInt64) ( (Float64) fMovieDuration * (Float64) PlayListUtils::eMilli)) - (SInt64) playDurationMilli;
fMovieTimeDiffMilli-= (movieStartOffset/2);
return err;
}
/* changed by emil@popwire.com (see relaod.txt for info) */
int QTFileBroadcaster::PlayMovie(char *movieFileName, char *currentFile)
/* ***************************************************** */
{
int err = eMovieFileInvalidName;
if (movieFileName != NULL)
{
err = SetUpAMovie(movieFileName);
if (!err && fPlay)
/* changed by emil@popwire.com (see relaod.txt for info) */
{ err = Play(currentFile);
/* ***************************************************** */
}
}
return err;
}
int QTFileBroadcaster::EvalErrorCode(QTRTPFile::ErrorCode err)
{
int result = eNoErr;
switch( err )
{
case QTRTPFile::errNoError:
break;
case QTRTPFile::errFileNotFound:
result = eMovieFileNotFound;
break;
case QTRTPFile::errNoHintTracks:
result = eMovieFileNoHintedTracks;
break;
case QTRTPFile::errInvalidQuickTimeFile:
result = eMovieFileInvalid;
break;
case QTRTPFile::errInternalError:
result = eInternalError;
break;
default:
result = eInternalError;
}
return result;
}

View file

@ -0,0 +1,168 @@
/*
*
* @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@
*
*/
/* contributions by emil@popwire.com
*/
#ifndef playlist_broadcaster_H
#define playlist_broadcaster_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#include "OSHeaders.h"
#include "playlist_utils.h"
#include "playlist_elements.h"
#include "playlist_lists.h"
#include "playlist_parsers.h"
#include "QTRTPFile.h"
#include "PLBroadcastDef.h"
#ifndef __Win32__
#include <sys/types.h>
#include <fcntl.h>
#endif
static PlayListUtils gUtils;
class QTFileBroadcaster
{
protected:
QTRTPFile *fRTPFilePtr ;
SDPFileParser fStreamSDPParser;
SDPFileParser *fMovieSDPParser;
SocketList fSocketlist;
MediaStreamList fMediaStreamList;
int fBasePort;
bool fDebug;
bool fDeepDebug;
bool *fQuitImmediatePtr;
// transmit time trackers
Float64 fLastTransmitTime;
SInt64 fStreamStartTime;
SInt64 fMovieStartTime;
SInt64 fMovieEndTime;
SInt64 fMovieIntervalTime;
SInt64 fMovieTimeDiffMilli;
bool fMovieStart;
Float64 fSendTimeOffset;
Float64 fMovieDuration;
int fMovieTracks;
int fMappedMovieTracks;
UInt64 fNumMoviesPlayed;
PayLoad * FindPayLoad(short id, ArrayList<PayLoad> *PayLoadListPtr);
bool CompareRTPMaps(TypeMap *movieMediaTypePtr, TypeMap *streamMediaTypePtr, short id);
bool CompareMediaTypes(TypeMap *movieMediaTypePtr, TypeMap *streamMediaTypePtr);
UInt32 GetSDPTracks(QTRTPFile *newRTPFilePtr);
int SetUpAMovie(char *movieFileName);
int AddTrackAndStream(QTRTPFile *newRTPFilePtr);
int MapMovieToStream();
int Play(char *mTimeFile);
Float64 SleepInterval(Float64 sleepTime) { return Sleep( (Float64) (PlayListUtils::Milliseconds() - fMovieStartTime) + sleepTime); };
Float64 Sleep(Float64 transmitTime);
void SetDebug(bool debug) {fDebug = debug;};
void SetDeepDebug(bool debug) {fDeepDebug = debug;};
PLBroadcastDef *fBroadcastDefPtr;
public:
QTFileBroadcaster();
~QTFileBroadcaster();
static int EvalErrorCode(QTRTPFile::ErrorCode err);
int SetUp(PLBroadcastDef *broadcastDefPtr, bool *quitImmediatePtr);
int PlayMovie(char *movieFileName, char *currentFile);
int GetMovieTrackCount() { return fMovieTracks; };
int GetMappedMovieTrackCount() { return fMappedMovieTracks; };
void MilliSleep(SInt32 sleepTimeMilli);
bool fPlay;
bool fSend;
enum { eClientBufferSecs = 0,
eMaxPacketQLen = 200
};
enum ErrorID
{ // General errors
eNoErr = 0
,eParam
,eMem
,eInternalError
,eFailedBind
// Setup Errors
,eNoAvailableSockets
,eSDPFileNotFound
,eSDPDestAddrInvalid
,eSDPFileInvalid
,eSDPFileNoMedia
,eSDPFileNoPorts
,eSDPFileInvalidPort
,eSDPFileInvalidName
,eSDPFileInvalidTTL
// eMem also
// Play Errors,
,eMovieFileNotFound
,eMovieFileNoHintedTracks
,eMovieFileNoSDPMatches
,eMovieFileInvalid
,eMovieFileInvalidName
,eNetworkConnectionError
,eNetworkRequestError
,eNetworkConnectionStopped
,eNetworkAuthorization
,eNetworkNotSupported
,eNetworkSDPFileNameInvalidMissing
,eNetworkSDPFileNameInvalidBadPath
,eNetworkConnectionFailed
,eDescriptionInvalidDestPort
};
char fCurrentMovieName[256];
char fCurrentMovieCopyright[256];
char fCurrentMovieComment[256];
char fCurrentMovieAuthor[256];
char fCurrentMovieArtist[256];
char fCurrentMovieAlbum[256];
private:
};
#endif //playlist_broadcaster_H

View 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;
}

View file

@ -0,0 +1,327 @@
/*
*
* @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@
*
*/
#ifndef playlist_elements_H
#define playlist_elements_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#ifndef __Win32__
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#endif
#include "playlist_array.h"
#include "OSHeaders.h"
#include "playlist_SimpleParse.h"
#include "QTRTPFile.h"
#include "BroadcasterSession.h"
class MediaStream;
struct SoundDescription {
SInt32 descSize; /* total size of SoundDescription including extra data */
SInt32 dataFormat; /* sound format */
SInt32 resvd1; /* reserved for apple use. set to zero */
SInt16 resvd2; /* reserved for apple use. set to zero */
SInt16 dataRefIndex;
SInt16 version; /* which version is this data */
SInt16 revlevel; /* what version of that codec did this */
SInt32 vendor; /* whose codec compressed this data */
SInt16 numChannels; /* number of channels of sound */
SInt16 sampleSize; /* number of bits per sample */
SInt16 compressionID; /* unused. set to zero. */
SInt16 packetSize; /* unused. set to zero. */
UInt32 sampleRate; /* sample rate sound is captured at */
};
class PayLoad {
public:
PayLoad(void) : payloadID(0), timeScale(1) {};
int payloadID;
SimpleString payLoadString;
UInt32 timeScale;
};
class TypeMap {
public:
TypeMap(void) : fMediaStreamPtr(0), fTrackID(0), fPort(0), fTimeScale(1) {};
~TypeMap() { } ;
MediaStream *fMediaStreamPtr;
int fTrackID;
int fPort;
UInt32 fTimeScale;
SimpleString fTheTypeStr;
SimpleString fProtocolStr;
ArrayList<PayLoad> fPayLoadTypes;
ArrayList<SInt16> fPayLoads;
};
class RTpPacket
{
struct SoundHeader {
char bytes[4];
SInt32 skip1;
char sndtype[4];
SInt32 skip2;
char test[4];
};
public:
enum { kRTpHeaderSize = 12 };
char *fThePacket;
int fLength;
bool fHasSoundDescription;
SInt32 fSoundDescriptionLen;
RTpPacket() : fThePacket(NULL), fLength(0), fHasSoundDescription(false), fSoundDescriptionLen(0) {};
void SetPacketData(char *thePacket, int length) {fThePacket = thePacket; fLength = length; };
SInt16 SetHeaderInfo( UInt32 timeStamp, UInt16 sequence,UInt32 SSRC,unsigned char payloadType);
SInt16 GetHeaderInfo( UInt32 *timeStampPtr, UInt16 *sequencePtr,UInt32 *SSRCPtr,unsigned char*payloadType);
bool HasSoundDescription();
SInt16 GetSoundDescriptionRef(SoundDescription **soundDescriptionPtr);
protected:
enum { cSequenceNumber = 1, cTimeStamp = 1, cSSRC = 2, cPayloadType = 1};
};
class UDPSocketPair
{
public:
enum
{
kBound = 1L << 0,
kConnected = 1L << 1
};
enum { eBindMaxTries = 100,
eSourcePortStart = 49152, // rtp + rtcp
eSourcePortRange = 65535 // 49152,49153 - 65534,65535
};
enum
{
kInvalidSocket = -1, //int
kPortRTCpufSizeInBytes = 8, //UInt32
kMaxIPAddrSizeInBytes = 20 //UInt32
};
int fMaxBindAttempts;
int fState;
int fSocketRTp;
struct sockaddr_in fLocalAddrRTp;
struct sockaddr_in fDestAddrRTp;
int fSocketRTCp;
struct sockaddr_in fLocalAddrRTCp;
struct sockaddr_in fDestAddrRTCp;
BroadcasterSession *fBroadcasterSession;
UInt8 fChannel;
Bool16 fIsMultiCast;
Bool16 fMultiCastJoined;
UDPSocketPair() : fMaxBindAttempts(eBindMaxTries),
fState(0),
fSocketRTp(0),
fSocketRTCp(0),
fBroadcasterSession(NULL),
fChannel(0),
fIsMultiCast(false),
fMultiCastJoined(false)
{};
~UDPSocketPair() { Close(); };
SInt16 Open();
void Close();
void InitPorts(UInt32 addr);
SInt16 Bind(UInt32 addr);
SInt16 OpenAndBind( UInt16 rtpPort,UInt16 rtcpPort,char *destAddress);
SInt16 SetDestination (char *destAddress,UInt16 destPortRTp, UInt16 destPortRTCp);
SInt16 SetTTL(SInt16 timeToLive);
SInt16 JoinMulticast();
SInt16 LeaveMulticast();
SInt16 SetMulticastInterface();
SInt16 SetMultiCastOptions(SInt16 ttl);
SInt16 SendTo(int socket, sockaddr *destAddrPtr, char* inBuffer, UInt32 inLength );
SInt16 SendRTp(char* inBuffer, UInt32 inLength);
SInt16 SendRTCp(char* inBuffer, UInt32 inLength);
SInt16 RecvFrom(sockaddr *recvAddrPtr, int socket, char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
SInt16 RecvRTp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
SInt16 RecvRTCp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen);
void SetRTSPSession(BroadcasterSession *theSession,UInt8 channel) {fBroadcasterSession = theSession, fChannel=channel;}
};
class ReceiveBuffer
{
public:
enum { kReadBufferSize = 256 }; //UInt32
char fReadBuffer[kReadBufferSize];
UInt32 fReceiveLen;
};
class MediaStream
{
protected:
int SendRTp(RTpPacket *packet);
int CalcRTCps();
int SendRTCp_SenderReport();
static UInt32 GetACName(char* ioCNameBuffer);
void MapToStream(UInt32 curRTpTimeStamp, UInt16 curRTpSequenceNumber, unsigned char curPayload, UInt32 *outRTpTimeStampPtr, UInt16 *outRTpSequenceNumberPtr, unsigned char *outPayloadPtr);
void UpdatePacketInStream(RTpPacket *packetPtr);
SInt16 Accounting(RTpPacket *packetPtr);
void BuildStaticRTCpReport();
void InitIfAudio();
void TestAndIncSoundDescriptor(RTpPacket *packetPtr);
public:
enum { kMaxCNameLen = 20 }; //UInt32
enum { eMaxSoundDescriptionSize = 1024};
enum {
kSenderReportSizeInBytes = 36, //UInt32
kMaxRTCpPacketSizeInBytes = 1024, //All are UInt32s
kMaxSsrcSizeInBytes = 25,
kSenderReportIntervalInSecs = 5
};
enum {
eSocketNotOpen,
eSocketFailed
};
struct MemberData {
ReceiveBuffer fPortRTpReadBuff;
ReceiveBuffer fPortRTCpReadBuff;
UInt64 fRTCpTimer;
SInt16 fState;
UInt64 fBytesSent;
UInt64 fPacketsSent;
SInt64 fStreamStartTime;
SInt64 fNTPPlayTime;
char fSenderReportBuffer[kSenderReportSizeInBytes + kMaxCNameLen];
UInt32 fSenderReportSize;
//who am i sending to?
UInt16 fRemoteRTpPort;
UInt16 fRemoteRTCpPort;
//RTCp stuff
SInt64 fLastSenderReportTime;
UInt32 fPacketCount;
UInt32 fByteCount;
Bool16 fSenderReportReady;
UInt32 fLastTimeStamp;
// current RTP packet info
UInt32 fLastTimeStampOffset;
UInt32 fTimeStamp;
UInt32 fSsrc;
UInt16 fLastSequenceNumber;
UInt32 fInitSSRC; // initial SSRC
UInt64 fCurStreamRTpSequenceNumber; // now
TypeMap *fStreamMediaTypePtr;
TypeMap *fMovieMediaTypePtr;
SInt64 fMovieStartTime;
SInt64 fMovieEndTime;
Float64 fLastMovieDurationSecs;
UInt64 fMediaStartOffsetMediaScale;
UInt64 fMovieStartOffset;
UInt32 fSeqRandomOffset;
UInt32 fRTpRandomOffset;
bool fNewMovieStarted;
bool fNewStreamStarted;
bool fIsSoundStream;
bool fIsVideoStream;
char *fSoundDescriptionBuffer;
SInt32 fSavedSoundDescSize;
SInt16 fSavedDataRefIndex;
UDPSocketPair *fSocketPair;
QTRTPFile *fRTPFilePtr;
};
MemberData fData;
bool fSend;
~MediaStream();
MediaStream();
char* GetRTCpSR() { return fData.fSenderReportBuffer; }
UInt32 GetRTCpSRLen() { return fData.fSenderReportSize; }
SInt64 GetPlayTime() { return fData.fStreamStartTime; }
SInt64 GetNTPPlayTime() { return fData.fNTPPlayTime; }
SInt16 Send(RTpPacket *packetPtr);
void ReceiveOnPorts();
int UpdateSenderReport(SInt64 theTime);
void StreamStart(SInt64 startTime);
void MovieStart(SInt64 startTime);
void MovieEnd(SInt64 endTime);
};
#endif // playlist_elements_H

View file

@ -0,0 +1,115 @@
/*
*
* @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_lists.h"
#include "OS.h"
#include "playlist_utils.h"
// ************************
//
// MEDIA STREAM LIST
//
// ************************
void MediaStreamList::SetUpStreamSSRCs()
{
UInt32 ssrc;
MediaStream* setMediaStreamPtr;
MediaStream* aMediaStreamPtr;
bool found_duplicate;
for (int i = 0; i < Size(); i++)
{
setMediaStreamPtr = SetPos(i);
if (setMediaStreamPtr != NULL) do
{
ssrc = PlayListUtils::Random() + ( (UInt32) OS::Milliseconds() ); // get a new ssrc
aMediaStreamPtr = Begin(); // start at the beginning of the stream list
found_duplicate = false; // default is don't loop
while (aMediaStreamPtr != NULL) //check all the streams for a duplicate
{
if (aMediaStreamPtr->fData.fInitSSRC == ssrc) // it is a duplicate
{ found_duplicate = true; // set to loop: try a new ssrc
break;
}
aMediaStreamPtr = Next(); // keep checking for a duplicate
}
if (!found_duplicate) // no duplicates found so keep this ssrc
setMediaStreamPtr->fData.fInitSSRC = ssrc;
} while (found_duplicate); // we have a duplicate ssrc so find another one
}
}
void MediaStreamList::StreamStarted(SInt64 startTime)
{
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
theStreamPtr->StreamStart(startTime);
}
}
void MediaStreamList::MovieStarted(SInt64 startTime)
{
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
theStreamPtr->MovieStart(startTime);
}
}
void MediaStreamList::MovieEnded(SInt64 endTime)
{
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
theStreamPtr->MovieEnd(endTime);
}
}
SInt16 MediaStreamList::UpdateStreams()
{
SInt16 err = 0;
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
theStreamPtr->ReceiveOnPorts();
};
return err;
}
void MediaStreamList::UpdateSenderReportsOnStreams()
{
SInt64 theTime = PlayListUtils::Milliseconds();
for ( MediaStream *theStreamPtr = Begin(); (theStreamPtr != NULL) ; theStreamPtr = Next() )
{
(void) theStreamPtr->UpdateSenderReport(theTime);
};
}

View file

@ -0,0 +1,91 @@
/*
*
* @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@
*
*/
#ifndef playlist_lists_H
#define playlist_lists_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#ifndef __Win32__
#include <sys/types.h>
#include <fcntl.h>
#endif
#include "OSHeaders.h"
#include "playlist_array.h"
#include "playlist_elements.h"
#include "playlist_utils.h"
// ************************
//
// SOCKET LIST
//
// ************************
class SocketList : public ArrayList<UDPSocketPair> {
};
// ************************
//
// MEDIA STREAM LIST
//
// ************************
class MediaStreamList : public ArrayList<MediaStream> {
protected:
public:
SInt16 UpdateStreams();
void UpdateSenderReportsOnStreams();
void SetUpStreamSSRCs();
void StreamStarted(SInt64 startTime);
void MovieStarted(SInt64 startTime);
void MovieEnded(SInt64 endTime);
};
// ************************
//
// SDP MEDIA LIST
//
// ************************
class SDPMediaList : public ArrayList<TypeMap> {
};
#endif //playlist_lists_H

View file

@ -0,0 +1,540 @@
/*
*
* @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_parsers.h"
char* SDPFileParser::sMediaTag = "m";
char* SDPFileParser::sAttributeTag = "a";
char* SDPFileParser::sConnectionTag = "c";
SDPFileParser::~SDPFileParser()
{
if (fSDPBuff)
{ delete[] fSDPBuff;
fSDPBuff = NULL;
}
}
bool SDPFileParser::IsCommented(SimpleString *theString)
{
if ( NULL == theString) return false;
if ( theString->fLen == 0) return false;
if ( theString->fTheString[0] == '#' ) return true; // It's commented if the first non-white char is #
return false;
}
int TextLine::Parse (SimpleString *textStrPtr)
{
short count = 0;
do
{
if (!textStrPtr) break;
count = CountDelimeters(textStrPtr,sWordDelimeters);
if (count < 1) break;
fWords.SetSize(count);
fSource = *textStrPtr;
SimpleString *listStringPtr = fWords.Begin();
SimpleString currentString;
currentString.SetString(textStrPtr->fTheString, 0);
for ( short i = 0; i < count; i ++)
{ GetNextThing(textStrPtr,&currentString, sWordDelimeters, &currentString);
*listStringPtr = currentString;
listStringPtr++;
}
} while (false);
return count;
}
int LineAndWordsParser::Parse (SimpleString *textStrPtr)
{
short count = 0;
do
{
if (!textStrPtr) break;
count = CountDelimeters(textStrPtr,sLineDelimeters);
if (count < 1) break;
fLines.SetSize(count);
fSource = *textStrPtr;
TextLine *listStringPtr = fLines.Begin();
SimpleString currentString;
currentString.SetString(textStrPtr->fTheString, 0);
for ( short i = 0; i < count; i ++)
{ GetNextThing(textStrPtr,&currentString, sLineDelimeters, &currentString);
listStringPtr->Parse(&currentString);
listStringPtr++;
}
} while (false);
return count;
}
short SDPFileParser::CountQTTextLines()
{
short numlines = 0;
TextLine *theLinePtr = fParser.fLines.Begin();
while (theLinePtr)
{ if (GetQTTextFromLine(theLinePtr))
numlines ++;
theLinePtr = fParser.fLines.Next();
};
return numlines;
}
short SDPFileParser::CountMediaEntries()
{
bool commented = false;
bool isEqual = false;
short numTracks = 0;
TextLine *theLinePtr = fParser.fLines.Begin();
SimpleString *firstWordPtr;
while (theLinePtr)
{
do
{ firstWordPtr = theLinePtr->fWords.Begin();
if (!firstWordPtr) break;
commented = IsCommented(firstWordPtr);
if (commented) break;
isEqual = Compare(firstWordPtr, SDPFileParser::sMediaTag, true);
if (!isEqual) break;
numTracks ++;
} while (false);
theLinePtr = fParser.fLines.Next();
};
return numTracks;
}
short SDPFileParser::CountRTPMapEntries()
{
short startPos = fParser.fLines.GetPos();
short result = 0;
TextLine *theLinePtr = fParser.fLines.Get();
SimpleString mapString("rtpmap");
SimpleString *aWordPtr;
bool isEqual;
while (theLinePtr)
{
aWordPtr = theLinePtr->fWords.Begin();
if (aWordPtr)
{
isEqual = Compare(aWordPtr, SDPFileParser::sAttributeTag, true);
if (isEqual) // see if this attribute is a rtpmap line
{
aWordPtr = theLinePtr->fWords.SetPos(1);
isEqual = Compare(aWordPtr, &mapString, false);
if (isEqual) result ++;
}
else // could be a comment or some other attribute
{ isEqual = Compare(aWordPtr, SDPFileParser::sMediaTag, true);
if (isEqual) break; // its another media line so stop
}
}
theLinePtr = fParser.fLines.Next();
};
fParser.fLines.SetPos(startPos);
return result;
}
void SDPFileParser::GetPayLoadsFromLine(TextLine *theLinePtr, TypeMap *theTypeMapPtr)
{
short count = 0;
if (theLinePtr == NULL || theTypeMapPtr == NULL)
return;
SimpleString *aWordPtr = theLinePtr->fWords.SetPos(5);// get protocol ID str
while (aWordPtr)
{ count ++;
aWordPtr = theLinePtr->fWords.Next();// get next protocol ID str
}
theTypeMapPtr->fPayLoads.SetSize(count);
short* idPtr = theTypeMapPtr->fPayLoads.Begin();// get protocol ID ref
aWordPtr = theLinePtr->fWords.SetPos(5);// get protocol ID str
while (aWordPtr && idPtr)
{
*idPtr = (short) aWordPtr->GetInt();
aWordPtr = theLinePtr->fWords.Next();// get next protocol ID str
idPtr = theTypeMapPtr->fPayLoads.Next();// get next protocol ID ref
}
}
bool SDPFileParser::GetQTTextFromLine(TextLine *theLinePtr)
{
//a=x-qt-text-cpy:xxxxx
//a=x-qt-text-nam:xxxxxx
//a=x-qt-text-inf:xxxxxxx
bool result = false;
SimpleString *aWordPtr;
char *xString ="a=x-qt-text";
do
{
aWordPtr = theLinePtr->fWords.Begin();
if (!aWordPtr) break;
bool isEqual = (0 == strncmp(aWordPtr->fTheString, xString,strlen(xString) ) ) ? true: false;
if (!isEqual) break;
result = true;
} while (false);
return result;
}
bool SDPFileParser::GetMediaFromLine(TextLine *theLinePtr, TypeMap *theTypeMapPtr)
{
bool result = false;
SimpleString *aWordPtr;
do
{
aWordPtr = theLinePtr->fWords.Begin();
if (!aWordPtr) break;
bool isEqual = Compare(aWordPtr, SDPFileParser::sMediaTag, true);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(1);// get type
if (!aWordPtr) break;
theTypeMapPtr->fTheTypeStr = *aWordPtr;
aWordPtr = theLinePtr->fWords.SetPos(2);// get movie port
if (!aWordPtr) break;
theTypeMapPtr->fPort = aWordPtr->GetInt();
aWordPtr = theLinePtr->fWords.SetPos(3);// get protocol
if (!aWordPtr) break;
theTypeMapPtr->fProtocolStr = *aWordPtr;
GetPayLoadsFromLine(theLinePtr, theTypeMapPtr);
result = true;
} while (false);
return result;
}
bool SDPFileParser::GetRTPMap(TextLine *theLinePtr,PayLoad *payloadPtr)
{
bool lineOK = false;
SimpleString *aWordPtr;
SimpleString mapString("rtpmap");
do
{
if (!theLinePtr || !payloadPtr) break;
aWordPtr = theLinePtr->fWords.SetPos(1); // the attribute name
if (!aWordPtr) break;
if (!Compare(aWordPtr, &mapString, false))
break;
aWordPtr = theLinePtr->fWords.Next(); // the Payload ID
if (!aWordPtr) break;
payloadPtr->payloadID = aWordPtr->GetInt();
aWordPtr = theLinePtr->fWords.Next(); // the Payload type string
if (!aWordPtr) break;
payloadPtr->payLoadString = *aWordPtr;
payloadPtr->timeScale = 0;
aWordPtr = theLinePtr->fWords.Next(); // the Payload timeScale
if (aWordPtr)
payloadPtr->timeScale = aWordPtr->GetInt();
lineOK = true;
} while (false);
return lineOK;
}
TextLine *SDPFileParser::GetRTPMapLines(TextLine *theLinePtr,TypeMap *theTypeMapPtr)
{
do
{
if (!theLinePtr || !theTypeMapPtr) break;
short numAttributes = CountRTPMapEntries();
theTypeMapPtr->fPayLoadTypes.SetSize(numAttributes);
PayLoad *payloadPtr = theTypeMapPtr->fPayLoadTypes.Begin();
while( theLinePtr && payloadPtr && (numAttributes > 0) )
{
bool haveMAP = GetRTPMap(theLinePtr,payloadPtr);
if (haveMAP)
{ numAttributes --;
payloadPtr = theTypeMapPtr->fPayLoadTypes.Next(); //skip to next payload entry
}
theLinePtr = fParser.fLines.Next(); // skip to next line
if(theLinePtr == NULL || Compare(theLinePtr->fWords.Begin(), SDPFileParser::sMediaTag, true)) //stop checking if this is a new media line
break;
}
} while (false);
return theLinePtr;
}
TextLine * SDPFileParser::GetTrackID(TextLine *theLinePtr,TypeMap *theTypeMapPtr)
{
SimpleString *aFieldPtr;
SimpleString *aWordPtr;
Bool16 foundID = false;
while(theLinePtr && !foundID)
{
if(Compare(theLinePtr->fWords.Begin(), SDPFileParser::sMediaTag, true)) //stop checking if this is a new media line
break;
do
{
SimpleString controlString("control");
aFieldPtr = theLinePtr->fWords.Begin();
if (!aFieldPtr) break;
bool isEqual = Compare(aFieldPtr, SDPFileParser::sAttributeTag, true);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(1);
if (!aWordPtr) break;
isEqual = Compare(aWordPtr, &controlString, false);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(3);
if (!aWordPtr) break;
theTypeMapPtr->fTrackID = aWordPtr->GetInt();
foundID = true;
} while (false);
theLinePtr = fParser.fLines.Next();
}
return theLinePtr;
}
bool SDPFileParser::ParseIPString(TextLine *theLinePtr)
{
bool result = false;
SimpleString *aWordPtr;
do
{
SimpleString ipIDString("IP4");
aWordPtr = theLinePtr->fWords.Begin();
if (!aWordPtr) break;
bool isEqual = Compare(aWordPtr,SDPFileParser::sConnectionTag, true);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(2);
if (!aWordPtr) break;
isEqual = Compare(aWordPtr, &ipIDString, false);
if (!isEqual) break;
aWordPtr = theLinePtr->fWords.SetPos(3);
if (!aWordPtr) break;
fIPAddressString.SetString(aWordPtr->fTheString, aWordPtr->fLen);
result = true;
} while (false);
return result;
}
SInt32 SDPFileParser::ParseSDP(char *theBuff)
{
SInt32 result = 0;
bool found = false;
SimpleString source(theBuff);
fSource.SetString( theBuff, strlen(theBuff) );
fParser.Parse(&source);
// Test parse
#if 0
qtss_printf("-----------------------------------------------------\n");
char tempString[256];
TextLine *theLine = fParser.fLines.Begin();
while (theLine)
{ SimpleString *theWord = theLine->fWords.Begin();
while (theWord)
{ theWord->GetString(tempString,256);
qtss_printf(tempString);
theWord = theLine->fWords.Next();
if (theWord) qtss_printf(" _ ");
}
theLine = fParser.fLines.Next();
qtss_printf("\n");
}
// exit (0);
#endif
fNumQTTextLines = CountQTTextLines();
fQTTextLines.SetSize( (SInt16) fNumQTTextLines);
SimpleString *theQTTextPtr = fQTTextLines.Begin();
fNumTracks = CountMediaEntries();
fSDPMediaList.SetSize((SInt16) fNumTracks);
TextLine *theLinePtr = fParser.fLines.Begin();
TypeMap *theTypeMapPtr = fSDPMediaList.Begin();
bool foundIP = false;
while (theLinePtr && theTypeMapPtr)
{
if (foundIP == false)
{ foundIP = ParseIPString(theLinePtr);
}
if (theQTTextPtr && GetQTTextFromLine(theLinePtr))
{ SimpleString *srcLinePtr = theLinePtr->fWords.Begin();
theQTTextPtr->SetString(srcLinePtr->fTheString, strcspn(srcLinePtr->fTheString, "\r\n") );
theQTTextPtr = fQTTextLines.Next();
}
found = GetMediaFromLine(theLinePtr, theTypeMapPtr);
if (found)
{
theLinePtr = fParser.fLines.Next();
if (!theLinePtr) break; // no more lines to process
int startLine = fParser.fLines.GetPos();
theLinePtr = fParser.fLines.SetPos(startLine);
(void) GetRTPMapLines(theLinePtr,theTypeMapPtr);
theLinePtr = fParser.fLines.SetPos(startLine);
(void) GetTrackID(theLinePtr,theTypeMapPtr);
theLinePtr = fParser.fLines.SetPos(startLine);
theTypeMapPtr = fSDPMediaList.Next();
continue;
}
theLinePtr = fParser.fLines.Next();
}
return result;
}
SInt32 SDPFileParser::ReadSDP(char *filename)
{
int result = -1;
SInt32 bytes= 0;
FILE *f = NULL;
if (fSDPBuff != NULL)
{ delete[] fSDPBuff;
fSDPBuff = NULL;
}
do
{
f = ::fopen(filename, "r");
if (f == NULL) break;
result = 1;
result = ::fseek(f, 0, SEEK_SET);
if (result != 0) break;
fSDPBuff = new char[cMaxBytes + 1];
if (NULL == fSDPBuff) break;
fSDPBuff[cMaxBytes] = 0;
bytes = ::fread(fSDPBuff, sizeof(char), cMaxBytes, f);
if (bytes < 1) break;
fSDPBuff[bytes] = 0;
result = ParseSDP(fSDPBuff);
if (result != 0) break;
result = 0;
} while (false);
if (f != NULL)
{ ::fclose (f);
f = NULL;
}
return result;
}

View file

@ -0,0 +1,109 @@
/*
*
* @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@
*
*/
#ifndef playlist_parsers_H
#define playlist_parsers_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "playlist_elements.h"
#include "OSHeaders.h"
#include "playlist_SimpleParse.h"
#include "playlist_utils.h"
#include "playlist_lists.h"
#ifndef __Win32__
#include <sys/types.h>
#endif
class TextLine : public SimpleParser
{
public:
ArrayList<SimpleString> fWords;
int Parse (SimpleString *textStrPtr);
};
class LineAndWordsParser : public SimpleParser
{
public:
ArrayList<TextLine> fLines;
int Parse (SimpleString *textStrPtr);
};
class SDPFileParser : SimpleParser
{
public:
SDPFileParser(void) : fNumTracks(0), fSDPBuff(NULL) {}
~SDPFileParser(void);
SInt32 ReadSDP(char *theFile);
SInt32 ParseSDP(char *theBuff) ;
SInt32 GetNumTracks() {return fNumTracks;} ;
bool IsCommented(SimpleString *aLine);
TextLine* GetRTPMapLines(TextLine *theLinePtr,TypeMap *theTypeMapPtr);
bool GetRTPMap(TextLine *theLinePtr,PayLoad *payloadPtr);
bool GetMediaFromLine(TextLine *theLinePtr, TypeMap *theTypeMapPtr);
void GetPayLoadsFromLine(TextLine *theLinePtr, TypeMap *theTypeMapPtr);
TextLine* GetTrackID(TextLine *theLinePtr,TypeMap *theTypeMapPtr);
bool ParseIPString(TextLine *theLinePtr);
SimpleString* GetIPString() { return &fIPAddressString; };
ArrayList<SimpleString> fQTTextLines;
SInt32 GetNumQTTextLines() {return fNumQTTextLines;} ;
bool GetQTTextFromLine(TextLine *theLinePtr);
SDPMediaList fSDPMediaList;
protected:
UInt32 TimeScaleLookUp(int payLoadID, SimpleString *typeStringPtr);
short CountMediaEntries() ;
short CountRTPMapEntries() ;
short CountQTTextLines();
UInt32 fNumQTTextLines;
UInt32 fNumTracks;
LineAndWordsParser fParser;
SimpleString fIPAddressString;
private:
enum { cMaxBytes = 4096}; // maximum accepted sdp file size
static char* sMediaTag;
static char* sAttributeTag;
static char* sConnectionTag;
char *fSDPBuff;
};
#endif //playlist_parsers_H

View file

@ -0,0 +1,60 @@
/*
*
* @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@
*
*/
/*
*
* History:
* 26-Oct-1998 Umesh Vaishampayan (umeshv@apple.com)
* Made the header c++ friendly.
*
* 23-Oct-1998 Umesh Vaishampayan (umeshv@apple.com)
* Created.
*/
#ifndef _TIMESTAMP_H_
#define _TIMESTAMP_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Get a 64 bit timestamp */
extern SInt64 timestamp(void);
struct timescale {
SInt64 tsc_numerator;
SInt64 tsc_denominator;
};
/*
* Get numerator and denominator to convert value returned
* by timestamp() to microseconds
*/
extern void utimescale(struct timescale *tscp);
#ifdef __cplusplus
}
#endif
#endif /* _TIMESTAMP_H_ */

View file

@ -0,0 +1,255 @@
/*
*
* @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_utils.h"
#include "OS.h"
#if Log_Enabled
enum {gBuffSize = 532, gBuffMaxStr = 512};
enum {switchEntries, switchTime, switchBytes};
enum {gLogMaxBytes = 100000};
enum {gLogMaxEntries = 1000};
enum {gLogMaxMilliSecs = 3 * 60 * 1000};
static int gLogSwitchSetting = switchEntries;
static SInt32 gLogEntries = 0;
static SInt64 gLogTimeStart = 0;
static SInt32 gLogNumBytes = 0;
static gLogNumPackets = 0;
static char gTempStr[256];
static FILE *gLogFile_1 = 0;
static FILE *gLogFile_2 = 0;
static FILE *gLogFileCurrent = 0;
static int gFileNum = 1;
static bool gLogStarted = false;
static char gLogBuff[gBuffSize];
static int gBuffUsed = 0;
void LogFileOpen(void)
{
if (!gLogFile_1 && !gLogFile_2)
{ gLogFile_1 = fopen("logfile_1.txt","w");
gLogFileCurrent = gLogFile_1;
*gLogBuff = 0;
gLogTimeStart = PlayListUtils::Milliseconds();
gLogStarted = true;
gLogEntries = 0;
gLogTimeStart = 0;
gLogNumBytes = 0;
gLogNumPackets = 0;
gFileNum = 1;
gBuffUsed = 0;
}
}
void LogFileClose(void)
{
fclose(gLogFile_1);
fclose(gLogFile_2);
gLogFileCurrent = gLogFile_1 = gLogFile_2 = 0;
}
bool TimeToSwitch(int len)
{
bool timeToSwitch = false;
if (!gLogStarted) return timeToSwitch;
switch( gLogSwitchSetting )
{
case switchEntries:
if (gLogEntries >= gLogMaxEntries)
{ timeToSwitch = true;
gLogEntries = 1;
}
else
gLogEntries ++;
break;
case switchTime:
{ SInt64 timeNow = PlayListUtils::Milliseconds();
SInt64 timeThisFile = timeNow - gLogTimeStart;
if ( timeThisFile > gLogMaxMilliSecs )
{ timeToSwitch = true;
gLogTimeStart = timeNow;
}
}
break;
case switchBytes:
if (gLogNumBytes > gLogMaxBytes)
{ timeToSwitch = true;
gLogNumBytes = 0;
}
gLogNumBytes += len;
break;
};
return timeToSwitch;
}
void WriteToLog(void *data, int len)
{
if (gLogFileCurrent && data && len)
{
bool timetoswitch = TimeToSwitch(len);
if ( timetoswitch )
{
if (gFileNum == 1)
{
if (gLogFile_1) fclose(gLogFile_1);
gLogFile_1 = 0;
gLogFile_2 = fopen("logfile_2.txt","w");
gFileNum = 2;
gLogFileCurrent = gLogFile_2;
fseek(gLogFileCurrent , 0, SEEK_SET);
}
else
{
if (gLogFile_2) fclose(gLogFile_2);
gLogFile_2 = 0;
gLogFile_1 = fopen("logfile_1.txt","w");
gFileNum = 1;
gLogFileCurrent = gLogFile_1;
fseek(gLogFileCurrent , 0, SEEK_SET);
}
}
fwrite(data, sizeof(char), len, gLogFileCurrent);
fflush(gLogFileCurrent);
}
}
void WritePacketToLog(void *data, int len)
{
gLogNumPackets ++;
LogUInt("Packet:", (UInt32) gLogNumPackets,"\n");
LogBuffer();
WriteToLog(data, len);
}
void WritToBuffer(void *data, int len)
{
if (data )
{
if (len >= gBuffSize)
len = gBuffSize -1;
memcpy (gLogBuff, (char *) data, len);
gLogBuff[gBuffSize] = 0;
}
gBuffUsed = len;
}
void LogBuffer(void)
{
WriteToLog(gLogBuff, strlen(gLogBuff) );
*gLogBuff =0;
gBuffUsed = strlen(gLogBuff);
}
void PrintLogBuffer(bool log)
{
qtss_printf(gLogBuff);
if (log) LogBuffer();
*gLogBuff =0;
gBuffUsed = strlen(gLogBuff);
}
void LogNum(char *str1,char *str2,char *str3)
{
int size = strlen(str1) + strlen(str2) + strlen(str3);
if ( size < gBuffMaxStr )
qtss_sprintf(gLogBuff, "%s%s%s%s",gLogBuff, str1, str2,str3);
gBuffUsed = strlen(gLogBuff);
}
void LogFloat(char *str, float num, char *str2)
{
qtss_sprintf(gTempStr,"%f",num);
LogNum(str,gTempStr,str2);
}
void LogInt(char *str, SInt32 num, char *str2)
{
qtss_sprintf(gTempStr,"%"_S32BITARG_"",num);
LogNum(str,gTempStr,str2);
}
void LogUInt (char *str, UInt32 num, char *str2)
{
qtss_sprintf(gTempStr,"%"_U32BITARG_"",num);
LogNum(str,gTempStr,str2);
}
void LogStr(char *str)
{
*gLogBuff = 0;
int size = strlen(str) + gBuffUsed;
if ( size <= gBuffMaxStr )
qtss_sprintf(gLogBuff, "%s%s",gLogBuff, str);
gBuffUsed = strlen(gLogBuff);
}
#endif
SInt64 PlayListUtils::sInitialMsecOffset = 0;
UInt32 PlayListUtils::sRandomNum = 0;
void PlayListUtils::Initialize()
{
if (sInitialMsecOffset != 0) return;
sInitialMsecOffset = OS::Milliseconds(); //Milliseconds uses sInitialMsec to make a 0 offset millisecond so this assignment is valid only once.
//qtss_printf("sInitialMsecOffset =%qd\n",sInitialMsecOffset);
::srand( (UInt16) OS::UnixTime_Secs() );
sRandomNum = ::rand();
}
PlayListUtils::PlayListUtils()
{
}
UInt32 PlayListUtils::Random()
{
UInt32 seed = 1664525L * sRandomNum + 1013904223L; //1013904223 is prime .. Knuth D.E.
::srand( seed );
sRandomNum = ::rand();
return sRandomNum;
}

View file

@ -0,0 +1,101 @@
/*
*
* @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@
*
*/
#ifndef playlist_utils_H
#define playlist_utils_H
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <errno.h>
#ifndef __Win32__
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#endif
#include "OSHeaders.h"
#include "OS.h"
#define Log_Enabled 0
#if Log_Enabled
void LogFileOpen(void);
void LogFileClose(void);
bool TimeToSwitch(int len);
void WriteToLog(void *data, int len);
void WritePacketToLog(void *data, int len);
void WritToBuffer(void *data, int len);
void LogBuffer(void);
void PrintLogBuffer(bool log);
void LogNum(void);
void LogFloat(char *str, float num, char *str2= "\0");
void LogInt(char *str, SInt32 num, char *str2= "\0");
void LogUInt (char *str, UInt32 num, char *str2 = "\0");
void LogStr(char *str);
#else
#define LogFileOpen()
#define LogFileClose()
#define TimeToSwitch(len)
#define WriteToLog(data,len)
#define WritePacketToLog(data,len)
#define WritToBuffer(data, len)
#define LogBuffer()
#define PrintLogBuffer(log)
#define LogFloat(str,num,str2)
#define LogInt(str,num,str2)
#define LogUInt(str,num,str2)
#define LogStr(str)
#define LogNum()
#endif
#define kFixed64 ( (UInt64) 1 << 32)
class PlayListUtils
{
public:
PlayListUtils();
enum {eMicro = 1000000, eMilli = 1000};
static SInt64 sInitialMsecOffset;
static UInt32 sRandomNum;
static void InitRandom() {};
static void Initialize();
static UInt32 Random();
static SInt64 Milliseconds() {return OS::Milliseconds() - sInitialMsecOffset;};
static SInt64 TimeMilli_To_1900Fixed64Secs(SInt64 inMilliseconds) { return OS::TimeMilli_To_1900Fixed64Secs(OS::TimeMilli_To_UnixTimeMilli(sInitialMsecOffset + inMilliseconds)); }
static SInt64 TimeMilli_To_Fixed64Secs(SInt64 inMilliseconds) { return OS::TimeMilli_To_Fixed64Secs(inMilliseconds); }
};
#endif //playlist_utils_H

View file

@ -0,0 +1,352 @@
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @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@
*/
/* tailor.h -- target dependent definitions
* Copyright (C) 1992-1993 Jean-loup Gailly.
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, see the file COPYING.
*/
/* The target dependent definitions should be defined here only.
* The target dependent functions should be defined in tailor.c.
*/
/* $Id: tailor.h,v 1.1 2006/01/05 13:20:36 murata Exp $ */
#if defined(__MSDOS__) && !defined(MSDOS)
# define MSDOS
#endif
#if defined(__OS2__) && !defined(OS2)
# define OS2
#endif
#if defined(OS2) && defined(MSDOS) /* MS C under OS/2 */
# undef MSDOS
#endif
#ifdef MSDOS
# ifdef __GNUC__
/* DJGPP version 1.09+ on MS-DOS.
* The DJGPP 1.09 stat() function must be upgraded before gzip will
* fully work.
* No need for DIRENT, since <unistd.h> defines POSIX_SOURCE which
* implies DIRENT.
*/
# define near
# else
# define MAXSEG_64K
# ifdef __TURBOC__
# define NO_OFF_T
# ifdef __BORLANDC__
# define DIRENT
# else
# define NO_UTIME
# endif
# else /* MSC */
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# endif
# endif
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 128
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# define NO_SIZE_CHECK
# define casemap(c) tolow(c) /* Force file names to lower case */
# include <io.h>
# define OS_CODE 0x00
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# if !defined(NO_ASM) && !defined(ASMV)
# define ASMV
# endif
#else
# define near
#endif
#ifdef OS2
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 260
# ifdef OS2FAT
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define casemap(c) tolow(c)
# endif
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# include <io.h>
# define OS_CODE 0x06
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# ifdef _MSC_VER
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define MAXSEG_64K
# undef near
# define near _near
# endif
# ifdef __EMX__
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define DIRENT
# define EXPAND(argc,argv) \
{_response(&argc, &argv); _wildcard(&argc, &argv);}
# endif
# ifdef __BORLANDC__
# define DIRENT
# endif
# ifdef __ZTC__
# define NO_DIR
# define NO_UTIME_H
# include <dos.h>
# define EXPAND(argc,argv) \
{response_expand(&argc, &argv);}
# endif
#endif
#ifdef WIN32 /* Windows NT */
# define HAVE_SYS_UTIME_H
# define NO_UTIME_H
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 260
# define NO_CHOWN
# define PROTO
# define STDC_HEADERS
# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY)
# include <io.h>
# include <malloc.h>
# ifdef NTFAT
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define casemap(c) tolow(c) /* Force file names to lower case */
# endif
# define OS_CODE 0x0b
#endif
#ifdef MSDOS
# ifdef __TURBOC__
# include <alloc.h>
# define DYN_ALLOC
/* Turbo C 2.0 does not accept static allocations of large arrays */
void * fcalloc (unsigned items, unsigned size);
void fcfree (void *ptr);
# else /* MSC */
# include <malloc.h>
# define fcalloc(nitems,itemsize) halloc((SInt32)(nitems),(itemsize))
# define fcfree(ptr) hfree(ptr)
# endif
#else
# ifdef MAXSEG_64K
# define fcalloc(items,size) calloc((items),(size))
# else
# define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size))
# endif
# define fcfree(ptr) free(ptr)
#endif
#if defined(VAXC) || defined(VMS)
# define PATH_SEP ']'
# define PATH_SEP2 ':'
# define SUFFIX_SEP ';'
# define NO_MULTIPLE_DOTS
# define Z_SUFFIX "-gz"
# define RECORD_IO 1
# define casemap(c) tolow(c)
# define OS_CODE 0x02
# define OPTIONS_VAR "GZIP_OPT"
# define STDC_HEADERS
# define NO_UTIME
# define EXPAND(argc,argv) vms_expand_args(&argc,&argv);
# include <file.h>
# define unlink delete
# ifdef VAXC
# define NO_FCNTL_H
# include <unixio.h>
# endif
#endif
#ifdef AMIGA
# define PATH_SEP2 ':'
# define STDC_HEADERS
# define OS_CODE 0x01
# define ASMV
# ifdef __GNUC__
# define DIRENT
# define HAVE_UNISTD_H
# else /* SASC */
# define NO_STDIN_FSTAT
# define SYSDIR
# define NO_SYMLINK
# define NO_CHOWN
# define NO_FCNTL_H
# include <fcntl.h> /* for read() and write() */
# define direct dirent
extern void _expand_args(int *argc, char ***argv);
# define EXPAND(argc,argv) _expand_args(&argc,&argv);
# undef O_BINARY /* disable useless --ascii option */
# endif
#endif
#if defined(ATARI) || defined(atarist)
# ifndef STDC_HEADERS
# define STDC_HEADERS
# define HAVE_UNISTD_H
# define DIRENT
# endif
# define ASMV
# define OS_CODE 0x05
# ifdef TOSFS
# define PATH_SEP2 '\\'
# define PATH_SEP3 ':'
# define MAX_PATH_LEN 128
# define NO_MULTIPLE_DOTS
# define MAX_EXT_CHARS 3
# define Z_SUFFIX "z"
# define NO_CHOWN
# define casemap(c) tolow(c) /* Force file names to lower case */
# define NO_SYMLINK
# endif
#endif
#ifdef MACOS
# define PATH_SEP ':'
# define DYN_ALLOC
# define PROTO
# define NO_STDIN_FSTAT
# define NO_CHOWN
# define NO_UTIME
# define chmod(file, mode) (0)
# define OPEN(name, flags, mode) open(name, flags)
# define OS_CODE 0x07
# ifdef MPW
# define isatty(fd) ((fd) <= 2)
# endif
#endif
#ifdef __50SERIES /* Prime/PRIMOS */
# define PATH_SEP '>'
# define STDC_HEADERS
# define NO_MEMORY_H
# define NO_UTIME_H
# define NO_UTIME
# define NO_CHOWN
# define NO_STDIN_FSTAT
# define NO_SIZE_CHECK
# define NO_SYMLINK
# define RECORD_IO 1
# define casemap(c) tolow(c) /* Force file names to lower case */
# define put_char(c) put_byte((c) & 0x7F)
# define get_char(c) ascii2pascii(get_byte())
# define OS_CODE 0x0F /* temporary, subject to change */
# ifdef SIGTERM
# undef SIGTERM /* We don't want a signal handler for SIGTERM */
# endif
#endif
#if defined(pyr) && !defined(NOMEMCPY) /* Pyramid */
# define NOMEMCPY /* problem with overlapping copies */
#endif
#ifdef TOPS20
# define OS_CODE 0x0a
#endif
#ifndef unix
# define NO_ST_INO /* don't rely on inode numbers */
#endif
/* Common defaults */
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
#endif
#ifndef PATH_SEP
# define PATH_SEP '/'
#endif
#ifndef casemap
# define casemap(c) (c)
#endif
#ifndef OPTIONS_VAR
# define OPTIONS_VAR "GZIP"
#endif
#ifndef Z_SUFFIX
# define Z_SUFFIX ".gz"
#endif
#ifdef MAX_EXT_CHARS
# define MAX_SUFFIX MAX_EXT_CHARS
#else
# define MAX_SUFFIX 30
#endif
#ifndef MAKE_LEGAL_NAME
# ifdef NO_MULTIPLE_DOTS
# define MAKE_LEGAL_NAME(name) make_simple_name(name)
# else
# define MAKE_LEGAL_NAME(name)
# endif
#endif
#ifndef MIN_PART
# define MIN_PART 3
/* keep at least MIN_PART chars between dots in a file name. */
#endif
#ifndef EXPAND
# define EXPAND(argc,argv)
#endif
#ifndef RECORD_IO
# define RECORD_IO 0
#endif
#ifndef SET_BINARY_MODE
# define SET_BINARY_MODE(fd)
#endif
#ifndef OPEN
# define OPEN(name, flags, mode) open(name, flags, mode)
#endif
#ifndef get_char
# define get_char() get_byte()
#endif
#ifndef put_char
# define put_char(c) put_byte(c)
#endif