[PATCH 1/4] xaudio2: Implement device activation
Matt Durgavich
mattdurgavich at gmail.com
Fri Aug 28 20:51:24 CDT 2015
Looks like it is too late :(
This appears to break the build on OSX. Any idea for when a patch will arrive?
-Matt
> On Aug 24, 2015, at 3:29 PM, Andrew Eikum <aeikum at codeweavers.com> wrote:
>
> Please don't merge these patches. I got some feedback on IRC and will
> be sending improved versions.
>
> Andrew
>
> On Mon, Aug 24, 2015 at 10:31:36AM -0500, Andrew Eikum wrote:
>> This adds a build-time dependency on openal, and a run-time dependency
>> on openal-soft's ALC_SOFT_loopback extension.
>>
>> ---
>> configure.ac | 3 +-
>> dlls/xaudio2_7/Makefile.in | 1 +
>> dlls/xaudio2_7/xaudio_dll.c | 274 +++++++++++++++++++++++++++++++++++++++++++-
>> 3 files changed, 274 insertions(+), 4 deletions(-)
>>
>> diff --git a/configure.ac b/configure.ac
>> index 004e79d..dea394f 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -1738,8 +1738,9 @@ then
>> AC_DEFINE_UNQUOTED(HAVE_OPENAL,1,[Define to 1 if OpenAL is available])],,)
>> fi
>> WINE_NOTICE_WITH(openal,[test "x$ac_cv_lib_openal" != xyes],
>> - [libopenal ${notice_platform}development files not found (or too old), OpenAL won't be supported.])
>> + [libopenal ${notice_platform}development files not found (or too old), OpenAL and XAudio2 won't be supported])
>> test "x$ac_cv_lib_openal" = xyes || enable_openal32=${enable_openal32:-no}
>> +test "x$ac_cv_lib_openal" = xyes || enable_xaudio2_7=${enable_xaudio2_7:-no}
>>
>> dnl **** Check for libkstat ****
>> if test "$ac_cv_header_kstat_h" = "yes"
>> diff --git a/dlls/xaudio2_7/Makefile.in b/dlls/xaudio2_7/Makefile.in
>> index 6bdf362..5a09c82 100644
>> --- a/dlls/xaudio2_7/Makefile.in
>> +++ b/dlls/xaudio2_7/Makefile.in
>> @@ -1,5 +1,6 @@
>> MODULE = xaudio2_7.dll
>> IMPORTS = advapi32 kernel32 ole32 user32 uuid
>> +EXTRALIBS = $(OPENAL_LIBS)
>>
>> C_SRCS = \
>> xaudio_dll.c
>> diff --git a/dlls/xaudio2_7/xaudio_dll.c b/dlls/xaudio2_7/xaudio_dll.c
>> index 6bb48e6..95740fa 100644
>> --- a/dlls/xaudio2_7/xaudio_dll.c
>> +++ b/dlls/xaudio2_7/xaudio_dll.c
>> @@ -41,8 +41,14 @@
>> #include "mmdeviceapi.h"
>> #include "audioclient.h"
>>
>> +#include <AL/al.h>
>> +#include <AL/alc.h>
>> +#include <AL/alext.h>
>> +
>> WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
>>
>> +static ALCdevice *(ALC_APIENTRY *palcLoopbackOpenDeviceSOFT)(const ALCchar*);
>> +
>> static HINSTANCE instance;
>>
>> static void dump_fmt(const WAVEFORMATEX *fmt)
>> @@ -86,6 +92,13 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, void *pReserved)
>> case DLL_PROCESS_ATTACH:
>> instance = hinstDLL;
>> DisableThreadLibraryCalls( hinstDLL );
>> +
>> + if(!alcIsExtensionPresent(NULL, "ALC_SOFT_loopback") ||
>> + !(palcLoopbackOpenDeviceSOFT = alGetProcAddress("alcLoopbackOpenDeviceSOFT"))){
>> + ERR("XAudio2 requires the ALC_SOFT_loopback extension (OpenAL-Soft >= 1.14)\n");
>> + return FALSE;
>> + }
>> +
>> break;
>> }
>> return TRUE;
>> @@ -173,6 +186,14 @@ struct _IXAudio2Impl {
>>
>> WCHAR **devids;
>> UINT32 ndevs;
>> +
>> + IAudioClient *aclient;
>> + IAudioRenderClient *render;
>> +
>> + WAVEFORMATEXTENSIBLE fmt;
>> +
>> + ALCdevice *al_device;
>> + ALCcontext *al_ctx;
>> };
>>
>> static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
>> @@ -190,6 +211,32 @@ IXAudio2Impl *impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice *iface)
>> return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2MasteringVoice_iface);
>> }
>>
>> +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 void WINAPI XA2SRC_GetVoiceDetails(IXAudio2SourceVoice *iface,
>> XAUDIO2_VOICE_DETAILS *pVoiceDetails)
>> {
>> @@ -891,7 +938,29 @@ static void WINAPI XA2M_GetOutputMatrix(IXAudio2MasteringVoice *iface,
>> static void WINAPI XA2M_DestroyVoice(IXAudio2MasteringVoice *iface)
>> {
>> IXAudio2Impl *This = impl_from_IXAudio2MasteringVoice(iface);
>> +
>> TRACE("%p\n", This);
>> +
>> + EnterCriticalSection(&This->lock);
>> +
>> + if(!This->aclient){
>> + LeaveCriticalSection(&This->lock);
>> + return;
>> + }
>> +
>> + IAudioRenderClient_Release(This->render);
>> + This->render = NULL;
>> +
>> + IAudioClient_Release(This->aclient);
>> + This->aclient = NULL;
>> +
>> + alcCloseDevice(This->al_device);
>> + This->al_device = NULL;
>> +
>> + alcDestroyContext(This->al_ctx);
>> + This->al_ctx = NULL;
>> +
>> + LeaveCriticalSection(&This->lock);
>> }
>>
>> /* not present in XAudio2 2.7 */
>> @@ -1164,6 +1233,8 @@ static ULONG WINAPI IXAudio2Impl_Release(IXAudio2 *iface)
>> HeapFree(GetProcessHeap(), 0, sub);
>> }
>>
>> + IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
>> +
>> if(This->devenum)
>> IMMDeviceEnumerator_Release(This->devenum);
>> for(i = 0; i < This->ndevs; ++i)
>> @@ -1322,6 +1393,28 @@ static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
>> return S_OK;
>> }
>>
>> +static ALenum al_get_loopback_format(const WAVEFORMATEXTENSIBLE *fmt)
>> +{
>> + if(fmt->Format.wFormatTag == WAVE_FORMAT_PCM ||
>> + (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
>> + IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
>> + switch(fmt->Format.wBitsPerSample){
>> + case 8:
>> + return AL_UNSIGNED_BYTE_SOFT;
>> + case 16:
>> + return AL_SHORT_SOFT;
>> + case 32:
>> + return AL_INT_SOFT;
>> + }
>> + }else if(fmt->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
>> + (fmt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
>> + IsEqualGUID(&fmt->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
>> + if(fmt->Format.wBitsPerSample == 32)
>> + return AL_FLOAT_SOFT;
>> + }
>> + return 0;
>> +}
>> +
>> static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
>> IXAudio2MasteringVoice **ppMasteringVoice, UINT32 inputChannels,
>> UINT32 inputSampleRate, UINT32 flags, const WCHAR *deviceId,
>> @@ -1329,8 +1422,12 @@ static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
>> AUDIO_STREAM_CATEGORY streamCategory)
>> {
>> IXAudio2Impl *This = impl_from_IXAudio2(iface);
>> + IMMDevice *dev;
>> + HRESULT hr;
>> + WAVEFORMATEX *fmt;
>> + ALCint attrs[7];
>>
>> - FIXME("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x): stub!\n", This,
>> + TRACE("(%p)->(%p, %u, %u, 0x%x, %s, %p, 0x%x)\n", This,
>> ppMasteringVoice, inputChannels, inputSampleRate, flags,
>> wine_dbgstr_w(deviceId), pEffectChain, streamCategory);
>>
>> @@ -1340,12 +1437,183 @@ static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
>> if(pEffectChain)
>> WARN("Effect chain is unimplemented\n");
>>
>> - /* TODO: Initialize mmdevice */
>> + EnterCriticalSection(&This->lock);
>>
>> /* there can only be one Mastering Voice, so just build it into XA2 */
>> + if(This->aclient){
>> + LeaveCriticalSection(&This->lock);
>> + return XAUDIO2_E_INVALID_CALL;
>> + }
>> +
>> + if(!deviceId){
>> + if(This->ndevs == 0){
>> + LeaveCriticalSection(&This->lock);
>> + return ERROR_NOT_FOUND;
>> + }
>> + deviceId = This->devids[0];
>> + }
>> +
>> + hr = IMMDeviceEnumerator_GetDevice(This->devenum, deviceId, &dev);
>> + if(FAILED(hr)){
>> + WARN("GetDevice failed: %08x\n", hr);
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + hr = IMMDevice_Activate(dev, &IID_IAudioClient,
>> + CLSCTX_INPROC_SERVER, NULL, (void**)&This->aclient);
>> + if(FAILED(hr)){
>> + WARN("Activate(IAudioClient) failed: %08x\n", hr);
>> + IMMDevice_Release(dev);
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + IMMDevice_Release(dev);
>> +
>> + hr = IAudioClient_GetMixFormat(This->aclient, &fmt);
>> + if(FAILED(hr)){
>> + WARN("GetMixFormat failed: %08x\n", hr);
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
>> + FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + if(inputChannels == XAUDIO2_DEFAULT_CHANNELS)
>> + inputChannels = fmt->nChannels;
>> + if(inputSampleRate == XAUDIO2_DEFAULT_SAMPLERATE)
>> + inputSampleRate = fmt->nSamplesPerSec;
>> +
>> + memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
>> + This->fmt.Format.nChannels = inputChannels;
>> + This->fmt.Format.nSamplesPerSec = inputSampleRate;
>> + This->fmt.Format.nBlockAlign = This->fmt.Format.nChannels * This->fmt.Format.wBitsPerSample / 8;
>> + This->fmt.Format.nAvgBytesPerSec = This->fmt.Format.nSamplesPerSec * This->fmt.Format.nBlockAlign;
>> + This->fmt.dwChannelMask = get_channel_mask(This->fmt.Format.nChannels);
>> +
>> + CoTaskMemFree(fmt);
>> + fmt = NULL;
>> +
>> + hr = IAudioClient_IsFormatSupported(This->aclient,
>> + AUDCLNT_SHAREMODE_SHARED, &This->fmt.Format, &fmt);
>> + if(hr == S_FALSE){
>> + if(sizeof(WAVEFORMATEX) + fmt->cbSize > sizeof(WAVEFORMATEXTENSIBLE)){
>> + FIXME("Mix format doesn't fit into WAVEFORMATEXTENSIBLE!\n");
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> + memcpy(&This->fmt, fmt, sizeof(WAVEFORMATEX) + fmt->cbSize);
>> + }
>> +
>> + CoTaskMemFree(fmt);
>> +
>> + hr = IAudioClient_Initialize(This->aclient, AUDCLNT_SHAREMODE_SHARED,
>> + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, inputSampleRate /* 1s buffer */,
>> + 0, &This->fmt.Format, NULL);
>> + if(FAILED(hr)){
>> + WARN("Initialize failed: %08x\n", hr);
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + hr = IAudioClient_GetService(This->aclient, &IID_IAudioRenderClient,
>> + (void**)&This->render);
>> + if(FAILED(hr)){
>> + WARN("GetService(IAudioRenderClient) failed: %08x\n", hr);
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + /* setup openal context */
>> + attrs[0] = ALC_FORMAT_CHANNELS_SOFT;
>> + switch(inputChannels){
>> + case 1:
>> + attrs[1] = ALC_MONO_SOFT;
>> + break;
>> + case 2:
>> + attrs[1] = ALC_STEREO_SOFT;
>> + break;
>> + case 4:
>> + attrs[1] = ALC_QUAD_SOFT;
>> + break;
>> + case 6:
>> + attrs[1] = ALC_5POINT1_SOFT;
>> + break;
>> + case 7:
>> + attrs[1] = ALC_6POINT1_SOFT;
>> + break;
>> + case 8:
>> + attrs[1] = ALC_7POINT1_SOFT;
>> + break;
>> + default:
>> + WARN("OpenAL doesn't support %u channels\n", inputChannels);
>> + LeaveCriticalSection(&This->lock);
>> + return AUDCLNT_E_UNSUPPORTED_FORMAT;
>> + }
>> + attrs[2] = ALC_FREQUENCY;
>> + attrs[3] = inputSampleRate;
>> + attrs[4] = ALC_FORMAT_TYPE_SOFT;
>> + attrs[5] = al_get_loopback_format(&This->fmt);
>> + attrs[6] = 0;
>> +
>> + if(!attrs[5]){
>> + WARN("OpenAL can't output samples in this format\n");
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + This->al_device = palcLoopbackOpenDeviceSOFT(NULL);
>> + if(!This->al_device){
>> + WARN("alcLoopbackOpenDeviceSOFT failed\n");
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + This->al_ctx = alcCreateContext(This->al_device, attrs);
>> + if(!This->al_ctx){
>> + WARN("alcCreateContext failed\n");
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + if(alcMakeContextCurrent(This->al_ctx) == ALC_FALSE){
>> + WARN("alcMakeContextCurrent failed\n");
>> + hr = XAUDIO2_E_DEVICE_INVALIDATED;
>> + goto exit;
>> + }
>> +
>> + IAudioClient_Start(This->aclient);
>> +
>> *ppMasteringVoice = &This->IXAudio2MasteringVoice_iface;
>>
>> - return S_OK;
>> +exit:
>> + if(FAILED(hr)){
>> + if(This->render){
>> + IAudioRenderClient_Release(This->render);
>> + This->render = NULL;
>> + }
>> + if(This->aclient){
>> + IAudioClient_Release(This->aclient);
>> + This->aclient = NULL;
>> + }
>> + if(This->al_ctx){
>> + alcDestroyContext(This->al_ctx);
>> + This->al_ctx = NULL;
>> + }
>> + if(This->al_device){
>> + alcCloseDevice(This->al_device);
>> + This->al_device = NULL;
>> + }
>> + }
>> +
>> + LeaveCriticalSection(&This->lock);
>> +
>> + return hr;
>> }
>>
>> static HRESULT WINAPI IXAudio2Impl_StartEngine(IXAudio2 *iface)
>> --
>> 2.5.0
>>
>>
>>
>>
>
>
More information about the wine-devel
mailing list