Multiple audio device code is now working for dsp and dma targets. SDL-ryan-multiple-audio-device
authorRyan C. Gordon <icculus@icculus.org>
Thu, 05 Oct 2006 04:47:13 +0000
branchSDL-ryan-multiple-audio-device
changeset 38102c5387c0a642
parent 3809 7852b5b78af5
child 3811 d980c4dcad0f
Multiple audio device code is now working for dsp and dma targets.
src/audio/SDL_audiodev.c
src/audio/SDL_audiodev_c.h
src/audio/dma/SDL_dmaaudio.c
src/audio/dsp/SDL_dspaudio.c
     1.1 --- a/src/audio/SDL_audiodev.c	Thu Oct 05 01:13:47 2006 +0000
     1.2 +++ b/src/audio/SDL_audiodev.c	Thu Oct 05 04:47:13 2006 +0000
     1.3 @@ -46,14 +46,63 @@
     1.4  #define _PATH_DEV_AUDIO	"/dev/audio"
     1.5  #endif
     1.6  
     1.7 +static inline void
     1.8 +test_device(const char *fname, int flags, int (*test)(int fd),
     1.9 +            char ***devices, int *devCount)
    1.10 +{
    1.11 +    struct stat sb;
    1.12 +    if ( (stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode)) ) {
    1.13 +        int audio_fd = open(fname, flags, 0);
    1.14 +        if ( (audio_fd >= 0) && (test(audio_fd)) ) {
    1.15 +            void *p = SDL_realloc(*devices, ((*devCount)+1) * sizeof (char *));
    1.16 +            if (p != NULL) {
    1.17 +                size_t len = strlen(fname) + 1;
    1.18 +                char *str = (char *) SDL_malloc(len);
    1.19 +                *devices = (char **) p;
    1.20 +                if (str != NULL) {
    1.21 +                    SDL_strlcpy(str, fname, len);
    1.22 +                    (*devices)[(*devCount)++] = str;
    1.23 +                }
    1.24 +            }
    1.25 +            close(audio_fd);
    1.26 +        }
    1.27 +    }
    1.28 +}
    1.29  
    1.30 -int
    1.31 -SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
    1.32 +void
    1.33 +SDL_FreeUnixAudioDevices(char ***devices, int *devCount)
    1.34 +{
    1.35 +    int i = *devCount;
    1.36 +    if ((i > 0) && (*devices != NULL)) {
    1.37 +        while (i--) {
    1.38 +            SDL_free( (*devices)[*devCount] );
    1.39 +        }
    1.40 +    }
    1.41 +
    1.42 +    if (*devices != NULL) {
    1.43 +        SDL_free(*devices);
    1.44 +    }
    1.45 +
    1.46 +    *devices = NULL;
    1.47 +    *devCount = 0;
    1.48 +}
    1.49 +
    1.50 +static int
    1.51 +test_stub(int fd)
    1.52 +{
    1.53 +    return 1;
    1.54 +}
    1.55 +
    1.56 +void
    1.57 +SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd),
    1.58 +                         char ***devices, int *devCount)
    1.59  {
    1.60      const char *audiodev;
    1.61 -    int audio_fd;
    1.62      char audiopath[1024];
    1.63  
    1.64 +    if (test == NULL)
    1.65 +        test = test_stub;
    1.66 +
    1.67      /* Figure out what our audio device is */
    1.68      if (((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) &&
    1.69          ((audiodev = SDL_getenv("AUDIODEV")) == NULL)) {
    1.70 @@ -72,31 +121,16 @@
    1.71              }
    1.72          }
    1.73      }
    1.74 -    audio_fd = open(audiodev, flags, 0);
    1.75 +    test_device(audiodev, flags, test, devices, devCount);
    1.76  
    1.77 -    /* If the first open fails, look for other devices */
    1.78 -    if ((audio_fd < 0) && (SDL_strlen(audiodev) < (sizeof(audiopath) - 3))) {
    1.79 -        int exists, instance;
    1.80 -        struct stat sb;
    1.81 -
    1.82 -        instance = 1;
    1.83 -        do {                    /* Don't use errno ENOENT - it may not be thread-safe */
    1.84 +    if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
    1.85 +        int instance = 0;
    1.86 +        while (instance++ <= 64) {
    1.87              SDL_snprintf(audiopath, SDL_arraysize(audiopath),
    1.88 -                         "%s%d", audiodev, instance++);
    1.89 -            exists = 0;
    1.90 -            if (stat(audiopath, &sb) == 0) {
    1.91 -                exists = 1;
    1.92 -                audio_fd = open(audiopath, flags, 0);
    1.93 -            }
    1.94 +                         "%s%d", audiodev, instance);
    1.95 +            test_device(audiopath, flags, test, devices, devCount);
    1.96          }
    1.97 -        while (exists && (audio_fd < 0));
    1.98 -        audiodev = audiopath;
    1.99      }
   1.100 -    if (path != NULL) {
   1.101 -        SDL_strlcpy(path, audiodev, maxlen);
   1.102 -        path[maxlen - 1] = '\0';
   1.103 -    }
   1.104 -    return (audio_fd);
   1.105  }
   1.106  
   1.107  #endif /* Audio driver selection */
     2.1 --- a/src/audio/SDL_audiodev_c.h	Thu Oct 05 01:13:47 2006 +0000
     2.2 +++ b/src/audio/SDL_audiodev_c.h	Thu Oct 05 04:47:13 2006 +0000
     2.3 @@ -21,6 +21,8 @@
     2.4  */
     2.5  #include "SDL_config.h"
     2.6  
     2.7 -/* Open the audio device, storing the pathname in 'path'  */
     2.8 -extern int SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic);
     2.9 +void SDL_EnumUnixAudioDevices(int flags, int classic, int (*test)(int fd),
    2.10 +                              char ***devs, int *count);
    2.11 +void SDL_FreeUnixAudioDevices(char ***devices, int *devCount);
    2.12 +
    2.13  /* vi: set ts=4 sw=4 expandtab: */
     3.1 --- a/src/audio/dma/SDL_dmaaudio.c	Thu Oct 05 01:13:47 2006 +0000
     3.2 +++ b/src/audio/dma/SDL_dmaaudio.c	Thu Oct 05 04:47:13 2006 +0000
     3.3 @@ -59,7 +59,8 @@
     3.4  #define DMA_DRIVER_NAME         "dma"
     3.5  
     3.6  /* Open the audio device for playback, and don't block if busy */
     3.7 -#define OPEN_FLAGS	(O_RDWR|O_NONBLOCK)
     3.8 +#define OPEN_FLAGS_INPUT    (O_RDWR|O_NONBLOCK)
     3.9 +#define OPEN_FLAGS_OUTPUT   (O_RDWR|O_NONBLOCK)
    3.10  
    3.11  /* Audio driver functions */
    3.12  static int DMA_DetectDevices(int iscapture);
    3.13 @@ -69,34 +70,72 @@
    3.14  static void DMA_PlayDevice(_THIS);
    3.15  static Uint8 *DMA_GetDeviceBuf(_THIS);
    3.16  static void DMA_CloseDevice(_THIS);
    3.17 +static void DMA_Deinitialize(void);
    3.18  
    3.19  /* Audio driver bootstrap functions */
    3.20  
    3.21 +static char **outputDevices = NULL;
    3.22 +static int outputDeviceCount = 0;
    3.23 +static char **inputDevices = NULL;
    3.24 +static int inputDeviceCount = 0;
    3.25 +
    3.26 +static int
    3.27 +test_for_mmap(int fd)
    3.28 +{
    3.29 +    int caps = 0;
    3.30 +    struct audio_buf_info info;
    3.31 +    if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
    3.32 +        (caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
    3.33 +        (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0))
    3.34 +    {
    3.35 +        size_t len = info.fragstotal * info.fragsize;
    3.36 +        Uint8 *buf = (Uint8 *) mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
    3.37 +        if (buf != MAP_FAILED) {
    3.38 +            munmap(buf, len);
    3.39 +            return 1;
    3.40 +        }
    3.41 +    }
    3.42 +    return 0;
    3.43 +}
    3.44 +
    3.45 +
    3.46 +static inline void
    3.47 +free_device_list(char ***devs, int *count)
    3.48 +{
    3.49 +    SDL_FreeUnixAudioDevices(devs, count);
    3.50 +}
    3.51 +
    3.52 +static inline void
    3.53 +build_device_list(int iscapture, char ***devs, int *count)
    3.54 +{
    3.55 +    const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
    3.56 +    free_device_list(devs, count);
    3.57 +    SDL_EnumUnixAudioDevices(flags, 0, test_for_mmap, devs, count);
    3.58 +}
    3.59 +
    3.60 +static inline void
    3.61 +build_device_lists(void)
    3.62 +{
    3.63 +    build_device_list(0, &outputDevices, &outputDeviceCount);
    3.64 +    build_device_list(1, &inputDevices, &inputDeviceCount);
    3.65 +}
    3.66 +
    3.67 +
    3.68 +static inline void
    3.69 +free_device_lists(void)
    3.70 +{
    3.71 +    free_device_list(&outputDevices, &outputDeviceCount);
    3.72 +    free_device_list(&inputDevices, &inputDeviceCount);
    3.73 +}
    3.74 +
    3.75  static int
    3.76  DMA_Available(void)
    3.77  {
    3.78 -    /*
    3.79 -     * !!! FIXME: maybe change this to always available, and move this to
    3.80 -     * !!! FIXME:  to device enumeration and opening?
    3.81 -     */
    3.82 -    int available;
    3.83 -    int fd;
    3.84 -
    3.85 -    available = 0;
    3.86 -
    3.87 -    fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
    3.88 -    if (fd >= 0) {
    3.89 -        int caps;
    3.90 -        struct audio_buf_info info;
    3.91 -
    3.92 -        if ((ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
    3.93 -            (caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
    3.94 -            (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0)) {
    3.95 -            available = 1;
    3.96 -        }
    3.97 -        close(fd);
    3.98 -    }
    3.99 -    return (available);
   3.100 +    int available = 0;
   3.101 +    build_device_lists();
   3.102 +    available = ((outputDeviceCount > 0) || (inputDeviceCount > 0));
   3.103 +    free_device_lists();
   3.104 +    return available;
   3.105  }
   3.106  
   3.107  
   3.108 @@ -111,7 +150,9 @@
   3.109      impl->PlayDevice = DMA_PlayDevice;
   3.110      impl->GetDeviceBuf = DMA_GetDeviceBuf;
   3.111      impl->CloseDevice = DMA_CloseDevice;
   3.112 +    impl->Deinitialize = DMA_Deinitialize;
   3.113  
   3.114 +    build_device_lists();
   3.115      return 1;
   3.116  }
   3.117  
   3.118 @@ -120,18 +161,36 @@
   3.119      DMA_Available, DMA_Init, 0
   3.120  };
   3.121  
   3.122 +static void DMA_Deinitialize(void)
   3.123 +{
   3.124 +    free_device_lists();
   3.125 +}
   3.126  
   3.127  static int
   3.128  DMA_DetectDevices(int iscapture)
   3.129  {
   3.130 -    return -1;  /* !!! FIXME */
   3.131 +    if (iscapture) {
   3.132 +        build_device_list(1, &inputDevices, &inputDeviceCount);
   3.133 +        return inputDeviceCount;
   3.134 +    } else {
   3.135 +        build_device_list(0, &outputDevices, &outputDeviceCount);
   3.136 +        return outputDeviceCount;
   3.137 +    }
   3.138 +
   3.139 +    return 0;  /* shouldn't ever hit this. */
   3.140  }
   3.141  
   3.142  
   3.143  static const char *
   3.144  DMA_GetDeviceName(int index, int iscapture)
   3.145  {
   3.146 -    SDL_SetError("No such device");  /* !!! FIXME */
   3.147 +    if ((iscapture) && (index < inputDeviceCount)) {
   3.148 +        return inputDevices[index];
   3.149 +    } else if ((!iscapture) && (index < outputDeviceCount)) {
   3.150 +        return outputDevices[index];
   3.151 +    }
   3.152 +
   3.153 +    SDL_SetError("No such device");
   3.154      return NULL;
   3.155  }
   3.156  
   3.157 @@ -198,13 +257,24 @@
   3.158  static int
   3.159  open_device_internal(_THIS, const char *devname, int iscapture)
   3.160  {
   3.161 -    char audiodev[1024];
   3.162 +    const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
   3.163      int format;
   3.164      int stereo;
   3.165      int value;
   3.166      SDL_AudioFormat test_format;
   3.167      struct audio_buf_info info;
   3.168  
   3.169 +    /* We don't care what the devname is...we'll try to open anything. */
   3.170 +    /*  ...but default to first name in the list... */
   3.171 +    if (devname == NULL) {
   3.172 +        if ( ((iscapture) && (inputDeviceCount == 0)) ||
   3.173 +             ((!iscapture) && (outputDeviceCount == 0)) ) {
   3.174 +            SDL_SetError("No such audio device");
   3.175 +            return 0;
   3.176 +        }
   3.177 +        devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
   3.178 +    }
   3.179 +
   3.180      /* Initialize all variables that we clean on shutdown */
   3.181      this->hidden = (struct SDL_PrivateAudioData *)
   3.182                          SDL_malloc((sizeof *this->hidden));
   3.183 @@ -214,13 +284,11 @@
   3.184      }
   3.185      SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   3.186  
   3.187 -    /* !!! FIXME: handle devname */
   3.188 -    /* !!! FIXME: handle iscapture */
   3.189  
   3.190      /* Open the audio device */
   3.191 -    audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
   3.192 +    audio_fd = open(devname, flags, 0);
   3.193      if (audio_fd < 0) {
   3.194 -        SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
   3.195 +        SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
   3.196          return 0;
   3.197      }
   3.198      dma_buf = NULL;
   3.199 @@ -304,7 +372,7 @@
   3.200         after setting the format, we must re-open the audio device
   3.201         once we know what format and channels are supported
   3.202       */
   3.203 -    if (DMA_ReopenAudio(this, audiodev, format, stereo) < 0) {
   3.204 +    if (DMA_ReopenAudio(this, devname, format, stereo) < 0) {
   3.205          /* Error is set by DMA_ReopenAudio() */
   3.206          return 0;
   3.207      }
     4.1 --- a/src/audio/dsp/SDL_dspaudio.c	Thu Oct 05 01:13:47 2006 +0000
     4.2 +++ b/src/audio/dsp/SDL_dspaudio.c	Thu Oct 05 04:47:13 2006 +0000
     4.3 @@ -55,7 +55,8 @@
     4.4  #define DSP_DRIVER_NAME         "dsp"
     4.5  
     4.6  /* Open the audio device for playback, and don't block if busy */
     4.7 -#define OPEN_FLAGS	(O_WRONLY|O_NONBLOCK)
     4.8 +#define OPEN_FLAGS_OUTPUT    (O_WRONLY|O_NONBLOCK)
     4.9 +#define OPEN_FLAGS_INPUT    (O_RDONLY|O_NONBLOCK)
    4.10  
    4.11  /* Audio driver functions */
    4.12  static int DSP_DetectDevices(int iscapture);
    4.13 @@ -65,23 +66,53 @@
    4.14  static void DSP_PlayDevice(_THIS);
    4.15  static Uint8 *DSP_GetDeviceBuf(_THIS);
    4.16  static void DSP_CloseDevice(_THIS);
    4.17 +static void DSP_Deinitialize(void);
    4.18  
    4.19  /* Audio driver bootstrap functions */
    4.20  
    4.21 +static char **outputDevices = NULL;
    4.22 +static int outputDeviceCount = 0;
    4.23 +static char **inputDevices = NULL;
    4.24 +static int inputDeviceCount = 0;
    4.25 +
    4.26 +static inline void
    4.27 +free_device_list(char ***devs, int *count)
    4.28 +{
    4.29 +    SDL_FreeUnixAudioDevices(devs, count);
    4.30 +}
    4.31 +
    4.32 +static inline void
    4.33 +build_device_list(int iscapture, char ***devs, int *count)
    4.34 +{
    4.35 +    const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
    4.36 +    free_device_list(devs, count);
    4.37 +    SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count);
    4.38 +}
    4.39 +
    4.40 +static inline void
    4.41 +build_device_lists(void)
    4.42 +{
    4.43 +    build_device_list(0, &outputDevices, &outputDeviceCount);
    4.44 +    build_device_list(1, &inputDevices, &inputDeviceCount);
    4.45 +}
    4.46 +
    4.47 +
    4.48 +static inline void
    4.49 +free_device_lists(void)
    4.50 +{
    4.51 +    free_device_list(&outputDevices, &outputDeviceCount);
    4.52 +    free_device_list(&inputDevices, &inputDeviceCount);
    4.53 +}
    4.54 +
    4.55 +
    4.56  static int
    4.57  DSP_Available(void)
    4.58  {
    4.59 -    /*
    4.60 -     * !!! FIXME: maybe change this to always available, and move this to
    4.61 -     * !!! FIXME:  to device enumeration and opening?
    4.62 -     */
    4.63 -    int fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
    4.64      int available = 0;
    4.65 -    if (fd >= 0) {
    4.66 -        available = 1;
    4.67 -        close(fd);
    4.68 -    }
    4.69 -    return (available);
    4.70 +    build_device_lists();
    4.71 +    available = ((outputDeviceCount > 0) || (inputDeviceCount > 0));
    4.72 +    free_device_lists();
    4.73 +    return available;
    4.74  }
    4.75  
    4.76  
    4.77 @@ -92,11 +123,12 @@
    4.78      impl->DetectDevices = DSP_DetectDevices;
    4.79      impl->GetDeviceName = DSP_GetDeviceName;
    4.80      impl->OpenDevice = DSP_OpenDevice;
    4.81 -    impl->WaitDevice = DSP_WaitDevice;
    4.82      impl->PlayDevice = DSP_PlayDevice;
    4.83      impl->GetDeviceBuf = DSP_GetDeviceBuf;
    4.84      impl->CloseDevice = DSP_CloseDevice;
    4.85 +    impl->Deinitialize = DSP_Deinitialize;
    4.86  
    4.87 +    build_device_lists();
    4.88      return 1;
    4.89  }
    4.90  
    4.91 @@ -107,17 +139,36 @@
    4.92  };
    4.93  
    4.94  
    4.95 +static void DSP_Deinitialize(void)
    4.96 +{
    4.97 +    free_device_lists();
    4.98 +}
    4.99 +
   4.100 +
   4.101  static int
   4.102  DSP_DetectDevices(int iscapture)
   4.103  {
   4.104 -    return -1;  /* !!! FIXME */
   4.105 +    if (iscapture) {
   4.106 +        build_device_list(1, &inputDevices, &inputDeviceCount);
   4.107 +        return inputDeviceCount;
   4.108 +    } else {
   4.109 +        build_device_list(0, &outputDevices, &outputDeviceCount);
   4.110 +        return outputDeviceCount;
   4.111 +    }
   4.112 +
   4.113 +    return 0;  /* shouldn't ever hit this. */
   4.114  }
   4.115  
   4.116 -
   4.117  static const char *
   4.118  DSP_GetDeviceName(int index, int iscapture)
   4.119  {
   4.120 -    SDL_SetError("No such device");  /* !!! FIXME */
   4.121 +    if ((iscapture) && (index < inputDeviceCount)) {
   4.122 +        return inputDevices[index];
   4.123 +    } else if ((!iscapture) && (index < outputDeviceCount)) {
   4.124 +        return outputDevices[index];
   4.125 +    }
   4.126 +
   4.127 +    SDL_SetError("No such device");
   4.128      return NULL;
   4.129  }
   4.130  
   4.131 @@ -125,12 +176,23 @@
   4.132  static int
   4.133  DSP_OpenDevice(_THIS, const char *devname, int iscapture)
   4.134  {
   4.135 -    char dev[1024];
   4.136 +    const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
   4.137      int format;
   4.138      int value;
   4.139      int frag_spec;
   4.140      SDL_AudioFormat test_format;
   4.141  
   4.142 +    /* We don't care what the devname is...we'll try to open anything. */
   4.143 +    /*  ...but default to first name in the list... */
   4.144 +    if (devname == NULL) {
   4.145 +        if ( ((iscapture) && (inputDeviceCount == 0)) ||
   4.146 +             ((!iscapture) && (outputDeviceCount == 0)) ) {
   4.147 +            SDL_SetError("No such audio device");
   4.148 +            return 0;
   4.149 +        }
   4.150 +        devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
   4.151 +    }
   4.152 +
   4.153      /* Initialize all variables that we clean on shutdown */
   4.154      this->hidden = (struct SDL_PrivateAudioData *)
   4.155                          SDL_malloc((sizeof *this->hidden));
   4.156 @@ -141,13 +203,10 @@
   4.157      SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   4.158      this->hidden->audio_fd = -1;
   4.159  
   4.160 -    /* !!! FIXME: handle devname */
   4.161 -    /* !!! FIXME: handle iscapture */
   4.162 -
   4.163      /* Open the audio device */
   4.164 -    this->hidden->audio_fd = SDL_OpenAudioPath(dev, sizeof(dev), OPEN_FLAGS, 0);
   4.165 +    this->hidden->audio_fd = open(devname, flags, 0);
   4.166      if (this->hidden->audio_fd < 0) {
   4.167 -        SDL_SetError("Couldn't open %s: %s", dev, strerror(errno));
   4.168 +        SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
   4.169          return 0;
   4.170      }
   4.171      this->hidden->mixbuf = NULL;
   4.172 @@ -306,14 +365,6 @@
   4.173  }
   4.174  
   4.175  
   4.176 -/* This function waits until it is possible to write a full sound buffer */
   4.177 -static void
   4.178 -DSP_WaitDevice(_THIS)
   4.179 -{
   4.180 -    /* Not needed at all since OSS handles waiting automagically */
   4.181 -}
   4.182 -
   4.183 -
   4.184  static void
   4.185  DSP_PlayDevice(_THIS)
   4.186  {