WASAPI: get the list of supported formats from devices

This commit is contained in:
Andrew Kelley 2015-08-12 17:11:03 -07:00
parent f4ad630769
commit 75185d17d7
7 changed files with 59 additions and 32 deletions

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
} }
} }

View file

@ -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);

View file

@ -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) {