Initializing the audio client without AUTOCONVERTPCM is expected to fail when the requested sampling rate or channel count does not match the mixing format. Such behavior is not currently modeled on Wine, but it should be introduced, and since in many cases we expect automatic format conversion to work we add the flag.
From: Giovanni Mascellani gmascellani@codeweavers.com
--- dlls/mmdevapi/tests/render.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 2bedcd876bb..f0dc29dd1ed 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -602,8 +602,8 @@ static void test_formats(AUDCLNT_SHAREMODE mode, BOOL extensible) if (fmt.Format.nChannels > 2 && !extensible) expected = E_INVALIDARG; todo_wine_if(fmt.Format.nChannels > 2 && !extensible) - ok(hr == expected, "Initialize(shared, %s%lux%2ux%u) returns %08lx\n", - format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr); + ok(hr == expected, "Initialize(shared, %s%lux%2ux%u) returns %08lx, expected %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr, expected); } else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) /* Unsupported format implies "create failed" and shadows "not allowed" */ ok(hrs == hexcl && (hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == hrs), @@ -634,8 +634,8 @@ static void test_formats(AUDCLNT_SHAREMODE mode, BOOL extensible) if (fmt.Format.nChannels > 2 && !extensible) expected = E_INVALIDARG; todo_wine_if(hr != expected) - ok(hr == expected, "Initialize(shared, %s%lux%2ux%u, RATEADJUST) returns %08lx\n", - format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr); + ok(hr == expected, "Initialize(shared, %s%lux%2ux%u, RATEADJUST) returns %08lx, expected %08lx\n", + format_chr, fmt.Format.nSamplesPerSec, fmt.Format.wBitsPerSample, fmt.Format.nChannels, hr, expected); } else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) /* Unsupported format implies "create failed" and shadows "not allowed" */ ok(hrs == hexcl && (hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == hrs),
From: Giovanni Mascellani gmascellani@codeweavers.com
Initializing the audio client without AUTOCONVERTPCM is expected to fail when the requested sampling rate or channel count does not match the mixing format. Such behavior is not currently modeled on Wine, but it should be introduced, and since here we expect automatic format conversion to work we add the flag. --- dlls/mmdevapi/spatialaudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/mmdevapi/spatialaudio.c b/dlls/mmdevapi/spatialaudio.c index b721af6229b..8ae37cb5b92 100644 --- a/dlls/mmdevapi/spatialaudio.c +++ b/dlls/mmdevapi/spatialaudio.c @@ -740,7 +740,7 @@ static HRESULT activate_stream(SpatialAudioStreamImpl *stream) stream->stream_fmtex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
hr = IAudioClient_Initialize(stream->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, period, 0, &stream->stream_fmtex.Format, NULL); if(FAILED(hr)){ WARN("Initialize failed: %08lx\n", hr);
From: Giovanni Mascellani gmascellani@codeweavers.com
Initializing the audio client without AUTOCONVERTPCM is expected to fail when the requested sampling rate or channel count does not match the mixing format. Such behavior is not currently modeled on Wine, but it should be introduced, and since here we expect automatic format conversion to work we add the flag. --- dlls/windows.media.speech/recognizer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 5c83beec063..1b365f0f39d 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -1071,7 +1071,8 @@ static HRESULT recognizer_factory_create_audio_capture(struct session *session) wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; TRACE("wfx tag %u, channels %u, samples %lu, bits %u, align %u.\n", wfx.wFormatTag, wfx.nChannels, wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nBlockAlign);
- if (FAILED(hr = IAudioClient_Initialize(session->audio_client, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buffer_duration, 0, &wfx, NULL))) + if (FAILED(hr = IAudioClient_Initialize(session->audio_client, AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, buffer_duration, 0, &wfx, NULL))) goto cleanup;
if (FAILED(hr = IAudioClient_SetEventHandle(session->audio_client, session->audio_buf_event)))
From: Giovanni Mascellani gmascellani@codeweavers.com
While it might seem that this change is altering the behavior, it really isn't, because right now Initialize() always does automatic format conversion. So we're just consolidating the current behavior, even if at some point the lack of AUTOCONVERTPCM is properly honored. --- dlls/winmm/waveform.c | 205 ++---------------------------------------- 1 file changed, 5 insertions(+), 200 deletions(-)
diff --git a/dlls/winmm/waveform.c b/dlls/winmm/waveform.c index fa1c446ff91..b0634c75011 100644 --- a/dlls/winmm/waveform.c +++ b/dlls/winmm/waveform.c @@ -878,187 +878,6 @@ static inline BOOL WINMM_IsMapper(UINT device) return (device == WAVE_MAPPER || device == (UINT16)WAVE_MAPPER); }
-static MMRESULT WINMM_TryDeviceMapping(WINMM_Device *device, WAVEFORMATEX *fmt, - WORD channels, DWORD freq, DWORD bits_per_samp, BOOL is_query, BOOL is_out) -{ - WAVEFORMATEX target, *closer_fmt = NULL; - HRESULT hr; - MMRESULT mr; - - TRACE("format: %u, channels: %u, sample rate: %lu, bit depth: %lu\n", - WAVE_FORMAT_PCM, channels, freq, bits_per_samp); - - target.wFormatTag = WAVE_FORMAT_PCM; - target.nChannels = channels; - target.nSamplesPerSec = freq; - target.wBitsPerSample = bits_per_samp; - target.nBlockAlign = (target.nChannels * target.wBitsPerSample) / 8; - target.nAvgBytesPerSec = target.nSamplesPerSec * target.nBlockAlign; - target.cbSize = 0; - - hr = IAudioClient_IsFormatSupported(device->client, - AUDCLNT_SHAREMODE_SHARED, &target, &closer_fmt); - CoTaskMemFree(closer_fmt); - if(hr != S_OK) - return WAVERR_BADFORMAT; - - /* device supports our target format, so see if MSACM can - * do the conversion */ - if(is_out) - mr = acmStreamOpen(&device->acm_handle, NULL, fmt, &target, NULL, - 0, 0, 0); - else - mr = acmStreamOpen(&device->acm_handle, NULL, &target, fmt, NULL, - 0, 0, 0); - if(mr != MMSYSERR_NOERROR) - return mr; - - /* yes it can. initialize the audioclient and return success */ - if(is_query){ - acmStreamClose(device->acm_handle, 0); - device->acm_handle = NULL; - return MMSYSERR_NOERROR; - } - - hr = IAudioClient_Initialize(device->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, - AC_BUFLEN, 0, &target, &device->parent->session); - if(hr != S_OK){ - WARN("Initialize failed: %08lx\n", hr); - acmStreamClose(device->acm_handle, 0); - device->acm_handle = NULL; - return MMSYSERR_ERROR; - } - - device->bytes_per_frame = target.nBlockAlign; - device->samples_per_sec = target.nSamplesPerSec; - - TRACE("Success!\n"); - - return MMSYSERR_NOERROR; -} - -static MMRESULT WINMM_MapDevice(WINMM_Device *device, BOOL is_query, BOOL is_out) -{ - MMRESULT mr; - WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)device->orig_fmt; - - TRACE("(%p, %u)\n", device, is_out); - - /* set up the ACM stream */ - if(device->orig_fmt->wFormatTag != WAVE_FORMAT_PCM && - !(device->orig_fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){ - /* convert to PCM format if it's not already */ - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, - device->orig_fmt->nChannels, device->orig_fmt->nSamplesPerSec, - 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, - device->orig_fmt->nChannels, device->orig_fmt->nSamplesPerSec, - 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - }else{ - WORD channels; - - /* first try just changing bit depth and channels */ - channels = device->orig_fmt->nChannels; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, - device->orig_fmt->nSamplesPerSec, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, - device->orig_fmt->nSamplesPerSec, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - - channels = (channels == 2) ? 1 : 2; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, - device->orig_fmt->nSamplesPerSec, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, - device->orig_fmt->nSamplesPerSec, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - - /* that didn't work, so now try different sample rates */ - channels = device->orig_fmt->nChannels; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 96000, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 48000, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 44100, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 22050, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 11025, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - - channels = (channels == 2) ? 1 : 2; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 96000, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 48000, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 44100, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 22050, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 11025, 16, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - - channels = device->orig_fmt->nChannels; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 96000, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 48000, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 44100, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 22050, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 11025, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - - channels = (channels == 2) ? 1 : 2; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 96000, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 48000, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 44100, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 22050, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - mr = WINMM_TryDeviceMapping(device, device->orig_fmt, channels, 11025, 8, is_query, is_out); - if(mr == MMSYSERR_NOERROR) - return mr; - } - - WARN("Unable to find compatible device!\n"); - return WAVERR_BADFORMAT; -} - static LRESULT WINMM_OpenDevice(WINMM_Device *device, WINMM_OpenInfo *info, BOOL is_out) { @@ -1119,31 +938,17 @@ static LRESULT WINMM_OpenDevice(WINMM_Device *device, WINMM_OpenInfo *info, }
if(info->flags & WAVE_FORMAT_QUERY){ - WAVEFORMATEX *closer_fmt = NULL; - - hr = IAudioClient_IsFormatSupported(device->client, - AUDCLNT_SHAREMODE_SHARED, device->orig_fmt, &closer_fmt); - CoTaskMemFree(closer_fmt); - if((hr == S_FALSE || hr == AUDCLNT_E_UNSUPPORTED_FORMAT) && !(info->flags & WAVE_FORMAT_DIRECT)) - ret = WINMM_MapDevice(device, TRUE, is_out); - else - ret = hr == S_FALSE ? WAVERR_BADFORMAT : hr2mmr(hr); + ret = MMSYSERR_NOERROR; goto error; }
hr = IAudioClient_Initialize(device->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, AC_BUFLEN, 0, device->orig_fmt, &device->parent->session); if(FAILED(hr)){ - if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT && !(info->flags & WAVE_FORMAT_DIRECT)){ - ret = WINMM_MapDevice(device, FALSE, is_out); - if(ret != MMSYSERR_NOERROR || info->flags & WAVE_FORMAT_QUERY) - goto error; - }else{ - WARN("Initialize failed: %08lx\n", hr); - ret = hr2mmr(hr); - goto error; - } + WARN("Initialize failed: %08lx\n", hr); + ret = hr2mmr(hr); + goto error; }else{ device->bytes_per_frame = device->orig_fmt->nBlockAlign; device->samples_per_sec = device->orig_fmt->nSamplesPerSec;
From: Giovanni Mascellani gmascellani@codeweavers.com
Initializing the audio client without AUTOCONVERTPCM is expected to fail when the requested sampling rate or channel count does not match the mixing format. Such behavior is not currently modeled on Wine, but it should be introduced, and since here we expect automatic format conversion to work we add the flag. Consequently we also remove the supported format detection logic. --- dlls/dsound/capture.c | 55 +++++++++++++------------------------------ 1 file changed, 17 insertions(+), 38 deletions(-)
diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c index e9012600cfa..c3f6902c15b 100644 --- a/dlls/dsound/capture.c +++ b/dlls/dsound/capture.c @@ -744,7 +744,8 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( }
err = IAudioClient_Initialize(device->client, - AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST + | AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM, 200 * 100000, 0, device->pwfx, NULL); if(FAILED(err)){ WARN("Initialize failed: %08lx\n", err); @@ -965,43 +966,24 @@ static DWORD WINAPI DSOUND_capture_thread(void *user) return 0; }
-static struct _TestFormat { - DWORD flag; - DWORD rate; - DWORD depth; - WORD channels; -} formats_to_test[] = { - { WAVE_FORMAT_1M08, 11025, 8, 1 }, - { WAVE_FORMAT_1M16, 11025, 16, 1 }, - { WAVE_FORMAT_1S08, 11025, 8, 2 }, - { WAVE_FORMAT_1S16, 11025, 16, 2 }, - { WAVE_FORMAT_2M08, 22050, 8, 1 }, - { WAVE_FORMAT_2M16, 22050, 16, 1 }, - { WAVE_FORMAT_2S08, 22050, 8, 2 }, - { WAVE_FORMAT_2S16, 22050, 16, 2 }, - { WAVE_FORMAT_4M08, 44100, 8, 1 }, - { WAVE_FORMAT_4M16, 44100, 16, 1 }, - { WAVE_FORMAT_4S08, 44100, 8, 2 }, - { WAVE_FORMAT_4S16, 44100, 16, 2 }, - { WAVE_FORMAT_48M08, 48000, 8, 1 }, - { WAVE_FORMAT_48M16, 48000, 16, 1 }, - { WAVE_FORMAT_48S08, 48000, 8, 2 }, - { WAVE_FORMAT_48S16, 48000, 16, 2 }, - { WAVE_FORMAT_96M08, 96000, 8, 1 }, - { WAVE_FORMAT_96M16, 96000, 16, 1 }, - { WAVE_FORMAT_96S08, 96000, 8, 2 }, - { WAVE_FORMAT_96S16, 96000, 16, 2 }, - {0} -}; - static HRESULT DirectSoundCaptureDevice_Initialize( DirectSoundCaptureDevice ** ppDevice, LPCGUID lpcGUID) { + static const DWORD all_formats = + WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | + WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | + WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | + WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | + WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | + WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | + WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | + WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | + WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | + WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16; HRESULT hr; GUID devGUID; IMMDevice *mmdevice; - struct _TestFormat *fmt; DirectSoundCaptureDevice *device; IAudioClient *client;
@@ -1047,13 +1029,10 @@ static HRESULT DirectSoundCaptureDevice_Initialize( return DSERR_NODRIVER; }
- for(fmt = formats_to_test; fmt->flag; ++fmt){ - if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){ - device->drvcaps.dwFormats |= fmt->flag; - if(fmt->channels > device->drvcaps.dwChannels) - device->drvcaps.dwChannels = fmt->channels; - } - } + /* We use AUTOCONVERTPCM, so all formats are supported. */ + device->drvcaps.dwFormats = all_formats; + device->drvcaps.dwChannels = 2; + IAudioClient_Release(client);
*ppDevice = device;
As it often happens, test failures don't seem to be related to my MR, and also happen on other MRs.
This merge request was approved by Huw Davies.