Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
50140999
Commit
50140999
authored
Apr 22, 2011
by
Andrew Eikum
Committed by
Alexandre Julliard
Apr 25, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mmdevapi: Reimplement using a driver system.
parent
30b8d046
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
220 additions
and
2861 deletions
+220
-2861
Makefile.in
dlls/mmdevapi/Makefile.in
+0
-2
alext.h
dlls/mmdevapi/alext.h
+0
-144
audio.c
dlls/mmdevapi/audio.c
+0
-1909
audiovolume.c
dlls/mmdevapi/audiovolume.c
+0
-11
devenum.c
dlls/mmdevapi/devenum.c
+135
-288
main.c
dlls/mmdevapi/main.c
+67
-262
mmdevapi.h
dlls/mmdevapi/mmdevapi.h
+18
-245
No files found.
dlls/mmdevapi/Makefile.in
View file @
50140999
MODULE
=
mmdevapi.dll
IMPORTS
=
uuid ole32 oleaut32 user32 advapi32
EXTRALIBS
=
@FRAMEWORK_OPENAL@
C_SRCS
=
\
audio.c
\
audiovolume.c
\
devenum.c
\
main.c
...
...
dlls/mmdevapi/alext.h
deleted
100644 → 0
View file @
30b8d046
/**
* 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
dlls/mmdevapi/audio.c
deleted
100644 → 0
View file @
30b8d046
/*
* Copyright 2010 Maarten Lankhorst for CodeWeavers
*
* 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
*/
#define NONAMELESSUNION
#define COBJMACROS
#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"
#include "winnls.h"
#include "winreg.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "ole2.h"
#include "mmdeviceapi.h"
#include "dshow.h"
#include "dsound.h"
#include "audioclient.h"
#include "endpointvolume.h"
#include "audiopolicy.h"
#include "mmdevapi.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
mmdevapi
);
#ifdef HAVE_OPENAL
typedef
struct
ACRender
ACRender
;
typedef
struct
ACCapture
ACCapture
;
typedef
struct
ACSession
ACSession
;
typedef
struct
ASVolume
ASVolume
;
typedef
struct
AClock
AClock
;
typedef
struct
ACImpl
{
const
IAudioClientVtbl
*
lpVtbl
;
LONG
ref
;
MMDevice
*
parent
;
BOOL
init
,
running
;
CRITICAL_SECTION
*
crst
;
HANDLE
handle
;
DWORD
locked
,
flags
,
candisconnect
;
DWORD
bufsize_frames
,
ofs_frames
,
periodsize_frames
,
pad
,
padpartial
;
BYTE
*
buffer
;
WAVEFORMATEX
*
pwfx
;
ALuint
source
;
INT64
frameswritten
;
REFERENCE_TIME
laststamp
;
HANDLE
timer_id
;
ALCdevice
*
dev
;
ALint
format
;
ACRender
*
render
;
ACCapture
*
capture
;
ACSession
*
session
;
ASVolume
*
svolume
;
AClock
*
clock
;
}
ACImpl
;
struct
ACRender
{
const
IAudioRenderClientVtbl
*
lpVtbl
;
LONG
ref
;
ACImpl
*
parent
;
};
struct
ACCapture
{
const
IAudioCaptureClientVtbl
*
lpVtbl
;
LONG
ref
;
ACImpl
*
parent
;
};
struct
ACSession
{
const
IAudioSessionControl2Vtbl
*
lpVtbl
;
LONG
ref
;
ACImpl
*
parent
;
};
struct
ASVolume
{
const
ISimpleAudioVolumeVtbl
*
lpVtbl
;
LONG
ref
;
ACImpl
*
parent
;
};
struct
AClock
{
const
IAudioClockVtbl
*
lpVtbl
;
const
IAudioClock2Vtbl
*
lp2Vtbl
;
LONG
ref
;
ACImpl
*
parent
;
};
static
const
IAudioClientVtbl
ACImpl_Vtbl
;
static
const
IAudioRenderClientVtbl
ACRender_Vtbl
;
static
const
IAudioCaptureClientVtbl
ACCapture_Vtbl
;
static
const
IAudioSessionControl2Vtbl
ACSession_Vtbl
;
static
const
ISimpleAudioVolumeVtbl
ASVolume_Vtbl
;
static
const
IAudioClockVtbl
AClock_Vtbl
;
static
const
IAudioClock2Vtbl
AClock2_Vtbl
;
static
HRESULT
AudioRenderClient_Create
(
ACImpl
*
parent
,
ACRender
**
ppv
);
static
void
AudioRenderClient_Destroy
(
ACRender
*
This
);
static
HRESULT
AudioCaptureClient_Create
(
ACImpl
*
parent
,
ACCapture
**
ppv
);
static
void
AudioCaptureClient_Destroy
(
ACCapture
*
This
);
static
HRESULT
AudioSessionControl_Create
(
ACImpl
*
parent
,
ACSession
**
ppv
);
static
void
AudioSessionControl_Destroy
(
ACSession
*
This
);
static
HRESULT
AudioSimpleVolume_Create
(
ACImpl
*
parent
,
ASVolume
**
ppv
);
static
void
AudioSimpleVolume_Destroy
(
ASVolume
*
This
);
static
HRESULT
AudioClock_Create
(
ACImpl
*
parent
,
AClock
**
ppv
);
static
void
AudioClock_Destroy
(
AClock
*
This
);
static
int
valid_dev
(
ACImpl
*
This
)
{
if
(
!
This
->
dev
)
return
0
;
if
(
This
->
parent
->
flow
==
eRender
&&
This
->
dev
!=
This
->
parent
->
device
)
return
0
;
return
1
;
}
static
int
get_format_PCM
(
WAVEFORMATEX
*
format
)
{
if
(
format
->
nChannels
>
2
)
{
FIXME
(
"nChannels > 2 not documented for WAVE_FORMAT_PCM!
\n
"
);
return
0
;
}
format
->
cbSize
=
0
;
if
(
format
->
nBlockAlign
!=
format
->
wBitsPerSample
/
8
*
format
->
nChannels
)
{
WARN
(
"Invalid nBlockAlign %u, from %u %u
\n
"
,
format
->
nBlockAlign
,
format
->
wBitsPerSample
,
format
->
nChannels
);
return
0
;
}
switch
(
format
->
wBitsPerSample
)
{
case
8
:
{
switch
(
format
->
nChannels
)
{
case
1
:
return
AL_FORMAT_MONO8
;
case
2
:
return
AL_FORMAT_STEREO8
;
}
}
case
16
:
{
switch
(
format
->
nChannels
)
{
case
1
:
return
AL_FORMAT_MONO16
;
case
2
:
return
AL_FORMAT_STEREO16
;
}
}
}
if
(
!
(
format
->
wBitsPerSample
%
8
))
WARN
(
"Could not get OpenAL format (%d-bit, %d channels)
\n
"
,
format
->
wBitsPerSample
,
format
->
nChannels
);
return
0
;
}
/* Speaker configs */
#define MONO SPEAKER_FRONT_CENTER
#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
#define REAR (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
static
int
get_format_EXT
(
WAVEFORMATEX
*
format
)
{
WAVEFORMATEXTENSIBLE
*
wfe
;
if
(
format
->
cbSize
<
sizeof
(
WAVEFORMATEXTENSIBLE
)
-
sizeof
(
WAVEFORMATEX
))
{
WARN
(
"Invalid cbSize specified for WAVE_FORMAT_EXTENSIBLE (%d)
\n
"
,
format
->
cbSize
);
return
0
;
}
wfe
=
(
WAVEFORMATEXTENSIBLE
*
)
format
;
wfe
->
Format
.
cbSize
=
sizeof
(
WAVEFORMATEXTENSIBLE
)
-
sizeof
(
WAVEFORMATEX
);
if
(
wfe
->
Samples
.
wValidBitsPerSample
&&
wfe
->
Samples
.
wValidBitsPerSample
!=
format
->
wBitsPerSample
)
{
FIXME
(
"wValidBitsPerSample(%u) != wBitsPerSample(%u) unsupported
\n
"
,
wfe
->
Samples
.
wValidBitsPerSample
,
format
->
wBitsPerSample
);
return
0
;
}
TRACE
(
"Extensible values:
\n
"
" Samples = %d
\n
"
" ChannelMask = 0x%08x
\n
"
" SubFormat = %s
\n
"
,
wfe
->
Samples
.
wReserved
,
wfe
->
dwChannelMask
,
debugstr_guid
(
&
wfe
->
SubFormat
));
if
(
wfe
->
dwChannelMask
!=
MONO
&&
wfe
->
dwChannelMask
!=
STEREO
&&
!
palIsExtensionPresent
(
"AL_EXT_MCFORMATS"
))
{
/* QUAD PCM might still work, special case */
if
(
palIsExtensionPresent
(
"AL_LOKI_quadriphonic"
)
&&
IsEqualGUID
(
&
wfe
->
SubFormat
,
&
KSDATAFORMAT_SUBTYPE_PCM
)
&&
wfe
->
dwChannelMask
==
QUAD
)
{
if
(
format
->
wBitsPerSample
==
16
)
return
AL_FORMAT_QUAD16_LOKI
;
else
if
(
format
->
wBitsPerSample
==
8
)
return
AL_FORMAT_QUAD8_LOKI
;
}
WARN
(
"Not all formats available
\n
"
);
return
0
;
}
if
(
IsEqualGUID
(
&
wfe
->
SubFormat
,
&
KSDATAFORMAT_SUBTYPE_PCM
))
{
if
(
format
->
wBitsPerSample
==
8
)
{
switch
(
wfe
->
dwChannelMask
)
{
case
MONO
:
return
AL_FORMAT_MONO8
;
case
STEREO
:
return
AL_FORMAT_STEREO8
;
case
REAR
:
return
AL_FORMAT_REAR8
;
case
QUAD
:
return
AL_FORMAT_QUAD8
;
case
X5DOT1
:
return
AL_FORMAT_51CHN8
;
case
X6DOT1
:
return
AL_FORMAT_61CHN8
;
case
X7DOT1
:
return
AL_FORMAT_71CHN8
;
default:
break
;
}
}
else
if
(
format
->
wBitsPerSample
==
16
)
{
switch
(
wfe
->
dwChannelMask
)
{
case
MONO
:
return
AL_FORMAT_MONO16
;
case
STEREO
:
return
AL_FORMAT_STEREO16
;
case
REAR
:
return
AL_FORMAT_REAR16
;
case
QUAD
:
return
AL_FORMAT_QUAD16
;
case
X5DOT1
:
return
AL_FORMAT_51CHN16
;
case
X6DOT1
:
return
AL_FORMAT_61CHN16
;
case
X7DOT1
:
return
AL_FORMAT_71CHN16
;
default:
break
;
}
}
else
if
(
!
(
format
->
wBitsPerSample
%
8
))
ERR
(
"Could not get OpenAL PCM format (%d-bit, mask 0x%08x)
\n
"
,
format
->
wBitsPerSample
,
wfe
->
dwChannelMask
);
return
0
;
}
else
if
(
IsEqualGUID
(
&
wfe
->
SubFormat
,
&
KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))
{
if
(
format
->
wBitsPerSample
!=
32
)
{
WARN
(
"Invalid valid bits %u/32
\n
"
,
format
->
wBitsPerSample
);
return
0
;
}
switch
(
wfe
->
dwChannelMask
)
{
case
MONO
:
return
AL_FORMAT_MONO_FLOAT32
;
case
STEREO
:
return
AL_FORMAT_STEREO_FLOAT32
;
case
REAR
:
return
AL_FORMAT_REAR32
;
case
QUAD
:
return
AL_FORMAT_QUAD32
;
case
X5DOT1
:
return
AL_FORMAT_51CHN32
;
case
X6DOT1
:
return
AL_FORMAT_61CHN32
;
case
X7DOT1
:
return
AL_FORMAT_71CHN32
;
default:
ERR
(
"Could not get OpenAL float format (%d-bit, mask 0x%08x)
\n
"
,
format
->
wBitsPerSample
,
wfe
->
dwChannelMask
);
return
0
;
}
}
else
if
(
!
IsEqualGUID
(
&
wfe
->
SubFormat
,
&
GUID_NULL
))
ERR
(
"Unhandled extensible format: %s
\n
"
,
debugstr_guid
(
&
wfe
->
SubFormat
));
return
0
;
}
static
ALint
get_format
(
WAVEFORMATEX
*
in
)
{
int
ret
=
0
;
if
(
in
->
wFormatTag
==
WAVE_FORMAT_PCM
)
ret
=
get_format_PCM
(
in
);
else
if
(
in
->
wFormatTag
==
WAVE_FORMAT_EXTENSIBLE
)
ret
=
get_format_EXT
(
in
);
return
ret
;
}
static
REFERENCE_TIME
gettime
(
void
)
{
LARGE_INTEGER
stamp
,
freq
;
QueryPerformanceCounter
(
&
stamp
);
QueryPerformanceFrequency
(
&
freq
);
return
(
stamp
.
QuadPart
*
(
INT64
)
10000000
)
/
freq
.
QuadPart
;
}
HRESULT
AudioClient_Create
(
MMDevice
*
parent
,
IAudioClient
**
ppv
)
{
ACImpl
*
This
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
*
This
));
*
ppv
=
(
IAudioClient
*
)
This
;
if
(
!*
ppv
)
return
E_OUTOFMEMORY
;
This
->
crst
=
&
parent
->
crst
;
This
->
lpVtbl
=
&
ACImpl_Vtbl
;
This
->
ref
=
1
;
This
->
parent
=
parent
;
return
S_OK
;
}
static
void
AudioClient_Destroy
(
ACImpl
*
This
)
{
if
(
This
->
timer_id
)
{
DeleteTimerQueueTimer
(
NULL
,
This
->
timer_id
,
INVALID_HANDLE_VALUE
);
This
->
timer_id
=
0
;
}
if
(
This
->
render
)
AudioRenderClient_Destroy
(
This
->
render
);
if
(
This
->
capture
)
AudioCaptureClient_Destroy
(
This
->
capture
);
if
(
This
->
session
)
AudioSessionControl_Destroy
(
This
->
session
);
if
(
This
->
svolume
)
AudioSimpleVolume_Destroy
(
This
->
svolume
);
if
(
This
->
clock
)
AudioClock_Destroy
(
This
->
clock
);
if
(
!
valid_dev
(
This
))
TRACE
(
"Not destroying device since none exists
\n
"
);
else
if
(
This
->
parent
->
flow
==
eRender
)
{
setALContext
(
This
->
parent
->
ctx
);
IAudioClient_Stop
((
IAudioClient
*
)
This
);
IAudioClient_Reset
((
IAudioClient
*
)
This
);
palDeleteSources
(
1
,
&
This
->
source
);
getALError
();
popALContext
();
}
else
if
(
This
->
parent
->
flow
==
eCapture
)
palcCaptureCloseDevice
(
This
->
dev
);
HeapFree
(
GetProcessHeap
(),
0
,
This
->
pwfx
);
HeapFree
(
GetProcessHeap
(),
0
,
This
->
buffer
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
}
static
void
CALLBACK
AC_tick
(
void
*
data
,
BOOLEAN
fired
)
{
ACImpl
*
This
=
data
;
DWORD
pad
;
EnterCriticalSection
(
This
->
crst
);
if
(
This
->
running
)
IAudioClient_GetCurrentPadding
((
IAudioClient
*
)
This
,
&
pad
);
LeaveCriticalSection
(
This
->
crst
);
}
/* Open device and set/update internal mixing format based on information
* openal provides us. if the device cannot be opened, assume 48khz
* Guessing the frequency is harmless, since if GetMixFormat fails to open
* the device, then Initialize will likely fail as well
*/
static
HRESULT
AC_OpenRenderAL
(
ACImpl
*
This
)
{
char
alname
[
MAX_PATH
];
MMDevice
*
cur
=
This
->
parent
;
alname
[
sizeof
(
alname
)
-
1
]
=
0
;
if
(
cur
->
device
)
return
cur
->
ctx
?
S_OK
:
AUDCLNT_E_SERVICE_NOT_RUNNING
;
WideCharToMultiByte
(
CP_UNIXCP
,
0
,
cur
->
alname
,
-
1
,
alname
,
sizeof
(
alname
)
/
sizeof
(
*
alname
)
-
1
,
NULL
,
NULL
);
cur
->
device
=
palcOpenDevice
(
alname
);
if
(
!
cur
->
device
)
{
ALCenum
err
=
palcGetError
(
NULL
);
WARN
(
"Could not open device %s: 0x%04x
\n
"
,
alname
,
err
);
return
AUDCLNT_E_DEVICE_IN_USE
;
}
cur
->
ctx
=
palcCreateContext
(
cur
->
device
,
NULL
);
if
(
!
cur
->
ctx
)
{
ALCenum
err
=
palcGetError
(
cur
->
device
);
ERR
(
"Could not create context: 0x%04x
\n
"
,
err
);
return
AUDCLNT_E_SERVICE_NOT_RUNNING
;
}
if
(
!
cur
->
device
)
return
AUDCLNT_E_DEVICE_IN_USE
;
return
S_OK
;
}
static
HRESULT
AC_OpenCaptureAL
(
ACImpl
*
This
)
{
char
alname
[
MAX_PATH
];
ALint
freq
,
size_frames
;
freq
=
This
->
pwfx
->
nSamplesPerSec
;
size_frames
=
This
->
bufsize_frames
;
alname
[
sizeof
(
alname
)
-
1
]
=
0
;
if
(
This
->
dev
)
{
FIXME
(
"Attempting to open device while already open
\n
"
);
return
S_OK
;
}
WideCharToMultiByte
(
CP_UNIXCP
,
0
,
This
->
parent
->
alname
,
-
1
,
alname
,
sizeof
(
alname
)
/
sizeof
(
*
alname
)
-
1
,
NULL
,
NULL
);
This
->
dev
=
palcCaptureOpenDevice
(
alname
,
freq
,
This
->
format
,
size_frames
);
if
(
!
This
->
dev
)
{
ALCenum
err
=
palcGetError
(
NULL
);
FIXME
(
"Could not open device %s with buf size %u: 0x%04x
\n
"
,
alname
,
This
->
bufsize_frames
,
err
);
return
AUDCLNT_E_DEVICE_IN_USE
;
}
return
S_OK
;
}
static
HRESULT
WINAPI
AC_QueryInterface
(
IAudioClient
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
TRACE
(
"(%p)->(%s,%p)
\n
"
,
iface
,
debugstr_guid
(
riid
),
ppv
);
if
(
!
ppv
)
return
E_POINTER
;
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
)
||
IsEqualIID
(
riid
,
&
IID_IAudioClient
))
*
ppv
=
iface
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)
*
ppv
);
return
S_OK
;
}
WARN
(
"Unknown interface %s
\n
"
,
debugstr_guid
(
riid
));
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
AC_AddRef
(
IAudioClient
*
iface
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedIncrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
return
ref
;
}
static
ULONG
WINAPI
AC_Release
(
IAudioClient
*
iface
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedDecrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
if
(
!
ref
)
AudioClient_Destroy
(
This
);
return
ref
;
}
static
HRESULT
WINAPI
AC_Initialize
(
IAudioClient
*
iface
,
AUDCLNT_SHAREMODE
mode
,
DWORD
flags
,
REFERENCE_TIME
duration
,
REFERENCE_TIME
period
,
const
WAVEFORMATEX
*
pwfx
,
const
GUID
*
sessionguid
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
HRESULT
hr
=
S_OK
;
WAVEFORMATEX
*
pwfx2
;
REFERENCE_TIME
time
;
DWORD
bufsize_bytes
;
TRACE
(
"(%p)->(%x,%x,%u,%u,%p,%s)
\n
"
,
This
,
mode
,
flags
,
(
int
)
duration
,
(
int
)
period
,
pwfx
,
debugstr_guid
(
sessionguid
));
if
(
This
->
init
)
return
AUDCLNT_E_ALREADY_INITIALIZED
;
if
(
mode
!=
AUDCLNT_SHAREMODE_SHARED
&&
mode
!=
AUDCLNT_SHAREMODE_EXCLUSIVE
)
{
WARN
(
"Unknown mode %x
\n
"
,
mode
);
return
AUDCLNT_E_NOT_INITIALIZED
;
}
if
(
flags
&
~
(
AUDCLNT_STREAMFLAGS_CROSSPROCESS
|
AUDCLNT_STREAMFLAGS_LOOPBACK
|
AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
AUDCLNT_STREAMFLAGS_NOPERSIST
|
AUDCLNT_STREAMFLAGS_RATEADJUST
|
AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
|
AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
|
AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
))
{
WARN
(
"Unknown flags 0x%08x
\n
"
,
flags
);
return
E_INVALIDARG
;
}
if
(
flags
)
WARN
(
"Flags 0x%08x ignored
\n
"
,
flags
);
if
(
!
pwfx
)
return
E_POINTER
;
if
(
sessionguid
)
WARN
(
"Session guid %s ignored
\n
"
,
debugstr_guid
(
sessionguid
));
hr
=
IAudioClient_IsFormatSupported
(
iface
,
mode
,
pwfx
,
&
pwfx2
);
CoTaskMemFree
(
pwfx2
);
if
(
FAILED
(
hr
)
||
pwfx2
)
{
WARN
(
"Format not supported, or had to be modified!
\n
"
);
return
AUDCLNT_E_UNSUPPORTED_FORMAT
;
}
EnterCriticalSection
(
This
->
crst
);
HeapFree
(
GetProcessHeap
(),
0
,
This
->
pwfx
);
This
->
pwfx
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
pwfx
)
+
pwfx
->
cbSize
);
if
(
!
This
->
pwfx
)
{
hr
=
E_OUTOFMEMORY
;
goto
out
;
}
memcpy
(
This
->
pwfx
,
pwfx
,
sizeof
(
*
pwfx
)
+
pwfx
->
cbSize
);
if
(
pwfx
->
wFormatTag
==
WAVE_FORMAT_EXTENSIBLE
)
{
WAVEFORMATEXTENSIBLE
*
wfe
=
(
WAVEFORMATEXTENSIBLE
*
)
This
->
pwfx
;
switch
(
pwfx
->
nChannels
)
{
case
1
:
wfe
->
dwChannelMask
=
MONO
;
break
;
case
2
:
wfe
->
dwChannelMask
=
STEREO
;
break
;
case
4
:
wfe
->
dwChannelMask
=
QUAD
;
break
;
case
6
:
wfe
->
dwChannelMask
=
X5DOT1
;
break
;
case
7
:
wfe
->
dwChannelMask
=
X6DOT1
;
break
;
case
8
:
wfe
->
dwChannelMask
=
X7DOT1
;
break
;
default:
ERR
(
"How did we end up with %i channels?
\n
"
,
pwfx
->
nChannels
);
hr
=
AUDCLNT_E_UNSUPPORTED_FORMAT
;
goto
out
;
}
}
hr
=
IAudioClient_GetDevicePeriod
(
iface
,
&
time
,
NULL
);
if
(
FAILED
(
hr
))
goto
out
;
This
->
periodsize_frames
=
(
DWORD64
)
This
->
pwfx
->
nSamplesPerSec
*
time
/
(
DWORD64
)
10000000
;
if
(
duration
>
20000000
)
duration
=
20000000
;
This
->
bufsize_frames
=
duration
/
time
*
This
->
periodsize_frames
;
if
(
duration
%
time
)
This
->
bufsize_frames
+=
This
->
periodsize_frames
;
bufsize_bytes
=
This
->
bufsize_frames
*
pwfx
->
nBlockAlign
;
This
->
format
=
get_format
(
This
->
pwfx
);
if
(
This
->
parent
->
flow
==
eRender
)
{
char
silence
[
32
];
ALuint
buf
=
0
,
towrite
;
hr
=
AC_OpenRenderAL
(
This
);
This
->
dev
=
This
->
parent
->
device
;
if
(
FAILED
(
hr
))
goto
out
;
/* Test the returned format */
towrite
=
sizeof
(
silence
);
towrite
-=
towrite
%
This
->
pwfx
->
nBlockAlign
;
if
(
This
->
pwfx
->
wBitsPerSample
!=
8
)
memset
(
silence
,
0
,
sizeof
(
silence
));
else
memset
(
silence
,
128
,
sizeof
(
silence
));
setALContext
(
This
->
parent
->
ctx
);
getALError
();
palGenBuffers
(
1
,
&
buf
);
palBufferData
(
buf
,
This
->
format
,
silence
,
towrite
,
This
->
pwfx
->
nSamplesPerSec
);
palDeleteBuffers
(
1
,
&
buf
);
if
(
palGetError
())
hr
=
AUDCLNT_E_UNSUPPORTED_FORMAT
;
else
if
(
!
This
->
source
)
{
palGenSources
(
1
,
&
This
->
source
);
palSourcei
(
This
->
source
,
AL_LOOPING
,
AL_FALSE
);
getALError
();
}
popALContext
();
}
else
hr
=
AC_OpenCaptureAL
(
This
);
if
(
FAILED
(
hr
))
goto
out
;
This
->
candisconnect
=
palcIsExtensionPresent
(
This
->
dev
,
"ALC_EXT_disconnect"
);
This
->
buffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
bufsize_bytes
);
if
(
!
This
->
buffer
)
{
hr
=
E_OUTOFMEMORY
;
goto
out
;
}
This
->
flags
=
flags
;
This
->
handle
=
NULL
;
This
->
running
=
FALSE
;
This
->
init
=
TRUE
;
out:
LeaveCriticalSection
(
This
->
crst
);
return
hr
;
}
static
HRESULT
WINAPI
AC_GetBufferSize
(
IAudioClient
*
iface
,
UINT32
*
frames
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
frames
);
if
(
!
This
->
init
)
return
AUDCLNT_E_NOT_INITIALIZED
;
if
(
!
frames
)
return
E_POINTER
;
*
frames
=
This
->
bufsize_frames
;
return
S_OK
;
}
static
HRESULT
WINAPI
AC_GetStreamLatency
(
IAudioClient
*
iface
,
REFERENCE_TIME
*
latency
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
latency
);
if
(
!
This
->
init
)
return
AUDCLNT_E_NOT_INITIALIZED
;
if
(
!
latency
)
return
E_POINTER
;
*
latency
=
50000
;
return
S_OK
;
}
static
int
disconnected
(
ACImpl
*
This
)
{
if
(
!
This
->
candisconnect
)
return
0
;
if
(
This
->
parent
->
flow
==
eRender
)
{
if
(
This
->
parent
->
device
)
{
ALCint
con
=
1
;
palcGetIntegerv
(
This
->
parent
->
device
,
ALC_CONNECTED
,
1
,
&
con
);
palcGetError
(
This
->
parent
->
device
);
if
(
!
con
)
{
palcCloseDevice
(
This
->
parent
->
device
);
This
->
parent
->
device
=
NULL
;
This
->
parent
->
ctx
=
NULL
;
This
->
dev
=
NULL
;
}
}
if
(
!
This
->
parent
->
device
&&
FAILED
(
AC_OpenRenderAL
(
This
)))
{
This
->
pad
-=
This
->
padpartial
;
This
->
padpartial
=
0
;
return
1
;
}
if
(
This
->
parent
->
device
!=
This
->
dev
)
{
WARN
(
"Emptying buffer after newly reconnected!
\n
"
);
This
->
pad
-=
This
->
padpartial
;
This
->
padpartial
=
0
;
This
->
dev
=
This
->
parent
->
device
;
setALContext
(
This
->
parent
->
ctx
);
palGenSources
(
1
,
&
This
->
source
);
palSourcei
(
This
->
source
,
AL_LOOPING
,
AL_FALSE
);
getALError
();
if
(
This
->
render
&&
!
This
->
locked
&&
This
->
pad
)
{
UINT
pad
=
This
->
pad
;
BYTE
*
data
;
This
->
pad
=
0
;
/* Probably will cause sound glitches, who cares? */
IAudioRenderClient_GetBuffer
((
IAudioRenderClient
*
)
This
->
render
,
pad
,
&
data
);
IAudioRenderClient_ReleaseBuffer
((
IAudioRenderClient
*
)
This
->
render
,
pad
,
0
);
}
popALContext
();
}
}
else
{
if
(
This
->
dev
)
{
ALCint
con
=
1
;
palcGetIntegerv
(
This
->
dev
,
ALC_CONNECTED
,
1
,
&
con
);
palcGetError
(
This
->
dev
);
if
(
!
con
)
{
palcCaptureCloseDevice
(
This
->
dev
);
This
->
dev
=
NULL
;
}
}
if
(
!
This
->
dev
)
{
if
(
FAILED
(
AC_OpenCaptureAL
(
This
)))
return
1
;
WARN
(
"Emptying buffer after newly reconnected!
\n
"
);
This
->
pad
=
This
->
ofs_frames
=
0
;
if
(
This
->
running
)
palcCaptureStart
(
This
->
dev
);
}
}
return
0
;
}
static
HRESULT
WINAPI
AC_GetCurrentPadding
(
IAudioClient
*
iface
,
UINT32
*
numpad
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
ALint
avail
=
0
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
numpad
);
if
(
!
This
->
init
)
return
AUDCLNT_E_NOT_INITIALIZED
;
if
(
!
numpad
)
return
E_POINTER
;
EnterCriticalSection
(
This
->
crst
);
if
(
disconnected
(
This
))
{
REFERENCE_TIME
time
=
gettime
(),
period
;
WARN
(
"No device found, faking increment
\n
"
);
IAudioClient_GetDevicePeriod
(
iface
,
&
period
,
NULL
);
while
(
This
->
running
&&
time
-
This
->
laststamp
>=
period
)
{
This
->
laststamp
+=
period
;
if
(
This
->
parent
->
flow
==
eCapture
)
{
This
->
pad
+=
This
->
periodsize_frames
;
if
(
This
->
pad
>
This
->
bufsize_frames
)
This
->
pad
=
This
->
bufsize_frames
;
}
else
{
if
(
This
->
pad
<=
This
->
periodsize_frames
)
{
This
->
pad
=
0
;
break
;
}
else
This
->
pad
-=
This
->
periodsize_frames
;
}
}
if
(
This
->
parent
->
flow
==
eCapture
)
*
numpad
=
This
->
pad
>=
This
->
periodsize_frames
?
This
->
periodsize_frames
:
0
;
else
*
numpad
=
This
->
pad
;
}
else
if
(
This
->
parent
->
flow
==
eRender
)
{
UINT64
played
=
0
;
ALint
state
,
padpart
;
setALContext
(
This
->
parent
->
ctx
);
palGetSourcei
(
This
->
source
,
AL_BYTE_OFFSET
,
&
padpart
);
palGetSourcei
(
This
->
source
,
AL_SOURCE_STATE
,
&
state
);
padpart
/=
This
->
pwfx
->
nBlockAlign
;
if
(
state
==
AL_STOPPED
&&
This
->
running
)
padpart
=
This
->
pad
;
if
(
This
->
running
&&
This
->
padpartial
!=
padpart
)
{
This
->
padpartial
=
padpart
;
This
->
laststamp
=
gettime
();
#if 0 /* Manipulative lie */
} else if (This->running) {
ALint size = This->pad - padpart;
if (size > This->periodsize_frames)
size = This->periodsize_frames;
played = (gettime() - This->laststamp)*8;
played = played * This->pwfx->nSamplesPerSec / 10000000;
if (played > size)
played = size;
#endif
}
*
numpad
=
This
->
pad
-
This
->
padpartial
-
played
;
if
(
This
->
handle
&&
(
*
numpad
+
This
->
periodsize_frames
)
<=
This
->
bufsize_frames
)
SetEvent
(
This
->
handle
);
getALError
();
popALContext
();
}
else
{
DWORD
block
=
This
->
pwfx
->
nBlockAlign
;
palcGetIntegerv
(
This
->
dev
,
ALC_CAPTURE_SAMPLES
,
1
,
&
avail
);
if
(
avail
)
{
DWORD
ofs_frames
=
This
->
ofs_frames
+
This
->
pad
;
BYTE
*
buf1
;
ofs_frames
%=
This
->
bufsize_frames
;
buf1
=
This
->
buffer
+
(
ofs_frames
*
block
);
This
->
laststamp
=
gettime
();
if
(
This
->
handle
)
SetEvent
(
This
->
handle
);
if
(
ofs_frames
+
avail
<=
This
->
bufsize_frames
)
palcCaptureSamples
(
This
->
dev
,
buf1
,
avail
);
else
{
DWORD
part1
=
This
->
bufsize_frames
-
ofs_frames
;
palcCaptureSamples
(
This
->
dev
,
buf1
,
part1
);
palcCaptureSamples
(
This
->
dev
,
This
->
buffer
,
avail
-
part1
);
}
This
->
pad
+=
avail
;
This
->
frameswritten
+=
avail
;
/* Increase ofs if the app forgets to read */
if
(
This
->
pad
>
This
->
bufsize_frames
)
{
DWORD
rest
;
WARN
(
"Overflowed! %u frames
\n
"
,
This
->
pad
-
This
->
bufsize_frames
);
This
->
ofs_frames
+=
This
->
pad
-
This
->
bufsize_frames
;
rest
=
This
->
ofs_frames
%
This
->
periodsize_frames
;
if
(
rest
)
This
->
ofs_frames
+=
This
->
periodsize_frames
-
rest
;
This
->
ofs_frames
%=
This
->
bufsize_frames
;
This
->
pad
=
This
->
bufsize_frames
;
}
}
if
(
This
->
pad
>=
This
->
periodsize_frames
)
*
numpad
=
This
->
periodsize_frames
;
else
*
numpad
=
0
;
}
LeaveCriticalSection
(
This
->
crst
);
TRACE
(
"%u queued
\n
"
,
*
numpad
);
return
S_OK
;
}
static
HRESULT
WINAPI
AC_IsFormatSupported
(
IAudioClient
*
iface
,
AUDCLNT_SHAREMODE
mode
,
const
WAVEFORMATEX
*
pwfx
,
WAVEFORMATEX
**
outpwfx
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
WAVEFORMATEX
*
tmp
;
DWORD
mask
;
DWORD
size
;
TRACE
(
"(%p)->(%x,%p,%p)
\n
"
,
This
,
mode
,
pwfx
,
outpwfx
);
if
(
!
pwfx
)
return
E_POINTER
;
if
(
mode
==
AUDCLNT_SHAREMODE_SHARED
&&
!
outpwfx
)
return
E_POINTER
;
if
(
mode
!=
AUDCLNT_SHAREMODE_SHARED
&&
mode
!=
AUDCLNT_SHAREMODE_EXCLUSIVE
)
{
WARN
(
"Unknown mode %x
\n
"
,
mode
);
return
E_INVALIDARG
;
}
if
(
pwfx
->
wFormatTag
==
WAVE_FORMAT_EXTENSIBLE
)
size
=
sizeof
(
WAVEFORMATEXTENSIBLE
);
else
if
(
pwfx
->
wFormatTag
==
WAVE_FORMAT_PCM
)
size
=
sizeof
(
WAVEFORMATEX
);
else
return
AUDCLNT_E_UNSUPPORTED_FORMAT
;
if
(
pwfx
->
nSamplesPerSec
<
8000
||
pwfx
->
nSamplesPerSec
>
192000
)
return
AUDCLNT_E_UNSUPPORTED_FORMAT
;
if
(
pwfx
->
wFormatTag
!=
WAVE_FORMAT_EXTENSIBLE
||
!
IsEqualIID
(
&
((
WAVEFORMATEXTENSIBLE
*
)
pwfx
)
->
SubFormat
,
&
KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))
{
if
(
pwfx
->
wBitsPerSample
>
16
)
return
AUDCLNT_E_UNSUPPORTED_FORMAT
;
}
switch
(
pwfx
->
nChannels
)
{
case
1
:
mask
=
MONO
;
break
;
case
2
:
mask
=
STEREO
;
break
;
case
4
:
mask
=
QUAD
;
break
;
case
6
:
mask
=
X5DOT1
;
break
;
case
7
:
mask
=
X6DOT1
;
break
;
case
8
:
mask
=
X7DOT1
;
break
;
default:
TRACE
(
"Unsupported channel count %i
\n
"
,
pwfx
->
nChannels
);
return
AUDCLNT_E_UNSUPPORTED_FORMAT
;
}
tmp
=
CoTaskMemAlloc
(
size
);
if
(
outpwfx
)
*
outpwfx
=
tmp
;
if
(
!
tmp
)
return
E_OUTOFMEMORY
;
memcpy
(
tmp
,
pwfx
,
size
);
tmp
->
nBlockAlign
=
tmp
->
nChannels
*
tmp
->
wBitsPerSample
/
8
;
tmp
->
nAvgBytesPerSec
=
tmp
->
nBlockAlign
*
tmp
->
nSamplesPerSec
;
tmp
->
cbSize
=
size
-
sizeof
(
WAVEFORMATEX
);
if
(
tmp
->
wFormatTag
==
WAVE_FORMAT_EXTENSIBLE
)
{
WAVEFORMATEXTENSIBLE
*
ex
=
(
WAVEFORMATEXTENSIBLE
*
)
tmp
;
if
(
ex
->
Samples
.
wValidBitsPerSample
)
ex
->
Samples
.
wValidBitsPerSample
=
ex
->
Format
.
wBitsPerSample
;
/* Rear is a special allowed case */
if
(
ex
->
dwChannelMask
&&
!
(
ex
->
Format
.
nChannels
==
2
&&
ex
->
dwChannelMask
==
REAR
))
ex
->
dwChannelMask
=
mask
;
}
if
(
memcmp
(
pwfx
,
tmp
,
size
))
{
if
(
outpwfx
)
return
S_FALSE
;
CoTaskMemFree
(
tmp
);
return
AUDCLNT_E_UNSUPPORTED_FORMAT
;
}
if
(
outpwfx
)
*
outpwfx
=
NULL
;
CoTaskMemFree
(
tmp
);
return
S_OK
;
}
static
HRESULT
WINAPI
AC_GetMixFormat
(
IAudioClient
*
iface
,
WAVEFORMATEX
**
pwfx
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
PROPVARIANT
pv
=
{
VT_EMPTY
};
HRESULT
hr
=
S_OK
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
pwfx
);
if
(
!
pwfx
)
return
E_POINTER
;
hr
=
MMDevice_GetPropValue
(
&
This
->
parent
->
devguid
,
This
->
parent
->
flow
,
&
PKEY_AudioEngine_DeviceFormat
,
&
pv
);
*
pwfx
=
(
WAVEFORMATEX
*
)
pv
.
u
.
blob
.
pBlobData
;
if
(
SUCCEEDED
(
hr
)
&&
pv
.
vt
==
VT_EMPTY
)
return
E_FAIL
;
TRACE
(
"Returning 0x%08x
\n
"
,
hr
);
return
hr
;
}
static
HRESULT
WINAPI
AC_GetDevicePeriod
(
IAudioClient
*
iface
,
REFERENCE_TIME
*
defperiod
,
REFERENCE_TIME
*
minperiod
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
minperiod
);
if
(
!
defperiod
&&
!
minperiod
)
return
E_POINTER
;
if
(
minperiod
)
*
minperiod
=
30000
;
if
(
defperiod
)
*
defperiod
=
200000
;
return
S_OK
;
}
static
HRESULT
WINAPI
AC_Start
(
IAudioClient
*
iface
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
HRESULT
hr
;
REFERENCE_TIME
refresh
;
TRACE
(
"(%p)
\n
"
,
This
);
if
(
!
This
->
init
)
return
AUDCLNT_E_NOT_INITIALIZED
;
if
(
This
->
flags
&
AUDCLNT_STREAMFLAGS_EVENTCALLBACK
)
{
if
(
!
This
->
handle
)
return
AUDCLNT_E_EVENTHANDLE_NOT_SET
;
FIXME
(
"Event handles not fully tested
\n
"
);
}
EnterCriticalSection
(
This
->
crst
);
if
(
This
->
running
)
{
hr
=
AUDCLNT_E_NOT_STOPPED
;
goto
out
;
}
if
(
!
valid_dev
(
This
))
WARN
(
"No valid device
\n
"
);
else
if
(
This
->
parent
->
flow
==
eRender
)
{
setALContext
(
This
->
parent
->
ctx
);
palSourcePlay
(
This
->
source
);
getALError
();
popALContext
();
}
else
palcCaptureStart
(
This
->
dev
);
AC_GetDevicePeriod
(
iface
,
&
refresh
,
NULL
);
if
(
!
This
->
timer_id
&&
This
->
handle
)
CreateTimerQueueTimer
(
&
This
->
timer_id
,
NULL
,
AC_tick
,
This
,
refresh
/
20000
,
refresh
/
20000
,
WT_EXECUTEINTIMERTHREAD
);
/* Set to 0, otherwise risk running the clock backwards
* This will cause AudioClock::GetPosition to return the maximum
* possible value for the current buffer
*/
This
->
laststamp
=
0
;
This
->
running
=
TRUE
;
hr
=
S_OK
;
out:
LeaveCriticalSection
(
This
->
crst
);
return
hr
;
}
static
HRESULT
WINAPI
AC_Stop
(
IAudioClient
*
iface
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
HANDLE
timer_id
;
TRACE
(
"(%p)
\n
"
,
This
);
if
(
!
This
->
init
)
return
AUDCLNT_E_NOT_INITIALIZED
;
if
(
!
This
->
running
)
return
S_FALSE
;
EnterCriticalSection
(
This
->
crst
);
if
(
!
valid_dev
(
This
))
WARN
(
"No valid device
\n
"
);
else
if
(
This
->
parent
->
flow
==
eRender
)
{
ALint
state
;
setALContext
(
This
->
parent
->
ctx
);
palSourcePause
(
This
->
source
);
while
(
1
)
{
state
=
AL_STOPPED
;
palGetSourcei
(
This
->
source
,
AL_SOURCE_STATE
,
&
state
);
if
(
state
!=
AL_PLAYING
)
break
;
Sleep
(
1
);
}
getALError
();
popALContext
();
}
else
palcCaptureStop
(
This
->
dev
);
This
->
running
=
FALSE
;
timer_id
=
This
->
timer_id
;
This
->
timer_id
=
0
;
LeaveCriticalSection
(
This
->
crst
);
if
(
timer_id
)
DeleteTimerQueueTimer
(
NULL
,
timer_id
,
INVALID_HANDLE_VALUE
);
return
S_OK
;
}
static
HRESULT
WINAPI
AC_Reset
(
IAudioClient
*
iface
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
HRESULT
hr
=
S_OK
;
TRACE
(
"(%p)
\n
"
,
This
);
if
(
!
This
->
init
)
return
AUDCLNT_E_NOT_INITIALIZED
;
if
(
This
->
running
)
return
AUDCLNT_E_NOT_STOPPED
;
EnterCriticalSection
(
This
->
crst
);
if
(
This
->
locked
)
{
hr
=
AUDCLNT_E_BUFFER_OPERATION_PENDING
;
goto
out
;
}
if
(
!
valid_dev
(
This
))
WARN
(
"No valid device
\n
"
);
else
if
(
This
->
parent
->
flow
==
eRender
)
{
ALuint
buf
;
ALint
n
=
0
;
setALContext
(
This
->
parent
->
ctx
);
palSourceStop
(
This
->
source
);
palGetSourcei
(
This
->
source
,
AL_BUFFERS_PROCESSED
,
&
n
);
while
(
n
--
)
{
palSourceUnqueueBuffers
(
This
->
source
,
1
,
&
buf
);
palDeleteBuffers
(
1
,
&
buf
);
}
getALError
();
popALContext
();
}
else
{
ALint
avail
=
0
;
palcGetIntegerv
(
This
->
dev
,
ALC_CAPTURE_SAMPLES
,
1
,
&
avail
);
if
(
avail
)
palcCaptureSamples
(
This
->
dev
,
This
->
buffer
,
avail
);
}
This
->
pad
=
This
->
padpartial
=
0
;
This
->
ofs_frames
=
0
;
This
->
frameswritten
=
0
;
out:
LeaveCriticalSection
(
This
->
crst
);
return
hr
;
}
static
HRESULT
WINAPI
AC_SetEventHandle
(
IAudioClient
*
iface
,
HANDLE
handle
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
TRACE
(
"(%p)
\n
"
,
This
);
if
(
!
This
->
init
)
return
AUDCLNT_E_NOT_INITIALIZED
;
if
(
!
handle
)
return
E_INVALIDARG
;
if
(
!
(
This
->
flags
&
AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
return
AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
This
->
handle
=
handle
;
return
S_OK
;
}
static
HRESULT
WINAPI
AC_GetService
(
IAudioClient
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
ACImpl
*
This
=
(
ACImpl
*
)
iface
;
HRESULT
hr
=
S_OK
;
TRACE
(
"(%p)->(%s,%p)
\n
"
,
This
,
debugstr_guid
(
riid
),
ppv
);
if
(
!
This
->
init
)
return
AUDCLNT_E_NOT_INITIALIZED
;
if
(
!
ppv
)
return
E_POINTER
;
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IAudioRenderClient
))
{
if
(
This
->
parent
->
flow
!=
eRender
)
return
AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
if
(
!
This
->
render
)
hr
=
AudioRenderClient_Create
(
This
,
&
This
->
render
);
*
ppv
=
This
->
render
;
}
else
if
(
IsEqualIID
(
riid
,
&
IID_IAudioCaptureClient
))
{
if
(
This
->
parent
->
flow
!=
eCapture
)
return
AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
if
(
!
This
->
capture
)
hr
=
AudioCaptureClient_Create
(
This
,
&
This
->
capture
);
*
ppv
=
This
->
capture
;
}
else
if
(
IsEqualIID
(
riid
,
&
IID_IAudioSessionControl
))
{
if
(
!
This
->
session
)
hr
=
AudioSessionControl_Create
(
This
,
&
This
->
session
);
*
ppv
=
This
->
session
;
}
else
if
(
IsEqualIID
(
riid
,
&
IID_ISimpleAudioVolume
))
{
if
(
!
This
->
svolume
)
hr
=
AudioSimpleVolume_Create
(
This
,
&
This
->
svolume
);
*
ppv
=
This
->
svolume
;
}
else
if
(
IsEqualIID
(
riid
,
&
IID_IAudioClock
))
{
if
(
!
This
->
clock
)
hr
=
AudioClock_Create
(
This
,
&
This
->
clock
);
*
ppv
=
This
->
clock
;
}
if
(
FAILED
(
hr
))
return
hr
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)
*
ppv
);
return
S_OK
;
}
FIXME
(
"stub %s
\n
"
,
debugstr_guid
(
riid
));
return
E_NOINTERFACE
;
}
static
const
IAudioClientVtbl
ACImpl_Vtbl
=
{
AC_QueryInterface
,
AC_AddRef
,
AC_Release
,
AC_Initialize
,
AC_GetBufferSize
,
AC_GetStreamLatency
,
AC_GetCurrentPadding
,
AC_IsFormatSupported
,
AC_GetMixFormat
,
AC_GetDevicePeriod
,
AC_Start
,
AC_Stop
,
AC_Reset
,
AC_SetEventHandle
,
AC_GetService
};
static
HRESULT
AudioRenderClient_Create
(
ACImpl
*
parent
,
ACRender
**
ppv
)
{
ACRender
*
This
;
This
=
*
ppv
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
This
));
if
(
!
This
)
return
E_OUTOFMEMORY
;
This
->
lpVtbl
=
&
ACRender_Vtbl
;
This
->
ref
=
0
;
This
->
parent
=
parent
;
AC_AddRef
((
IAudioClient
*
)
This
->
parent
);
return
S_OK
;
}
static
void
AudioRenderClient_Destroy
(
ACRender
*
This
)
{
This
->
parent
->
render
=
NULL
;
AC_Release
((
IAudioClient
*
)
This
->
parent
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
}
static
HRESULT
WINAPI
ACR_QueryInterface
(
IAudioRenderClient
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
TRACE
(
"(%p)->(%s,%p)
\n
"
,
iface
,
debugstr_guid
(
riid
),
ppv
);
if
(
!
ppv
)
return
E_POINTER
;
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
)
||
IsEqualIID
(
riid
,
&
IID_IAudioRenderClient
))
*
ppv
=
iface
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)
*
ppv
);
return
S_OK
;
}
WARN
(
"Unknown interface %s
\n
"
,
debugstr_guid
(
riid
));
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
ACR_AddRef
(
IAudioRenderClient
*
iface
)
{
ACRender
*
This
=
(
ACRender
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedIncrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
return
ref
;
}
static
ULONG
WINAPI
ACR_Release
(
IAudioRenderClient
*
iface
)
{
ACRender
*
This
=
(
ACRender
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedDecrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
if
(
!
ref
)
AudioRenderClient_Destroy
(
This
);
return
ref
;
}
static
HRESULT
WINAPI
ACR_GetBuffer
(
IAudioRenderClient
*
iface
,
UINT32
frames
,
BYTE
**
data
)
{
ACRender
*
This
=
(
ACRender
*
)
iface
;
DWORD
free
,
framesize
;
TRACE
(
"(%p)->(%u,%p)
\n
"
,
This
,
frames
,
data
);
if
(
!
data
)
return
E_POINTER
;
if
(
!
frames
)
return
S_OK
;
*
data
=
NULL
;
if
(
This
->
parent
->
locked
)
{
ERR
(
"Locked
\n
"
);
return
AUDCLNT_E_OUT_OF_ORDER
;
}
AC_GetCurrentPadding
((
IAudioClient
*
)
This
->
parent
,
&
free
);
if
(
This
->
parent
->
bufsize_frames
-
free
<
frames
)
{
ERR
(
"Too large: %u %u %u
\n
"
,
This
->
parent
->
bufsize_frames
,
free
,
frames
);
return
AUDCLNT_E_BUFFER_TOO_LARGE
;
}
EnterCriticalSection
(
This
->
parent
->
crst
);
This
->
parent
->
locked
=
frames
;
framesize
=
This
->
parent
->
pwfx
->
nBlockAlign
;
/* Exact offset doesn't matter, offset could be 0 forever
* but increasing it is easier to debug */
if
(
This
->
parent
->
ofs_frames
+
frames
>
This
->
parent
->
bufsize_frames
)
This
->
parent
->
ofs_frames
=
0
;
*
data
=
This
->
parent
->
buffer
+
This
->
parent
->
ofs_frames
*
framesize
;
LeaveCriticalSection
(
This
->
parent
->
crst
);
return
S_OK
;
}
static
HRESULT
WINAPI
ACR_ReleaseBuffer
(
IAudioRenderClient
*
iface
,
UINT32
written_frames
,
DWORD
flags
)
{
ACRender
*
This
=
(
ACRender
*
)
iface
;
BYTE
*
buf
=
This
->
parent
->
buffer
;
DWORD
framesize
=
This
->
parent
->
pwfx
->
nBlockAlign
;
DWORD
ofs_bytes
=
This
->
parent
->
ofs_frames
*
framesize
;
DWORD
written_bytes
=
written_frames
*
framesize
;
DWORD
freq
=
This
->
parent
->
pwfx
->
nSamplesPerSec
;
DWORD
bpp
=
This
->
parent
->
pwfx
->
wBitsPerSample
;
ALuint
albuf
;
TRACE
(
"(%p)->(%u,%x)
\n
"
,
This
,
written_frames
,
flags
);
if
(
This
->
parent
->
locked
<
written_frames
)
return
AUDCLNT_E_INVALID_SIZE
;
if
(
flags
&
~
AUDCLNT_BUFFERFLAGS_SILENT
)
return
E_INVALIDARG
;
if
(
!
written_frames
)
{
if
(
This
->
parent
->
locked
)
FIXME
(
"Handled right?
\n
"
);
This
->
parent
->
locked
=
0
;
return
S_OK
;
}
if
(
!
This
->
parent
->
locked
)
return
AUDCLNT_E_OUT_OF_ORDER
;
EnterCriticalSection
(
This
->
parent
->
crst
);
This
->
parent
->
ofs_frames
+=
written_frames
;
This
->
parent
->
ofs_frames
%=
This
->
parent
->
bufsize_frames
;
This
->
parent
->
pad
+=
written_frames
;
This
->
parent
->
frameswritten
+=
written_frames
;
This
->
parent
->
locked
=
0
;
if
(
flags
&
AUDCLNT_BUFFERFLAGS_SILENT
)
memset
(
buf
+
ofs_bytes
,
bpp
!=
8
?
0
:
128
,
written_bytes
);
TRACE
(
"buf: %p, ofs: %x, written %u, freq %u
\n
"
,
buf
,
ofs_bytes
,
written_bytes
,
freq
);
if
(
!
valid_dev
(
This
->
parent
))
goto
out
;
setALContext
(
This
->
parent
->
parent
->
ctx
);
palGenBuffers
(
1
,
&
albuf
);
palBufferData
(
albuf
,
This
->
parent
->
format
,
buf
+
ofs_bytes
,
written_bytes
,
freq
);
palSourceQueueBuffers
(
This
->
parent
->
source
,
1
,
&
albuf
);
TRACE
(
"Queued %u
\n
"
,
albuf
);
if
(
This
->
parent
->
running
)
{
ALint
state
=
AL_PLAYING
,
done
=
0
,
padpart
=
0
;
palGetSourcei
(
This
->
parent
->
source
,
AL_BUFFERS_PROCESSED
,
&
done
);
palGetSourcei
(
This
->
parent
->
source
,
AL_BYTE_OFFSET
,
&
padpart
);
palGetSourcei
(
This
->
parent
->
source
,
AL_SOURCE_STATE
,
&
state
);
padpart
/=
framesize
;
if
(
state
==
AL_STOPPED
)
{
padpart
=
This
->
parent
->
pad
;
/* Buffer might have been processed in the small window
* between first and third call */
palGetSourcei
(
This
->
parent
->
source
,
AL_BUFFERS_PROCESSED
,
&
done
);
}
if
(
done
||
This
->
parent
->
padpartial
!=
padpart
)
This
->
parent
->
laststamp
=
gettime
();
This
->
parent
->
padpartial
=
padpart
;
while
(
done
--
)
{
ALint
size
,
bits
,
chan
;
ALuint
which
;
palSourceUnqueueBuffers
(
This
->
parent
->
source
,
1
,
&
which
);
palGetBufferi
(
which
,
AL_SIZE
,
&
size
);
palGetBufferi
(
which
,
AL_BITS
,
&
bits
);
palGetBufferi
(
which
,
AL_CHANNELS
,
&
chan
);
size
/=
bits
*
chan
/
8
;
if
(
size
>
This
->
parent
->
pad
)
{
ERR
(
"Overflow!
\n
"
);
size
=
This
->
parent
->
pad
;
}
This
->
parent
->
pad
-=
size
;
This
->
parent
->
padpartial
-=
size
;
TRACE
(
"Unqueued %u
\n
"
,
which
);
palDeleteBuffers
(
1
,
&
which
);
}
if
(
state
!=
AL_PLAYING
)
{
ERR
(
"Starting from %x
\n
"
,
state
);
palSourcePlay
(
This
->
parent
->
source
);
}
getALError
();
}
getALError
();
popALContext
();
out:
LeaveCriticalSection
(
This
->
parent
->
crst
);
return
S_OK
;
}
static
const
IAudioRenderClientVtbl
ACRender_Vtbl
=
{
ACR_QueryInterface
,
ACR_AddRef
,
ACR_Release
,
ACR_GetBuffer
,
ACR_ReleaseBuffer
};
static
HRESULT
AudioCaptureClient_Create
(
ACImpl
*
parent
,
ACCapture
**
ppv
)
{
ACCapture
*
This
;
This
=
*
ppv
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
This
));
if
(
!
This
)
return
E_OUTOFMEMORY
;
This
->
lpVtbl
=
&
ACCapture_Vtbl
;
This
->
ref
=
0
;
This
->
parent
=
parent
;
AC_AddRef
((
IAudioClient
*
)
This
->
parent
);
return
S_OK
;
}
static
void
AudioCaptureClient_Destroy
(
ACCapture
*
This
)
{
This
->
parent
->
capture
=
NULL
;
AC_Release
((
IAudioClient
*
)
This
->
parent
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
}
static
HRESULT
WINAPI
ACC_QueryInterface
(
IAudioCaptureClient
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
TRACE
(
"(%p)->(%s,%p)
\n
"
,
iface
,
debugstr_guid
(
riid
),
ppv
);
if
(
!
ppv
)
return
E_POINTER
;
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
)
||
IsEqualIID
(
riid
,
&
IID_IAudioCaptureClient
))
*
ppv
=
iface
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)
*
ppv
);
return
S_OK
;
}
WARN
(
"Unknown interface %s
\n
"
,
debugstr_guid
(
riid
));
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
ACC_AddRef
(
IAudioCaptureClient
*
iface
)
{
ACCapture
*
This
=
(
ACCapture
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedIncrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
return
ref
;
}
static
ULONG
WINAPI
ACC_Release
(
IAudioCaptureClient
*
iface
)
{
ACCapture
*
This
=
(
ACCapture
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedDecrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
if
(
!
ref
)
AudioCaptureClient_Destroy
(
This
);
return
ref
;
}
static
HRESULT
WINAPI
ACC_GetBuffer
(
IAudioCaptureClient
*
iface
,
BYTE
**
data
,
UINT32
*
frames
,
DWORD
*
flags
,
UINT64
*
devpos
,
UINT64
*
qpcpos
)
{
ACCapture
*
This
=
(
ACCapture
*
)
iface
;
HRESULT
hr
;
DWORD
block
=
This
->
parent
->
pwfx
->
nBlockAlign
;
DWORD
ofs
;
TRACE
(
"(%p)->(%p,%p,%p,%p,%p)
\n
"
,
This
,
data
,
frames
,
flags
,
devpos
,
qpcpos
);
if
(
!
data
)
return
E_POINTER
;
if
(
!
frames
)
return
E_POINTER
;
if
(
!
flags
)
{
FIXME
(
"Flags can be null?
\n
"
);
return
E_POINTER
;
}
EnterCriticalSection
(
This
->
parent
->
crst
);
hr
=
AUDCLNT_E_OUT_OF_ORDER
;
if
(
This
->
parent
->
locked
)
goto
out
;
IAudioCaptureClient_GetNextPacketSize
(
iface
,
frames
);
ofs
=
This
->
parent
->
ofs_frames
;
if
(
ofs
%
This
->
parent
->
periodsize_frames
)
ERR
(
"Unaligned offset %u with %u
\n
"
,
ofs
,
This
->
parent
->
periodsize_frames
);
*
data
=
This
->
parent
->
buffer
+
ofs
*
block
;
This
->
parent
->
locked
=
*
frames
;
if
(
devpos
)
*
devpos
=
This
->
parent
->
frameswritten
-
This
->
parent
->
pad
;
if
(
qpcpos
)
*
qpcpos
=
This
->
parent
->
laststamp
;
if
(
*
frames
)
hr
=
S_OK
;
else
hr
=
AUDCLNT_S_BUFFER_EMPTY
;
out:
LeaveCriticalSection
(
This
->
parent
->
crst
);
TRACE
(
"Returning %08x %i
\n
"
,
hr
,
*
frames
);
return
hr
;
}
static
HRESULT
WINAPI
ACC_ReleaseBuffer
(
IAudioCaptureClient
*
iface
,
UINT32
written
)
{
ACCapture
*
This
=
(
ACCapture
*
)
iface
;
HRESULT
hr
=
S_OK
;
EnterCriticalSection
(
This
->
parent
->
crst
);
if
(
!
written
||
written
==
This
->
parent
->
locked
)
{
This
->
parent
->
locked
=
0
;
This
->
parent
->
ofs_frames
+=
written
;
This
->
parent
->
ofs_frames
%=
This
->
parent
->
bufsize_frames
;
This
->
parent
->
pad
-=
written
;
}
else
if
(
!
This
->
parent
->
locked
)
hr
=
AUDCLNT_E_OUT_OF_ORDER
;
else
hr
=
AUDCLNT_E_INVALID_SIZE
;
LeaveCriticalSection
(
This
->
parent
->
crst
);
return
hr
;
}
static
HRESULT
WINAPI
ACC_GetNextPacketSize
(
IAudioCaptureClient
*
iface
,
UINT32
*
frames
)
{
ACCapture
*
This
=
(
ACCapture
*
)
iface
;
return
AC_GetCurrentPadding
((
IAudioClient
*
)
This
->
parent
,
frames
);
}
static
const
IAudioCaptureClientVtbl
ACCapture_Vtbl
=
{
ACC_QueryInterface
,
ACC_AddRef
,
ACC_Release
,
ACC_GetBuffer
,
ACC_ReleaseBuffer
,
ACC_GetNextPacketSize
};
static
HRESULT
AudioSessionControl_Create
(
ACImpl
*
parent
,
ACSession
**
ppv
)
{
ACSession
*
This
;
This
=
*
ppv
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
This
));
if
(
!
This
)
return
E_OUTOFMEMORY
;
This
->
lpVtbl
=
&
ACSession_Vtbl
;
This
->
ref
=
0
;
This
->
parent
=
parent
;
AC_AddRef
((
IAudioClient
*
)
This
->
parent
);
return
S_OK
;
}
static
void
AudioSessionControl_Destroy
(
ACSession
*
This
)
{
This
->
parent
->
session
=
NULL
;
AC_Release
((
IAudioClient
*
)
This
->
parent
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
}
static
HRESULT
WINAPI
ACS_QueryInterface
(
IAudioSessionControl2
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
TRACE
(
"(%p)->(%s,%p)
\n
"
,
iface
,
debugstr_guid
(
riid
),
ppv
);
if
(
!
ppv
)
return
E_POINTER
;
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
)
||
IsEqualIID
(
riid
,
&
IID_IAudioSessionControl
)
||
IsEqualIID
(
riid
,
&
IID_IAudioSessionControl2
))
*
ppv
=
iface
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)
*
ppv
);
return
S_OK
;
}
WARN
(
"Unknown interface %s
\n
"
,
debugstr_guid
(
riid
));
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
ACS_AddRef
(
IAudioSessionControl2
*
iface
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedIncrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
return
ref
;
}
static
ULONG
WINAPI
ACS_Release
(
IAudioSessionControl2
*
iface
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedDecrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
if
(
!
ref
)
AudioSessionControl_Destroy
(
This
);
return
ref
;
}
static
HRESULT
WINAPI
ACS_GetState
(
IAudioSessionControl2
*
iface
,
AudioSessionState
*
state
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
state
);
if
(
!
state
)
return
E_POINTER
;
*
state
=
This
->
parent
->
parent
->
state
;
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_GetDisplayName
(
IAudioSessionControl2
*
iface
,
WCHAR
**
name
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
name
);
FIXME
(
"stub
\n
"
);
if
(
name
)
*
name
=
NULL
;
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_SetDisplayName
(
IAudioSessionControl2
*
iface
,
const
WCHAR
*
name
,
const
GUID
*
session
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p,%s)
\n
"
,
This
,
name
,
debugstr_guid
(
session
));
FIXME
(
"stub
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_GetIconPath
(
IAudioSessionControl2
*
iface
,
WCHAR
**
path
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
path
);
FIXME
(
"stub
\n
"
);
if
(
path
)
*
path
=
NULL
;
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_SetIconPath
(
IAudioSessionControl2
*
iface
,
const
WCHAR
*
path
,
const
GUID
*
session
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p,%s)
\n
"
,
This
,
path
,
debugstr_guid
(
session
));
FIXME
(
"stub
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_GetGroupingParam
(
IAudioSessionControl2
*
iface
,
GUID
*
group
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
group
);
FIXME
(
"stub
\n
"
);
if
(
group
)
*
group
=
GUID_NULL
;
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_SetGroupingParam
(
IAudioSessionControl2
*
iface
,
GUID
*
group
,
const
GUID
*
session
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%s,%s)
\n
"
,
This
,
debugstr_guid
(
group
),
debugstr_guid
(
session
));
FIXME
(
"stub
\n
"
);
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_RegisterAudioSessionNotification
(
IAudioSessionControl2
*
iface
,
IAudioSessionEvents
*
events
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
events
);
FIXME
(
"stub
\n
"
);
return
S_OK
;
}
static
HRESULT
WINAPI
ACS_UnregisterAudioSessionNotification
(
IAudioSessionControl2
*
iface
,
IAudioSessionEvents
*
events
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
events
);
FIXME
(
"stub
\n
"
);
return
S_OK
;
}
static
HRESULT
WINAPI
ACS_GetSessionIdentifier
(
IAudioSessionControl2
*
iface
,
WCHAR
**
id
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
id
);
FIXME
(
"stub
\n
"
);
if
(
id
)
*
id
=
NULL
;
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_GetSessionInstanceIdentifier
(
IAudioSessionControl2
*
iface
,
WCHAR
**
id
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
id
);
FIXME
(
"stub
\n
"
);
if
(
id
)
*
id
=
NULL
;
return
E_NOTIMPL
;
}
static
HRESULT
WINAPI
ACS_GetProcessId
(
IAudioSessionControl2
*
iface
,
DWORD
*
pid
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
pid
);
if
(
!
pid
)
return
E_POINTER
;
*
pid
=
GetCurrentProcessId
();
return
S_OK
;
}
static
HRESULT
WINAPI
ACS_IsSystemSoundsSession
(
IAudioSessionControl2
*
iface
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)
\n
"
,
This
);
return
S_FALSE
;
}
static
HRESULT
WINAPI
ACS_SetDuckingPreference
(
IAudioSessionControl2
*
iface
,
BOOL
optout
)
{
ACSession
*
This
=
(
ACSession
*
)
iface
;
TRACE
(
"(%p)
\n
"
,
This
);
return
S_OK
;
}
static
const
IAudioSessionControl2Vtbl
ACSession_Vtbl
=
{
ACS_QueryInterface
,
ACS_AddRef
,
ACS_Release
,
ACS_GetState
,
ACS_GetDisplayName
,
ACS_SetDisplayName
,
ACS_GetIconPath
,
ACS_SetIconPath
,
ACS_GetGroupingParam
,
ACS_SetGroupingParam
,
ACS_RegisterAudioSessionNotification
,
ACS_UnregisterAudioSessionNotification
,
ACS_GetSessionIdentifier
,
ACS_GetSessionInstanceIdentifier
,
ACS_GetProcessId
,
ACS_IsSystemSoundsSession
,
ACS_SetDuckingPreference
};
static
HRESULT
AudioSimpleVolume_Create
(
ACImpl
*
parent
,
ASVolume
**
ppv
)
{
ASVolume
*
This
;
This
=
*
ppv
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
This
));
if
(
!
This
)
return
E_OUTOFMEMORY
;
This
->
lpVtbl
=
&
ASVolume_Vtbl
;
This
->
ref
=
0
;
This
->
parent
=
parent
;
AC_AddRef
((
IAudioClient
*
)
This
->
parent
);
return
S_OK
;
}
static
void
AudioSimpleVolume_Destroy
(
ASVolume
*
This
)
{
This
->
parent
->
svolume
=
NULL
;
AC_Release
((
IAudioClient
*
)
This
->
parent
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
}
static
HRESULT
WINAPI
ASV_QueryInterface
(
ISimpleAudioVolume
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
TRACE
(
"(%p)->(%s,%p)
\n
"
,
iface
,
debugstr_guid
(
riid
),
ppv
);
if
(
!
ppv
)
return
E_POINTER
;
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
)
||
IsEqualIID
(
riid
,
&
IID_ISimpleAudioVolume
))
*
ppv
=
iface
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)
*
ppv
);
return
S_OK
;
}
WARN
(
"Unknown interface %s
\n
"
,
debugstr_guid
(
riid
));
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
ASV_AddRef
(
ISimpleAudioVolume
*
iface
)
{
ASVolume
*
This
=
(
ASVolume
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedIncrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
return
ref
;
}
static
ULONG
WINAPI
ASV_Release
(
ISimpleAudioVolume
*
iface
)
{
ASVolume
*
This
=
(
ASVolume
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedDecrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
if
(
!
ref
)
AudioSimpleVolume_Destroy
(
This
);
return
ref
;
}
static
HRESULT
WINAPI
ASV_SetMasterVolume
(
ISimpleAudioVolume
*
iface
,
float
level
,
const
GUID
*
context
)
{
ASVolume
*
This
=
(
ASVolume
*
)
iface
;
TRACE
(
"(%p)->(%f,%p)
\n
"
,
This
,
level
,
context
);
FIXME
(
"stub
\n
"
);
return
S_OK
;
}
static
HRESULT
WINAPI
ASV_GetMasterVolume
(
ISimpleAudioVolume
*
iface
,
float
*
level
)
{
ASVolume
*
This
=
(
ASVolume
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
level
);
*
level
=
1
.
f
;
FIXME
(
"stub
\n
"
);
return
S_OK
;
}
static
HRESULT
WINAPI
ASV_SetMute
(
ISimpleAudioVolume
*
iface
,
BOOL
mute
,
const
GUID
*
context
)
{
ASVolume
*
This
=
(
ASVolume
*
)
iface
;
TRACE
(
"(%p)->(%u,%p)
\n
"
,
This
,
mute
,
context
);
FIXME
(
"stub
\n
"
);
return
S_OK
;
}
static
HRESULT
WINAPI
ASV_GetMute
(
ISimpleAudioVolume
*
iface
,
BOOL
*
mute
)
{
ASVolume
*
This
=
(
ASVolume
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
mute
);
*
mute
=
0
;
FIXME
(
"stub
\n
"
);
return
S_OK
;
}
static
const
ISimpleAudioVolumeVtbl
ASVolume_Vtbl
=
{
ASV_QueryInterface
,
ASV_AddRef
,
ASV_Release
,
ASV_SetMasterVolume
,
ASV_GetMasterVolume
,
ASV_SetMute
,
ASV_GetMute
};
static
HRESULT
AudioClock_Create
(
ACImpl
*
parent
,
AClock
**
ppv
)
{
AClock
*
This
;
This
=
*
ppv
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
This
));
if
(
!
This
)
return
E_OUTOFMEMORY
;
This
->
lpVtbl
=
&
AClock_Vtbl
;
This
->
lp2Vtbl
=
&
AClock2_Vtbl
;
This
->
ref
=
0
;
This
->
parent
=
parent
;
AC_AddRef
((
IAudioClient
*
)
This
->
parent
);
return
S_OK
;
}
static
void
AudioClock_Destroy
(
AClock
*
This
)
{
This
->
parent
->
clock
=
NULL
;
AC_Release
((
IAudioClient
*
)
This
->
parent
);
HeapFree
(
GetProcessHeap
(),
0
,
This
);
}
static
HRESULT
WINAPI
AClock_QueryInterface
(
IAudioClock
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
AClock
*
This
=
(
AClock
*
)
iface
;
TRACE
(
"(%p)->(%s,%p)
\n
"
,
iface
,
debugstr_guid
(
riid
),
ppv
);
if
(
!
ppv
)
return
E_POINTER
;
*
ppv
=
NULL
;
if
(
IsEqualIID
(
riid
,
&
IID_IUnknown
)
||
IsEqualIID
(
riid
,
&
IID_IAudioClock
))
*
ppv
=
iface
;
else
if
(
IsEqualIID
(
riid
,
&
IID_IAudioClock2
))
*
ppv
=
&
This
->
lp2Vtbl
;
if
(
*
ppv
)
{
IUnknown_AddRef
((
IUnknown
*
)
*
ppv
);
return
S_OK
;
}
WARN
(
"Unknown interface %s
\n
"
,
debugstr_guid
(
riid
));
return
E_NOINTERFACE
;
}
static
ULONG
WINAPI
AClock_AddRef
(
IAudioClock
*
iface
)
{
AClock
*
This
=
(
AClock
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedIncrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
return
ref
;
}
static
ULONG
WINAPI
AClock_Release
(
IAudioClock
*
iface
)
{
AClock
*
This
=
(
AClock
*
)
iface
;
ULONG
ref
;
ref
=
InterlockedDecrement
(
&
This
->
ref
);
TRACE
(
"Refcount now %i
\n
"
,
ref
);
if
(
!
ref
)
AudioClock_Destroy
(
This
);
return
ref
;
}
static
HRESULT
WINAPI
AClock_GetFrequency
(
IAudioClock
*
iface
,
UINT64
*
freq
)
{
AClock
*
This
=
(
AClock
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
freq
);
*
freq
=
(
UINT64
)
This
->
parent
->
pwfx
->
nSamplesPerSec
;
return
S_OK
;
}
static
HRESULT
WINAPI
AClock_GetPosition
(
IAudioClock
*
iface
,
UINT64
*
pos
,
UINT64
*
qpctime
)
{
AClock
*
This
=
(
AClock
*
)
iface
;
DWORD
pad
;
TRACE
(
"(%p)->(%p,%p)
\n
"
,
This
,
pos
,
qpctime
);
if
(
!
pos
)
return
E_POINTER
;
EnterCriticalSection
(
This
->
parent
->
crst
);
AC_GetCurrentPadding
((
IAudioClient
*
)
This
->
parent
,
&
pad
);
*
pos
=
This
->
parent
->
frameswritten
-
pad
;
if
(
qpctime
)
*
qpctime
=
gettime
();
LeaveCriticalSection
(
This
->
parent
->
crst
);
return
S_OK
;
}
static
HRESULT
WINAPI
AClock_GetCharacteristics
(
IAudioClock
*
iface
,
DWORD
*
chars
)
{
AClock
*
This
=
(
AClock
*
)
iface
;
TRACE
(
"(%p)->(%p)
\n
"
,
This
,
chars
);
if
(
!
chars
)
return
E_POINTER
;
*
chars
=
AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
return
S_OK
;
}
static
const
IAudioClockVtbl
AClock_Vtbl
=
{
AClock_QueryInterface
,
AClock_AddRef
,
AClock_Release
,
AClock_GetFrequency
,
AClock_GetPosition
,
AClock_GetCharacteristics
};
static
AClock
*
get_clock_from_clock2
(
IAudioClock2
*
iface
)
{
return
(
AClock
*
)((
char
*
)
iface
-
offsetof
(
AClock
,
lp2Vtbl
));
}
static
HRESULT
WINAPI
AClock2_QueryInterface
(
IAudioClock2
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
AClock
*
This
=
get_clock_from_clock2
(
iface
);
return
IUnknown_QueryInterface
((
IUnknown
*
)
This
,
riid
,
ppv
);
}
static
ULONG
WINAPI
AClock2_AddRef
(
IAudioClock2
*
iface
)
{
AClock
*
This
=
get_clock_from_clock2
(
iface
);
return
IUnknown_AddRef
((
IUnknown
*
)
This
);
}
static
ULONG
WINAPI
AClock2_Release
(
IAudioClock2
*
iface
)
{
AClock
*
This
=
get_clock_from_clock2
(
iface
);
return
IUnknown_Release
((
IUnknown
*
)
This
);
}
static
HRESULT
WINAPI
AClock2_GetPosition
(
IAudioClock2
*
iface
,
UINT64
*
pos
,
UINT64
*
qpctime
)
{
AClock
*
This
=
get_clock_from_clock2
(
iface
);
return
AClock_GetPosition
((
IAudioClock
*
)
This
,
pos
,
qpctime
);
}
static
const
IAudioClock2Vtbl
AClock2_Vtbl
=
{
AClock2_QueryInterface
,
AClock2_AddRef
,
AClock2_Release
,
AClock2_GetPosition
};
#endif
dlls/mmdevapi/audiovolume.c
View file @
50140999
...
...
@@ -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
dlls/mmdevapi/devenum.c
View file @
50140999
...
...
@@ -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
);
}
...
...
dlls/mmdevapi/main.c
View file @
50140999
/*
* 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_context
s
;
DriverFuncs
drv
s
;
static
CRITICAL_SECTION_DEBUG
openal_crst_debug
=
{
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
};
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
typeof
(
alcGetCurrentContext
)
*
get_context
;
typeof
(
alcMakeContextCurrent
)
*
set_context
;
static
void
load_libopenal
(
void
)
static
BOOL
load_driver
(
const
WCHAR
*
name
)
{
DWORD
failed
=
0
;
WCHAR
driver_module
[
264
];
static
const
WCHAR
wineW
[]
=
{
'w'
,
'i'
,
'n'
,
'e'
,
0
};
static
const
WCHAR
dotdrvW
[]
=
{
'.'
,
'd'
,
'r'
,
'v'
,
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
;
}
lstrcpyW
(
driver_module
,
wineW
);
lstrcatW
(
driver_module
,
name
);
lstrcatW
(
driver_module
,
dotdrvW
);
#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; \
}
TRACE
(
"Attempting to load %s
\n
"
,
wine_dbgstr_w
(
driver_module
));
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
if
(
failed
)
{
WARN
(
"Unloading openal
\n
"
);
if
(
openal_handle
!=
RTLD_DEFAULT
)
wine_dlclose
(
openal_handle
,
NULL
,
0
);
openal_handle
=
NULL
;
openal_loaded
=
0
;
drvs
.
module
=
LoadLibraryW
(
driver_module
);
if
(
!
drvs
.
module
){
TRACE
(
"Unable to load %s: %u
\n
"
,
wine_dbgstr_w
(
driver_module
),
GetLastError
());
return
FALSE
;
}
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
;
#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
TRACE
(
"Successfully loaded %s
\n
"
,
wine_dbgstr_w
(
driver_module
));
return
TRUE
;
}
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
;
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
);
}
}
#endif
/*HAVE_OPENAL*/
for
(
i
=
0
;
i
<
sizeof
(
default_drivers
)
/
sizeof
(
*
default_drivers
);
++
i
)
if
(
load_driver
(
default_drivers
[
i
]))
return
TRUE
;
static
HINSTANCE
instance
;
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
;
...
...
dlls/mmdevapi/mmdevapi.h
View file @
50140999
...
...
@@ -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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment