diff src/audio/windib/SDL_dibaudio.c @ 3841:3479f939987c SDL-ryan-multiple-audio-device

Moved windib (waveout) audio to 1.3 API and made other cleanups.
author Ryan C. Gordon <icculus@icculus.org>
date Sun, 08 Oct 2006 23:04:24 +0000
parents c8b3d3d13ed1
children 66fb40445587
line wrap: on
line diff
--- a/src/audio/windib/SDL_dibaudio.c	Sun Oct 08 08:58:36 2006 +0000
+++ b/src/audio/windib/SDL_dibaudio.c	Sun Oct 08 23:04:24 2006 +0000
@@ -35,72 +35,20 @@
 #include "win_ce_semaphore.h"
 #endif
 
-
-/* Audio driver functions */
-static int DIB_OpenAudio(_THIS, SDL_AudioSpec * spec);
-static void DIB_ThreadInit(_THIS);
-static void DIB_WaitAudio(_THIS);
-static Uint8 *DIB_GetAudioBuf(_THIS);
-static void DIB_PlayAudio(_THIS);
-static void DIB_WaitDone(_THIS);
-static void DIB_CloseAudio(_THIS);
-
-/* Audio driver bootstrap functions */
+#if defined(_WIN32_WCE)
+#define WINDOWS_OS_NAME "Windows CE/PocketPC"
+#elif defined(WIN64)
+#define WINDOWS_OS_NAME "Win64"
+#else
+#define WINDOWS_OS_NAME "Win32"
+#endif
 
 static int
-Audio_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)
+WINWAVEOUT_Available(void)
 {
-    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 = DIB_OpenAudio;
-    this->ThreadInit = DIB_ThreadInit;
-    this->WaitAudio = DIB_WaitAudio;
-    this->PlayAudio = DIB_PlayAudio;
-    this->GetAudioBuf = DIB_GetAudioBuf;
-    this->WaitDone = DIB_WaitDone;
-    this->CloseAudio = DIB_CloseAudio;
-
-    this->free = Audio_DeleteDevice;
-
-    return this;
+    return 1;   /* Always available on win32/pocketpc systems... */
 }
 
-AudioBootStrap WAVEOUT_bootstrap = {
-    "waveout", "Win95/98/NT/2000 WaveOut",
-    Audio_Available, Audio_CreateDevice, 0
-};
-
-
 /* The Win32 callback for filling the WAVE device */
 static void CALLBACK
 FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
@@ -114,9 +62,9 @@
 
     /* Signal that we are done playing a buffer */
 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
-    ReleaseSemaphoreCE(audio_sem, 1, NULL);
+    ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL);
 #else
-    ReleaseSemaphore(audio_sem, 1, NULL);
+    ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
 #endif
 }
 
@@ -146,48 +94,47 @@
 
 /* Set high priority for the audio thread */
 static void
-DIB_ThreadInit(_THIS)
+WINWAVEOUT_ThreadInit(_THIS)
 {
     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
 }
 
 void
-DIB_WaitAudio(_THIS)
+WINWAVEOUT_WaitDevice(_THIS)
 {
     /* Wait for an audio chunk to finish */
 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
-    WaitForSemaphoreCE(audio_sem, INFINITE);
+    WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE);
 #else
-    WaitForSingleObject(audio_sem, INFINITE);
+    WaitForSingleObject(this->hidden->audio_sem, INFINITE);
 #endif
 }
 
 Uint8 *
-DIB_GetAudioBuf(_THIS)
+WINWAVEOUT_GetDeviceBuf(_THIS)
 {
-    Uint8 *retval;
-
-    retval = (Uint8 *) (wavebuf[next_buffer].lpData);
-    return retval;
+    return (Uint8 *) (this->hidden->wavebuf[this->hidden->next_buffer].lpData);
 }
 
 void
-DIB_PlayAudio(_THIS)
+WINWAVEOUT_PlayDevice(_THIS)
 {
     /* Queue it up */
-    waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0]));
-    next_buffer = (next_buffer + 1) % NUM_BUFFERS;
+    waveOutWrite(this->hidden->sound,
+                 &this->hidden->wavebuf[this->hidden->next_buffer],
+                 sizeof (this->hidden->wavebuf[0]));
+    this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
 }
 
 void
