Signed-off-by: Huw Davies huw@codeweavers.com --- dlls/winealsa.drv/alsa.c | 178 +++++++++++++++++++++++++++++++++++ dlls/winealsa.drv/mmdevdrv.c | 126 +++---------------------- dlls/winealsa.drv/unixlib.h | 9 ++ 3 files changed, 199 insertions(+), 114 deletions(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c index ae05c7a8b9b..320d676effb 100644 --- a/dlls/winealsa.drv/alsa.c +++ b/dlls/winealsa.drv/alsa.c @@ -39,6 +39,7 @@ #include "wine/list.h" #include "wine/unixlib.h"
+#include "initguid.h" #include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(alsa); @@ -452,7 +453,184 @@ static NTSTATUS get_endpoint_ids(void *args) return STATUS_SUCCESS; }
+static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle, + snd_pcm_hw_params_t **hw_params) +{ + snd_pcm_stream_t pcm_stream; + int err; + + if(flow == eRender) + pcm_stream = SND_PCM_STREAM_PLAYBACK; + else if(flow == eCapture) + pcm_stream = SND_PCM_STREAM_CAPTURE; + else + return E_UNEXPECTED; + + err = snd_pcm_open(pcm_handle, alsa_name, pcm_stream, SND_PCM_NONBLOCK); + if(err < 0){ + WARN("Unable to open PCM "%s": %d (%s)\n", alsa_name, err, snd_strerror(err)); + switch(err){ + case -EBUSY: + return AUDCLNT_E_DEVICE_IN_USE; + default: + return AUDCLNT_E_ENDPOINT_CREATE_FAILED; + } + } + + *hw_params = malloc(snd_pcm_hw_params_sizeof()); + if(!*hw_params){ + snd_pcm_close(*pcm_handle); + return E_OUTOFMEMORY; + } + + return S_OK; +} + +static DWORD get_channel_mask(unsigned int channels) +{ + switch(channels){ + case 0: + return 0; + case 1: + return KSAUDIO_SPEAKER_MONO; + case 2: + return KSAUDIO_SPEAKER_STEREO; + case 3: + return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY; + case 4: + return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */ + case 5: + return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY; + case 6: + return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */ + case 7: + return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER; + case 8: + return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */ + } + FIXME("Unknown speaker configuration: %u\n", channels); + return 0; +} + +static NTSTATUS get_mix_format(void *args) +{ + struct get_mix_format_params *params = args; + WAVEFORMATEXTENSIBLE *fmt = params->fmt; + snd_pcm_t *pcm_handle; + snd_pcm_hw_params_t *hw_params; + snd_pcm_format_mask_t *formats; + unsigned int max_rate, max_channels; + int err; + + params->result = alsa_open_device(params->alsa_name, params->flow, &pcm_handle, &hw_params); + if(FAILED(params->result)) + return STATUS_SUCCESS; + + formats = calloc(1, snd_pcm_format_mask_sizeof()); + if(!formats){ + free(hw_params); + snd_pcm_close(pcm_handle); + params->result = E_OUTOFMEMORY; + return STATUS_SUCCESS; + } + + if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){ + WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err)); + params->result = AUDCLNT_E_DEVICE_INVALIDATED; + goto exit; + } + + snd_pcm_hw_params_get_format_mask(hw_params, formats); + + fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){ + fmt->Format.wBitsPerSample = 32; + fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){ + fmt->Format.wBitsPerSample = 16; + fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){ + fmt->Format.wBitsPerSample = 8; + fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){ + fmt->Format.wBitsPerSample = 32; + fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){ + fmt->Format.wBitsPerSample = 24; + fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + }else{ + ERR("Didn't recognize any available ALSA formats\n"); + params->result = AUDCLNT_E_DEVICE_INVALIDATED; + goto exit; + } + + if((err = snd_pcm_hw_params_get_channels_max(hw_params, &max_channels)) < 0){ + WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err)); + params->result = AUDCLNT_E_DEVICE_INVALIDATED; + goto exit; + } + + if(max_channels > 6) + fmt->Format.nChannels = 2; + else + fmt->Format.nChannels = max_channels; + + if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){ + /* For most hardware on Windows, users must choose a configuration with an even + * number of channels (stereo, quad, 5.1, 7.1). Users can then disable + * channels, but those channels are still reported to applications from + * GetMixFormat! Some applications behave badly if given an odd number of + * channels (e.g. 2.1). */ + + if(fmt->Format.nChannels < max_channels) + fmt->Format.nChannels += 1; + else + /* We could "fake" more channels and downmix the emulated channels, + * but at that point you really ought to tweak your ALSA setup or + * just use PulseAudio. */ + WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels); + } + + fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels); + + if((err = snd_pcm_hw_params_get_rate_max(hw_params, &max_rate, NULL)) < 0){ + WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err)); + params->result = AUDCLNT_E_DEVICE_INVALIDATED; + goto exit; + } + + if(max_rate >= 48000) + fmt->Format.nSamplesPerSec = 48000; + else if(max_rate >= 44100) + fmt->Format.nSamplesPerSec = 44100; + else if(max_rate >= 22050) + fmt->Format.nSamplesPerSec = 22050; + else if(max_rate >= 11025) + fmt->Format.nSamplesPerSec = 11025; + else if(max_rate >= 8000) + fmt->Format.nSamplesPerSec = 8000; + else{ + ERR("Unknown max rate: %u\n", max_rate); + params->result = AUDCLNT_E_DEVICE_INVALIDATED; + goto exit; + } + + fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample * fmt->Format.nChannels) / 8; + fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec * fmt->Format.nBlockAlign; + + fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample; + fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + +exit: + free(formats); + free(hw_params); + snd_pcm_close(pcm_handle); + + return STATUS_SUCCESS; +} + unixlib_entry_t __wine_unix_call_funcs[] = { get_endpoint_ids, + get_mix_format, }; diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c index ecd74d373aa..24c6755d697 100644 --- a/dlls/winealsa.drv/mmdevdrv.c +++ b/dlls/winealsa.drv/mmdevdrv.c @@ -1446,11 +1446,7 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, WAVEFORMATEX **pwfx) { ACImpl *This = impl_from_IAudioClient3(iface); - WAVEFORMATEXTENSIBLE *fmt; - snd_pcm_format_mask_t *formats; - unsigned int max_rate, max_channels; - int err; - HRESULT hr = S_OK; + struct get_mix_format_params params;
TRACE("(%p)->(%p)\n", This, pwfx);
@@ -1458,119 +1454,21 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, return E_POINTER; *pwfx = NULL;
- fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE)); - if(!fmt) + params.alsa_name = This->alsa_name; + params.flow = This->dataflow; + params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE)); + if(!params.fmt) return E_OUTOFMEMORY;
- formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof()); - if(!formats){ - CoTaskMemFree(fmt); - return E_OUTOFMEMORY; - } - - EnterCriticalSection(&This->lock); - - if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){ - WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err)); - hr = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats); - - fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){ - fmt->Format.wBitsPerSample = 32; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){ - fmt->Format.wBitsPerSample = 16; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){ - fmt->Format.wBitsPerSample = 8; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){ - fmt->Format.wBitsPerSample = 32; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){ - fmt->Format.wBitsPerSample = 24; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else{ - ERR("Didn't recognize any available ALSA formats\n"); - hr = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params, - &max_channels)) < 0){ - WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err)); - hr = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - if(max_channels > 6) - fmt->Format.nChannels = 2; - else - fmt->Format.nChannels = max_channels; - - if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){ - /* For most hardware on Windows, users must choose a configuration with an even - * number of channels (stereo, quad, 5.1, 7.1). Users can then disable - * channels, but those channels are still reported to applications from - * GetMixFormat! Some applications behave badly if given an odd number of - * channels (e.g. 2.1). */ - - if(fmt->Format.nChannels < max_channels) - fmt->Format.nChannels += 1; - else - /* We could "fake" more channels and downmix the emulated channels, - * but at that point you really ought to tweak your ALSA setup or - * just use PulseAudio. */ - WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels); - } - - fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels); + ALSA_CALL(get_mix_format, ¶ms);
- if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max_rate, - NULL)) < 0){ - WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err)); - hr = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - if(max_rate >= 48000) - fmt->Format.nSamplesPerSec = 48000; - else if(max_rate >= 44100) - fmt->Format.nSamplesPerSec = 44100; - else if(max_rate >= 22050) - fmt->Format.nSamplesPerSec = 22050; - else if(max_rate >= 11025) - fmt->Format.nSamplesPerSec = 11025; - else if(max_rate >= 8000) - fmt->Format.nSamplesPerSec = 8000; - else{ - ERR("Unknown max rate: %u\n", max_rate); - hr = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample * - fmt->Format.nChannels) / 8; - fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec * - fmt->Format.nBlockAlign; - - fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample; - fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - - dump_fmt((WAVEFORMATEX*)fmt); - *pwfx = (WAVEFORMATEX*)fmt; - -exit: - LeaveCriticalSection(&This->lock); - if(FAILED(hr)) - CoTaskMemFree(fmt); - HeapFree(GetProcessHeap(), 0, formats); + if(SUCCEEDED(params.result)){ + *pwfx = ¶ms.fmt->Format; + dump_fmt(*pwfx); + } else + CoTaskMemFree(params.fmt);
- return hr; + return params.result; }
static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h index 8a20710b7e5..ef5b470e1ed 100644 --- a/dlls/winealsa.drv/unixlib.h +++ b/dlls/winealsa.drv/unixlib.h @@ -67,9 +67,18 @@ struct get_endpoint_ids_params unsigned int default_idx; };
+struct get_mix_format_params +{ + const char *alsa_name; + EDataFlow flow; + WAVEFORMATEXTENSIBLE *fmt; + HRESULT result; +}; + enum alsa_funcs { alsa_get_endpoint_ids, + alsa_get_mix_format, };
extern unixlib_handle_t alsa_handle;
Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Wed, Feb 16, 2022 at 09:34:51AM +0000, Huw Davies wrote:
Signed-off-by: Huw Davies huw@codeweavers.com
dlls/winealsa.drv/alsa.c | 178 +++++++++++++++++++++++++++++++++++ dlls/winealsa.drv/mmdevdrv.c | 126 +++---------------------- dlls/winealsa.drv/unixlib.h | 9 ++ 3 files changed, 199 insertions(+), 114 deletions(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c index ae05c7a8b9b..320d676effb 100644 --- a/dlls/winealsa.drv/alsa.c +++ b/dlls/winealsa.drv/alsa.c @@ -39,6 +39,7 @@ #include "wine/list.h" #include "wine/unixlib.h"
+#include "initguid.h" #include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(alsa); @@ -452,7 +453,184 @@ static NTSTATUS get_endpoint_ids(void *args) return STATUS_SUCCESS; }
+static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle,
snd_pcm_hw_params_t **hw_params)
+{
- snd_pcm_stream_t pcm_stream;
- int err;
- if(flow == eRender)
pcm_stream = SND_PCM_STREAM_PLAYBACK;
- else if(flow == eCapture)
pcm_stream = SND_PCM_STREAM_CAPTURE;
- else
return E_UNEXPECTED;
- err = snd_pcm_open(pcm_handle, alsa_name, pcm_stream, SND_PCM_NONBLOCK);
- if(err < 0){
WARN("Unable to open PCM \"%s\": %d (%s)\n", alsa_name, err, snd_strerror(err));
switch(err){
case -EBUSY:
return AUDCLNT_E_DEVICE_IN_USE;
default:
return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
}
- }
- *hw_params = malloc(snd_pcm_hw_params_sizeof());
- if(!*hw_params){
snd_pcm_close(*pcm_handle);
return E_OUTOFMEMORY;
- }
- return S_OK;
+}
+static DWORD get_channel_mask(unsigned int channels) +{
- switch(channels){
- case 0:
return 0;
- case 1:
return KSAUDIO_SPEAKER_MONO;
- case 2:
return KSAUDIO_SPEAKER_STEREO;
- case 3:
return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
- case 4:
return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
- case 5:
return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
- case 6:
return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
- case 7:
return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
- case 8:
return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
- }
- FIXME("Unknown speaker configuration: %u\n", channels);
- return 0;
+}
+static NTSTATUS get_mix_format(void *args) +{
- struct get_mix_format_params *params = args;
- WAVEFORMATEXTENSIBLE *fmt = params->fmt;
- snd_pcm_t *pcm_handle;
- snd_pcm_hw_params_t *hw_params;
- snd_pcm_format_mask_t *formats;
- unsigned int max_rate, max_channels;
- int err;
- params->result = alsa_open_device(params->alsa_name, params->flow, &pcm_handle, &hw_params);
- if(FAILED(params->result))
return STATUS_SUCCESS;
- formats = calloc(1, snd_pcm_format_mask_sizeof());
- if(!formats){
free(hw_params);
snd_pcm_close(pcm_handle);
params->result = E_OUTOFMEMORY;
return STATUS_SUCCESS;
- }
- if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){
WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- snd_pcm_hw_params_get_format_mask(hw_params, formats);
- fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
- if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
fmt->Format.wBitsPerSample = 32;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
fmt->Format.wBitsPerSample = 16;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
fmt->Format.wBitsPerSample = 8;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
fmt->Format.wBitsPerSample = 32;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
fmt->Format.wBitsPerSample = 24;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else{
ERR("Didn't recognize any available ALSA formats\n");
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- if((err = snd_pcm_hw_params_get_channels_max(hw_params, &max_channels)) < 0){
WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- if(max_channels > 6)
fmt->Format.nChannels = 2;
- else
fmt->Format.nChannels = max_channels;
- if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){
/* For most hardware on Windows, users must choose a configuration with an even
* number of channels (stereo, quad, 5.1, 7.1). Users can then disable
* channels, but those channels are still reported to applications from
* GetMixFormat! Some applications behave badly if given an odd number of
* channels (e.g. 2.1). */
if(fmt->Format.nChannels < max_channels)
fmt->Format.nChannels += 1;
else
/* We could "fake" more channels and downmix the emulated channels,
* but at that point you really ought to tweak your ALSA setup or
* just use PulseAudio. */
WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
- }
- fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
- if((err = snd_pcm_hw_params_get_rate_max(hw_params, &max_rate, NULL)) < 0){
WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- if(max_rate >= 48000)
fmt->Format.nSamplesPerSec = 48000;
- else if(max_rate >= 44100)
fmt->Format.nSamplesPerSec = 44100;
- else if(max_rate >= 22050)
fmt->Format.nSamplesPerSec = 22050;
- else if(max_rate >= 11025)
fmt->Format.nSamplesPerSec = 11025;
- else if(max_rate >= 8000)
fmt->Format.nSamplesPerSec = 8000;
- else{
ERR("Unknown max rate: %u\n", max_rate);
params->result = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample * fmt->Format.nChannels) / 8;
- fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec * fmt->Format.nBlockAlign;
- fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
- fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+exit:
- free(formats);
- free(hw_params);
- snd_pcm_close(pcm_handle);
- return STATUS_SUCCESS;
+}
unixlib_entry_t __wine_unix_call_funcs[] = { get_endpoint_ids,
- get_mix_format,
}; diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c index ecd74d373aa..24c6755d697 100644 --- a/dlls/winealsa.drv/mmdevdrv.c +++ b/dlls/winealsa.drv/mmdevdrv.c @@ -1446,11 +1446,7 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, WAVEFORMATEX **pwfx) { ACImpl *This = impl_from_IAudioClient3(iface);
- WAVEFORMATEXTENSIBLE *fmt;
- snd_pcm_format_mask_t *formats;
- unsigned int max_rate, max_channels;
- int err;
- HRESULT hr = S_OK;
struct get_mix_format_params params;
TRACE("(%p)->(%p)\n", This, pwfx);
@@ -1458,119 +1454,21 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, return E_POINTER; *pwfx = NULL;
- fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
- if(!fmt)
- params.alsa_name = This->alsa_name;
- params.flow = This->dataflow;
- params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
- if(!params.fmt) return E_OUTOFMEMORY;
- formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof());
- if(!formats){
CoTaskMemFree(fmt);
return E_OUTOFMEMORY;
- }
- EnterCriticalSection(&This->lock);
- if((err = snd_pcm_hw_params_any(This->stream->pcm_handle, This->stream->hw_params)) < 0){
WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- snd_pcm_hw_params_get_format_mask(This->stream->hw_params, formats);
- fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
- if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
fmt->Format.wBitsPerSample = 32;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
fmt->Format.wBitsPerSample = 16;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
fmt->Format.wBitsPerSample = 8;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
fmt->Format.wBitsPerSample = 32;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
fmt->Format.wBitsPerSample = 24;
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- }else{
ERR("Didn't recognize any available ALSA formats\n");
hr = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- if((err = snd_pcm_hw_params_get_channels_max(This->stream->hw_params,
&max_channels)) < 0){
WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- if(max_channels > 6)
fmt->Format.nChannels = 2;
- else
fmt->Format.nChannels = max_channels;
- if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){
/* For most hardware on Windows, users must choose a configuration with an even
* number of channels (stereo, quad, 5.1, 7.1). Users can then disable
* channels, but those channels are still reported to applications from
* GetMixFormat! Some applications behave badly if given an odd number of
* channels (e.g. 2.1). */
if(fmt->Format.nChannels < max_channels)
fmt->Format.nChannels += 1;
else
/* We could "fake" more channels and downmix the emulated channels,
* but at that point you really ought to tweak your ALSA setup or
* just use PulseAudio. */
WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels);
- }
- fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
- ALSA_CALL(get_mix_format, ¶ms);
- if((err = snd_pcm_hw_params_get_rate_max(This->stream->hw_params, &max_rate,
NULL)) < 0){
WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
hr = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- if(max_rate >= 48000)
fmt->Format.nSamplesPerSec = 48000;
- else if(max_rate >= 44100)
fmt->Format.nSamplesPerSec = 44100;
- else if(max_rate >= 22050)
fmt->Format.nSamplesPerSec = 22050;
- else if(max_rate >= 11025)
fmt->Format.nSamplesPerSec = 11025;
- else if(max_rate >= 8000)
fmt->Format.nSamplesPerSec = 8000;
- else{
ERR("Unknown max rate: %u\n", max_rate);
hr = AUDCLNT_E_DEVICE_INVALIDATED;
goto exit;
- }
- fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
fmt->Format.nChannels) / 8;
- fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
fmt->Format.nBlockAlign;
- fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
- fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
- dump_fmt((WAVEFORMATEX*)fmt);
- *pwfx = (WAVEFORMATEX*)fmt;
-exit:
- LeaveCriticalSection(&This->lock);
- if(FAILED(hr))
CoTaskMemFree(fmt);
- HeapFree(GetProcessHeap(), 0, formats);
- if(SUCCEEDED(params.result)){
*pwfx = ¶ms.fmt->Format;
dump_fmt(*pwfx);
- } else
CoTaskMemFree(params.fmt);
- return hr;
- return params.result;
}
static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h index 8a20710b7e5..ef5b470e1ed 100644 --- a/dlls/winealsa.drv/unixlib.h +++ b/dlls/winealsa.drv/unixlib.h @@ -67,9 +67,18 @@ struct get_endpoint_ids_params unsigned int default_idx; };
+struct get_mix_format_params +{
- const char *alsa_name;
- EDataFlow flow;
- WAVEFORMATEXTENSIBLE *fmt;
- HRESULT result;
+};
enum alsa_funcs { alsa_get_endpoint_ids,
- alsa_get_mix_format,
};
extern unixlib_handle_t alsa_handle;
2.25.1