diff --git a/README.md b/README.md index a5e8520..cb3f071 100644 --- a/README.md +++ b/README.md @@ -251,10 +251,9 @@ view `coverage/index.html` in a browser. 0. implement WASAPI (Windows) backend, get examples working - list devices - - formats + - channel layout - buffer duration - raw mode - - channel layout - watching - sine wave - microphone diff --git a/soundio/soundio.h b/soundio/soundio.h index 3c6d54e..bdffd50 100644 --- a/soundio/soundio.h +++ b/soundio/soundio.h @@ -304,7 +304,9 @@ struct SoundIoDevice { // If the same physical device supports both input and output, that makes // 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 - // `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 *name; diff --git a/src/coreaudio.cpp b/src/coreaudio.cpp index 3b8b1dc..ab86b7d 100644 --- a/src/coreaudio.cpp +++ b/src/coreaudio.cpp @@ -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->layout_count = 1; rd.device->layouts = allocate(1); - rd.device->format_count = 1; - rd.device->formats = allocate(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); return SoundIoErrorNoMem; } @@ -622,6 +620,8 @@ static int refresh_devices(struct SoundIoPrivate *si) { rd.device->layouts[0] = rd.device->current_layout; // 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; prop_address.mSelector = kAudioDevicePropertyNominalSampleRate; diff --git a/src/jack.cpp b/src/jack.cpp index 217a36b..9f51b1a 100644 --- a/src/jack.cpp +++ b/src/jack.cpp @@ -189,8 +189,6 @@ static int refresh_devices_bare(SoundIoPrivate *si) { device->name = allocate(description_len); device->layout_count = 1; device->layouts = allocate(1); - device->format_count = 1; - device->formats = allocate(1); device->current_format = SoundIoFormatFloat32NE; device->sample_rate_count = 1; 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->ports = allocate(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); soundio_device_unref(device); soundio_destroy_devices_info(devices_info); @@ -257,6 +255,8 @@ static int refresh_devices_bare(SoundIoPrivate *si) { } device->layouts[0] = device->current_layout; + device->format_count = 1; + device->formats = &dev->prealloc_format; device->formats[0] = device->current_format; SoundIoList *device_list; diff --git a/src/soundio.cpp b/src/soundio.cpp index b23f186..28f3af3 100644 --- a/src/soundio.cpp +++ b/src/soundio.cpp @@ -374,12 +374,14 @@ void soundio_device_unref(struct SoundIoDevice *device) { free(device->id); free(device->name); - free(device->formats); free(device->layouts); if (device->sample_rates != &dev->prealloc_sample_rate_range) free(device->sample_rates); + if (device->formats != &dev->prealloc_format) + free(device->formats); + free(dev); } } diff --git a/src/soundio.hpp b/src/soundio.hpp index 2e9d179..88908c3 100644 --- a/src/soundio.hpp +++ b/src/soundio.hpp @@ -164,6 +164,7 @@ struct SoundIoDevicePrivate { SoundIoDeviceBackendData backend_data; void (*destruct)(SoundIoDevicePrivate *); SoundIoSampleRateRange prealloc_sample_rate_range; + SoundIoFormat prealloc_format; }; void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info); diff --git a/src/wasapi.cpp b/src/wasapi.cpp index 792dd97..a7bbdf1 100644 --- a/src/wasapi.cpp +++ b/src/wasapi.cpp @@ -47,6 +47,36 @@ static int from_lpwstr(LPWSTR lpwstr, char **out_str, int *out_str_len) { 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) { return (data_flow == eRender) ? SoundIoDeviceAimOutput : SoundIoDeviceAimInput; } @@ -65,6 +95,7 @@ struct RefreshDevices { IPropertyStore *prop_store; LPWSTR lpwstr; PROPVARIANT prop_variant_value; + WAVEFORMATEXTENSIBLE *wave_format; bool prop_variant_value_inited; SoundIoDevicesInfo *devices_info; SoundIoDevice *device; @@ -93,6 +124,8 @@ static void deinit_refresh_devices(RefreshDevices *rd) { IPropertyStore_Release(rd->prop_store); if (rd->prop_variant_value_inited) PropVariantClear(&rd->prop_variant_value); + if (rd->wave_format) + CoTaskMemFree(rd->wave_format); } static void destruct_device(SoundIoDevicePrivate *dev) { @@ -265,39 +298,29 @@ static int refresh_devices(SoundIoPrivate *si) { return SoundIoErrorOpeningDevice; } - if (rd.prop_variant_value_inited) - PropVariantClear(&rd.prop_variant_value); - PropVariantInit(&rd.prop_variant_value); - rd.prop_variant_value_inited = true; - if ((FAILED(hr = IPropertyStore_GetValue(rd.prop_store, - PKEY_AudioEngine_DeviceFormat, &rd.prop_variant_value)))) - { + if (rd.wave_format) + CoTaskMemFree(rd.wave_format); + if (FAILED(hr = IAudioClient_GetMixFormat(dw->audio_client, (WAVEFORMATEX**)&rd.wave_format))) { deinit_refresh_devices(&rd); return SoundIoErrorOpeningDevice; } - - WAVEFORMATEXTENSIBLE *wave_format = (WAVEFORMATEXTENSIBLE *)rd.prop_variant_value.blob.pBlobData; - if (wave_format->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) { + if (rd.wave_format->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) { deinit_refresh_devices(&rd); 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_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].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 *device_list; if (rd.device->aim == SoundIoDeviceAimOutput) {