From 9da9dd998e99e4d903b3b2b53c656a546e147191 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 4 Oct 2006 06:00:10 +0000 Subject: [PATCH] More 1.3 audio work...moved dsp and dma drivers over to new model. Untested! --- src/audio/SDL_audio.c | 14 ++ src/audio/SDL_sysaudio.h | 1 + src/audio/dma/SDL_dmaaudio.c | 397 ++++++++++++++++--------------- src/audio/dsp/SDL_dspaudio.c | 266 +++++++++++---------- src/audio/dsp/SDL_dspaudio.h | 11 - src/audio/macosx/SDL_coreaudio.c | 10 +- test/testaudioinfo.c | 9 +- 7 files changed, 377 insertions(+), 331 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 62e2a1ed7..d7e497f78 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -132,6 +132,16 @@ static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id) } +/* 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 @@ SDL_AudioInit(const char *driver_name) current_audio.impl.UnlockDevice = SDL_UnlockDevice_Default; } + if (!current_audio.impl.Deinitialize) { + current_audio.impl.Deinitialize = SDL_DeinitializeAudio_Default; + } + return (0); } diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 0d006328a..bed2bd261 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -47,6 +47,7 @@ typedef struct SDL_AudioDriverImpl void (*Deinitialize) (void); } SDL_AudioDriverImpl; + typedef struct SDL_AudioDriver { /* * * */ diff --git a/src/audio/dma/SDL_dmaaudio.c b/src/audio/dma/SDL_dmaaudio.c index f1d08cc03..272155f2e 100644 --- a/src/audio/dma/SDL_dmaaudio.c +++ b/src/audio/dma/SDL_dmaaudio.c @@ -21,6 +21,8 @@ */ #include "SDL_config.h" +/* !!! FIXME: merge this driver with "dsp". */ + /* Allow access to a raw mixing buffer */ #include @@ -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,174 +99,45 @@ Audio_Available(void) return (available); } -static void -Audio_DeleteDevice(SDL_AudioDevice * device) -{ - SDL_free(device->hidden); - SDL_free(device); -} -static SDL_AudioDevice * -Audio_CreateDevice(int devindex) +static int +DMA_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)); - audio_fd = -1; - /* 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; + 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; + + return 1; } AudioBootStrap DMA_bootstrap = { DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio", - Audio_Available, Audio_CreateDevice + DMA_Available, DMA_Init }; -/* This function waits until it is possible to write a full sound buffer */ -static void -DMA_WaitAudio(_THIS) -{ - fd_set fdset; - /* Check to see if the thread-parent process is still alive */ - { - static int cnt = 0; - /* Note that this only works with thread implementations - that use a different process id for each thread. - */ - if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ - if (kill(parent, 0) < 0) { - this->enabled = 0; - } - } - } - - /* See if we need to use timed audio synchronization */ - if (frame_ticks) { - /* Use timer for general audio synchronization */ - Sint32 ticks; - - ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; - if (ticks > 0) { - SDL_Delay(ticks); - } - } else { - /* Use select() for audio synchronization */ - struct timeval timeout; - FD_ZERO(&fdset); - FD_SET(audio_fd, &fdset); - timeout.tv_sec = 10; - timeout.tv_usec = 0; -#ifdef DEBUG_AUDIO - fprintf(stderr, "Waiting for audio to get ready\n"); -#endif - if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) { - const char *message = -#ifdef AUDIO_OSPACE_HACK - "Audio timeout - buggy audio driver? (trying ospace)"; -#else - "Audio timeout - buggy audio driver? (disabled)"; -#endif - /* In general we should never print to the screen, - but in this case we have no other way of letting - the user know what happened. - */ - 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; - next_frame = SDL_GetTicks() + frame_ticks; -#else - this->enabled = 0; - /* Don't try to close - may hang */ - audio_fd = -1; -#ifdef DEBUG_AUDIO - fprintf(stderr, "Done disabling audio\n"); -#endif -#endif /* AUDIO_OSPACE_HACK */ - } -#ifdef DEBUG_AUDIO - fprintf(stderr, "Ready!\n"); -#endif - } -} - -static void -DMA_PlayAudio(_THIS) +static int +DMA_DetectDevices(int iscapture) { - /* If timer synchronization is enabled, set the next write frame */ - if (frame_ticks) { - next_frame += frame_ticks; - } - return; + return -1; /* !!! FIXME */ } -static Uint8 * -DMA_GetAudioBuf(_THIS) -{ - count_info info; - int playing; - int filling; - - /* Get number of blocks, looping if we're not using select() */ - do { - if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) < 0) { - /* Uh oh... */ - this->enabled = 0; - return (NULL); - } - } - while (frame_ticks && (info.blocks < 1)); -#ifdef DEBUG_AUDIO - if (info.blocks > 1) { - printf("Warning: audio underflow (%d frags)\n", info.blocks - 1); - } -#endif - playing = info.ptr / this->spec.size; - filling = (playing + 1) % num_buffers; - return (dma_buf + (filling * this->spec.size)); -} -static void -DMA_CloseAudio(_THIS) +static const char * +DMA_GetDeviceName(int index, int iscapture) { - if (dma_buf != NULL) { - munmap(dma_buf, dma_len); - dma_buf = NULL; - } - if (audio_fd >= 0) { - close(audio_fd); - audio_fd = -1; - } + SDL_SetError("No such device"); /* !!! FIXME */ + return NULL; } + static int -DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, - SDL_AudioSpec * spec) +DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo) { int frag_spec; int value; @@ -272,11 +151,11 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, } /* 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; (0x01 << frag_spec) < spec->size; ++frag_spec); - if ((0x01 << frag_spec) != spec->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); } @@ -295,7 +174,7 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, } /* Set mono or stereo audio */ - value = (spec->channels > 1); + value = (this->spec.channels > 1); if ((ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) || (value != stereo)) { SDL_SetError("Couldn't set audio channels"); @@ -303,19 +182,21 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo, } /* Set the DSP frequency */ - value = spec->freq; + value = this->spec.freq; if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { SDL_SetError("Couldn't set audio frequency"); return (-1); } - spec->freq = value; + this->spec.freq = value; /* We successfully re-opened the audio */ return (0); } + + static int -DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) +open_device_internal(_THIS, const char *devname, int iscapture) { char audiodev[1024]; int format; @@ -324,14 +205,23 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) SDL_AudioFormat test_format; struct audio_buf_info info; - /* Reset the timer synchronization flag */ - frame_ticks = 0.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: 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); + return 0; } dma_buf = NULL; ioctl(audio_fd, SNDCTL_DSP_RESET, 0); @@ -339,12 +229,12 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) /* 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); + 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); @@ -390,60 +280,60 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) } if (format == 0) { SDL_SetError("Couldn't find any hardware audio formats"); - return (-1); + 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)) { SDL_SetError("Couldn't set audio format"); - return (-1); + return 0; } /* Set mono or stereo audio (currently only two channels supported) */ - stereo = (spec->channels > 1); + stereo = (this->spec.channels > 1); ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo); if (stereo) { - spec->channels = 2; + this->spec.channels = 2; } else { - spec->channels = 1; + 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, spec) < 0) { + if (DMA_ReopenAudio(this, audiodev, format, stereo) < 0) { /* Error is set by DMA_ReopenAudio() */ - return (-1); + return 0; } /* Memory map the audio buffer */ if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { SDL_SetError("Couldn't get OSPACE parameters"); - return (-1); + return 0; } - spec->size = info.fragsize; - spec->samples = spec->size / ((spec->format & 0xFF) / 8); - spec->samples /= spec->channels; + 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 * spec->size; + 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 (-1); + return 0; } - SDL_memset(dma_buf, spec->silence, dma_len); + 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) (spec->samples * 1000) / spec->freq; + frame_ticks = (float) (this->spec.samples*1000) / this->spec.freq; next_frame = SDL_GetTicks() + frame_ticks; } } @@ -454,14 +344,149 @@ DMA_OpenAudio(_THIS, SDL_AudioSpec * spec) value = PCM_ENABLE_OUTPUT; if (ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0) { SDL_SetError("Couldn't trigger audio output"); - return (-1); + 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 (0); + 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_WaitDevice(_THIS) +{ + fd_set fdset; + + /* Check to see if the thread-parent process is still alive */ + { + static int cnt = 0; + /* Note that this only works with thread implementations + that use a different process id for each thread. + */ + if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ + if (kill(parent, 0) < 0) { + this->enabled = 0; + } + } + } + + /* See if we need to use timed audio synchronization */ + if (frame_ticks) { + /* Use timer for general audio synchronization */ + Sint32 ticks; + + ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; + if (ticks > 0) { + SDL_Delay(ticks); + } + } else { + /* Use select() for audio synchronization */ + struct timeval timeout; + FD_ZERO(&fdset); + FD_SET(audio_fd, &fdset); + timeout.tv_sec = 10; + timeout.tv_usec = 0; +#ifdef DEBUG_AUDIO + fprintf(stderr, "Waiting for audio to get ready\n"); +#endif + if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) { + const char *message = +#ifdef AUDIO_OSPACE_HACK + "Audio timeout - buggy audio driver? (trying ospace)"; +#else + "Audio timeout - buggy audio driver? (disabled)"; +#endif + /* In general we should never print to the screen, + but in this case we have no other way of letting + the user know what happened. + */ + 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; + next_frame = SDL_GetTicks() + frame_ticks; +#else + this->enabled = 0; + /* Don't try to close - may hang */ + audio_fd = -1; +#ifdef DEBUG_AUDIO + fprintf(stderr, "Done disabling audio\n"); +#endif +#endif /* AUDIO_OSPACE_HACK */ + } +#ifdef DEBUG_AUDIO + fprintf(stderr, "Ready!\n"); +#endif + } +} + +static void +DMA_PlayDevice(_THIS) +{ + /* If timer synchronization is enabled, set the next write frame */ + if (frame_ticks) { + next_frame += frame_ticks; + } + return; +} + +static Uint8 * +DMA_GetDeviceBuf(_THIS) +{ + count_info info; + int playing; + int filling; + + /* Get number of blocks, looping if we're not using select() */ + do { + if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + /* Uh oh... */ + this->enabled = 0; + return (NULL); + } + } + while (frame_ticks && (info.blocks < 1)); +#ifdef DEBUG_AUDIO + if (info.blocks > 1) { + printf("Warning: audio underflow (%d frags)\n", info.blocks - 1); + } +#endif + playing = info.ptr / this->spec.size; + filling = (playing + 1) % num_buffers; + return (dma_buf + (filling * this->spec.size)); +} + +static void +DMA_CloseDevice(_THIS) +{ + 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; + } } /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index 7fd3f06a4..017b8b2c0 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -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 @@ Audio_Available(void) return (available); } -static void -Audio_DeleteDevice(SDL_AudioDevice * device) -{ - SDL_free(device->hidden); - SDL_free(device); -} -static SDL_AudioDevice * -Audio_CreateDevice(int devindex) +static int +DSP_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)); - 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; + 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; } + 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) -{ - /* Not needed at all since OSS handles waiting automagically */ -} -static void -DSP_PlayAudio(_THIS) +static int +DSP_DetectDevices(int iscapture) { - 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) -{ - return (mixbuf); -} -static void -DSP_CloseAudio(_THIS) +static const char * +DSP_GetDeviceName(int index, int iscapture) { - if (mixbuf != NULL) { - SDL_FreeAudioMem(mixbuf); - mixbuf = NULL; - } - if (audio_fd >= 0) { - close(audio_fd); - audio_fd = -1; - } + SDL_SetError("No such device"); /* !!! FIXME */ + return NULL; } + 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 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec) } 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 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec) 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 @@ DSP_OpenAudio(_THIS, SDL_AudioSpec * spec) #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: */ diff --git a/src/audio/dsp/SDL_dspaudio.h b/src/audio/dsp/SDL_dspaudio.h index 3f1af967b..bf71c12a0 100644 --- a/src/audio/dsp/SDL_dspaudio.h +++ b/src/audio/dsp/SDL_dspaudio.h @@ -34,22 +34,11 @@ struct SDL_PrivateAudioData /* 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: */ diff --git a/src/audio/macosx/SDL_coreaudio.c b/src/audio/macosx/SDL_coreaudio.c index 4cb385e2d..df858bab1 100644 --- a/src/audio/macosx/SDL_coreaudio.c +++ b/src/audio/macosx/SDL_coreaudio.c @@ -356,25 +356,25 @@ inputCallback(void *inRefCon, /* 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 @@ prepare_audiounit(_THIS, const char *devname, int iscapture, } -int +static int COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) { AudioStreamBasicDescription strdesc; diff --git a/test/testaudioinfo.c b/test/testaudioinfo.c index 83b991cda..4c4eee1a8 100644 --- a/test/testaudioinfo.c +++ b/test/testaudioinfo.c @@ -5,12 +5,15 @@ static void print_devices(int iscapture) 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)); }