symbian-qemu-0.9.1-12/libsdl-trunk/src/cdrom/macosx/CDPlayer.c
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/libsdl-trunk/src/cdrom/macosx/CDPlayer.c	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,628 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "CDPlayer.h"
+#include "AudioFilePlayer.h"
+#include "SDLOSXCAGuard.h"
+
+/* we're exporting these functions into C land for SDL_syscdrom.c */
+/*extern "C" {*/
+
+/*///////////////////////////////////////////////////////////////////////////
+    Constants
+  //////////////////////////////////////////////////////////////////////////*/
+
+#define kAudioCDFilesystemID   (UInt16)(('J' << 8) | 'H') /* 'JH'; this avoids compiler warning */
+
+/* XML PList keys */
+#define kRawTOCDataString           "Format 0x02 TOC Data"
+#define kSessionsString             "Sessions"
+#define kSessionTypeString          "Session Type"
+#define kTrackArrayString           "Track Array"
+#define kFirstTrackInSessionString      "First Track"
+#define kLastTrackInSessionString       "Last Track"
+#define kLeadoutBlockString         "Leadout Block"
+#define kDataKeyString              "Data"
+#define kPointKeyString             "Point"
+#define kSessionNumberKeyString         "Session Number"
+#define kStartBlockKeyString            "Start Block"   
+    
+/*///////////////////////////////////////////////////////////////////////////
+    Globals
+  //////////////////////////////////////////////////////////////////////////*/
+
+#pragma mark -- Globals --
+
+static int             playBackWasInit = 0;
+static AudioUnit        theUnit;
+static AudioFilePlayer* thePlayer = NULL;
+static CDPlayerCompletionProc   completionProc = NULL;
+static SDL_mutex       *apiMutex = NULL;
+static SDL_sem         *callbackSem;
+static SDL_CD*          theCDROM;
+
+/*///////////////////////////////////////////////////////////////////////////
+    Prototypes
+  //////////////////////////////////////////////////////////////////////////*/
+
+#pragma mark -- Prototypes --
+
+static OSStatus CheckInit ();
+
+static void     FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus);
+
+static int      RunCallBackThread (void* inRefCon);
+
+
+#pragma mark -- Public Functions --
+
+void     Lock ()
+{
+    if (!apiMutex) {
+        apiMutex = SDL_CreateMutex();
+    }
+    SDL_mutexP(apiMutex);
+}
+
+void     Unlock ()
+{
+    SDL_mutexV(apiMutex);
+}
+
+int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes)
+{
+    int volumeIndex;
+    int cdVolumeCount = 0;
+    OSStatus result = noErr;
+    
+    for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++)
+    {
+        FSVolumeRefNum  actualVolume;
+        FSVolumeInfo    volumeInfo;
+        
+        memset (&volumeInfo, 0, sizeof(volumeInfo));
+        
+        result = FSGetVolumeInfo (kFSInvalidVolumeRefNum,
+                                  volumeIndex,
+                                  &actualVolume,
+                                  kFSVolInfoFSInfo,
+                                  &volumeInfo,
+                                  NULL,
+                                  NULL); 
+         
+        if (result == noErr)
+        {
+            if (volumeInfo.filesystemID == kAudioCDFilesystemID) /* It's an audio CD */
+            {
+                if (volumes != NULL && cdVolumeCount < numVolumes)
+                    volumes[cdVolumeCount] = actualVolume;
+            
+                cdVolumeCount++;
+            }
+        }
+        else 
+        {
+            /* I'm commenting this out because it seems to be harmless */
+            /*SDL_SetError ("DetectAudioCDVolumes: FSGetVolumeInfo returned %d", result);*/
+        }
+    }
+        
+    return cdVolumeCount;
+}
+
+int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD)
+{
+    HFSUniStr255      dataForkName;
+    OSStatus          theErr;
+    SInt16            forkRefNum;
+    SInt64            forkSize;
+    Ptr               forkData = 0;
+    ByteCount         actualRead;
+    CFDataRef         dataRef = 0;
+    CFPropertyListRef propertyListRef = 0;
+
+    FSRefParam      fsRefPB;
+    FSRef           tocPlistFSRef;
+    
+    const char* error = "Unspecified Error";
+    
+    /* get stuff from .TOC.plist */
+    fsRefPB.ioCompletion = NULL;
+    fsRefPB.ioNamePtr = "\p.TOC.plist";
+    fsRefPB.ioVRefNum = theVolume;
+    fsRefPB.ioDirID = 0;
+    fsRefPB.newRef = &tocPlistFSRef;
+    
+    theErr = PBMakeFSRefSync (&fsRefPB);
+    if(theErr != noErr) {
+        error = "PBMakeFSRefSync";
+        goto bail;
+    }
+    
+    /* Load and parse the TOC XML data */
+
+    theErr = FSGetDataForkName (&dataForkName);
+    if (theErr != noErr) {
+        error = "FSGetDataForkName";
+        goto bail;
+    }
+    
+    theErr = FSOpenFork (&tocPlistFSRef, dataForkName.length, dataForkName.unicode, fsRdPerm, &forkRefNum);
+    if (theErr != noErr) {
+        error = "FSOpenFork";
+        goto bail;
+    }
+    
+    theErr = FSGetForkSize (forkRefNum, &forkSize);
+    if (theErr != noErr) {
+        error = "FSGetForkSize";
+        goto bail;
+    }
+    
+    /* Allocate some memory for the XML data */
+    forkData = NewPtr (forkSize);
+    if(forkData == NULL) {
+        error = "NewPtr";
+        goto bail;
+    }
+    
+    theErr = FSReadFork (forkRefNum, fsFromStart, 0 /* offset location */, forkSize, forkData, &actualRead);
+    if(theErr != noErr) {
+        error = "FSReadFork";
+        goto bail;
+    }
+    
+    dataRef = CFDataCreate (kCFAllocatorDefault, (UInt8 *)forkData, forkSize);
+    if(dataRef == 0) {
+        error = "CFDataCreate";
+        goto bail;
+    }
+
+    propertyListRef = CFPropertyListCreateFromXMLData (kCFAllocatorDefault,
+                                                       dataRef,
+                                                       kCFPropertyListImmutable,
+                                                       NULL);
+    if (propertyListRef == NULL) {
+        error = "CFPropertyListCreateFromXMLData";
+        goto bail;
+    }
+
+    /* Now we got the Property List in memory. Parse it. */
+    
+    /* First, make sure the root item is a CFDictionary. If not, release and bail. */
+    if(CFGetTypeID(propertyListRef)== CFDictionaryGetTypeID())
+    {
+        CFDictionaryRef dictRef = (CFDictionaryRef)propertyListRef;
+        
+        CFDataRef   theRawTOCDataRef;
+        CFArrayRef  theSessionArrayRef;
+        CFIndex     numSessions;
+        CFIndex     index;
+        
+        /* This is how we get the Raw TOC Data */
+        theRawTOCDataRef = (CFDataRef)CFDictionaryGetValue (dictRef, CFSTR(kRawTOCDataString));
+        
+        /* Get the session array info. */
+        theSessionArrayRef = (CFArrayRef)CFDictionaryGetValue (dictRef, CFSTR(kSessionsString));
+        
+        /* Find out how many sessions there are. */
+        numSessions = CFArrayGetCount (theSessionArrayRef);
+        
+        /* Initialize the total number of tracks to 0 */
+        theCD->numtracks = 0;
+        
+        /* Iterate over all sessions, collecting the track data */
+        for(index = 0; index < numSessions; index++)
+        {
+            CFDictionaryRef theSessionDict;
+            CFNumberRef     leadoutBlock;
+            CFArrayRef      trackArray;
+            CFIndex         numTracks;
+            CFIndex         trackIndex;
+            UInt32          value = 0;
+            
+            theSessionDict      = (CFDictionaryRef) CFArrayGetValueAtIndex (theSessionArrayRef, index);
+            leadoutBlock        = (CFNumberRef) CFDictionaryGetValue (theSessionDict, CFSTR(kLeadoutBlockString));
+            
+            trackArray = (CFArrayRef)CFDictionaryGetValue (theSessionDict, CFSTR(kTrackArrayString));
+            
+            numTracks = CFArrayGetCount (trackArray);
+
+            for(trackIndex = 0; trackIndex < numTracks; trackIndex++) {
+                    
+                CFDictionaryRef theTrackDict;
+                CFNumberRef     trackNumber;
+                CFNumberRef     sessionNumber;
+                CFNumberRef     startBlock;
+                CFBooleanRef    isDataTrack;
+                UInt32          value;
+                
+                theTrackDict  = (CFDictionaryRef) CFArrayGetValueAtIndex (trackArray, trackIndex);
+                
+                trackNumber   = (CFNumberRef)  CFDictionaryGetValue (theTrackDict, CFSTR(kPointKeyString));
+                sessionNumber = (CFNumberRef)  CFDictionaryGetValue (theTrackDict, CFSTR(kSessionNumberKeyString));
+                startBlock    = (CFNumberRef)  CFDictionaryGetValue (theTrackDict, CFSTR(kStartBlockKeyString));
+                isDataTrack   = (CFBooleanRef) CFDictionaryGetValue (theTrackDict, CFSTR(kDataKeyString));
+                                                        
+                /* Fill in the SDL_CD struct */
+                int idx = theCD->numtracks++;
+
+                CFNumberGetValue (trackNumber, kCFNumberSInt32Type, &value);
+                theCD->track[idx].id = value;
+                
+                CFNumberGetValue (startBlock, kCFNumberSInt32Type, &value);
+                theCD->track[idx].offset = value;
+
+                theCD->track[idx].type = (isDataTrack == kCFBooleanTrue) ? SDL_DATA_TRACK : SDL_AUDIO_TRACK;
+
+                /* Since the track lengths are not stored in .TOC.plist we compute them. */
+                if (trackIndex > 0) {
+                    theCD->track[idx-1].length = theCD->track[idx].offset - theCD->track[idx-1].offset;
+                }
+            }
+            
+            /* Compute the length of the last track */
+            CFNumberGetValue (leadoutBlock, kCFNumberSInt32Type, &value);
+            
+            theCD->track[theCD->numtracks-1].length = 
+                value - theCD->track[theCD->numtracks-1].offset;
+
+            /* Set offset to leadout track */
+            theCD->track[theCD->numtracks].offset = value;
+        }
+    
+    }
+
+    theErr = 0;
+    goto cleanup;
+bail:
+    SDL_SetError ("ReadTOCData: %s returned %d", error, theErr);
+    theErr = -1;
+cleanup:
+
+    if (propertyListRef != NULL)
+        CFRelease(propertyListRef);
+    if (dataRef != NULL)
+        CFRelease(dataRef);
+    if (forkData != NULL)
+        DisposePtr(forkData);
+        
+    FSCloseFork (forkRefNum);
+
+    return theErr;
+}
+
+int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks)
+{
+    OSStatus        result = -1;
+    FSIterator      iterator;
+    ItemCount       actualObjects;
+    FSRef           rootDirectory;
+    FSRef           ref;
+    HFSUniStr255    nameStr;
+    
+    result = FSGetVolumeInfo (theVolume,
+                              0,
+                              NULL,
+                              kFSVolInfoFSInfo,
+                              NULL,
+                              NULL,
+                              &rootDirectory); 
+                                 
+    if (result != noErr) {
+        SDL_SetError ("ListTrackFiles: FSGetVolumeInfo returned %d", result);
+        return result;
+    }
+
+    result = FSOpenIterator (&rootDirectory, kFSIterateFlat, &iterator);
+    if (result == noErr) {
+        do
+        {
+            result = FSGetCatalogInfoBulk (iterator, 1, &actualObjects,
+                                           NULL, kFSCatInfoNone, NULL, &ref, NULL, &nameStr);
+            if (result == noErr) {
+                
+                CFStringRef  name;
+                name = CFStringCreateWithCharacters (NULL, nameStr.unicode, nameStr.length);
+                
+                /* Look for .aiff extension */
+                if (CFStringHasSuffix (name, CFSTR(".aiff")) ||
+                    CFStringHasSuffix (name, CFSTR(".cdda"))) {
+                    
+                    /* Extract the track id from the filename */
+                    int trackID = 0, i = 0;
+                    while (i < nameStr.length && !isdigit(nameStr.unicode[i])) {
+                        ++i;
+                    }
+                    while (i < nameStr.length && isdigit(nameStr.unicode[i])) {
+                        trackID = 10 * trackID +(nameStr.unicode[i] - '0');
+                        ++i;
+                    }
+
+                    #if DEBUG_CDROM
+                    printf("Found AIFF for track %d: '%s'\n", trackID, 
+                    CFStringGetCStringPtr (name, CFStringGetSystemEncoding()));
+                    #endif
+                    
+                    /* Track ID's start at 1, but we want to start at 0 */
+                    trackID--;
+                    
+                    assert(0 <= trackID && trackID <= SDL_MAX_TRACKS);
+                    
+                    if (trackID < numTracks)
+                        memcpy (&trackFiles[trackID], &ref, sizeof(FSRef));
+                }
+                CFRelease (name);
+            }
+        } while(noErr == result);
+        FSCloseIterator (iterator);
+    }
+    
+    return 0;
+}
+
+int LoadFile (const FSRef *ref, int startFrame, int stopFrame)
+{
+    int error = -1;
+    
+    if (CheckInit () < 0)
+        goto bail;
+    
+    /* release any currently playing file */
+    if (ReleaseFile () < 0)
+        goto bail;
+    
+    #if DEBUG_CDROM
+    printf ("LoadFile: %d %d\n", startFrame, stopFrame);
+    #endif
+    
+    /*try {*/
+    
+        /* create a new player, and attach to the audio unit */
+        
+        thePlayer = new_AudioFilePlayer(ref);
+        if (thePlayer == NULL) {
+            SDL_SetError ("LoadFile: Could not create player");
+            return -3; /*throw (-3);*/
+        }
+            
+        if (!thePlayer->SetDestination(thePlayer, &theUnit))
+            goto bail;
+        
+        if (startFrame >= 0)
+            thePlayer->SetStartFrame (thePlayer, startFrame);
+        
+        if (stopFrame >= 0 && stopFrame > startFrame)
+            thePlayer->SetStopFrame (thePlayer, stopFrame);
+        
+        /* we set the notifier later */
+        /*thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, NULL);*/
+            
+        if (!thePlayer->Connect(thePlayer))
+            goto bail;
+    
+        #if DEBUG_CDROM
+        thePlayer->Print(thePlayer);
+        fflush (stdout);
+        #endif
+    /*}
+      catch (...)
+      {
+          goto bail;
+      }*/
+        
+    error = 0;
+
+    bail:
+    return error;
+}
+
+int ReleaseFile ()
+{
+    int error = -1;
+        
+    /* (Don't see any way that the original C++ code could throw here.) --ryan. */
+    /*try {*/
+        if (thePlayer != NULL) {
+            
+            thePlayer->Disconnect(thePlayer);
+            
+            delete_AudioFilePlayer(thePlayer);
+            
+            thePlayer = NULL;
+        }
+    /*}
+      catch (...)
+      {
+          goto bail;
+      }*/
+    
+    error = 0;
+    
+/*  bail: */
+    return error;
+}
+
+int PlayFile ()
+{
+    OSStatus result = -1;
+    
+    if (CheckInit () < 0)
+        goto bail;
+        
+    /*try {*/
+    
+        // start processing of the audio unit
+        result = AudioOutputUnitStart (theUnit);
+            if (result) goto bail; //THROW_RESULT("PlayFile: AudioOutputUnitStart")
+        
+    /*}
+    catch (...)
+    {
+        goto bail;
+    }*/
+    
+    result = 0;
+    
+bail:
+    return result;
+}
+
+int PauseFile ()
+{
+    OSStatus result = -1;
+    
+    if (CheckInit () < 0)
+        goto bail;
+            
+    /*try {*/
+    
+        /* stop processing the audio unit */
+        result = AudioOutputUnitStop (theUnit);
+            if (result) goto bail;  /*THROW_RESULT("PauseFile: AudioOutputUnitStop")*/
+    /*}
+      catch (...)
+      {
+          goto bail;
+      }*/
+    
+    result = 0;
+bail:
+    return result;
+}
+
+void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom)
+{
+    assert(thePlayer != NULL);
+
+    theCDROM = cdrom;
+    completionProc = proc;
+    thePlayer->SetNotifier (thePlayer, FilePlayNotificationHandler, cdrom);
+}
+
+int GetCurrentFrame ()
+{    
+    int frame;
+    
+    if (thePlayer == NULL)
+        frame = 0;
+    else
+        frame = thePlayer->GetCurrentFrame (thePlayer);
+        
+    return frame; 
+}
+
+
+#pragma mark -- Private Functions --
+
+static OSStatus CheckInit ()
+{    
+    if (playBackWasInit)
+        return 0;
+    
+    OSStatus result = noErr;
+    
+    /* Create the callback semaphore */
+    callbackSem = SDL_CreateSemaphore(0);
+
+    /* Start callback thread */
+    SDL_CreateThread(RunCallBackThread, NULL);
+
+    { /*try {*/
+        ComponentDescription desc;
+    
+        desc.componentType = kAudioUnitComponentType;
+        desc.componentSubType = kAudioUnitSubType_Output;
+        desc.componentManufacturer = kAudioUnitID_DefaultOutput;
+        desc.componentFlags = 0;
+        desc.componentFlagsMask = 0;
+        
+        Component comp = FindNextComponent (NULL, &desc);
+        if (comp == NULL) {
+            SDL_SetError ("CheckInit: FindNextComponent returned NULL");
+            if (result) return -1; //throw(internalComponentErr);
+        }
+        
+        result = OpenAComponent (comp, &theUnit);
+            if (result) return -1; //THROW_RESULT("CheckInit: OpenAComponent")
+                    
+        // you need to initialize the output unit before you set it as a destination
+        result = AudioUnitInitialize (theUnit);
+            if (result) return -1; //THROW_RESULT("CheckInit: AudioUnitInitialize")
+        
+                    
+        playBackWasInit = true;
+    }
+    /*catch (...)
+      {
+          return -1;
+      }*/
+    
+    return 0;
+}
+
+static void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus)
+{
+    if (inStatus == kAudioFilePlay_FileIsFinished) {
+    
+        /* notify non-CA thread to perform the callback */
+        SDL_SemPost(callbackSem);
+        
+    } else if (inStatus == kAudioFilePlayErr_FilePlayUnderrun) {
+    
+        SDL_SetError ("CDPlayer Notification: buffer underrun");
+    } else if (inStatus == kAudioFilePlay_PlayerIsUninitialized) {
+    
+        SDL_SetError ("CDPlayer Notification: player is uninitialized");
+    } else {
+        
+        SDL_SetError ("CDPlayer Notification: unknown error %ld", inStatus);
+    }
+}
+
+static int RunCallBackThread (void *param)
+{
+    for (;;) {
+    
+	SDL_SemWait(callbackSem);
+
+        if (completionProc && theCDROM) {
+            #if DEBUG_CDROM
+            printf ("callback!\n");
+            #endif
+            (*completionProc)(theCDROM);
+        } else {
+            #if DEBUG_CDROM
+            printf ("callback?\n");
+            #endif
+        }
+    }
+    
+    #if DEBUG_CDROM
+    printf ("thread dying now...\n");
+    #endif
+    
+    return 0;
+}
+
+/*}; // extern "C" */