symbian-qemu-0.9.1-12/libsdl-trunk/src/cdrom/macosx/CDPlayer.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
       
     4 
       
     5     This library is free software; you can redistribute it and/or
       
     6     modify it under the terms of the GNU Library General Public
       
     7     License as published by the Free Software Foundation; either
       
     8     version 2 of the License, or (at your option) any later version.
       
     9 
       
    10     This library is distributed in the hope that it will be useful,
       
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13     Library General Public License for more details.
       
    14 
       
    15     You should have received a copy of the GNU Library General Public
       
    16     License along with this library; if not, write to the Free
       
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    18 
       
    19     Sam Lantinga
       
    20     slouken@libsdl.org
       
    21 */
       
    22 #include "SDL_config.h"
       
    23 
       
    24 #include "CDPlayer.h"
       
    25 #include "AudioFilePlayer.h"
       
    26 #include "SDLOSXCAGuard.h"
       
    27 
       
    28 /* we're exporting these functions into C land for SDL_syscdrom.c */
       
    29 /*extern "C" {*/
       
    30 
       
    31 /*///////////////////////////////////////////////////////////////////////////
       
    32     Constants
       
    33   //////////////////////////////////////////////////////////////////////////*/
       
    34 
       
    35 #define kAudioCDFilesystemID   (UInt16)(('J' << 8) | 'H') /* 'JH'; this avoids compiler warning */
       
    36 
       
    37 /* XML PList keys */
       
    38 #define kRawTOCDataString           "Format 0x02 TOC Data"
       
    39 #define kSessionsString             "Sessions"
       
    40 #define kSessionTypeString          "Session Type"
       
    41 #define kTrackArrayString           "Track Array"
       
    42 #define kFirstTrackInSessionString      "First Track"
       
    43 #define kLastTrackInSessionString       "Last Track"
       
    44 #define kLeadoutBlockString         "Leadout Block"
       
    45 #define kDataKeyString              "Data"
       
    46 #define kPointKeyString             "Point"
       
    47 #define kSessionNumberKeyString         "Session Number"
       
    48 #define kStartBlockKeyString            "Start Block"   
       
    49     
       
    50 /*///////////////////////////////////////////////////////////////////////////
       
    51     Globals
       
    52   //////////////////////////////////////////////////////////////////////////*/
       
    53 
       
    54 #pragma mark -- Globals --
       
    55 
       
    56 static int             playBackWasInit = 0;
       
    57 static AudioUnit        theUnit;
       
    58 static AudioFilePlayer* thePlayer = NULL;
       
    59 static CDPlayerCompletionProc   completionProc = NULL;
       
    60 static SDL_mutex       *apiMutex = NULL;
       
    61 static SDL_sem         *callbackSem;
       
    62 static SDL_CD*          theCDROM;
       
    63 
       
    64 /*///////////////////////////////////////////////////////////////////////////
       
    65     Prototypes
       
    66   //////////////////////////////////////////////////////////////////////////*/
       
    67 
       
    68 #pragma mark -- Prototypes --
       
    69 
       
    70 static OSStatus CheckInit ();
       
    71 
       
    72 static void     FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus);
       
    73 
       
    74 static int      RunCallBackThread (void* inRefCon);
       
    75 
       
    76 
       
    77 #pragma mark -- Public Functions --
       
    78 
       
    79 void     Lock ()
       
    80 {
       
    81     if (!apiMutex) {
       
    82         apiMutex = SDL_CreateMutex();
       
    83     }
       
    84     SDL_mutexP(apiMutex);
       
    85 }
       
    86 
       
    87 void     Unlock ()
       
    88 {
       
    89     SDL_mutexV(apiMutex);
       
    90 }
       
    91 
       
    92 int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes)
       
    93 {
       
    94     int volumeIndex;
       
    95     int cdVolumeCount = 0;
       
    96     OSStatus result = noErr;
       
    97     
       
    98     for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++)
       
    99     {
       
   100         FSVolumeRefNum  actualVolume;
       
   101         FSVolumeInfo    volumeInfo;
       
   102         
       
   103         memset (&volumeInfo, 0, sizeof(volumeInfo));
       
   104         
       
   105         result = FSGetVolumeInfo (kFSInvalidVolumeRefNum,
       
   106                                   volumeIndex,
       
   107                                   &actualVolume,
       
   108                                   kFSVolInfoFSInfo,
       
   109                                   &volumeInfo,
       
   110                                   NULL,
       
   111                                   NULL); 
       
   112          
       
   113         if (result == noErr)
       
   114         {
       
   115             if (volumeInfo.filesystemID == kAudioCDFilesystemID) /* It's an audio CD */
       
   116             {
       
   117                 if (volumes != NULL && cdVolumeCount < numVolumes)
       
   118                     volumes[cdVolumeCount] = actualVolume;
       
   119             
       
   120                 cdVolumeCount++;
       
   121             }
       
   122         }
       
   123         else 
       
   124         {
       
   125             /* I'm commenting this out because it seems to be harmless */
       
   126             /*SDL_SetError ("DetectAudioCDVolumes: FSGetVolumeInfo returned %d", result);*/
       
   127         }
       
   128     }
       
   129         
       
   130     return cdVolumeCount;
       
   131 }
       
   132 
       
   133 int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD)
       
   134 {
       
   135     HFSUniStr255      dataForkName;
       
   136     OSStatus          theErr;
       
   137     SInt16            forkRefNum;
       
   138     SInt64            forkSize;
       
   139     Ptr               forkData = 0;
       
   140     ByteCount         actualRead;
       
   141     CFDataRef         dataRef = 0;
       
   142     CFPropertyListRef propertyListRef = 0;
       
   143 
       
   144     FSRefParam      fsRefPB;
       
   145     FSRef           tocPlistFSRef;
       
   146     
       
   147     const char* error = "Unspecified Error";
       
   148     
       
   149     /* get stuff from .TOC.plist */
       
   150     fsRefPB.ioCompletion = NULL;
       
   151     fsRefPB.ioNamePtr = "\p.TOC.plist";
       
   152     fsRefPB.ioVRefNum = theVolume;
       
   153     fsRefPB.ioDirID = 0;
       
   154     fsRefPB.newRef = &tocPlistFSRef;
       
   155     
       
   156     theErr = PBMakeFSRefSync (&fsRefPB);
       
   157     if(theErr != noErr) {
       
   158         error = "PBMakeFSRefSync";
       
   159         goto bail;
       
   160     }
       
   161     
       
   162     /* Load and parse the TOC XML data */
       
   163 
       
   164     theErr = FSGetDataForkName (&dataForkName);
       
   165     if (theErr != noErr) {
       
   166         error = "FSGetDataForkName";
       
   167         goto bail;
       
   168     }
       
   169     
       
   170     theErr = FSOpenFork (&tocPlistFSRef, dataForkName.length, dataForkName.unicode, fsRdPerm, &forkRefNum);
       
   171     if (theErr != noErr) {
       
   172         error = "FSOpenFork";
       
   173         goto bail;
       
   174     }
       
   175     
       
   176     theErr = FSGetForkSize (forkRefNum, &forkSize);
       
   177     if (theErr != noErr) {
       
   178         error = "FSGetForkSize";
       
   179         goto bail;
       
   180     }
       
   181     
       
   182     /* Allocate some memory for the XML data */
       
   183     forkData = NewPtr (forkSize);
       
   184     if(forkData == NULL) {
       
   185         error = "NewPtr";
       
   186         goto bail;
       
   187     }
       
   188     
       
   189     theErr = FSReadFork (forkRefNum, fsFromStart, 0 /* offset location */, forkSize, forkData, &actualRead);
       
   190     if(theErr != noErr) {
       
   191         error = "FSReadFork";
       
   192         goto bail;
       
   193     }
       
   194     
       
   195     dataRef = CFDataCreate (kCFAllocatorDefault, (UInt8 *)forkData, forkSize);
       
   196     if(dataRef == 0) {
       
   197         error = "CFDataCreate";
       
   198         goto bail;
       
   199     }
       
   200 
       
   201     propertyListRef = CFPropertyListCreateFromXMLData (kCFAllocatorDefault,
       
   202                                                        dataRef,
       
   203                                                        kCFPropertyListImmutable,
       
   204                                                        NULL);
       
   205     if (propertyListRef == NULL) {
       
   206         error = "CFPropertyListCreateFromXMLData";
       
   207         goto bail;
       
   208     }
       
   209 
       
   210     /* Now we got the Property List in memory. Parse it. */
       
   211     
       
   212     /* First, make sure the root item is a CFDictionary. If not, release and bail. */
       
   213     if(CFGetTypeID(propertyListRef)== CFDictionaryGetTypeID())
       
   214     {
       
   215         CFDictionaryRef dictRef = (CFDictionaryRef)propertyListRef;
       
   216         
       
   217         CFDataRef   theRawTOCDataRef;
       
   218         CFArrayRef  theSessionArrayRef;
       
   219         CFIndex     numSessions;
       
   220         CFIndex     index;
       
   221         
       
   222         /* This is how we get the Raw TOC Data */
       
   223         theRawTOCDataRef = (CFDataRef)CFDictionaryGetValue (dictRef, CFSTR(kRawTOCDataString));
       
   224         
       
   225         /* Get the session array info. */
       
   226         theSessionArrayRef = (CFArrayRef)CFDictionaryGetValue (dictRef, CFSTR(kSessionsString));
       
   227         
       
   228         /* Find out how many sessions there are. */
       
   229         numSessions = CFArrayGetCount (theSessionArrayRef);
       
   230         
       
   231         /* Initialize the total number of tracks to 0 */
       
   232         theCD->numtracks = 0;
       
   233         
       
   234         /* Iterate over all sessions, collecting the track data */
       
   235         for(index = 0; index < numSessions; index++)
       
   236         {
       
   237             CFDictionaryRef theSessionDict;
       
   238             CFNumberRef     leadoutBlock;
       
   239             CFArrayRef      trackArray;
       
   240             CFIndex         numTracks;
       
   241             CFIndex         trackIndex;
       
   242             UInt32          value = 0;
       
   243             
       
   244             theSessionDict      = (CFDictionaryRef) CFArrayGetValueAtIndex (theSessionArrayRef, index);
       
   245             leadoutBlock        = (CFNumberRef) CFDictionaryGetValue (theSessionDict, CFSTR(kLeadoutBlockString));
       
   246             
       
   247             trackArray = (CFArrayRef)CFDictionaryGetValue (theSessionDict, CFSTR(kTrackArrayString));
       
   248             
       
   249             numTracks = CFArrayGetCount (trackArray);
       
   250 
       
   251             for(trackIndex = 0; trackIndex < numTracks; trackIndex++) {
       
   252                     
       
   253                 CFDictionaryRef theTrackDict;
       
   254                 CFNumberRef     trackNumber;
       
   255                 CFNumberRef     sessionNumber;
       
   256                 CFNumberRef     startBlock;
       
   257                 CFBooleanRef    isDataTrack;
       
   258                 UInt32          value;
       
   259                 
       
   260                 theTrackDict  = (CFDictionaryRef) CFArrayGetValueAtIndex (trackArray, trackIndex);
       
   261                 
       
   262                 trackNumber   = (CFNumberRef)  CFDictionaryGetValue (theTrackDict, CFSTR(kPointKeyString));
       
   263                 sessionNumber = (CFNumberRef)  CFDictionaryGetValue (theTrackDict, CFSTR(kSessionNumberKeyString));
       
   264                 startBlock    = (CFNumberRef)  CFDictionaryGetValue (theTrackDict, CFSTR(kStartBlockKeyString));
       
   265                 isDataTrack   = (CFBooleanRef) CFDictionaryGetValue (theTrackDict, CFSTR(kDataKeyString));
       
   266                                                         
       
   267                 /* Fill in the SDL_CD struct */
       
   268                 int idx = theCD->numtracks++;
       
   269 
       
   270                 CFNumberGetValue (trackNumber, kCFNumberSInt32Type, &value);
       
   271                 theCD->track[idx].id = value;
       
   272                 
       
   273                 CFNumberGetValue (startBlock, kCFNumberSInt32Type, &value);
       
   274                 theCD->track[idx].offset = value;
       
   275 
       
   276                 theCD->track[idx].type = (isDataTrack == kCFBooleanTrue) ? SDL_DATA_TRACK : SDL_AUDIO_TRACK;
       
   277 
       
   278                 /* Since the track lengths are not stored in .TOC.plist we compute them. */
       
   279                 if (trackIndex > 0) {
       
   280                     theCD->track[idx-1].length = theCD->track[idx].offset - theCD->track[idx-1].offset;
       
   281                 }
       
   282             }
       
   283             
       
   284             /* Compute the length of the last track */
       
   285             CFNumberGetValue (leadoutBlock, kCFNumberSInt32Type, &value);
       
   286             
       
   287             theCD->track[theCD->numtracks-1].length = 
       
   288                 value - theCD->track[theCD->numtracks-1].offset;
       
   289 
       
   290             /* Set offset to leadout track */
       
   291             theCD->track[theCD->numtracks].offset = value;
       
   292         }
       
   293     
       
   294     }
       
   295 
       
   296     theErr = 0;
       
   297     goto cleanup;
       
   298 bail:
       
   299     SDL_SetError ("ReadTOCData: %s returned %d", error, theErr);
       
   300     theErr = -1;
       
   301 cleanup:
       
   302 
       
   303     if (propertyListRef != NULL)
       
   304         CFRelease(propertyListRef);
       
   305     if (dataRef != NULL)
       
   306         CFRelease(dataRef);
       
   307     if (forkData != NULL)
       
   308         DisposePtr(forkData);
       
   309         
       
   310     FSCloseFork (forkRefNum);
       
   311 
       
   312     return theErr;
       
   313 }
       
   314 
       
   315 int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks)
       
   316 {
       
   317     OSStatus        result = -1;
       
   318     FSIterator      iterator;
       
   319     ItemCount       actualObjects;
       
   320     FSRef           rootDirectory;
       
   321     FSRef           ref;
       
   322     HFSUniStr255    nameStr;
       
   323     
       
   324     result = FSGetVolumeInfo (theVolume,
       
   325                               0,
       
   326                               NULL,
       
   327                               kFSVolInfoFSInfo,
       
   328                               NULL,
       
   329                               NULL,
       
   330                               &rootDirectory); 
       
   331                                  
       
   332     if (result != noErr) {
       
   333         SDL_SetError ("ListTrackFiles: FSGetVolumeInfo returned %d", result);
       
   334         return result;
       
   335     }
       
   336 
       
   337     result = FSOpenIterator (&rootDirectory, kFSIterateFlat, &iterator);
       
   338     if (result == noErr) {
       
   339         do
       
   340         {
       
   341             result = FSGetCatalogInfoBulk (iterator, 1, &actualObjects,
       
   342                                            NULL, kFSCatInfoNone, NULL, &ref, NULL, &nameStr);
       
   343             if (result == noErr) {
       
   344                 
       
   345                 CFStringRef  name;
       
   346                 name = CFStringCreateWithCharacters (NULL, nameStr.unicode, nameStr.length);
       
   347                 
       
   348                 /* Look for .aiff extension */
       
   349                 if (CFStringHasSuffix (name, CFSTR(".aiff")) ||
       
   350                     CFStringHasSuffix (name, CFSTR(".cdda"))) {
       
   351                     
       
   352                     /* Extract the track id from the filename */
       
   353                     int trackID = 0, i = 0;
       
   354                     while (i < nameStr.length && !isdigit(nameStr.unicode[i])) {
       
   355                         ++i;
       
   356                     }
       
   357                     while (i < nameStr.length && isdigit(nameStr.unicode[i])) {
       
   358                         trackID = 10 * trackID +(nameStr.unicode[i] - '0');
       
   359                         ++i;
       
   360                     }
       
   361 
       
   362                     #if DEBUG_CDROM
       
   363                     printf("Found AIFF for track %d: '%s'\n", trackID, 
       
   364                     CFStringGetCStringPtr (name, CFStringGetSystemEncoding()));
       
   365                     #endif
       
   366                     
       
   367                     /* Track ID's start at 1, but we want to start at 0 */
       
   368                     trackID--;
       
   369                     
       
   370                     assert(0 <= trackID && trackID <= SDL_MAX_TRACKS);
       
   371                     
       
   372                     if (trackID < numTracks)
       
   373                         memcpy (&trackFiles[trackID], &ref, sizeof(FSRef));
       
   374                 }
       
   375                 CFRelease (name);
       
   376             }
       
   377         } while(noErr == result);
       
   378         FSCloseIterator (iterator);
       
   379     }
       
   380     
       
   381     return 0;
       
   382 }
       
   383 
       
   384 int LoadFile (const FSRef *ref, int startFrame, int stopFrame)
       
   385 {
       
   386     int error = -1;
       
   387     
       
   388     if (CheckInit () < 0)
       
   389         goto bail;
       
   390     
       
   391     /* release any currently playing file */
       
   392     if (ReleaseFile () < 0)
       
   393         goto bail;
       
   394     
       
   395     #if DEBUG_CDROM
       
   396     printf ("LoadFile: %d %d\n", startFrame, stopFrame);
       
   397     #endif
       
   398     
       
   399     /*try {*/
       
   400     
       
   401         /* create a new player, and attach to the audio unit */
       
   402         
       
   403         thePlayer = new_AudioFilePlayer(ref);
       
   404         if (thePlayer == NULL) {
       
   405             SDL_SetError ("LoadFile: Could not create player");
       
   406             return -3; /*throw (-3);*/
       
   407         }
       
   408             
       
   409         if (!thePlayer->SetDestination(thePlayer, &theUnit))
       
   410             goto bail;
       
   411         
       
   412         if (startFrame >= 0)
       
   413             thePlayer->SetStartFrame (thePlayer, startFrame);
       
   414         
       
   415         if (stopFrame >= 0 && stopFrame > startFrame)
       
   416             thePlayer->SetStopFrame (thePlayer, stopFrame);
       
   417         
       
   418         /* we set the notifier later */
       
   419         /*thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, NULL);*/
       
   420             
       
   421         if (!thePlayer->Connect(thePlayer))
       
   422             goto bail;
       
   423     
       
   424         #if DEBUG_CDROM
       
   425         thePlayer->Print(thePlayer);
       
   426         fflush (stdout);
       
   427         #endif
       
   428     /*}
       
   429       catch (...)
       
   430       {
       
   431           goto bail;
       
   432       }*/
       
   433         
       
   434     error = 0;
       
   435 
       
   436     bail:
       
   437     return error;
       
   438 }
       
   439 
       
   440 int ReleaseFile ()
       
   441 {
       
   442     int error = -1;
       
   443         
       
   444     /* (Don't see any way that the original C++ code could throw here.) --ryan. */
       
   445     /*try {*/
       
   446         if (thePlayer != NULL) {
       
   447             
       
   448             thePlayer->Disconnect(thePlayer);
       
   449             
       
   450             delete_AudioFilePlayer(thePlayer);
       
   451             
       
   452             thePlayer = NULL;
       
   453         }
       
   454     /*}
       
   455       catch (...)
       
   456       {
       
   457           goto bail;
       
   458       }*/
       
   459     
       
   460     error = 0;
       
   461     
       
   462 /*  bail: */
       
   463     return error;
       
   464 }
       
   465 
       
   466 int PlayFile ()
       
   467 {
       
   468     OSStatus result = -1;
       
   469     
       
   470     if (CheckInit () < 0)
       
   471         goto bail;
       
   472         
       
   473     /*try {*/
       
   474     
       
   475         // start processing of the audio unit
       
   476         result = AudioOutputUnitStart (theUnit);
       
   477             if (result) goto bail; //THROW_RESULT("PlayFile: AudioOutputUnitStart")
       
   478         
       
   479     /*}
       
   480     catch (...)
       
   481     {
       
   482         goto bail;
       
   483     }*/
       
   484     
       
   485     result = 0;
       
   486     
       
   487 bail:
       
   488     return result;
       
   489 }
       
   490 
       
   491 int PauseFile ()
       
   492 {
       
   493     OSStatus result = -1;
       
   494     
       
   495     if (CheckInit () < 0)
       
   496         goto bail;
       
   497             
       
   498     /*try {*/
       
   499     
       
   500         /* stop processing the audio unit */
       
   501         result = AudioOutputUnitStop (theUnit);
       
   502             if (result) goto bail;  /*THROW_RESULT("PauseFile: AudioOutputUnitStop")*/
       
   503     /*}
       
   504       catch (...)
       
   505       {
       
   506           goto bail;
       
   507       }*/
       
   508     
       
   509     result = 0;
       
   510 bail:
       
   511     return result;
       
   512 }
       
   513 
       
   514 void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom)
       
   515 {
       
   516     assert(thePlayer != NULL);
       
   517 
       
   518     theCDROM = cdrom;
       
   519     completionProc = proc;
       
   520     thePlayer->SetNotifier (thePlayer, FilePlayNotificationHandler, cdrom);
       
   521 }
       
   522 
       
   523 int GetCurrentFrame ()
       
   524 {    
       
   525     int frame;
       
   526     
       
   527     if (thePlayer == NULL)
       
   528         frame = 0;
       
   529     else
       
   530         frame = thePlayer->GetCurrentFrame (thePlayer);
       
   531         
       
   532     return frame; 
       
   533 }
       
   534 
       
   535 
       
   536 #pragma mark -- Private Functions --
       
   537 
       
   538 static OSStatus CheckInit ()
       
   539 {    
       
   540     if (playBackWasInit)
       
   541         return 0;
       
   542     
       
   543     OSStatus result = noErr;
       
   544     
       
   545     /* Create the callback semaphore */
       
   546     callbackSem = SDL_CreateSemaphore(0);
       
   547 
       
   548     /* Start callback thread */
       
   549     SDL_CreateThread(RunCallBackThread, NULL);
       
   550 
       
   551     { /*try {*/
       
   552         ComponentDescription desc;
       
   553     
       
   554         desc.componentType = kAudioUnitComponentType;
       
   555         desc.componentSubType = kAudioUnitSubType_Output;
       
   556         desc.componentManufacturer = kAudioUnitID_DefaultOutput;
       
   557         desc.componentFlags = 0;
       
   558         desc.componentFlagsMask = 0;
       
   559         
       
   560         Component comp = FindNextComponent (NULL, &desc);
       
   561         if (comp == NULL) {
       
   562             SDL_SetError ("CheckInit: FindNextComponent returned NULL");
       
   563             if (result) return -1; //throw(internalComponentErr);
       
   564         }
       
   565         
       
   566         result = OpenAComponent (comp, &theUnit);
       
   567             if (result) return -1; //THROW_RESULT("CheckInit: OpenAComponent")
       
   568                     
       
   569         // you need to initialize the output unit before you set it as a destination
       
   570         result = AudioUnitInitialize (theUnit);
       
   571             if (result) return -1; //THROW_RESULT("CheckInit: AudioUnitInitialize")
       
   572         
       
   573                     
       
   574         playBackWasInit = true;
       
   575     }
       
   576     /*catch (...)
       
   577       {
       
   578           return -1;
       
   579       }*/
       
   580     
       
   581     return 0;
       
   582 }
       
   583 
       
   584 static void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus)
       
   585 {
       
   586     if (inStatus == kAudioFilePlay_FileIsFinished) {
       
   587     
       
   588         /* notify non-CA thread to perform the callback */
       
   589         SDL_SemPost(callbackSem);
       
   590         
       
   591     } else if (inStatus == kAudioFilePlayErr_FilePlayUnderrun) {
       
   592     
       
   593         SDL_SetError ("CDPlayer Notification: buffer underrun");
       
   594     } else if (inStatus == kAudioFilePlay_PlayerIsUninitialized) {
       
   595     
       
   596         SDL_SetError ("CDPlayer Notification: player is uninitialized");
       
   597     } else {
       
   598         
       
   599         SDL_SetError ("CDPlayer Notification: unknown error %ld", inStatus);
       
   600     }
       
   601 }
       
   602 
       
   603 static int RunCallBackThread (void *param)
       
   604 {
       
   605     for (;;) {
       
   606     
       
   607 	SDL_SemWait(callbackSem);
       
   608 
       
   609         if (completionProc && theCDROM) {
       
   610             #if DEBUG_CDROM
       
   611             printf ("callback!\n");
       
   612             #endif
       
   613             (*completionProc)(theCDROM);
       
   614         } else {
       
   615             #if DEBUG_CDROM
       
   616             printf ("callback?\n");
       
   617             #endif
       
   618         }
       
   619     }
       
   620     
       
   621     #if DEBUG_CDROM
       
   622     printf ("thread dying now...\n");
       
   623     #endif
       
   624     
       
   625     return 0;
       
   626 }
       
   627 
       
   628 /*}; // extern "C" */