Skip to content

Commit

Permalink
Bunch of reworking to how we manage audio devices.
Browse files Browse the repository at this point in the history
Device enumeration now happens at startup and then is managed exclusively
through hotplugging instead of full redetection. The device name list now has
a unique "handle" associated with each item and SDL will pass this to the
backend so they don't have to figure out how a human readable name maps to
real hardware for a second time.

Other cleanups, fixes, improvements, plus all the audio backends updated to
the new interface...largely untested at this point, though.
  • Loading branch information
icculus committed Mar 18, 2015
1 parent 0e02ce0 commit f9cfd9f
Show file tree
Hide file tree
Showing 27 changed files with 430 additions and 575 deletions.
348 changes: 174 additions & 174 deletions src/audio/SDL_audio.c

Large diffs are not rendered by default.

34 changes: 22 additions & 12 deletions src/audio/SDL_audiodev.c
Expand Up @@ -46,18 +46,21 @@
#define _PATH_DEV_AUDIO "/dev/audio"
#endif

static SDL_INLINE void
test_device(const char *fname, int flags, int (*test) (int fd),
SDL_AddAudioDevice addfn)
static void
test_device(const int iscapture, const char *fname, int flags, int (*test) (int fd))
{
struct stat sb;
if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
const int audio_fd = open(fname, flags, 0);
if (audio_fd >= 0) {
if (test(audio_fd)) {
addfn(fname);
}
const int okay = test(audio_fd);
close(audio_fd);
if (okay) {
static size_t dummyhandle = 0;
dummyhandle++;
SDL_assert(dummyhandle != 0);
SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle);
}
}
}
}
Expand All @@ -68,11 +71,10 @@ test_stub(int fd)
return 1;
}

void
SDL_EnumUnixAudioDevices(int iscapture, int classic, int (*test)(int fd),
SDL_AddAudioDevice addfn)
static void
SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int classic, int (*test)(int))
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
const char *audiodev;
char audiopath[1024];

Expand All @@ -97,17 +99,25 @@ SDL_EnumUnixAudioDevices(int iscapture, int classic, int (*test)(int fd),
}
}
}
test_device(audiodev, flags, test, addfn);
test_device(iscapture, audiodev, flags, test);

if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
int instance = 0;
while (instance++ <= 64) {
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
"%s%d", audiodev, instance);
test_device(audiopath, flags, test, addfn);
test_device(iscapture, audiopath, flags, test);
}
}
}

void
SDL_EnumUnixAudioDevices(const int classic, int (*test)(int))
{
SDL_EnumUnixAudioDevices_Internal(SDL_TRUE, classic, test);
SDL_EnumUnixAudioDevices_Internal(SDL_FALSE, classic, test);
}

#endif /* Audio driver selection */

/* vi: set ts=4 sw=4 expandtab: */
3 changes: 1 addition & 2 deletions src/audio/SDL_audiodev_c.h
Expand Up @@ -33,7 +33,6 @@
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
#endif

void SDL_EnumUnixAudioDevices(int iscapture, int classic,
int (*test) (int fd), SDL_AddAudioDevice addfn);
extern void SDL_EnumUnixAudioDevices(const int classic, int (*test)(int));

/* vi: set ts=4 sw=4 expandtab: */
47 changes: 29 additions & 18 deletions src/audio/SDL_sysaudio.h
Expand Up @@ -30,16 +30,20 @@
typedef struct SDL_AudioDevice SDL_AudioDevice;
#define _THIS SDL_AudioDevice *_this

/* Used by audio targets during DetectDevices() */
typedef int (*SDL_AddAudioDevice)(const char *name);
/* Audio targets should call this as devices are added to the system (such as
a USB headset being plugged in), and should also be called for
for every device found during DetectDevices(). */
extern void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle);

/* Audio targets should call this as devices are hotplugged. Don't call
during DetectDevices(), this is for hotplugging a device later. */
extern void SDL_AudioDeviceConnected(const int iscapture, const char *name);
/* Audio targets should call this as devices are removed, so SDL can update
its list of available devices. */
extern void SDL_RemoveAudioDevice(void *handle);

/* Audio targets should call this as devices are unplugged.
(device) can be NULL if an unopened device is lost. */
extern void SDL_AudioDeviceDisconnected(const int iscapture, SDL_AudioDevice *device);
/* Audio targets should call this if an opened audio device is lost while
being used. This can happen due to i/o errors, or a device being unplugged,
etc. If the device is totally gone, please also call SDL_RemoveAudioDevice()
as appropriate so SDL's list of devices is accurate. */
extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device);


