diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cdrom/macosx/SDL_syscdrom_c.h	Tue Apr 15 16:33:56 2003 +0000
@@ -0,0 +1,132 @@
+/*
+    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
+*/
+
+
+/***********************************************************************************
+ Implementation Notes
+ *********************
+
+    This code has several limitations currently (all of which are proabaly fixable):
+    
+    1. A CD-ROM device is inferred from a mounted cdfs volume, so device 0 is
+       not necessarily the first CD-ROM device on the system. (Somewhat easy to fix
+       by useing the device name from the volume id's to reorder the volumes)
+       
+    2. You can only open and control 1 CD-ROM device at a time. (Challenging to fix,
+       due to extensive code restructuring)
+    
+    3. The status reported by SDL_CDStatus only changes to from CD_PLAYING to CD_STOPPED in
+       1-second intervals (because the audio is buffered in 1-second chunks) If
+       the audio data is less than 1 second, the remainder is filled with silence.
+       
+       If you need to play sequences back-to-back that are less that 1 second long,
+       use the frame position to determine when to play the next sequence, instead
+       of SDL_CDStatus.
+       
+       This may be possible to fix with a clever usage of the AudioUnit API.
+       
+    4. When new volumes are inserted, our volume information is not updated. The only way
+       to refresh this information is to reinit the CD-ROM subsystem of SDL. To fix this,
+       one would probably have to fix point 1 above first, then figure out how to register
+       for a notification when new media is mounted in order to perform an automatic
+       rescan for cdfs volumes.
+    
+    
+    
+    So, here comes a description of how this all works.
+    
+        < Initializing >
+        
+        To get things rolling, we have to locate mounted volumes that contain
+        audio (since nearly all Macs don't have analog audio-in on the sound card).
+        That's easy, since these volumes have a flag that indicates this special
+        filesystem. See DetectAudioCDVolumes() in CDPlayer.cpp for this code.
+        
+        Next, we parse the invisible .TOC.plist in the root of the volume, which gets us
+        the track information (number, offset, length, leadout, etc). See ReadTOCData() in
+        CDPlayer.cpp for the skinny on this.
+        
+        
+        < The Playback Loop >
+        
+        Now come the tricky parts. Let's start with basic audio playback. When a frame
+        range to play is requested, we must first find the .aiff files on the volume, 
+        hopefully in the right order. Since these files all begin with a number "1 Audio Track", 
+        etc, this is used to determine the correct track order.
+        
+        Once all files are determined, we have to find what file corresponds to the start
+        and length parameter to SDL_SYS_CDPlay(). Again, this is quite simple by walking the
+        cdrom's track list. At this point, we also save the offset to the next track and frames
+        remaining, if we're going to have to play another file after the first one. See
+        GetFileForOffset() for this code.
+        
+        At this point we have all info needed to start playback, so we hand off to the LoadFile()
+        function, which proceeds to do its magic and plays back the file.
+        
+        When the file is finished playing, CompletionProc() is invoked, at which time we can
+        play the next file if the previously saved next track and frames remaining
+        indicates that we should. 
+        
+        
+        < Magic >
+        
+        OK, so it's not really magic, but since I don't fully understand all the hidden details it
+        seems like it to me ;-) The API's involved are the AudioUnit and AudioFile API's. These
+        appear to be an extension of CoreAudio for creating modular playback and f/x entities.
+        The important thing is that CPU usage is very low and reliability is very high. You'd
+        be hard-pressed to find a way to stutter the playback with other CPU-intensive tasks.
+    
+        One part of this magic is that it uses multiple threads, which carries the usual potential
+        for disaster if not handled carefully. Playback currently requires 4 additional threads:
+            1. The coreaudio runloop thread
+            2. The coreaudio device i/o thread
+            3. The file streaming thread
+            4. The notification/callback thread
+        
+        The first 2 threads are necessary evil - CoreAudio creates this no matter what the situation
+        is (even the SDL sound implementation creates theses suckers). The last two are are created
+        by us.
+        
+        The file is streamed from disk using a threaded double-buffer approach. 
+        This way, the high latency operation of reading from disk can be performed without interrupting
+        the real-time device thread (which amounts to avoiding dropouts). The device thread grabs the
+        buffer that isn't being read and sends it to the CoreAudio mixer where it eventually gets 
+        to the sound card.
+        
+        The device thread posts a notification when the file streaming thread is out of data. This
+        notification must be handled in a separate thread to avoid potential deadlock in the
+        device thread. That's where the notification thread comes in. This thread is signaled
+        whenever a notification needs to be processed, so another file can be played back if need be.
+        
+        The API in CDPlayer.cpp contains synchronization because otherwise both the notification thread
+        and main thread (or another other thread using the SDL CD api) can potentially call it at the same time.
+    
+************************************************************************************/
+
+
+#include "SDL_cdrom.h"
+#include "SDL_syscdrom.h"
+
+#include "CDPlayer.h"
+
+#define kErrorFakeDevice "Error: Cannot proceed since we're faking a CD-ROM device. Reinit the CD-ROM subsystem to scan for new volumes."
+