Mercurial > sdl-ios-xcode
comparison src/cdrom/macosx/SDL_syscdrom_c.h @ 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 |
comparison
equal
deleted
inserted
replaced
612:0648505b1f8b | 613:9c6717a1c66f |
---|---|
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 | |
24 /*********************************************************************************** | |
25 Implementation Notes | |
26 ********************* | |
27 | |
28 This code has several limitations currently (all of which are proabaly fixable): | |
29 | |
30 1. A CD-ROM device is inferred from a mounted cdfs volume, so device 0 is | |
31 not necessarily the first CD-ROM device on the system. (Somewhat easy to fix | |
32 by useing the device name from the volume id's to reorder the volumes) | |
33 | |
34 2. You can only open and control 1 CD-ROM device at a time. (Challenging to fix, | |
35 due to extensive code restructuring) | |
36 | |
37 3. The status reported by SDL_CDStatus only changes to from CD_PLAYING to CD_STOPPED in | |
38 1-second intervals (because the audio is buffered in 1-second chunks) If | |
39 the audio data is less than 1 second, the remainder is filled with silence. | |
40 | |
41 If you need to play sequences back-to-back that are less that 1 second long, | |
42 use the frame position to determine when to play the next sequence, instead | |
43 of SDL_CDStatus. | |
44 | |
45 This may be possible to fix with a clever usage of the AudioUnit API. | |
46 | |
47 4. When new volumes are inserted, our volume information is not updated. The only way | |
48 to refresh this information is to reinit the CD-ROM subsystem of SDL. To fix this, | |
49 one would probably have to fix point 1 above first, then figure out how to register | |
50 for a notification when new media is mounted in order to perform an automatic | |
51 rescan for cdfs volumes. | |
52 | |
53 | |
54 | |
55 So, here comes a description of how this all works. | |
56 | |
57 < Initializing > | |
58 | |
59 To get things rolling, we have to locate mounted volumes that contain | |
60 audio (since nearly all Macs don't have analog audio-in on the sound card). | |
61 That's easy, since these volumes have a flag that indicates this special | |
62 filesystem. See DetectAudioCDVolumes() in CDPlayer.cpp for this code. | |
63 | |
64 Next, we parse the invisible .TOC.plist in the root of the volume, which gets us | |
65 the track information (number, offset, length, leadout, etc). See ReadTOCData() in | |
66 CDPlayer.cpp for the skinny on this. | |
67 | |
68 | |
69 < The Playback Loop > | |
70 | |
71 Now come the tricky parts. Let's start with basic audio playback. When a frame | |
72 range to play is requested, we must first find the .aiff files on the volume, | |
73 hopefully in the right order. Since these files all begin with a number "1 Audio Track", | |
74 etc, this is used to determine the correct track order. | |
75 | |
76 Once all files are determined, we have to find what file corresponds to the start | |
77 and length parameter to SDL_SYS_CDPlay(). Again, this is quite simple by walking the | |
78 cdrom's track list. At this point, we also save the offset to the next track and frames | |
79 remaining, if we're going to have to play another file after the first one. See | |
80 GetFileForOffset() for this code. | |
81 | |
82 At this point we have all info needed to start playback, so we hand off to the LoadFile() | |
83 function, which proceeds to do its magic and plays back the file. | |
84 | |
85 When the file is finished playing, CompletionProc() is invoked, at which time we can | |
86 play the next file if the previously saved next track and frames remaining | |
87 indicates that we should. | |
88 | |
89 | |
90 < Magic > | |
91 | |
92 OK, so it's not really magic, but since I don't fully understand all the hidden details it | |
93 seems like it to me ;-) The API's involved are the AudioUnit and AudioFile API's. These | |
94 appear to be an extension of CoreAudio for creating modular playback and f/x entities. | |
95 The important thing is that CPU usage is very low and reliability is very high. You'd | |
96 be hard-pressed to find a way to stutter the playback with other CPU-intensive tasks. | |
97 | |
98 One part of this magic is that it uses multiple threads, which carries the usual potential | |
99 for disaster if not handled carefully. Playback currently requires 4 additional threads: | |
100 1. The coreaudio runloop thread | |
101 2. The coreaudio device i/o thread | |
102 3. The file streaming thread | |
103 4. The notification/callback thread | |
104 | |
105 The first 2 threads are necessary evil - CoreAudio creates this no matter what the situation | |
106 is (even the SDL sound implementation creates theses suckers). The last two are are created | |
107 by us. | |
108 | |
109 The file is streamed from disk using a threaded double-buffer approach. | |
110 This way, the high latency operation of reading from disk can be performed without interrupting | |
111 the real-time device thread (which amounts to avoiding dropouts). The device thread grabs the | |
112 buffer that isn't being read and sends it to the CoreAudio mixer where it eventually gets | |
113 to the sound card. | |
114 | |
115 The device thread posts a notification when the file streaming thread is out of data. This | |
116 notification must be handled in a separate thread to avoid potential deadlock in the | |
117 device thread. That's where the notification thread comes in. This thread is signaled | |
118 whenever a notification needs to be processed, so another file can be played back if need be. | |
119 | |
120 The API in CDPlayer.cpp contains synchronization because otherwise both the notification thread | |
121 and main thread (or another other thread using the SDL CD api) can potentially call it at the same time. | |
122 | |
123 ************************************************************************************/ | |
124 | |
125 | |
126 #include "SDL_cdrom.h" | |
127 #include "SDL_syscdrom.h" | |
128 | |
129 #include "CDPlayer.h" | |
130 | |
131 #define kErrorFakeDevice "Error: Cannot proceed since we're faking a CD-ROM device. Reinit the CD-ROM subsystem to scan for new volumes." | |
132 |