-DIB_WaitDone(_THIS)
+WINWAVEOUT_WaitDone(_THIS)
 {
     int i, left;
 
     do {
         left = NUM_BUFFERS;
         for (i = 0; i < NUM_BUFFERS; ++i) {
-            if (wavebuf[i].dwFlags & WHDR_DONE) {
+            if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
                 --left;
             }
         }
@@ -199,143 +146,198 @@
 }
 
 void
-DIB_CloseAudio(_THIS)
+WINWAVEOUT_CloseDevice(_THIS)
 {
-    int i;
-
     /* Close up audio */
-    if (audio_sem) {
+    if (this->hidden != NULL) {
+        int i;
+
+        if (this->hidden->audio_sem) {
 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
-        CloseSynchHandle(audio_sem);
+            CloseSynchHandle(this->hidden->audio_sem);
 #else
-        CloseHandle(audio_sem);
+            CloseHandle(this->hidden->audio_sem);
 #endif
-    }
-    if (sound) {
-        waveOutClose(sound);
-    }
+            this->hidden->audio_sem = 0;
+        }
+
+        if (this->hidden->sound) {
+            waveOutClose(this->hidden->sound);
+            this->hidden->sound = 0;
+        }
 
-    /* Clean up mixing buffers */
-    for (i = 0; i < NUM_BUFFERS; ++i) {
-        if (wavebuf[i].dwUser != 0xFFFF) {
-            waveOutUnprepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i]));
-            wavebuf[i].dwUser = 0xFFFF;
+        /* Clean up mixing buffers */
+        for (i = 0; i < NUM_BUFFERS; ++i) {
+            if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
+                waveOutUnprepareHeader(this->hidden->sound,
+                                       &this->hidden->wavebuf[i],
+                                       sizeof (this->hidden->wavebuf[i]));
+                this->hidden->wavebuf[i].dwUser = 0xFFFF;
+            }
         }
-    }
-    /* Free raw mixing buffer */
-    if (mixbuf != NULL) {
-        SDL_free(mixbuf);
-        mixbuf = NULL;
+
+        if (this->hidden->mixbuf != NULL) {
+            /* Free raw mixing buffer */
+            SDL_free(this->hidden->mixbuf);
+            this->hidden->mixbuf = NULL;
+        }
+
+        SDL_free(this->hidden);
+        this->hidden = NULL;
     }
 }
 
 int
-DIB_OpenAudio(_THIS, SDL_AudioSpec * spec)
+WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture)
 {
+    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
+    int valid_datatype = 0;
     MMRESULT result;
+    WAVEFORMATEX waveformat;
     int i;
-    WAVEFORMATEX waveformat;
+
+    /* 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));
 
     /* Initialize the wavebuf structures for closing */
-    sound = NULL;
-    audio_sem = NULL;
     for (i = 0; i < NUM_BUFFERS; ++i)
-        wavebuf[i].dwUser = 0xFFFF;
-    mixbuf = NULL;
+        this->hidden->wavebuf[i].dwUser = 0xFFFF;
+
+    while ((!valid_datatype) && (test_format)) {
+        valid_datatype = 1;
+        _this->spec.format = test_format;
+        switch (test_format) {
+            case AUDIO_U8:
+            case AUDIO_S16:
+            case AUDIO_S32:
+                break;  /* valid. */
+
+            default:
+                valid_datatype = 0;
+                test_format = SDL_NextAudioFormat();
+                break;
+        }
+    }
+
+    if (!valid_datatype) {
+        WINWAVEOUT_CloseDevice(this);
+        SDL_SetError("Unsupported audio format");
+        return 0;
+    }
 
     /* Set basic WAVE format parameters */
-    SDL_memset(&waveformat, 0, sizeof(waveformat));
+    SDL_memset(&waveformat, '\0', sizeof (waveformat));
     waveformat.wFormatTag = WAVE_FORMAT_PCM;
+    waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
 
-    /* Determine the audio parameters from the AudioSpec */
-    switch (SDL_AUDIO_BITSIZE(spec->format)) {
-    case 8:
-        /* Unsigned 8 bit audio data */
-        spec->format = AUDIO_U8;
-        waveformat.wBitsPerSample = 8;
-        break;
-    case 16:
-        /* Signed 16 bit audio data */
-        spec->format = AUDIO_S16;
-        waveformat.wBitsPerSample = 16;
-        break;
-    case 32:
-        /* Signed 32 bit audio data */
-        spec->format = AUDIO_S32;
-        waveformat.wBitsPerSample = 32;
-        break;
-    default:
-        SDL_SetError("Unsupported audio format");
-        return (-1);
-    }
-    waveformat.nChannels = spec->channels;
-    waveformat.nSamplesPerSec = spec->freq;
+    if (this->spec.channels > 2)
+        this->spec.channels = 2;  /* !!! FIXME: is this right? */
+
+    waveformat.nChannels = this->spec.channels;
+    waveformat.nSamplesPerSec = this->spec.freq;
     waveformat.nBlockAlign =
         waveformat.nChannels * (waveformat.wBitsPerSample / 8);
     waveformat.nAvgBytesPerSec =
         waveformat.nSamplesPerSec * waveformat.nBlockAlign;
 
     /* Check the buffer size -- minimum of 1/4 second (word aligned) */
-    if (spec->samples < (spec->freq / 4))
-        spec->samples = ((spec->freq / 4) + 3) & ~3;
+    if (this->spec.samples < (this->spec.freq / 4))
+        this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
 
     /* Update the fragment size as size in bytes */
-    SDL_CalculateAudioSpec(spec);
+    SDL_CalculateAudioSpec(&this->spec);
 
     /* Open the audio device */
-    result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
+    result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat,
                          (DWORD_PTR) FillSound, (DWORD_PTR) this,
                          CALLBACK_FUNCTION);
     if (result != MMSYSERR_NOERROR) {
+        WINWAVEOUT_CloseDevice(this);
         SetMMerror("waveOutOpen()", result);
-        return (-1);
+        return 0;
     }
 #ifdef SOUND_DEBUG
     /* Check the sound device we retrieved */
     {
         WAVEOUTCAPS caps;
 
-        result = waveOutGetDevCaps((UINT) sound, &caps, sizeof(caps));
+        result = waveOutGetDevCaps((UINT) this->hidden->sound,
+                                   &caps, sizeof(caps));
         if (result != MMSYSERR_NOERROR) {
+            WINWAVEOUT_CloseDevice(this);
             SetMMerror("waveOutGetDevCaps()", result);
-            return (-1);
+            return 0;
         }
         printf("Audio device: %s\n", caps.szPname);
     }
 #endif
 
     /* Create the audio buffer semaphore */
