comparison src/cdrom/macosx/CDPlayer.c @ 1143:71a2648acc75

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