changeset 3784:37c9c4590689 SDL-ryan-multiple-audio-device

First batch of heavy lifting on supporting multiple audio devices at once. This has a long way to go yet, most of the drivers aren't updated for the new interfaces, and it's still got some obvious bugs, FIXMEs, and wistlist items. Don't use yet.
author Ryan C. Gordon <icculus@icculus.org>
date Sun, 01 Oct 2006 05:24:03 +0000
parents dc3870a3f30d
children da2ea0694d11
files include/SDL_audio.h src/audio/SDL_audio.c src/audio/SDL_mixer.c src/audio/SDL_sysaudio.h src/audio/disk/SDL_diskaudio.c src/audio/dummy/SDL_dummyaudio.c src/audio/macosx/SDL_coreaudio.c src/audio/macosx/SDL_coreaudio.h src/audio/macrom/SDL_romaudio.c src/audio/macrom/SDL_romaudio.h
diffstat 10 files changed, 636 insertions(+), 514 deletions(-) [+]
line wrap: on
line diff
--- a/include/SDL_audio.h	Sun Oct 01 05:21:40 2006 +0000
+++ b/include/SDL_audio.h	Sun Oct 01 05:24:03 2006 +0000
@@ -212,7 +212,7 @@
  * may modify the requested size of the audio buffer, you should allocate
  * any local mixing buffers after you open the audio device.
  */
-extern DECLSPEC int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
+extern DECLSPEC int SDLCALL SDL_OpenAudio(const SDL_AudioSpec * desired,
                                           SDL_AudioSpec * obtained);
 
 /*
@@ -243,7 +243,8 @@
 /*
  * Open a specific audio device. Passing in a device name of NULL is
  *  equivalent to SDL_OpenAudio(). Returns 0 on error, a valid device ID
- *  on success.
+ *  on success. SDL_OpenAudio(), unlike this function, always acts on device
+ *  ID 1.
  */
 extern DECLSPEC SDL_AudioDeviceID SDLCALL SDL_OpenAudioDevice(const char
                                                               *device,
--- a/src/audio/SDL_audio.c	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/SDL_audio.c	Sun Oct 01 05:24:03 2006 +0000
@@ -34,6 +34,12 @@
 #include <os2.h>
 #endif
 
+static SDL_AudioDriver current_audio;
+
+/* !!! FIXME: don't use a static array, but it's Good Enough For Now... */
+static SDL_AudioDevice *open_devices[16];
+
+
 /* Available audio drivers */
 static AudioBootStrap *bootstrap[] = {
 #if SDL_AUDIO_DRIVER_BSD
@@ -109,27 +115,38 @@
 #endif
     NULL
 };
-SDL_AudioDevice *current_audio = NULL;
-
-/* Various local functions */
-int SDL_AudioInit(const char *driver_name);
-void SDL_AudioQuit(void);
 
 #if SDL_AUDIO_DRIVER_AHI
 static int audio_configured = 0;
 #endif
 
+static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id)
+{
+    id--;
+    if ( (id >= SDL_arraysize(open_devices)) || (open_devices[id] == NULL) ) {
+        SDL_SetError("Invalid audio device ID");
+        return NULL;
+    }
+
+    return open_devices[id];
+}
+
+
 /* The general mixing thread function */
 int SDLCALL
