Mercurial > sdl-ios-xcode
changeset 3810:2c5387c0a642 SDL-ryan-multiple-audio-device
Multiple audio device code is now working for dsp and dma targets.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Thu, 05 Oct 2006 04:47:13 +0000 |
parents | 7852b5b78af5 |
children | d980c4dcad0f |
files | src/audio/SDL_audiodev.c src/audio/SDL_audiodev_c.h src/audio/dma/SDL_dmaaudio.c src/audio/dsp/SDL_dspaudio.c |
diffstat | 4 files changed, 241 insertions(+), 86 deletions(-) [+] |
line wrap: on
line diff
--- a/src/audio/SDL_audiodev.c Thu Oct 05 01:13:47 2006 +0000 +++ b/src/audio/SDL_audiodev.c Thu Oct 05 04:47:13 2006 +0000 @@ -46,14 +46,63 @@ #define _PATH_DEV_AUDIO "/dev/audio" #endif +static inline void +test_device(const char *fname, int flags, int (*test)(int fd), + char ***devices, int *devCount) +{ + struct stat sb; + if ( (stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode)) ) { + int audio_fd = open(fname, flags, 0); + if ( (audio_fd >= 0) && (test(audio_fd)) ) { + void *p = SDL_realloc(*devices, ((*devCount)+1) * sizeof (char *)); + if (p != NULL) { + size_t len = strlen(fname) + 1; + char *str = (char *) SDL_malloc(len); + *devices = (char **) p; + if (str != NULL) { + SDL_strlcpy(str, fname, len); + (*devices)[(*devCount)++] = str; + } + } + close(audio_fd); + } + } +} -int -SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic) +void +SDL_FreeUnixAudioDevices(char ***devices, int *devCount) +{ + int i = *devCount; + if ((i > 0) && (*devices != NULL)) { + while (i--) { + SDL_free( (*devices)[*devCount] ); + } + } + + if (*devices != NULL) { + SDL_free(*devices); + } + + *devices = NULL; + *devCount = 0; +} + +static int +test_stub(int fd) +{ + return 1; +} + +void +SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd), + char ***devices, int *devCount) { const char *audiodev; - int audio_fd; char audiopath[1024]; + if (test == NULL) + test = test_stub; + /* Figure out what our audio device is */ if (((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) && ((audiodev = SDL_getenv("AUDIODEV")) == NULL)) { @@ -72,31 +121,16 @@ } } } - audio_fd = open(audiodev, flags, 0); + test_device(audiodev, flags, test, devices, devCount); - /* If the first open fails, look for other devices */ - if ((audio_fd < 0) && (SDL_strlen(audiodev) < (sizeof(audiopath) - 3))) { - int exists, instance; - struct stat sb; - - instance = 1; - do { /* Don't use errno ENOENT - it may not be thread-safe */ + if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) { + int instance = 0; + while (instance++ <= 64) { SDL_snprintf(audiopath, SDL_arraysize(audiopath), - "%s%d", audiodev, instance++); - exists = 0; - if (stat(audiopath, &sb) == 0) { - exists = 1; - audio_fd = open(audiopath, flags, 0); - } + "%s%d", audiodev, instance); + test_device(audiopath, flags, test, devices, devCount); } - while (exists && (audio_fd < 0)); - audiodev = audiopath; } - if (path != NULL) { - SDL_strlcpy(path, audiodev, maxlen); - path[maxlen - 1] = '\0'; - } - return (audio_fd); } #endif /* Audio driver selection */
--- a/src/audio/SDL_audiodev_c.h Thu Oct 05 01:13:47 2006 +0000 +++ b/src/audio/SDL_audiodev_c.h Thu Oct 05 04:47:13 2006 +0000 @@ -21,6 +21,8 @@ */ #include "SDL_config.h" -/* Open the audio device, storing the pathname in 'path' */ -extern int SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic); +void SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd), + char ***devs, int *count); +void SDL_FreeUnixAudioDevices(char ***devices, int *devCount); + /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/dma/SDL_dmaaudio.c Thu Oct 05 01:13:47 2006 +0000 +++ b/src/audio/dma/SDL_dmaaudio.c Thu Oct 05 04:47:13 2006 +0000 @@ -59,7 +59,8 @@ #define DMA_DRIVER_NAME "dma" /* Open the audio device for playback, and don't block if busy */ -#define OPEN_FLAGS (O_RDWR|O_NONBLOCK) +#define OPEN_FLAGS_INPUT (O_RDWR|O_NONBLOCK) +#define OPEN_FLAGS_OUTPUT (O_RDWR|O_NONBLOCK) /* Audio driver functions */ static int DMA_DetectDevices(int iscapture); @@ -69,34 +70,72 @@ static void DMA_PlayDevice(_THIS); static Uint8 *DMA_GetDeviceBuf(_THIS); static void DMA_CloseDevice(_THIS); +static void DMA_Deinitialize(void); /* Audio driver bootstrap functions */ +static char **outputDevices = NULL; +static int outputDeviceCount = 0; +static char **inputDevices = NULL; +static int inputDeviceCount = 0; + +static int +test_for_mmap(int fd) +{ + int caps = 0; + struct audio_buf_info info; + if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) && + (caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) && + (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0)) + { + size_t len = info.fragstotal * info.fragsize; + Uint8 *buf = (Uint8 *) mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0); + if (buf != MAP_FAILED) { + munmap(buf, len); + return 1; + } + } + return 0; +} + + +static inline void +free_device_list(char ***devs, int *count) +{ + SDL_FreeUnixAudioDevices(devs, count); +} + +static inline void +build_device_list(int iscapture, char ***devs, int *count) +{ + const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); + free_device_list(devs, count); + SDL_EnumUnixAudioDevices(flags, 0, test_for_mmap, devs, count); +} + +static inline void +build_device_lists(void) +{ + build_device_list(0, &outputDevices, &outputDeviceCount); + build_device_list(1, &inputDevices, &inputDeviceCount); +} + + +static inline void +free_device_lists(void) +{ + free_device_list(&outputDevices, &outputDeviceCount); + free_device_list(&inputDevices, &inputDeviceCount); +} + static int DMA_Available(void) { - /* - * !!! FIXME: maybe change this to always available, and move this to - * !!! FIXME: to device enumeration and opening? - */ - int available; - int fd; - - available = 0; - - fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); - if (fd >= 0) { - int caps; - struct audio_buf_info info; - - if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) && - (caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) && - (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0)) { - available = 1; - } - close(fd); - } - return (available); + int available = 0; + build_device_lists(); + available = ((outputDeviceCount > 0) || (inputDeviceCount > 0)); + free_device_lists(); + return available; } @@ -111,7 +150,9 @@ impl->PlayDevice = DMA_PlayDevice; impl->GetDeviceBuf = DMA_GetDeviceBuf; impl->CloseDevice = DMA_CloseDevice; + impl->Deinitialize = DMA_Deinitialize; + build_device_lists(); return 1; } @@ -120,18 +161,36 @@ DMA_Available, DMA_Init, 0 }; +static void DMA_Deinitialize(void) +{ + free_device_lists(); +} static int DMA_DetectDevices(int iscapture) { - return -1; /* !!! FIXME */ + if (iscapture) { + build_device_list(1, &inputDevices, &inputDeviceCount); + return inputDeviceCount; + } else { + build_device_list(0, &outputDevices, &outputDeviceCount); + return outputDeviceCount; + } + + return 0; /* shouldn't ever hit this. */ } static const char * DMA_GetDeviceName(int index, int iscapture) { - SDL_SetError("No such device"); /* !!! FIXME */ + if ((iscapture) && (index < inputDeviceCount)) { + return inputDevices[index]; + } else if ((!iscapture) && (index < outputDeviceCount)) { + return outputDevices[index]; + } + + SDL_SetError("No such device"); return NULL; } @@ -198,13 +257,24 @@ static int open_device_internal(_THIS, const char *devname, int iscapture) { - char audiodev[1024]; + const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); int format; int stereo; int value; SDL_AudioFormat test_format; struct audio_buf_info info; + /* We don't care what the devname is...we'll try to open anything. */ + /* ...but default to first name in the list... */ + if (devname == NULL) { + if ( ((iscapture) && (inputDeviceCount == 0)) || + ((!iscapture) && (outputDeviceCount == 0)) ) { + SDL_SetError("No such audio device"); + return 0; + } + devname = ((iscapture) ? inputDevices[0] : outputDevices[0]); + } + /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); @@ -214,13 +284,11 @@ } 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); + audio_fd = open(devname, flags, 0); if (audio_fd < 0) { - SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); + SDL_SetError("Couldn't open %s: %s", devname, strerror(errno)); return 0; } dma_buf = NULL; @@ -304,7 +372,7 @@ 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) { + if (DMA_ReopenAudio(this, devname, format, stereo) < 0) { /* Error is set by DMA_ReopenAudio() */ return 0; }
--- a/src/audio/dsp/SDL_dspaudio.c Thu Oct 05 01:13:47 2006 +0000 +++ b/src/audio/dsp/SDL_dspaudio.c Thu Oct 05 04:47:13 2006 +0000 @@ -55,7 +55,8 @@ #define DSP_DRIVER_NAME "dsp" /* Open the audio device for playback, and don't block if busy */ -#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) +#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK) +#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK) /* Audio driver functions */ static int DSP_DetectDevices(int iscapture); @@ -65,23 +66,53 @@ static void DSP_PlayDevice(_THIS); static Uint8 *DSP_GetDeviceBuf(_THIS); static void DSP_CloseDevice(_THIS); +static void DSP_Deinitialize(void); /* Audio driver bootstrap functions */ +static char **outputDevices = NULL; +static int outputDeviceCount = 0; +static char **inputDevices = NULL; +static int inputDeviceCount = 0; + +static inline void +free_device_list(char ***devs, int *count) +{ + SDL_FreeUnixAudioDevices(devs, count); +} + +static inline void +build_device_list(int iscapture, char ***devs, int *count) +{ + const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); + free_device_list(devs, count); + SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count); +} + +static inline void +build_device_lists(void) +{ + build_device_list(0, &outputDevices, &outputDeviceCount); + build_device_list(1, &inputDevices, &inputDeviceCount); +} + + +static inline void +free_device_lists(void) +{ + free_device_list(&outputDevices, &outputDeviceCount); + free_device_list(&inputDevices, &inputDeviceCount); +} + + static int DSP_Available(void) { - /* - * !!! 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); - } - return (available); + build_device_lists(); + available = ((outputDeviceCount > 0) || (inputDeviceCount > 0)); + free_device_lists(); + return available; } @@ -92,11 +123,12 @@ 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; + impl->Deinitialize = DSP_Deinitialize; + build_device_lists(); return 1; } @@ -107,17 +139,36 @@ }; +static void DSP_Deinitialize(void) +{ + free_device_lists(); +} + + static int DSP_DetectDevices(int iscapture) { - return -1; /* !!! FIXME */ + if (iscapture) { + build_device_list(1, &inputDevices, &inputDeviceCount); + return inputDeviceCount; + } else { + build_device_list(0, &outputDevices, &outputDeviceCount); + return outputDeviceCount; + } + + return 0; /* shouldn't ever hit this. */ } - static const char * DSP_GetDeviceName(int index, int iscapture) { - SDL_SetError("No such device"); /* !!! FIXME */ + if ((iscapture) && (index < inputDeviceCount)) { + return inputDevices[index]; + } else if ((!iscapture) && (index < outputDeviceCount)) { + return outputDevices[index]; + } + + SDL_SetError("No such device"); return NULL; } @@ -125,12 +176,23 @@ static int DSP_OpenDevice(_THIS, const char *devname, int iscapture) { - char dev[1024]; + const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); int format; int value; int frag_spec; SDL_AudioFormat test_format; + /* We don't care what the devname is...we'll try to open anything. */ + /* ...but default to first name in the list... */ + if (devname == NULL) { + if ( ((iscapture) && (inputDeviceCount == 0)) || + ((!iscapture) && (outputDeviceCount == 0)) ) { + SDL_SetError("No such audio device"); + return 0; + } + devname = ((iscapture) ? inputDevices[0] : outputDevices[0]); + } + /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); @@ -141,13 +203,10 @@ SDL_memset(this->hidden, 0, (sizeof *this->hidden)); this->hidden->audio_fd = -1; - /* !!! FIXME: handle devname */ - /* !!! FIXME: handle iscapture */ - /* Open the audio device */ - this->hidden->audio_fd = SDL_OpenAudioPath(dev, sizeof(dev), OPEN_FLAGS, 0); + this->hidden->audio_fd = open(devname, flags, 0); if (this->hidden->audio_fd < 0) { - SDL_SetError("Couldn't open %s: %s", dev, strerror(errno)); + SDL_SetError("Couldn't open %s: %s", devname, strerror(errno)); return 0; } this->hidden->mixbuf = NULL; @@ -306,14 +365,6 @@ } -/* 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) {