mirror of https://github.com/encounter/SDL.git
Add SDL_GetAudioDeviceSpec.
This API is supported by pipewire, pulseaudio, coreaudio, wasapi, and disk.
This commit is contained in:
parent
00fabdde18
commit
67e8522d31
|
@ -359,6 +359,25 @@ extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
|
||||||
extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
|
extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
|
||||||
int iscapture);
|
int iscapture);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the audio format of a specific audio device.
|
||||||
|
* Must be a value between 0 and (number of audio devices-1).
|
||||||
|
* Only valid after a successfully initializing the audio subsystem.
|
||||||
|
* The values returned by this function reflect the latest call to
|
||||||
|
* SDL_GetNumAudioDevices(); recall that function to redetect available
|
||||||
|
* hardware.
|
||||||
|
*
|
||||||
|
* The spec will be filled with the sample rate, sample format, and channel
|
||||||
|
* count. All other values in the structure are filled with 0. When the
|
||||||
|
* supported struct members are 0, SDL was unable to get the property from the
|
||||||
|
* backend.
|
||||||
|
*
|
||||||
|
* \return 0 on success, nonzero on error
|
||||||
|
*/
|
||||||
|
extern DECLSPEC int SDLCALL SDL_GetAudioDeviceSpec(int index,
|
||||||
|
int iscapture,
|
||||||
|
SDL_AudioSpec *spec);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a specific audio device. Passing in a device name of NULL requests
|
* Open a specific audio device. Passing in a device name of NULL requests
|
||||||
|
|
|
@ -223,9 +223,9 @@ SDL_AudioDetectDevices_Default(void)
|
||||||
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
|
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
|
||||||
SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
|
SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
|
||||||
|
|
||||||
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
|
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *) ((size_t) 0x1));
|
||||||
if (current_audio.impl.HasCaptureSupport) {
|
if (current_audio.impl.HasCaptureSupport) {
|
||||||
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) ((size_t) 0x2));
|
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) ((size_t) 0x2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@ finish_audio_entry_points_init(void)
|
||||||
/* device hotplug support... */
|
/* device hotplug support... */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
|
add_audio_device(const char *name, SDL_AudioSpec *spec, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
SDL_AudioDeviceItem *item;
|
SDL_AudioDeviceItem *item;
|
||||||
|
@ -400,6 +400,11 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
|
||||||
|
|
||||||
item->dupenum = 0;
|
item->dupenum = 0;
|
||||||
item->name = item->original_name;
|
item->name = item->original_name;
|
||||||
|
if (spec != NULL) {
|
||||||
|
SDL_memcpy(&item->spec, spec, sizeof(SDL_AudioSpec));
|
||||||
|
} else {
|
||||||
|
SDL_zero(item->spec);
|
||||||
|
}
|
||||||
item->handle = handle;
|
item->handle = handle;
|
||||||
|
|
||||||
SDL_LockMutex(current_audio.detectionLock);
|
SDL_LockMutex(current_audio.detectionLock);
|
||||||
|
@ -437,16 +442,16 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_INLINE int
|
static SDL_INLINE int
|
||||||
add_capture_device(const char *name, void *handle)
|
add_capture_device(const char *name, SDL_AudioSpec *spec, void *handle)
|
||||||
{
|
{
|
||||||
SDL_assert(current_audio.impl.HasCaptureSupport);
|
SDL_assert(current_audio.impl.HasCaptureSupport);
|
||||||
return add_audio_device(name, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount);
|
return add_audio_device(name, spec, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_INLINE int
|
static SDL_INLINE int
|
||||||
add_output_device(const char *name, void *handle)
|
add_output_device(const char *name, SDL_AudioSpec *spec, void *handle)
|
||||||
{
|
{
|
||||||
return add_audio_device(name, handle, ¤t_audio.outputDevices, ¤t_audio.outputDeviceCount);
|
return add_audio_device(name, spec, handle, ¤t_audio.outputDevices, ¤t_audio.outputDeviceCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -472,9 +477,9 @@ free_device_list(SDL_AudioDeviceItem **devices, int *devCount)
|
||||||
|
|
||||||
/* 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_AddAudioDevice(const int iscapture, const char *name, void *handle)
|
SDL_AddAudioDevice(const int iscapture, const char *name, SDL_AudioSpec *spec, void *handle)
|
||||||
{
|
{
|
||||||
const int device_index = iscapture ? add_capture_device(name, handle) : add_output_device(name, handle);
|
const int device_index = iscapture ? add_capture_device(name, spec, handle) : add_output_device(name, spec, handle);
|
||||||
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) {
|
||||||
|
@ -1112,6 +1117,44 @@ SDL_GetAudioDeviceName(int index, int iscapture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
SDL_GetAudioDeviceSpec(int index, int iscapture, SDL_AudioSpec *spec)
|
||||||
|
{
|
||||||
|
if (spec == NULL) {
|
||||||
|
return SDL_InvalidParamError("spec");
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_zerop(spec);
|
||||||
|
|
||||||
|
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||||
|
return SDL_SetError("Audio subsystem is not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iscapture && !current_audio.impl.HasCaptureSupport) {
|
||||||
|
return SDL_SetError("No capture support");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
SDL_AudioDeviceItem *item;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
SDL_LockMutex(current_audio.detectionLock);
|
||||||
|
item = iscapture ? current_audio.inputDevices : current_audio.outputDevices;
|
||||||
|
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);
|
||||||
|
SDL_memcpy(spec, &item->spec, sizeof(SDL_AudioSpec));
|
||||||
|
}
|
||||||
|
SDL_UnlockMutex(current_audio.detectionLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
close_audio_device(SDL_AudioDevice * device)
|
close_audio_device(SDL_AudioDevice * device)
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,7 +59,13 @@ test_device(const int iscapture, const char *fname, int flags, int (*test) (int
|
||||||
static size_t dummyhandle = 0;
|
static size_t dummyhandle = 0;
|
||||||
dummyhandle++;
|
dummyhandle++;
|
||||||
SDL_assert(dummyhandle != 0);
|
SDL_assert(dummyhandle != 0);
|
||||||
SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle);
|
|
||||||
|
/* Note that spec is NULL; while we are opening the device
|
||||||
|
* endpoint here, the endpoint does not provide any mix format
|
||||||
|
* information, making this information inaccessible at
|
||||||
|
* enumeration time
|
||||||
|
*/
|
||||||
|
SDL_AddAudioDevice(iscapture, fname, NULL, (void *) dummyhandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ typedef struct SDL_AudioDevice SDL_AudioDevice;
|
||||||
/* Audio targets should call this as devices are added to the system (such as
|
/* Audio targets should call this as devices are added to the system (such as
|
||||||
a USB headset being plugged in), and should also be called for
|
a USB headset being plugged in), and should also be called for
|
||||||
for every device found during DetectDevices(). */
|
for every device found during DetectDevices(). */
|
||||||
extern void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle);
|
extern void SDL_AddAudioDevice(const int iscapture, const char *name, SDL_AudioSpec *spec, void *handle);
|
||||||
|
|
||||||
/* Audio targets should call this as devices are removed, so SDL can update
|
/* Audio targets should call this as devices are removed, so SDL can update
|
||||||
its list of available devices. */
|
its list of available devices. */
|
||||||
|
@ -99,6 +99,7 @@ typedef struct SDL_AudioDeviceItem
|
||||||
void *handle;
|
void *handle;
|
||||||
char *name;
|
char *name;
|
||||||
char *original_name;
|
char *original_name;
|
||||||
|
SDL_AudioSpec spec;
|
||||||
int dupenum;
|
int dupenum;
|
||||||
struct SDL_AudioDeviceItem *next;
|
struct SDL_AudioDeviceItem *next;
|
||||||
} SDL_AudioDeviceItem;
|
} SDL_AudioDeviceItem;
|
||||||
|
|
|
@ -765,7 +765,11 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AddAudioDevice(iscapture, desc, handle);
|
/* Note that spec is NULL, because we are required to open the device before
|
||||||
|
* acquiring the mix format, making this information inaccessible at
|
||||||
|
* enumeration time
|
||||||
|
*/
|
||||||
|
SDL_AddAudioDevice(iscapture, desc, NULL, handle);
|
||||||
if (hint)
|
if (hint)
|
||||||
free(desc);
|
free(desc);
|
||||||
dev->name = handle;
|
dev->name = handle;
|
||||||
|
|
|
@ -56,7 +56,7 @@ static const AudioObjectPropertyAddress devlist_address = {
|
||||||
kAudioObjectPropertyElementMaster
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
|
typedef void (*addDevFn)(const char *name, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data);
|
||||||
|
|
||||||
typedef struct AudioDeviceList
|
typedef struct AudioDeviceList
|
||||||
{
|
{
|
||||||
|
@ -88,10 +88,10 @@ 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, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data)
|
||||||
{
|
{
|
||||||
if (add_to_internal_dev_list(iscapture, devId)) {
|
if (add_to_internal_dev_list(iscapture, devId)) {
|
||||||
SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
|
SDL_AddAudioDevice(iscapture, name, spec, (void *) ((size_t) devId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,17 +126,23 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
|
||||||
AudioBufferList *buflist = NULL;
|
AudioBufferList *buflist = NULL;
|
||||||
int usable = 0;
|
int usable = 0;
|
||||||
CFIndex len = 0;
|
CFIndex len = 0;
|
||||||
|
double sampleRate = 0;
|
||||||
|
SDL_AudioSpec spec;
|
||||||
const AudioObjectPropertyAddress addr = {
|
const AudioObjectPropertyAddress addr = {
|
||||||
kAudioDevicePropertyStreamConfiguration,
|
kAudioDevicePropertyStreamConfiguration,
|
||||||
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMaster
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
const AudioObjectPropertyAddress nameaddr = {
|
const AudioObjectPropertyAddress nameaddr = {
|
||||||
kAudioObjectPropertyName,
|
kAudioObjectPropertyName,
|
||||||
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMaster
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
const AudioObjectPropertyAddress freqaddr = {
|
||||||
|
kAudioDevicePropertyNominalSampleRate,
|
||||||
|
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||||
|
kAudioObjectPropertyElementMaster
|
||||||
|
};
|
||||||
|
|
||||||
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
|
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
|
||||||
if (result != noErr)
|
if (result != noErr)
|
||||||
|
@ -149,21 +155,24 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
|
||||||
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
|
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
|
||||||
&size, buflist);
|
&size, buflist);
|
||||||
|
|
||||||
|
SDL_zero(spec);
|
||||||
if (result == noErr) {
|
if (result == noErr) {
|
||||||
UInt32 j;
|
UInt32 j;
|
||||||
for (j = 0; j < buflist->mNumberBuffers; j++) {
|
for (j = 0; j < buflist->mNumberBuffers; j++) {
|
||||||
if (buflist->mBuffers[j].mNumberChannels > 0) {
|
spec.channels += buflist->mBuffers[j].mNumberChannels;
|
||||||
usable = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(buflist);
|
SDL_free(buflist);
|
||||||
|
|
||||||
if (!usable)
|
if (spec.channels == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
size = sizeof (sampleRate);
|
||||||
|
result = AudioObjectGetPropertyData(dev, &freqaddr, 0, NULL, &size, &sampleRate);
|
||||||
|
if (result == noErr) {
|
||||||
|
spec.freq = (int) sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
size = sizeof (CFStringRef);
|
size = sizeof (CFStringRef);
|
||||||
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
|
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
|
||||||
|
@ -197,7 +206,7 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata)
|
||||||
((iscapture) ? "capture" : "output"),
|
((iscapture) ? "capture" : "output"),
|
||||||
(int) i, ptr, (int) dev);
|
(int) i, ptr, (int) dev);
|
||||||
#endif
|
#endif
|
||||||
addfn(ptr, iscapture, dev, addfndata);
|
addfn(ptr, &spec, iscapture, dev, addfndata);
|
||||||
}
|
}
|
||||||
SDL_free(ptr); /* addfn() would have copied the string. */
|
SDL_free(ptr); /* addfn() would have copied the string. */
|
||||||
}
|
}
|
||||||
|
@ -223,7 +232,7 @@ COREAUDIO_DetectDevices(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data)
|
build_device_change_list(const char *name, SDL_AudioSpec *spec, const int iscapture, AudioDeviceID devId, void *data)
|
||||||
{
|
{
|
||||||
AudioDeviceList **list = (AudioDeviceList **) data;
|
AudioDeviceList **list = (AudioDeviceList **) data;
|
||||||
AudioDeviceList *item;
|
AudioDeviceList *item;
|
||||||
|
@ -235,7 +244,7 @@ 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_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
|
SDL_AddAudioDevice(iscapture, name, spec, (void *) ((size_t) devId));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -163,7 +163,12 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
|
||||||
if (str != NULL) {
|
if (str != NULL) {
|
||||||
LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
|
LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
|
||||||
SDL_memcpy(cpyguid, guid, sizeof (GUID));
|
SDL_memcpy(cpyguid, guid, sizeof (GUID));
|
||||||
SDL_AddAudioDevice(iscapture, str, cpyguid);
|
|
||||||
|
/* Note that spec is NULL, because we are required to connect to the
|
||||||
|
* device before getting the channel mask and output format, making
|
||||||
|
* this information inaccessible at enumeration time
|
||||||
|
*/
|
||||||
|
SDL_AddAudioDevice(iscapture, str, NULL, cpyguid);
|
||||||
SDL_free(str); /* addfn() makes a copy of this string. */
|
SDL_free(str); /* addfn() makes a copy of this string. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,8 +173,8 @@ DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||||
static void
|
static void
|
||||||
DISKAUDIO_DetectDevices(void)
|
DISKAUDIO_DetectDevices(void)
|
||||||
{
|
{
|
||||||
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
|
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *) 0x1);
|
||||||
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
|
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) 0x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -160,9 +160,9 @@ static void OS2_DetectDevices(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
ulHandle++;
|
ulHandle++;
|
||||||
SDL_AddAudioDevice(0, stLogDevice.szProductInfo, (void *)(ulHandle));
|
SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
|
||||||
ulHandle++;
|
ulHandle++;
|
||||||
SDL_AddAudioDevice(1, stLogDevice.szProductInfo, (void *)(ulHandle));
|
SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -266,7 +266,7 @@ io_list_check_add(struct io_node *node)
|
||||||
spa_list_append(&hotplug_io_list, &node->link);
|
spa_list_append(&hotplug_io_list, &node->link);
|
||||||
|
|
||||||
if (SDL_AtomicGet(&hotplug_events_enabled)) {
|
if (SDL_AtomicGet(&hotplug_events_enabled)) {
|
||||||
SDL_AddAudioDevice(node->is_capture, node->name, PW_ID_TO_HANDLE(node->id));
|
SDL_AddAudioDevice(node->is_capture, node->name, &node->spec, PW_ID_TO_HANDLE(node->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
dup_found:
|
dup_found:
|
||||||
|
@ -768,7 +768,7 @@ PIPEWIRE_DetectDevices()
|
||||||
io_list_sort();
|
io_list_sort();
|
||||||
|
|
||||||
spa_list_for_each (io, &hotplug_io_list, link) {
|
spa_list_for_each (io, &hotplug_io_list, link) {
|
||||||
SDL_AddAudioDevice(io->is_capture, io->name, PW_ID_TO_HANDLE(io->id));
|
SDL_AddAudioDevice(io->is_capture, io->name, &io->spec, PW_ID_TO_HANDLE(io->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AtomicSet(&hotplug_events_enabled, 1);
|
SDL_AtomicSet(&hotplug_events_enabled, 1);
|
||||||
|
|
|
@ -696,12 +696,45 @@ static SDL_Thread *hotplug_thread = NULL;
|
||||||
|
|
||||||
/* device handles are device index + 1, cast to void*, so we never pass a NULL. */
|
/* device handles are device index + 1, cast to void*, so we never pass a NULL. */
|
||||||
|
|
||||||
|
static SDL_AudioFormat
|
||||||
|
PulseFormatToSDLFormat(pa_sample_format_t format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case PA_SAMPLE_U8:
|
||||||
|
return AUDIO_U8;
|
||||||
|
case PA_SAMPLE_S16LE:
|
||||||
|
return AUDIO_S16LSB;
|
||||||
|
case PA_SAMPLE_S16BE:
|
||||||
|
return AUDIO_S16MSB;
|
||||||
|
case PA_SAMPLE_S32LE:
|
||||||
|
return AUDIO_S32LSB;
|
||||||
|
case PA_SAMPLE_S32BE:
|
||||||
|
return AUDIO_S32MSB;
|
||||||
|
case PA_SAMPLE_FLOAT32LE:
|
||||||
|
return AUDIO_F32LSB;
|
||||||
|
case PA_SAMPLE_FLOAT32BE:
|
||||||
|
return AUDIO_F32MSB;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* This is called when PulseAudio adds an output ("sink") device. */
|
/* This is called when PulseAudio adds an output ("sink") device. */
|
||||||
static void
|
static void
|
||||||
SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
|
SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
|
||||||
{
|
{
|
||||||
|
SDL_AudioSpec spec;
|
||||||
if (i) {
|
if (i) {
|
||||||
SDL_AddAudioDevice(SDL_FALSE, i->description, (void *) ((size_t) i->index+1));
|
spec.freq = i->sample_spec.rate;
|
||||||
|
spec.channels = i->sample_spec.channels;
|
||||||
|
spec.format = PulseFormatToSDLFormat(i->sample_spec.format);
|
||||||
|
spec.silence = 0;
|
||||||
|
spec.samples = 0;
|
||||||
|
spec.size = 0;
|
||||||
|
spec.callback = NULL;
|
||||||
|
spec.userdata = NULL;
|
||||||
|
|
||||||
|
SDL_AddAudioDevice(SDL_FALSE, i->description, &spec, (void *) ((size_t) i->index+1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,10 +742,20 @@ SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
|
||||||
static void
|
static void
|
||||||
SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
|
SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
|
||||||
{
|
{
|
||||||
|
SDL_AudioSpec spec;
|
||||||
if (i) {
|
if (i) {
|
||||||
/* Skip "monitor" sources. These are just output from other sinks. */
|
/* Skip "monitor" sources. These are just output from other sinks. */
|
||||||
if (i->monitor_of_sink == PA_INVALID_INDEX) {
|
if (i->monitor_of_sink == PA_INVALID_INDEX) {
|
||||||
SDL_AddAudioDevice(SDL_TRUE, i->description, (void *) ((size_t) i->index+1));
|
spec.freq = i->sample_spec.rate;
|
||||||
|
spec.channels = i->sample_spec.channels;
|
||||||
|
spec.format = PulseFormatToSDLFormat(i->sample_spec.format);
|
||||||
|
spec.silence = 0;
|
||||||
|
spec.samples = 0;
|
||||||
|
spec.size = 0;
|
||||||
|
spec.callback = NULL;
|
||||||
|
spec.userdata = NULL;
|
||||||
|
|
||||||
|
SDL_AddAudioDevice(SDL_TRUE, i->description, &spec, (void *) ((size_t) i->index+1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -528,7 +528,11 @@ QSA_DetectDevices(void)
|
||||||
devices;
|
devices;
|
||||||
status = snd_pcm_close(handle);
|
status = snd_pcm_close(handle);
|
||||||
if (status == EOK) {
|
if (status == EOK) {
|
||||||
SDL_AddAudioDevice(SDL_FALSE, qsa_playback_device[qsa_playback_devices].name, &qsa_playback_device[qsa_playback_devices]);
|
/* Note that spec is NULL, because we are required to open the device before
|
||||||
|
* acquiring the mix format, making this information inaccessible at
|
||||||
|
* enumeration time
|
||||||
|
*/
|
||||||
|
SDL_AddAudioDevice(SDL_FALSE, qsa_playback_device[qsa_playback_devices].name, NULL, &qsa_playback_device[qsa_playback_devices]);
|
||||||
qsa_playback_devices++;
|
qsa_playback_devices++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -586,7 +590,11 @@ QSA_DetectDevices(void)
|
||||||
devices;
|
devices;
|
||||||
status = snd_pcm_close(handle);
|
status = snd_pcm_close(handle);
|
||||||
if (status == EOK) {
|
if (status == EOK) {
|
||||||
SDL_AddAudioDevice(SDL_TRUE, qsa_capture_device[qsa_capture_devices].name, &qsa_capture_device[qsa_capture_devices]);
|
/* Note that spec is NULL, because we are required to open the device before
|
||||||
|
* acquiring the mix format, making this information inaccessible at
|
||||||
|
* enumeration time
|
||||||
|
*/
|
||||||
|
SDL_AddAudioDevice(SDL_TRUE, qsa_capture_device[qsa_capture_devices].name, NULL, &qsa_capture_device[qsa_capture_devices]);
|
||||||
qsa_capture_devices++;
|
qsa_capture_devices++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -117,10 +117,34 @@ WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_AudioFormat
|
||||||
|
WaveFormatToSDLFormat(WAVEFORMATEX *waveformat)
|
||||||
|
{
|
||||||
|
if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
|
||||||
|
return AUDIO_F32SYS;
|
||||||
|
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
|
||||||
|
return AUDIO_S16SYS;
|
||||||
|
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
|
||||||
|
return AUDIO_S32SYS;
|
||||||
|
} else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||||
|
const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *) waveformat;
|
||||||
|
if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
||||||
|
return AUDIO_F32SYS;
|
||||||
|
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
|
||||||
|
return AUDIO_S16SYS;
|
||||||
|
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
||||||
|
return AUDIO_S32SYS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_assert(0 && "Unrecognized wFormatTag!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
|
WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid)
|
||||||
{
|
{
|
||||||
DevIdList *devidlist;
|
DevIdList *devidlist;
|
||||||
|
SDL_AudioSpec spec;
|
||||||
|
|
||||||
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
|
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
|
||||||
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
|
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
|
||||||
|
@ -149,7 +173,11 @@ WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
|
||||||
devidlist->next = deviceid_list;
|
devidlist->next = deviceid_list;
|
||||||
deviceid_list = devidlist;
|
deviceid_list = devidlist;
|
||||||
|
|
||||||
SDL_AddAudioDevice(iscapture, devname, (void *) devid);
|
SDL_zero(spec);
|
||||||
|
spec.channels = fmt->Format.nChannels;
|
||||||
|
spec.freq = fmt->Format.nSamplesPerSec;
|
||||||
|
spec.format = WaveFormatToSDLFormat((WAVEFORMATEX *) fmt);
|
||||||
|
SDL_AddAudioDevice(iscapture, devname, &spec, (void *) devid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -539,22 +567,7 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
this->spec.channels = (Uint8) waveformat->nChannels;
|
this->spec.channels = (Uint8) waveformat->nChannels;
|
||||||
|
|
||||||
/* Make sure we have a valid format that we can convert to whatever WASAPI wants. */
|
/* Make sure we have a valid format that we can convert to whatever WASAPI wants. */
|
||||||
if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
|
wasapi_format = WaveFormatToSDLFormat(waveformat);
|
||||||
wasapi_format = AUDIO_F32SYS;
|
|
||||||
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
|
|
||||||
wasapi_format = AUDIO_S16SYS;
|
|
||||||
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
|
|
||||||
wasapi_format = AUDIO_S32SYS;
|
|
||||||
} else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
|
||||||
const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *) waveformat;
|
|
||||||
if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
|
||||||
wasapi_format = AUDIO_F32SYS;
|
|
||||||
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
|
|
||||||
wasapi_format = AUDIO_S16SYS;
|
|
||||||
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
|
||||||
wasapi_format = AUDIO_S32SYS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((!valid_format) && (test_format)) {
|
while ((!valid_format) && (test_format)) {
|
||||||
if (test_format == wasapi_format) {
|
if (test_format == wasapi_format) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ extern SDL_atomic_t WASAPI_DefaultCaptureGeneration;
|
||||||
int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream);
|
int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream);
|
||||||
void WASAPI_RefDevice(_THIS);
|
void WASAPI_RefDevice(_THIS);
|
||||||
void WASAPI_UnrefDevice(_THIS);
|
void WASAPI_UnrefDevice(_THIS);
|
||||||
void WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid);
|
void WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid);
|
||||||
void WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid);
|
void WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid);
|
||||||
|
|
||||||
/* These are functions that are implemented differently for Windows vs WinRT. */
|
/* These are functions that are implemented differently for Windows vs WinRT. */
|
||||||
|
|
|
@ -65,26 +65,31 @@ static const IID SDL_IID_IMMNotificationClient = { 0x7991eec9, 0x7e89, 0x4d85,{
|
||||||
static const IID SDL_IID_IMMEndpoint = { 0x1be09788, 0x6894, 0x4089,{ 0x85, 0x86, 0x9a, 0x2a, 0x6c, 0x26, 0x5a, 0xc5 } };
|
static const IID SDL_IID_IMMEndpoint = { 0x1be09788, 0x6894, 0x4089,{ 0x85, 0x86, 0x9a, 0x2a, 0x6c, 0x26, 0x5a, 0xc5 } };
|
||||||
static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32,{ 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
|
static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32,{ 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
|
||||||
static const PROPERTYKEY SDL_PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd,{ 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, } }, 14 };
|
static const PROPERTYKEY SDL_PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd,{ 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, } }, 14 };
|
||||||
|
static const PROPERTYKEY SDL_PKEY_AudioEngine_DeviceFormat = { { 0xf19f064d, 0x82c, 0x4e27,{ 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c, } }, 0 };
|
||||||
|
|
||||||
|
|
||||||
static char *
|
static void
|
||||||
GetWasapiDeviceName(IMMDevice *device)
|
GetWasapiDeviceInfo(IMMDevice *device, char **utf8dev, WAVEFORMATEXTENSIBLE *fmt)
|
||||||
{
|
{
|
||||||
/* PKEY_Device_FriendlyName gives you "Speakers (SoundBlaster Pro)" which drives me nuts. I'd rather it be
|
/* PKEY_Device_FriendlyName gives you "Speakers (SoundBlaster Pro)" which drives me nuts. I'd rather it be
|
||||||
"SoundBlaster Pro (Speakers)" but I guess that's developers vs users. Windows uses the FriendlyName in
|
"SoundBlaster Pro (Speakers)" but I guess that's developers vs users. Windows uses the FriendlyName in
|
||||||
its own UIs, like Volume Control, etc. */
|
its own UIs, like Volume Control, etc. */
|
||||||
char *utf8dev = NULL;
|
|
||||||
IPropertyStore *props = NULL;
|
IPropertyStore *props = NULL;
|
||||||
|
*utf8dev = NULL;
|
||||||
|
SDL_zerop(fmt);
|
||||||
if (SUCCEEDED(IMMDevice_OpenPropertyStore(device, STGM_READ, &props))) {
|
if (SUCCEEDED(IMMDevice_OpenPropertyStore(device, STGM_READ, &props))) {
|
||||||
PROPVARIANT var;
|
PROPVARIANT var;
|
||||||
PropVariantInit(&var);
|
PropVariantInit(&var);
|
||||||
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_Device_FriendlyName, &var))) {
|
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_Device_FriendlyName, &var))) {
|
||||||
utf8dev = WIN_StringToUTF8W(var.pwszVal);
|
*utf8dev = WIN_StringToUTF8W(var.pwszVal);
|
||||||
|
}
|
||||||
|
PropVariantClear(&var);
|
||||||
|
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_AudioEngine_DeviceFormat, &var))) {
|
||||||
|
SDL_memcpy(fmt, var.blob.pBlobData, SDL_min(var.blob.cbSize, sizeof(WAVEFORMATEXTENSIBLE)));
|
||||||
}
|
}
|
||||||
PropVariantClear(&var);
|
PropVariantClear(&var);
|
||||||
IPropertyStore_Release(props);
|
IPropertyStore_Release(props);
|
||||||
}
|
}
|
||||||
return utf8dev;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -194,9 +199,11 @@ SDLMMNotificationClient_OnDeviceStateChanged(IMMNotificationClient *ithis, LPCWS
|
||||||
if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
|
if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
|
||||||
const SDL_bool iscapture = (flow == eCapture);
|
const SDL_bool iscapture = (flow == eCapture);
|
||||||
if (dwNewState == DEVICE_STATE_ACTIVE) {
|
if (dwNewState == DEVICE_STATE_ACTIVE) {
|
||||||
char *utf8dev = GetWasapiDeviceName(device);
|
char *utf8dev;
|
||||||
|
WAVEFORMATEXTENSIBLE fmt;
|
||||||
|
GetWasapiDeviceInfo(device, &utf8dev, &fmt);
|
||||||
if (utf8dev) {
|
if (utf8dev) {
|
||||||
WASAPI_AddDevice(iscapture, utf8dev, pwstrDeviceId);
|
WASAPI_AddDevice(iscapture, utf8dev, &fmt, pwstrDeviceId);
|
||||||
SDL_free(utf8dev);
|
SDL_free(utf8dev);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -352,6 +359,7 @@ typedef struct
|
||||||
{
|
{
|
||||||
LPWSTR devid;
|
LPWSTR devid;
|
||||||
char *devname;
|
char *devname;
|
||||||
|
WAVEFORMATEXTENSIBLE fmt;
|
||||||
} EndpointItem;
|
} EndpointItem;
|
||||||
|
|
||||||
static int sort_endpoints(const void *_a, const void *_b)
|
static int sort_endpoints(const void *_a, const void *_b)
|
||||||
|
@ -408,7 +416,7 @@ WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture)
|
||||||
IMMDevice *device = NULL;
|
IMMDevice *device = NULL;
|
||||||
if (SUCCEEDED(IMMDeviceCollection_Item(collection, i, &device))) {
|
if (SUCCEEDED(IMMDeviceCollection_Item(collection, i, &device))) {
|
||||||
if (SUCCEEDED(IMMDevice_GetId(device, &item->devid))) {
|
if (SUCCEEDED(IMMDevice_GetId(device, &item->devid))) {
|
||||||
item->devname = GetWasapiDeviceName(device);
|
GetWasapiDeviceInfo(device, &item->devname, &item->fmt);
|
||||||
}
|
}
|
||||||
IMMDevice_Release(device);
|
IMMDevice_Release(device);
|
||||||
}
|
}
|
||||||
|
@ -421,7 +429,7 @@ WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture)
|
||||||
for (i = 0; i < total; i++) {
|
for (i = 0; i < total; i++) {
|
||||||
EndpointItem *item = items + i;
|
EndpointItem *item = items + i;
|
||||||
if ((item->devid) && (item->devname)) {
|
if ((item->devid) && (item->devname)) {
|
||||||
WASAPI_AddDevice(iscapture, item->devname, item->devid);
|
WASAPI_AddDevice(iscapture, item->devname, &item->fmt, item->devid);
|
||||||
}
|
}
|
||||||
SDL_free(item->devname);
|
SDL_free(item->devname);
|
||||||
CoTaskMemFree(item->devid);
|
CoTaskMemFree(item->devid);
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <windows.devices.enumeration.h>
|
#include <windows.devices.enumeration.h>
|
||||||
#include <windows.media.devices.h>
|
#include <windows.media.devices.h>
|
||||||
#include <wrl/implements.h>
|
#include <wrl/implements.h>
|
||||||
|
#include <collection.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "../../core/windows/SDL_windows.h"
|
#include "../../core/windows/SDL_windows.h"
|
||||||
|
@ -52,6 +53,8 @@ using namespace Windows::Media::Devices;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
using namespace Microsoft::WRL;
|
using namespace Microsoft::WRL;
|
||||||
|
|
||||||
|
static Platform::String^ SDL_PKEY_AudioEngine_DeviceFormat = L"{f19f064d-082c-4e27-bc73-6882a1bb8e4c} 0";
|
||||||
|
|
||||||
class SDL_WasapiDeviceEventHandler
|
class SDL_WasapiDeviceEventHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -78,9 +81,16 @@ private:
|
||||||
SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture)
|
SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture)
|
||||||
: iscapture(_iscapture)
|
: iscapture(_iscapture)
|
||||||
, completed(SDL_CreateSemaphore(0))
|
, completed(SDL_CreateSemaphore(0))
|
||||||
, watcher(DeviceInformation::CreateWatcher(_iscapture ? DeviceClass::AudioCapture : DeviceClass::AudioRender))
|
|
||||||
{
|
{
|
||||||
if (!watcher || !completed)
|
if (!completed)
|
||||||
|
return; // uhoh.
|
||||||
|
|
||||||
|
Platform::String^ selector = _iscapture ? MediaDevice::GetAudioCaptureSelector() :
|
||||||
|
MediaDevice::GetAudioRenderSelector();
|
||||||
|
Platform::Collections::Vector<Platform::String^> properties;
|
||||||
|
properties.Append(SDL_PKEY_AudioEngine_DeviceFormat);
|
||||||
|
watcher = DeviceInformation::CreateWatcher(selector, properties.GetView());
|
||||||
|
if (!watcher)
|
||||||
return; // uhoh.
|
return; // uhoh.
|
||||||
|
|
||||||
// !!! FIXME: this doesn't need a lambda here, I think, if I make SDL_WasapiDeviceEventHandler a proper C++/CX class. --ryan.
|
// !!! FIXME: this doesn't need a lambda here, I think, if I make SDL_WasapiDeviceEventHandler a proper C++/CX class. --ryan.
|
||||||
|
@ -124,7 +134,18 @@ SDL_WasapiDeviceEventHandler::OnDeviceAdded(DeviceWatcher^ sender, DeviceInforma
|
||||||
SDL_assert(sender == this->watcher);
|
SDL_assert(sender == this->watcher);
|
||||||
char *utf8dev = WIN_StringToUTF8(info->Name->Data());
|
char *utf8dev = WIN_StringToUTF8(info->Name->Data());
|
||||||
if (utf8dev) {
|
if (utf8dev) {
|
||||||
WASAPI_AddDevice(this->iscapture, utf8dev, info->Id->Data());
|
WAVEFORMATEXTENSIBLE fmt;
|
||||||
|
Platform::Object^ obj = info->Properties->Lookup(SDL_PKEY_AudioEngine_DeviceFormat);
|
||||||
|
if (obj) {
|
||||||
|
IPropertyValue^ property = (IPropertyValue^) obj;
|
||||||
|
Platform::Array<unsigned char>^ data;
|
||||||
|
property->GetUInt8Array(&data);
|
||||||
|
SDL_memcpy(&fmt, data->Data, SDL_min(data->Length, sizeof(WAVEFORMATEXTENSIBLE)));
|
||||||
|
} else {
|
||||||
|
SDL_zero(fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
WASAPI_AddDevice(this->iscapture, utf8dev, &fmt, info->Id->Data());
|
||||||
SDL_free(utf8dev);
|
SDL_free(utf8dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,12 +75,19 @@ static void DetectWave##typ##Devs(void) { \
|
||||||
const UINT iscapture = iscap ? 1 : 0; \
|
const UINT iscapture = iscap ? 1 : 0; \
|
||||||
const UINT devcount = wave##typ##GetNumDevs(); \
|
const UINT devcount = wave##typ##GetNumDevs(); \
|
||||||
capstyp##2W caps; \
|
capstyp##2W caps; \
|
||||||
|
SDL_AudioSpec spec; \
|
||||||
UINT i; \
|
UINT i; \
|
||||||
|
SDL_zero(spec); \
|
||||||
for (i = 0; i < devcount; i++) { \
|
for (i = 0; i < devcount; i++) { \
|
||||||
if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
|
if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
|
||||||
char *name = WIN_LookupAudioDeviceName(caps.szPname,&caps.NameGuid); \
|
char *name = WIN_LookupAudioDeviceName(caps.szPname,&caps.NameGuid); \
|
||||||
if (name != NULL) { \
|
if (name != NULL) { \
|
||||||
SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \
|
/* Note that freq/format are not filled in, as this information \
|
||||||
|
* is not provided by the caps struct! At best, we get possible \
|
||||||
|
* sample formats, but not an _active_ format. \
|
||||||
|
*/ \
|
||||||
|
spec.channels = caps.wChannels; \
|
||||||
|
SDL_AddAudioDevice((int) iscapture, name, &spec, (void *) ((size_t) i+1)); \
|
||||||
SDL_free(name); \
|
SDL_free(name); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
|
|
@ -808,3 +808,4 @@
|
||||||
#define SDL_isprint SDL_isprint_REAL
|
#define SDL_isprint SDL_isprint_REAL
|
||||||
#define SDL_isgraph SDL_isgraph_REAL
|
#define SDL_isgraph SDL_isgraph_REAL
|
||||||
#define SDL_AndroidShowToast SDL_AndroidShowToast_REAL
|
#define SDL_AndroidShowToast SDL_AndroidShowToast_REAL
|
||||||
|
#define SDL_GetAudioDeviceSpec SDL_GetAudioDeviceSpec_REAL
|
||||||
|
|
|
@ -873,3 +873,4 @@ SDL_DYNAPI_PROC(int,SDL_isgraph,(int a),(a),return)
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
SDL_DYNAPI_PROC(int,SDL_AndroidShowToast,(const char *a, int b, int c, int d, int e),(a,b,c,d,e),return)
|
SDL_DYNAPI_PROC(int,SDL_AndroidShowToast,(const char *a, int b, int c, int d, int e),(a,b,c,d,e),return)
|
||||||
#endif
|
#endif
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceSpec,(int a, int b, SDL_AudioSpec *c),(a,b,c),return)
|
||||||
|
|
Loading…
Reference in New Issue