mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-23 02:15:32 +00:00
WASAPI: get the list of supported formats from devices
This commit is contained in:
parent
f4ad630769
commit
75185d17d7
|
@ -251,10 +251,9 @@ view `coverage/index.html` in a browser.
|
||||||
|
|
||||||
0. implement WASAPI (Windows) backend, get examples working
|
0. implement WASAPI (Windows) backend, get examples working
|
||||||
- list devices
|
- list devices
|
||||||
- formats
|
- channel layout
|
||||||
- buffer duration
|
- buffer duration
|
||||||
- raw mode
|
- raw mode
|
||||||
- channel layout
|
|
||||||
- watching
|
- watching
|
||||||
- sine wave
|
- sine wave
|
||||||
- microphone
|
- microphone
|
||||||
|
|
|
@ -304,7 +304,9 @@ struct SoundIoDevice {
|
||||||
// If the same physical device supports both input and output, that makes
|
// If the same physical device supports both input and output, that makes
|
||||||
// one SoundIoDevice for the input and one SoundIoDevice for the output.
|
// one SoundIoDevice for the input and one SoundIoDevice for the output.
|
||||||
// In this case, the `id` of each SoundIoDevice will be the same, and the
|
// In this case, the `id` of each SoundIoDevice will be the same, and the
|
||||||
// `aim` field will be different.
|
// `aim` field will be different. Additionally, if the device supports raw
|
||||||
|
// mode, there may be up to four devices with the same id: one for each
|
||||||
|
// value of `is_raw` and one for each value of `aim`.
|
||||||
char *id;
|
char *id;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
|
|
|
@ -584,10 +584,8 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
rd.device->name = soundio_str_dupe(rd.device_name, rd.device_name_len);
|
rd.device->name = soundio_str_dupe(rd.device_name, rd.device_name_len);
|
||||||
rd.device->layout_count = 1;
|
rd.device->layout_count = 1;
|
||||||
rd.device->layouts = allocate<SoundIoChannelLayout>(1);
|
rd.device->layouts = allocate<SoundIoChannelLayout>(1);
|
||||||
rd.device->format_count = 1;
|
|
||||||
rd.device->formats = allocate<SoundIoFormat>(1);
|
|
||||||
|
|
||||||
if (!rd.device->id || !rd.device->name || !rd.device->layouts || !rd.device->formats) {
|
if (!rd.device->id || !rd.device->name || !rd.device->layouts) {
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
@ -622,6 +620,8 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
|
|
||||||
rd.device->layouts[0] = rd.device->current_layout;
|
rd.device->layouts[0] = rd.device->current_layout;
|
||||||
// in CoreAudio, format is always 32-bit native endian float
|
// in CoreAudio, format is always 32-bit native endian float
|
||||||
|
rd.device->format_count = 1;
|
||||||
|
rd.device->formats = &dev->prealloc_format;
|
||||||
rd.device->formats[0] = SoundIoFormatFloat32NE;
|
rd.device->formats[0] = SoundIoFormatFloat32NE;
|
||||||
|
|
||||||
prop_address.mSelector = kAudioDevicePropertyNominalSampleRate;
|
prop_address.mSelector = kAudioDevicePropertyNominalSampleRate;
|
||||||
|
|
|
@ -189,8 +189,6 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
device->name = allocate<char>(description_len);
|
device->name = allocate<char>(description_len);
|
||||||
device->layout_count = 1;
|
device->layout_count = 1;
|
||||||
device->layouts = allocate<SoundIoChannelLayout>(1);
|
device->layouts = allocate<SoundIoChannelLayout>(1);
|
||||||
device->format_count = 1;
|
|
||||||
device->formats = allocate<SoundIoFormat>(1);
|
|
||||||
device->current_format = SoundIoFormatFloat32NE;
|
device->current_format = SoundIoFormatFloat32NE;
|
||||||
device->sample_rate_count = 1;
|
device->sample_rate_count = 1;
|
||||||
device->sample_rates = &dev->prealloc_sample_rate_range;
|
device->sample_rates = &dev->prealloc_sample_rate_range;
|
||||||
|
@ -206,7 +204,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
dj->port_count = client->port_count;
|
dj->port_count = client->port_count;
|
||||||
dj->ports = allocate<SoundIoDeviceJackPort>(dj->port_count);
|
dj->ports = allocate<SoundIoDeviceJackPort>(dj->port_count);
|
||||||
|
|
||||||
if (!device->id || !device->name || !device->layouts || !device->formats || !dj->ports) {
|
if (!device->id || !device->name || !device->layouts || !dj->ports) {
|
||||||
jack_free(port_names);
|
jack_free(port_names);
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
soundio_destroy_devices_info(devices_info);
|
soundio_destroy_devices_info(devices_info);
|
||||||
|
@ -257,6 +255,8 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
device->layouts[0] = device->current_layout;
|
device->layouts[0] = device->current_layout;
|
||||||
|
device->format_count = 1;
|
||||||
|
device->formats = &dev->prealloc_format;
|
||||||
device->formats[0] = device->current_format;
|
device->formats[0] = device->current_format;
|
||||||
|
|
||||||
SoundIoList<SoundIoDevice *> *device_list;
|
SoundIoList<SoundIoDevice *> *device_list;
|
||||||
|
|
|
@ -374,12 +374,14 @@ void soundio_device_unref(struct SoundIoDevice *device) {
|
||||||
|
|
||||||
free(device->id);
|
free(device->id);
|
||||||
free(device->name);
|
free(device->name);
|
||||||
free(device->formats);
|
|
||||||
free(device->layouts);
|
free(device->layouts);
|
||||||
|
|
||||||
if (device->sample_rates != &dev->prealloc_sample_rate_range)
|
if (device->sample_rates != &dev->prealloc_sample_rate_range)
|
||||||
free(device->sample_rates);
|
free(device->sample_rates);
|
||||||
|
|
||||||
|
if (device->formats != &dev->prealloc_format)
|
||||||
|
free(device->formats);
|
||||||
|
|
||||||
free(dev);
|
free(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,7 @@ struct SoundIoDevicePrivate {
|
||||||
SoundIoDeviceBackendData backend_data;
|
SoundIoDeviceBackendData backend_data;
|
||||||
void (*destruct)(SoundIoDevicePrivate *);
|
void (*destruct)(SoundIoDevicePrivate *);
|
||||||
SoundIoSampleRateRange prealloc_sample_rate_range;
|
SoundIoSampleRateRange prealloc_sample_rate_range;
|
||||||
|
SoundIoFormat prealloc_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
||||||
|
|
|
@ -47,6 +47,36 @@ static int from_lpwstr(LPWSTR lpwstr, char **out_str, int *out_str_len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SoundIoFormat from_wave_format(WAVEFORMATEXTENSIBLE *wave_format) {
|
||||||
|
assert(wave_format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE);
|
||||||
|
bool is_pcm = IsEqualGUID(wave_format->SubFormat, SOUNDIO_KSDATAFORMAT_SUBTYPE_PCM);
|
||||||
|
bool is_float = IsEqualGUID(wave_format->SubFormat, SOUNDIO_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
|
||||||
|
|
||||||
|
if (wave_format->Samples.wValidBitsPerSample == wave_format->Format.wBitsPerSample) {
|
||||||
|
if (wave_format->Format.wBitsPerSample == 8) {
|
||||||
|
if (is_pcm)
|
||||||
|
return SoundIoFormatU8;
|
||||||
|
} else if (wave_format->Format.wBitsPerSample == 16) {
|
||||||
|
if (is_pcm)
|
||||||
|
return SoundIoFormatS16LE;
|
||||||
|
} else if (wave_format->Format.wBitsPerSample == 32) {
|
||||||
|
if (is_pcm)
|
||||||
|
return SoundIoFormatS32LE;
|
||||||
|
else if (is_float)
|
||||||
|
return SoundIoFormatFloat32LE;
|
||||||
|
} else if (wave_format->Format.wBitsPerSample == 64) {
|
||||||
|
if (is_float)
|
||||||
|
return SoundIoFormatFloat64LE;
|
||||||
|
}
|
||||||
|
} else if (wave_format->Format.wBitsPerSample == 32 &&
|
||||||
|
wave_format->Samples.wValidBitsPerSample == 24)
|
||||||
|
{
|
||||||
|
return SoundIoFormatS24LE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SoundIoFormatInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
static SoundIoDeviceAim data_flow_to_aim(EDataFlow data_flow) {
|
static SoundIoDeviceAim data_flow_to_aim(EDataFlow data_flow) {
|
||||||
return (data_flow == eRender) ? SoundIoDeviceAimOutput : SoundIoDeviceAimInput;
|
return (data_flow == eRender) ? SoundIoDeviceAimOutput : SoundIoDeviceAimInput;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +95,7 @@ struct RefreshDevices {
|
||||||
IPropertyStore *prop_store;
|
IPropertyStore *prop_store;
|
||||||
LPWSTR lpwstr;
|
LPWSTR lpwstr;
|
||||||
PROPVARIANT prop_variant_value;
|
PROPVARIANT prop_variant_value;
|
||||||
|
WAVEFORMATEXTENSIBLE *wave_format;
|
||||||
bool prop_variant_value_inited;
|
bool prop_variant_value_inited;
|
||||||
SoundIoDevicesInfo *devices_info;
|
SoundIoDevicesInfo *devices_info;
|
||||||
SoundIoDevice *device;
|
SoundIoDevice *device;
|
||||||
|
@ -93,6 +124,8 @@ static void deinit_refresh_devices(RefreshDevices *rd) {
|
||||||
IPropertyStore_Release(rd->prop_store);
|
IPropertyStore_Release(rd->prop_store);
|
||||||
if (rd->prop_variant_value_inited)
|
if (rd->prop_variant_value_inited)
|
||||||
PropVariantClear(&rd->prop_variant_value);
|
PropVariantClear(&rd->prop_variant_value);
|
||||||
|
if (rd->wave_format)
|
||||||
|
CoTaskMemFree(rd->wave_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destruct_device(SoundIoDevicePrivate *dev) {
|
static void destruct_device(SoundIoDevicePrivate *dev) {
|
||||||
|
@ -265,39 +298,29 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rd.prop_variant_value_inited)
|
if (rd.wave_format)
|
||||||
PropVariantClear(&rd.prop_variant_value);
|
CoTaskMemFree(rd.wave_format);
|
||||||
PropVariantInit(&rd.prop_variant_value);
|
if (FAILED(hr = IAudioClient_GetMixFormat(dw->audio_client, (WAVEFORMATEX**)&rd.wave_format))) {
|
||||||
rd.prop_variant_value_inited = true;
|
|
||||||
if ((FAILED(hr = IPropertyStore_GetValue(rd.prop_store,
|
|
||||||
PKEY_AudioEngine_DeviceFormat, &rd.prop_variant_value))))
|
|
||||||
{
|
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
if (rd.wave_format->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
|
||||||
WAVEFORMATEXTENSIBLE *wave_format = (WAVEFORMATEXTENSIBLE *)rd.prop_variant_value.blob.pBlobData;
|
|
||||||
if (wave_format->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
|
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if (IsEqualGUID(wave_format->SubFormat, SOUNDIO_KSDATAFORMAT_SUBTYPE_PCM)) {
|
|
||||||
} else if (IsEqualGUID(wave_format->SubFormat, SOUNDIO_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
|
|
||||||
} else {
|
|
||||||
deinit_refresh_devices(&rd);
|
|
||||||
return SoundIoErrorOpeningDevice;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
rd.device->sample_rate_count = 1;
|
rd.device->sample_rate_count = 1;
|
||||||
rd.device->sample_rates = &dev->prealloc_sample_rate_range;
|
rd.device->sample_rates = &dev->prealloc_sample_rate_range;
|
||||||
rd.device->sample_rate_current = wave_format->Format.nSamplesPerSec;
|
rd.device->sample_rate_current = rd.wave_format->Format.nSamplesPerSec;
|
||||||
rd.device->sample_rates[0].min = rd.device->sample_rate_current;
|
rd.device->sample_rates[0].min = rd.device->sample_rate_current;
|
||||||
rd.device->sample_rates[0].max = rd.device->sample_rate_current;
|
rd.device->sample_rates[0].max = rd.device->sample_rate_current;
|
||||||
|
|
||||||
fprintf(stderr, "bits per sample: %d\n", (int)wave_format->Format.wBitsPerSample);
|
rd.device->current_format = from_wave_format(rd.wave_format);
|
||||||
|
rd.device->format_count = 1;
|
||||||
|
rd.device->formats = &dev->prealloc_format;
|
||||||
|
rd.device->formats[0] = rd.device->current_format;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SoundIoList<SoundIoDevice *> *device_list;
|
SoundIoList<SoundIoDevice *> *device_list;
|
||||||
if (rd.device->aim == SoundIoDeviceAimOutput) {
|
if (rd.device->aim == SoundIoDeviceAimOutput) {
|
||||||
|
|
Loading…
Reference in a new issue