/* This is the size of a packet when using SDL_QueueAudio(). We allocate
Expand All @@ -64,8 +68,8 @@ typedef struct SDL_AudioBufferQueue

typedef struct SDL_AudioDriverImpl
{
void (*DetectDevices) (int iscapture, SDL_AddAudioDevice addfn);
int (*OpenDevice) (_THIS, const char *devname, int iscapture);
void (*DetectDevices) (void);
int (*OpenDevice) (_THIS, void *handle, const char *devname, int iscapture);
void (*ThreadInit) (_THIS); /* Called by audio thread at start */
void (*WaitDevice) (_THIS);
void (*PlayDevice) (_THIS);
Expand All @@ -75,6 +79,7 @@ typedef struct SDL_AudioDriverImpl
void (*CloseDevice) (_THIS);
void (*LockDevice) (_THIS);
void (*UnlockDevice) (_THIS);
void (*FreeDeviceHandle) (void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */
void (*Deinitialize) (void);

/* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */
Expand All @@ -86,9 +91,18 @@ typedef struct SDL_AudioDriverImpl
int HasCaptureSupport;
int OnlyHasDefaultOutputDevice;
int OnlyHasDefaultInputDevice;
int AllowsArbitraryDeviceNames;
} SDL_AudioDriverImpl;


typedef struct SDL_AudioDeviceItem
{
void *handle;
struct SDL_AudioDeviceItem *next;
char name[];
} SDL_AudioDeviceItem;


typedef struct SDL_AudioDriver
{
/* * * */
Expand All @@ -102,16 +116,13 @@ typedef struct SDL_AudioDriver
SDL_AudioDriverImpl impl;

/* A mutex for device detection */
SDL_mutex *detection_lock;

SDL_bool need_capture_device_redetect;
SDL_bool need_output_device_redetect;

char **outputDevices;
SDL_mutex *detectionLock;
SDL_bool captureDevicesRemoved;
SDL_bool outputDevicesRemoved;
int outputDeviceCount;

char **inputDevices;
int inputDeviceCount;
SDL_AudioDeviceItem *outputDevices;
SDL_AudioDeviceItem *inputDevices;
} SDL_AudioDriver;


Expand Down
4 changes: 2 additions & 2 deletions src/audio/alsa/SDL_alsa_audio.c
Expand Up @@ -320,7 +320,7 @@ ALSA_PlayDevice(_THIS)
/* Hmm, not much we can do - abort */
fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
ALSA_snd_strerror(status));
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
SDL_OpenedAudioDeviceDisconnected(this);
return;
}
continue;
Expand Down Expand Up @@ -465,7 +465,7 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override)
}

static int
ALSA_OpenDevice(_THIS, const char *devname, int iscapture)
ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int status = 0;
snd_pcm_t *pcm_handle = NULL;
Expand Down
2 changes: 1 addition & 1 deletion src/audio/android/SDL_androidaudio.c
Expand Up @@ -35,7 +35,7 @@
static SDL_AudioDevice* audioDevice = NULL;

static int
AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture)
AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
SDL_AudioFormat test_format;

Expand Down
6 changes: 3 additions & 3 deletions src/audio/arts/SDL_artsaudio.c
Expand Up @@ -151,7 +151,7 @@ ARTS_WaitDevice(_THIS)
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
SDL_OpenedAudioDeviceDisconnected(this);
}
}
}
Expand Down Expand Up @@ -179,7 +179,7 @@ ARTS_PlayDevice(_THIS)

/* If we couldn't write, assume fatal error for now */
if (written < 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
Expand Down Expand Up @@ -229,7 +229,7 @@ ARTS_Suspend(void)
}

static int
ARTS_OpenDevice(_THIS, const char *devname, int iscapture)
ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int rc = 0;
int bits = 0, frag_spec = 0;
Expand Down
12 changes: 7 additions & 5 deletions src/audio/bsd/SDL_bsdaudio.c
Expand Up @@ -51,9 +51,9 @@


static void
BSDAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
BSDAUDIO_DetectDevices(void)
{
SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn);
SDL_EnumUnixAudioDevices(0, NULL);
}


Expand Down Expand Up @@ -150,7 +150,7 @@ BSDAUDIO_WaitDevice(_THIS)
the user know what happened.
*/
fprintf(stderr, "SDL: %s\n", message);
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
SDL_OpenedAudioDeviceDisconnected(this);
/* Don't try to close - may hang */
this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO
Expand Down Expand Up @@ -195,7 +195,7 @@ BSDAUDIO_PlayDevice(_THIS)

/* If we couldn't write, assume fatal error for now */
if (written < 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
Expand Down Expand Up @@ -224,7 +224,7 @@ BSDAUDIO_CloseDevice(_THIS)
}

static int
BSDAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0;
Expand Down Expand Up @@ -348,6 +348,8 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
impl->CloseDevice = BSDAUDIO_CloseDevice;

impl->AllowsArbitraryDeviceNames = 1;

return 1; /* this audio target is available. */
}

Expand Down

0 comments on commit f9cfd9f

Please sign in to comment.