From 75b57ea13de48994d29401afebbbe534cd503b86 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 23 Nov 2021 07:54:58 +0000 Subject: [PATCH] winecoreaudio: Move is_format_supported to the unixlib. Signed-off-by: Huw Davies Signed-off-by: Andrew Eikum Signed-off-by: Alexandre Julliard --- dlls/winecoreaudio.drv/coreaudio.c | 65 ++++++++ dlls/winecoreaudio.drv/mmdevdrv.c | 255 ++--------------------------- dlls/winecoreaudio.drv/unixlib.h | 11 ++ 3 files changed, 91 insertions(+), 240 deletions(-) diff --git a/dlls/winecoreaudio.drv/coreaudio.c b/dlls/winecoreaudio.drv/coreaudio.c index 208655d20c6..f7f7777efcb 100644 --- a/dlls/winecoreaudio.drv/coreaudio.c +++ b/dlls/winecoreaudio.drv/coreaudio.c @@ -948,10 +948,75 @@ static NTSTATUS get_mix_format(void *args) return STATUS_SUCCESS; } +static NTSTATUS is_format_supported(void *args) +{ + struct is_format_supported_params *params = args; + const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)params->fmt_in; + AudioStreamBasicDescription dev_desc; + AudioConverterRef converter; + AudioComponentInstance unit; + + params->result = S_OK; + + if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out)) + params->result = E_POINTER; + else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE) + params->result = E_INVALIDARG; + else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ + if(params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) + params->result = E_INVALIDARG; + else if(params->fmt_in->nAvgBytesPerSec == 0 || params->fmt_in->nBlockAlign == 0 || + fmtex->Samples.wValidBitsPerSample > params->fmt_in->wBitsPerSample) + params->result = E_INVALIDARG; + else if(fmtex->Samples.wValidBitsPerSample < params->fmt_in->wBitsPerSample) + goto unsupported; + else if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE && + (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)) + goto unsupported; + } + if(FAILED(params->result)) return STATUS_SUCCESS; + + if(params->fmt_in->nBlockAlign != params->fmt_in->nChannels * params->fmt_in->wBitsPerSample / 8 || + params->fmt_in->nAvgBytesPerSec != params->fmt_in->nBlockAlign * params->fmt_in->nSamplesPerSec) + goto unsupported; + + if(params->fmt_in->nChannels == 0){ + params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; + return STATUS_SUCCESS; + } + unit = get_audiounit(params->flow, params->dev_id); + + converter = NULL; + params->result = ca_setup_audiounit(params->flow, unit, params->fmt_in, &dev_desc, &converter); + AudioComponentInstanceDispose(unit); + if(FAILED(params->result)) goto unsupported; + if(converter) AudioConverterDispose(converter); + + params->result = S_OK; + return STATUS_SUCCESS; + +unsupported: + if(params->fmt_out){ + struct get_mix_format_params get_mix_params = + { + .flow = params->flow, + .dev_id = params->dev_id, + .fmt = params->fmt_out, + }; + + get_mix_format(&get_mix_params); + params->result = get_mix_params.result; + if(SUCCEEDED(params->result)) params->result = S_FALSE; + } + else params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; + return STATUS_SUCCESS; +} + unixlib_entry_t __wine_unix_call_funcs[] = { get_endpoint_ids, create_stream, release_stream, get_mix_format, + is_format_supported, }; diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c index 2ad2938a5d8..418bbfa00af 100644 --- a/dlls/winecoreaudio.drv/mmdevdrv.c +++ b/dlls/winecoreaudio.drv/mmdevdrv.c @@ -473,62 +473,6 @@ static BOOL get_deviceid_by_guid(GUID *guid, AudioDeviceID *id, EDataFlow *flow) return FALSE; } -static AudioComponentInstance get_audiounit(EDataFlow dataflow, AudioDeviceID adevid) -{ - AudioComponentInstance unit; - AudioComponent comp; - AudioComponentDescription desc; - OSStatus sc; - - memset(&desc, 0, sizeof(desc)); - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_HALOutput; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - - if(!(comp = AudioComponentFindNext(NULL, &desc))){ - WARN("AudioComponentFindNext failed\n"); - return NULL; - } - - sc = AudioComponentInstanceNew(comp, &unit); - if(sc != noErr){ - WARN("AudioComponentInstanceNew failed: %x\n", (int)sc); - return NULL; - } - - if(dataflow == eCapture){ - UInt32 enableio; - - enableio = 1; - sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, 1, &enableio, sizeof(enableio)); - if(sc != noErr){ - WARN("Couldn't enable I/O on input element: %x\n", (int)sc); - AudioComponentInstanceDispose(unit); - return NULL; - } - - enableio = 0; - sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, 0, &enableio, sizeof(enableio)); - if(sc != noErr){ - WARN("Couldn't disable I/O on output element: %x\n", (int)sc); - AudioComponentInstanceDispose(unit); - return NULL; - } - } - - sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, &adevid, sizeof(adevid)); - if(sc != noErr){ - WARN("Couldn't set audio unit device\n"); - AudioComponentInstanceDispose(unit); - return NULL; - } - - return unit; -} - HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out) { ACImpl *This; @@ -689,46 +633,6 @@ static void dump_fmt(const WAVEFORMATEX *fmt) } } -static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc, - const WAVEFORMATEX *fmt) -{ - const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt; - - desc->mFormatFlags = 0; - - if(fmt->wFormatTag == WAVE_FORMAT_PCM || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){ - desc->mFormatID = kAudioFormatLinearPCM; - if(fmt->wBitsPerSample > 8) - desc->mFormatFlags = kAudioFormatFlagIsSignedInteger; - }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){ - desc->mFormatID = kAudioFormatLinearPCM; - desc->mFormatFlags = kAudioFormatFlagIsFloat; - }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){ - desc->mFormatID = kAudioFormatULaw; - }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){ - desc->mFormatID = kAudioFormatALaw; - }else - return AUDCLNT_E_UNSUPPORTED_FORMAT; - - desc->mSampleRate = fmt->nSamplesPerSec; - desc->mBytesPerPacket = fmt->nBlockAlign; - desc->mFramesPerPacket = 1; - desc->mBytesPerFrame = fmt->nBlockAlign; - desc->mChannelsPerFrame = fmt->nChannels; - desc->mBitsPerChannel = fmt->wBitsPerSample; - desc->mReserved = 0; - - return S_OK; -} - static void session_init_vols(AudioSession *session, UINT channels) { if(session->channel_count < channels){ @@ -931,90 +835,6 @@ static void capture_resample(ACImpl *This) } } -static void dump_adesc(const char *aux, AudioStreamBasicDescription *desc) -{ - TRACE("%s: mSampleRate: %f\n", aux, desc->mSampleRate); - TRACE("%s: mBytesPerPacket: %u\n", aux, (unsigned int)desc->mBytesPerPacket); - TRACE("%s: mFramesPerPacket: %u\n", aux, (unsigned int)desc->mFramesPerPacket); - TRACE("%s: mBytesPerFrame: %u\n", aux, (unsigned int)desc->mBytesPerFrame); - TRACE("%s: mChannelsPerFrame: %u\n", aux, (unsigned int)desc->mChannelsPerFrame); - TRACE("%s: mBitsPerChannel: %u\n", aux, (unsigned int)desc->mBitsPerChannel); -} - -static HRESULT ca_setup_audiounit(EDataFlow dataflow, AudioComponentInstance unit, - const WAVEFORMATEX *fmt, AudioStreamBasicDescription *dev_desc, - AudioConverterRef *converter) -{ - OSStatus sc; - HRESULT hr; - - if(dataflow == eCapture){ - AudioStreamBasicDescription desc; - UInt32 size; - Float64 rate; - fenv_t fenv; - BOOL fenv_stored = TRUE; - - hr = ca_get_audiodesc(&desc, fmt); - if(FAILED(hr)) - return hr; - dump_adesc("requested", &desc); - - /* input-only units can't perform sample rate conversion, so we have to - * set up our own AudioConverter to support arbitrary sample rates. */ - size = sizeof(*dev_desc); - sc = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 1, dev_desc, &size); - if(sc != noErr){ - WARN("Couldn't get unit format: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - dump_adesc("hardware", dev_desc); - - rate = dev_desc->mSampleRate; - *dev_desc = desc; - dev_desc->mSampleRate = rate; - - dump_adesc("final", dev_desc); - sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, dev_desc, sizeof(*dev_desc)); - if(sc != noErr){ - WARN("Couldn't set unit format: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - - /* AudioConverterNew requires divide-by-zero SSE exceptions to be masked */ - if(feholdexcept(&fenv)){ - WARN("Failed to store fenv state\n"); - fenv_stored = FALSE; - } - - sc = AudioConverterNew(dev_desc, &desc, converter); - - if(fenv_stored && fesetenv(&fenv)) - WARN("Failed to restore fenv state\n"); - - if(sc != noErr){ - WARN("Couldn't create audio converter: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - }else{ - hr = ca_get_audiodesc(dev_desc, fmt); - if(FAILED(hr)) - return hr; - - dump_adesc("final", dev_desc); - sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, dev_desc, sizeof(*dev_desc)); - if(sc != noErr){ - WARN("Couldn't set format: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - } - - return S_OK; -} - static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration, REFERENCE_TIME period, const WAVEFORMATEX *fmt, @@ -1298,75 +1118,30 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface, WAVEFORMATEX **outpwfx) { ACImpl *This = impl_from_IAudioClient3(iface); - AudioStreamBasicDescription dev_desc; - AudioConverterRef converter; - AudioComponentInstance unit; - WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)pwfx; - HRESULT hr; + struct is_format_supported_params params; TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx); + if(pwfx) dump_fmt(pwfx); - if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx)) - return E_POINTER; - - if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) - return E_INVALIDARG; - - if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) - return E_INVALIDARG; - - dump_fmt(pwfx); + params.dev_id = This->adevid; + params.flow = This->dataflow; + params.share = mode; + params.fmt_in = pwfx; + params.fmt_out = NULL; if(outpwfx){ *outpwfx = NULL; - if(mode != AUDCLNT_SHAREMODE_SHARED) - outpwfx = NULL; + if(mode == AUDCLNT_SHAREMODE_SHARED) + params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out)); } + UNIX_CALL(is_format_supported, ¶ms); - if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - if(pwfx->nAvgBytesPerSec == 0 || - pwfx->nBlockAlign == 0 || - fmtex->Samples.wValidBitsPerSample > pwfx->wBitsPerSample) - return E_INVALIDARG; - if(fmtex->Samples.wValidBitsPerSample < pwfx->wBitsPerSample) - goto unsupported; - if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE){ - if(fmtex->dwChannelMask == 0 || - fmtex->dwChannelMask & SPEAKER_RESERVED) - goto unsupported; - } - } + if(params.result == S_FALSE) + *outpwfx = ¶ms.fmt_out->Format; + else + CoTaskMemFree(params.fmt_out); - if(pwfx->nBlockAlign != pwfx->nChannels * pwfx->wBitsPerSample / 8 || - pwfx->nAvgBytesPerSec != pwfx->nBlockAlign * pwfx->nSamplesPerSec) - goto unsupported; - - if(pwfx->nChannels == 0) - return AUDCLNT_E_UNSUPPORTED_FORMAT; - - unit = get_audiounit(This->dataflow, This->adevid); - - converter = NULL; - hr = ca_setup_audiounit(This->dataflow, unit, pwfx, &dev_desc, &converter); - AudioComponentInstanceDispose(unit); - if(FAILED(hr)) - goto unsupported; - - if(converter) - AudioConverterDispose(converter); - - return S_OK; - -unsupported: - if(outpwfx){ - hr = IAudioClient3_GetMixFormat(&This->IAudioClient3_iface, outpwfx); - if(FAILED(hr)) - return hr; - return S_FALSE; - } - - return AUDCLNT_E_UNSUPPORTED_FORMAT; + return params.result; } static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, diff --git a/dlls/winecoreaudio.drv/unixlib.h b/dlls/winecoreaudio.drv/unixlib.h index e247b789d55..23de92ecfdd 100644 --- a/dlls/winecoreaudio.drv/unixlib.h +++ b/dlls/winecoreaudio.drv/unixlib.h @@ -83,12 +83,23 @@ struct get_mix_format_params HRESULT result; }; +struct is_format_supported_params +{ + EDataFlow flow; + DWORD dev_id; + AUDCLNT_SHAREMODE share; + const WAVEFORMATEX *fmt_in; + WAVEFORMATEXTENSIBLE *fmt_out; + HRESULT result; +}; + enum unix_funcs { unix_get_endpoint_ids, unix_create_stream, unix_release_stream, unix_get_mix_format, + unix_is_format_supported, }; extern unixlib_handle_t coreaudio_handle;