Mercurial > sdl-ios-xcode
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" |