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