-SDL_RunAudio(void *audiop)
+SDL_RunAudio(void *devicep)
 {
-    SDL_AudioDevice *audio = (SDL_AudioDevice *) audiop;
+    SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
+    const int legacy_device = (device == open_devices[0]);
     Uint8 *stream;
     int stream_len;
     void *udata;
     void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
     int silence;
+
+/* !!! FIXME: can we push this into the Amiga driver? */
 #if SDL_AUDIO_DRIVER_AHI
+#error this is probably broken.
     int started = 0;
 
 /* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */
@@ -145,14 +162,14 @@
 #endif
 
     /* Perform any thread setup */
-    if (audio->ThreadInit) {
-        audio->ThreadInit(audio);
+    if (current_audio.impl.ThreadInit != NULL) {
+        current_audio.impl.ThreadInit(device);
     }
-    audio->threadid = SDL_ThreadID();
+    device->threadid = SDL_ThreadID();
 
     /* Set up the mixing function */
-    fill = audio->spec.callback;
-    udata = audio->spec.userdata;
+    fill = device->spec.callback;
+    udata = device->spec.userdata;
 
 #if SDL_AUDIO_DRIVER_AHI
     audio_configured = 1;
@@ -162,23 +179,24 @@
     D(bug("Semaphore obtained...\n"));
 #endif
 
-    if (audio->convert.needed) {
-        if (audio->convert.src_format == AUDIO_U8) {
+    if (device->convert.needed) {
+        if (device->convert.src_format == AUDIO_U8) {
             silence = 0x80;
         } else {
             silence = 0;
         }
-        stream_len = audio->convert.len;
+        stream_len = device->convert.len;
     } else {
-        silence = audio->spec.silence;
-        stream_len = audio->spec.size;
+        silence = device->spec.silence;
+        stream_len = device->spec.size;
     }
 
 #if SDL_AUDIO_DRIVER_AHI
-    SDL_mutexV(audio->mixer_lock);
+    SDL_mutexV(device->mixer_lock);
     D(bug("Entering audio loop...\n"));
 #endif
 
+/* !!! FIXME: push this out of core. */
 #ifdef __OS2__
     /* Increase the priority of this thread to make sure that
        the audio will be continuous all the time! */
@@ -202,55 +220,59 @@
 #endif
 
     /* Loop, filling the audio buffers */
-    while (audio->enabled) {
+    while (device->enabled) {
 
         /* Fill the current buffer with sound */
-        if (audio->convert.needed) {
-            if (audio->convert.buf) {
-                stream = audio->convert.buf;
+        if (device->convert.needed) {
+            if (device->convert.buf) {
+                stream = device->convert.buf;
             } else {
                 continue;
             }
         } else {
-            stream = audio->GetAudioBuf(audio);
+            stream = current_audio.impl.GetAudioBuf(device);
             if (stream == NULL) {
-                stream = audio->fake_stream;
+                stream = device->fake_stream;
             }
         }
-        SDL_memset(stream, silence, stream_len);
 
-        if (!audio->paused) {
-            SDL_mutexP(audio->mixer_lock);
+        /* New code should fill buffer or set it to silence themselves. */
+        if (legacy_device) {
+            SDL_memset(stream, silence, stream_len);
+        }
+
+        if (!device->paused) {
+            SDL_mutexP(device->mixer_lock);
             (*fill) (udata, stream, stream_len);
-            SDL_mutexV(audio->mixer_lock);
+            SDL_mutexV(device->mixer_lock);
         }
 
         /* Convert the audio if necessary */
-        if (audio->convert.needed) {
-            SDL_ConvertAudio(&audio->convert);
-            stream = audio->GetAudioBuf(audio);
+        if (device->convert.needed) {
+            SDL_ConvertAudio(&device->convert);
+            stream = current_audio.impl.GetAudioBuf(device);
             if (stream == NULL) {
-                stream = audio->fake_stream;
+                stream = device->fake_stream;
             }
-            SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
+            SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt);
         }
 
         /* Ready current buffer for play and change current buffer */
-        if (stream != audio->fake_stream) {
-            audio->PlayAudio(audio);
+        if (stream != device->fake_stream) {
+            current_audio.impl.PlayAudio(device);
         }
 
         /* Wait for an audio buffer to become available */
-        if (stream == audio->fake_stream) {
-            SDL_Delay((audio->spec.samples * 1000) / audio->spec.freq);
+        if (stream == device->fake_stream) {
+            SDL_Delay((device->spec.samples * 1000) / device->spec.freq);
         } else {
-            audio->WaitAudio(audio);
+            current_audio.impl.WaitAudio(device);
         }
     }
 
     /* Wait for the audio to drain.. */
-    if (audio->WaitDone) {
-        audio->WaitDone(audio);
+    if (current_audio.impl.WaitDone) {
+        current_audio.impl.WaitDone(device);
     }
 #if SDL_AUDIO_DRIVER_AHI
     D(bug("WaitAudio...Done\n"));
@@ -330,20 +352,24 @@
 int
 SDL_AudioInit(const char *driver_name)
 {
-    SDL_AudioDevice *audio;
-    int i = 0, idx;
+    int i = 0;
+    int initialized = 0;
 
-    /* Check to make sure we don't overwrite 'current_audio' */
-    if (current_audio != NULL) {
-        SDL_AudioQuit();
+    if (SDL_WasInit(SDL_INIT_AUDIO)) {
+        SDL_AudioQuit();  /* shutdown driver if already running. */
     }
 
+    SDL_memset(&current_audio, '\0', sizeof (current_audio));
+    SDL_memset(open_devices, '\0', sizeof (open_devices));
+
+    /* !!! FIXME: build a priority list of available drivers... */
+
     /* Select the proper audio driver */
-    audio = NULL;
-    idx = 0;
     if (driver_name == NULL) {
         driver_name = SDL_getenv("SDL_AUDIODRIVER");
     }
+
+/* !!! FIXME: move this esound shite into the esound driver... */
 #if SDL_AUDIO_DRIVER_ESD
     if ((driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL)) {
         /* Ahem, we know that if ESPEAKER is set, user probably wants
@@ -362,7 +388,10 @@
                 }
 #endif
                 if (bootstrap[i]->available()) {
-                    audio = bootstrap[i]->create(0);
+                    SDL_memset(&current_audio, 0, sizeof (current_audio));
+                    current_audio.name = bootstrap[i]->name;
+                    current_audio.desc = bootstrap[i]->desc;
+                    initialized = bootstrap[i]->init(&current_audio.impl);
                     break;
                 }
 #ifdef HAVE_UNSETENV
@@ -374,47 +403,44 @@
         }
     }
 #endif /* SDL_AUDIO_DRIVER_ESD */
-    if (audio == NULL) {
+
+    if (!initialized) {
         if (driver_name != NULL) {
             for (i = 0; bootstrap[i]; ++i) {
                 if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
                     if (bootstrap[i]->available()) {
-                        audio = bootstrap[i]->create(idx);
+                        SDL_memset(&current_audio, 0, sizeof (current_audio));
+                        current_audio.name = bootstrap[i]->name;
+                        current_audio.desc = bootstrap[i]->desc;
+                        initialized = bootstrap[i]->init(&current_audio.impl);
                     }
                     break;
                 }
             }
         } else {
-            for (i = 0; bootstrap[i]; ++i) {
+            for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
                 if (bootstrap[i]->available()) {
-                    audio = bootstrap[i]->create(idx);
-                    if (audio != NULL) {
-                        break;
-                    }
+                    SDL_memset(&current_audio, 0, sizeof (current_audio));
+                    current_audio.name = bootstrap[i]->name;
+                    current_audio.desc = bootstrap[i]->desc;
+                    initialized = bootstrap[i]->init(&current_audio.impl);
                 }
             }
         }
-        if (audio == NULL) {
+        if (!initialized) {
             if (driver_name) {
                 SDL_SetError("%s not available", driver_name);
             } else {
                 SDL_SetError("No available audio device");
             }
-#if 0
-            /* Don't fail SDL_Init() if audio isn't available.
-               SDL_OpenAudio() will handle it at that point.  *sigh*
-             */
-            return (-1);
-#endif
+            SDL_memset(&current_audio, 0, sizeof (current_audio));
+            return (-1);  /* No driver was available, so fail. */
         }
     }
-    current_audio = audio;
-    if (current_audio) {
-        current_audio->name = bootstrap[i]->name;
-        if (!current_audio->LockAudio && !current_audio->UnlockAudio) {
-            current_audio->LockAudio = SDL_LockAudio_Default;
-            current_audio->UnlockAudio = SDL_UnlockAudio_Default;
-        }
+
+    if (!current_audio.impl.LockAudio && !current_audio.impl.UnlockAudio) {
+        current_audio.impl.LockAudio = SDL_LockAudio_Default;
+        current_audio.impl.UnlockAudio = SDL_UnlockAudio_Default;
     }
     return (0);
 }
@@ -425,123 +451,161 @@
 const char *
 SDL_GetCurrentAudioDriver()
 {
-    if (current_audio) {
-        return current_audio->name;
-    }
-    return (NULL);
+    return current_audio.name;
 }
 
-int
-SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
+static void
+close_audio_device(SDL_AudioDevice *device)
 {
-    SDL_AudioDevice *audio;
-    const char *env;
+    device->enabled = 0;
+    if (device->thread != NULL) {
+        SDL_WaitThread(device->thread, NULL);
+    }
+    if (device->mixer_lock != NULL) {
+        SDL_DestroyMutex(device->mixer_lock);
+    }
+    if (device->fake_stream != NULL) {
+        SDL_FreeAudioMem(device->fake_stream);
+    }
+    if (device->convert.needed) {
+        SDL_FreeAudioMem(device->convert.buf);
+    }
+#if !SDL_AUDIO_DRIVER_AHI   /* !!! FIXME: get rid of this #if. */
+    if (device->opened) {
+        current_audio.impl.CloseAudio(device);
+        device->opened = 0;
+    }
+#endif
+    SDL_FreeAudioMem(device);
+}
 
-    /* Start up the audio driver, if necessary */
-    if (!current_audio) {
-        if ((SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
-            (current_audio == NULL)) {
-            return (-1);
-        }
-    }
-    audio = current_audio;
 
-    if (audio->opened) {
-        SDL_SetError("Audio device is already opened");
-        return (-1);
+/*
+ * Sanity check desired AudioSpec for SDL_OpenAudio() in (orig).
+ *  Fills in a sanitized copy in (prepared).
+ *  Returns non-zero if okay, zero on fatal parameters in (orig).
+ */
+static int
+prepare_audiospec(const SDL_AudioSpec *orig, SDL_AudioSpec *prepared)
+{
+    SDL_memcpy(prepared, orig, sizeof (SDL_AudioSpec));
+
+    if (orig->callback == NULL) {
+        SDL_SetError("SDL_OpenAudio() passed a NULL callback");
+        return 0;
     }
 
-    /* Verify some parameters */
-    if (desired->freq == 0) {
-        env = SDL_getenv("SDL_AUDIO_FREQUENCY");
-        if (env) {
-            desired->freq = SDL_atoi(env);
+    if (orig->freq == 0) {
+        const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY");
+        if ( (!env) || ((prepared->freq = SDL_atoi(env)) == 0) ) {
+            prepared->freq = 22050;  /* a reasonable default */
         }
     }
-    if (desired->freq == 0) {
-        /* Pick some default audio frequency */
-        desired->freq = 22050;
-    }
-    if (desired->format == 0) {
-        env = SDL_getenv("SDL_AUDIO_FORMAT");
-        if (env) {
-            desired->format = SDL_ParseAudioFormat(env);
+
+    if (orig->format == 0) {
+        const char *env = SDL_getenv("SDL_AUDIO_FORMAT");
+        if ((!env) || ((prepared->format = SDL_ParseAudioFormat(env)) == 0)) {
+            prepared->format = AUDIO_S16;  /* a reasonable default */
         }
     }
-    if (desired->format == 0) {
-        /* Pick some default audio format */
-        desired->format = AUDIO_S16;
+
+    switch (orig->channels) {
+    case 0: {
+        const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
+        if ( (!env) || ((prepared->channels = SDL_atoi(env)) == 0) ) {
+            prepared->channels = 2;  /* a reasonable default */
+        }
+        break;
     }
-    if (desired->channels == 0) {
-        env = SDL_getenv("SDL_AUDIO_CHANNELS");
-        if (env) {
-            desired->channels = (Uint8) SDL_atoi(env);
-        }
-    }
-    if (desired->channels == 0) {
-        /* Pick a default number of channels */
-        desired->channels = 2;
-    }
-    switch (desired->channels) {
     case 1:                    /* Mono */
     case 2:                    /* Stereo */
     case 4:                    /* surround */
     case 6:                    /* surround with center and lfe */
         break;
     default:
-        SDL_SetError("1 (mono) and 2 (stereo) channels supported");
-        return (-1);
+        SDL_SetError("Unsupported number of audio channels.");
+        return 0;
     }
-    if (desired->samples == 0) {
-        env = SDL_getenv("SDL_AUDIO_SAMPLES");
-        if (env) {
-            desired->samples = (Uint16) SDL_atoi(env);
+
+    if (orig->samples == 0) {
+        const char *env = SDL_getenv("SDL_AUDIO_SAMPLES");
+        if ( (!env) || ((prepared->samples = (Uint16) SDL_atoi(env)) == 0) ) {
+            /* Pick a default of ~46 ms at desired frequency */
+            /* !!! FIXME: remove this when the non-Po2 resampling is in. */
+            const int samples = (prepared->freq / 1000) * 46;
+            int power2 = 1;
+            while (power2 < samples) {
+                power2 *= 2;
+            }
+            prepared->samples = power2;
         }
     }
-    if (desired->samples == 0) {
-        /* Pick a default of ~46 ms at desired frequency */
-        int samples = (desired->freq / 1000) * 46;
-        int power2 = 1;
-        while (power2 < samples) {
-            power2 *= 2;
-        }
-        desired->samples = power2;
+
+    /* Calculate the silence and size of the audio specification */
+    SDL_CalculateAudioSpec(prepared);
+
+    return 1;
+}
+
+
+static SDL_AudioDeviceID
+open_audio_device(const char *devname, int iscapture,
+                    const SDL_AudioSpec *_desired, SDL_AudioSpec *obtained,
+                    int min_id)
+{
+    int i = 0;
+    SDL_AudioDeviceID id = 0;
+    SDL_AudioSpec desired;
+    SDL_AudioDevice *device;
+
+    if (iscapture) {
+        SDL_SetError("Audio capture support not implemented yet!");
+        return 0;  /* !!! FIXME */
     }
-    if (desired->callback == NULL) {
-        SDL_SetError("SDL_OpenAudio() passed a NULL callback");
-        return (-1);
+
+    if (!SDL_WasInit(SDL_INIT_AUDIO)) {
+        SDL_SetError("Audio subsystem is not initialized");
+        return 0;
+    }
+
+    if (!prepare_audiospec(_desired, &desired)) {
+        return 0;
     }
+
+    device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof (SDL_AudioDevice));
+    if (device == NULL) {
+        SDL_OutOfMemory();
+        return 0;
+    }
+    SDL_memset(device, '\0', sizeof (SDL_AudioDevice));
+    SDL_memcpy(&device->spec, &desired, sizeof (SDL_AudioSpec));
+    device->driver = &current_audio;  /* !!! FIXME: unused... */
+    device->enabled = 1;
+    device->paused = 1;
+
+/* !!! FIXME: Get this out of the core. */
 #if defined(__MINT__) && SDL_THREADS_DISABLED
     /* Uses interrupt driven audio, without thread */
 #else
     /* Create a semaphore for locking the sound buffers */
-    audio->mixer_lock = SDL_CreateMutex();
-    if (audio->mixer_lock == NULL) {
+    device->mixer_lock = SDL_CreateMutex();
+    if (device->mixer_lock == NULL) {
         SDL_SetError("Couldn't create mixer lock");
-        SDL_CloseAudio();
-        return (-1);
+        return 0;
     }
 #endif /* __MINT__ */
 
-    /* Calculate the silence and size of the audio specification */
-    SDL_CalculateAudioSpec(desired);
-
-    /* Open the audio subsystem */
-    SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
-    audio->convert.needed = 0;
-    audio->enabled = 1;
-    audio->paused = 1;
-
+/* !!! FIXME: Get this #if out of the core. */
+/* AmigaOS opens audio inside the main loop */
 #if !SDL_AUDIO_DRIVER_AHI
-
-/* AmigaOS opens audio inside the main loop */
-    audio->opened = audio->OpenAudio(audio, &audio->spec) + 1;
+    if (!current_audio.impl.OpenAudio(device, devname, iscapture)) {
+        close_audio_device(device);
+        return 0;
+    }
+    device->opened = 2;  /* !!! FIXME */
+#else
+#   error needs to be fixed for new internal API. Email Ryan for details.
 
-    if (!audio->opened) {
-        SDL_CloseAudio();
-        return (-1);
-    }
-#else
     D(bug("Locking semaphore..."));
     SDL_mutexP(audio->mixer_lock);
 
@@ -553,7 +617,7 @@
         SDL_mutexV(audio->mixer_lock);
         SDL_CloseAudio();
         SDL_SetError("Couldn't create audio thread");
-        return (-1);
+        return 0;
     }
 
     while (!audio_configured)
@@ -561,61 +625,78 @@
 #endif
 
     /* If the audio driver changes the buffer size, accept it */
-    if (audio->spec.samples != desired->samples) {
-        desired->samples = audio->spec.samples;
-        SDL_CalculateAudioSpec(desired);
+    if (device->spec.samples != desired.samples) {
+        desired.samples = device->spec.samples;
+        SDL_CalculateAudioSpec(&device->spec);
     }
 
     /* Allocate a fake audio memory buffer */
-    audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
-    if (audio->fake_stream == NULL) {
-        SDL_CloseAudio();
+    device->fake_stream = SDL_AllocAudioMem(device->spec.size);
+    if (device->fake_stream == NULL) {
+        close_audio_device(device);
         SDL_OutOfMemory();
-        return (-1);
+        return 0;
     }
 
     /* See if we need to do any conversion */
     if (obtained != NULL) {
-        SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec));
-    } else if (desired->freq != audio->spec.freq ||
-               desired->format != audio->spec.format ||
-               desired->channels != audio->spec.channels) {
+        SDL_memcpy(obtained, &device->spec, sizeof(SDL_AudioSpec));
+    } else if (desired.freq != device->spec.freq ||
+               desired.format != device->spec.format ||
+               desired.channels != device->spec.channels) {
         /* Build an audio conversion block */
-        if (SDL_BuildAudioCVT(&audio->convert,
-                              desired->format, desired->channels,
-                              desired->freq,
-                              audio->spec.format, audio->spec.channels,
-                              audio->spec.freq) < 0) {
-            SDL_CloseAudio();
-            return (-1);
+        if (SDL_BuildAudioCVT(&device->convert,
+                              desired.format, desired.channels,
+                              desired.freq,
+                              device->spec.format, device->spec.channels,
+                              device->spec.freq) < 0) {
+            close_audio_device(device);
+            return 0;
         }
-        if (audio->convert.needed) {
-            audio->convert.len = desired->size;
-            audio->convert.buf =
-                (Uint8 *) SDL_AllocAudioMem(audio->convert.len *
-                                            audio->convert.len_mult);
-            if (audio->convert.buf == NULL) {
-                SDL_CloseAudio();
+        if (device->convert.needed) {
+            device->convert.len = desired.size;
+            device->convert.buf =
+                (Uint8 *) SDL_AllocAudioMem(device->convert.len *
+                                            device->convert.len_mult);
+            if (device->convert.buf == NULL) {
+                close_audio_device(device);
                 SDL_OutOfMemory();
-                return (-1);
+                return 0;
             }
         }
     }
+
+    /* Find an available device ID and store the structure... */
+    for (id = min_id-1; id < SDL_arraysize(open_devices); id++) {
+        if (open_devices[id] == NULL) {
+            open_devices[id] = device;
+            break;
+        }
+    }
+
+    /* !!! FIXME: remove static array... */
+    if (id == SDL_arraysize(open_devices)) {
+        SDL_SetError("Too many open audio devices");
+        close_audio_device(device);
+        return 0;
+    }
+
 #if !SDL_AUDIO_DRIVER_AHI
     /* Start the audio thread if necessary */
-    switch (audio->opened) {
+    switch (device->opened) {  /* !!! FIXME: what is this?! */
     case 1:
         /* Start the audio thread */
+/* !!! FIXME: this is nasty. */
 #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
 #undef SDL_CreateThread
-        audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL);
+        device->thread = SDL_CreateThread(SDL_RunAudio, device, NULL, NULL);
 #else
-        audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
+        device->thread = SDL_CreateThread(SDL_RunAudio, device);
 #endif
-        if (audio->thread == NULL) {
-            SDL_CloseAudio();
+        if (device->thread == NULL) {
+            SDL_CloseAudioDevice(id+1);
             SDL_SetError("Couldn't create audio thread");
-            return (-1);
+            return 0;
         }
         break;
 
@@ -629,18 +710,52 @@
 
 #endif
 
-    return (0);
+    return id+1;
+}
+
+
+int
+SDL_OpenAudio(const SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
+{
+    SDL_AudioDeviceID id = 0;
+
+    /* Start up the audio driver, if necessary. This is legacy behaviour! */
+    if (!SDL_WasInit(SDL_INIT_AUDIO)) {
+        if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
+            return (-1);
+        }
+    }
+
+    /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
+    if (open_devices[0] != NULL) {
+        SDL_SetError("Audio device is already opened");
+        return (-1);
+    }
+
+    id = open_audio_device(NULL, 0, desired, obtained, 1);
+    if (id > 1) {  /* this should never happen in theory... */
+        SDL_CloseAudioDevice(id);
+        SDL_SetError("Internal error");  /* MUST be Device ID #1! */
+        return (-1);
+    }
+
+    return ((id == 0) ? -1 : 0);
+}
+
+SDL_AudioDeviceID
+SDL_OpenAudioDevice(const char *device, int iscapture,
+                    const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
+{
+    return open_audio_device(device, iscapture, desired, obtained, 2);
 }
 
 SDL_audiostatus
-SDL_GetAudioStatus(void)
+SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
 {
-    SDL_AudioDevice *audio = current_audio;
-    SDL_audiostatus status;
-
-    status = SDL_AUDIO_STOPPED;
-    if (audio && audio->enabled) {
-        if (audio->paused) {
+    SDL_AudioDevice *device = get_audio_device(devid);
+    SDL_audiostatus status = SDL_AUDIO_STOPPED;
+    if (device && device->enabled) {
+        if (device->paused) {
             status = SDL_AUDIO_PAUSED;
         } else {
             status = SDL_AUDIO_PLAYING;
@@ -649,74 +764,93 @@
     return (status);
 }
 
+
+SDL_audiostatus
+SDL_GetAudioStatus(void)
+{
+    return SDL_GetAudioDeviceStatus(1);
+}
+
+void
+SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
+{
+    SDL_AudioDevice *device = get_audio_device(devid);
+    if (device) {
+        device->paused = pause_on;
+    }
+}
+
 void
 SDL_PauseAudio(int pause_on)
 {
-    SDL_AudioDevice *audio = current_audio;
+    SDL_PauseAudioDevice(1, pause_on);
+}
+
 
-    if (audio) {
-        audio->paused = pause_on;
+void
+SDL_LockAudioDevice(SDL_AudioDeviceID devid)
+{
+    if (current_audio.impl.LockAudio != NULL) {
+        SDL_AudioDevice *device = get_audio_device(devid);
+        /* Obtain a lock on the mixing buffers */
+        if (device) {
+            current_audio.impl.LockAudio(device);
+        }
     }
 }
 
 void
 SDL_LockAudio(void)
 {
-    SDL_AudioDevice *audio = current_audio;
+    SDL_LockAudioDevice(1);
+}
 
-    /* Obtain a lock on the mixing buffers */
-    if (audio && audio->LockAudio) {
-        audio->LockAudio(audio);
+void
+SDL_UnlockAudioDevice(SDL_AudioDeviceID devid)
+{
+    if (current_audio.impl.UnlockAudio != NULL) {
+        SDL_AudioDevice *device = get_audio_device(devid);
+        /* Obtain a lock on the mixing buffers */
+        if (device) {
+            current_audio.impl.UnlockAudio(device);
+        }
     }
 }
 
 void
 SDL_UnlockAudio(void)
 {
-    SDL_AudioDevice *audio = current_audio;
+    SDL_UnlockAudioDevice(1);
+}
 
-    /* Release lock on the mixing buffers */
-    if (audio && audio->UnlockAudio) {
-        audio->UnlockAudio(audio);
+void
+SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
+{
+    SDL_AudioDevice *device = get_audio_device(devid);
+    if (device) {
+        close_audio_device(device);
+        open_devices[devid-1] = NULL;
     }
 }
 
 void
 SDL_CloseAudio(void)
 {
-    SDL_QuitSubSystem(SDL_INIT_AUDIO);
+    SDL_CloseAudioDevice(1);
 }
 
 void
 SDL_AudioQuit(void)
 {
-    SDL_AudioDevice *audio = current_audio;
+    SDL_AudioDeviceID i;
+    for (i = 0; i < SDL_arraysize(open_devices); i++) {
+        SDL_CloseAudioDevice(i);
+    }
+    /* Free the driver data */
 
-    if (audio) {
-        audio->enabled = 0;
-        if (audio->thread != NULL) {
-            SDL_WaitThread(audio->thread, NULL);
-        }
-        if (audio->mixer_lock != NULL) {
-            SDL_DestroyMutex(audio->mixer_lock);
-        }
-        if (audio->fake_stream != NULL) {
-            SDL_FreeAudioMem(audio->fake_stream);
-        }
-        if (audio->convert.needed) {
-            SDL_FreeAudioMem(audio->convert.buf);
-
-        }
-#if !SDL_AUDIO_DRIVER_AHI
-        if (audio->opened) {
-            audio->CloseAudio(audio);
-            audio->opened = 0;
-        }
-#endif
-        /* Free the driver data */
-        audio->free(audio);
-        current_audio = NULL;
-    }
+/* !!! FIXME!    current_audio.free(&current_audio); */
+    SDL_memset(&current_audio, '\0', sizeof (current_audio));
+    SDL_memset(open_devices, '\0', sizeof (open_devices));
 }
 
 #define NUM_FORMATS 10
@@ -777,9 +911,30 @@
         spec->silence = 0x00;
         break;
     }
-    spec->size = (spec->format & 0xFF) / 8;
+    spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
     spec->size *= spec->channels;
     spec->size *= spec->samples;
 }
 
+
+/*
+ * Moved here from SDL_mixer.c, since it relies on internals of an opened
+ *  audio device (and is deprecated, by the way!).
+ */
+void
+SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
+{
+    /* Mix the user-level audio format */
+    SDL_AudioDevice *device = get_audio_device(1);
+    if (device != NULL) {
+        SDL_AudioFormat format;
+        if (device->convert.needed) {
+            format = device->convert.src_format;
+        } else {
+            format = device->spec.format;
+        }
+        SDL_MixAudioFormat(dst, src, format, len, volume);
+    }
+}
+
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/SDL_mixer.c	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/SDL_mixer.c	Sun Oct 01 05:24:03 2006 +0000
@@ -89,21 +89,6 @@
 #define ADJUST_VOLUME(s, v)	(s = (s*v)/SDL_MIX_MAXVOLUME)
 #define ADJUST_VOLUME_U8(s, v)	(s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128)
 
-void
-SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
-{
-    /* Mix the user-level audio format */
-    if (current_audio) {
-        SDL_AudioFormat format;
-        if (current_audio->convert.needed) {
-            format = current_audio->convert.src_format;
-        } else {
-            format = current_audio->spec.format;
-        }
-        SDL_MixAudioFormat(dst, src, format, len, volume);
-    }
-}
-
 
 void
 SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
--- a/src/audio/SDL_sysaudio.h	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/SDL_sysaudio.h	Sun Oct 01 05:24:03 2006 +0000
@@ -29,13 +29,23 @@
 
 /* The SDL audio driver */
 typedef struct SDL_AudioDevice SDL_AudioDevice;
+#define _THIS	SDL_AudioDevice *_this
 
-/* Define the SDL audio driver structure */
-#define _THIS	SDL_AudioDevice *_this
-#ifndef _STATUS
-#define _STATUS	SDL_status *status
-#endif
-struct SDL_AudioDevice
+/* !!! FIXME: rename these from "Audio" to "Device" ... */
+typedef struct SDL_AudioDriverImpl
+{
+    int (*OpenAudio) (_THIS, const char *devname, int iscapture);
+    void (*ThreadInit) (_THIS); /* Called by audio thread at start */
+    void (*WaitAudio) (_THIS);
+    void (*PlayAudio) (_THIS);
+    Uint8 *(*GetAudioBuf) (_THIS);
+    void (*WaitDone) (_THIS);
+    void (*CloseAudio) (_THIS);
+    void (*LockAudio) (_THIS);
+    void (*UnlockAudio) (_THIS);
+} SDL_AudioDriverImpl;
+
+typedef struct SDL_AudioDriver
 {
     /* * * */
     /* The name of this audio driver */
@@ -45,20 +55,16 @@
     /* The description of this audio driver */
     const char *desc;
 
+    SDL_AudioDriverImpl impl;
+} SDL_AudioDriver;
+
+
+/* Define the SDL audio driver structure */
+struct SDL_AudioDevice
+{
     /* * * */
-    /* Public driver functions */
-    int (*OpenAudio) (_THIS, SDL_AudioSpec * spec);
-    void (*ThreadInit) (_THIS); /* Called by audio thread at start */
-    void (*WaitAudio) (_THIS);
-    void (*PlayAudio) (_THIS);
-    Uint8 *(*GetAudioBuf) (_THIS);
-    void (*WaitDone) (_THIS);
-    void (*CloseAudio) (_THIS);
-
-    /* * * */
-    /* Lock / Unlock functions added for the Mac port */
-    void (*LockAudio) (_THIS);
-    void (*UnlockAudio) (_THIS);
+    /* Lowlevel audio implementation */
+    const SDL_AudioDriver *driver;
 
     /* * * */
     /* Data common to all devices */
@@ -99,7 +105,7 @@
     const char *name;
     const char *desc;
     int (*available) (void);
-    SDL_AudioDevice *(*create) (int devindex);
+    int (*init) (SDL_AudioDriverImpl *impl);
 } AudioBootStrap;
 
 #if SDL_AUDIO_DRIVER_BSD
@@ -174,8 +180,5 @@
 extern AudioBootStrap DART_bootstrap;
 #endif
 
-/* This is the current audio device */
-extern SDL_AudioDevice *current_audio;
-
 #endif /* _SDL_sysaudio_h */
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/disk/SDL_diskaudio.c	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/disk/SDL_diskaudio.c	Sun Oct 01 05:24:03 2006 +0000
@@ -47,7 +47,7 @@
 #define DISKDEFAULT_WRITEDELAY   150
 
 /* Audio driver functions */
-static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
+static int DISKAUD_OpenAudio(_THIS, const char *devname, int iscapture);
 static void DISKAUD_WaitAudio(_THIS);
 static void DISKAUD_PlayAudio(_THIS);
 static Uint8 *DISKAUD_GetAudioBuf(_THIS);
@@ -64,61 +64,34 @@
 static int
 DISKAUD_Available(void)
 {
+    /* !!! FIXME: check this at a higher level... */
+    /* only ever use this driver if explicitly requested. */
     const char *envr = SDL_getenv("SDL_AUDIODRIVER");
-    if (envr && (SDL_strcmp(envr, DISKAUD_DRIVER_NAME) == 0)) {
+    if (envr && (SDL_strcasecmp(envr, DISKAUD_DRIVER_NAME) == 0)) {
         return (1);
     }
     return (0);
 }
 
-static void
-DISKAUD_DeleteDevice(SDL_AudioDevice * device)
+static int
+DISKAUD_Init(SDL_AudioDriverImpl *impl)
 {
-    SDL_free(device->hidden);
-    SDL_free(device);
-}
-
-static SDL_AudioDevice *
-DISKAUD_CreateDevice(int devindex)
-{
-    SDL_AudioDevice *this;
-    const char *envr;
-
     /* Initialize all variables that we clean on shutdown */
-    this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
-    if (this) {
-        SDL_memset(this, 0, (sizeof *this));
-        this->hidden = (struct SDL_PrivateAudioData *)
-            SDL_malloc((sizeof *this->hidden));
-    }
-    if ((this == NULL) || (this->hidden == NULL)) {
-        SDL_OutOfMemory();
-        if (this) {
-            SDL_free(this);
-        }
-        return (0);
-    }
-    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
-
-    envr = SDL_getenv(DISKENVR_WRITEDELAY);
-    this->hidden->write_delay =
-        (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
+    SDL_memset(impl, '\0', sizeof (SDL_AudioDriverImpl));
 
     /* Set the function pointers */
-    this->OpenAudio = DISKAUD_OpenAudio;
-    this->WaitAudio = DISKAUD_WaitAudio;
-    this->PlayAudio = DISKAUD_PlayAudio;
-    this->GetAudioBuf = DISKAUD_GetAudioBuf;
-    this->CloseAudio = DISKAUD_CloseAudio;
+    impl->OpenAudio = DISKAUD_OpenAudio;
+    impl->WaitAudio = DISKAUD_WaitAudio;
+    impl->PlayAudio = DISKAUD_PlayAudio;
+    impl->GetAudioBuf = DISKAUD_GetAudioBuf;
+    impl->CloseAudio = DISKAUD_CloseAudio;
 
-    this->free = DISKAUD_DeleteDevice;
-
-    return this;
+    return 1;
 }
 
 AudioBootStrap DISKAUD_bootstrap = {
     DISKAUD_DRIVER_NAME, "direct-to-disk audio",
-    DISKAUD_Available, DISKAUD_CreateDevice
+    DISKAUD_Available, DISKAUD_Init
 };
 
 /* This function waits until it is possible to write a full sound buffer */
@@ -163,33 +136,57 @@
         SDL_RWclose(this->hidden->output);
         this->hidden->output = NULL;
     }
+    SDL_free(this->hidden);
+    this->hidden = NULL;
 }
 
 static int
-DISKAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
+DISKAUD_OpenAudio(_THIS, const char *devname, int iscapture)
 {
+    const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
     const char *fname = DISKAUD_GetOutputFilename();
 
+    /* !!! FIXME: use device name for non-default filename? */
+    if (devname != NULL) {
+        SDL_SetError("Disk audio device name must be NULL");
+        return 0;
+    }
+
+    this->hidden = (struct SDL_PrivateAudioData *)
+            SDL_malloc(sizeof (*this->hidden));
+    if (this->hidden == NULL) {
+        SDL_OutOfMemory();
+        return 0;
+    }
+    SDL_memset(this->hidden, 0, sizeof (*this->hidden));
+
     /* Open the audio device */
     this->hidden->output = SDL_RWFromFile(fname, "wb");
     if (this->hidden->output == NULL) {
-        return (-1);
+        DISKAUD_CloseAudio(this);
+        return 0;
     }
-#if HAVE_STDIO_H
-    fprintf(stderr, "WARNING: You are using the SDL disk writer"
-            " audio driver!\n Writing to file [%s].\n", fname);
-#endif
 
     /* Allocate mixing buffer */
-    this->hidden->mixlen = spec->size;
     this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
     if (this->hidden->mixbuf == NULL) {
-        return (-1);
+        DISKAUD_CloseAudio(this);
+        return 0;
     }
-    SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
+    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
+
+    this->hidden->mixlen = this->spec.size;
+    this->hidden->write_delay =
+        (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
+
+#if HAVE_STDIO_H
+    fprintf(stderr,
+            "WARNING: You are using the SDL disk writer audio driver!\n"
+            " Writing to file [%s].\n", fname);
+#endif
 
     /* We're ready to rock and roll. :-) */
-    return (0);
+    return 1;
 }
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/dummy/SDL_dummyaudio.c	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/dummy/SDL_dummyaudio.c	Sun Oct 01 05:24:03 2006 +0000
@@ -37,7 +37,7 @@
 #define DUMMYAUD_DRIVER_NAME         "dummy"
 
 /* Audio driver functions */
-static int DUMMYAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
+static int DUMMYAUD_OpenAudio(_THIS, const char *devname, int iscapture);
 static void DUMMYAUD_WaitAudio(_THIS);
 static void DUMMYAUD_PlayAudio(_THIS);
 static Uint8 *DUMMYAUD_GetAudioBuf(_THIS);
@@ -47,6 +47,8 @@
 static int
 DUMMYAUD_Available(void)
 {
+    /* !!! FIXME: check this at a higher level... */
+    /* only ever use this driver if explicitly requested. */
     const char *envr = SDL_getenv("SDL_AUDIODRIVER");
     if (envr && (SDL_strcmp(envr, DUMMYAUD_DRIVER_NAME) == 0)) {
         return (1);
@@ -54,49 +56,22 @@
     return (0);
 }
 
-static void
-DUMMYAUD_DeleteDevice(SDL_AudioDevice * device)
+static int
+DUMMYAUD_Init(SDL_AudioDriverImpl *impl)
 {
-    SDL_free(device->hidden);
-    SDL_free(device);
-}
-
-static SDL_AudioDevice *
-DUMMYAUD_CreateDevice(int devindex)
-{
-    SDL_AudioDevice *this;
+    /* Set the function pointers */
+    impl->OpenAudio = DUMMYAUD_OpenAudio;
+    impl->WaitAudio = DUMMYAUD_WaitAudio;
+    impl->PlayAudio = DUMMYAUD_PlayAudio;
+    impl->GetAudioBuf = DUMMYAUD_GetAudioBuf;
+    impl->CloseAudio = DUMMYAUD_CloseAudio;
 
-    /* Initialize all variables that we clean on shutdown */
-    this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
-    if (this) {
-        SDL_memset(this, 0, (sizeof *this));
-        this->hidden = (struct SDL_PrivateAudioData *)
-            SDL_malloc((sizeof *this->hidden));
-    }
-    if ((this == NULL) || (this->hidden == NULL)) {
-        SDL_OutOfMemory();
-        if (this) {
-            SDL_free(this);
-        }
-        return (0);
-    }
-    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
-
-    /* Set the function pointers */
-    this->OpenAudio = DUMMYAUD_OpenAudio;
-    this->WaitAudio = DUMMYAUD_WaitAudio;
-    this->PlayAudio = DUMMYAUD_PlayAudio;
-    this->GetAudioBuf = DUMMYAUD_GetAudioBuf;
-    this->CloseAudio = DUMMYAUD_CloseAudio;
-
-    this->free = DUMMYAUD_DeleteDevice;
-
-    return this;
+    return 1;
 }
 
 AudioBootStrap DUMMYAUD_bootstrap = {
     DUMMYAUD_DRIVER_NAME, "SDL dummy audio driver",
-    DUMMYAUD_Available, DUMMYAUD_CreateDevice
+    DUMMYAUD_Available, DUMMYAUD_Init
 };
 
 /* This function waits until it is possible to write a full sound buffer */
@@ -129,23 +104,35 @@
         SDL_FreeAudioMem(this->hidden->mixbuf);
         this->hidden->mixbuf = NULL;
     }
+    SDL_free(this->hidden);
+    this->hidden = NULL;
 }
 
 static int
-DUMMYAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
+DUMMYAUD_OpenAudio(_THIS, const char *devname, int iscapture)
 {
     float bytes_per_sec = 0.0f;
 
+    /* Initialize all variables that we clean on shutdown */
+    this->hidden = (struct SDL_PrivateAudioData *)
+                    SDL_malloc((sizeof *this->hidden));
+    if (this->hidden == NULL) {
+        SDL_OutOfMemory();
+        return 0;
+    }
+    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
     /* Allocate mixing buffer */
-    this->hidden->mixlen = spec->size;
+    this->hidden->mixlen = this->spec.size;
     this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
     if (this->hidden->mixbuf == NULL) {
-        return (-1);
+        DUMMYAUD_CloseAudio(this);
+        return 0;
     }
-    SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
+    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
 
-    bytes_per_sec = (float) (((spec->format & 0xFF) / 8) *
-                             spec->channels * spec->freq);
+    bytes_per_sec = (float) (SDL_AUDIO_BITSIZE(this->spec.format) / 8) *
+                             this->spec.channels * this->spec.freq;
 
     /*
      * We try to make this request more audio at the correct rate for
@@ -156,10 +143,10 @@
      */
     this->hidden->initial_calls = 2;
     this->hidden->write_delay =
-        (Uint32) ((((float) spec->size) / bytes_per_sec) * 1000.0f);
+        (Uint32) ((((float) this->spec.size) / bytes_per_sec) * 1000.0f);
 
     /* We're ready to rock and roll. :-) */
-    return (0);
+    return 1;
 }
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/macosx/SDL_coreaudio.c	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/macosx/SDL_coreaudio.c	Sun Oct 01 05:24:03 2006 +0000
@@ -31,63 +31,36 @@
 
 /* Audio driver functions */
 
-static int Core_OpenAudio(_THIS, SDL_AudioSpec * spec);
-static void Core_WaitAudio(_THIS);
-static void Core_PlayAudio(_THIS);
-static Uint8 *Core_GetAudioBuf(_THIS);
-static void Core_CloseAudio(_THIS);
+static int COREAUDIO_OpenAudio(_THIS, const char *devname, int iscapture);
+static void COREAUDIO_WaitAudio(_THIS);
+static void COREAUDIO_PlayAudio(_THIS);
+static Uint8 *COREAUDIO_GetAudioBuf(_THIS);
+static void COREAUDIO_CloseAudio(_THIS);
 
 /* Audio driver bootstrap functions */
 
 static int
-Audio_Available(void)
+COREAUDIO_Available(void)
 {
     return (1);
 }
 
-static void
-Audio_DeleteDevice(SDL_AudioDevice * device)
+static int
+COREAUDIO_Init(SDL_AudioDriverImpl *impl)
 {
-    SDL_free(device->hidden);
-    SDL_free(device);
-}
-
-static SDL_AudioDevice *
-Audio_CreateDevice(int devindex)
-{
-    SDL_AudioDevice *this;
+    /* Set the function pointers */
+    impl->OpenAudio = COREAUDIO_OpenAudio;
+    impl->WaitAudio = COREAUDIO_WaitAudio;
+    impl->PlayAudio = COREAUDIO_PlayAudio;
+    impl->GetAudioBuf = COREAUDIO_GetAudioBuf;
+    impl->CloseAudio = COREAUDIO_CloseAudio;
 
-    /* Initialize all variables that we clean on shutdown */
-    this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
-    if (this) {
-        SDL_memset(this, 0, (sizeof *this));
-        this->hidden = (struct SDL_PrivateAudioData *)
-            SDL_malloc((sizeof *this->hidden));
-    }
-    if ((this == NULL) || (this->hidden == NULL)) {
-        SDL_OutOfMemory();
-        if (this) {
-            SDL_free(this);
-        }
-        return (0);
-    }
-    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
-
-    /* Set the function pointers */
-    this->OpenAudio = Core_OpenAudio;
-    this->WaitAudio = Core_WaitAudio;
-    this->PlayAudio = Core_PlayAudio;
-    this->GetAudioBuf = Core_GetAudioBuf;
-    this->CloseAudio = Core_CloseAudio;
-
-    this->free = Audio_DeleteDevice;
-
-    return this;
+    return 1;
 }
 
 AudioBootStrap COREAUDIO_bootstrap = {
     "coreaudio", "Mac OS X CoreAudio",
-    Audio_Available, Audio_CreateDevice
+    COREAUDIO_Available, COREAUDIO_Init
 };
 
 /* The CoreAudio callback */
@@ -118,22 +91,26 @@
     remaining = ioData->mDataByteSize;
     ptr = ioData->mData;
     while (remaining > 0) {
-        if (bufferOffset >= bufferSize) {
+        if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
             /* Generate the data */
-            SDL_memset(buffer, this->spec.silence, bufferSize);
+            SDL_memset(this->hidden->buffer, this->spec.silence,
+                       this->hidden->bufferSize);
             SDL_mutexP(this->mixer_lock);
-            (*this->spec.callback) (this->spec.userdata, buffer, bufferSize);
+            (*this->spec.callback) (this->spec.userdata, this->hidden->buffer,
+                                    this->hidden->bufferSize);
             SDL_mutexV(this->mixer_lock);
-            bufferOffset = 0;
+            this->hidden->bufferOffset = 0;
         }
 
-        len = bufferSize - bufferOffset;
+        len = this->hidden->bufferSize - this->hidden->bufferOffset;
         if (len > remaining)
             len = remaining;
-        SDL_memcpy(ptr, (char *) buffer + bufferOffset, len);
+        SDL_memcpy(ptr,
+                    (char *) this->hidden->buffer + this->hidden->bufferOffset,
+                    len);
         ptr = (char *) ptr + len;
         remaining -= len;
-        bufferOffset += len;
+        this->hidden->bufferOffset += len;
     }
 
     return 0;
@@ -141,86 +118,104 @@
 
 /* Dummy functions -- we don't use thread-based audio */
 void
-Core_WaitAudio(_THIS)
+COREAUDIO_WaitAudio(_THIS)
 {
     return;
 }
 
 void
-Core_PlayAudio(_THIS)
+COREAUDIO_PlayAudio(_THIS)
 {
     return;
 }
 
 Uint8 *
-Core_GetAudioBuf(_THIS)
+COREAUDIO_GetAudioBuf(_THIS)
 {
     return (NULL);
 }
 
 void
-Core_CloseAudio(_THIS)
+COREAUDIO_CloseAudio(_THIS)
 {
     OSStatus result;
     struct AudioUnitInputCallback callback;
 
+    if (this->hidden == NULL) {
+        return;
+    }
+
     /* stop processing the audio unit */
-    result = AudioOutputUnitStop(outputAudioUnit);
+    result = AudioOutputUnitStop(this->hidden->outputAudioUnit);
     if (result != noErr) {
-        SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
+        SDL_SetError("COREAUDIO_CloseAudio: AudioOutputUnitStop");
         return;
     }
 
     /* Remove the input callback */
     callback.inputProc = 0;
     callback.inputProcRefCon = 0;
-    result = AudioUnitSetProperty(outputAudioUnit,
+    result = AudioUnitSetProperty(this->hidden->outputAudioUnit,
                                   kAudioUnitProperty_SetInputCallback,
                                   kAudioUnitScope_Input,
                                   0, &callback, sizeof(callback));
     if (result != noErr) {
         SDL_SetError
-            ("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
+            ("COREAUDIO_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
         return;
     }
 
-    result = CloseComponent(outputAudioUnit);
+    result = CloseComponent(this->hidden->outputAudioUnit);
     if (result != noErr) {
-        SDL_SetError("Core_CloseAudio: CloseComponent");
+        SDL_SetError("COREAUDIO_CloseAudio: CloseComponent");
         return;
     }
 
-    SDL_free(buffer);
+    SDL_free(this->hidden->buffer);
+    SDL_free(this->hidden);
+    this->hidden = NULL;
 }
 
 #define CHECK_RESULT(msg) \
     if (result != noErr) { \
+        COREAUDIO_CloseAudio(this); \
         SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
         return -1; \
     }
 
 
 int
-Core_OpenAudio(_THIS, SDL_AudioSpec * spec)
+COREAUDIO_OpenAudio(_THIS, const char *devname, int iscapture)
 {
     OSStatus result = noErr;
     Component comp;
     ComponentDescription desc;
     struct AudioUnitInputCallback callback;
     AudioStreamBasicDescription strdesc;
-    SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
+    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
     int valid_datatype = 0;
 
+    /* Initialize all variables that we clean on shutdown */
+    this->hidden = (struct SDL_PrivateAudioData *)
+                        SDL_malloc((sizeof *this->hidden));
+    if (this->hidden == NULL) {
+        SDL_OutOfMemory();
+        return (0);
+    }
+    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+    /* !!! FIXME: check devname and iscapture... */
+
     /* Setup a AudioStreamBasicDescription with the requested format */
     memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
     strdesc.mFormatID = kAudioFormatLinearPCM;
     strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
-    strdesc.mChannelsPerFrame = spec->channels;
-    strdesc.mSampleRate = spec->freq;
+    strdesc.mChannelsPerFrame = this->spec.channels;
+    strdesc.mSampleRate = this->spec.freq;
     strdesc.mFramesPerPacket = 1;
 
     while ((!valid_datatype) && (test_format)) {
-        spec->format = test_format;
+        this->spec.format = test_format;
         /* Just a list of valid SDL formats, so people don't pass junk here. */
         switch (test_format) {
         case AUDIO_U8:
@@ -234,13 +229,13 @@
         case AUDIO_F32LSB:
         case AUDIO_F32MSB:
             valid_datatype = 1;
-            strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(spec->format);
-            if (SDL_AUDIO_ISBIGENDIAN(spec->format))
+            strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
+            if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
                 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
 
-            if (SDL_AUDIO_ISFLOAT(spec->format))
+            if (SDL_AUDIO_ISFLOAT(this->spec.format))
                 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
-            else if (SDL_AUDIO_ISSIGNED(spec->format))
+            else if (SDL_AUDIO_ISSIGNED(this->spec.format))
                 strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
             break;
         }
@@ -248,7 +243,7 @@
 
     if (!valid_datatype) {      /* shouldn't happen, but just in case... */
         SDL_SetError("Unsupported audio format");
-        return (-1);
+        return 0;
     }
 
     strdesc.mBytesPerFrame =
@@ -266,18 +261,19 @@
 
     comp = FindNextComponent(NULL, &desc);
     if (comp == NULL) {
+        COREAUDIO_CloseAudio(this);
         SDL_SetError
             ("Failed to start CoreAudio: FindNextComponent returned NULL");
-        return -1;
+        return 0;
     }
 
     /* Open & initialize the default output audio unit */
-    result = OpenAComponent(comp, &outputAudioUnit);
+    result = OpenAComponent(comp, &this->hidden->outputAudioUnit);
     CHECK_RESULT("OpenAComponent")
-        result = AudioUnitInitialize(outputAudioUnit);
+        result = AudioUnitInitialize(this->hidden->outputAudioUnit);
     CHECK_RESULT("AudioUnitInitialize")
         /* Set the input format of the audio unit. */
-        result = AudioUnitSetProperty(outputAudioUnit,
+        result = AudioUnitSetProperty(this->hidden->outputAudioUnit,
                                       kAudioUnitProperty_StreamFormat,
                                       kAudioUnitScope_Input,
                                       0, &strdesc, sizeof(strdesc));
@@ -285,20 +281,20 @@
         /* Set the audio callback */
         callback.inputProc = audioCallback;
     callback.inputProcRefCon = this;
-    result = AudioUnitSetProperty(outputAudioUnit,
+    result = AudioUnitSetProperty(this->hidden->outputAudioUnit,
                                   kAudioUnitProperty_SetInputCallback,
                                   kAudioUnitScope_Input,
                                   0, &callback, sizeof(callback));
     CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
         /* Calculate the final parameters for this audio specification */
-        SDL_CalculateAudioSpec(spec);
+        SDL_CalculateAudioSpec(&this->spec);
 
     /* Allocate a sample buffer */
-    bufferOffset = bufferSize = this->spec.size;
-    buffer = SDL_malloc(bufferSize);
+    this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
+    this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
 
     /* Finally, start processing of the audio unit */
-    result = AudioOutputUnitStart(outputAudioUnit);
+    result = AudioOutputUnitStart(this->hidden->outputAudioUnit);
     CHECK_RESULT("AudioOutputUnitStart")
         /* We're running! */
         return (1);
--- a/src/audio/macosx/SDL_coreaudio.h	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/macosx/SDL_coreaudio.h	Sun Oct 01 05:24:03 2006 +0000
@@ -37,11 +37,5 @@
     UInt32 bufferSize;
 };
 
-/* Old variable names */
-#define outputAudioUnit		(this->hidden->outputAudioUnit)
-#define buffer		(this->hidden->buffer)
-#define bufferOffset		(this->hidden->bufferOffset)
-#define bufferSize		(this->hidden->bufferSize)
-
 #endif /* _SDL_coreaudio_h */
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/macrom/SDL_romaudio.c	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/macrom/SDL_romaudio.c	Sun Oct 01 05:24:03 2006 +0000
@@ -52,69 +52,46 @@
 
 /* Audio driver functions */
 
-static void Mac_CloseAudio(_THIS);
-static int Mac_OpenAudio(_THIS, SDL_AudioSpec * spec);
-static void Mac_LockAudio(_THIS);
-static void Mac_UnlockAudio(_THIS);
+static void SNDMGR_CloseAudio(_THIS);
+static int SNDMGR_OpenAudio(_THIS, const char *devname, int iscapture);
+static void SNDMGR_LockAudio(_THIS);
+static void SNDMGR_UnlockAudio(_THIS);
 
 /* Audio driver bootstrap functions */
 
 
 static int
-Audio_Available(void)
+SNDMGR_Available(void)
 {
     return (1);
 }
 
-static void
-Audio_DeleteDevice(SDL_AudioDevice * device)
-{
-    SDL_free(device->hidden);
-    SDL_free(device);
-}
 
-static SDL_AudioDevice *
-Audio_CreateDevice(int devindex)
+static int
+SNDMGR_Init(SDL_AudioDriverImpl *impl)
 {
-    SDL_AudioDevice *this;
-
-    /* Initialize all variables that we clean on shutdown */
-    this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
-    if (this) {
-        SDL_memset(this, 0, (sizeof *this));
-        this->hidden = (struct SDL_PrivateAudioData *)
-            SDL_malloc((sizeof *this->hidden));
-    }
-    if ((this == NULL) || (this->hidden == NULL)) {
-        SDL_OutOfMemory();
-        if (this) {
-            SDL_free(this);
-        }
-        return (0);
-    }
-    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
-
     /* Set the function pointers */
-    this->OpenAudio = Mac_OpenAudio;
-    this->CloseAudio = Mac_CloseAudio;
-    this->LockAudio = Mac_LockAudio;
-    this->UnlockAudio = Mac_UnlockAudio;
-    this->free = Audio_DeleteDevice;
+    impl->OpenAudio = SNDMGR_OpenAudio;
+    impl->CloseAudio = SNDMGR_CloseAudio;
+    impl->LockAudio = SNDMGR_LockAudio;
+    impl->UnlockAudio = SNDMGR_UnlockAudio;
 
 #ifdef __MACOSX__               /* Mac OS X uses threaded audio, so normal thread code is okay */
-    this->LockAudio = NULL;
-    this->UnlockAudio = NULL;
+    impl->LockAudio = NULL;
+    impl->UnlockAudio = NULL;
 #endif
-    return this;
+
+    return 1;
 }
 
 AudioBootStrap SNDMGR_bootstrap = {
     "sndmgr", SDL_MACOS_NAME " SoundManager",
-    Audio_Available, Audio_CreateDevice
+    SNDMGR_Available, SNDMGR_Init
 };
 
 #pragma options align=power
 
+static volatile int audio_is_opened = 0;
 static volatile SInt32 audio_is_locked = 0;
 static volatile SInt32 need_to_mix = 0;
 
@@ -152,13 +129,13 @@
 }
 
 static void
-Mac_LockAudio(_THIS)
+SNDMGR_LockAudio(_THIS)
 {
     IncrementAtomic((SInt32 *) & audio_is_locked);
 }
 
 static void
-Mac_UnlockAudio(_THIS)
+SNDMGR_UnlockAudio(_THIS)
 {
     SInt32 oldval;
 
@@ -221,14 +198,39 @@
 }
 
 static int
-Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
+SNDMGR_OpenAudio(_THIS, const char *devname, int iscapture)
 {
-
+    SDL_AudioSpec *spec = &this->spec;
+    SndChannelPtr channel = NULL;
     SndCallBackUPP callback;
     int sample_bits;
     int i;
     long initOptions;
 
+    if (audio_is_opened) {
+        SDL_SetError("SoundManager driver doesn't support multiple opens");
+        return 0;
+    }
+
+    if (iscapture) {
+        SDL_SetError("SoundManager driver doesn't support recording");
+        return 0;
+    }
+
+    /* !!! FIXME: ignore devname? */
+
+    /* Initialize all variables that we clean on shutdown */
+    this->hidden = (struct SDL_PrivateAudioData *)
+                        SDL_malloc((sizeof *this->hidden));
+    if (this->hidden == NULL) {
+        SDL_OutOfMemory();
+        return 0;
+    }
+    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+    /* !!! FIXME: check devname and iscapture... */
+
+    /* !!! FIXME: iterate through format matrix... */
     /* Very few conversions are required, but... */
     switch (spec->format) {
     case AUDIO_S8:
@@ -244,7 +246,7 @@
         spec->format = AUDIO_F32MSB;
         break;
     }
-    SDL_CalculateAudioSpec(spec);
+    SDL_CalculateAudioSpec(&this->spec);
 
     /* initialize bufferCmd header */
     memset(&header, 0, sizeof(header));
@@ -282,8 +284,9 @@
     for (i = 0; i < 2; i++) {
         buffer[i] = (UInt8 *) malloc(sizeof(UInt8) * spec->size);
         if (buffer[i] == NULL) {
+            SNDMGR_CloseAudio(this);
             SDL_OutOfMemory();
-            return (-1);
+            return 0;
         }
         memset(buffer[i], 0, spec->size);
     }
@@ -291,9 +294,11 @@
     /* Create the sound manager channel */
     channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
     if (channel == NULL) {
+        SNDMGR_CloseAudio(this);
         SDL_OutOfMemory();
-        return (-1);
+        return 0;
     }
+    this->hidden->channel = channel;
     if (spec->channels >= 2) {
         initOptions = initStereo;
     } else {
@@ -302,10 +307,9 @@
     channel->userInfo = (long) this;
     channel->qLength = 128;
     if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) {
+        SNDMGR_CloseAudio(this);
         SDL_SetError("Unable to create audio channel");
-        SDL_free(channel);
-        channel = NULL;
-        return (-1);
+        return 0;
     }
 
     /* start playback */
@@ -317,20 +321,21 @@
         SndDoCommand(channel, &cmd, 0);
     }
 
+    audio_is_opened = 1;
     return 1;
 }
 
 static void
-Mac_CloseAudio(_THIS)
+SNDMGR_CloseAudio(_THIS)
 {
 
     int i;
 
     running = 0;
 
-    if (channel) {
-        SndDisposeChannel(channel, true);
-        channel = NULL;
+    if (this->hidden->channel) {
+        SndDisposeChannel(this->hidden->channel, true);
+        this->hidden->channel = NULL;
     }
 
     for (i = 0; i < 2; ++i) {
@@ -339,6 +344,9 @@
             buffer[i] = NULL;
         }
     }
+    SDL_free(this->hidden);
+    this->hidden = NULL;
+    audio_is_opened = 0;
 }
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/macrom/SDL_romaudio.h	Sun Oct 01 05:21:40 2006 +0000
+++ b/src/audio/macrom/SDL_romaudio.h	Sun Oct 01 05:24:03 2006 +0000
@@ -35,9 +35,5 @@
     SndChannelPtr channel;
 };
 
-/* Old variable names */
-#define channel		(this->hidden->channel)
-#define audio_buf	(this->hidden->audio_buf)
-
 #endif /* _SDL_romaudio_h */
 /* vi: set ts=4 sw=4 expandtab: */