void MP3Broadcaster::UpdatePlaylistFiles(PlaylistPicker *picker,PlaylistPicker *insertPicker)
{
    if ( (NULL == picker) || (NULL == insertPicker) ) 
        return;
        
    /* if .stoplist file exists - prepare to stop broadcast */
    if(!access(mStopFile, R_OK))
    {
        picker->CleanList();
        PopulatePickerFromFile(picker, mStopFile, "", NULL);

        mTempPicker->CleanList();

        remove(mStopFile);
        picker->mStopFlag = true;
    }

    /* if .replacelist file exists - replace current playlist */
    if(!access(mReplaceFile, R_OK))
    {
        picker->CleanList();     
        PopulatePickerFromFile(picker, mReplaceFile, "", NULL);
        
        mTempPicker->CleanList();
        
        remove(mReplaceFile);
        picker->mStopFlag = false;
    }

    /* if .insertlist file exists - insert into current playlist */
    if(!access(mInsertFile, R_OK))
    {
        insertPicker->CleanList();
        mTempPicker->CleanList();

        PopulatePickerFromFile(insertPicker, mInsertFile, "", NULL);
        remove(mInsertFile);
        picker->mStopFlag = false;
    }


                // write upcoming playlist to .upcoming file 
    if (mShowUpcoming) 
    {
        FILE *upcomingFile = fopen(mUpcomingFile, "w");
        if(upcomingFile)
        {
            mElementCount = 0;
        
            if (!::strcmp(mPlayMode, "weighted_random")) 
                qtss_fprintf(upcomingFile,"#random play - upcoming list not supported\n");
            else
            {   qtss_fprintf(upcomingFile,"*PLAY-LIST*\n");
                ShowPlaylistElements(insertPicker,upcomingFile);
                ShowPlaylistElements(picker,upcomingFile);
                if (    picker->GetNumMovies() == 0 
                        && !picker->mStopFlag 
                        && 0 != ::strcmp(mPlayMode, "sequential") 
                    )
                {   picker->CleanList();
                    PopulatePickerFromFile(picker,mPlayListPath,"",NULL);
                    ShowPlaylistElements(picker,upcomingFile);
                    mTempPicker->CleanList();
                    PopulatePickerFromFile(mTempPicker,mPlayListPath,"",NULL);
                }
                
                if  (   mElementCount <= mUpcomingSongsListSize 
                        && 0 == ::strcmp(mPlayMode, "sequential_looped")
                    )
                {   if (mTempPicker->GetNumMovies() == 0)
                    {   mTempPicker->CleanList();
                        PopulatePickerFromFile(mTempPicker,mPlayListPath,"",NULL);
                    }
                    //sElementCount can be zero if the playlist contains no paths to valid files
                    while ( (mElementCount != 0) && mElementCount <= mUpcomingSongsListSize )
                        ShowPlaylistElements(mTempPicker,upcomingFile);
                }
            }
            fclose(upcomingFile);
        }   
    }
    else
    {   
        if (    picker->GetNumMovies() == 0 
                && !picker->mStopFlag 
                && ::strcmp(mPlayMode, "sequential") 
            )
        {   picker->CleanList();
            PopulatePickerFromFile(picker,mPlayListPath,"",NULL);
        }       
    }
}
void MP3Broadcaster::PreFlightOrBroadcast( bool preflight, bool daemonize, bool showMovieList, bool currentMovie, bool checkMP3s, const char* errorlog)
{
    PlaylistPicker*     picker = NULL;
    PlaylistPicker*     insertPicker = NULL;
    MP3FileBroadcaster  fileBroadcaster(&mSocket, mBitRate, mFrequency);
    MP3MetaInfoUpdater* metaInfoUpdater = NULL;
    
    SInt32                moviePlayCount;
    char*               thePick = NULL;
    SInt32                numMovieErrors;
   	bool				didAtLeastOneMoviePlay = false;
    int err;
        
        mPreflight = preflight;
        
    if ( preflight )
        ShowSetupParams();

    if (preflight)
        picker = new PlaylistPicker(false);             // make sequential picker, no looping
    else
    {   
        picker = MakePickerFromConfig(); // make  picker according to parms
        mTempPicker =  new PlaylistPicker(false);
        insertPicker = new PlaylistPicker(false);
        insertPicker->mRemoveFlag = true;
    }
    
    // initial call uses empty string for path, NULL for loop detection list
    (void)PopulatePickerFromFile( picker, mPlayListPath, "", NULL );
    
    if ( preflight )
    {
        if ( picker->mNumToPickFrom == 1 )
            qtss_printf( "\nThere is one movie in the Playlist.\n\n" );
        else
            qtss_printf( "\nThere are (%li) movies in the Playlist.\n\n", (SInt32) picker->mNumToPickFrom );
    }   
    
    if ( picker->mNumToPickFrom == 0 )
    {   
        qtss_printf( "- MP3Broadcaster setup failed: There are no movies to play.\n" );
        mNumErrors++;
        goto bail;
    }
    

    // check that we have enough movies to cover the recent movies list.
    if ( preflight )
    {
        if (  !strcmp( mPlayMode, "weighted_random" ) ) // this implies "random" play
        {   
            if ( mRecentSongsListSize >=  picker->mNumToPickFrom )
            {
                mRecentSongsListSize = picker->mNumToPickFrom - 1;
                qtss_printf("- PlaylistBroadcaster Warning:\n  The recent_movies_list_size setting is greater than \n");
                qtss_printf("  or equal to the number of movies in the playlist.\n" );
                                mNumWarnings++;
            }
        }
    }
    
    // create the log file
    mLog = new MP3BroadcasterLog( mWorkingDirPath,  mLogFile, mLogging );
    
//  if ( !PreflightTrackerFileAccess( R_OK | W_OK ) )
//      goto bail;

    if (!preflight)
    {
        err = ConnectToServer();
        if (err)
        {       
                        if (err == EACCES)
                            qtss_printf("- MP3Broadcaster: Disconnected from Server. Bad password or mount point\n  Exiting.\n" );
                        else
                            qtss_printf("- MP3Broadcaster: Couldn't connect to server\n  Exiting.\n" );
            mNumErrors++;
            goto bail;
        }
    }
    
    //Unless the Debug command line option is set, daemonize the process at this point
    if (daemonize)
    {   
#ifndef __Win32__
        qtss_printf("- MP3Broadcaster: Started in background.\n");
        
        // keep the same working directory..
#ifdef __sgi__
		if (::_daemonize(_DF_NOCHDIR, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO) != 0)
#else
        if (::daemon( 1, 0 ) != 0)
#endif
        {
            qtss_printf("- MP3Broadcaster:  System error (%i).\n", errno);
            mNumErrors++;
            goto bail;
        }

#endif      
    }
    
        if (daemonize && (errorlog != NULL))
    {   
                freopen(errorlog, "a", stdout);
        ::setvbuf(stdout, (char *)NULL, _IONBF, 0);
    }
        
        if (!preflight)
        {
                metaInfoUpdater = new MP3MetaInfoUpdater(mPassword, mMountPoint, mSocket.GetRemoteAddr(), mPort);
                metaInfoUpdater->Start();
                fileBroadcaster.SetInfoUpdater(metaInfoUpdater);
    }
        
        // ^ daemon must be called before we Open the log and tracker since we'll
    // get a new pid, our files close,  ( does SIGTERM get sent? )
    
    if (( mLog ) && ( mLogging ))
        mLog->EnableLog( false ); // don't append ".log" to name for PLB
    
    if ( mLogging && !mLog->IsLogEnabled() )
    {
        if (  mLog->LogDirName() && *mLog->LogDirName() )
            qtss_printf("- MP3Broadcaster: The log file failed to open.\n  ( path: %s/%s )\n  Exiting.\n", mLog->LogDirName(), mLog->LogFileName() );
        else
            qtss_printf("- MP3Broadcaster: The log file failed to open.\n  ( path: %s )\n  Exiting.\n", mLog->LogFileName() );
        
        mNumErrors++;
        goto bail;
    }
    
    
    if (mPIDFile[0] != 0)
    {
        if(!FileCreateAndCheckAccess(mPIDFile))
        {
            FILE *pidFile = fopen(mPIDFile, "w");
            if(pidFile)
            {
                qtss_fprintf(pidFile,"%d\n",getpid());
                fclose(pidFile);
            }   
        }
    }
    
//  AddOurPIDToTracker( bcastSetupFilePath ); // <-- exits on failure

    if ( !preflight )
        mLog->LogInfo( "MP3Broadcaster started." );
    else
        mLog->LogInfo( "MP3Broadcaster preflight started." );

    if(!preflight)
    {   
        CreateCurrentAndUpcomingFiles();
        SendXAudioCastHeaders();
    }
        
    if (!preflight)
    {
        // check the frequency of the first song
        fileBroadcaster.PlaySong( picker->GetFirstFile(), NULL, true, true );
    }
    
    moviePlayCount = 0;
    numMovieErrors = 0;
 	didAtLeastOneMoviePlay = false;
           
    while (true)
    {   
    
        if (!showMovieList && !preflight)
            UpdatePlaylistFiles(picker, insertPicker);
             
        if (NULL != insertPicker)
            thePick = insertPicker->PickOne(); 
            
        if (NULL == thePick && (NULL != picker))
            thePick = picker->PickOne();
                
        if ( (thePick != NULL) && (!preflight && showMovieList) )
        {
            // display the picks in debug mode, but not preflight
            qtss_printf( "[%li] %s picked\n", moviePlayCount, thePick );
        }
        
        
        if ( !showMovieList )
        {
            int playError;
                
            if(!preflight)
            {   UpdateCurrentFile(thePick);
                /* if playlist is about to run out repopulate it */
                if  (   !::strcmp(mPlayMode, "sequential_looped") )
                {   
                    if(NULL == thePick &&!picker->mStopFlag)
                    {   
                        if (picker->GetNumMovies() == 0) 
                            break;
                        else
                            continue;
                    }
                        
                }
            }

            if (thePick == NULL)
                break;
            
            ++moviePlayCount;
            
            if(!preflight)
            {
            
                SInt64 startTime = OS::Milliseconds();
                SInt64 endTime = 0;
                playError = fileBroadcaster.PlaySong( thePick, mCurrentFile );
                endTime = OS::Milliseconds();
                
				//were we able to actually play the movie?
				didAtLeastOneMoviePlay = didAtLeastOneMoviePlay || (playError == 0);
				
				//ok, we've reached the end of the current playlist
				if (picker->GetNumMovies() == 0)
				{
					//If we determine that every one of the movies resulted in an error, then bail
					if (!didAtLeastOneMoviePlay)
					{
						qtss_printf("Quitting:  Playlist contains no valid files.\n");
						mLog->LogInfo( "Quitting:  Playlist contains no valid files.\n" );
						goto bail;
					}
					else
					{
						didAtLeastOneMoviePlay = false;
					}
				}
                
                mLog->LogMediaData(thePick, fileBroadcaster.GetTitle(), 
                                            fileBroadcaster.GetArtist(), 
                                            fileBroadcaster.GetAlbum(),
                                            (UInt32) ((endTime - startTime)/1000L),
                                            playError);
            }
            else
            {
                playError = fileBroadcaster.PlaySong( thePick, NULL, preflight, !checkMP3s );
            }
            
            if (playError == MP3FileBroadcaster::kConnectionError)
            {
                // do something
                mNumErrors++;
                goto bail;
            }
            
            if ( !preflight && (playError != 0))
            {    
                 qtss_printf("File %s : ", thePick);
                 mLog->LogMediaError( thePick, MapErrorToString(playError), NULL );
            }
            else if (playError != 0)
            {
                qtss_printf("File %s : ", thePick);
                MapErrorToString(playError);
                numMovieErrors++;
                mNumWarnings++;
            }
        }
        

        delete [] thePick;
        thePick = NULL;
    } //while (true)
    
    remove(mCurrentFile);
    remove(mUpcomingFile);  

    if ( preflight )
    {
        char    str[256];   
        qtss_printf( " - "  );
        if (numMovieErrors == 1)
            strcpy(str, "MP3Broadcaster found one problem MP3 file.");
        else
            qtss_sprintf( str, "MP3Broadcaster found %li problem MP3 files." , numMovieErrors );
        qtss_printf( "%s\n", str );
        if (mLog) mLog->LogInfo( str );
        
        if (numMovieErrors == moviePlayCount)
        {
            qtss_printf("There are no valid MP3s to play\n");
            mNumErrors++;
        }
    }
    
bail:

    delete picker;

    if (metaInfoUpdater)
        delete metaInfoUpdater;
        
        Cleanup();

#ifndef __Win32__
/*
    if ( sgTrackingSucceeded )
    {
        // remove ourselves from the tracker
        // this is the "normal" remove, also signal handlers
        // may remove us.
        
        BCasterTracker  tracker( sgTrackerFilePath );
        
        tracker.RemoveByProcessID( getpid() );
        tracker.Save();
    }
*/
#endif
}
Пример #3
0
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 )
    {
        long    lineBuffSize = (kMaxPickerPath *2) - 1;
        long    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 = %lu\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;
}