mmdevapi: Reimplement using a driver system.
This commit is contained in:
parent
30b8d046ba
commit
5014099928
|
@ -1,9 +1,7 @@
|
|||
MODULE = mmdevapi.dll
|
||||
IMPORTS = uuid ole32 oleaut32 user32 advapi32
|
||||
EXTRALIBS = @FRAMEWORK_OPENAL@
|
||||
|
||||
C_SRCS = \
|
||||
audio.c \
|
||||
audiovolume.c \
|
||||
devenum.c \
|
||||
main.c
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 2008 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#ifndef AL_ALEXT_H
|
||||
#define AL_ALEXT_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef AL_LOKI_IMA_ADPCM_format
|
||||
#define AL_LOKI_IMA_ADPCM_format 1
|
||||
#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000
|
||||
#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001
|
||||
#endif
|
||||
|
||||
#ifndef AL_LOKI_WAVE_format
|
||||
#define AL_LOKI_WAVE_format 1
|
||||
#define AL_FORMAT_WAVE_EXT 0x10002
|
||||
#endif
|
||||
|
||||
#ifndef AL_EXT_vorbis
|
||||
#define AL_EXT_vorbis 1
|
||||
#define AL_FORMAT_VORBIS_EXT 0x10003
|
||||
#endif
|
||||
|
||||
#ifndef AL_LOKI_quadriphonic
|
||||
#define AL_LOKI_quadriphonic 1
|
||||
#define AL_FORMAT_QUAD8_LOKI 0x10004
|
||||
#define AL_FORMAT_QUAD16_LOKI 0x10005
|
||||
#endif
|
||||
|
||||
#ifndef AL_EXT_float32
|
||||
#define AL_EXT_float32 1
|
||||
#define AL_FORMAT_MONO_FLOAT32 0x10010
|
||||
#define AL_FORMAT_STEREO_FLOAT32 0x10011
|
||||
#endif
|
||||
|
||||
#ifndef AL_EXT_double
|
||||
#define AL_EXT_double 1
|
||||
#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012
|
||||
#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013
|
||||
#endif
|
||||
|
||||
#ifndef ALC_LOKI_audio_channel
|
||||
#define ALC_LOKI_audio_channel 1
|
||||
#define ALC_CHAN_MAIN_LOKI 0x500001
|
||||
#define ALC_CHAN_PCM_LOKI 0x500002
|
||||
#define ALC_CHAN_CD_LOKI 0x500003
|
||||
#endif
|
||||
|
||||
#ifndef ALC_ENUMERATE_ALL_EXT
|
||||
#define ALC_ENUMERATE_ALL_EXT 1
|
||||
#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
|
||||
#define ALC_ALL_DEVICES_SPECIFIER 0x1013
|
||||
#endif
|
||||
|
||||
#ifndef AL_EXT_MCFORMATS
|
||||
#define AL_EXT_MCFORMATS 1
|
||||
#define AL_FORMAT_QUAD8 0x1204
|
||||
#define AL_FORMAT_QUAD16 0x1205
|
||||
#define AL_FORMAT_QUAD32 0x1206
|
||||
#define AL_FORMAT_REAR8 0x1207
|
||||
#define AL_FORMAT_REAR16 0x1208
|
||||
#define AL_FORMAT_REAR32 0x1209
|
||||
#define AL_FORMAT_51CHN8 0x120A
|
||||
#define AL_FORMAT_51CHN16 0x120B
|
||||
#define AL_FORMAT_51CHN32 0x120C
|
||||
#define AL_FORMAT_61CHN8 0x120D
|
||||
#define AL_FORMAT_61CHN16 0x120E
|
||||
#define AL_FORMAT_61CHN32 0x120F
|
||||
#define AL_FORMAT_71CHN8 0x1210
|
||||
#define AL_FORMAT_71CHN16 0x1211
|
||||
#define AL_FORMAT_71CHN32 0x1212
|
||||
#endif
|
||||
|
||||
#ifndef AL_EXT_MULAW_MCFORMATS
|
||||
#define AL_EXT_MULAW_MCFORMATS 1
|
||||
#define AL_FORMAT_MONO_MULAW 0x10014
|
||||
#define AL_FORMAT_STEREO_MULAW 0x10015
|
||||
#define AL_FORMAT_QUAD_MULAW 0x10021
|
||||
#define AL_FORMAT_REAR_MULAW 0x10022
|
||||
#define AL_FORMAT_51CHN_MULAW 0x10023
|
||||
#define AL_FORMAT_61CHN_MULAW 0x10024
|
||||
#define AL_FORMAT_71CHN_MULAW 0x10025
|
||||
#endif
|
||||
|
||||
#ifndef AL_EXT_IMA4
|
||||
#define AL_EXT_IMA4 1
|
||||
#define AL_FORMAT_MONO_IMA4 0x1300
|
||||
#define AL_FORMAT_STEREO_IMA4 0x1301
|
||||
#endif
|
||||
|
||||
#ifndef AL_EXT_STATIC_BUFFER
|
||||
#define AL_EXT_STATIC_BUFFER 1
|
||||
typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei);
|
||||
#ifdef AL_ALEXT_PROTOTYPES
|
||||
AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ALC_EXT_disconnect
|
||||
#define ALC_EXT_disconnect 1
|
||||
#define ALC_CONNECTED 0x313
|
||||
#endif
|
||||
|
||||
#ifndef ALC_EXT_thread_local_context
|
||||
#define ALC_EXT_thread_local_context 1
|
||||
typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context);
|
||||
typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void);
|
||||
#ifdef AL_ALEXT_PROTOTYPES
|
||||
ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context);
|
||||
ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AL_EXT_source_distance_model
|
||||
#define AL_EXT_source_distance_model 1
|
||||
#define AL_SOURCE_DISTANCE_MODEL 0x200
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -22,13 +22,6 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#ifdef HAVE_AL_AL_H
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#elif defined(HAVE_OPENAL_AL_H)
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#endif
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
@ -49,8 +42,6 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
|
||||
|
||||
#ifdef HAVE_OPENAL
|
||||
|
||||
static const IAudioEndpointVolumeExVtbl AEVImpl_Vtbl;
|
||||
|
||||
typedef struct AEVImpl {
|
||||
|
@ -297,5 +288,3 @@ static const IAudioEndpointVolumeExVtbl AEVImpl_Vtbl = {
|
|||
AEV_GetVolumeRange,
|
||||
AEV_GetVolumeRangeChannel
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,14 +20,6 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_AL_AL_H
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#elif defined(HAVE_OPENAL_AL_H)
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#endif
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define COBJMACROS
|
||||
#include "windef.h"
|
||||
|
@ -267,7 +259,7 @@ static HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERT
|
|||
* If GUID is null, a random guid will be assigned
|
||||
* and the device will be created
|
||||
*/
|
||||
static void MMDevice_Create(MMDevice **dev, WCHAR *name, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault)
|
||||
static MMDevice *MMDevice_Create(WCHAR *name, void *devkey, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault)
|
||||
{
|
||||
HKEY key, root;
|
||||
MMDevice *cur;
|
||||
|
@ -277,11 +269,12 @@ static void MMDevice_Create(MMDevice **dev, WCHAR *name, GUID *id, EDataFlow flo
|
|||
for (i = 0; i < MMDevice_count; ++i)
|
||||
{
|
||||
cur = MMDevice_head[i];
|
||||
if (cur->flow == flow && !lstrcmpW(cur->alname, name))
|
||||
if (cur->flow == flow && !lstrcmpW(cur->drv_id, name))
|
||||
{
|
||||
LONG ret;
|
||||
/* Same device, update state */
|
||||
cur->state = state;
|
||||
cur->key = devkey;
|
||||
StringFromGUID2(&cur->devguid, guidstr, sizeof(guidstr)/sizeof(*guidstr));
|
||||
ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, guidstr, 0, KEY_WRITE, &key);
|
||||
if (ret == ERROR_SUCCESS)
|
||||
|
@ -295,15 +288,19 @@ static void MMDevice_Create(MMDevice **dev, WCHAR *name, GUID *id, EDataFlow flo
|
|||
|
||||
/* No device found, allocate new one */
|
||||
cur = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur));
|
||||
if (!cur)
|
||||
return;
|
||||
cur->alname = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name)+1)*sizeof(WCHAR));
|
||||
if (!cur->alname)
|
||||
if (!cur){
|
||||
HeapFree(GetProcessHeap(), 0, devkey);
|
||||
return NULL;
|
||||
}
|
||||
cur->drv_id = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name)+1)*sizeof(WCHAR));
|
||||
if (!cur->drv_id)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, cur);
|
||||
return;
|
||||
HeapFree(GetProcessHeap(), 0, devkey);
|
||||
return NULL;
|
||||
}
|
||||
lstrcpyW(cur->alname, name);
|
||||
lstrcpyW(cur->drv_id, name);
|
||||
cur->key = devkey;
|
||||
cur->IMMDevice_iface.lpVtbl = &MMDeviceVtbl;
|
||||
cur->IMMEndpoint_iface.lpVtbl = &MMEndpointVtbl;
|
||||
cur->ref = 0;
|
||||
|
@ -311,7 +308,6 @@ static void MMDevice_Create(MMDevice **dev, WCHAR *name, GUID *id, EDataFlow flo
|
|||
cur->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MMDevice.crst");
|
||||
cur->flow = flow;
|
||||
cur->state = state;
|
||||
cur->device = NULL;
|
||||
if (!id)
|
||||
{
|
||||
id = &cur->devguid;
|
||||
|
@ -352,14 +348,125 @@ done:
|
|||
else
|
||||
MMDevice_def_rec = cur;
|
||||
}
|
||||
if (dev)
|
||||
*dev = cur;
|
||||
return cur;
|
||||
}
|
||||
|
||||
static HRESULT load_devices_from_reg(void)
|
||||
{
|
||||
DWORD i = 0;
|
||||
HKEY root, cur;
|
||||
LONG ret;
|
||||
DWORD curflow;
|
||||
|
||||
ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &root, NULL);
|
||||
if (ret == ERROR_SUCCESS)
|
||||
ret = RegCreateKeyExW(root, reg_capture, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_capture, NULL);
|
||||
if (ret == ERROR_SUCCESS)
|
||||
ret = RegCreateKeyExW(root, reg_render, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_render, NULL);
|
||||
RegCloseKey(root);
|
||||
cur = key_capture;
|
||||
curflow = eCapture;
|
||||
if (ret != ERROR_SUCCESS)
|
||||
{
|
||||
RegCloseKey(key_capture);
|
||||
key_render = key_capture = NULL;
|
||||
WARN("Couldn't create key: %u\n", ret);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
do {
|
||||
WCHAR guidvalue[39];
|
||||
GUID guid;
|
||||
DWORD len;
|
||||
PROPVARIANT pv = { VT_EMPTY };
|
||||
|
||||
len = sizeof(guidvalue)/sizeof(guidvalue[0]);
|
||||
ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL);
|
||||
if (ret == ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
if (cur == key_capture)
|
||||
{
|
||||
cur = key_render;
|
||||
curflow = eRender;
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ret != ERROR_SUCCESS)
|
||||
continue;
|
||||
if (SUCCEEDED(CLSIDFromString(guidvalue, &guid))
|
||||
&& SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv))
|
||||
&& pv.vt == VT_LPWSTR)
|
||||
{
|
||||
MMDevice_Create(pv.u.pwszVal, NULL, &guid, curflow,
|
||||
DEVICE_STATE_NOTPRESENT, FALSE);
|
||||
CoTaskMemFree(pv.u.pwszVal);
|
||||
}
|
||||
} while (1);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT set_format(MMDevice *dev)
|
||||
{
|
||||
HRESULT hr;
|
||||
IAudioClient *client;
|
||||
WAVEFORMATEX *fmt;
|
||||
PROPVARIANT pv = { VT_EMPTY };
|
||||
|
||||
hr = drvs.pGetAudioEndpoint(dev->key, &dev->IMMDevice_iface, dev->flow, &client);
|
||||
if(FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = IAudioClient_GetMixFormat(client, &fmt);
|
||||
if(FAILED(hr)){
|
||||
IAudioClient_Release(client);
|
||||
return hr;
|
||||
}
|
||||
|
||||
IAudioClient_Release(client);
|
||||
|
||||
pv.vt = VT_BLOB;
|
||||
pv.u.blob.cbSize = sizeof(WAVEFORMATEX) + fmt->cbSize;
|
||||
pv.u.blob.pBlobData = (BYTE*)fmt;
|
||||
MMDevice_SetPropValue(&dev->devguid, dev->flow,
|
||||
&PKEY_AudioEngine_DeviceFormat, &pv);
|
||||
MMDevice_SetPropValue(&dev->devguid, dev->flow,
|
||||
&PKEY_AudioEngine_OEMFormat, &pv);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT load_driver_devices(EDataFlow flow)
|
||||
{
|
||||
WCHAR **ids;
|
||||
void **keys;
|
||||
UINT num, def, i;
|
||||
HRESULT hr;
|
||||
|
||||
hr = drvs.pGetEndpointIDs(flow, &ids, &keys, &num, &def);
|
||||
if(FAILED(hr))
|
||||
return hr;
|
||||
|
||||
for(i = 0; i < num; ++i){
|
||||
MMDevice *dev;
|
||||
dev = MMDevice_Create(ids[i], keys[i], NULL, flow, DEVICE_STATE_ACTIVE,
|
||||
def == i);
|
||||
set_format(dev);
|
||||
HeapFree(GetProcessHeap(), 0, ids[i]);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, keys);
|
||||
HeapFree(GetProcessHeap(), 0, ids);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void MMDevice_Destroy(MMDevice *This)
|
||||
{
|
||||
DWORD i;
|
||||
TRACE("Freeing %s\n", debugstr_w(This->alname));
|
||||
TRACE("Freeing %s\n", debugstr_w(This->drv_id));
|
||||
/* Since this function is called at destruction time, reordering of the list is unimportant */
|
||||
for (i = 0; i < MMDevice_count; ++i)
|
||||
{
|
||||
|
@ -369,13 +476,10 @@ static void MMDevice_Destroy(MMDevice *This)
|
|||
break;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_OPENAL
|
||||
if (This->device)
|
||||
palcCloseDevice(This->device);
|
||||
#endif
|
||||
This->crst.DebugInfo->Spare[0] = 0;
|
||||
DeleteCriticalSection(&This->crst);
|
||||
HeapFree(GetProcessHeap(), 0, This->alname);
|
||||
HeapFree(GetProcessHeap(), 0, This->drv_id);
|
||||
HeapFree(GetProcessHeap(), 0, This->key);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
|
@ -429,8 +533,6 @@ static ULONG WINAPI MMDevice_Release(IMMDevice *iface)
|
|||
static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD clsctx, PROPVARIANT *params, void **ppv)
|
||||
{
|
||||
HRESULT hr = E_NOINTERFACE;
|
||||
|
||||
#ifdef HAVE_OPENAL
|
||||
MMDevice *This = impl_from_IMMDevice(iface);
|
||||
|
||||
TRACE("(%p)->(%p,%x,%p,%p)\n", iface, riid, clsctx, params, ppv);
|
||||
|
@ -438,14 +540,9 @@ static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD cls
|
|||
if (!ppv)
|
||||
return E_POINTER;
|
||||
|
||||
if (!openal_loaded)
|
||||
{
|
||||
WARN("OpenAL is still not loaded\n");
|
||||
hr = AUDCLNT_E_SERVICE_NOT_RUNNING;
|
||||
}
|
||||
else if (IsEqualIID(riid, &IID_IAudioClient))
|
||||
hr = AudioClient_Create(This, (IAudioClient**)ppv);
|
||||
else if (IsEqualIID(riid, &IID_IAudioEndpointVolume))
|
||||
if (IsEqualIID(riid, &IID_IAudioClient)){
|
||||
hr = drvs.pGetAudioEndpoint(This->key, iface, This->flow, (IAudioClient**)ppv);
|
||||
}else if (IsEqualIID(riid, &IID_IAudioEndpointVolume))
|
||||
hr = AudioEndpointVolume_Create(This, (IAudioEndpointVolume**)ppv);
|
||||
else if (IsEqualIID(riid, &IID_IAudioSessionManager)
|
||||
|| IsEqualIID(riid, &IID_IAudioSessionManager2))
|
||||
|
@ -509,10 +606,6 @@ static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD cls
|
|||
}
|
||||
else
|
||||
ERR("Invalid/unknown iid %s\n", debugstr_guid(riid));
|
||||
#else
|
||||
if (!ppv) return E_POINTER;
|
||||
hr = AUDCLNT_E_SERVICE_NOT_RUNNING;
|
||||
#endif
|
||||
|
||||
if (FAILED(hr))
|
||||
*ppv = NULL;
|
||||
|
@ -727,205 +820,12 @@ static const IMMDeviceCollectionVtbl MMDevColVtbl =
|
|||
MMDevCol_Item
|
||||
};
|
||||
|
||||
#ifdef HAVE_OPENAL
|
||||
|
||||
static void openal_setformat(MMDevice *This, DWORD freq)
|
||||
{
|
||||
HRESULT hr;
|
||||
PROPVARIANT pv = { VT_EMPTY };
|
||||
|
||||
hr = MMDevice_GetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
|
||||
if (SUCCEEDED(hr) && pv.vt == VT_BLOB)
|
||||
{
|
||||
WAVEFORMATEX *pwfx;
|
||||
pwfx = (WAVEFORMATEX*)pv.u.blob.pBlobData;
|
||||
if (pwfx->nSamplesPerSec != freq)
|
||||
{
|
||||
pwfx->nSamplesPerSec = freq;
|
||||
pwfx->nAvgBytesPerSec = freq * pwfx->nBlockAlign;
|
||||
MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
|
||||
}
|
||||
CoTaskMemFree(pwfx);
|
||||
}
|
||||
else
|
||||
{
|
||||
WAVEFORMATEXTENSIBLE wfxe;
|
||||
|
||||
wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
wfxe.Format.nChannels = 2;
|
||||
wfxe.Format.wBitsPerSample = 32;
|
||||
wfxe.Format.nBlockAlign = wfxe.Format.nChannels * wfxe.Format.wBitsPerSample/8;
|
||||
wfxe.Format.nSamplesPerSec = freq;
|
||||
wfxe.Format.nAvgBytesPerSec = wfxe.Format.nSamplesPerSec * wfxe.Format.nBlockAlign;
|
||||
wfxe.Format.cbSize = sizeof(wfxe)-sizeof(WAVEFORMATEX);
|
||||
wfxe.Samples.wValidBitsPerSample = 32;
|
||||
wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
wfxe.dwChannelMask = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT;
|
||||
|
||||
pv.vt = VT_BLOB;
|
||||
pv.u.blob.cbSize = sizeof(wfxe);
|
||||
pv.u.blob.pBlobData = (BYTE*)&wfxe;
|
||||
MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv);
|
||||
MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_OEMFormat, &pv);
|
||||
}
|
||||
}
|
||||
|
||||
static int blacklist_pulse;
|
||||
|
||||
static int blacklist(const char *dev) {
|
||||
#ifdef __linux__
|
||||
if (!strncmp(dev, "OSS ", 4))
|
||||
return 1;
|
||||
#endif
|
||||
if (blacklist_pulse && !strncmp(dev, "PulseAudio ", 11))
|
||||
return 1;
|
||||
if (!strncmp(dev, "ALSA ", 5) && strstr(dev, "hw:"))
|
||||
return 1;
|
||||
if (!strncmp(dev, "PortAudio ", 10))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pulse_fixup(const char *devstr, const char **defstr, int render) {
|
||||
static int warned;
|
||||
int default_pulse;
|
||||
|
||||
if (render && !blacklist_pulse && !local_contexts)
|
||||
blacklist_pulse = 1;
|
||||
|
||||
if (!blacklist_pulse || !devstr || !*devstr)
|
||||
return;
|
||||
|
||||
default_pulse = !strncmp(*defstr, "PulseAudio ", 11);
|
||||
|
||||
while (*devstr && !strncmp(devstr, "PulseAudio ", 11))
|
||||
devstr += strlen(devstr) + 1;
|
||||
|
||||
/* Could still be a newer version, so check for 1.11 if more devices are enabled */
|
||||
if (render && *devstr) {
|
||||
ALCdevice *dev = palcOpenDevice(devstr);
|
||||
ALCcontext *ctx = palcCreateContext(dev, NULL);
|
||||
if (ctx) {
|
||||
const char *ver;
|
||||
|
||||
setALContext(ctx);
|
||||
ver = palGetString(AL_VERSION);
|
||||
popALContext();
|
||||
palcDestroyContext(ctx);
|
||||
|
||||
if (!strcmp(ver, "1.1 ALSOFT 1.11.753")) {
|
||||
blacklist_pulse = 0;
|
||||
palcCloseDevice(dev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (dev)
|
||||
palcCloseDevice(dev);
|
||||
}
|
||||
|
||||
if (!warned++) {
|
||||
ERR("Disabling pulseaudio because of old openal version\n");
|
||||
ERR("Please upgrade to openal-soft v1.12 or newer\n");
|
||||
}
|
||||
TRACE("New default: %s\n", devstr);
|
||||
if (default_pulse)
|
||||
*defstr = devstr;
|
||||
}
|
||||
|
||||
static void openal_scanrender(void)
|
||||
{
|
||||
WCHAR name[MAX_PATH];
|
||||
ALCdevice *dev;
|
||||
const ALCchar *devstr, *defaultstr;
|
||||
int defblacklisted;
|
||||
EnterCriticalSection(&openal_crst);
|
||||
if (palcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) {
|
||||
defaultstr = palcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
|
||||
devstr = palcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||
} else {
|
||||
defaultstr = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
devstr = palcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
}
|
||||
pulse_fixup(devstr, &defaultstr, 1);
|
||||
defblacklisted = blacklist(defaultstr);
|
||||
if (defblacklisted)
|
||||
WARN("Disabling blacklist because %s is blacklisted\n", defaultstr);
|
||||
if (devstr)
|
||||
for (; *devstr; devstr += strlen(devstr)+1) {
|
||||
MMDevice *mmdev;
|
||||
MultiByteToWideChar( CP_UNIXCP, 0, devstr, -1,
|
||||
name, sizeof(name)/sizeof(*name)-1 );
|
||||
name[sizeof(name)/sizeof(*name)-1] = 0;
|
||||
/* Only enable blacklist if the default device isn't blacklisted */
|
||||
if (!defblacklisted && blacklist(devstr)) {
|
||||
WARN("Not adding %s: device is blacklisted\n", devstr);
|
||||
continue;
|
||||
}
|
||||
TRACE("Adding %s\n", devstr);
|
||||
dev = palcOpenDevice(devstr);
|
||||
MMDevice_Create(&mmdev, name, NULL, eRender, dev ? DEVICE_STATE_ACTIVE : DEVICE_STATE_NOTPRESENT, !strcmp(devstr, defaultstr));
|
||||
if (dev)
|
||||
{
|
||||
ALint freq = 44100;
|
||||
palcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq);
|
||||
openal_setformat(mmdev, freq);
|
||||
palcCloseDevice(dev);
|
||||
}
|
||||
else
|
||||
WARN("Could not open device: %04x\n", palcGetError(NULL));
|
||||
}
|
||||
LeaveCriticalSection(&openal_crst);
|
||||
}
|
||||
|
||||
static void openal_scancapture(void)
|
||||
{
|
||||
WCHAR name[MAX_PATH];
|
||||
ALCdevice *dev;
|
||||
const ALCchar *devstr, *defaultstr;
|
||||
int defblacklisted;
|
||||
|
||||
EnterCriticalSection(&openal_crst);
|
||||
devstr = palcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
defaultstr = palcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
|
||||
pulse_fixup(devstr, &defaultstr, 0);
|
||||
defblacklisted = blacklist(defaultstr);
|
||||
if (defblacklisted)
|
||||
WARN("Disabling blacklist because %s is blacklisted\n", defaultstr);
|
||||
if (devstr && *devstr)
|
||||
for (; *devstr; devstr += strlen(devstr)+1) {
|
||||
MMDevice *mmdev;
|
||||
ALint freq = 44100;
|
||||
MultiByteToWideChar( CP_UNIXCP, 0, devstr, -1,
|
||||
name, sizeof(name)/sizeof(*name)-1 );
|
||||
name[sizeof(name)/sizeof(*name)-1] = 0;
|
||||
if (!defblacklisted && blacklist(devstr)) {
|
||||
WARN("Not adding %s: device is blacklisted\n", devstr);
|
||||
continue;
|
||||
}
|
||||
TRACE("Adding %s\n", devstr);
|
||||
dev = palcCaptureOpenDevice(devstr, freq, AL_FORMAT_MONO16, 65536);
|
||||
MMDevice_Create(&mmdev, name, NULL, eCapture, dev ? DEVICE_STATE_ACTIVE : DEVICE_STATE_NOTPRESENT, !strcmp(devstr, defaultstr));
|
||||
if (dev) {
|
||||
openal_setformat(mmdev, freq);
|
||||
palcCaptureCloseDevice(dev);
|
||||
} else
|
||||
WARN("Could not open device: %04x\n", palcGetError(NULL));
|
||||
}
|
||||
LeaveCriticalSection(&openal_crst);
|
||||
}
|
||||
#endif /*HAVE_OPENAL*/
|
||||
|
||||
HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
|
||||
{
|
||||
MMDevEnumImpl *This = MMDevEnumerator;
|
||||
|
||||
if (!This)
|
||||
{
|
||||
DWORD i = 0;
|
||||
HKEY root, cur;
|
||||
LONG ret;
|
||||
DWORD curflow;
|
||||
|
||||
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
||||
*ppv = NULL;
|
||||
if (!This)
|
||||
|
@ -934,62 +834,9 @@ HRESULT MMDevEnum_Create(REFIID riid, void **ppv)
|
|||
This->IMMDeviceEnumerator_iface.lpVtbl = &MMDevEnumVtbl;
|
||||
MMDevEnumerator = This;
|
||||
|
||||
ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &root, NULL);
|
||||
if (ret == ERROR_SUCCESS)
|
||||
ret = RegCreateKeyExW(root, reg_capture, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_capture, NULL);
|
||||
if (ret == ERROR_SUCCESS)
|
||||
ret = RegCreateKeyExW(root, reg_render, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_render, NULL);
|
||||
RegCloseKey(root);
|
||||
cur = key_capture;
|
||||
curflow = eCapture;
|
||||
if (ret != ERROR_SUCCESS)
|
||||
{
|
||||
RegCloseKey(key_capture);
|
||||
key_render = key_capture = NULL;
|
||||
WARN("Couldn't create key: %u\n", ret);
|
||||
return E_FAIL;
|
||||
}
|
||||
else do {
|
||||
WCHAR guidvalue[39];
|
||||
GUID guid;
|
||||
DWORD len;
|
||||
PROPVARIANT pv = { VT_EMPTY };
|
||||
|
||||
len = sizeof(guidvalue)/sizeof(guidvalue[0]);
|
||||
ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL);
|
||||
if (ret == ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
if (cur == key_capture)
|
||||
{
|
||||
cur = key_render;
|
||||
curflow = eRender;
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ret != ERROR_SUCCESS)
|
||||
continue;
|
||||
if (SUCCEEDED(CLSIDFromString(guidvalue, &guid))
|
||||
&& SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv))
|
||||
&& pv.vt == VT_LPWSTR)
|
||||
{
|
||||
MMDevice_Create(NULL, pv.u.pwszVal, &guid, curflow,
|
||||
DEVICE_STATE_NOTPRESENT, FALSE);
|
||||
CoTaskMemFree(pv.u.pwszVal);
|
||||
}
|
||||
} while (1);
|
||||
#ifdef HAVE_OPENAL
|
||||
if (openal_loaded)
|
||||
{
|
||||
openal_scanrender();
|
||||
openal_scancapture();
|
||||
}
|
||||
else
|
||||
FIXME("OpenAL support not enabled, application will not find sound devices\n");
|
||||
#else
|
||||
ERR("OpenAL support not compiled in, application will not find sound devices\n");
|
||||
#endif /*HAVE_OPENAL*/
|
||||
load_devices_from_reg();
|
||||
load_driver_devices(eRender);
|
||||
load_driver_devices(eCapture);
|
||||
}
|
||||
return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright 2009 Maarten Lankhorst
|
||||
* Copyright 2011 Andrew Eikum for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -21,14 +22,6 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_AL_AL_H
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#elif defined(HAVE_OPENAL_AL_H)
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#endif
|
||||
|
||||
#define COBJMACROS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
@ -48,274 +41,84 @@
|
|||
#include "endpointvolume.h"
|
||||
#include "audiopolicy.h"
|
||||
#include "devpkey.h"
|
||||
#include "winreg.h"
|
||||
|
||||
#include "mmdevapi.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
|
||||
|
||||
#ifdef HAVE_OPENAL
|
||||
static HINSTANCE instance;
|
||||
|
||||
int local_contexts;
|
||||
DriverFuncs drvs;
|
||||
|
||||
static CRITICAL_SECTION_DEBUG openal_crst_debug =
|
||||
static BOOL load_driver(const WCHAR *name)
|
||||
{
|
||||
0, 0, &openal_crst,
|
||||
{ &openal_crst_debug.ProcessLocksList,
|
||||
&openal_crst_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": openal_crst_debug") }
|
||||
};
|
||||
CRITICAL_SECTION openal_crst = { &openal_crst_debug, -1, 0, 0, 0, 0 };
|
||||
WCHAR driver_module[264];
|
||||
static const WCHAR wineW[] = {'w','i','n','e',0};
|
||||
static const WCHAR dotdrvW[] = {'.','d','r','v',0};
|
||||
|
||||
static void *openal_handle = RTLD_DEFAULT;
|
||||
int openal_loaded;
|
||||
#ifdef SONAME_LIBOPENAL
|
||||
LPALCCREATECONTEXT palcCreateContext = NULL;
|
||||
LPALCMAKECONTEXTCURRENT palcMakeContextCurrent = NULL;
|
||||
LPALCPROCESSCONTEXT palcProcessContext = NULL;
|
||||
LPALCSUSPENDCONTEXT palcSuspendContext = NULL;
|
||||
LPALCDESTROYCONTEXT palcDestroyContext = NULL;
|
||||
LPALCGETCURRENTCONTEXT palcGetCurrentContext = NULL;
|
||||
LPALCGETCONTEXTSDEVICE palcGetContextsDevice = NULL;
|
||||
LPALCOPENDEVICE palcOpenDevice = NULL;
|
||||
LPALCCLOSEDEVICE palcCloseDevice = NULL;
|
||||
LPALCGETERROR palcGetError = NULL;
|
||||
LPALCISEXTENSIONPRESENT palcIsExtensionPresent = NULL;
|
||||
LPALCGETPROCADDRESS palcGetProcAddress = NULL;
|
||||
LPALCGETENUMVALUE palcGetEnumValue = NULL;
|
||||
LPALCGETSTRING palcGetString = NULL;
|
||||
LPALCGETINTEGERV palcGetIntegerv = NULL;
|
||||
LPALCCAPTUREOPENDEVICE palcCaptureOpenDevice = NULL;
|
||||
LPALCCAPTURECLOSEDEVICE palcCaptureCloseDevice = NULL;
|
||||
LPALCCAPTURESTART palcCaptureStart = NULL;
|
||||
LPALCCAPTURESTOP palcCaptureStop = NULL;
|
||||
LPALCCAPTURESAMPLES palcCaptureSamples = NULL;
|
||||
LPALENABLE palEnable = NULL;
|
||||
LPALDISABLE palDisable = NULL;
|
||||
LPALISENABLED palIsEnabled = NULL;
|
||||
LPALGETSTRING palGetString = NULL;
|
||||
LPALGETBOOLEANV palGetBooleanv = NULL;
|
||||
LPALGETINTEGERV palGetIntegerv = NULL;
|
||||
LPALGETFLOATV palGetFloatv = NULL;
|
||||
LPALGETDOUBLEV palGetDoublev = NULL;
|
||||
LPALGETBOOLEAN palGetBoolean = NULL;
|
||||
LPALGETINTEGER palGetInteger = NULL;
|
||||
LPALGETFLOAT palGetFloat = NULL;
|
||||
LPALGETDOUBLE palGetDouble = NULL;
|
||||
LPALGETERROR palGetError = NULL;
|
||||
LPALISEXTENSIONPRESENT palIsExtensionPresent = NULL;
|
||||
LPALGETPROCADDRESS palGetProcAddress = NULL;
|
||||
LPALGETENUMVALUE palGetEnumValue = NULL;
|
||||
LPALLISTENERF palListenerf = NULL;
|
||||
LPALLISTENER3F palListener3f = NULL;
|
||||
LPALLISTENERFV palListenerfv = NULL;
|
||||
LPALLISTENERI palListeneri = NULL;
|
||||
LPALLISTENER3I palListener3i = NULL;
|
||||
LPALLISTENERIV palListeneriv = NULL;
|
||||
LPALGETLISTENERF palGetListenerf = NULL;
|
||||
LPALGETLISTENER3F palGetListener3f = NULL;
|
||||
LPALGETLISTENERFV palGetListenerfv = NULL;
|
||||
LPALGETLISTENERI palGetListeneri = NULL;
|
||||
LPALGETLISTENER3I palGetListener3i = NULL;
|
||||
LPALGETLISTENERIV palGetListeneriv = NULL;
|
||||
LPALGENSOURCES palGenSources = NULL;
|
||||
LPALDELETESOURCES palDeleteSources = NULL;
|
||||
LPALISSOURCE palIsSource = NULL;
|
||||
LPALSOURCEF palSourcef = NULL;
|
||||
LPALSOURCE3F palSource3f = NULL;
|
||||
LPALSOURCEFV palSourcefv = NULL;
|
||||
LPALSOURCEI palSourcei = NULL;
|
||||
LPALSOURCE3I palSource3i = NULL;
|
||||
LPALSOURCEIV palSourceiv = NULL;
|
||||
LPALGETSOURCEF palGetSourcef = NULL;
|
||||
LPALGETSOURCE3F palGetSource3f = NULL;
|
||||
LPALGETSOURCEFV palGetSourcefv = NULL;
|
||||
LPALGETSOURCEI palGetSourcei = NULL;
|
||||
LPALGETSOURCE3I palGetSource3i = NULL;
|
||||
LPALGETSOURCEIV palGetSourceiv = NULL;
|
||||
LPALSOURCEPLAYV palSourcePlayv = NULL;
|
||||
LPALSOURCESTOPV palSourceStopv = NULL;
|
||||
LPALSOURCEREWINDV palSourceRewindv = NULL;
|
||||
LPALSOURCEPAUSEV palSourcePausev = NULL;
|
||||
LPALSOURCEPLAY palSourcePlay = NULL;
|
||||
LPALSOURCESTOP palSourceStop = NULL;
|
||||
LPALSOURCEREWIND palSourceRewind = NULL;
|
||||
LPALSOURCEPAUSE palSourcePause = NULL;
|
||||
LPALSOURCEQUEUEBUFFERS palSourceQueueBuffers = NULL;
|
||||
LPALSOURCEUNQUEUEBUFFERS palSourceUnqueueBuffers = NULL;
|
||||
LPALGENBUFFERS palGenBuffers = NULL;
|
||||
LPALDELETEBUFFERS palDeleteBuffers = NULL;
|
||||
LPALISBUFFER palIsBuffer = NULL;
|
||||
LPALBUFFERF palBufferf = NULL;
|
||||
LPALBUFFER3F palBuffer3f = NULL;
|
||||
LPALBUFFERFV palBufferfv = NULL;
|
||||
LPALBUFFERI palBufferi = NULL;
|
||||
LPALBUFFER3I palBuffer3i = NULL;
|
||||
LPALBUFFERIV palBufferiv = NULL;
|
||||
LPALGETBUFFERF palGetBufferf = NULL;
|
||||
LPALGETBUFFER3F palGetBuffer3f = NULL;
|
||||
LPALGETBUFFERFV palGetBufferfv = NULL;
|
||||
LPALGETBUFFERI palGetBufferi = NULL;
|
||||
LPALGETBUFFER3I palGetBuffer3i = NULL;
|
||||
LPALGETBUFFERIV palGetBufferiv = NULL;
|
||||
LPALBUFFERDATA palBufferData = NULL;
|
||||
LPALDOPPLERFACTOR palDopplerFactor = NULL;
|
||||
LPALDOPPLERVELOCITY palDopplerVelocity = NULL;
|
||||
LPALDISTANCEMODEL palDistanceModel = NULL;
|
||||
LPALSPEEDOFSOUND palSpeedOfSound = NULL;
|
||||
#endif
|
||||
lstrcpyW(driver_module, wineW);
|
||||
lstrcatW(driver_module, name);
|
||||
lstrcatW(driver_module, dotdrvW);
|
||||
|
||||
typeof(alcGetCurrentContext) *get_context;
|
||||
typeof(alcMakeContextCurrent) *set_context;
|
||||
TRACE("Attempting to load %s\n", wine_dbgstr_w(driver_module));
|
||||
|
||||
static void load_libopenal(void)
|
||||
{
|
||||
DWORD failed = 0;
|
||||
|
||||
#ifdef SONAME_LIBOPENAL
|
||||
char error[128];
|
||||
openal_handle = wine_dlopen(SONAME_LIBOPENAL, RTLD_NOW, error, sizeof(error));
|
||||
if (!openal_handle)
|
||||
{
|
||||
ERR("Couldn't load " SONAME_LIBOPENAL ": %s\n", error);
|
||||
return;
|
||||
drvs.module = LoadLibraryW(driver_module);
|
||||
if(!drvs.module){
|
||||
TRACE("Unable to load %s: %u\n", wine_dbgstr_w(driver_module),
|
||||
GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define LOAD_FUNCPTR(f) \
|
||||
if((p##f = wine_dlsym(openal_handle, #f, NULL, 0)) == NULL) { \
|
||||
ERR("Couldn't lookup %s in libopenal\n", #f); \
|
||||
failed = 1; \
|
||||
}
|
||||
#define LDFC(n) do { drvs.p##n = (void*)GetProcAddress(drvs.module, #n);\
|
||||
if(!drvs.p##n) return FALSE; } while(0);
|
||||
LDFC(GetEndpointIDs);
|
||||
LDFC(GetAudioEndpoint);
|
||||
#undef LDFC
|
||||
|
||||
LOAD_FUNCPTR(alcCreateContext);
|
||||
LOAD_FUNCPTR(alcMakeContextCurrent);
|
||||
LOAD_FUNCPTR(alcProcessContext);
|
||||
LOAD_FUNCPTR(alcSuspendContext);
|
||||
LOAD_FUNCPTR(alcDestroyContext);
|
||||
LOAD_FUNCPTR(alcGetCurrentContext);
|
||||
LOAD_FUNCPTR(alcGetContextsDevice);
|
||||
LOAD_FUNCPTR(alcOpenDevice);
|
||||
LOAD_FUNCPTR(alcCloseDevice);
|
||||
LOAD_FUNCPTR(alcGetError);
|
||||
LOAD_FUNCPTR(alcIsExtensionPresent);
|
||||
LOAD_FUNCPTR(alcGetProcAddress);
|
||||
LOAD_FUNCPTR(alcGetEnumValue);
|
||||
LOAD_FUNCPTR(alcGetString);
|
||||
LOAD_FUNCPTR(alcGetIntegerv);
|
||||
LOAD_FUNCPTR(alcCaptureOpenDevice);
|
||||
LOAD_FUNCPTR(alcCaptureCloseDevice);
|
||||
LOAD_FUNCPTR(alcCaptureStart);
|
||||
LOAD_FUNCPTR(alcCaptureStop);
|
||||
LOAD_FUNCPTR(alcCaptureSamples);
|
||||
LOAD_FUNCPTR(alEnable);
|
||||
LOAD_FUNCPTR(alDisable);
|
||||
LOAD_FUNCPTR(alIsEnabled);
|
||||
LOAD_FUNCPTR(alGetString);
|
||||
LOAD_FUNCPTR(alGetBooleanv);
|
||||
LOAD_FUNCPTR(alGetIntegerv);
|
||||
LOAD_FUNCPTR(alGetFloatv);
|
||||
LOAD_FUNCPTR(alGetDoublev);
|
||||
LOAD_FUNCPTR(alGetBoolean);
|
||||
LOAD_FUNCPTR(alGetInteger);
|
||||
LOAD_FUNCPTR(alGetFloat);
|
||||
LOAD_FUNCPTR(alGetDouble);
|
||||
LOAD_FUNCPTR(alGetError);
|
||||
LOAD_FUNCPTR(alIsExtensionPresent);
|
||||
LOAD_FUNCPTR(alGetProcAddress);
|
||||
LOAD_FUNCPTR(alGetEnumValue);
|
||||
LOAD_FUNCPTR(alListenerf);
|
||||
LOAD_FUNCPTR(alListener3f);
|
||||
LOAD_FUNCPTR(alListenerfv);
|
||||
LOAD_FUNCPTR(alListeneri);
|
||||
LOAD_FUNCPTR(alListener3i);
|
||||
LOAD_FUNCPTR(alListeneriv);
|
||||
LOAD_FUNCPTR(alGetListenerf);
|
||||
LOAD_FUNCPTR(alGetListener3f);
|
||||
LOAD_FUNCPTR(alGetListenerfv);
|
||||
LOAD_FUNCPTR(alGetListeneri);
|
||||
LOAD_FUNCPTR(alGetListener3i);
|
||||
LOAD_FUNCPTR(alGetListeneriv);
|
||||
LOAD_FUNCPTR(alGenSources);
|
||||
LOAD_FUNCPTR(alDeleteSources);
|
||||
LOAD_FUNCPTR(alIsSource);
|
||||
LOAD_FUNCPTR(alSourcef);
|
||||
LOAD_FUNCPTR(alSource3f);
|
||||
LOAD_FUNCPTR(alSourcefv);
|
||||
LOAD_FUNCPTR(alSourcei);
|
||||
LOAD_FUNCPTR(alSource3i);
|
||||
LOAD_FUNCPTR(alSourceiv);
|
||||
LOAD_FUNCPTR(alGetSourcef);
|
||||
LOAD_FUNCPTR(alGetSource3f);
|
||||
LOAD_FUNCPTR(alGetSourcefv);
|
||||
LOAD_FUNCPTR(alGetSourcei);
|
||||
LOAD_FUNCPTR(alGetSource3i);
|
||||
LOAD_FUNCPTR(alGetSourceiv);
|
||||
LOAD_FUNCPTR(alSourcePlayv);
|
||||
LOAD_FUNCPTR(alSourceStopv);
|
||||
LOAD_FUNCPTR(alSourceRewindv);
|
||||
LOAD_FUNCPTR(alSourcePausev);
|
||||
LOAD_FUNCPTR(alSourcePlay);
|
||||
LOAD_FUNCPTR(alSourceStop);
|
||||
LOAD_FUNCPTR(alSourceRewind);
|
||||
LOAD_FUNCPTR(alSourcePause);
|
||||
LOAD_FUNCPTR(alSourceQueueBuffers);
|
||||
LOAD_FUNCPTR(alSourceUnqueueBuffers);
|
||||
LOAD_FUNCPTR(alGenBuffers);
|
||||
LOAD_FUNCPTR(alDeleteBuffers);
|
||||
LOAD_FUNCPTR(alIsBuffer);
|
||||
LOAD_FUNCPTR(alBufferf);
|
||||
LOAD_FUNCPTR(alBuffer3f);
|
||||
LOAD_FUNCPTR(alBufferfv);
|
||||
LOAD_FUNCPTR(alBufferi);
|
||||
LOAD_FUNCPTR(alBuffer3i);
|
||||
LOAD_FUNCPTR(alBufferiv);
|
||||
LOAD_FUNCPTR(alGetBufferf);
|
||||
LOAD_FUNCPTR(alGetBuffer3f);
|
||||
LOAD_FUNCPTR(alGetBufferfv);
|
||||
LOAD_FUNCPTR(alGetBufferi);
|
||||
LOAD_FUNCPTR(alGetBuffer3i);
|
||||
LOAD_FUNCPTR(alGetBufferiv);
|
||||
LOAD_FUNCPTR(alBufferData);
|
||||
LOAD_FUNCPTR(alDopplerFactor);
|
||||
LOAD_FUNCPTR(alDopplerVelocity);
|
||||
LOAD_FUNCPTR(alDistanceModel);
|
||||
LOAD_FUNCPTR(alSpeedOfSound);
|
||||
#undef LOAD_FUNCPTR
|
||||
#endif
|
||||
TRACE("Successfully loaded %s\n", wine_dbgstr_w(driver_module));
|
||||
|
||||
if (failed)
|
||||
{
|
||||
WARN("Unloading openal\n");
|
||||
if (openal_handle != RTLD_DEFAULT)
|
||||
wine_dlclose(openal_handle, NULL, 0);
|
||||
openal_handle = NULL;
|
||||
openal_loaded = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
openal_loaded = 1;
|
||||
local_contexts = palcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context");
|
||||
if (local_contexts)
|
||||
{
|
||||
set_context = palcGetProcAddress(NULL, "alcSetThreadContext");
|
||||
get_context = palcGetProcAddress(NULL, "alcGetThreadContext");
|
||||
if (!set_context || !get_context)
|
||||
{
|
||||
ERR("TLS advertised but functions not found, disabling thread local context\n");
|
||||
local_contexts = 0;
|
||||
}
|
||||
}
|
||||
if (!local_contexts)
|
||||
{
|
||||
set_context = palcMakeContextCurrent;
|
||||
get_context = palcGetCurrentContext;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /*HAVE_OPENAL*/
|
||||
static BOOL init_driver(void)
|
||||
{
|
||||
static const WCHAR alsaW[] = {'a','l','s','a',0};
|
||||
static const WCHAR ossW[] = {'o','s','s',0};
|
||||
static const WCHAR coreaudioW[] = {'c','o','r','e','a','u','d','i','o',0};
|
||||
static const WCHAR *default_drivers[] = { alsaW, coreaudioW, ossW };
|
||||
static const WCHAR drv_key[] = {'S','o','f','t','w','a','r','e','\\',
|
||||
'W','i','n','e','\\','D','r','i','v','e','r','s',0};
|
||||
static const WCHAR drv_value[] = {'A','u','d','i','o',0};
|
||||
HKEY key;
|
||||
UINT i;
|
||||
|
||||
static HINSTANCE instance;
|
||||
if(drvs.module)
|
||||
return TRUE;
|
||||
|
||||
if(RegOpenKeyW(HKEY_CURRENT_USER, drv_key, &key) == ERROR_SUCCESS){
|
||||
WCHAR driver_name[256];
|
||||
DWORD size = sizeof(driver_name);
|
||||
|
||||
if(RegQueryValueExW(key, drv_value, 0, NULL, (BYTE*)driver_name,
|
||||
&size) == ERROR_SUCCESS){
|
||||
BOOL ret = load_driver(driver_name);
|
||||
RegCloseKey(key);
|
||||
if(!ret)
|
||||
ERR("Failed to load driver: %s\n", wine_dbgstr_w(driver_name));
|
||||
return ret;
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
for(i = 0; i < sizeof(default_drivers)/sizeof(*default_drivers); ++i)
|
||||
if(load_driver(default_drivers[i]))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
|
@ -326,9 +129,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|||
case DLL_PROCESS_ATTACH:
|
||||
instance = hinstDLL;
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
#ifdef HAVE_OPENAL
|
||||
load_libopenal();
|
||||
#endif /*HAVE_OPENAL*/
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
MMDevEnum_Free();
|
||||
|
@ -429,6 +229,11 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
|
|||
int i = 0;
|
||||
TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
|
||||
|
||||
if(!init_driver()){
|
||||
ERR("Driver initialization failed\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (ppv == NULL) {
|
||||
WARN("invalid parameter\n");
|
||||
return E_INVALIDARG;
|
||||
|
|
|
@ -25,6 +25,22 @@ extern void MMDevEnum_Free(void);
|
|||
|
||||
extern HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv);
|
||||
|
||||
typedef struct _DriverFuncs {
|
||||
HMODULE module;
|
||||
|
||||
/* ids gets an array of human-friendly endpoint names
|
||||
* keys gets an array of driver-specific stuff that is used
|
||||
* in GetAudioEndpoint to identify the endpoint
|
||||
* it is the caller's responsibility to free both arrays, and
|
||||
* all of the elements in both arrays with HeapFree() */
|
||||
HRESULT WINAPI (*pGetEndpointIDs)(EDataFlow flow, WCHAR ***ids,
|
||||
void ***keys, UINT *num, UINT *default_index);
|
||||
HRESULT WINAPI (*pGetAudioEndpoint)(void *key, IMMDevice *dev,
|
||||
EDataFlow dataflow, IAudioClient **out);
|
||||
} DriverFuncs;
|
||||
|
||||
extern DriverFuncs drvs;
|
||||
|
||||
typedef struct MMDevice {
|
||||
IMMDevice IMMDevice_iface;
|
||||
IMMEndpoint IMMEndpoint_iface;
|
||||
|
@ -35,252 +51,9 @@ typedef struct MMDevice {
|
|||
EDataFlow flow;
|
||||
DWORD state;
|
||||
GUID devguid;
|
||||
WCHAR *alname;
|
||||
void *device, *ctx;
|
||||
WCHAR *drv_id;
|
||||
void *key;
|
||||
} MMDevice;
|
||||
|
||||
extern HRESULT AudioClient_Create(MMDevice *parent, IAudioClient **ppv);
|
||||
extern HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolume **ppv);
|
||||
|
||||
#ifdef HAVE_OPENAL
|
||||
|
||||
#include "alext.h"
|
||||
|
||||
/* All openal functions */
|
||||
extern int openal_loaded;
|
||||
#ifdef SONAME_LIBOPENAL
|
||||
extern LPALCCREATECONTEXT palcCreateContext;
|
||||
extern LPALCMAKECONTEXTCURRENT palcMakeContextCurrent;
|
||||
extern LPALCPROCESSCONTEXT palcProcessContext;
|
||||
extern LPALCSUSPENDCONTEXT palcSuspendContext;
|
||||
extern LPALCDESTROYCONTEXT palcDestroyContext;
|
||||
extern LPALCGETCURRENTCONTEXT palcGetCurrentContext;
|
||||
extern LPALCGETCONTEXTSDEVICE palcGetContextsDevice;
|
||||
extern LPALCOPENDEVICE palcOpenDevice;
|
||||
extern LPALCCLOSEDEVICE palcCloseDevice;
|
||||
extern LPALCGETERROR palcGetError;
|
||||
extern LPALCISEXTENSIONPRESENT palcIsExtensionPresent;
|
||||
extern LPALCGETPROCADDRESS palcGetProcAddress;
|
||||
extern LPALCGETENUMVALUE palcGetEnumValue;
|
||||
extern LPALCGETSTRING palcGetString;
|
||||
extern LPALCGETINTEGERV palcGetIntegerv;
|
||||
extern LPALCCAPTUREOPENDEVICE palcCaptureOpenDevice;
|
||||
extern LPALCCAPTURECLOSEDEVICE palcCaptureCloseDevice;
|
||||
extern LPALCCAPTURESTART palcCaptureStart;
|
||||
extern LPALCCAPTURESTOP palcCaptureStop;
|
||||
extern LPALCCAPTURESAMPLES palcCaptureSamples;
|
||||
extern LPALENABLE palEnable;
|
||||
extern LPALDISABLE palDisable;
|
||||
extern LPALISENABLED palIsEnabled;
|
||||
extern LPALGETSTRING palGetString;
|
||||
extern LPALGETBOOLEANV palGetBooleanv;
|
||||
extern LPALGETINTEGERV palGetIntegerv;
|
||||
extern LPALGETFLOATV palGetFloatv;
|
||||
extern LPALGETDOUBLEV palGetDoublev;
|
||||
extern LPALGETBOOLEAN palGetBoolean;
|
||||
extern LPALGETINTEGER palGetInteger;
|
||||
extern LPALGETFLOAT palGetFloat;
|
||||
extern LPALGETDOUBLE palGetDouble;
|
||||
extern LPALGETERROR palGetError;
|
||||
extern LPALISEXTENSIONPRESENT palIsExtensionPresent;
|
||||
extern LPALGETPROCADDRESS palGetProcAddress;
|
||||
extern LPALGETENUMVALUE palGetEnumValue;
|
||||
extern LPALLISTENERF palListenerf;
|
||||
extern LPALLISTENER3F palListener3f;
|
||||
extern LPALLISTENERFV palListenerfv;
|
||||
extern LPALLISTENERI palListeneri;
|
||||
extern LPALLISTENER3I palListener3i;
|
||||
extern LPALLISTENERIV palListeneriv;
|
||||
extern LPALGETLISTENERF palGetListenerf;
|
||||
extern LPALGETLISTENER3F palGetListener3f;
|
||||
extern LPALGETLISTENERFV palGetListenerfv;
|
||||
extern LPALGETLISTENERI palGetListeneri;
|
||||
extern LPALGETLISTENER3I palGetListener3i;
|
||||
extern LPALGETLISTENERIV palGetListeneriv;
|
||||
extern LPALGENSOURCES palGenSources;
|
||||
extern LPALDELETESOURCES palDeleteSources;
|
||||
extern LPALISSOURCE palIsSource;
|
||||
extern LPALSOURCEF palSourcef;
|
||||
extern LPALSOURCE3F palSource3f;
|
||||
extern LPALSOURCEFV palSourcefv;
|
||||
extern LPALSOURCEI palSourcei;
|
||||
extern LPALSOURCE3I palSource3i;
|
||||
extern LPALSOURCEIV palSourceiv;
|
||||
extern LPALGETSOURCEF palGetSourcef;
|
||||
extern LPALGETSOURCE3F palGetSource3f;
|
||||
extern LPALGETSOURCEFV palGetSourcefv;
|
||||
extern LPALGETSOURCEI palGetSourcei;
|
||||
extern LPALGETSOURCE3I palGetSource3i;
|
||||
extern LPALGETSOURCEIV palGetSourceiv;
|
||||
extern LPALSOURCEPLAYV palSourcePlayv;
|
||||
extern LPALSOURCESTOPV palSourceStopv;
|
||||
extern LPALSOURCEREWINDV palSourceRewindv;
|
||||
extern LPALSOURCEPAUSEV palSourcePausev;
|
||||
extern LPALSOURCEPLAY palSourcePlay;
|
||||
extern LPALSOURCESTOP palSourceStop;
|
||||
extern LPALSOURCEREWIND palSourceRewind;
|
||||
extern LPALSOURCEPAUSE palSourcePause;
|
||||
extern LPALSOURCEQUEUEBUFFERS palSourceQueueBuffers;
|
||||
extern LPALSOURCEUNQUEUEBUFFERS palSourceUnqueueBuffers;
|
||||
extern LPALGENBUFFERS palGenBuffers;
|
||||
extern LPALDELETEBUFFERS palDeleteBuffers;
|
||||
extern LPALISBUFFER palIsBuffer;
|
||||
extern LPALBUFFERF palBufferf;
|
||||
extern LPALBUFFER3F palBuffer3f;
|
||||
extern LPALBUFFERFV palBufferfv;
|
||||
extern LPALBUFFERI palBufferi;
|
||||
extern LPALBUFFER3I palBuffer3i;
|
||||
extern LPALBUFFERIV palBufferiv;
|
||||
extern LPALGETBUFFERF palGetBufferf;
|
||||
extern LPALGETBUFFER3F palGetBuffer3f;
|
||||
extern LPALGETBUFFERFV palGetBufferfv;
|
||||
extern LPALGETBUFFERI palGetBufferi;
|
||||
extern LPALGETBUFFER3I palGetBuffer3i;
|
||||
extern LPALGETBUFFERIV palGetBufferiv;
|
||||
extern LPALBUFFERDATA palBufferData;
|
||||
extern LPALDOPPLERFACTOR palDopplerFactor;
|
||||
extern LPALDOPPLERVELOCITY palDopplerVelocity;
|
||||
extern LPALDISTANCEMODEL palDistanceModel;
|
||||
extern LPALSPEEDOFSOUND palSpeedOfSound;
|
||||
#else
|
||||
#define palcCreateContext alcCreateContext
|
||||
#define palcMakeContextCurrent alcMakeContextCurrent
|
||||
#define palcProcessContext alcProcessContext
|
||||
#define palcSuspendContext alcSuspendContext
|
||||
#define palcDestroyContext alcDestroyContext
|
||||
#define palcGetCurrentContext alcGetCurrentContext
|
||||
#define palcGetContextsDevice alcGetContextsDevice
|
||||
#define palcOpenDevice alcOpenDevice
|
||||
#define palcCloseDevice alcCloseDevice
|
||||
#define palcGetError alcGetError
|
||||
#define palcIsExtensionPresent alcIsExtensionPresent
|
||||
#define palcGetProcAddress alcGetProcAddress
|
||||
#define palcGetEnumValue alcGetEnumValue
|
||||
#define palcGetString alcGetString
|
||||
#define palcGetIntegerv alcGetIntegerv
|
||||
#define palcCaptureOpenDevice alcCaptureOpenDevice
|
||||
#define palcCaptureCloseDevice alcCaptureCloseDevice
|
||||
#define palcCaptureStart alcCaptureStart
|
||||
#define palcCaptureStop alcCaptureStop
|
||||
#define palcCaptureSamples alcCaptureSamples
|
||||
#define palEnable alEnable
|
||||
#define palDisable alDisable
|
||||
#define palIsEnabled alIsEnabled
|
||||
#define palGetString alGetString
|
||||
#define palGetBooleanv alGetBooleanv
|
||||
#define palGetIntegerv alGetIntegerv
|
||||
#define palGetFloatv alGetFloatv
|
||||
#define palGetDoublev alGetDoublev
|
||||
#define palGetBoolean alGetBoolean
|
||||
#define palGetInteger alGetInteger
|
||||
#define palGetFloat alGetFloat
|
||||
#define palGetDouble alGetDouble
|
||||
#define palGetError alGetError
|
||||
#define palIsExtensionPresent alIsExtensionPresent
|
||||
#define palGetProcAddress alGetProcAddress
|
||||
#define palGetEnumValue alGetEnumValue
|
||||
#define palListenerf alListenerf
|
||||
#define palListener3f alListener3f
|
||||
#define palListenerfv alListenerfv
|
||||
#define palListeneri alListeneri
|
||||
#define palListener3i alListener3i
|
||||
#define palListeneriv alListeneriv
|
||||
#define palGetListenerf alGetListenerf
|
||||
#define palGetListener3f alGetListener3f
|
||||
#define palGetListenerfv alGetListenerfv
|
||||
#define palGetListeneri alGetListeneri
|
||||
#define palGetListener3i alGetListener3i
|
||||
#define palGetListeneriv alGetListeneriv
|
||||
#define palGenSources alGenSources
|
||||
#define palDeleteSources alDeleteSources
|
||||
#define palIsSource alIsSource
|
||||
#define palSourcef alSourcef
|
||||
#define palSource3f alSource3f
|
||||
#define palSourcefv alSourcefv
|
||||
#define palSourcei alSourcei
|
||||
#define palSource3i alSource3i
|
||||
#define palSourceiv alSourceiv
|
||||
#define palGetSourcef alGetSourcef
|
||||
#define palGetSource3f alGetSource3f
|
||||
#define palGetSourcefv alGetSourcefv
|
||||
#define palGetSourcei alGetSourcei
|
||||
#define palGetSource3i alGetSource3i
|
||||
#define palGetSourceiv alGetSourceiv
|
||||
#define palSourcePlayv alSourcePlayv
|
||||
#define palSourceStopv alSourceStopv
|
||||
#define palSourceRewindv alSourceRewindv
|
||||
#define palSourcePausev alSourcePausev
|
||||
#define palSourcePlay alSourcePlay
|
||||
#define palSourceStop alSourceStop
|
||||
#define palSourceRewind alSourceRewind
|
||||
#define palSourcePause alSourcePause
|
||||
#define palSourceQueueBuffers alSourceQueueBuffers
|
||||
#define palSourceUnqueueBuffers alSourceUnqueueBuffers
|
||||
#define palGenBuffers alGenBuffers
|
||||
#define palDeleteBuffers alDeleteBuffers
|
||||
#define palIsBuffer alIsBuffer
|
||||
#define palBufferf alBufferf
|
||||
#define palBuffer3f alBuffer3f
|
||||
#define palBufferfv alBufferfv
|
||||
#define palBufferi alBufferi
|
||||
#define palBuffer3i alBuffer3i
|
||||
#define palBufferiv alBufferiv
|
||||
#define palGetBufferf alGetBufferf
|
||||
#define palGetBuffer3f alGetBuffer3f
|
||||
#define palGetBufferfv alGetBufferfv
|
||||
#define palGetBufferi alGetBufferi
|
||||
#define palGetBuffer3i alGetBuffer3i
|
||||
#define palGetBufferiv alGetBufferiv
|
||||
#define palBufferData alBufferData
|
||||
#define palDopplerFactor alDopplerFactor
|
||||
#define palDopplerVelocity alDopplerVelocity
|
||||
#define palDistanceModel alDistanceModel
|
||||
#define palSpeedOfSound alSpeedOfSound
|
||||
#endif
|
||||
|
||||
/* OpenAL only allows for 1 single access to the device at the same time */
|
||||
extern CRITICAL_SECTION openal_crst;
|
||||
extern int local_contexts;
|
||||
extern typeof(alcGetCurrentContext) *get_context;
|
||||
extern typeof(alcMakeContextCurrent) *set_context;
|
||||
|
||||
#define getALError() \
|
||||
do { \
|
||||
ALenum err = palGetError(); \
|
||||
if(err != AL_NO_ERROR) \
|
||||
{ \
|
||||
ERR(">>>>>>>>>>>> Received AL error %#x on context %p, %s:%u\n", err, get_context(), __FUNCTION__, __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define getALCError(dev) \
|
||||
do { \
|
||||
ALenum err = palcGetError(dev); \
|
||||
if(err != ALC_NO_ERROR) \
|
||||
{ \
|
||||
ERR(">>>>>>>>>>>> Received ALC error %#x on device %p, %s:%u\n", err, dev, __FUNCTION__, __LINE__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define setALContext(actx) \
|
||||
do { \
|
||||
ALCcontext *__old_ctx, *cur_ctx = actx ; \
|
||||
if (!local_contexts) EnterCriticalSection(&openal_crst); \
|
||||
__old_ctx = get_context(); \
|
||||
if (__old_ctx != cur_ctx && set_context(cur_ctx) == ALC_FALSE) {\
|
||||
ERR("Couldn't set current context!!\n"); \
|
||||
getALCError(palcGetContextsDevice(cur_ctx)); \
|
||||
}
|
||||
|
||||
/* Only restore a NULL context if using global contexts, for TLS contexts always restore */
|
||||
#define popALContext() \
|
||||
if (__old_ctx != cur_ctx \
|
||||
&& (local_contexts || __old_ctx) \
|
||||
&& set_context(__old_ctx) == ALC_FALSE) { \
|
||||
ERR("Couldn't restore old context!!\n"); \
|
||||
getALCError(palcGetContextsDevice(__old_ctx)); \
|
||||
} \
|
||||
if (!local_contexts) LeaveCriticalSection(&openal_crst); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue