Mercurial > sdl-ios-xcode
changeset 3795:589bc3d060cd SDL-ryan-multiple-audio-device
More 1.3 audio work...moved dsp and dma drivers over to new model. Untested!
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Wed, 04 Oct 2006 06:00:10 +0000 |
parents | db24e43972ac |
children | b19680c84cdf |
files | src/audio/SDL_audio.c src/audio/SDL_sysaudio.h src/audio/dma/SDL_dmaaudio.c src/audio/dsp/SDL_dspaudio.c src/audio/dsp/SDL_dspaudio.h src/audio/macosx/SDL_coreaudio.c test/testaudioinfo.c |
diffstat | 7 files changed, 458 insertions(+), 412 deletions(-) [+] |
line wrap: on
line diff
--- a/src/audio/SDL_audio.c Tue Oct 03 23:45:36 2006 +0000 +++ b/src/audio/SDL_audio.c Wed Oct 04 06:00:10 2006 +0000 @@ -132,6 +132,16 @@ } +/* stubs for audio drivers that don't need a specific entry point... */ +/* !!! FIXME: fill in more of these. */ + +static void SDL_DeinitializeAudio_Default(void) +{ + /* no-op. */ +} + + + /* The general mixing thread function */ int SDLCALL SDL_RunAudio(void *devicep) @@ -443,6 +453,10 @@ current_audio.impl.UnlockDevice = SDL_UnlockDevice_Default; } + if (!current_audio.impl.Deinitialize) { + current_audio.impl.Deinitialize = SDL_DeinitializeAudio_Default; + } + return (0); }
--- a/src/audio/SDL_sysaudio.h Tue Oct 03 23:45:36 2006 +0000 +++ b/src/audio/SDL_sysaudio.h Wed Oct 04 06:00:10 2006 +0000 @@ -47,6 +47,7 @@ void (*Deinitialize) (void); } SDL_AudioDriverImpl; + typedef struct SDL_AudioDriver { /* * * */
--- a/src/audio/dma/SDL_dmaaudio.c Tue Oct 03 23:45:36 2006 +0000 +++ b/src/audio/dma/SDL_dmaaudio.c Wed Oct 04 06:00:10 2006 +0000 @@ -21,6 +21,8 @@ */ #include "SDL_config.h" +/* !!! FIXME: merge this driver with "dsp". */ + /* Allow access to a raw mixing buffer */ #include <stdio.h> @@ -60,17 +62,23 @@ #define OPEN_FLAGS (O_RDWR|O_NONBLOCK) /* Audio driver functions */ -static int DMA_OpenAudio(_THIS, SDL_AudioSpec * spec); -static void DMA_WaitAudio(_THIS); -static void DMA_PlayAudio(_THIS); -static Uint8 *DMA_GetAudioBuf(_THIS); -static void DMA_CloseAudio(_THIS); +static int DMA_DetectDevices(int iscapture); +static const char *DMA_GetDeviceName(int index, int iscapture); +static int DMA_OpenDevice(_THIS, const char *devname, int iscapture); +static void DMA_WaitDevice(_THIS); +static void DMA_PlayDevice(_THIS); +static Uint8 *DMA_GetDeviceBuf(_THIS); +static void DMA_CloseDevice(_THIS); /* Audio driver bootstrap functions */ static int -Audio_Available(void) +DMA_Available(void) { + /* + * !!! FIXME: maybe change this to always available, and move this to + * !!! FIXME: to device enumeration and opening? + */ int available; int fd; @@ -91,55 +99,276 @@ return (available); } -static void -Audio_DeleteDevice(SDL_AudioDevice * device) -{ - SDL_free(device->hidden); - SDL_free(device); -} - -static SDL_AudioDevice * -Audio_CreateDevice(int devindex) -{ - 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)); - audio_fd = -1; +static int +DMA_Init(SDL_AudioDriverImpl *impl) +{ + /* Set the function pointers */ + impl->DetectDevices = DMA_DetectDevices; + impl->GetDeviceName = DMA_GetDeviceName; + impl->OpenDevice = DMA_OpenDevice; + impl->WaitDevice = DMA_WaitDevice; + impl->PlayDevice = DMA_PlayDevice; + impl->GetDeviceBuf = DMA_GetDeviceBuf; + impl->CloseDevice = DMA_CloseDevice; - /* Set the function pointers */ - this->OpenAudio = DMA_OpenAudio; - this->WaitAudio = DMA_WaitAudio; - this->PlayAudio = DMA_PlayAudio; - this->GetAudioBuf = DMA_GetAudioBuf; - this->CloseAudio = DMA_CloseAudio; - - this->free = Audio_DeleteDevice; - - return this; + return 1; } AudioBootStrap DMA_bootstrap = { DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", - Audio_Available, Audio_CreateDevice + DMA_Available, DMA_Init }; + +static int +DMA_DetectDevices(int iscapture) +{ + return -1; /* !!! FIXME */ +} + + +static const char * +DMA_GetDeviceName(int index, int iscapture) +{ + SDL_SetError("No such device"); /* !!! FIXME */ + return NULL; +} + + +static int +DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo) +{ + int frag_spec; + int value; + + /* Close and then reopen the audio device */ + close(audio_fd); + audio_fd = open(audiodev, O_RDWR, 0); + if (audio_fd < 0) { + SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); + return (-1); + } + + /* Calculate the final parameters for this audio specification */ + SDL_CalculateAudioSpec(&this->spec); + + /* Determine the power of two of the fragment size */ + for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec); + if ((0x01 << frag_spec) != this->spec.size) { + SDL_SetError("Fragment size must be a power of two"); + return (-1); + } + + /* Set the audio buffering parameters */ + if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) { + SDL_SetError("Couldn't set audio fragment spec"); + return (-1); + } + + /* Set the audio format */ + value = format; + if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { + SDL_SetError("Couldn't set audio format"); + return (-1); + } + + /* Set mono or stereo audio */ + value = (this->spec.channels > 1); + if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) || + (value != stereo)) { + SDL_SetError("Couldn't set audio channels"); + return (-1); + } + + /* Set the DSP frequency */ + value = this->spec.freq; + if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { + SDL_SetError("Couldn't set audio frequency"); + return (-1); + } + this->spec.freq = value; + + /* We successfully re-opened the audio */ + return (0); +} + + + +static int +open_device_internal(_THIS, const char *devname, int iscapture) +{ + char audiodev[1024]; + int format; + int stereo; + int value; + SDL_AudioFormat test_format; + struct audio_buf_info info; + + /* 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: handle devname */ + /* !!! FIXME: handle iscapture */ + + /* Open the audio device */ + audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); + if (audio_fd < 0) { + SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); + return 0; + } + dma_buf = NULL; + ioctl(audio_fd, SNDCTL_DSP_RESET, 0); + + /* Get a list of supported hardware formats */ + if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { + SDL_SetError("Couldn't get audio format list"); + return 0; + } + + /* Try for a closest match on audio format */ + format = 0; + for (test_format = SDL_FirstAudioFormat(this->spec.format); + !format && test_format;) { +#ifdef DEBUG_AUDIO + fprintf(stderr, "Trying format 0x%4.4x\n", test_format); +#endif + switch (test_format) { + case AUDIO_U8: + if (value & AFMT_U8) { + format = AFMT_U8; + } + break; + case AUDIO_S8: + if (value & AFMT_S8) { + format = AFMT_S8; + } + break; + case AUDIO_S16LSB: + if (value & AFMT_S16_LE) { + format = AFMT_S16_LE; + } + break; + case AUDIO_S16MSB: + if (value & AFMT_S16_BE) { + format = AFMT_S16_BE; + } + break; + case AUDIO_U16LSB: + if (value & AFMT_U16_LE) { + format = AFMT_U16_LE; + } + break; + case AUDIO_U16MSB: + if (value & AFMT_U16_BE) { + format = AFMT_U16_BE; + } + break; + default: + format = 0; + break; + } + if (!format) { + test_format = SDL_NextAudioFormat(); + } + } + if (format == 0) { + SDL_SetError("Couldn't find any hardware audio formats"); + return 0; + } + this->spec.format = test_format; + + /* Set the audio format */ + value = format; + if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { + SDL_SetError("Couldn't set audio format"); + return 0; + } + + /* Set mono or stereo audio (currently only two channels supported) */ + stereo = (this->spec.channels > 1); + ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo); + if (stereo) { + this->spec.channels = 2; + } else { + this->spec.channels = 1; + } + + /* Because some drivers don't allow setting the buffer size + after setting the format, we must re-open the audio device + once we know what format and channels are supported + */ + if (DMA_ReopenAudio(this, audiodev, format, stereo) < 0) { + /* Error is set by DMA_ReopenAudio() */ + return 0; + } + + /* Memory map the audio buffer */ + if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + SDL_SetError("Couldn't get OSPACE parameters"); + return 0; + } + this->spec.size = info.fragsize; + this->spec.samples = this->spec.size / ((this->spec.format & 0xFF) / 8); + this->spec.samples /= this->spec.channels; + num_buffers = info.fragstotal; + dma_len = num_buffers * this->spec.size; + dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED, + audio_fd, 0); + if (dma_buf == MAP_FAILED) { + SDL_SetError("DMA memory map failed"); + dma_buf = NULL; + return 0; + } + SDL_memset(dma_buf, this->spec.silence, dma_len); + + /* Check to see if we need to use select() workaround */ + { + char *workaround; + workaround = SDL_getenv("SDL_DSP_NOSELECT"); + if (workaround) { + frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq; + next_frame = SDL_GetTicks() + frame_ticks; + } + } + + /* Trigger audio playback */ + value = 0; + ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value); + value = PCM_ENABLE_OUTPUT; + if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) { + SDL_SetError("Couldn't trigger audio output"); + return 0; + } + + /* Get the parent process id (we're the parent of the audio thread) */ + parent = getpid(); + + /* We're ready to rock and roll. :-) */ + return 1; +} + +static int +DMA_OpenDevice(_THIS, const char *devname, int iscapture) +{ + int retval = open_device_internal(this, devname, iscapture); + if (!retval) + DMA_CloseDevice(this); /* !!! FIXME: do this at higher level. */ + return retval; +} + + + + /* This function waits until it is possible to write a full sound buffer */ static void -DMA_WaitAudio(_THIS) +DMA_WaitDevice(_THIS) { fd_set fdset; @@ -189,8 +418,8 @@ fprintf(stderr, "SDL: %s\n", message); #ifdef AUDIO_OSPACE_HACK /* We may be able to use GET_OSPACE trick */ - frame_ticks = (float) (this->spec->samples * 1000) / - this->spec->freq; + frame_ticks = (float) (this->spec.samples * 1000) / + this->spec.freq; next_frame = SDL_GetTicks() + frame_ticks; #else this->enabled = 0; @@ -208,7 +437,7 @@ } static void -DMA_PlayAudio(_THIS) +DMA_PlayDevice(_THIS) { /* If timer synchronization is enabled, set the next write frame */ if (frame_ticks) { @@ -218,7 +447,7 @@ } static Uint8 * -DMA_GetAudioBuf(_THIS) +DMA_GetDeviceBuf(_THIS) { count_info info; int playing; @@ -244,224 +473,20 @@ } static void -DMA_CloseAudio(_THIS) +DMA_CloseDevice(_THIS) { - if (dma_buf != NULL) { - munmap(dma_buf, dma_len); - dma_buf = NULL; - } - if (audio_fd >= 0) { - close(audio_fd); - audio_fd = -1; + if (this->hidden != NULL) { + if (dma_buf != NULL) { + munmap(dma_buf, dma_len); + dma_buf = NULL; + } + if (audio_fd >= 0) { + close(audio_fd); + audio_fd = -1; + } + SDL_free(this->hidden); + this->hidden = NULL; } } -static int -DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, - SDL_AudioSpec * spec) -{ - int frag_spec; - int value; - - /* Close and then reopen the audio device */ - close(audio_fd); - audio_fd = open(audiodev, O_RDWR, 0); - if (audio_fd < 0) { - SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); - return (-1); - } - - /* Calculate the final parameters for this audio specification */ - SDL_CalculateAudioSpec(spec); - - /* Determine the power of two of the fragment size */ - for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); - if ((0x01 << frag_spec) != spec->size) { - SDL_SetError("Fragment size must be a power of two"); - return (-1); - } - - /* Set the audio buffering parameters */ - if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) { - SDL_SetError("Couldn't set audio fragment spec"); - return (-1); - } - - /* Set the audio format */ - value = format; - if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { - SDL_SetError("Couldn't set audio format"); - return (-1); - } - - /* Set mono or stereo audio */ - value = (spec->channels > 1); - if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) || - (value != stereo)) { - SDL_SetError("Couldn't set audio channels"); - return (-1); - } - - /* Set the DSP frequency */ - value = spec->freq; - if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { - SDL_SetError("Couldn't set audio frequency"); - return (-1); - } - spec->freq = value; - - /* We successfully re-opened the audio */ - return (0); -} - -static int -DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) -{ - char audiodev[1024]; - int format; - int stereo; - int value; - SDL_AudioFormat test_format; - struct audio_buf_info info; - - /* Reset the timer synchronization flag */ - frame_ticks = 0.0; - - /* Open the audio device */ - audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); - if (audio_fd < 0) { - SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); - return (-1); - } - dma_buf = NULL; - ioctl(audio_fd, SNDCTL_DSP_RESET, 0); - - /* Get a list of supported hardware formats */ - if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { - SDL_SetError("Couldn't get audio format list"); - return (-1); - } - - /* Try for a closest match on audio format */ - format = 0; - for (test_format = SDL_FirstAudioFormat(spec->format); - !format && test_format;) { -#ifdef DEBUG_AUDIO - fprintf(stderr, "Trying format 0x%4.4x\n", test_format); -#endif - switch (test_format) { - case AUDIO_U8: - if (value & AFMT_U8) { - format = AFMT_U8; - } - break; - case AUDIO_S8: - if (value & AFMT_S8) { - format = AFMT_S8; - } - break; - case AUDIO_S16LSB: - if (value & AFMT_S16_LE) { - format = AFMT_S16_LE; - } - break; - case AUDIO_S16MSB: - if (value & AFMT_S16_BE) { - format = AFMT_S16_BE; - } - break; - case AUDIO_U16LSB: - if (value & AFMT_U16_LE) { - format = AFMT_U16_LE; - } - break; - case AUDIO_U16MSB: - if (value & AFMT_U16_BE) { - format = AFMT_U16_BE; - } - break; - default: - format = 0; - break; - } - if (!format) { - test_format = SDL_NextAudioFormat(); - } - } - if (format == 0) { - SDL_SetError("Couldn't find any hardware audio formats"); - return (-1); - } - spec->format = test_format; - - /* Set the audio format */ - value = format; - if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { - SDL_SetError("Couldn't set audio format"); - return (-1); - } - - /* Set mono or stereo audio (currently only two channels supported) */ - stereo = (spec->channels > 1); - ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo); - if (stereo) { - spec->channels = 2; - } else { - spec->channels = 1; - } - - /* Because some drivers don't allow setting the buffer size - after setting the format, we must re-open the audio device - once we know what format and channels are supported - */ - if (DMA_ReopenAudio(this, audiodev, format, stereo, spec) < 0) { - /* Error is set by DMA_ReopenAudio() */ - return (-1); - } - - /* Memory map the audio buffer */ - if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { - SDL_SetError("Couldn't get OSPACE parameters"); - return (-1); - } - spec->size = info.fragsize; - spec->samples = spec->size / ((spec->format & 0xFF) / 8); - spec->samples /= spec->channels; - num_buffers = info.fragstotal; - dma_len = num_buffers * spec->size; - dma_buf = (Uint8 *) mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED, - audio_fd, 0); - if (dma_buf == MAP_FAILED) { - SDL_SetError("DMA memory map failed"); - dma_buf = NULL; - return (-1); - } - SDL_memset(dma_buf, spec->silence, dma_len); - - /* Check to see if we need to use select() workaround */ - { - char *workaround; - workaround = SDL_getenv("SDL_DSP_NOSELECT"); - if (workaround) { - frame_ticks = (float) (spec->samples * 1000) / spec->freq; - next_frame = SDL_GetTicks() + frame_ticks; - } - } - - /* Trigger audio playback */ - value = 0; - ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value); - value = PCM_ENABLE_OUTPUT; - if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) { - SDL_SetError("Couldn't trigger audio output"); - return (-1); - } - - /* Get the parent process id (we're the parent of the audio thread) */ - parent = getpid(); - - /* We're ready to rock and roll. :-) */ - return (0); -} - /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/dsp/SDL_dspaudio.c Tue Oct 03 23:45:36 2006 +0000 +++ b/src/audio/dsp/SDL_dspaudio.c Wed Oct 04 06:00:10 2006 +0000 @@ -58,22 +58,25 @@ #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) /* Audio driver functions */ -static int DSP_OpenAudio(_THIS, SDL_AudioSpec * spec); -static void DSP_WaitAudio(_THIS); -static void DSP_PlayAudio(_THIS); -static Uint8 *DSP_GetAudioBuf(_THIS); -static void DSP_CloseAudio(_THIS); +static int DSP_DetectDevices(int iscapture); +static const char *DSP_GetDeviceName(int index, int iscapture); +static int DSP_OpenDevice(_THIS, const char *devname, int iscapture); +static void DSP_WaitDevice(_THIS); +static void DSP_PlayDevice(_THIS); +static Uint8 *DSP_GetDeviceBuf(_THIS); +static void DSP_CloseDevice(_THIS); /* Audio driver bootstrap functions */ static int -Audio_Available(void) +DSP_Available(void) { - int fd; - int available; - - available = 0; - fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); + /* + * !!! FIXME: maybe change this to always available, and move this to + * !!! FIXME: to device enumeration and opening? + */ + int fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); + int available = 0; if (fd >= 0) { available = 1; close(fd); @@ -81,130 +84,97 @@ return (available); } -static void -Audio_DeleteDevice(SDL_AudioDevice * device) + +static int +DSP_Init(SDL_AudioDriverImpl *impl) { - SDL_free(device->hidden); - SDL_free(device); + /* Set the function pointers */ + impl->DetectDevices = DSP_DetectDevices; + impl->GetDeviceName = DSP_GetDeviceName; + impl->OpenDevice = DSP_OpenDevice; + impl->WaitDevice = DSP_WaitDevice; + impl->PlayDevice = DSP_PlayDevice; + impl->GetDeviceBuf = DSP_GetDeviceBuf; + impl->CloseDevice = DSP_CloseDevice; + + return 1; } -static SDL_AudioDevice * -Audio_CreateDevice(int devindex) -{ - 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)); - audio_fd = -1; - - /* Set the function pointers */ - this->OpenAudio = DSP_OpenAudio; - this->WaitAudio = DSP_WaitAudio; - this->PlayAudio = DSP_PlayAudio; - this->GetAudioBuf = DSP_GetAudioBuf; - this->CloseAudio = DSP_CloseAudio; - - this->free = Audio_DeleteDevice; - - return this; -} AudioBootStrap DSP_bootstrap = { DSP_DRIVER_NAME, "OSS /dev/dsp standard audio", - Audio_Available, Audio_CreateDevice + DSP_Available, DSP_Init }; -/* This function waits until it is possible to write a full sound buffer */ -static void -DSP_WaitAudio(_THIS) + +static int +DSP_DetectDevices(int iscapture) { - /* Not needed at all since OSS handles waiting automagically */ -} - -static void -DSP_PlayAudio(_THIS) -{ - if (write(audio_fd, mixbuf, mixlen) == -1) { - perror("Audio write"); - this->enabled = 0; - } -#ifdef DEBUG_AUDIO - fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); -#endif + return -1; /* !!! FIXME */ } -static Uint8 * -DSP_GetAudioBuf(_THIS) + +static const char * +DSP_GetDeviceName(int index, int iscapture) { - return (mixbuf); + SDL_SetError("No such device"); /* !!! FIXME */ + return NULL; } -static void -DSP_CloseAudio(_THIS) -{ - if (mixbuf != NULL) { - SDL_FreeAudioMem(mixbuf); - mixbuf = NULL; - } - if (audio_fd >= 0) { - close(audio_fd); - audio_fd = -1; - } -} static int -DSP_OpenAudio(_THIS, SDL_AudioSpec * spec) +DSP_OpenDevice(_THIS, const char *devname, int iscapture) { - char audiodev[1024]; + char dev[1024]; int format; int value; int frag_spec; SDL_AudioFormat test_format; + /* 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)); + this->hidden->audio_fd = -1; + + /* !!! FIXME: handle devname */ + /* !!! FIXME: handle iscapture */ + /* Open the audio device */ - audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); - if (audio_fd < 0) { - SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); - return (-1); + this->hidden->audio_fd = SDL_OpenAudioPath(dev, sizeof(dev), OPEN_FLAGS, 0); + if (this->hidden->audio_fd < 0) { + SDL_SetError("Couldn't open %s: %s", dev, strerror(errno)); + return 0; } - mixbuf = NULL; + this->hidden->mixbuf = NULL; /* Make the file descriptor use blocking writes with fcntl() */ { long flags; - flags = fcntl(audio_fd, F_GETFL); + flags = fcntl(this->hidden->audio_fd, F_GETFL); flags &= ~O_NONBLOCK; - if (fcntl(audio_fd, F_SETFL, flags) < 0) { + if (fcntl(this->hidden->audio_fd, F_SETFL, flags) < 0) { SDL_SetError("Couldn't set audio blocking mode"); - DSP_CloseAudio(this); - return (-1); + DSP_CloseDevice(this); + return 0; } } /* Get a list of supported hardware formats */ - if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { + if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { perror("SNDCTL_DSP_GETFMTS"); SDL_SetError("Couldn't get audio format list"); - DSP_CloseAudio(this); - return (-1); + DSP_CloseDevice(this); + return 0; } /* Try for a closest match on audio format */ format = 0; - for (test_format = SDL_FirstAudioFormat(spec->format); + for (test_format = SDL_FirstAudioFormat(this->spec.format); !format && test_format;) { #ifdef DEBUG_AUDIO fprintf(stderr, "Trying format 0x%4.4x\n", test_format); @@ -256,49 +226,50 @@ } if (format == 0) { SDL_SetError("Couldn't find any hardware audio formats"); - DSP_CloseAudio(this); - return (-1); + DSP_CloseDevice(this); + return 0; } - spec->format = test_format; + this->spec.format = test_format; /* Set the audio format */ value = format; - if ((ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { + if ( (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || + (value != format) ) { perror("SNDCTL_DSP_SETFMT"); SDL_SetError("Couldn't set audio format"); - DSP_CloseAudio(this); - return (-1); + DSP_CloseDevice(this); + return 0; } /* Set the number of channels of output */ - value = spec->channels; - if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) { + value = this->spec.channels; + if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) { perror("SNDCTL_DSP_CHANNELS"); SDL_SetError("Cannot set the number of channels"); - DSP_CloseAudio(this); - return (-1); + DSP_CloseDevice(this); + return 0; } - spec->channels = value; + this->spec.channels = value; /* Set the DSP frequency */ - value = spec->freq; - if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { + value = this->spec.freq; + if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { perror("SNDCTL_DSP_SPEED"); SDL_SetError("Couldn't set audio frequency"); - DSP_CloseAudio(this); - return (-1); + DSP_CloseDevice(this); + return 0; } - spec->freq = value; + this->spec.freq = value; /* Calculate the final parameters for this audio specification */ - SDL_CalculateAudioSpec(spec); + SDL_CalculateAudioSpec(&this->spec); /* Determine the power of two of the fragment size */ - for (frag_spec = 0; (0x01U << frag_spec) < spec->size; ++frag_spec); - if ((0x01U << frag_spec) != spec->size) { + for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec); + if ((0x01U << frag_spec) != this->spec.size) { SDL_SetError("Fragment size must be a power of two"); - DSP_CloseAudio(this); - return (-1); + DSP_CloseDevice(this); + return 0; } frag_spec |= 0x00020000; /* two fragments, for low latency */ @@ -307,13 +278,13 @@ fprintf(stderr, "Requesting %d fragments of size %d\n", (frag_spec >> 16), 1 << (frag_spec & 0xFFFF)); #endif - if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) { + if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) { perror("SNDCTL_DSP_SETFRAGMENT"); } #ifdef DEBUG_AUDIO { audio_buf_info info; - ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info); + ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info); fprintf(stderr, "fragments = %d\n", info.fragments); fprintf(stderr, "fragstotal = %d\n", info.fragstotal); fprintf(stderr, "fragsize = %d\n", info.fragsize); @@ -322,19 +293,62 @@ #endif /* Allocate mixing buffer */ - mixlen = spec->size; - mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); - if (mixbuf == NULL) { - DSP_CloseAudio(this); - return (-1); + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + DSP_CloseDevice(this); + return 0; } - SDL_memset(mixbuf, spec->silence, spec->size); - - /* Get the parent process id (we're the parent of the audio thread) */ - parent = getpid(); + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); /* We're ready to rock and roll. :-) */ - return (0); + return 1; +} + + +/* This function waits until it is possible to write a full sound buffer */ +static void +DSP_WaitDevice(_THIS) +{ + /* Not needed at all since OSS handles waiting automagically */ +} + + +static void +DSP_PlayDevice(_THIS) +{ + const Uint8 *mixbuf = this->hidden->mixbuf; + const int mixlen = this->hidden->mixlen; + if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) { + perror("Audio write"); + this->enabled = 0; + } +#ifdef DEBUG_AUDIO + fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); +#endif +} + +static Uint8 * +DSP_GetDeviceBuf(_THIS) +{ + return (this->hidden->mixbuf); +} + +static void +DSP_CloseDevice(_THIS) +{ + if (this->hidden != NULL) { + if (this->hidden->mixbuf != NULL) { + SDL_FreeAudioMem(this->hidden->mixbuf); + this->hidden->mixbuf = NULL; + } + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); + this->hidden->audio_fd = -1; + } + SDL_free(this->hidden); + this->hidden = NULL; + } } /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/dsp/SDL_dspaudio.h Tue Oct 03 23:45:36 2006 +0000 +++ b/src/audio/dsp/SDL_dspaudio.h Wed Oct 04 06:00:10 2006 +0000 @@ -34,22 +34,11 @@ /* The file descriptor for the audio device */ int audio_fd; - /* The parent process id, to detect when application quits */ - pid_t parent; - /* Raw mixing buffer */ Uint8 *mixbuf; int mixlen; }; #define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ -/* Old variable names */ -#define audio_fd (this->hidden->audio_fd) -#define parent (this->hidden->parent) -#define mixbuf (this->hidden->mixbuf) -#define mixlen (this->hidden->mixlen) -#define frame_ticks (this->hidden->frame_ticks) -#define next_frame (this->hidden->next_frame) - #endif /* _SDL_dspaudio_h */ /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/macosx/SDL_coreaudio.c Tue Oct 03 23:45:36 2006 +0000 +++ b/src/audio/macosx/SDL_coreaudio.c Wed Oct 04 06:00:10 2006 +0000 @@ -356,25 +356,25 @@ /* Dummy functions -- we don't use thread-based audio */ -void +static void COREAUDIO_WaitDevice(_THIS) { return; } -void +static void COREAUDIO_PlayDevice(_THIS) { return; } -Uint8 * +static Uint8 * COREAUDIO_GetDeviceBuf(_THIS) { return (NULL); } -void +static void COREAUDIO_CloseDevice(_THIS) { if (this->hidden != NULL) { @@ -555,7 +555,7 @@ } -int +static int COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) { AudioStreamBasicDescription strdesc;
--- a/test/testaudioinfo.c Tue Oct 03 23:45:36 2006 +0000 +++ b/test/testaudioinfo.c Wed Oct 04 06:00:10 2006 +0000 @@ -5,12 +5,15 @@ const char *typestr = ((iscapture) ? "capture" : "output"); int n = SDL_GetNumAudioDevices(iscapture); - if (n == 0) - printf("No %s devices.\n\n", typestr); + printf("%s devices:\n", typestr); + + if (n == -1) + printf(" Driver can't detect specific devices.\n\n", typestr); + else if (n == 0) + printf(" No %s devices found.\n\n", typestr); else { int i; - printf("%s devices:\n", typestr); for (i = 0; i < n; i++) { printf(" %s\n", SDL_GetAudioDeviceName(i, iscapture)); }