+    this->hidden->audio_sem = 
 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
-    audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
+            CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
 #else
-    audio_sem = CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
+            CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
 #endif
-    if (audio_sem == NULL) {
+    if (this->hidden->audio_sem == NULL) {
+        WINWAVEOUT_CloseDevice(this);
         SDL_SetError("Couldn't create semaphore");
-        return (-1);
+        return 0;
     }
 
     /* Create the sound buffers */
-    mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * spec->size);
+    this->hidden->mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
     if (mixbuf == NULL) {
-        SDL_SetError("Out of memory");
-        return (-1);
+        WINWAVEOUT_CloseDevice(this);
+        SDL_OutOfMemory();
+        return 0;
     }
     for (i = 0; i < NUM_BUFFERS; ++i) {
-        SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
-        wavebuf[i].lpData = (LPSTR) & mixbuf[i * spec->size];
-        wavebuf[i].dwBufferLength = spec->size;
-        wavebuf[i].dwFlags = WHDR_DONE;
-        result = waveOutPrepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i]));
+        SDL_memset(&this->hidden->wavebuf[i], '\0',
+                    sizeof (this->hidden->wavebuf[i]));
+        this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
+        this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
+        this->hidden->wavebuf[i].lpData =
+                            (LPSTR) &this->hidden->mixbuf[i * this->spec.size];
+        result = waveOutPrepareHeader(this->hidden->sound,
+                                      &this->hidden->wavebuf[i],
+                                      sizeof (this->hidden->wavebuf[i]));
         if (result != MMSYSERR_NOERROR) {
+            WINWAVEOUT_CloseDevice(this);
             SetMMerror("waveOutPrepareHeader()", result);
-            return (-1);
+            return 0;
         }
     }
 
-    /* Ready to go! */
-    next_buffer = 0;
-    return (0);
+    return 1;   /* Ready to go! */
 }
 
+
+static int
+WINWAVEOUT_Init(SDL_AudioDriverImpl *impl)
+{
+    /* Set the function pointers */
+    impl->OpenDevice = WINWAVEOUT_OpenDevice;
+    impl->ThreadInit = WINWAVEOUT_ThreadInit;
+    impl->PlayDevice = WINWAVEOUT_PlayDevice;
+    impl->WaitDevice = WINWAVEOUT_WaitDevice;
+    impl->WaitDone = WINWAVEOUT_WaitDone;
+    impl->GetDeviceBuf = WINWAVEOUT_GetDeviceBuf;
+    impl->CloseDevice = WINWAVEOUT_CloseDevice;
+    impl->OnlyHasDefaultOutputDevice = 1;  /* !!! FIXME: Is this true? */
+
+    return 1;
+}
+
+AudioBootStrap WINWAVEOUT_bootstrap = {
+    "waveout", WINDOWS_OS_NAME " WaveOut",
+    WINWAVEOUT_Available, WINWAVEOUT_Init, 0
+};
+
 /* vi: set ts=4 sw=4 expandtab: */