Mercurial > sdl-ios-xcode
diff src/cdrom/macosx/CDPlayer.cpp @ 613:9c6717a1c66f
Added MacOS X CD-ROM audio support (thanks Max and Darrell)
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Tue, 15 Apr 2003 16:33:56 +0000 |
parents | |
children | de1b2c3063b9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cdrom/macosx/CDPlayer.cpp Tue Apr 15 16:33:56 2003 +0000 @@ -0,0 +1,715 @@ +/* + 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 "CDPlayer.h" +#include "AudioFilePlayer.h" +#include "CAGuard.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 bool playBackWasInit = false; +static AudioUnit theUnit; +static AudioFilePlayer* thePlayer = NULL; +static CDPlayerCompletionProc completionProc = NULL; +static pthread_mutex_t apiMutex; +static pthread_t callbackThread; +static pthread_mutex_t callbackMutex; +static volatile int runCallBackThread; +static int initMutex = SDL_TRUE; +static SDL_CD* theCDROM; + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// Prototypes +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +#pragma mark -- Prototypes -- + +OSStatus CheckInit (); + +OSStatus MatchAUFormats (AudioUnit theUnit, UInt32 theInputBus); + +void FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus); + +void* RunCallBackThread (void* inRefCon); + + +#pragma mark -- Public Functions -- + +void Lock () +{ + if (initMutex) { + + pthread_mutexattr_t attr; + + pthread_mutexattr_init (&attr); + pthread_mutex_init (&apiMutex, &attr); + pthread_mutexattr_destroy (&attr); + + initMutex = SDL_FALSE; + } + + pthread_mutex_lock (&apiMutex); +} + +void Unlock () +{ + pthread_mutex_unlock (&apiMutex); +} + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// DetectAudioCDVolumes +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes) +{ + int volumeIndex; + int cdVolumeCount = 0; + OSStatus result = noErr; + + for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++) + { + FSVolumeRefNum actualVolume; + HFSUniStr255 volumeName; + FSVolumeInfo volumeInfo; + FSRef rootDirectory; + + memset (&volumeInfo, 0, sizeof(volumeInfo)); + + result = FSGetVolumeInfo (kFSInvalidVolumeRefNum, + volumeIndex, + &actualVolume, + kFSVolInfoFSInfo, + &volumeInfo, + &volumeName, + &rootDirectory); + + 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; +} + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// ReadTOCData +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +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; +} + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// ListTrackFiles +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +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); + goto bail; + } + + 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"))) { + + // Extract the track id from the filename + int trackID = 0, i = 0; + while (nameStr.unicode[i] >= '0' && nameStr.unicode[i] <= '9') { + 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); + } + + result = 0; + bail: + return result; +} + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// LoadFile +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +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"); + throw (-3); + } + + thePlayer->SetDestination(theUnit, 0); + + if (startFrame >= 0) + thePlayer->SetStartFrame (startFrame); + + if (stopFrame >= 0 && stopFrame > startFrame) + thePlayer->SetStopFrame (stopFrame); + + // we set the notifier later + //thePlayer->SetNotifier(FilePlayNotificationHandler, NULL); + + thePlayer->Connect(); + + #if DEBUG_CDROM + thePlayer->Print(); + fflush (stdout); + #endif + } + catch (...) + { + goto bail; + } + + error = 0; + + bail: + return error; +} + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// ReleaseFile +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +int ReleaseFile () +{ + int error = -1; + + try { + if (thePlayer != NULL) { + + thePlayer->Disconnect(); + + delete thePlayer; + + thePlayer = NULL; + } + } + catch (...) + { + goto bail; + } + + error = 0; + + bail: + return error; +} + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// PlayFile +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +int PlayFile () +{ + OSStatus result = -1; + + if (CheckInit () < 0) + goto bail; + + try { + + // start processing of the audio unit + result = AudioOutputUnitStart (theUnit); + THROW_RESULT("PlayFile: AudioOutputUnitStart") + + } + catch (...) + { + goto bail; + } + + result = 0; + +bail: + return result; +} + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// PauseFile +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +int PauseFile () +{ + OSStatus result = -1; + + if (CheckInit () < 0) + goto bail; + + try { + + // stop processing the audio unit + result = AudioOutputUnitStop (theUnit); + THROW_RESULT("PauseFile: AudioOutputUnitStop") + } + catch (...) + { + goto bail; + } + + result = 0; +bail: + return result; +} + +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ +// SetCompletionProc +//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ + +void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom) +{ + assert(thePlayer != NULL); + + theCDROM = cdrom; + completionProc = proc; + thePlayer->SetNotifier (FilePlayNotificationHandler, cdrom); +} + + +int GetCurrentFrame () +{ + int frame; + + if (thePlayer == NULL) + frame = 0; + else + frame = thePlayer->GetCurrentFrame (); + + return frame; +} + + +#pragma mark -- Private Functions -- + +OSStatus CheckInit () +{ + if (playBackWasInit) + return 0; + + OSStatus result = noErr; + + + // Create the callback mutex + pthread_mutexattr_t attr; + pthread_mutexattr_init (&attr); + pthread_mutex_init (&callbackMutex, &attr); + pthread_mutexattr_destroy (&attr); + pthread_mutex_lock (&callbackMutex); + + // Start callback thread + pthread_attr_t attr1; + pthread_attr_init (&attr1); + pthread_create (&callbackThread, &attr1, RunCallBackThread, NULL); + pthread_attr_destroy (&attr1); + + 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"); + throw(internalComponentErr); + } + + result = OpenAComponent (comp, &theUnit); + THROW_RESULT("CheckInit: OpenAComponent") + + // you need to initialize the output unit before you set it as a destination + result = AudioUnitInitialize (theUnit); + THROW_RESULT("CheckInit: AudioUnitInitialize") + + + // In this case we first want to get the output format of the OutputUnit + // Then we set that as the input format. Why? + // So that only a single conversion process is done + // when SetDestination is called it will get the input format of the + // unit its supplying data to. This defaults to 44.1K, stereo, so if + // the device is not that, then we lose a possibly rendering of data + + result = MatchAUFormats (theUnit, 0); + THROW_RESULT("CheckInit: MatchAUFormats") + + playBackWasInit = true; + } + catch (...) + { + return -1; + } + + return 0; +} + + +OSStatus MatchAUFormats (AudioUnit theUnit, UInt32 theInputBus) +{ + AudioStreamBasicDescription theDesc; + UInt32 size = sizeof (theDesc); + OSStatus result = AudioUnitGetProperty (theUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 0, + &theDesc, + &size); + THROW_RESULT("MatchAUFormats: AudioUnitGetProperty") + + result = AudioUnitSetProperty (theUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + theInputBus, + &theDesc, + size); + + return result; +} + +void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus) +{ + if (inStatus == kAudioFilePlay_FileIsFinished) { + + // notify non-CA thread to perform the callback + pthread_mutex_unlock (&callbackMutex); + + } 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); + } +} + +void* RunCallBackThread (void *param) +{ + runCallBackThread = 1; + + while (runCallBackThread) { + + pthread_mutex_lock (&callbackMutex); + + if (completionProc && theCDROM) { + #if DEBUG_CDROM + printf ("callback!\n"); + #endif + (*completionProc)(theCDROM); + } else { + #if DEBUG_CDROM + printf ("callback?\n"); + #endif + } + } + + runCallBackThread = -1; + + #if DEBUG_CDROM + printf ("thread dying now...\n"); + #endif + + return NULL; +} + +}; // extern "C"