Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Multiple audio device code is now working for dsp and dma targets.

  • Loading branch information
icculus committed Oct 5, 2006
1 parent 136a5ed commit 957fc4649d09b6c8ecb1b0139c3633c9f07a96f6
Showing with 239 additions and 84 deletions.
  1. +58 −24 src/audio/SDL_audiodev.c
  2. +4 −2 src/audio/SDL_audiodev_c.h
  3. +97 −29 src/audio/dma/SDL_dmaaudio.c
  4. +80 −29 src/audio/dsp/SDL_dspaudio.c
@@ -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);
}
}
}

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;
}

int
SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
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 @@ SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
}
}
}
audio_fd = open(audiodev, flags, 0);

/* 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;
test_device(audiodev, flags, test, devices, devCount);

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 */
@@ -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: */
@@ -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_WaitDevice(_THIS);
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
DMA_Available(void)
test_for_mmap(int fd)
{
/*
* !!! FIXME: maybe change this to always available, and move this to
* !!! FIXME: to device enumeration and opening?
*/
int available;
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;
}


available = 0;
static inline void
free_device_list(char ***devs, int *count)
{
SDL_FreeUnixAudioDevices(devs, count);
}

fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd >= 0) {
int caps;
struct audio_buf_info info;
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);
}

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);
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)
{
int available = 0;
build_device_lists();
available = ((outputDeviceCount > 0) || (inputDeviceCount > 0));
free_device_lists();
return available;
}


@@ -111,7 +150,9 @@ DMA_Init(SDL_AudioDriverImpl *impl)
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 @@ AudioBootStrap DMA_bootstrap = {
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 @@ DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo)
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 @@ open_device_internal(_THIS, const char *devname, int iscapture)
}
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 @@ open_device_internal(_THIS, const char *devname, int iscapture)
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;
}

0 comments on commit 957fc46

Please sign in to comment.