Bunch of reworking to how we manage audio devices.

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.
Ryan C. Gordon 2015-03-18 02:01:17 -04:00
parent 0e02ce0856
commit f9cfd9fa14
27 changed files with 430 additions and 575 deletions

View File

@ -161,8 +161,16 @@ get_audio_device(SDL_AudioDeviceID id)
/* stubs for audio drivers that don't need a specific entry point... */ /* stubs for audio drivers that don't need a specific entry point... */
static void static void
SDL_AudioDetectDevices_Default(int iscapture, SDL_AddAudioDevice addfn) SDL_AudioDetectDevices_Default(void)
{ /* no-op. */ {
/* you have to write your own implementation if these assertions fail. */
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
SDL_assert(current_audio.impl.OnlyHasDefaultInputDevice || !current_audio.impl.HasCaptureSupport);
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
if (current_audio.impl.HasCaptureSupport) {
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) ((size_t) 0x2));
}
} }
static void static void
@ -207,10 +215,16 @@ SDL_AudioDeinitialize_Default(void)
{ /* no-op. */ { /* no-op. */
} }
static void
SDL_AudioFreeDeviceHandle_Default(void *handle)
{ /* no-op. */
}
static int static int
SDL_AudioOpenDevice_Default(_THIS, const char *devname, int iscapture) SDL_AudioOpenDevice_Default(_THIS, void *handle, const char *devname, int iscapture)
{ {
return -1; return SDL_Unsupported();
} }
static SDL_INLINE SDL_bool static SDL_INLINE SDL_bool
@ -267,6 +281,7 @@ finalize_audio_entry_points(void)
FILL_STUB(CloseDevice); FILL_STUB(CloseDevice);
FILL_STUB(LockDevice); FILL_STUB(LockDevice);
FILL_STUB(UnlockDevice); FILL_STUB(UnlockDevice);
FILL_STUB(FreeDeviceHandle);
FILL_STUB(Deinitialize); FILL_STUB(Deinitialize);
#undef FILL_STUB #undef FILL_STUB
} }
@ -335,94 +350,64 @@ SDL_StreamDeinit(SDL_AudioStreamer * stream)
/* device hotplug support... */ /* device hotplug support... */
/* this function expects its caller to hold current_audio.detection_lock */
static int static int
add_audio_device(const char *_name, char ***_devices, int *_devCount) add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
{ {
char *name = SDL_strdup(_name);
int retval = -1; int retval = -1;
const size_t size = sizeof (SDL_AudioDeviceItem) + SDL_strlen(name) + 1;
if (name != NULL) { SDL_AudioDeviceItem *item = (SDL_AudioDeviceItem *) SDL_malloc(size);
char **devices = *_devices; if (item == NULL) {
int devCount = *_devCount; return -1;
void *ptr = SDL_realloc(devices, (devCount+1) * sizeof(char*));
if (ptr == NULL) {
SDL_free(name);
} else {
retval = devCount;
devices = (char **) ptr;
devices[devCount++] = name;
*_devices = devices;
*_devCount = devCount;
}
} }
SDL_assert(handle != NULL);
item->handle = handle;
SDL_strlcpy(item->name, name, size - sizeof (SDL_AudioDeviceItem));
SDL_LockMutex(current_audio.detectionLock);
item->next = *devices;
*devices = item;
retval = (*devCount)++;
SDL_UnlockMutex(current_audio.detectionLock);
return retval; return retval;
} }
static int static SDL_INLINE int
add_capture_device(const char *name) add_capture_device(const char *name, void *handle)
{ {
/* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/ /* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/
return add_audio_device(name, &current_audio.inputDevices, &current_audio.inputDeviceCount); return add_audio_device(name, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
} }
static int static SDL_INLINE int
add_output_device(const char *name) add_output_device(const char *name, void *handle)
{ {
return add_audio_device(name, &current_audio.outputDevices, &current_audio.outputDeviceCount); return add_audio_device(name, handle, &current_audio.outputDevices, &current_audio.outputDeviceCount);
} }
static void static void
free_device_list(char ***devices, int *devCount) free_device_list(SDL_AudioDeviceItem **devices, int *devCount)
{ {
int i = *devCount; SDL_AudioDeviceItem *item, *next;
if ((i > 0) && (*devices != NULL)) { for (item = *devices; item != NULL; item = next) {
while (i--) { next = item->next;
SDL_free((*devices)[i]); if (item->handle != NULL) {
current_audio.impl.FreeDeviceHandle(item->handle);
} }
SDL_free(item);
} }
SDL_free(*devices);
*devices = NULL; *devices = NULL;
*devCount = 0; *devCount = 0;
} }
static void
perform_full_device_redetect(const int iscapture)
{
SDL_LockMutex(current_audio.detection_lock);
if (iscapture) {
if (!current_audio.impl.OnlyHasDefaultOutputDevice) {
free_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount);
current_audio.impl.DetectDevices(SDL_FALSE, add_output_device);
}
} else {
if ((current_audio.impl.HasCaptureSupport) && (!current_audio.impl.OnlyHasDefaultInputDevice)) {
free_device_list(&current_audio.inputDevices, &current_audio.inputDeviceCount);
current_audio.impl.DetectDevices(SDL_TRUE, add_capture_device);
}
}
SDL_UnlockMutex(current_audio.detection_lock);
}
/* The audio backends call this when a new device is plugged in. */ /* The audio backends call this when a new device is plugged in. */
void void
SDL_AudioDeviceConnected(const int iscapture, const char *name) SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)
{ {
int device_index = -1; const int device_index = iscapture ? add_capture_device(name, handle) : add_output_device(name, handle);
SDL_LockMutex(current_audio.detection_lock);
if (iscapture) {
device_index = add_capture_device(name);
} else {
device_index = add_output_device(name);
}
SDL_UnlockMutex(current_audio.detection_lock);
if (device_index != -1) { if (device_index != -1) {
/* Post the event, if desired */ /* Post the event, if desired */
if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) { if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) {
@ -435,39 +420,51 @@ SDL_AudioDeviceConnected(const int iscapture, const char *name)
} }
} }
/* The audio backends call this when a device is unplugged. */ /* The audio backends call this when a currently-opened device is lost. */
void void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
SDL_AudioDeviceDisconnected(const int iscapture, SDL_AudioDevice *device)
{ {
/* device==NULL means an unopened device was lost; do the redetect only. */ SDL_assert(get_audio_device(device->id) == device);
if (device != NULL) { SDL_assert(device->enabled); /* called more than once?! */
SDL_assert(get_audio_device(device->id) == device);
SDL_assert(device->enabled); /* called more than once?! */
/* Ends the audio callback and mark the device as STOPPED, but the /* Ends the audio callback and mark the device as STOPPED, but the
app still needs to close the device to free resources. */ app still needs to close the device to free resources. */
current_audio.impl.LockDevice(device); current_audio.impl.LockDevice(device);
device->enabled = 0; device->enabled = 0;
current_audio.impl.UnlockDevice(device); current_audio.impl.UnlockDevice(device);
/* Post the event, if desired */ /* Post the event, if desired */
if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) { if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) {
SDL_Event event; SDL_Event event;
event.adevice.type = SDL_AUDIODEVICEREMOVED; event.adevice.type = SDL_AUDIODEVICEREMOVED;
event.adevice.which = device->id; event.adevice.which = device->id;
event.adevice.iscapture = device->iscapture ? 1 : 0; event.adevice.iscapture = device->iscapture ? 1 : 0;
SDL_PushEvent(&event); SDL_PushEvent(&event);
}
}
static void
mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *removedFlag)
{
SDL_AudioDeviceItem *item;
SDL_assert(handle != NULL);
for (item = devices; item != NULL; item = item->next) {
if (item->handle == handle) {
item->handle = NULL;
*removedFlag = SDL_TRUE;
return;
} }
} }
}
/* we don't really know which name (if any) was associated with this /* The audio backends call this when a device is removed from the system. */
device in the device list, so drop the entire list and rebuild it. void
(we should probably change the API in 2.1 to make this more clear?) */ SDL_RemoveAudioDevice(void *handle)
if (iscapture) { {
current_audio.need_capture_device_redetect = SDL_TRUE; SDL_LockMutex(current_audio.detectionLock);
} else { mark_device_removed(handle, current_audio.inputDevices, &current_audio.captureDevicesRemoved);
current_audio.need_output_device_redetect = SDL_TRUE; mark_device_removed(handle, current_audio.outputDevices, &current_audio.outputDevicesRemoved);
} SDL_UnlockMutex(current_audio.detectionLock);
current_audio.impl.FreeDeviceHandle(handle);
} }
@ -966,33 +963,12 @@ SDL_AudioInit(const char *driver_name)
return -1; /* No driver was available, so fail. */ return -1; /* No driver was available, so fail. */
} }
current_audio.detection_lock = SDL_CreateMutex(); current_audio.detectionLock = SDL_CreateMutex();
finalize_audio_entry_points(); finalize_audio_entry_points();
/* Make sure we have a list of devices available at startup. */ /* Make sure we have a list of devices available at startup. */
perform_full_device_redetect(SDL_TRUE); current_audio.impl.DetectDevices();
perform_full_device_redetect(SDL_FALSE);
/* Post an add event for each initial device, if desired */
if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) {
SDL_Event event;
SDL_zero(event);
event.adevice.type = SDL_AUDIODEVICEADDED;
event.adevice.iscapture = 0;
for (i = 0; i < current_audio.outputDeviceCount; i++) {
event.adevice.which = i;
SDL_PushEvent(&event);
}
event.adevice.iscapture = 1;
for (i = 0; i < current_audio.inputDeviceCount; i++) {
event.adevice.which = i;
SDL_PushEvent(&event);
}
}
return 0; return 0;
} }
@ -1006,6 +982,35 @@ SDL_GetCurrentAudioDriver()
return current_audio.name; return current_audio.name;
} }
/* Clean out devices that we've removed but had to keep around for stability. */
static void
clean_out_device_list(SDL_AudioDeviceItem **devices, int *devCount, SDL_bool *removedFlag)
{
SDL_AudioDeviceItem *item = *devices;
SDL_AudioDeviceItem *prev = NULL;
int total = 0;
while (item) {
SDL_AudioDeviceItem *next = item->next;
if (item->handle != NULL) {
total++;
prev = item;
} else {
if (prev) {
prev->next = next;
} else {
*devices = next;
}
SDL_free(item);
}
item = next;
}
*devCount = total;
*removedFlag = SDL_FALSE;
}
int int
SDL_GetNumAudioDevices(int iscapture) SDL_GetNumAudioDevices(int iscapture)
{ {
@ -1015,31 +1020,18 @@ SDL_GetNumAudioDevices(int iscapture)
return -1; return -1;
} }
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) { SDL_LockMutex(current_audio.detectionLock);
return 0; if (iscapture && current_audio.captureDevicesRemoved) {
clean_out_device_list(&current_audio.inputDevices, &current_audio.inputDeviceCount, &current_audio.captureDevicesRemoved);
} }
if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { if (!iscapture && current_audio.outputDevicesRemoved) {
return 1; clean_out_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount, &current_audio.outputDevicesRemoved);
current_audio.outputDevicesRemoved = SDL_FALSE;
} }
if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
return 1;
}
if (current_audio.need_capture_device_redetect) {
current_audio.need_capture_device_redetect = SDL_FALSE;
perform_full_device_redetect(SDL_TRUE);
}
if (current_audio.need_output_device_redetect) {
current_audio.need_output_device_redetect = SDL_FALSE;
perform_full_device_redetect(SDL_FALSE);
}
SDL_LockMutex(current_audio.detection_lock);
retval = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; retval = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
SDL_UnlockMutex(current_audio.detection_lock); SDL_UnlockMutex(current_audio.detectionLock);
return retval; return retval;
} }
@ -1060,41 +1052,28 @@ SDL_GetAudioDeviceName(int index, int iscapture)
return NULL; return NULL;
} }
if (index < 0) { if (index >= 0) {
goto no_such_device; SDL_AudioDeviceItem *item;
} int i;
if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { SDL_LockMutex(current_audio.detectionLock);
if (index > 0) { item = iscapture ? current_audio.inputDevices : current_audio.outputDevices;
goto no_such_device; i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
if (index < i) {
for (i--; i > index; i--, item = item->next) {
SDL_assert(item != NULL);
}
SDL_assert(item != NULL);
retval = item->name;
} }
return DEFAULT_INPUT_DEVNAME; SDL_UnlockMutex(current_audio.detectionLock);
} }
if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { if (retval == NULL) {
if (index > 0) { SDL_SetError("No such device");
goto no_such_device;
}
return DEFAULT_OUTPUT_DEVNAME;
} }
SDL_LockMutex(current_audio.detection_lock); return retval;
if (iscapture && (index < current_audio.inputDeviceCount)) {
retval = current_audio.inputDevices[index];
} else if (!iscapture && (index < current_audio.outputDeviceCount)) {
retval = current_audio.outputDevices[index];
}
SDL_UnlockMutex(current_audio.detection_lock);
/* !!! FIXME: a device could be removed after being returned here, freeing retval's pointer. */
if (retval != NULL) {
return retval;
}
no_such_device:
SDL_SetError("No such device");
return NULL;
} }
@ -1195,6 +1174,7 @@ open_audio_device(const char *devname, int iscapture,
SDL_AudioSpec _obtained; SDL_AudioSpec _obtained;
SDL_AudioDevice *device; SDL_AudioDevice *device;
SDL_bool build_cvt; SDL_bool build_cvt;
void *handle = NULL;
int i = 0; int i = 0;
if (!SDL_WasInit(SDL_INIT_AUDIO)) { if (!SDL_WasInit(SDL_INIT_AUDIO)) {
@ -1254,9 +1234,7 @@ open_audio_device(const char *devname, int iscapture,
return 0; return 0;
} }
} }
} } else if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) { if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
SDL_SetError("No such device"); SDL_SetError("No such device");
return 0; return 0;
@ -1269,6 +1247,30 @@ open_audio_device(const char *devname, int iscapture,
return 0; return 0;
} }
} }
} else if (devname != NULL) {
/* if the app specifies an exact string, we can pass the backend
an actual device handle thingey, which saves them the effort of
figuring out what device this was (such as, reenumerating
everything again to find the matching human-readable name).
It might still need to open a device based on the string for,
say, a network audio server, but this optimizes some cases. */
SDL_AudioDeviceItem *item;
SDL_LockMutex(current_audio.detectionLock);
for (item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; item; item = item->next) {
if ((item->handle != NULL) && (SDL_strcmp(item->name, devname) == 0)) {
handle = item->handle;
break;
}
}
SDL_UnlockMutex(current_audio.detectionLock);
}
if (!current_audio.impl.AllowsArbitraryDeviceNames) {
/* has to be in our device list, or the default device. */
if ((handle == NULL) && (devname != NULL)) {
SDL_SetError("No such device.");
return 0;
}
} }
device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice)); device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice));
@ -1293,7 +1295,7 @@ open_audio_device(const char *devname, int iscapture,
} }
} }
if (current_audio.impl.OpenDevice(device, devname, iscapture) < 0) { if (current_audio.impl.OpenDevice(device, handle, devname, iscapture) < 0) {
close_audio_device(device); close_audio_device(device);
return 0; return 0;
} }
@ -1555,15 +1557,13 @@ SDL_AudioQuit(void)
} }
} }
free_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount);
free_device_list(&current_audio.inputDevices, &current_audio.inputDeviceCount);
/* Free the driver data */ /* Free the driver data */
current_audio.impl.Deinitialize(); current_audio.impl.Deinitialize();
free_device_list(&current_audio.outputDevices, SDL_DestroyMutex(current_audio.detectionLock);
&current_audio.outputDeviceCount);
free_device_list(&current_audio.inputDevices,
&current_audio.inputDeviceCount);
SDL_DestroyMutex(current_audio.detection_lock);
SDL_zero(current_audio); SDL_zero(current_audio);
SDL_zero(open_devices); SDL_zero(open_devices);

View File

@ -46,18 +46,21 @@
#define _PATH_DEV_AUDIO "/dev/audio" #define _PATH_DEV_AUDIO "/dev/audio"
#endif #endif
static SDL_INLINE void static void
test_device(const char *fname, int flags, int (*test) (int fd), test_device(const int iscapture, const char *fname, int flags, int (*test) (int fd))
SDL_AddAudioDevice addfn)
{ {
struct stat sb; struct stat sb;
if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) { if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
const int audio_fd = open(fname, flags, 0); const int audio_fd = open(fname, flags, 0);
if (audio_fd >= 0) { if (audio_fd >= 0) {
if (test(audio_fd)) { const int okay = test(audio_fd);
addfn(fname);
}
close(audio_fd); close(audio_fd);
if (okay) {
static size_t dummyhandle = 0;
dummyhandle++;
SDL_assert(dummyhandle != 0);
SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle);
}
} }
} }
} }
@ -68,11 +71,10 @@ test_stub(int fd)
return 1; return 1;
} }
void static void
SDL_EnumUnixAudioDevices(int iscapture, int classic, int (*test)(int fd), SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int classic, int (*test)(int))
SDL_AddAudioDevice addfn)
{ {
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
const char *audiodev; const char *audiodev;
char audiopath[1024]; char audiopath[1024];
@ -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)) { if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
int instance = 0; int instance = 0;
while (instance++ <= 64) { while (instance++ <= 64) {
SDL_snprintf(audiopath, SDL_arraysize(audiopath), SDL_snprintf(audiopath, SDL_arraysize(audiopath),
"%s%d", audiodev, instance); "%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 */ #endif /* Audio driver selection */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */

View File

@ -33,7 +33,6 @@
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK) #define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
#endif #endif
void SDL_EnumUnixAudioDevices(int iscapture, int classic, extern void SDL_EnumUnixAudioDevices(const int classic, int (*test)(int));
int (*test) (int fd), SDL_AddAudioDevice addfn);
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */

View File

@ -30,16 +30,20 @@
typedef struct SDL_AudioDevice SDL_AudioDevice; typedef struct SDL_AudioDevice SDL_AudioDevice;
#define _THIS SDL_AudioDevice *_this #define _THIS SDL_AudioDevice *_this
/* Used by audio targets during DetectDevices() */ /* Audio targets should call this as devices are added to the system (such as
typedef int (*SDL_AddAudioDevice)(const char *name); 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 /* Audio targets should call this as devices are removed, so SDL can update
during DetectDevices(), this is for hotplugging a device later. */ its list of available devices. */
extern void SDL_AudioDeviceConnected(const int iscapture, const char *name); extern void SDL_RemoveAudioDevice(void *handle);
/* Audio targets should call this as devices are unplugged. /* Audio targets should call this if an opened audio device is lost while
(device) can be NULL if an unopened device is lost. */ being used. This can happen due to i/o errors, or a device being unplugged,
extern void SDL_AudioDeviceDisconnected(const int iscapture, SDL_AudioDevice *device); 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 /* This is the size of a packet when using SDL_QueueAudio(). We allocate
@ -64,8 +68,8 @@ typedef struct SDL_AudioBufferQueue
typedef struct SDL_AudioDriverImpl typedef struct SDL_AudioDriverImpl
{ {
void (*DetectDevices) (int iscapture, SDL_AddAudioDevice addfn); void (*DetectDevices) (void);
int (*OpenDevice) (_THIS, const char *devname, int iscapture); int (*OpenDevice) (_THIS, void *handle, const char *devname, int iscapture);
void (*ThreadInit) (_THIS); /* Called by audio thread at start */ void (*ThreadInit) (_THIS); /* Called by audio thread at start */
void (*WaitDevice) (_THIS); void (*WaitDevice) (_THIS);
void (*PlayDevice) (_THIS); void (*PlayDevice) (_THIS);
@ -75,6 +79,7 @@ typedef struct SDL_AudioDriverImpl
void (*CloseDevice) (_THIS); void (*CloseDevice) (_THIS);
void (*LockDevice) (_THIS); void (*LockDevice) (_THIS);
void (*UnlockDevice) (_THIS); void (*UnlockDevice) (_THIS);
void (*FreeDeviceHandle) (void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */
void (*Deinitialize) (void); void (*Deinitialize) (void);
/* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */ /* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */
@ -86,9 +91,18 @@ typedef struct SDL_AudioDriverImpl
int HasCaptureSupport; int HasCaptureSupport;
int OnlyHasDefaultOutputDevice; int OnlyHasDefaultOutputDevice;
int OnlyHasDefaultInputDevice; int OnlyHasDefaultInputDevice;
int AllowsArbitraryDeviceNames;
} SDL_AudioDriverImpl; } SDL_AudioDriverImpl;
typedef struct SDL_AudioDeviceItem
{
void *handle;
struct SDL_AudioDeviceItem *next;
char name[];
} SDL_AudioDeviceItem;
typedef struct SDL_AudioDriver typedef struct SDL_AudioDriver
{ {
/* * * */ /* * * */
@ -102,16 +116,13 @@ typedef struct SDL_AudioDriver
SDL_AudioDriverImpl impl; SDL_AudioDriverImpl impl;
/* A mutex for device detection */ /* A mutex for device detection */
SDL_mutex *detection_lock; SDL_mutex *detectionLock;
SDL_bool captureDevicesRemoved;
SDL_bool need_capture_device_redetect; SDL_bool outputDevicesRemoved;
SDL_bool need_output_device_redetect;
char **outputDevices;
int outputDeviceCount; int outputDeviceCount;
char **inputDevices;
int inputDeviceCount; int inputDeviceCount;
SDL_AudioDeviceItem *outputDevices;
SDL_AudioDeviceItem *inputDevices;
} SDL_AudioDriver; } SDL_AudioDriver;

View File

@ -320,7 +320,7 @@ ALSA_PlayDevice(_THIS)
/* Hmm, not much we can do - abort */ /* Hmm, not much we can do - abort */
fprintf(stderr, "ALSA write failed (unrecoverable): %s\n", fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
ALSA_snd_strerror(status)); ALSA_snd_strerror(status));
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
return; return;
} }
continue; continue;
@ -465,7 +465,7 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override)
} }
static int static int
ALSA_OpenDevice(_THIS, const char *devname, int iscapture) ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
int status = 0; int status = 0;
snd_pcm_t *pcm_handle = NULL; snd_pcm_t *pcm_handle = NULL;

View File

@ -35,7 +35,7 @@
static SDL_AudioDevice* audioDevice = NULL; static SDL_AudioDevice* audioDevice = NULL;
static int static int
AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture) AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
SDL_AudioFormat test_format; SDL_AudioFormat test_format;

View File

@ -151,7 +151,7 @@ ARTS_WaitDevice(_THIS)
/* Check every 10 loops */ /* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) { if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) { if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
} }
} }
@ -179,7 +179,7 @@ ARTS_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if (written < 0) { if (written < 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written); fprintf(stderr, "Wrote %d bytes of audio data\n", written);
@ -229,7 +229,7 @@ ARTS_Suspend(void)
} }
static int static int
ARTS_OpenDevice(_THIS, const char *devname, int iscapture) ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
int rc = 0; int rc = 0;
int bits = 0, frag_spec = 0; int bits = 0, frag_spec = 0;

View File

@ -51,9 +51,9 @@
static void static void
BSDAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) BSDAUDIO_DetectDevices(void)
{ {
SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn); SDL_EnumUnixAudioDevices(0, NULL);
} }
@ -150,7 +150,7 @@ BSDAUDIO_WaitDevice(_THIS)
the user know what happened. the user know what happened.
*/ */
fprintf(stderr, "SDL: %s\n", message); fprintf(stderr, "SDL: %s\n", message);
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
/* Don't try to close - may hang */ /* Don't try to close - may hang */
this->hidden->audio_fd = -1; this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
@ -195,7 +195,7 @@ BSDAUDIO_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if (written < 0) { if (written < 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written); fprintf(stderr, "Wrote %d bytes of audio data\n", written);
@ -224,7 +224,7 @@ BSDAUDIO_CloseDevice(_THIS)
} }
static int 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); const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0; SDL_AudioFormat format = 0;
@ -348,6 +348,8 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf; impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
impl->CloseDevice = BSDAUDIO_CloseDevice; impl->CloseDevice = BSDAUDIO_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */ return 1; /* this audio target is available. */
} }

View File

@ -80,28 +80,8 @@ add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
static void static void
addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data) addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
{ {
SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data;
if (add_to_internal_dev_list(iscapture, devId)) { if (add_to_internal_dev_list(iscapture, devId)) {
addfn(name); SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
}
}
typedef struct
{
const char *findname;
AudioDeviceID devId;
int found;
} FindDevIdData;
static void
findDevId(const char *name, const int iscapture, AudioDeviceID devId, void *_data)
{
FindDevIdData *data = (FindDevIdData *) _data;
if (!data->found) {
if (SDL_strcmp(name, data->findname) == 0) {
data->found = 1;
data->devId = devId;
}
} }
} }
@ -226,10 +206,10 @@ free_audio_device_list(AudioDeviceList **list)
} }
static void static void
COREAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) COREAUDIO_DetectDevices(void)
{ {
free_audio_device_list(iscapture ? &capture_devs : &output_devs); build_device_list(SDL_TRUE, addToDevList, NULL);
build_device_list(iscapture, addToDevList, addfn); build_device_list(SDL_FALSE, addToDevList, NULL);
} }
static void static void
@ -245,13 +225,12 @@ build_device_change_list(const char *name, const int iscapture, AudioDeviceID de
} }
add_to_internal_dev_list(iscapture, devId); /* new device, add it. */ add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
SDL_AudioDeviceConnected(iscapture, name); SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
} }
static SDL_bool static void
reprocess_device_list(const int iscapture, AudioDeviceList **list) reprocess_device_list(const int iscapture, AudioDeviceList **list)
{ {
SDL_bool was_disconnect = SDL_FALSE;
AudioDeviceList *item; AudioDeviceList *item;
AudioDeviceList *prev = NULL; AudioDeviceList *prev = NULL;
for (item = *list; item != NULL; item = item->next) { for (item = *list; item != NULL; item = item->next) {
@ -267,7 +246,7 @@ reprocess_device_list(const int iscapture, AudioDeviceList **list)
if (item->alive) { if (item->alive) {
prev = item; prev = item;
} else { } else {
was_disconnect = SDL_TRUE; SDL_RemoveAudioDevice((void *) ((size_t) item->devid));
if (prev) { if (prev) {
prev->next = item->next; prev->next = item->next;
} else { } else {
@ -277,88 +256,16 @@ reprocess_device_list(const int iscapture, AudioDeviceList **list)
} }
item = next; item = next;
} }
return was_disconnect;
} }
/* this is called when the system's list of available audio devices changes. */ /* this is called when the system's list of available audio devices changes. */
static OSStatus static OSStatus
device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data) device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{ {
if (reprocess_device_list(SDL_TRUE, &capture_devs)) { reprocess_device_list(SDL_TRUE, &capture_devs);
SDL_AudioDeviceDisconnected(SDL_TRUE, NULL); reprocess_device_list(SDL_FALSE, &output_devs);
}
if (reprocess_device_list(SDL_FALSE, &output_devs)) {
SDL_AudioDeviceDisconnected(SDL_FALSE, NULL);
}
return 0; return 0;
} }
static int
find_device_by_name(_THIS, const char *devname, int iscapture)
{
AudioDeviceID devid = 0;
OSStatus result = noErr;
UInt32 size = 0;
UInt32 alive = 0;
pid_t pid = 0;
AudioObjectPropertyAddress addr = {
0,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
if (devname == NULL) {
size = sizeof (AudioDeviceID);
addr.mSelector =
((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
kAudioHardwarePropertyDefaultOutputDevice);
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
0, NULL, &size, &devid);
CHECK_RESULT("AudioHardwareGetProperty (default device)");
} else {
FindDevIdData data;
SDL_zero(data);
data.findname = devname;
build_device_list(iscapture, findDevId, &data);
if (!data.found) {
SDL_SetError("CoreAudio: No such audio device.");
return 0;
}
devid = data.devId;
}
addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
kAudioDevicePropertyScopeOutput;
size = sizeof (alive);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
CHECK_RESULT
("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
if (!alive) {
SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
return 0;
}
addr.mSelector = kAudioDevicePropertyHogMode;
size = sizeof (pid);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid);
/* some devices don't support this property, so errors are fine here. */
if ((result == noErr) && (pid != -1)) {
SDL_SetError("CoreAudio: requested device is being hogged.");
return 0;
}
this->hidden->deviceID = devid;
return 1;
}
#endif #endif
/* The CoreAudio callback */ /* The CoreAudio callback */
@ -464,7 +371,7 @@ device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectProperty
} }
if (dead) { if (dead) {
SDL_AudioDeviceDisconnected(this->iscapture, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
return 0; return 0;
@ -514,8 +421,63 @@ COREAUDIO_CloseDevice(_THIS)
} }
} }
#if MACOSX_COREAUDIO
static int static int
prepare_audiounit(_THIS, const char *devname, int iscapture, prepare_device(_THIS, void *handle, int iscapture)
{
AudioDeviceID devid = (AudioDeviceID) ((size_t) handle);
OSStatus result = noErr;
UInt32 size = 0;
UInt32 alive = 0;
pid_t pid = 0;
AudioObjectPropertyAddress addr = {
0,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
if (handle == NULL) {
size = sizeof (AudioDeviceID);
addr.mSelector =
((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
kAudioHardwarePropertyDefaultOutputDevice);
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
0, NULL, &size, &devid);
CHECK_RESULT("AudioHardwareGetProperty (default device)");
}
addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
kAudioDevicePropertyScopeOutput;
size = sizeof (alive);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
CHECK_RESULT
("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
if (!alive) {
SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
return 0;
}
addr.mSelector = kAudioDevicePropertyHogMode;
size = sizeof (pid);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid);
/* some devices don't support this property, so errors are fine here. */
if ((result == noErr) && (pid != -1)) {
SDL_SetError("CoreAudio: requested device is being hogged.");
return 0;
}
this->hidden->deviceID = devid;
return 1;
}
#endif
static int
prepare_audiounit(_THIS, void *handle, int iscapture,
const AudioStreamBasicDescription * strdesc) const AudioStreamBasicDescription * strdesc)
{ {
OSStatus result = noErr; OSStatus result = noErr;
@ -534,8 +496,7 @@ prepare_audiounit(_THIS, const char *devname, int iscapture,
kAudioUnitScope_Input); kAudioUnitScope_Input);
#if MACOSX_COREAUDIO #if MACOSX_COREAUDIO
if (!find_device_by_name(this, devname, iscapture)) { if (!prepare_device(this, handle, iscapture)) {
SDL_SetError("Couldn't find requested CoreAudio device");
return 0; return 0;
} }
#endif #endif
@ -623,7 +584,7 @@ prepare_audiounit(_THIS, const char *devname, int iscapture,
static int static int
COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
AudioStreamBasicDescription strdesc; AudioStreamBasicDescription strdesc;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
@ -682,7 +643,7 @@ COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
strdesc.mBytesPerPacket = strdesc.mBytesPerPacket =
strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
if (!prepare_audiounit(this, devname, iscapture, &strdesc)) { if (!prepare_audiounit(this, handle, iscapture, &strdesc)) {
COREAUDIO_CloseDevice(this); COREAUDIO_CloseDevice(this);
return -1; /* prepare_audiounit() will call SDL_SetError()... */ return -1; /* prepare_audiounit() will call SDL_SetError()... */
} }

View File

@ -144,15 +144,22 @@ SetDSerror(const char *function, int code)
return SDL_SetError("%s", errbuf); return SDL_SetError("%s", errbuf);
} }
static void
DSOUND_FreeDeviceHandle(void *handle)
{
SDL_free(handle);
}
static BOOL CALLBACK static BOOL CALLBACK
FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data) FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
{ {
SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data; const int iscapture = (int) ((size_t) data);
if (guid != NULL) { /* skip default device */ if (guid != NULL) { /* skip default device */
char *str = WIN_StringToUTF8(desc); char *str = WIN_StringToUTF8(desc);
if (str != NULL) { if (str != NULL) {
addfn(str); LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
SDL_memcpy(cpyguid, guid, sizeof (GUID));
SDL_AddAudioDevice(iscapture, str, cpyguid);
SDL_free(str); /* addfn() makes a copy of this string. */ SDL_free(str); /* addfn() makes a copy of this string. */
} }
} }
@ -160,13 +167,10 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
} }
static void static void
DSOUND_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) DSOUND_DetectDevices(void)
{ {
if (iscapture) { pDirectSoundCaptureEnumerateW(FindAllDevs, (void *) ((size_t) 1));
pDirectSoundCaptureEnumerateW(FindAllDevs, addfn); pDirectSoundEnumerateW(FindAllDevs, (void *) ((size_t) 0));
} else {
pDirectSoundEnumerateW(FindAllDevs, addfn);
}
} }
@ -419,53 +423,14 @@ CreateSecondary(_THIS, HWND focus)
return (numchunks); return (numchunks);
} }
typedef struct FindDevGUIDData
{
const char *devname;
GUID guid;
int found;
} FindDevGUIDData;
static BOOL CALLBACK
FindDevGUID(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID _data)
{
if (guid != NULL) { /* skip the default device. */
FindDevGUIDData *data = (FindDevGUIDData *) _data;
char *str = WIN_StringToUTF8(desc);
const int match = (SDL_strcmp(str, data->devname) == 0);
SDL_free(str);
if (match) {
data->found = 1;
SDL_memcpy(&data->guid, guid, sizeof (data->guid));
return FALSE; /* found it! stop enumerating. */
}
}
return TRUE; /* keep enumerating. */
}
static int static int
DSOUND_OpenDevice(_THIS, const char *devname, int iscapture) DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
HRESULT result; HRESULT result;
SDL_bool valid_format = SDL_FALSE; SDL_bool valid_format = SDL_FALSE;
SDL_bool tried_format = SDL_FALSE; SDL_bool tried_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
FindDevGUIDData devguid; LPGUID guid = (LPGUID) handle;
LPGUID guid = NULL;
if (devname != NULL) {
devguid.found = 0;
devguid.devname = devname;
if (iscapture)
pDirectSoundCaptureEnumerateW(FindDevGUID, &devguid);
else
pDirectSoundEnumerateW(FindDevGUID, &devguid);
if (!devguid.found) {
return SDL_SetError("DirectSound: Requested device not found");
}
guid = &devguid.guid;
}
/* Initialize all variables that we clean on shutdown */ /* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *) this->hidden = (struct SDL_PrivateAudioData *)
@ -536,6 +501,8 @@ DSOUND_Init(SDL_AudioDriverImpl * impl)
impl->WaitDone = DSOUND_WaitDone; impl->WaitDone = DSOUND_WaitDone;
impl->GetDeviceBuf = DSOUND_GetDeviceBuf; impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
impl->CloseDevice = DSOUND_CloseDevice; impl->CloseDevice = DSOUND_CloseDevice;
impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
impl->Deinitialize = DSOUND_Deinitialize; impl->Deinitialize = DSOUND_Deinitialize;
return 1; /* this audio target is available. */ return 1; /* this audio target is available. */

View File

@ -71,7 +71,7 @@ DISKAUD_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if (written != this->hidden->mixlen) { if (written != this->hidden->mixlen) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written); fprintf(stderr, "Wrote %d bytes of audio data\n", written);
@ -100,7 +100,7 @@ DISKAUD_CloseDevice(_THIS)
} }
static int static int
DISKAUD_OpenDevice(_THIS, const char *devname, int iscapture) DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
const char *envr = SDL_getenv(DISKENVR_WRITEDELAY); const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
const char *fname = DISKAUD_GetOutputFilename(devname); const char *fname = DISKAUD_GetOutputFilename(devname);
@ -151,6 +151,8 @@ DISKAUD_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = DISKAUD_GetDeviceBuf; impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
impl->CloseDevice = DISKAUD_CloseDevice; impl->CloseDevice = DISKAUD_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */ return 1; /* this audio target is available. */
} }

View File

@ -51,9 +51,9 @@
static void static void
DSP_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) DSP_DetectDevices(void)
{ {
SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn); SDL_EnumUnixAudioDevices(0, NULL);
} }
@ -74,7 +74,7 @@ DSP_CloseDevice(_THIS)
static int static int
DSP_OpenDevice(_THIS, const char *devname, int iscapture) DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
int format; int format;
@ -270,7 +270,7 @@ DSP_PlayDevice(_THIS)
const int mixlen = this->hidden->mixlen; const int mixlen = this->hidden->mixlen;
if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) { if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
perror("Audio write"); perror("Audio write");
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
@ -293,6 +293,8 @@ DSP_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = DSP_GetDeviceBuf; impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice; impl->CloseDevice = DSP_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */ return 1; /* this audio target is available. */
} }

View File

@ -27,7 +27,7 @@
#include "SDL_dummyaudio.h" #include "SDL_dummyaudio.h"
static int static int
DUMMYAUD_OpenDevice(_THIS, const char *devname, int iscapture) DUMMYAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
return 0; /* always succeeds. */ return 0; /* always succeeds. */
} }

View File

@ -151,7 +151,7 @@ Emscripten_CloseDevice(_THIS)
} }
static int static int
Emscripten_OpenDevice(_THIS, const char *devname, int iscapture) Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
SDL_bool valid_format = SDL_FALSE; SDL_bool valid_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);

View File

@ -129,7 +129,7 @@ ESD_WaitDevice(_THIS)
/* Check every 10 loops */ /* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) { if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) { if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
} }
} }
@ -161,7 +161,7 @@ ESD_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if (written < 0) { if (written < 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
} }
@ -215,7 +215,7 @@ get_progname(void)
static int static int
ESD_OpenDevice(_THIS, const char *devname, int iscapture) ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
esd_format_t format = (ESD_STREAM | ESD_PLAY); esd_format_t format = (ESD_STREAM | ESD_PLAY);
SDL_AudioFormat test_format = 0; SDL_AudioFormat test_format = 0;

View File

@ -143,7 +143,7 @@ SDL_FS_PlayDevice(_THIS)
this->hidden->mixsamples); this->hidden->mixsamples);
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if (ret) { if (ret) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen); fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
@ -186,7 +186,7 @@ SDL_FS_CloseDevice(_THIS)
static int static int
SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture) SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
int bytes; int bytes;
SDL_AudioFormat test_format = 0, format = 0; SDL_AudioFormat test_format = 0, format = 0;

View File

@ -111,7 +111,7 @@ UnmaskSignals(sigset_t * omask)
static int static int
HAIKUAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
int valid_datatype = 0; int valid_datatype = 0;
media_raw_audio_format format; media_raw_audio_format format;

View File

@ -43,7 +43,7 @@
#define SAMPLE_FRAME_COUNT 4096 #define SAMPLE_FRAME_COUNT 4096
/* Audio driver functions */ /* Audio driver functions */
static int NACLAUD_OpenDevice(_THIS, const char *devname, int iscapture); static int NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture);
static void NACLAUD_CloseDevice(_THIS); static void NACLAUD_CloseDevice(_THIS);
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data); static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data);
@ -85,7 +85,7 @@ static void NACLAUD_CloseDevice(SDL_AudioDevice *device) {
} }
static int static int
NACLAUD_OpenDevice(_THIS, const char *devname, int iscapture) { NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
PP_Instance instance = PSGetInstanceId(); PP_Instance instance = PSGetInstanceId();
const PPB_Audio *ppb_audio = PSInterfaceAudio(); const PPB_Audio *ppb_audio = PSInterfaceAudio();
const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig(); const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
@ -130,9 +130,7 @@ NACLAUD_Init(SDL_AudioDriverImpl * impl)
/* Set the function pointers */ /* Set the function pointers */
impl->OpenDevice = NACLAUD_OpenDevice; impl->OpenDevice = NACLAUD_OpenDevice;
impl->CloseDevice = NACLAUD_CloseDevice; impl->CloseDevice = NACLAUD_CloseDevice;
impl->HasCaptureSupport = 0;
impl->OnlyHasDefaultOutputDevice = 1; impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultInputDevice = 1;
impl->ProvidesOwnCallbackThread = 1; impl->ProvidesOwnCallbackThread = 1;
/* /*
* impl->WaitDevice = NACLAUD_WaitDevice; * impl->WaitDevice = NACLAUD_WaitDevice;

View File

@ -276,7 +276,7 @@ find_device(_THIS, int nch)
} }
static int static int
NAS_OpenDevice(_THIS, const char *devname, int iscapture) NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
AuElement elms[3]; AuElement elms[3];
int buffer_size; int buffer_size;

View File

@ -176,7 +176,7 @@ PAUDIO_WaitDevice(_THIS)
* the user know what happened. * the user know what happened.
*/ */
fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message); fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
/* Don't try to close - may hang */ /* Don't try to close - may hang */
this->hidden->audio_fd = -1; this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
@ -212,7 +212,7 @@ PAUDIO_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if (written < 0) { if (written < 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written); fprintf(stderr, "Wrote %d bytes of audio data\n", written);
@ -241,7 +241,7 @@ PAUDIO_CloseDevice(_THIS)
} }
static int static int
PAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
const char *workaround = SDL_getenv("SDL_DSP_NOSELECT"); const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
char audiodev[1024]; char audiodev[1024];

View File

@ -43,7 +43,7 @@
#define PSPAUD_DRIVER_NAME "psp" #define PSPAUD_DRIVER_NAME "psp"
static int static int
PSPAUD_OpenDevice(_THIS, const char *devname, int iscapture) PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
int format, mixlen, i; int format, mixlen, i;
this->hidden = (struct SDL_PrivateAudioData *) this->hidden = (struct SDL_PrivateAudioData *)

View File

@ -302,7 +302,7 @@ PULSEAUDIO_WaitDevice(_THIS)
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
return; return;
} }
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) { if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) {
@ -318,7 +318,7 @@ PULSEAUDIO_PlayDevice(_THIS)
struct SDL_PrivateAudioData *h = this->hidden; struct SDL_PrivateAudioData *h = this->hidden;
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL,
PA_SEEK_RELATIVE) < 0) { PA_SEEK_RELATIVE) < 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
} }
@ -378,7 +378,7 @@ PULSEAUDIO_CloseDevice(_THIS)
} }
static int static int
PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
struct SDL_PrivateAudioData *h = NULL; struct SDL_PrivateAudioData *h = NULL;
Uint16 test_format = 0; Uint16 test_format = 0;

View File

@ -19,6 +19,15 @@
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
/*
* !!! FIXME: streamline this a little by removing all the
* !!! FIXME: if (capture) {} else {} sections that are identical
* !!! FIXME: except for one flag.
*/
/* !!! FIXME: can this target support hotplugging? */
/* !!! FIXME: ...does SDL2 even support QNX? */
#include "../../SDL_internal.h" #include "../../SDL_internal.h"
#if SDL_AUDIO_DRIVER_QSA #if SDL_AUDIO_DRIVER_QSA
@ -300,7 +309,7 @@ QSA_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if (towrite != 0) { if (towrite != 0) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
} }
@ -337,8 +346,9 @@ QSA_CloseDevice(_THIS)
} }
static int static int
QSA_OpenDevice(_THIS, const char *devname, int iscapture) QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
const QSA_Device *device = (const QSA_Device *) handle;
int status = 0; int status = 0;
int format = 0; int format = 0;
SDL_AudioFormat test_format = 0; SDL_AudioFormat test_format = 0;
@ -363,80 +373,19 @@ QSA_OpenDevice(_THIS, const char *devname, int iscapture)
/* Initialize channel direction: capture or playback */ /* Initialize channel direction: capture or playback */
this->hidden->iscapture = iscapture; this->hidden->iscapture = iscapture;
/* Find deviceid and cardid by device name for playback */ if (device != NULL) {
if ((!this->hidden->iscapture) && (devname != NULL)) {
uint32_t device;
int32_t status;
/* Search in the playback devices */
device = 0;
do {
status = SDL_strcmp(qsa_playback_device[device].name, devname);
if (status == 0) {
/* Found requested device */
this->hidden->deviceno = qsa_playback_device[device].deviceno;
this->hidden->cardno = qsa_playback_device[device].cardno;
break;
}
device++;
if (device >= qsa_playback_devices) {
QSA_CloseDevice(this);
return SDL_SetError("No such playback device");
}
} while (1);
}
/* Find deviceid and cardid by device name for capture */
if ((this->hidden->iscapture) && (devname != NULL)) {
/* Search in the capture devices */
uint32_t device;
int32_t status;
/* Searching in the playback devices */
device = 0;
do {
status = SDL_strcmp(qsa_capture_device[device].name, devname);
if (status == 0) {
/* Found requested device */
this->hidden->deviceno = qsa_capture_device[device].deviceno;
this->hidden->cardno = qsa_capture_device[device].cardno;
break;
}
device++;
if (device >= qsa_capture_devices) {
QSA_CloseDevice(this);
return SDL_SetError("No such capture device");
}
} while (1);
}
/* Check if SDL requested default audio device */
if (devname == NULL) {
/* Open system default audio device */
if (!this->hidden->iscapture) {
status = snd_pcm_open_preferred(&this->hidden->audio_handle,
&this->hidden->cardno,
&this->hidden->deviceno,
SND_PCM_OPEN_PLAYBACK);
} else {
status = snd_pcm_open_preferred(&this->hidden->audio_handle,
&this->hidden->cardno,
&this->hidden->deviceno,
SND_PCM_OPEN_CAPTURE);
}
} else {
/* Open requested audio device */ /* Open requested audio device */
if (!this->hidden->iscapture) { this->hidden->deviceno = device->deviceno;
status = this->hidden->cardno = device->cardno;
snd_pcm_open(&this->hidden->audio_handle, status = snd_pcm_open(&this->hidden->audio_handle,
this->hidden->cardno, this->hidden->deviceno, device->cardno, device->deviceno,
SND_PCM_OPEN_PLAYBACK); iscapture ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE);
} else { } else {
status = /* Open system default audio device */
snd_pcm_open(&this->hidden->audio_handle, status = snd_pcm_open_preferred(&this->hidden->audio_handle,
this->hidden->cardno, this->hidden->deviceno, &this->hidden->cardno,
SND_PCM_OPEN_CAPTURE); &this->hidden->deviceno,
} iscapture ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE);
} }
/* Check if requested device is opened */ /* Check if requested device is opened */
@ -638,7 +587,7 @@ QSA_OpenDevice(_THIS, const char *devname, int iscapture)
} }
static void static void
QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) QSA_DetectDevices(void)
{ {
uint32_t it; uint32_t it;
uint32_t cards; uint32_t cards;
@ -656,8 +605,9 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
return; return;
} }
/* !!! FIXME: code duplication */
/* Find requested devices by type */ /* Find requested devices by type */
if (!iscapture) { { /* output devices */
/* Playback devices enumeration requested */ /* Playback devices enumeration requested */
for (it = 0; it < cards; it++) { for (it = 0; it < cards; it++) {
devices = 0; devices = 0;
@ -688,7 +638,7 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
devices; devices;
status = snd_pcm_close(handle); status = snd_pcm_close(handle);
if (status == EOK) { if (status == EOK) {
addfn(qsa_playback_device[qsa_playback_devices].name); SDL_AddAudioDevice(SDL_FALSE, qsa_playback_device[qsa_playback_devices].name, &qsa_playback_device[qsa_playback_devices]);
qsa_playback_devices++; qsa_playback_devices++;
} }
} else { } else {
@ -713,7 +663,9 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
break; break;
} }
} }
} else { }
{ /* capture devices */
/* Capture devices enumeration requested */ /* Capture devices enumeration requested */
for (it = 0; it < cards; it++) { for (it = 0; it < cards; it++) {
devices = 0; devices = 0;
@ -744,7 +696,7 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
devices; devices;
status = snd_pcm_close(handle); status = snd_pcm_close(handle);
if (status == EOK) { if (status == EOK) {
addfn(qsa_capture_device[qsa_capture_devices].name); SDL_AddAudioDevice(SDL_TRUE, qsa_capture_device[qsa_capture_devices].name, &qsa_capture_device[qsa_capture_devices]);
qsa_capture_devices++; qsa_capture_devices++;
} }
} else { } else {

View File

@ -158,7 +158,7 @@ SNDIO_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if ( written == 0 ) { if ( written == 0 ) {
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written); fprintf(stderr, "Wrote %d bytes of audio data\n", written);
@ -193,7 +193,7 @@ SNDIO_CloseDevice(_THIS)
} }
static int static int
SNDIO_OpenDevice(_THIS, const char *devname, int iscapture) SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
struct sio_par par; struct sio_par par;

View File

@ -56,9 +56,9 @@ static Uint8 snd2au(int sample);
/* Audio driver bootstrap functions */ /* Audio driver bootstrap functions */
static void static void
SUNAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) SUNAUDIO_DetectDevices(void)
{ {
SDL_EnumUnixAudioDevices(iscapture, 1, (int (*)(int fd)) NULL, addfn); SDL_EnumUnixAudioDevices(1, (int (*)(int)) NULL);
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
@ -158,7 +158,7 @@ SUNAUDIO_PlayDevice(_THIS)
if (write(this->hidden->audio_fd, this->hidden->ulaw_buf, if (write(this->hidden->audio_fd, this->hidden->ulaw_buf,
this->hidden->fragsize) < 0) { this->hidden->fragsize) < 0) {
/* Assume fatal error, for now */ /* Assume fatal error, for now */
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
this->hidden->written += this->hidden->fragsize; this->hidden->written += this->hidden->fragsize;
} else { } else {
@ -168,7 +168,7 @@ SUNAUDIO_PlayDevice(_THIS)
if (write(this->hidden->audio_fd, this->hidden->mixbuf, if (write(this->hidden->audio_fd, this->hidden->mixbuf,
this->spec.size) < 0) { this->spec.size) < 0) {
/* Assume fatal error, for now */ /* Assume fatal error, for now */
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
this->hidden->written += this->hidden->fragsize; this->hidden->written += this->hidden->fragsize;
} }
@ -198,7 +198,7 @@ SUNAUDIO_CloseDevice(_THIS)
} }
static int static int
SUNAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0; SDL_AudioFormat format = 0;
@ -414,6 +414,8 @@ SUNAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf; impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf;
impl->CloseDevice = SUNAUDIO_CloseDevice; impl->CloseDevice = SUNAUDIO_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */ return 1; /* this audio target is available. */
} }

View File

@ -36,8 +36,10 @@
#define WAVE_FORMAT_IEEE_FLOAT 0x0003 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif #endif
#define DETECT_DEV_IMPL(typ, capstyp) \ #define DETECT_DEV_IMPL(iscap, typ, capstyp) \
static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \ static void DetectWave##typ##Devs(void) { \
const UINT iscapture = iscap ? 1 : 0; \
UINT devcount = wave##typ##GetNumDevs(); \
const UINT devcount = wave##typ##GetNumDevs(); \ const UINT devcount = wave##typ##GetNumDevs(); \
capstyp caps; \ capstyp caps; \
UINT i; \ UINT i; \
@ -45,24 +47,21 @@ static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \
if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \ if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
char *name = WIN_StringToUTF8(caps.szPname); \ char *name = WIN_StringToUTF8(caps.szPname); \
if (name != NULL) { \ if (name != NULL) { \
addfn(name); \ SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i|(iscap<<31))); \
SDL_free(name); \ SDL_free(name); \
} \ } \
} \ } \
} \ } \
} }
DETECT_DEV_IMPL(Out, WAVEOUTCAPS) DETECT_DEV_IMPL(SDL_FALSE, Out, WAVEOUTCAPS)
DETECT_DEV_IMPL(In, WAVEINCAPS) DETECT_DEV_IMPL(SDL_TRUE, In, WAVEINCAPS)
static void static void
WINMM_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) WINMM_DetectDevices()
{ {
if (iscapture) { DetectWaveInDevs();
DetectWaveInDevs(addfn); DetectWaveOutDevs();
} else {
DetectWaveOutDevs(addfn);
}
} }
static void CALLBACK static void CALLBACK
@ -220,7 +219,7 @@ PrepWaveFormat(_THIS, UINT devId, WAVEFORMATEX *pfmt, const int iscapture)
} }
static int static int
WINMM_OpenDevice(_THIS, const char *devname, int iscapture) WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0; int valid_datatype = 0;
@ -230,37 +229,13 @@ WINMM_OpenDevice(_THIS, const char *devname, int iscapture)
char *utf8 = NULL; char *utf8 = NULL;
UINT i; UINT i;
if (devname != NULL) { /* specific device requested? */ if (handle != NULL) { /* specific device requested? */
const size_t val = (size_t) handle;
devId = (UINT) val;
if (iscapture) { if (iscapture) {
const UINT devcount = waveInGetNumDevs(); /* we use the top bit to make value unique vs output indices. */
WAVEINCAPS caps; SDL_assert((devId & (1<<31)) != 0);
for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) { devId &= ~(1<<31);
result = waveInGetDevCaps(i, &caps, sizeof (caps));
if (result != MMSYSERR_NOERROR)
continue;
else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
continue;
else if (SDL_strcmp(devname, utf8) == 0)
devId = i;
SDL_free(utf8);
}
} else {
const UINT devcount = waveOutGetNumDevs();
WAVEOUTCAPS caps;
for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) {
result = waveOutGetDevCaps(i, &caps, sizeof (caps));
if (result != MMSYSERR_NOERROR)
continue;
else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL)
continue;
else if (SDL_strcmp(devname, utf8) == 0)
devId = i;
SDL_free(utf8);
}
}
if (devId == WAVE_MAPPER) {
return SDL_SetError("Requested device not found");
} }
} }

View File

@ -126,16 +126,13 @@ struct SDL_PrivateAudioData
static void static void
XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) XAUDIO2_DetectDevices(void)
{ {
IXAudio2 *ixa2 = NULL; IXAudio2 *ixa2 = NULL;
UINT32 devcount = 0; UINT32 devcount = 0;
UINT32 i = 0; UINT32 i = 0;
if (iscapture) { if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
SDL_SetError("XAudio2: capture devices unsupported.");
return;
} else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
SDL_SetError("XAudio2: XAudio2Create() failed at detection."); SDL_SetError("XAudio2: XAudio2Create() failed at detection.");
return; return;
} else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
@ -149,8 +146,8 @@ XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
char *str = WIN_StringToUTF8(details.DisplayName); char *str = WIN_StringToUTF8(details.DisplayName);
if (str != NULL) { if (str != NULL) {
addfn(str); SDL_AddAudioDevice(SDL_FALSE, str, (void *) ((size_t) i));
SDL_free(str); /* addfn() made a copy of the string. */ SDL_free(str); /* SDL_AddAudioDevice made a copy of the string. */
} }
} }
} }
@ -169,8 +166,8 @@ VoiceCBOnBufferEnd(THIS_ void *data)
static void STDMETHODCALLTYPE static void STDMETHODCALLTYPE
VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error) VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error)
{ {
/* !!! FIXME: attempt to recover, or mark device disconnected. */ SDL_AudioDevice *this = (SDL_AudioDevice *) data;
SDL_assert(0 && "write me!"); SDL_OpenedAudioDeviceDisconnected(this);
} }
/* no-op callbacks... */ /* no-op callbacks... */
@ -221,7 +218,7 @@ XAUDIO2_PlayDevice(_THIS)
if (result != S_OK) { /* uhoh, panic! */ if (result != S_OK) { /* uhoh, panic! */
IXAudio2SourceVoice_FlushSourceBuffers(source); IXAudio2SourceVoice_FlushSourceBuffers(source);
SDL_AudioDeviceDisconnected(SDL_FALSE, this); SDL_OpenedAudioDeviceDisconnected(this);
} }
} }
@ -289,7 +286,7 @@ XAUDIO2_CloseDevice(_THIS)
} }
static int static int
XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{ {
HRESULT result = S_OK; HRESULT result = S_OK;
WAVEFORMATEX waveformat; WAVEFORMATEX waveformat;
@ -300,7 +297,7 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
#if defined(SDL_XAUDIO2_WIN8) #if defined(SDL_XAUDIO2_WIN8)
LPCWSTR devId = NULL; LPCWSTR devId = NULL;
#else #else
UINT32 devId = 0; /* 0 == system default device. */ UINT32 devId = (UINT32) ((size_t) handle); /* 0 == system default device. */
#endif #endif
static IXAudio2VoiceCallbackVtbl callbacks_vtable = { static IXAudio2VoiceCallbackVtbl callbacks_vtable = {
@ -315,9 +312,7 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
static IXAudio2VoiceCallback callbacks = { &callbacks_vtable }; static IXAudio2VoiceCallback callbacks = { &callbacks_vtable };
if (iscapture) { if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
return SDL_SetError("XAudio2: capture devices unsupported.");
} else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
return SDL_SetError("XAudio2: XAudio2Create() failed at open."); return SDL_SetError("XAudio2: XAudio2Create() failed at open.");
} }
@ -332,37 +327,6 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
ixa2->SetDebugConfiguration(&debugConfig); ixa2->SetDebugConfiguration(&debugConfig);
*/ */
#if ! defined(__WINRT__)
if (devname != NULL) {
UINT32 devcount = 0;
UINT32 i = 0;
if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
IXAudio2_Release(ixa2);
return SDL_SetError("XAudio2: IXAudio2_GetDeviceCount() failed.");
}
for (i = 0; i < devcount; i++) {
XAUDIO2_DEVICE_DETAILS details;
if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
char *str = WIN_StringToUTF8(details.DisplayName);
if (str != NULL) {
const int match = (SDL_strcmp(str, devname) == 0);
SDL_free(str);
if (match) {
devId = i;
break;
}
}
}
}
if (i == devcount) {
IXAudio2_Release(ixa2);
return SDL_SetError("XAudio2: Requested device not found.");
}
}
#endif
/* Initialize all variables that we clean on shutdown */ /* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *) this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden)); SDL_malloc((sizeof *this->hidden));
@ -529,6 +493,16 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl)
impl->CloseDevice = XAUDIO2_CloseDevice; impl->CloseDevice = XAUDIO2_CloseDevice;
impl->Deinitialize = XAUDIO2_Deinitialize; impl->Deinitialize = XAUDIO2_Deinitialize;
/* !!! FIXME: We can apparently use a C++ interface on Windows 8
* !!! FIXME: (Windows::Devices::Enumeration::DeviceInformation) for device
* !!! FIXME: detection, but it's not implemented here yet.
* !!! FIXME: see http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx
* !!! FIXME: for now, force the default device.
*/
#if defined(SDL_XAUDIO2_WIN8) || defined(__WINRT__)
impl->OnlyHasDefaultOutputDevice = 1;
#endif
return 1; /* this audio target is available. */ return 1; /* this audio target is available. */
#endif #endif
} }