Very rough first start, not even everything added
This commit is contained in:
commit
af3619d4fa
88 changed files with 24251 additions and 0 deletions
578
PlaylistBroadcaster.tproj/BCasterTracker.cpp
Normal file
578
PlaylistBroadcaster.tproj/BCasterTracker.cpp
Normal 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...
|
||||
|
||||
}
|
61
PlaylistBroadcaster.tproj/BCasterTracker.h
Normal file
61
PlaylistBroadcaster.tproj/BCasterTracker.h
Normal 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
|
302
PlaylistBroadcaster.tproj/BroadcastLog.cpp
Normal file
302
PlaylistBroadcaster.tproj/BroadcastLog.cpp
Normal 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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
90
PlaylistBroadcaster.tproj/BroadcastLog.h
Normal file
90
PlaylistBroadcaster.tproj/BroadcastLog.h
Normal 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
|
1104
PlaylistBroadcaster.tproj/BroadcasterSession.cpp
Executable file
1104
PlaylistBroadcaster.tproj/BroadcasterSession.cpp
Executable file
File diff suppressed because it is too large
Load diff
288
PlaylistBroadcaster.tproj/BroadcasterSession.h
Executable file
288
PlaylistBroadcaster.tproj/BroadcasterSession.h
Executable 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__
|
165
PlaylistBroadcaster.tproj/GetLocalIPAddressString.c
Normal file
165
PlaylistBroadcaster.tproj/GetLocalIPAddressString.c
Normal 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;
|
||||
}
|
44
PlaylistBroadcaster.tproj/GetLocalIPAddressString.h
Normal file
44
PlaylistBroadcaster.tproj/GetLocalIPAddressString.h
Normal 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
|
118
PlaylistBroadcaster.tproj/NoRepeat.cpp
Normal file
118
PlaylistBroadcaster.tproj/NoRepeat.cpp
Normal 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;
|
||||
}
|
||||
|
52
PlaylistBroadcaster.tproj/NoRepeat.h
Normal file
52
PlaylistBroadcaster.tproj/NoRepeat.h
Normal 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
|
630
PlaylistBroadcaster.tproj/PLBroadcastDef.cpp
Normal file
630
PlaylistBroadcaster.tproj/PLBroadcastDef.cpp
Normal 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;
|
||||
|
||||
}
|
129
PlaylistBroadcaster.tproj/PLBroadcastDef.h
Normal file
129
PlaylistBroadcaster.tproj/PLBroadcastDef.h
Normal 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
|
483
PlaylistBroadcaster.tproj/PickerFromFile.cpp
Normal file
483
PlaylistBroadcaster.tproj/PickerFromFile.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
77
PlaylistBroadcaster.tproj/PickerFromFile.h
Normal file
77
PlaylistBroadcaster.tproj/PickerFromFile.h
Normal 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
|
2235
PlaylistBroadcaster.tproj/PlaylistBroadcaster.cpp
Normal file
2235
PlaylistBroadcaster.tproj/PlaylistBroadcaster.cpp
Normal file
File diff suppressed because it is too large
Load diff
430
PlaylistBroadcaster.tproj/PlaylistPicker.cpp
Normal file
430
PlaylistBroadcaster.tproj/PlaylistPicker.cpp
Normal 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;
|
||||
|
||||
}
|
86
PlaylistBroadcaster.tproj/PlaylistPicker.h
Normal file
86
PlaylistBroadcaster.tproj/PlaylistPicker.h
Normal 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
|
60
PlaylistBroadcaster.tproj/SimplePlayListElement.h
Normal file
60
PlaylistBroadcaster.tproj/SimplePlayListElement.h
Normal 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
|
56
PlaylistBroadcaster.tproj/StSmartArrayPointer.h
Normal file
56
PlaylistBroadcaster.tproj/StSmartArrayPointer.h
Normal 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
|
59
PlaylistBroadcaster.tproj/TrackingElement.h
Normal file
59
PlaylistBroadcaster.tproj/TrackingElement.h
Normal 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
|
209
PlaylistBroadcaster.tproj/notes.c
Normal file
209
PlaylistBroadcaster.tproj/notes.c
Normal 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
|
70
PlaylistBroadcaster.tproj/playlist_QTRTPBroadcastFile.cpp
Normal file
70
PlaylistBroadcaster.tproj/playlist_QTRTPBroadcastFile.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
56
PlaylistBroadcaster.tproj/playlist_QTRTPBroadcastFile.h
Normal file
56
PlaylistBroadcaster.tproj/playlist_QTRTPBroadcastFile.h
Normal 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
|
450
PlaylistBroadcaster.tproj/playlist_SDPGen.cpp
Normal file
450
PlaylistBroadcaster.tproj/playlist_SDPGen.cpp
Normal 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;
|
||||
|
||||
}
|
||||
|
106
PlaylistBroadcaster.tproj/playlist_SDPGen.h
Normal file
106
PlaylistBroadcaster.tproj/playlist_SDPGen.h
Normal 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
|
||||
|
357
PlaylistBroadcaster.tproj/playlist_SimpleParse.cpp
Normal file
357
PlaylistBroadcaster.tproj/playlist_SimpleParse.cpp
Normal 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(¤tPtr->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,¤tString, delimeters, ¤tString))
|
||||
{ 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) ¤tPtr->fTheString[currentPtr->fLen];
|
||||
|
||||
if (endCurrent > endSource) break;
|
||||
|
||||
SimpleString tempSource(NULL);
|
||||
|
||||
|
||||
UInt32 searchLen = endSource - endCurrent;
|
||||
|
||||
tempSource.SetString(¤tPtr->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;
|
||||
}
|
96
PlaylistBroadcaster.tproj/playlist_SimpleParse.h
Normal file
96
PlaylistBroadcaster.tproj/playlist_SimpleParse.h
Normal 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
|
139
PlaylistBroadcaster.tproj/playlist_array.h
Normal file
139
PlaylistBroadcaster.tproj/playlist_array.h
Normal 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
|
||||
|
765
PlaylistBroadcaster.tproj/playlist_broadcaster.cpp
Normal file
765
PlaylistBroadcaster.tproj/playlist_broadcaster.cpp
Normal 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;
|
||||
}
|
168
PlaylistBroadcaster.tproj/playlist_broadcaster.h
Normal file
168
PlaylistBroadcaster.tproj/playlist_broadcaster.h
Normal 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
|
874
PlaylistBroadcaster.tproj/playlist_elements.cpp
Normal file
874
PlaylistBroadcaster.tproj/playlist_elements.cpp
Normal file
|
@ -0,0 +1,874 @@
|
|||
/*
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "playlist_elements.h"
|
||||
#include "playlist_utils.h"
|
||||
#include "OS.h"
|
||||
#include "SocketUtils.h"
|
||||
#ifndef __Win32__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// ************************
|
||||
//
|
||||
// MediaStream
|
||||
//
|
||||
// ************************
|
||||
#define DROP_RTCP_TEST 0
|
||||
#define DROPCOUNT 1// drop count RTCPs
|
||||
|
||||
MediaStream::MediaStream(void)
|
||||
{
|
||||
memset( (char *)&fData, '\0', sizeof(fData));
|
||||
fSend = true;
|
||||
fData.fSenderReportReady = true;
|
||||
}
|
||||
MediaStream::~MediaStream()
|
||||
{
|
||||
if (fData.fSoundDescriptionBuffer) delete[] fData.fSoundDescriptionBuffer;
|
||||
}
|
||||
|
||||
|
||||
UInt32 MediaStream::GetACName(char* ioCNameBuffer)
|
||||
{
|
||||
//clear out the whole buffer
|
||||
::memset(ioCNameBuffer, 0, kMaxCNameLen);
|
||||
|
||||
//cName identifier
|
||||
ioCNameBuffer[0] = 1;
|
||||
|
||||
//Unique cname is constructed from the base name and the current time
|
||||
qtss_sprintf(&ioCNameBuffer[2], " %s%"_64BITARG_"d", "QTSS", OS::Milliseconds() / 1000);
|
||||
UInt32 cNameLen = ::strlen(&ioCNameBuffer[2]);
|
||||
//2nd byte of CName should be length
|
||||
ioCNameBuffer[1] = (UInt8) cNameLen ;//doesn't count indicator or length byte
|
||||
cNameLen += 2; // add the identifier and len bytes to the result len
|
||||
//pad length to a 4 byte boundary
|
||||
UInt32 padLength = cNameLen % 4;
|
||||
if (padLength > 0)
|
||||
cNameLen += 4 - padLength;
|
||||
|
||||
return cNameLen;
|
||||
}
|
||||
|
||||
void MediaStream::TestAndIncSoundDescriptor(RTpPacket *packetPtr)
|
||||
{ // currently not executed
|
||||
SInt16 test = 0;
|
||||
do
|
||||
{
|
||||
if (!fData.fIsSoundStream) break;
|
||||
if (!packetPtr->HasSoundDescription()) break;
|
||||
if (!fData.fSoundDescriptionBuffer) break;
|
||||
|
||||
SoundDescription *packetSDPtr = NULL;
|
||||
SoundDescription *savedSDPtr = (SoundDescription *) fData.fSoundDescriptionBuffer;
|
||||
(void) packetPtr->GetSoundDescriptionRef(&packetSDPtr);
|
||||
SInt32 descSize = packetPtr->fSoundDescriptionLen;
|
||||
|
||||
if (descSize == 0) break;
|
||||
if (descSize > eMaxSoundDescriptionSize) break;
|
||||
|
||||
if (fData.fSavedSoundDescSize == descSize)
|
||||
{ test = ::memcmp(packetSDPtr, fData.fSoundDescriptionBuffer, descSize);
|
||||
}
|
||||
else test = 1; // they are different sizes so it is a new sample description
|
||||
|
||||
if (test != 0) // they are different
|
||||
{ ::memcpy(savedSDPtr, packetSDPtr, descSize);
|
||||
fData.fSavedSoundDescSize = descSize;
|
||||
fData.fSavedDataRefIndex ++ ; // it is different than saved so change the index
|
||||
}
|
||||
packetSDPtr->dataRefIndex = htons(fData.fSavedDataRefIndex);
|
||||
|
||||
} while (false);
|
||||
}
|
||||
|
||||
|
||||
void MediaStream::UpdatePacketInStream(RTpPacket *packetPtr)
|
||||
{
|
||||
UInt32 curSSRC = 0;
|
||||
UInt32 curRTpTimeStamp = 0;
|
||||
UInt16 curRTpSequenceNumber = 0;
|
||||
UInt32 newRTpTimeStamp = 0;
|
||||
UInt16 newRTpSequenceNumber = 0;
|
||||
UInt32 newSSRC = 0;
|
||||
unsigned char curPayload;
|
||||
unsigned char newPayload;
|
||||
packetPtr->GetHeaderInfo(&curRTpTimeStamp, &curRTpSequenceNumber, &curSSRC, &curPayload);
|
||||
|
||||
newSSRC = fData.fInitSSRC;
|
||||
MapToStream(curRTpTimeStamp, curRTpSequenceNumber, curPayload, &newRTpTimeStamp, &newRTpSequenceNumber, &newPayload);
|
||||
|
||||
if (fData.fIsVideoStream) { LogStr("video "); }
|
||||
if (fData.fIsSoundStream) { LogStr("audio "); }
|
||||
|
||||
packetPtr->SetHeaderInfo(newRTpTimeStamp, newRTpSequenceNumber,newSSRC,newPayload);
|
||||
|
||||
//TestAndIncSoundDescriptor(packetPtr); // put in to track QuickTime format sound descriptors and flag change in sample types
|
||||
}
|
||||
|
||||
void MediaStream::MapToStream(UInt32 curRTpTimeStamp, UInt16 curRTpSequenceNumber, unsigned char curPayload, UInt32 *outRTpTimeStampPtr, UInt16 *outRTpSequenceNumberPtr, unsigned char *outPayloadPtr)
|
||||
{
|
||||
|
||||
if (fData.fNewMovieStarted == true) // this is the first packet in a new movie
|
||||
{
|
||||
fData.fNewMovieStarted = false;
|
||||
}
|
||||
|
||||
fData.fCurStreamRTpSequenceNumber++; // the stream sequence number
|
||||
|
||||
UInt64 curSequenceNumber = (UInt64) fData.fCurStreamRTpSequenceNumber + (UInt64) fData.fSeqRandomOffset;
|
||||
UInt64 curTimeStamp = (UInt64) curRTpTimeStamp + (UInt64) fData.fMediaStartOffsetMediaScale + (UInt64) fData.fRTpRandomOffset;
|
||||
|
||||
UInt32 outTime = (UInt32) ( (UInt64) curTimeStamp & (UInt64) 0xFFFFFFFF );
|
||||
UInt16 outSeq = (UInt16) ( (UInt64) curSequenceNumber & (UInt64) 0xFFFF );
|
||||
unsigned char outPayload = curPayload;
|
||||
Assert (fData.fMovieMediaTypePtr != NULL);// should always be valid
|
||||
PayLoad *firstPayLoadPtr = (fData.fMovieMediaTypePtr)->fPayLoadTypes.Begin(); // potential problem; assumes first payload per track is this payload
|
||||
if (firstPayLoadPtr)
|
||||
{
|
||||
outPayload = (unsigned char) ( 0x7F & firstPayLoadPtr->payloadID);
|
||||
outPayload |= (curPayload & 0x80);// the movie payload marker
|
||||
}
|
||||
|
||||
// qtss_printf("MediaStream::MapToStream outTime = %"_U32BITARG_"\n", outTime);
|
||||
// qtss_printf("MediaStream::MapToStream calculated time = %"_U32BITARG_"\n",(UInt32) curTimeInScale);
|
||||
|
||||
if (outRTpTimeStampPtr) *outRTpTimeStampPtr = outTime;
|
||||
if (outRTpSequenceNumberPtr) *outRTpSequenceNumberPtr = outSeq;
|
||||
if (outPayloadPtr) *outPayloadPtr = outPayload;
|
||||
}
|
||||
|
||||
void MediaStream::BuildStaticRTCpReport()
|
||||
{
|
||||
char theTempCName[kMaxCNameLen];
|
||||
UInt32 cNameLen = GetACName(theTempCName);
|
||||
|
||||
//write the SR & SDES headers
|
||||
UInt32* theSRWriter = (UInt32*)&fData.fSenderReportBuffer;
|
||||
*theSRWriter = htonl(0x80c80006);
|
||||
theSRWriter += 7;
|
||||
//SDES length is the length of the CName, plus 2 32bit words
|
||||
*theSRWriter = htonl(0x81ca0000 + (cNameLen >> 2) + 1);
|
||||
::memcpy(&fData.fSenderReportBuffer[kSenderReportSizeInBytes], theTempCName, cNameLen);
|
||||
fData.fSenderReportSize = kSenderReportSizeInBytes + cNameLen;
|
||||
}
|
||||
|
||||
void MediaStream::InitIfAudio()
|
||||
{
|
||||
if (fData.fStreamMediaTypePtr)
|
||||
{
|
||||
SimpleString audioStr("audio");
|
||||
fData.fIsSoundStream = SimpleParser::Compare(&audioStr, &(fData.fStreamMediaTypePtr->fTheTypeStr), false );
|
||||
if (fData.fIsSoundStream)
|
||||
{
|
||||
fData.fSoundDescriptionBuffer = new char[eMaxSoundDescriptionSize];
|
||||
::memset(fData.fSoundDescriptionBuffer, 0, eMaxSoundDescriptionSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
SimpleString videoStr("video");
|
||||
fData.fIsVideoStream = SimpleParser::Compare(&videoStr, &(fData.fStreamMediaTypePtr->fTheTypeStr), false );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MediaStream::StreamStart(SInt64 startTime)
|
||||
{
|
||||
|
||||
fData.fStreamStartTime = startTime;
|
||||
fData.fMovieEndTime = startTime;
|
||||
fData.fLastSenderReportTime = 0;
|
||||
|
||||
//for RTCp SRs, we also need to store the play time in NTP
|
||||
// fData.fNTPPlayTime = OS::TimeMilli_To_1900Fixed64Secs(startTime);
|
||||
fData.fNTPPlayTime = PlayListUtils::TimeMilli_To_1900Fixed64Secs(startTime);
|
||||
fData.fCurStreamRTpSequenceNumber = 0;
|
||||
fData.fMovieStartOffset = 0;
|
||||
|
||||
fData.fNewStreamStarted = true;
|
||||
fData.fSeqRandomOffset = PlayListUtils::Random();
|
||||
fData.fRTpRandomOffset = PlayListUtils::Random();
|
||||
|
||||
|
||||
// fData.fSeqRandomOffset = -1000; // test roll over
|
||||
// fData.fRTpRandomOffset = -100000; // test roll over
|
||||
|
||||
InitIfAudio();
|
||||
|
||||
//Build a static RTCp sender report (this way, only the info that changes
|
||||
//on the fly will have to be written)
|
||||
BuildStaticRTCpReport();
|
||||
}
|
||||
|
||||
void MediaStream::MovieStart(SInt64 startTime)
|
||||
{
|
||||
fData.fNewMovieStarted = true;
|
||||
fData.fMovieStartTime = startTime;
|
||||
|
||||
if (fData.fMovieMediaTypePtr && fData.fRTPFilePtr)
|
||||
{ UInt32 trackID = fData.fMovieMediaTypePtr->fTrackID;
|
||||
fData.fMovieMediaTypePtr->fTimeScale = fData.fRTPFilePtr->GetTrackTimeScale(trackID);
|
||||
|
||||
UInt64 lastMovieduration = (UInt64) ( (Float64) (fData.fLastMovieDurationSecs * (Float64) PlayListUtils::eMilli) ) ; // add the length of the last movie
|
||||
fData.fMovieStartOffset += lastMovieduration;
|
||||
|
||||
if (fData.fNewStreamStarted)
|
||||
{ fData.fNewStreamStarted = false;
|
||||
fData.fMovieEndTime = startTime; // first movie in stream has 0 movieInterval time.
|
||||
}
|
||||
|
||||
Float64 mediaOffSet = (Float64) (SInt64)fData.fMovieStartOffset / (Float64) PlayListUtils::eMilli; // convert to float seconds
|
||||
mediaOffSet = mediaOffSet * (Float64) fData.fMovieMediaTypePtr->fTimeScale; // mediaOffset in media time scale
|
||||
fData.fMediaStartOffsetMediaScale = (UInt64) mediaOffSet; // convert float time units to UInt64
|
||||
|
||||
fData.fLastMovieDurationSecs = fData.fRTPFilePtr->GetMovieDuration();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void MediaStream::MovieEnd(SInt64 endTime)
|
||||
{
|
||||
fData.fMovieEndTime = endTime;
|
||||
fData.fMovieMediaTypePtr = NULL;
|
||||
fData.fRTPFilePtr = NULL;
|
||||
}
|
||||
|
||||
SInt16 MediaStream::Accounting(RTpPacket *packetPtr)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
fData.fBytesSent += packetPtr->fLength;
|
||||
fData.fPacketsSent ++;
|
||||
|
||||
UInt32 lastTime = fData.fTimeStamp;
|
||||
unsigned char payload;
|
||||
packetPtr->GetHeaderInfo(&fData.fTimeStamp, &fData.fLastSequenceNumber, &fData.fSsrc, &payload);
|
||||
|
||||
fData.fLastTimeStampOffset = fData.fTimeStamp - lastTime;
|
||||
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 MediaStream::Send(RTpPacket *packetPtr)
|
||||
{
|
||||
|
||||
SInt16 result = -1;
|
||||
|
||||
do
|
||||
{
|
||||
if (fData.fMovieMediaTypePtr == NULL) break;
|
||||
|
||||
UpdatePacketInStream(packetPtr);
|
||||
|
||||
result = Accounting(packetPtr);
|
||||
if (result) break;
|
||||
|
||||
if (fSend)
|
||||
{ result = fData.fSocketPair->SendRTp(packetPtr->fThePacket, packetPtr->fLength);
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MediaStream::ReceiveOnPorts()
|
||||
{
|
||||
fData.fSocketPair->RecvRTp(fData.fPortRTpReadBuff.fReadBuffer, ReceiveBuffer::kReadBufferSize, &fData.fPortRTpReadBuff.fReceiveLen);
|
||||
fData.fSocketPair->RecvRTCp(fData.fPortRTCpReadBuff.fReadBuffer, ReceiveBuffer::kReadBufferSize, &fData.fPortRTCpReadBuff.fReceiveLen);
|
||||
}
|
||||
|
||||
#if DROP_RTCP_TEST
|
||||
static int numRTCPPackets = 0;
|
||||
static int numStartDropPackets = 0;
|
||||
#endif
|
||||
|
||||
int MediaStream::UpdateSenderReport(SInt64 theTime)
|
||||
{
|
||||
|
||||
if (NULL == fData.fMovieMediaTypePtr)
|
||||
return 0;
|
||||
|
||||
int result = 0;
|
||||
|
||||
SInt64 timeToSend = fData.fLastSenderReportTime + (kSenderReportIntervalInSecs * PlayListUtils::eMilli);
|
||||
|
||||
#if DROP_RTCP_TEST
|
||||
if (theTime > timeToSend )
|
||||
{
|
||||
if (fData.fIsSoundStream)
|
||||
{ numRTCPPackets ++;
|
||||
if ( (numRTCPPackets <= numStartDropPackets + DROPCOUNT) )
|
||||
{ qtss_printf("skip sound RTCP #%d time=%qd\n",numRTCPPackets, theTime / PlayListUtils::eMilli);
|
||||
fData.fLastSenderReportTime = theTime;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{ qtss_printf("send sound RTCP #%d time=%qd\n",numRTCPPackets, theTime / PlayListUtils::eMilli);
|
||||
numStartDropPackets = numRTCPPackets;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (theTime > timeToSend)
|
||||
{
|
||||
fData.fLastSenderReportTime = theTime;
|
||||
UInt32* theReport = (UInt32*) fData.fSenderReportBuffer;
|
||||
|
||||
theReport++;
|
||||
*theReport = htonl(fData.fSsrc);
|
||||
|
||||
theReport++;
|
||||
SInt64* theNTPTimestampP = (SInt64*)theReport;
|
||||
*theNTPTimestampP = OS::HostToNetworkSInt64(fData.fNTPPlayTime +
|
||||
PlayListUtils::TimeMilli_To_Fixed64Secs(theTime - fData.fStreamStartTime));
|
||||
|
||||
theReport += 2;
|
||||
*theReport = htonl(fData.fTimeStamp);
|
||||
|
||||
Float64 curTimeInScale = (Float64) (SInt64) PlayListUtils::Milliseconds() / (Float64) PlayListUtils::eMilli; // convert to float seconds
|
||||
curTimeInScale = curTimeInScale * (Float64) fData.fMovieMediaTypePtr->fTimeScale; // curTime in media time scale
|
||||
curTimeInScale +=(Float64) fData.fRTpRandomOffset;
|
||||
curTimeInScale = (UInt32) ( (UInt64) curTimeInScale & (UInt64) 0xFFFFFFFF );
|
||||
|
||||
//qtss_printf("MediaStream::UpdateSenderReport RTCP timestamp = %"_U32BITARG_"\n",(UInt32) curTimeInScale);
|
||||
*theReport = htonl((UInt32) curTimeInScale);
|
||||
|
||||
theReport++;
|
||||
fData.fPacketCount = (UInt32) fData.fPacketsSent;
|
||||
*theReport = htonl(fData.fPacketCount);
|
||||
|
||||
theReport++;
|
||||
fData.fByteCount = (UInt32) fData.fBytesSent;
|
||||
*theReport = htonl(fData.fByteCount);
|
||||
|
||||
theReport += 2;
|
||||
*theReport = htonl(fData.fSsrc);
|
||||
|
||||
LogStr("Sender Report\n");
|
||||
LogUInt("NTP ",(UInt32) ((*theNTPTimestampP) >> 32)," ");
|
||||
LogUInt(" ",(UInt32) ((*theNTPTimestampP) & 0xFFFFFFFF), "\n" );
|
||||
LogUInt("time stamp = ", fData.fTimeStamp, "\n");
|
||||
LogInt("SSRC = ", fData.fSsrc, "\n");
|
||||
LogUInt("Packets sent = ", fData.fPacketCount, "\n");
|
||||
LogUInt("Bytes sent = ", fData.fByteCount, "\n");
|
||||
LogBuffer();
|
||||
result = fData.fSocketPair->SendRTCp(fData.fSenderReportBuffer, fData.fSenderReportSize);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ************************
|
||||
//
|
||||
// UDPSOCKETPAIR
|
||||
//
|
||||
// ************************
|
||||
|
||||
|
||||
void UDPSocketPair::Close()
|
||||
{
|
||||
if (fMultiCastJoined)
|
||||
this->LeaveMulticast();
|
||||
|
||||
#ifdef __Win32__
|
||||
if (fSocketRTp != 0) ::closesocket(fSocketRTp);
|
||||
if (fSocketRTCp != 0) ::closesocket(fSocketRTCp);
|
||||
#else
|
||||
if (fSocketRTp != 0) ::close(fSocketRTp);
|
||||
if (fSocketRTCp != 0) ::close(fSocketRTCp);
|
||||
#endif
|
||||
fSocketRTp = 0;
|
||||
fSocketRTCp = 0;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::Open()
|
||||
{
|
||||
SInt16 result = 0;
|
||||
do
|
||||
{
|
||||
Close();
|
||||
|
||||
fSocketRTp = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fSocketRTp == kInvalidSocket)
|
||||
{ result = kInvalidSocket;
|
||||
break;
|
||||
}
|
||||
|
||||
fSocketRTCp = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fSocketRTCp == kInvalidSocket)
|
||||
{ result = kInvalidSocket;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __Win32__
|
||||
u_long one = 1;
|
||||
(void)::ioctlsocket(fSocketRTp, FIONBIO, &one);
|
||||
(void)::ioctlsocket(fSocketRTCp, FIONBIO, &one);
|
||||
#else
|
||||
int flag;
|
||||
int val;
|
||||
flag = ::fcntl(fSocketRTp, F_GETFL, 0);
|
||||
val = ::fcntl(fSocketRTp, F_SETFL, flag | O_NONBLOCK);
|
||||
if( val < 0 ) { result = -1; break; }
|
||||
|
||||
|
||||
flag = ::fcntl(fSocketRTCp, F_GETFL, 0);
|
||||
val = ::fcntl(fSocketRTCp, F_SETFL, flag | O_NONBLOCK);
|
||||
if( val < 0 ) { result = -1; break; }
|
||||
#endif
|
||||
} while (false);
|
||||
|
||||
if (result != 0)
|
||||
{ if (fSocketRTp != 0) ::close(fSocketRTp);
|
||||
if (fSocketRTCp != 0) ::close(fSocketRTCp);
|
||||
fSocketRTp = 0;
|
||||
fSocketRTCp = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void UDPSocketPair::InitPorts(UInt32 addr)
|
||||
{
|
||||
::memset(&fLocalAddrRTp, 0, sizeof(fLocalAddrRTp));
|
||||
fLocalAddrRTp.sin_family = PF_INET;
|
||||
fLocalAddrRTp.sin_port = htons(0);
|
||||
fLocalAddrRTp.sin_addr.s_addr = htonl(addr);
|
||||
|
||||
::memset(&fLocalAddrRTCp, 0, sizeof(fLocalAddrRTCp));
|
||||
fLocalAddrRTCp.sin_family = PF_INET;
|
||||
fLocalAddrRTCp.sin_port = htons(0);
|
||||
fLocalAddrRTCp.sin_addr.s_addr = htonl(addr);
|
||||
|
||||
::memset(&fDestAddrRTp, 0, sizeof(fDestAddrRTp));
|
||||
fDestAddrRTp.sin_family = PF_INET;
|
||||
fDestAddrRTp.sin_port = htons(0);
|
||||
fDestAddrRTp.sin_addr.s_addr = htonl(addr);
|
||||
|
||||
::memset(&fDestAddrRTCp, 0, sizeof(fDestAddrRTCp));
|
||||
fDestAddrRTCp.sin_family = PF_INET;
|
||||
fDestAddrRTCp.sin_port = htons(0);
|
||||
fDestAddrRTCp.sin_addr.s_addr = htonl(addr);
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::Bind(UInt32 addr)
|
||||
{
|
||||
int err = -1;
|
||||
|
||||
if ( (fSocketRTp == kInvalidSocket) || (fSocketRTCp == kInvalidSocket) )
|
||||
return -1;
|
||||
|
||||
InitPorts(addr);
|
||||
|
||||
UInt32 PortRTp = eSourcePortStart;
|
||||
UInt32 PortRTCp = PortRTp + 1; // keep them together for clarity
|
||||
|
||||
for (int count = eSourcePortStart; count < eSourcePortRange; count ++)
|
||||
{
|
||||
PortRTp = count;
|
||||
Assert( (PortRTp & 1) == 0); // must be even
|
||||
count += 1;
|
||||
PortRTCp = count;
|
||||
Assert( (PortRTCp & 1) == 1);// must be odd and one more than rtp port
|
||||
|
||||
fLocalAddrRTp.sin_port = htons( (UInt16) PortRTp);
|
||||
fLocalAddrRTCp.sin_port = htons( (UInt16) PortRTCp);
|
||||
|
||||
//qtss_printf("Attempting to bind to rtp port %d \n",PortRTp);
|
||||
|
||||
err = ::bind(fSocketRTp, (sockaddr *)&fLocalAddrRTp, sizeof(fLocalAddrRTp));
|
||||
if (err != 0)
|
||||
{
|
||||
//qtss_printf("UDPSocketPair::Bind Error binding to rtp port %d \n",PortRTp);
|
||||
InitPorts(addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
err = ::bind(fSocketRTCp, (sockaddr *)&fLocalAddrRTCp, sizeof(fLocalAddrRTCp));
|
||||
if (err != 0)
|
||||
{
|
||||
//qtss_printf("UDPSocketPair::Bind Error binding to rtcp port %d \n",PortRTp);
|
||||
Close();
|
||||
Open();
|
||||
InitPorts(addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
{
|
||||
//qtss_printf("Bound to rtp port = %d, rtcp port = %d \n",PortRTp, PortRTCp);
|
||||
fState |= kBound;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
SInt16 UDPSocketPair::SendTo(int socket, sockaddr *destAddrPtr, char* inBuffer, UInt32 inLength )
|
||||
{
|
||||
SInt16 result = -1;
|
||||
do
|
||||
{
|
||||
if (inBuffer == NULL) break;
|
||||
if (destAddrPtr == NULL) break;
|
||||
if (socket == kInvalidSocket) break;
|
||||
|
||||
//qtss_printf("Sending data to %d. Addr = %d inLength = %d\n", ntohs(theAddr->sin_port), ntohl(theAddr->sin_addr.s_addr), inLength);
|
||||
::sendto(socket, inBuffer, inLength, 0, destAddrPtr, sizeof(sockaddr));
|
||||
|
||||
result = 0;
|
||||
} while (false);
|
||||
|
||||
//if (result != 0) qtss_printf("UDP SENDTO ERROR!\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SInt16 UDPSocketPair::SendRTp(char* inBuffer, UInt32 inLength)
|
||||
{
|
||||
if (fBroadcasterSession != NULL)
|
||||
{ OSMutexLocker locker(fBroadcasterSession->GetMutex());
|
||||
return (SInt16) fBroadcasterSession->SendPacket(inBuffer,inLength,fChannel);
|
||||
}
|
||||
else
|
||||
return SendTo(fSocketRTp, (sockaddr*)&fDestAddrRTp, inBuffer, inLength );
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::SendRTCp(char* inBuffer, UInt32 inLength)
|
||||
{
|
||||
if (fBroadcasterSession != NULL)
|
||||
{ OSMutexLocker locker(fBroadcasterSession->GetMutex());
|
||||
return (SInt16) fBroadcasterSession->SendPacket(inBuffer,inLength,fChannel+1);
|
||||
}
|
||||
else
|
||||
return SendTo(fSocketRTCp, (sockaddr*)&fDestAddrRTCp, inBuffer, inLength );
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::SetDestination (char *destAddress,UInt16 destPortRTp, UInt16 destPortRTCp)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
if (destAddress != NULL)
|
||||
{ UInt32 netAddress = inet_addr(destAddress);
|
||||
|
||||
fDestAddrRTp = fLocalAddrRTp;
|
||||
fDestAddrRTp.sin_port = htons(destPortRTp);
|
||||
fDestAddrRTp.sin_addr.s_addr = netAddress;
|
||||
|
||||
fDestAddrRTCp = fLocalAddrRTCp;
|
||||
fDestAddrRTCp.sin_port = htons(destPortRTCp);
|
||||
fDestAddrRTCp.sin_addr.s_addr = netAddress;
|
||||
|
||||
fIsMultiCast = SocketUtils::IsMulticastIPAddr(ntohl(netAddress));
|
||||
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::SetMulticastInterface()
|
||||
{
|
||||
// set the outgoing interface for multicast datagrams on this socket
|
||||
in_addr theLocalAddr;
|
||||
::memset(&theLocalAddr, 0, sizeof(theLocalAddr));
|
||||
|
||||
theLocalAddr.s_addr = fLocalAddrRTp.sin_addr.s_addr;
|
||||
int err = setsockopt(fSocketRTp, IPPROTO_IP, IP_MULTICAST_IF, (char*)&theLocalAddr, sizeof(theLocalAddr));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::JoinMulticast()
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
|
||||
UInt32 localAddr = fLocalAddrRTp.sin_addr.s_addr; // Already in network byte order
|
||||
|
||||
#if __solaris__
|
||||
if( localAddr == htonl(INADDR_ANY) )
|
||||
localAddr = htonl(SocketUtils::GetIPAddr(0));
|
||||
#endif
|
||||
|
||||
struct ip_mreq theMulti;
|
||||
::memset(&theMulti, 0, sizeof(theMulti));
|
||||
|
||||
theMulti.imr_multiaddr.s_addr = fDestAddrRTp.sin_addr.s_addr;
|
||||
theMulti.imr_interface.s_addr = localAddr;
|
||||
err = setsockopt(fSocketRTp, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
|
||||
(void) setsockopt(fSocketRTCp, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
|
||||
|
||||
if (err == 0)
|
||||
fMultiCastJoined = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
SInt16 UDPSocketPair::SetTTL(SInt16 timeToLive)
|
||||
{
|
||||
// set the ttl
|
||||
int nOptVal = (int)timeToLive;
|
||||
int err = 0;
|
||||
|
||||
err = setsockopt(fSocketRTp, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&nOptVal, sizeof(nOptVal));
|
||||
if (err != 0) return err;
|
||||
|
||||
err = setsockopt(fSocketRTCp, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&nOptVal, sizeof(nOptVal));
|
||||
return err;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::LeaveMulticast()
|
||||
{
|
||||
UInt32 localAddr = fLocalAddrRTp.sin_addr.s_addr; // Already in network byte order
|
||||
|
||||
#if __solaris__
|
||||
if( localAddr == htonl(INADDR_ANY) )
|
||||
localAddr = htonl(SocketUtils::GetIPAddr(0));
|
||||
#endif
|
||||
|
||||
struct ip_mreq theMulti;
|
||||
::memset(&theMulti, 0, sizeof(theMulti));
|
||||
|
||||
theMulti.imr_multiaddr.s_addr = fDestAddrRTp.sin_addr.s_addr;
|
||||
theMulti.imr_interface.s_addr = localAddr;
|
||||
|
||||
int err = setsockopt(fSocketRTp, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
|
||||
(void) setsockopt(fSocketRTCp, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&theMulti, sizeof(theMulti));
|
||||
return err;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::RecvFrom(sockaddr *RecvRTpddrPtr, int socket, char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
do
|
||||
{
|
||||
if (ioBuffer == NULL) break;
|
||||
if (RecvRTpddrPtr == NULL) break;
|
||||
if (socket == kInvalidSocket) break;
|
||||
|
||||
sockaddr_in theAddr;
|
||||
#if __Win32__ || __osf__ || __sgi__ || __hpux__
|
||||
int addrLen = sizeof(theAddr);
|
||||
#else
|
||||
socklen_t addrLen = sizeof(theAddr);
|
||||
#endif
|
||||
|
||||
SInt32 theRecvLen = ::recvfrom(socket, ioBuffer, inBufLen, 0, (sockaddr*)&theAddr, &addrLen);
|
||||
if (theRecvLen == -1) break;
|
||||
|
||||
if (outRecvLen) *outRecvLen = (UInt32)theRecvLen;
|
||||
} while (false);
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::RecvRTp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
|
||||
{
|
||||
return RecvFrom( (sockaddr *)&fDestAddrRTp, fSocketRTp, ioBuffer, inBufLen, outRecvLen);
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::RecvRTCp(char* ioBuffer, UInt32 inBufLen, UInt32* outRecvLen)
|
||||
{
|
||||
return RecvFrom( (sockaddr *)&fDestAddrRTCp, fSocketRTCp, ioBuffer, inBufLen, outRecvLen);
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::SetMultiCastOptions(SInt16 ttl)
|
||||
{
|
||||
SInt16 err = 0;
|
||||
|
||||
if (this->fIsMultiCast) do// set by SetDestination
|
||||
{
|
||||
err = this->SetTTL(ttl);
|
||||
WarnV(err == 0 , "failed to set ttl");
|
||||
if (err != 0) break;
|
||||
|
||||
err = this->SetMulticastInterface();
|
||||
WarnV(err == 0 , "failed to set multicast socket option");
|
||||
if (err != 0) break;
|
||||
|
||||
err = this->JoinMulticast();
|
||||
WarnV(err == 0 , "failed to join multicast");
|
||||
if (err != 0) break;
|
||||
|
||||
} while (false);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SInt16 UDPSocketPair::OpenAndBind( UInt16 rtpPort,UInt16 rtcpPort,char *destAddress)
|
||||
{
|
||||
SInt16 err = -1;
|
||||
|
||||
do
|
||||
{
|
||||
err = this->Open();
|
||||
if (err != 0) break;
|
||||
|
||||
err = this->Bind(INADDR_ANY);
|
||||
if (err != 0) break;
|
||||
|
||||
err = this->SetDestination (destAddress, rtpPort, rtcpPort);
|
||||
if (err != 0) break;
|
||||
|
||||
} while (false);
|
||||
|
||||
if (err)
|
||||
{
|
||||
this->Close();
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
// ************************
|
||||
//
|
||||
// RTpPacket
|
||||
//
|
||||
// ************************
|
||||
|
||||
SInt16 RTpPacket::GetSoundDescriptionRef(SoundDescription **soundDescriptionPtr)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
if (fThePacket && soundDescriptionPtr)
|
||||
{
|
||||
SInt32 minSoundLength = sizeof(SoundHeader) + sizeof(SoundDescription) + kRTpHeaderSize;
|
||||
if ( fLength >= minSoundLength )
|
||||
{
|
||||
char *offsetPtr = fThePacket + kRTpHeaderSize + sizeof(SoundHeader);
|
||||
*soundDescriptionPtr = (SoundDescription *) offsetPtr;
|
||||
SInt32 descSize = ntohl( (**soundDescriptionPtr).descSize);
|
||||
fSoundDescriptionLen = descSize;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RTpPacket::HasSoundDescription()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (fThePacket)
|
||||
{
|
||||
|
||||
// WritePacketToLog(fThePacket, fLength);
|
||||
SInt32 minSoundLength = sizeof(SoundHeader) + sizeof(SoundDescription) + kRTpHeaderSize;
|
||||
if (fLength >= minSoundLength )
|
||||
{
|
||||
char *offsetPtr = fThePacket + kRTpHeaderSize;
|
||||
SoundHeader* testHeaderPtr = (SoundHeader*) offsetPtr;
|
||||
do
|
||||
{
|
||||
if (testHeaderPtr->bytes[0] != 0x17) break;
|
||||
if (testHeaderPtr->sndtype[0] != 's') break;
|
||||
if (testHeaderPtr->sndtype[1] != 'o') break;
|
||||
if (testHeaderPtr->sndtype[2] != 'u') break;
|
||||
if (testHeaderPtr->sndtype[3] != 'n') break;
|
||||
|
||||
fHasSoundDescription = result = true;
|
||||
|
||||
} while (false);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
LogStr("has sound description soun\n");
|
||||
}
|
||||
PrintLogBuffer(true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SInt16 RTpPacket::GetHeaderInfo(UInt32 *timeStampPtr, UInt16 *sequencePtr,UInt32 *SSRCPtr, unsigned char*payloadTypeAndMarkPtr)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
|
||||
unsigned char *header8Ptr = (unsigned char *) fThePacket;
|
||||
UInt16* header16Ptr = (UInt16*)fThePacket;
|
||||
UInt32* header32Ptr = (UInt32*)fThePacket;
|
||||
|
||||
if (fThePacket && timeStampPtr && sequencePtr && SSRCPtr && payloadTypeAndMarkPtr)
|
||||
{
|
||||
*payloadTypeAndMarkPtr = header8Ptr[cPayloadType];
|
||||
*sequencePtr = ntohs(header16Ptr[cSequenceNumber]);
|
||||
*timeStampPtr = ntohl(header32Ptr[cTimeStamp]);
|
||||
*SSRCPtr = ntohl(header32Ptr[cSSRC]);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SInt16 RTpPacket::SetHeaderInfo(UInt32 timeStamp, UInt16 sequence, UInt32 SSRC, unsigned char payloadTypeAndMark)
|
||||
{
|
||||
SInt16 result = -1;
|
||||
|
||||
unsigned char *header8Ptr = (unsigned char *) fThePacket;
|
||||
UInt16* header16Ptr = (UInt16*)fThePacket;
|
||||
UInt32* header32Ptr = (UInt32*)fThePacket;
|
||||
|
||||
|
||||
if (fThePacket)
|
||||
{
|
||||
LogInt("sequence = ", sequence, " ");
|
||||
LogUInt("time = ", timeStamp, " ");
|
||||
// LogUInt("old payload = ",( UInt32 ) (header8Ptr[cPayloadType] & 0x7F)," ");
|
||||
LogUInt("payload = ",( UInt32 ) (payloadTypeAndMark & 0x7F) ," ");
|
||||
// LogUInt("old marker = ", ( UInt32 ) (header8Ptr[cPayloadType] & 0x80) ," ");
|
||||
// LogUInt("marker = ", ( UInt32 ) (payloadTypeAndMark & 0x80) ," ");
|
||||
LogUInt("ssrc = ", SSRC, "\n");
|
||||
|
||||
header8Ptr[cPayloadType] = payloadTypeAndMark;
|
||||
header16Ptr[cSequenceNumber] = htons(sequence);
|
||||
header32Ptr[cTimeStamp] = htonl(timeStamp);
|
||||
header32Ptr[cSSRC] = htonl(SSRC);
|
||||
result = 0;
|
||||
|
||||
LogBuffer();
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
327
PlaylistBroadcaster.tproj/playlist_elements.h
Normal file
327
PlaylistBroadcaster.tproj/playlist_elements.h
Normal 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
|
115
PlaylistBroadcaster.tproj/playlist_lists.cpp
Normal file
115
PlaylistBroadcaster.tproj/playlist_lists.cpp
Normal 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);
|
||||
};
|
||||
|
||||
}
|
||||
|
91
PlaylistBroadcaster.tproj/playlist_lists.h
Normal file
91
PlaylistBroadcaster.tproj/playlist_lists.h
Normal 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
|
540
PlaylistBroadcaster.tproj/playlist_parsers.cpp
Normal file
540
PlaylistBroadcaster.tproj/playlist_parsers.cpp
Normal 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,¤tString, sWordDelimeters, ¤tString);
|
||||
*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,¤tString, sLineDelimeters, ¤tString);
|
||||
listStringPtr->Parse(¤tString);
|
||||
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;
|
||||
}
|
||||
|
||||
|
109
PlaylistBroadcaster.tproj/playlist_parsers.h
Normal file
109
PlaylistBroadcaster.tproj/playlist_parsers.h
Normal 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
|
60
PlaylistBroadcaster.tproj/playlist_timestamp.h
Normal file
60
PlaylistBroadcaster.tproj/playlist_timestamp.h
Normal 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_ */
|
255
PlaylistBroadcaster.tproj/playlist_utils.cpp
Normal file
255
PlaylistBroadcaster.tproj/playlist_utils.cpp
Normal 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;
|
||||
}
|
101
PlaylistBroadcaster.tproj/playlist_utils.h
Normal file
101
PlaylistBroadcaster.tproj/playlist_utils.h
Normal 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
|
352
PlaylistBroadcaster.tproj/tailor.h
Normal file
352
PlaylistBroadcaster.tproj/tailor.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue