Initial work on audio device hotplug support.

This fills in the core pieces and fully implements it for Mac OS X.

Most other platforms, at the moment, will report a disconnected device if
it fails to write audio, but don't notice if the system's device list changed
at all.
This commit is contained in:
Ryan C. Gordon
2015-03-16 02:11:39 -04:00
parent 338bf5d297
commit 0e02ce0856
19 changed files with 658 additions and 132 deletions

View File

@@ -333,6 +333,144 @@ SDL_StreamDeinit(SDL_AudioStreamer * stream)
}
#endif
/* device hotplug support... */
/* this function expects its caller to hold current_audio.detection_lock */
static int
add_audio_device(const char *_name, char ***_devices, int *_devCount)
{
char *name = SDL_strdup(_name);
int retval = -1;
if (name != NULL) {
char **devices = *_devices;
int devCount = *_devCount;
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;
}
}
return retval;
}
static int
add_capture_device(const char *name)
{
/* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/
return add_audio_device(name, &current_audio.inputDevices, &current_audio.inputDeviceCount);
}
static int
add_output_device(const char *name)
{
return add_audio_device(name, &current_audio.outputDevices, &current_audio.outputDeviceCount);
}
static void
free_device_list(char ***devices, int *devCount)
{
int i = *devCount;
if ((i > 0) && (*devices != NULL)) {
while (i--) {
SDL_free((*devices)[i]);
}
}
SDL_free(*devices);
*devices = NULL;
*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. */
void
SDL_AudioDeviceConnected(const int iscapture, const char *name)
{
int device_index = -1;
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) {
/* Post the event, if desired */
if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) {
SDL_Event event;
event.adevice.type = SDL_AUDIODEVICEADDED;
event.adevice.which = device_index;
event.adevice.iscapture = iscapture;
SDL_PushEvent(&event);
}
}
}
/* The audio backends call this when a device is unplugged. */
void
SDL_AudioDeviceDisconnected(const int iscapture, SDL_AudioDevice *device)
{
/* device==NULL means an unopened device was lost; do the redetect only. */
if (device != NULL) {
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
app still needs to close the device to free resources. */
current_audio.impl.LockDevice(device);
device->enabled = 0;
current_audio.impl.UnlockDevice(device);
/* Post the event, if desired */
if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) {
SDL_Event event;
event.adevice.type = SDL_AUDIODEVICEREMOVED;
event.adevice.which = device->id;
event.adevice.iscapture = device->iscapture ? 1 : 0;
SDL_PushEvent(&event);
}
}
/* we don't really know which name (if any) was associated with this
device in the device list, so drop the entire list and rebuild it.
(we should probably change the API in 2.1 to make this more clear?) */
if (iscapture) {
current_audio.need_capture_device_redetect = SDL_TRUE;
} else {
current_audio.need_output_device_redetect = SDL_TRUE;
}
}
/* buffer queueing support... */
@@ -690,6 +828,13 @@ SDL_RunAudio(void *devicep)
/* !!! FIXME: this should be LockDevice. */
SDL_LockMutex(device->mixer_lock);
/* Check again, in case device was removed while a lock was held. */
if (!device->enabled) {
SDL_UnlockMutex(device->mixer_lock);
break;
}
if (device->paused) {
SDL_memset(stream, silence, stream_len);
} else {
@@ -821,8 +966,34 @@ SDL_AudioInit(const char *driver_name)
return -1; /* No driver was available, so fail. */
}
current_audio.detection_lock = SDL_CreateMutex();
finalize_audio_entry_points();
/* Make sure we have a list of devices available at startup. */
perform_full_device_redetect(SDL_TRUE);
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;
}
@@ -835,53 +1006,6 @@ SDL_GetCurrentAudioDriver()
return current_audio.name;
}
static void
free_device_list(char ***devices, int *devCount)
{
int i = *devCount;
if ((i > 0) && (*devices != NULL)) {
while (i--) {
SDL_free((*devices)[i]);
}
}
SDL_free(*devices);
*devices = NULL;
*devCount = 0;
}
static
void SDL_AddCaptureAudioDevice(const char *_name)
{
char *name = NULL;
void *ptr = SDL_realloc(current_audio.inputDevices,
(current_audio.inputDeviceCount+1) * sizeof(char*));
if (ptr == NULL) {
return; /* oh well. */
}
current_audio.inputDevices = (char **) ptr;
name = SDL_strdup(_name); /* if this returns NULL, that's okay. */
current_audio.inputDevices[current_audio.inputDeviceCount++] = name;
}
static
void SDL_AddOutputAudioDevice(const char *_name)
{
char *name = NULL;
void *ptr = SDL_realloc(current_audio.outputDevices,
(current_audio.outputDeviceCount+1) * sizeof(char*));
if (ptr == NULL) {
return; /* oh well. */
}
current_audio.outputDevices = (char **) ptr;
name = SDL_strdup(_name); /* if this returns NULL, that's okay. */
current_audio.outputDevices[current_audio.outputDeviceCount++] = name;
}
int
SDL_GetNumAudioDevices(int iscapture)
{
@@ -903,18 +1027,20 @@ SDL_GetNumAudioDevices(int iscapture)
return 1;
}
if (iscapture) {
free_device_list(&current_audio.inputDevices,
&current_audio.inputDeviceCount);
current_audio.impl.DetectDevices(iscapture, SDL_AddCaptureAudioDevice);
retval = current_audio.inputDeviceCount;
} else {
free_device_list(&current_audio.outputDevices,
&current_audio.outputDeviceCount);
current_audio.impl.DetectDevices(iscapture, SDL_AddOutputAudioDevice);
retval = current_audio.outputDeviceCount;
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;
SDL_UnlockMutex(current_audio.detection_lock);
return retval;
}
@@ -922,6 +1048,8 @@ SDL_GetNumAudioDevices(int iscapture)
const char *
SDL_GetAudioDeviceName(int index, int iscapture)
{
const char *retval = NULL;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
SDL_SetError("Audio subsystem is not initialized");
return NULL;
@@ -950,16 +1078,18 @@ SDL_GetAudioDeviceName(int index, int iscapture)
return DEFAULT_OUTPUT_DEVNAME;
}
if (iscapture) {
if (index >= current_audio.inputDeviceCount) {
goto no_such_device;
}
return current_audio.inputDevices[index];
} else {
if (index >= current_audio.outputDeviceCount) {
goto no_such_device;
}
return current_audio.outputDevices[index];
SDL_LockMutex(current_audio.detection_lock);
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:
@@ -1077,6 +1207,18 @@ open_audio_device(const char *devname, int iscapture,
return 0;
}
/* Find an available device ID... */
for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) {
if (open_devices[id] == NULL) {
break;
}
}
if (id == SDL_arraysize(open_devices)) {
SDL_SetError("Too many open audio devices");
return 0;
}
if (!obtained) {
obtained = &_obtained;
}
@@ -1135,6 +1277,7 @@ open_audio_device(const char *devname, int iscapture,
return 0;
}
SDL_zerop(device);
device->id = id + 1;
device->spec = *obtained;
device->enabled = 1;
device->paused = 1;
@@ -1150,12 +1293,6 @@ open_audio_device(const char *devname, int iscapture,
}
}
/* force a device detection if we haven't done one yet. */
if ( ((iscapture) && (current_audio.inputDevices == NULL)) ||
((!iscapture) && (current_audio.outputDevices == NULL)) ) {
SDL_GetNumAudioDevices(iscapture);
}
if (current_audio.impl.OpenDevice(device, devname, iscapture) < 0) {
close_audio_device(device);
return 0;
@@ -1247,25 +1384,14 @@ open_audio_device(const char *devname, int iscapture,
device->spec.userdata = device;
}
/* Find an available device ID and store the structure... */
for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) {
if (open_devices[id] == NULL) {
open_devices[id] = device;
break;
}
}
if (id == SDL_arraysize(open_devices)) {
SDL_SetError("Too many open audio devices");
close_audio_device(device);
return 0;
}
/* add it to our list of open devices. */
open_devices[id] = device;
/* Start the audio thread if necessary */
if (!current_audio.impl.ProvidesOwnCallbackThread) {
/* Start the audio thread */
char name[64];
SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) (id + 1));
SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id);
/* !!! FIXME: this is nasty. */
#if defined(__WIN32__) && !defined(HAVE_LIBC)
#undef SDL_CreateThread
@@ -1278,13 +1404,13 @@ open_audio_device(const char *devname, int iscapture,
device->thread = SDL_CreateThread(SDL_RunAudio, name, device);
#endif
if (device->thread == NULL) {
SDL_CloseAudioDevice(id + 1);
SDL_CloseAudioDevice(device->id);
SDL_SetError("Couldn't create audio thread");
return 0;
}
}
return id + 1;
return device->id;
}
@@ -1431,12 +1557,16 @@ SDL_AudioQuit(void)
/* Free the driver data */
current_audio.impl.Deinitialize();
free_device_list(&current_audio.outputDevices,
&current_audio.outputDeviceCount);
free_device_list(&current_audio.inputDevices,
&current_audio.inputDeviceCount);
SDL_memset(&current_audio, '\0', sizeof(current_audio));
SDL_memset(open_devices, '\0', sizeof(open_devices));
SDL_DestroyMutex(current_audio.detection_lock);
SDL_zero(current_audio);
SDL_zero(open_devices);
}
#define NUM_FORMATS 10

View File

@@ -31,7 +31,16 @@ typedef struct SDL_AudioDevice SDL_AudioDevice;
#define _THIS SDL_AudioDevice *_this
/* Used by audio targets during DetectDevices() */
typedef void (*SDL_AddAudioDevice)(const char *name);
typedef int (*SDL_AddAudioDevice)(const char *name);
/* 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 unplugged.
(device) can be NULL if an unopened device is lost. */
extern void SDL_AudioDeviceDisconnected(const int iscapture, SDL_AudioDevice *device);
/* This is the size of a packet when using SDL_QueueAudio(). We allocate
these as necessary and pool them, under the assumption that we'll
@@ -92,6 +101,12 @@ 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;
int outputDeviceCount;
@@ -114,6 +129,7 @@ struct SDL_AudioDevice
{
/* * * */
/* Data common to all devices */
SDL_AudioDeviceID id;
/* The current audio specification (shared with audio thread) */
SDL_AudioSpec spec;

View File

@@ -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));
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
return;
}
continue;

View File

@@ -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) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
}
}
@@ -179,7 +179,7 @@ ARTS_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);

View File

@@ -150,7 +150,7 @@ BSDAUDIO_WaitDevice(_THIS)
the user know what happened.
*/
fprintf(stderr, "SDL: %s\n", message);
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
/* Don't try to close - may hang */
this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO
@@ -195,7 +195,7 @@ BSDAUDIO_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);

View File

@@ -40,13 +40,50 @@ static void COREAUDIO_CloseDevice(_THIS);
}
#if MACOSX_COREAUDIO
typedef void (*addDevFn)(const char *name, AudioDeviceID devId, void *data);
static const AudioObjectPropertyAddress devlist_address = {
kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
typedef struct AudioDeviceList
{
AudioDeviceID devid;
SDL_bool alive;
struct AudioDeviceList *next;
} AudioDeviceList;
static AudioDeviceList *output_devs = NULL;
static AudioDeviceList *capture_devs = NULL;
static SDL_bool
add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
{
AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList));
if (item == NULL) {
return SDL_FALSE;
}
item->devid = devId;
item->alive = SDL_TRUE;
item->next = iscapture ? capture_devs : output_devs;
if (iscapture) {
capture_devs = item;
} else {
output_devs = item;
}
return SDL_TRUE;
}
static void
addToDevList(const char *name, AudioDeviceID devId, void *data)
addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
{
SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data;
addfn(name);
if (add_to_internal_dev_list(iscapture, devId)) {
addfn(name);
}
}
typedef struct
@@ -57,7 +94,7 @@ typedef struct
} FindDevIdData;
static void
findDevId(const char *name, AudioDeviceID devId, void *_data)
findDevId(const char *name, const int iscapture, AudioDeviceID devId, void *_data)
{
FindDevIdData *data = (FindDevIdData *) _data;
if (!data->found) {
@@ -77,14 +114,8 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
UInt32 i = 0;
UInt32 max = 0;
AudioObjectPropertyAddress addr = {
kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr,
0, NULL, &size);
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size);
if (result != kAudioHardwareNoError)
return;
@@ -92,8 +123,8 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
if (devs == NULL)
return;
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
0, NULL, &size, devs);
result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size, devs);
if (result != kAudioHardwareNoError)
return;
@@ -105,10 +136,17 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
kAudioDevicePropertyScopeOutput;
addr.mSelector = kAudioDevicePropertyStreamConfiguration;
const AudioObjectPropertyAddress nameaddr = {
kAudioObjectPropertyName,
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
if (result != noErr)
@@ -136,9 +174,9 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
if (!usable)
continue;
addr.mSelector = kAudioObjectPropertyName;
size = sizeof (CFStringRef);
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, &cfstr);
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
if (result != kAudioHardwareNoError)
continue;
@@ -169,18 +207,96 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
((iscapture) ? "capture" : "output"),
(int) *devCount, ptr, (int) dev);
#endif
addfn(ptr, dev, addfndata);
addfn(ptr, iscapture, dev, addfndata);
}
SDL_free(ptr); /* addfn() would have copied the string. */
}
}
static void
free_audio_device_list(AudioDeviceList **list)
{
AudioDeviceList *item = *list;
while (item) {
AudioDeviceList *next = item->next;
SDL_free(item);
item = next;
}
*list = NULL;
}
static void
COREAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
{
free_audio_device_list(iscapture ? &capture_devs : &output_devs);
build_device_list(iscapture, addToDevList, addfn);
}
static void
build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data)
{
AudioDeviceList **list = (AudioDeviceList **) data;
AudioDeviceList *item;
for (item = *list; item != NULL; item = item->next) {
if (item->devid == devId) {
item->alive = SDL_TRUE;
return;
}
}
add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
SDL_AudioDeviceConnected(iscapture, name);
}
static SDL_bool
reprocess_device_list(const int iscapture, AudioDeviceList **list)
{
SDL_bool was_disconnect = SDL_FALSE;
AudioDeviceList *item;
AudioDeviceList *prev = NULL;
for (item = *list; item != NULL; item = item->next) {
item->alive = SDL_FALSE;
}
build_device_list(iscapture, build_device_change_list, list);
/* free items in the list that aren't still alive. */
item = *list;
while (item != NULL) {
AudioDeviceList *next = item->next;
if (item->alive) {
prev = item;
} else {
was_disconnect = SDL_TRUE;
if (prev) {
prev->next = item->next;
} else {
*list = item->next;
}
SDL_free(item);
}
item = next;
}
return was_disconnect;
}
/* this is called when the system's list of available audio devices changes. */
static OSStatus
device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{
if (reprocess_device_list(SDL_TRUE, &capture_devs)) {
SDL_AudioDeviceDisconnected(SDL_TRUE, NULL);
}
if (reprocess_device_list(SDL_FALSE, &output_devs)) {
SDL_AudioDeviceDisconnected(SDL_FALSE, NULL);
}
return 0;
}
static int
find_device_by_name(_THIS, const char *devname, int iscapture)
{
@@ -317,11 +433,54 @@ inputCallback(void *inRefCon,
}
#if MACOSX_COREAUDIO
static const AudioObjectPropertyAddress alive_address =
{
kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
static OSStatus
device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) data;
SDL_bool dead = SDL_FALSE;
UInt32 isAlive = 1;
UInt32 size = sizeof (isAlive);
OSStatus error;
if (!this->enabled) {
return 0; /* already known to be dead. */
}
error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address,
0, NULL, &size, &isAlive);
if (error == kAudioHardwareBadDeviceError) {
dead = SDL_TRUE; /* device was unplugged. */
} else if ((error == kAudioHardwareNoError) && (!isAlive)) {
dead = SDL_TRUE; /* device died in some other way. */
}
if (dead) {
SDL_AudioDeviceDisconnected(this->iscapture, this);
}
return 0;
}
#endif
static void
COREAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
if (this->hidden->audioUnitOpened) {
#if MACOSX_COREAUDIO
/* Unregister our disconnect callback. */
AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
#endif
AURenderCallbackStruct callback;
const AudioUnitElement output_bus = 0;
const AudioUnitElement input_bus = 1;
@@ -355,7 +514,6 @@ COREAUDIO_CloseDevice(_THIS)
}
}
static int
prepare_audiounit(_THIS, const char *devname, int iscapture,
const AudioStreamBasicDescription * strdesc)
@@ -454,6 +612,11 @@ prepare_audiounit(_THIS, const char *devname, int iscapture,
result = AudioOutputUnitStart(this->hidden->audioUnit);
CHECK_RESULT("AudioOutputUnitStart");
#if MACOSX_COREAUDIO
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
#endif
/* We're running! */
return 1;
}
@@ -527,15 +690,27 @@ COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
return 0; /* good to go. */
}
static void
COREAUDIO_Deinitialize(void)
{
#if MACOSX_COREAUDIO
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
free_audio_device_list(&capture_devs);
free_audio_device_list(&output_devs);
#endif
}
static int
COREAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = COREAUDIO_OpenDevice;
impl->CloseDevice = COREAUDIO_CloseDevice;
impl->Deinitialize = COREAUDIO_Deinitialize;
#if MACOSX_COREAUDIO
impl->DetectDevices = COREAUDIO_DetectDevices;
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
#else
impl->OnlyHasDefaultOutputDevice = 1;

View File

@@ -71,7 +71,7 @@ DISKAUD_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */
if (written != this->hidden->mixlen) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);

View File

@@ -270,7 +270,7 @@ DSP_PlayDevice(_THIS)
const int mixlen = this->hidden->mixlen;
if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
perror("Audio write");
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);

View File

@@ -129,7 +129,7 @@ ESD_WaitDevice(_THIS)
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
}
}
@@ -161,7 +161,7 @@ ESD_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
}

View File

@@ -143,7 +143,7 @@ SDL_FS_PlayDevice(_THIS)
this->hidden->mixsamples);
/* If we couldn't write, assume fatal error for now */
if (ret) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);

View File

@@ -176,7 +176,7 @@ PAUDIO_WaitDevice(_THIS)
* the user know what happened.
*/
fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
/* Don't try to close - may hang */
this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO
@@ -212,7 +212,7 @@ PAUDIO_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);

View File

@@ -302,7 +302,7 @@ PULSEAUDIO_WaitDevice(_THIS)
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
return;
}
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) {
@@ -318,7 +318,7 @@ PULSEAUDIO_PlayDevice(_THIS)
struct SDL_PrivateAudioData *h = this->hidden;
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL,
PA_SEEK_RELATIVE) < 0) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
}

View File

@@ -300,7 +300,7 @@ QSA_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */
if (towrite != 0) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
}

View File

@@ -158,7 +158,7 @@ SNDIO_PlayDevice(_THIS)
/* If we couldn't write, assume fatal error for now */
if ( written == 0 ) {
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);

View File

@@ -158,7 +158,7 @@ SUNAUDIO_PlayDevice(_THIS)
if (write(this->hidden->audio_fd, this->hidden->ulaw_buf,
this->hidden->fragsize) < 0) {
/* Assume fatal error, for now */
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
this->hidden->written += this->hidden->fragsize;
} else {
@@ -168,7 +168,7 @@ SUNAUDIO_PlayDevice(_THIS)
if (write(this->hidden->audio_fd, this->hidden->mixbuf,
this->spec.size) < 0) {
/* Assume fatal error, for now */
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
this->hidden->written += this->hidden->fragsize;
}

View File

@@ -221,7 +221,7 @@ XAUDIO2_PlayDevice(_THIS)
if (result != S_OK) { /* uhoh, panic! */
IXAudio2SourceVoice_FlushSourceBuffers(source);
this->enabled = 0;
SDL_AudioDeviceDisconnected(SDL_FALSE, this);
}
}