2 * Copyright 2011 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
29 #include <sys/types.h>
31 #include <sys/ioctl.h>
35 #include <sys/soundcard.h>
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
46 #include "mmdeviceapi.h"
50 #include "endpointvolume.h"
53 #include "audiopolicy.h"
54 #include "audioclient.h"
57 /* Some implementations of OSS, such as FreeBSD older than 9.0, lack
58 SNDCTL_DSP_HALT which is just a synonym for the older SNDCTL_DSP_RESET. */
59 #ifndef SNDCTL_DSP_HALT
60 #define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
63 WINE_DEFAULT_DEBUG_CHANNEL(oss
);
65 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
67 static const REFERENCE_TIME DefaultPeriod
= 200000;
68 static const REFERENCE_TIME MinimumPeriod
= 100000;
71 typedef struct ACImpl ACImpl
;
73 typedef struct _AudioSession
{
84 CRITICAL_SECTION lock
;
89 typedef struct _AudioSessionWrapper
{
90 IAudioSessionControl2 IAudioSessionControl2_iface
;
91 IChannelAudioVolume IChannelAudioVolume_iface
;
92 ISimpleAudioVolume ISimpleAudioVolume_iface
;
97 AudioSession
*session
;
98 } AudioSessionWrapper
;
101 IAudioClient IAudioClient_iface
;
102 IAudioRenderClient IAudioRenderClient_iface
;
103 IAudioCaptureClient IAudioCaptureClient_iface
;
104 IAudioClock IAudioClock_iface
;
105 IAudioClock2 IAudioClock2_iface
;
106 IAudioStreamVolume IAudioStreamVolume_iface
;
116 AUDCLNT_SHAREMODE share
;
123 BOOL initted
, playing
;
124 UINT64 written_frames
;
125 UINT32 period_us
, bufsize_frames
, held_frames
, tmp_buffer_frames
, inbuf_frames
;
126 UINT32 lcl_offs_frames
; /* offs into local_buffer where valid data starts */
128 BYTE
*local_buffer
, *tmp_buffer
;
132 CRITICAL_SECTION lock
;
134 AudioSession
*session
;
135 AudioSessionWrapper
*session_wrapper
;
142 LOCKED_NORMAL
, /* public buffer piece is from local_buffer */
143 LOCKED_WRAPPED
/* public buffer piece is in tmp_buffer */
146 typedef struct _SessionMgr
{
147 IAudioSessionManager2 IAudioSessionManager2_iface
;
154 static HANDLE g_timer_q
;
156 static CRITICAL_SECTION g_sessions_lock
;
157 static struct list g_sessions
= LIST_INIT(g_sessions
);
159 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
);
160 static HRESULT
oss_setvol(ACImpl
*This
, UINT32 index
);
162 static const IAudioClientVtbl AudioClient_Vtbl
;
163 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
;
164 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
;
165 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
;
166 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
;
167 static const IAudioClockVtbl AudioClock_Vtbl
;
168 static const IAudioClock2Vtbl AudioClock2_Vtbl
;
169 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
;
170 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
;
171 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
;
173 static inline ACImpl
*impl_from_IAudioClient(IAudioClient
*iface
)
175 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClient_iface
);
178 static inline ACImpl
*impl_from_IAudioRenderClient(IAudioRenderClient
*iface
)
180 return CONTAINING_RECORD(iface
, ACImpl
, IAudioRenderClient_iface
);
183 static inline ACImpl
*impl_from_IAudioCaptureClient(IAudioCaptureClient
*iface
)
185 return CONTAINING_RECORD(iface
, ACImpl
, IAudioCaptureClient_iface
);
188 static inline AudioSessionWrapper
*impl_from_IAudioSessionControl2(IAudioSessionControl2
*iface
)
190 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IAudioSessionControl2_iface
);
193 static inline AudioSessionWrapper
*impl_from_ISimpleAudioVolume(ISimpleAudioVolume
*iface
)
195 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, ISimpleAudioVolume_iface
);
198 static inline AudioSessionWrapper
*impl_from_IChannelAudioVolume(IChannelAudioVolume
*iface
)
200 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IChannelAudioVolume_iface
);
203 static inline ACImpl
*impl_from_IAudioClock(IAudioClock
*iface
)
205 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock_iface
);
208 static inline ACImpl
*impl_from_IAudioClock2(IAudioClock2
*iface
)
210 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock2_iface
);
213 static inline ACImpl
*impl_from_IAudioStreamVolume(IAudioStreamVolume
*iface
)
215 return CONTAINING_RECORD(iface
, ACImpl
, IAudioStreamVolume_iface
);
218 static inline SessionMgr
*impl_from_IAudioSessionManager2(IAudioSessionManager2
*iface
)
220 return CONTAINING_RECORD(iface
, SessionMgr
, IAudioSessionManager2_iface
);
223 BOOL WINAPI
DllMain(HINSTANCE dll
, DWORD reason
, void *reserved
)
225 if(reason
== DLL_PROCESS_ATTACH
){
226 g_timer_q
= CreateTimerQueue();
230 InitializeCriticalSection(&g_sessions_lock
);
236 /* From <dlls/mmdevapi/mmdevapi.h> */
237 enum DriverPriority
{
238 Priority_Unavailable
= 0,
244 int WINAPI
AUDDRV_GetPriority(void)
249 /* Attempt to determine if we are running on OSS or ALSA's OSS
250 * compatibility layer. There is no official way to do that, so just check
251 * for validity as best as possible, without rejecting valid OSS
252 * implementations. */
254 mixer_fd
= open("/dev/mixer", O_RDONLY
, 0);
256 TRACE("Priority_Unavailable: open failed\n");
257 return Priority_Unavailable
;
260 sysinfo
.version
[0] = 0xFF;
261 sysinfo
.versionnum
= ~0;
262 if(ioctl(mixer_fd
, SNDCTL_SYSINFO
, &sysinfo
) < 0){
263 TRACE("Priority_Unavailable: ioctl failed\n");
265 return Priority_Unavailable
;
270 if(sysinfo
.version
[0] < '4' || sysinfo
.version
[0] > '9'){
271 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo
.version
[0]);
274 if(sysinfo
.versionnum
& 0x80000000){
275 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo
.versionnum
);
279 TRACE("Priority_Preferred: Seems like valid OSS!\n");
281 return Priority_Preferred
;
284 static UINT
get_default_index(EDataFlow flow
, char **keys
, UINT num
)
290 fd
= open("/dev/dsp", O_WRONLY
);
292 fd
= open("/dev/dsp", O_RDONLY
);
295 WARN("Couldn't open default device!\n");
300 if((err
= ioctl(fd
, SNDCTL_ENGINEINFO
, &ai
)) < 0){
301 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err
, strerror(errno
));
308 TRACE("Default devnode: %s\n", ai
.devnode
);
309 for(i
= 0; i
< num
; ++i
)
310 if(!strcmp(ai
.devnode
, keys
[i
]))
313 WARN("Couldn't find default device! Choosing first.\n");
317 HRESULT WINAPI
AUDDRV_GetEndpointIDs(EDataFlow flow
, WCHAR
***ids
, char ***keys
,
318 UINT
*num
, UINT
*def_index
)
322 static int print_once
= 0;
324 TRACE("%d %p %p %p\n", flow
, ids
, num
, def_index
);
326 mixer_fd
= open("/dev/mixer", O_RDONLY
, 0);
328 ERR("OSS /dev/mixer doesn't seem to exist\n");
329 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
332 if(ioctl(mixer_fd
, SNDCTL_SYSINFO
, &sysinfo
) < 0){
336 ERR("OSS version too old, need at least OSSv4\n");
337 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
340 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno
, strerror(errno
));
345 TRACE("OSS sysinfo:\n");
346 TRACE("product: %s\n", sysinfo
.product
);
347 TRACE("version: %s\n", sysinfo
.version
);
348 TRACE("versionnum: %x\n", sysinfo
.versionnum
);
349 TRACE("numaudios: %d\n", sysinfo
.numaudios
);
350 TRACE("nummixers: %d\n", sysinfo
.nummixers
);
351 TRACE("numcards: %d\n", sysinfo
.numcards
);
352 TRACE("numaudioengines: %d\n", sysinfo
.numaudioengines
);
356 if(sysinfo
.numaudios
<= 0){
357 WARN("No audio devices!\n");
359 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
362 *ids
= HeapAlloc(GetProcessHeap(), 0, sysinfo
.numaudios
* sizeof(WCHAR
*));
363 *keys
= HeapAlloc(GetProcessHeap(), 0, sysinfo
.numaudios
* sizeof(char *));
366 for(i
= 0; i
< sysinfo
.numaudios
; ++i
){
367 oss_audioinfo ai
= {0};
371 if(ioctl(mixer_fd
, SNDCTL_AUDIOINFO
, &ai
) < 0){
372 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i
, errno
,
378 fd
= open(ai
.devnode
, O_WRONLY
, 0);
380 fd
= open(ai
.devnode
, O_RDONLY
, 0);
382 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
383 ai
.devnode
, errno
, strerror(errno
));
388 if((flow
== eCapture
&& (ai
.caps
& PCM_CAP_INPUT
)) ||
389 (flow
== eRender
&& (ai
.caps
& PCM_CAP_OUTPUT
))){
392 (*keys
)[*num
] = HeapAlloc(GetProcessHeap(), 0,
393 strlen(ai
.devnode
) + 1);
395 for(i
= 0; i
< *num
; ++i
){
396 HeapFree(GetProcessHeap(), 0, (*ids
)[i
]);
397 HeapFree(GetProcessHeap(), 0, (*keys
)[i
]);
399 HeapFree(GetProcessHeap(), 0, *ids
);
400 HeapFree(GetProcessHeap(), 0, *keys
);
402 return E_OUTOFMEMORY
;
404 strcpy((*keys
)[*num
], ai
.devnode
);
406 len
= MultiByteToWideChar(CP_UNIXCP
, 0, ai
.name
, -1, NULL
, 0);
407 (*ids
)[*num
] = HeapAlloc(GetProcessHeap(), 0,
408 len
* sizeof(WCHAR
));
410 HeapFree(GetProcessHeap(), 0, (*keys
)[*num
]);
411 for(i
= 0; i
< *num
; ++i
){
412 HeapFree(GetProcessHeap(), 0, (*ids
)[i
]);
413 HeapFree(GetProcessHeap(), 0, (*keys
)[i
]);
415 HeapFree(GetProcessHeap(), 0, *ids
);
416 HeapFree(GetProcessHeap(), 0, *keys
);
418 return E_OUTOFMEMORY
;
420 MultiByteToWideChar(CP_UNIXCP
, 0, ai
.name
, -1,
429 *def_index
= get_default_index(flow
, *keys
, *num
);
434 HRESULT WINAPI
AUDDRV_GetAudioEndpoint(char *devnode
, IMMDevice
*dev
,
435 EDataFlow dataflow
, IAudioClient
**out
)
439 TRACE("%s %p %d %p\n", devnode
, dev
, dataflow
, out
);
441 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ACImpl
));
443 return E_OUTOFMEMORY
;
445 if(dataflow
== eRender
)
446 This
->fd
= open(devnode
, O_WRONLY
, 0);
447 else if(dataflow
== eCapture
)
448 This
->fd
= open(devnode
, O_RDONLY
, 0);
450 HeapFree(GetProcessHeap(), 0, This
);
454 ERR("Unable to open device %s: %d (%s)\n", devnode
, errno
,
456 HeapFree(GetProcessHeap(), 0, This
);
457 return AUDCLNT_E_DEVICE_INVALIDATED
;
460 This
->dataflow
= dataflow
;
463 if(ioctl(This
->fd
, SNDCTL_ENGINEINFO
, &This
->ai
) < 0){
464 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode
,
465 errno
, strerror(errno
));
467 HeapFree(GetProcessHeap(), 0, This
);
471 TRACE("OSS audioinfo:\n");
472 TRACE("devnode: %s\n", This
->ai
.devnode
);
473 TRACE("name: %s\n", This
->ai
.name
);
474 TRACE("busy: %x\n", This
->ai
.busy
);
475 TRACE("caps: %x\n", This
->ai
.caps
);
476 TRACE("iformats: %x\n", This
->ai
.iformats
);
477 TRACE("oformats: %x\n", This
->ai
.oformats
);
478 TRACE("enabled: %d\n", This
->ai
.enabled
);
479 TRACE("min_rate: %d\n", This
->ai
.min_rate
);
480 TRACE("max_rate: %d\n", This
->ai
.max_rate
);
481 TRACE("min_channels: %d\n", This
->ai
.min_channels
);
482 TRACE("max_channels: %d\n", This
->ai
.max_channels
);
484 This
->IAudioClient_iface
.lpVtbl
= &AudioClient_Vtbl
;
485 This
->IAudioRenderClient_iface
.lpVtbl
= &AudioRenderClient_Vtbl
;
486 This
->IAudioCaptureClient_iface
.lpVtbl
= &AudioCaptureClient_Vtbl
;
487 This
->IAudioClock_iface
.lpVtbl
= &AudioClock_Vtbl
;
488 This
->IAudioClock2_iface
.lpVtbl
= &AudioClock2_Vtbl
;
489 This
->IAudioStreamVolume_iface
.lpVtbl
= &AudioStreamVolume_Vtbl
;
491 InitializeCriticalSection(&This
->lock
);
494 IMMDevice_AddRef(This
->parent
);
496 IAudioClient_AddRef(&This
->IAudioClient_iface
);
498 *out
= &This
->IAudioClient_iface
;
503 static HRESULT WINAPI
AudioClient_QueryInterface(IAudioClient
*iface
,
504 REFIID riid
, void **ppv
)
506 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
511 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClient
))
514 IUnknown_AddRef((IUnknown
*)*ppv
);
517 WARN("Unknown interface %s\n", debugstr_guid(riid
));
518 return E_NOINTERFACE
;
521 static ULONG WINAPI
AudioClient_AddRef(IAudioClient
*iface
)
523 ACImpl
*This
= impl_from_IAudioClient(iface
);
525 ref
= InterlockedIncrement(&This
->ref
);
526 TRACE("(%p) Refcount now %u\n", This
, ref
);
530 static ULONG WINAPI
AudioClient_Release(IAudioClient
*iface
)
532 ACImpl
*This
= impl_from_IAudioClient(iface
);
534 ref
= InterlockedDecrement(&This
->ref
);
535 TRACE("(%p) Refcount now %u\n", This
, ref
);
537 IAudioClient_Stop(iface
);
538 IMMDevice_Release(This
->parent
);
539 DeleteCriticalSection(&This
->lock
);
542 EnterCriticalSection(&g_sessions_lock
);
543 list_remove(&This
->entry
);
544 LeaveCriticalSection(&g_sessions_lock
);
546 HeapFree(GetProcessHeap(), 0, This
->vols
);
547 HeapFree(GetProcessHeap(), 0, This
->local_buffer
);
548 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
549 CoTaskMemFree(This
->fmt
);
550 HeapFree(GetProcessHeap(), 0, This
);
555 static void dump_fmt(const WAVEFORMATEX
*fmt
)
557 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
558 switch(fmt
->wFormatTag
){
559 case WAVE_FORMAT_PCM
:
560 TRACE("WAVE_FORMAT_PCM");
562 case WAVE_FORMAT_IEEE_FLOAT
:
563 TRACE("WAVE_FORMAT_IEEE_FLOAT");
565 case WAVE_FORMAT_EXTENSIBLE
:
566 TRACE("WAVE_FORMAT_EXTENSIBLE");
574 TRACE("nChannels: %u\n", fmt
->nChannels
);
575 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
576 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
577 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
578 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
579 TRACE("cbSize: %u\n", fmt
->cbSize
);
581 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
582 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
583 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
584 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
585 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
589 static DWORD
get_channel_mask(unsigned int channels
)
595 return KSAUDIO_SPEAKER_MONO
;
597 return KSAUDIO_SPEAKER_STEREO
;
599 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
601 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
603 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
605 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
607 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
609 return KSAUDIO_SPEAKER_7POINT1
; /* not 7POINT1_SURROUND */
611 FIXME("Unknown speaker configuration: %u\n", channels
);
615 static int get_oss_format(const WAVEFORMATEX
*fmt
)
617 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)fmt
;
619 if(fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
620 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
621 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
622 switch(fmt
->wBitsPerSample
){
636 if(fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
637 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
638 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
639 if(fmt
->wBitsPerSample
!= 32)
649 static WAVEFORMATEX
*clone_format(const WAVEFORMATEX
*fmt
)
654 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
655 size
= sizeof(WAVEFORMATEXTENSIBLE
);
657 size
= sizeof(WAVEFORMATEX
);
659 ret
= CoTaskMemAlloc(size
);
663 memcpy(ret
, fmt
, size
);
665 ret
->cbSize
= size
- sizeof(WAVEFORMATEX
);
670 static HRESULT
setup_oss_device(ACImpl
*This
, const WAVEFORMATEX
*fmt
,
676 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
677 WAVEFORMATEX
*closest
= NULL
;
682 tmp
= oss_format
= get_oss_format(fmt
);
684 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
685 if(ioctl(This
->fd
, SNDCTL_DSP_SETFMT
, &tmp
) < 0){
686 WARN("SETFMT failed: %d (%s)\n", errno
, strerror(errno
));
689 if(tmp
!= oss_format
){
690 TRACE("Format unsupported by this OSS version: %x\n", oss_format
);
691 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
694 closest
= clone_format(fmt
);
696 return E_OUTOFMEMORY
;
698 tmp
= fmt
->nSamplesPerSec
;
699 if(ioctl(This
->fd
, SNDCTL_DSP_SPEED
, &tmp
) < 0){
700 WARN("SPEED failed: %d (%s)\n", errno
, strerror(errno
));
701 CoTaskMemFree(closest
);
704 tenth
= fmt
->nSamplesPerSec
* 0.1;
705 if(tmp
> fmt
->nSamplesPerSec
+ tenth
|| tmp
< fmt
->nSamplesPerSec
- tenth
){
707 closest
->nSamplesPerSec
= tmp
;
710 tmp
= fmt
->nChannels
;
711 if(ioctl(This
->fd
, SNDCTL_DSP_CHANNELS
, &tmp
) < 0){
712 WARN("CHANNELS failed: %d (%s)\n", errno
, strerror(errno
));
713 CoTaskMemFree(closest
);
716 if(tmp
!= fmt
->nChannels
){
718 closest
->nChannels
= tmp
;
721 if(closest
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
722 DWORD mask
= get_channel_mask(closest
->nChannels
);
724 ((WAVEFORMATEXTENSIBLE
*)closest
)->dwChannelMask
= mask
;
726 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
727 fmtex
->dwChannelMask
!= mask
)
731 if(ret
== S_FALSE
&& out
){
732 closest
->nBlockAlign
=
733 closest
->nChannels
* closest
->wBitsPerSample
/ 8;
734 closest
->nAvgBytesPerSec
=
735 closest
->nBlockAlign
* closest
->nSamplesPerSec
;
738 CoTaskMemFree(closest
);
740 TRACE("returning: %08x\n", ret
);
744 static void session_init_vols(AudioSession
*session
, UINT channels
)
746 if(session
->channel_count
< channels
){
749 if(session
->channel_vols
)
750 session
->channel_vols
= HeapReAlloc(GetProcessHeap(), 0,
751 session
->channel_vols
, sizeof(float) * channels
);
753 session
->channel_vols
= HeapAlloc(GetProcessHeap(), 0,
754 sizeof(float) * channels
);
755 if(!session
->channel_vols
)
758 for(i
= session
->channel_count
; i
< channels
; ++i
)
759 session
->channel_vols
[i
] = 1.f
;
761 session
->channel_count
= channels
;
765 static AudioSession
*create_session(const GUID
*guid
, IMMDevice
*device
,
770 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AudioSession
));
774 memcpy(&ret
->guid
, guid
, sizeof(GUID
));
776 ret
->device
= device
;
778 list_init(&ret
->clients
);
780 list_add_head(&g_sessions
, &ret
->entry
);
782 InitializeCriticalSection(&ret
->lock
);
784 session_init_vols(ret
, num_channels
);
786 ret
->master_vol
= 1.f
;
791 /* if channels == 0, then this will return or create a session with
792 * matching dataflow and GUID. otherwise, channels must also match */
793 static HRESULT
get_audio_session(const GUID
*sessionguid
,
794 IMMDevice
*device
, UINT channels
, AudioSession
**out
)
796 AudioSession
*session
;
798 if(!sessionguid
|| IsEqualGUID(sessionguid
, &GUID_NULL
)){
799 *out
= create_session(&GUID_NULL
, device
, channels
);
801 return E_OUTOFMEMORY
;
807 LIST_FOR_EACH_ENTRY(session
, &g_sessions
, AudioSession
, entry
){
808 if(session
->device
== device
&&
809 IsEqualGUID(sessionguid
, &session
->guid
)){
810 session_init_vols(session
, channels
);
817 *out
= create_session(sessionguid
, device
, channels
);
819 return E_OUTOFMEMORY
;
825 static HRESULT WINAPI
AudioClient_Initialize(IAudioClient
*iface
,
826 AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
,
827 REFERENCE_TIME period
, const WAVEFORMATEX
*fmt
,
828 const GUID
*sessionguid
)
830 ACImpl
*This
= impl_from_IAudioClient(iface
);
834 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This
, mode
, flags
,
835 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(period
), fmt
, debugstr_guid(sessionguid
));
842 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
843 return AUDCLNT_E_NOT_INITIALIZED
;
845 if(flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
|
846 AUDCLNT_STREAMFLAGS_LOOPBACK
|
847 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
848 AUDCLNT_STREAMFLAGS_NOPERSIST
|
849 AUDCLNT_STREAMFLAGS_RATEADJUST
|
850 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
|
851 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
|
852 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
)){
853 TRACE("Unknown flags: %08x\n", flags
);
857 EnterCriticalSection(&This
->lock
);
860 LeaveCriticalSection(&This
->lock
);
861 return AUDCLNT_E_ALREADY_INITIALIZED
;
864 hr
= setup_oss_device(This
, fmt
, NULL
);
866 LeaveCriticalSection(&This
->lock
);
867 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
870 LeaveCriticalSection(&This
->lock
);
875 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
876 LeaveCriticalSection(&This
->lock
);
877 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
881 mask
= (100 << 8) | 100;
882 if(ioctl(This
->fd
, SNDCTL_DSP_SETPLAYVOL
, &mask
) < 0)
883 WARN("SETPLAYVOL failed: %d (%s)\n", errno
, strerror(errno
));
885 This
->fmt
= clone_format(fmt
);
887 LeaveCriticalSection(&This
->lock
);
888 return E_OUTOFMEMORY
;
892 This
->period_us
= period
/ 10;
894 This
->period_us
= DefaultPeriod
/ 10;
897 duration
= 300000; /* 0.03s */
898 This
->bufsize_frames
= ceil(fmt
->nSamplesPerSec
* (duration
/ 10000000.));
899 This
->local_buffer
= HeapAlloc(GetProcessHeap(), 0,
900 This
->bufsize_frames
* fmt
->nBlockAlign
);
901 if(!This
->local_buffer
){
902 CoTaskMemFree(This
->fmt
);
904 LeaveCriticalSection(&This
->lock
);
905 return E_OUTOFMEMORY
;
908 This
->vols
= HeapAlloc(GetProcessHeap(), 0, fmt
->nChannels
* sizeof(float));
910 CoTaskMemFree(This
->fmt
);
912 LeaveCriticalSection(&This
->lock
);
913 return E_OUTOFMEMORY
;
916 for(i
= 0; i
< fmt
->nChannels
; ++i
)
922 EnterCriticalSection(&g_sessions_lock
);
924 hr
= get_audio_session(sessionguid
, This
->parent
, fmt
->nChannels
,
927 LeaveCriticalSection(&g_sessions_lock
);
928 HeapFree(GetProcessHeap(), 0, This
->vols
);
930 CoTaskMemFree(This
->fmt
);
932 LeaveCriticalSection(&This
->lock
);
936 list_add_tail(&This
->session
->clients
, &This
->entry
);
938 LeaveCriticalSection(&g_sessions_lock
);
940 This
->initted
= TRUE
;
942 oss_setvol(This
, -1);
944 LeaveCriticalSection(&This
->lock
);
949 static HRESULT WINAPI
AudioClient_GetBufferSize(IAudioClient
*iface
,
952 ACImpl
*This
= impl_from_IAudioClient(iface
);
954 TRACE("(%p)->(%p)\n", This
, frames
);
959 EnterCriticalSection(&This
->lock
);
962 LeaveCriticalSection(&This
->lock
);
963 return AUDCLNT_E_NOT_INITIALIZED
;
966 *frames
= This
->bufsize_frames
;
968 LeaveCriticalSection(&This
->lock
);
973 static HRESULT WINAPI
AudioClient_GetStreamLatency(IAudioClient
*iface
,
974 REFERENCE_TIME
*latency
)
976 ACImpl
*This
= impl_from_IAudioClient(iface
);
978 TRACE("(%p)->(%p)\n", This
, latency
);
983 EnterCriticalSection(&This
->lock
);
986 LeaveCriticalSection(&This
->lock
);
987 return AUDCLNT_E_NOT_INITIALIZED
;
990 if(This
->dataflow
== eRender
){
994 if(ioctl(This
->fd
, SNDCTL_DSP_GETODELAY
, &delay_bytes
) < 0){
995 LeaveCriticalSection(&This
->lock
);
996 WARN("GETODELAY failed: %d (%s)\n", errno
, strerror(errno
));
1000 delay_s
= delay_bytes
/ (double)(This
->fmt
->nSamplesPerSec
*
1001 This
->fmt
->nBlockAlign
);
1003 *latency
= delay_s
* 10000000;
1005 *latency
= 10000; /* OSS doesn't provide input latency */
1007 LeaveCriticalSection(&This
->lock
);
1012 static HRESULT WINAPI
AudioClient_GetCurrentPadding(IAudioClient
*iface
,
1015 ACImpl
*This
= impl_from_IAudioClient(iface
);
1018 TRACE("(%p)->(%p)\n", This
, numpad
);
1023 EnterCriticalSection(&This
->lock
);
1026 LeaveCriticalSection(&This
->lock
);
1027 return AUDCLNT_E_NOT_INITIALIZED
;
1030 if(This
->dataflow
== eRender
){
1031 if(ioctl(This
->fd
, SNDCTL_DSP_GETOSPACE
, &bi
) < 0){
1032 LeaveCriticalSection(&This
->lock
);
1033 WARN("GETOSPACE failed: %d (%s)\n", errno
, strerror(errno
));
1037 *numpad
= (bi
.fragstotal
* bi
.fragsize
- bi
.bytes
) /
1038 This
->fmt
->nBlockAlign
;
1040 /* when the OSS buffer has less than one fragment of data, including
1041 * no data, it often reports it as some non-zero portion of a
1042 * fragment. when it has more than one fragment of data, it reports
1043 * it as some multiple of that portion of the fragment size.
1045 * so, we have to do some ugly workarounds to report the timing
1046 * as accurately as possible */
1047 if(*numpad
< bi
.fragsize
/ This
->fmt
->nBlockAlign
){
1048 *numpad
= This
->inbuf_frames
;
1049 This
->inbuf_frames
= 0;
1051 if(*numpad
< This
->inbuf_frames
)
1052 This
->inbuf_frames
= *numpad
;
1054 *numpad
= This
->inbuf_frames
;
1056 }else if(This
->dataflow
== eCapture
){
1057 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
1058 LeaveCriticalSection(&This
->lock
);
1059 WARN("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
1063 if(bi
.bytes
<= bi
.fragsize
)
1066 *numpad
= bi
.bytes
/ This
->fmt
->nBlockAlign
;
1068 LeaveCriticalSection(&This
->lock
);
1069 return E_UNEXPECTED
;
1072 *numpad
+= This
->held_frames
;
1074 LeaveCriticalSection(&This
->lock
);
1079 static HRESULT WINAPI
AudioClient_IsFormatSupported(IAudioClient
*iface
,
1080 AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
,
1081 WAVEFORMATEX
**outpwfx
)
1083 ACImpl
*This
= impl_from_IAudioClient(iface
);
1086 TRACE("(%p)->(%x, %p, %p)\n", This
, mode
, pwfx
, outpwfx
);
1088 if(!pwfx
|| (mode
== AUDCLNT_SHAREMODE_SHARED
&& !outpwfx
))
1091 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
1092 return E_INVALIDARG
;
1094 if(pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1095 pwfx
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
))
1096 return E_INVALIDARG
;
1100 EnterCriticalSection(&This
->lock
);
1102 ret
= setup_oss_device(This
, pwfx
, outpwfx
);
1104 LeaveCriticalSection(&This
->lock
);
1109 static HRESULT WINAPI
AudioClient_GetMixFormat(IAudioClient
*iface
,
1110 WAVEFORMATEX
**pwfx
)
1112 ACImpl
*This
= impl_from_IAudioClient(iface
);
1113 WAVEFORMATEXTENSIBLE
*fmt
;
1116 TRACE("(%p)->(%p)\n", This
, pwfx
);
1122 if(This
->dataflow
== eRender
)
1123 formats
= This
->ai
.oformats
;
1124 else if(This
->dataflow
== eCapture
)
1125 formats
= This
->ai
.iformats
;
1127 return E_UNEXPECTED
;
1129 fmt
= CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE
));
1131 return E_OUTOFMEMORY
;
1133 fmt
->Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
1134 if(formats
& AFMT_S16_LE
){
1135 fmt
->Format
.wBitsPerSample
= 16;
1136 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1138 }else if(formats
& AFMT_FLOAT
){
1139 fmt
->Format
.wBitsPerSample
= 32;
1140 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
1142 }else if(formats
& AFMT_U8
){
1143 fmt
->Format
.wBitsPerSample
= 8;
1144 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1145 }else if(formats
& AFMT_S32_LE
){
1146 fmt
->Format
.wBitsPerSample
= 32;
1147 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1148 }else if(formats
& AFMT_S24_LE
){
1149 fmt
->Format
.wBitsPerSample
= 24;
1150 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1152 ERR("Didn't recognize any available OSS formats: %x\n", formats
);
1157 fmt
->Format
.nChannels
= This
->ai
.max_channels
;
1158 fmt
->Format
.nSamplesPerSec
= This
->ai
.max_rate
;
1159 fmt
->dwChannelMask
= get_channel_mask(fmt
->Format
.nChannels
);
1161 fmt
->Format
.nBlockAlign
= (fmt
->Format
.wBitsPerSample
*
1162 fmt
->Format
.nChannels
) / 8;
1163 fmt
->Format
.nAvgBytesPerSec
= fmt
->Format
.nSamplesPerSec
*
1164 fmt
->Format
.nBlockAlign
;
1166 fmt
->Samples
.wValidBitsPerSample
= fmt
->Format
.wBitsPerSample
;
1167 fmt
->Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
1169 *pwfx
= (WAVEFORMATEX
*)fmt
;
1175 static HRESULT WINAPI
AudioClient_GetDevicePeriod(IAudioClient
*iface
,
1176 REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
1178 ACImpl
*This
= impl_from_IAudioClient(iface
);
1180 TRACE("(%p)->(%p, %p)\n", This
, defperiod
, minperiod
);
1182 if(!defperiod
&& !minperiod
)
1185 EnterCriticalSection(&This
->lock
);
1188 *defperiod
= DefaultPeriod
;
1190 *minperiod
= MinimumPeriod
;
1192 LeaveCriticalSection(&This
->lock
);
1197 static void oss_silence_buffer(ACImpl
*This
, BYTE
*buf
, UINT32 frames
)
1199 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)This
->fmt
;
1200 if((This
->fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
1201 (This
->fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1202 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))) &&
1203 This
->fmt
->wBitsPerSample
== 8)
1204 memset(buf
, 128, frames
* This
->fmt
->nBlockAlign
);
1206 memset(buf
, 0, frames
* This
->fmt
->nBlockAlign
);
1209 static void oss_write_data(ACImpl
*This
)
1212 UINT32 written_frames
;
1215 This
->local_buffer
+ (This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
);
1217 if(This
->lcl_offs_frames
+ This
->held_frames
> This
->bufsize_frames
)
1218 to_write
= This
->bufsize_frames
- This
->lcl_offs_frames
;
1220 to_write
= This
->held_frames
;
1222 if(This
->session
->mute
)
1223 oss_silence_buffer(This
, buf
, to_write
);
1225 written
= write(This
->fd
, buf
, to_write
* This
->fmt
->nBlockAlign
);
1227 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1230 written_frames
= written
/ This
->fmt
->nBlockAlign
;
1232 This
->lcl_offs_frames
+= written_frames
;
1233 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1234 This
->held_frames
-= written_frames
;
1235 This
->inbuf_frames
+= written_frames
;
1237 if(written_frames
< to_write
){
1238 /* OSS buffer probably full */
1242 if(This
->held_frames
){
1243 /* wrapped and have some data back at the start to write */
1245 if(This
->session
->mute
)
1246 oss_silence_buffer(This
, This
->local_buffer
, This
->held_frames
);
1248 written
= write(This
->fd
, This
->local_buffer
,
1249 This
->held_frames
* This
->fmt
->nBlockAlign
);
1251 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1254 written_frames
= written
/ This
->fmt
->nBlockAlign
;
1256 This
->lcl_offs_frames
+= written_frames
;
1257 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1258 This
->held_frames
-= written_frames
;
1259 This
->inbuf_frames
+= written_frames
;
1263 static void oss_read_data(ACImpl
*This
)
1265 UINT64 pos
, readable
;
1269 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
1270 WARN("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
1274 pos
= (This
->held_frames
+ This
->lcl_offs_frames
) % This
->bufsize_frames
;
1275 readable
= (This
->bufsize_frames
- pos
) * This
->fmt
->nBlockAlign
;
1277 if(bi
.bytes
< readable
)
1278 readable
= bi
.bytes
;
1280 nread
= read(This
->fd
, This
->local_buffer
+ pos
* This
->fmt
->nBlockAlign
,
1283 WARN("read failed: %d (%s)\n", errno
, strerror(errno
));
1287 This
->held_frames
+= nread
/ This
->fmt
->nBlockAlign
;
1289 if(This
->held_frames
> This
->bufsize_frames
){
1290 WARN("Overflow of unread data\n");
1291 This
->lcl_offs_frames
+= This
->held_frames
;
1292 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1293 This
->held_frames
= This
->bufsize_frames
;
1297 static void CALLBACK
oss_period_callback(void *user
, BOOLEAN timer
)
1299 ACImpl
*This
= user
;
1301 EnterCriticalSection(&This
->lock
);
1303 if(This
->dataflow
== eRender
&& This
->held_frames
)
1304 oss_write_data(This
);
1305 else if(This
->dataflow
== eCapture
)
1306 oss_read_data(This
);
1309 SetEvent(This
->event
);
1311 LeaveCriticalSection(&This
->lock
);
1314 static HRESULT WINAPI
AudioClient_Start(IAudioClient
*iface
)
1316 ACImpl
*This
= impl_from_IAudioClient(iface
);
1319 TRACE("(%p)\n", This
);
1321 EnterCriticalSection(&This
->lock
);
1324 LeaveCriticalSection(&This
->lock
);
1325 return AUDCLNT_E_NOT_INITIALIZED
;
1328 if((This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !This
->event
){
1329 LeaveCriticalSection(&This
->lock
);
1330 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1334 LeaveCriticalSection(&This
->lock
);
1335 return AUDCLNT_E_NOT_STOPPED
;
1338 if(This
->dataflow
== eRender
)
1339 mask
= PCM_ENABLE_OUTPUT
;
1340 else if(This
->dataflow
== eCapture
)
1341 mask
= PCM_ENABLE_INPUT
;
1343 LeaveCriticalSection(&This
->lock
);
1344 return E_UNEXPECTED
;
1347 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1348 LeaveCriticalSection(&This
->lock
);
1349 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1353 if(!CreateTimerQueueTimer(&This
->timer
, g_timer_q
,
1354 oss_period_callback
, This
, 0, This
->period_us
/ 1000,
1355 WT_EXECUTEINTIMERTHREAD
))
1356 ERR("Unable to create period timer: %u\n", GetLastError());
1358 This
->playing
= TRUE
;
1360 LeaveCriticalSection(&This
->lock
);
1365 static HRESULT WINAPI
AudioClient_Stop(IAudioClient
*iface
)
1367 ACImpl
*This
= impl_from_IAudioClient(iface
);
1370 TRACE("(%p)\n", This
);
1372 EnterCriticalSection(&This
->lock
);
1375 LeaveCriticalSection(&This
->lock
);
1376 return AUDCLNT_E_NOT_INITIALIZED
;
1380 LeaveCriticalSection(&This
->lock
);
1384 if(This
->timer
&& This
->timer
!= INVALID_HANDLE_VALUE
){
1385 DeleteTimerQueueTimer(g_timer_q
, This
->timer
,
1386 INVALID_HANDLE_VALUE
);
1390 if(ioctl(This
->fd
, SNDCTL_DSP_HALT
, NULL
) < 0){
1391 LeaveCriticalSection(&This
->lock
);
1392 WARN("HALT failed: %d (%s)\n", errno
, strerror(errno
));
1397 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1398 LeaveCriticalSection(&This
->lock
);
1399 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1403 This
->playing
= FALSE
;
1405 LeaveCriticalSection(&This
->lock
);
1410 static HRESULT WINAPI
AudioClient_Reset(IAudioClient
*iface
)
1412 ACImpl
*This
= impl_from_IAudioClient(iface
);
1414 TRACE("(%p)\n", This
);
1416 EnterCriticalSection(&This
->lock
);
1419 LeaveCriticalSection(&This
->lock
);
1420 return AUDCLNT_E_NOT_INITIALIZED
;
1424 LeaveCriticalSection(&This
->lock
);
1425 return AUDCLNT_E_NOT_STOPPED
;
1428 if(This
->buf_state
!= NOT_LOCKED
){
1429 LeaveCriticalSection(&This
->lock
);
1430 return AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1433 This
->written_frames
= 0;
1434 This
->inbuf_frames
= 0;
1435 This
->held_frames
= 0;
1437 if(ioctl(This
->fd
, SNDCTL_DSP_SKIP
, NULL
) < 0)
1438 WARN("SKIP failed: %d (%s)\n", errno
, strerror(errno
));
1440 LeaveCriticalSection(&This
->lock
);
1445 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient
*iface
,
1448 ACImpl
*This
= impl_from_IAudioClient(iface
);
1450 TRACE("(%p)->(%p)\n", This
, event
);
1453 return E_INVALIDARG
;
1455 EnterCriticalSection(&This
->lock
);
1458 LeaveCriticalSection(&This
->lock
);
1459 return AUDCLNT_E_NOT_INITIALIZED
;
1462 if(!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
)){
1463 LeaveCriticalSection(&This
->lock
);
1464 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1467 This
->event
= event
;
1469 LeaveCriticalSection(&This
->lock
);
1474 static HRESULT WINAPI
AudioClient_GetService(IAudioClient
*iface
, REFIID riid
,
1477 ACImpl
*This
= impl_from_IAudioClient(iface
);
1479 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1485 EnterCriticalSection(&This
->lock
);
1488 LeaveCriticalSection(&This
->lock
);
1489 return AUDCLNT_E_NOT_INITIALIZED
;
1492 if(IsEqualIID(riid
, &IID_IAudioRenderClient
)){
1493 if(This
->dataflow
!= eRender
){
1494 LeaveCriticalSection(&This
->lock
);
1495 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1497 IAudioRenderClient_AddRef(&This
->IAudioRenderClient_iface
);
1498 *ppv
= &This
->IAudioRenderClient_iface
;
1499 }else if(IsEqualIID(riid
, &IID_IAudioCaptureClient
)){
1500 if(This
->dataflow
!= eCapture
){
1501 LeaveCriticalSection(&This
->lock
);
1502 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1504 IAudioCaptureClient_AddRef(&This
->IAudioCaptureClient_iface
);
1505 *ppv
= &This
->IAudioCaptureClient_iface
;
1506 }else if(IsEqualIID(riid
, &IID_IAudioClock
)){
1507 IAudioClock_AddRef(&This
->IAudioClock_iface
);
1508 *ppv
= &This
->IAudioClock_iface
;
1509 }else if(IsEqualIID(riid
, &IID_IAudioStreamVolume
)){
1510 IAudioStreamVolume_AddRef(&This
->IAudioStreamVolume_iface
);
1511 *ppv
= &This
->IAudioStreamVolume_iface
;
1512 }else if(IsEqualIID(riid
, &IID_IAudioSessionControl
)){
1513 if(!This
->session_wrapper
){
1514 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1515 if(!This
->session_wrapper
){
1516 LeaveCriticalSection(&This
->lock
);
1517 return E_OUTOFMEMORY
;
1520 IAudioSessionControl2_AddRef(&This
->session_wrapper
->IAudioSessionControl2_iface
);
1522 *ppv
= &This
->session_wrapper
->IAudioSessionControl2_iface
;
1523 }else if(IsEqualIID(riid
, &IID_IChannelAudioVolume
)){
1524 if(!This
->session_wrapper
){
1525 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1526 if(!This
->session_wrapper
){
1527 LeaveCriticalSection(&This
->lock
);
1528 return E_OUTOFMEMORY
;
1531 IChannelAudioVolume_AddRef(&This
->session_wrapper
->IChannelAudioVolume_iface
);
1533 *ppv
= &This
->session_wrapper
->IChannelAudioVolume_iface
;
1534 }else if(IsEqualIID(riid
, &IID_ISimpleAudioVolume
)){
1535 if(!This
->session_wrapper
){
1536 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1537 if(!This
->session_wrapper
){
1538 LeaveCriticalSection(&This
->lock
);
1539 return E_OUTOFMEMORY
;
1542 ISimpleAudioVolume_AddRef(&This
->session_wrapper
->ISimpleAudioVolume_iface
);
1544 *ppv
= &This
->session_wrapper
->ISimpleAudioVolume_iface
;
1548 LeaveCriticalSection(&This
->lock
);
1552 LeaveCriticalSection(&This
->lock
);
1554 FIXME("stub %s\n", debugstr_guid(riid
));
1555 return E_NOINTERFACE
;
1558 static const IAudioClientVtbl AudioClient_Vtbl
=
1560 AudioClient_QueryInterface
,
1562 AudioClient_Release
,
1563 AudioClient_Initialize
,
1564 AudioClient_GetBufferSize
,
1565 AudioClient_GetStreamLatency
,
1566 AudioClient_GetCurrentPadding
,
1567 AudioClient_IsFormatSupported
,
1568 AudioClient_GetMixFormat
,
1569 AudioClient_GetDevicePeriod
,
1573 AudioClient_SetEventHandle
,
1574 AudioClient_GetService
1577 static HRESULT WINAPI
AudioRenderClient_QueryInterface(
1578 IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1580 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1586 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1587 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1590 IUnknown_AddRef((IUnknown
*)*ppv
);
1594 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1595 return E_NOINTERFACE
;
1598 static ULONG WINAPI
AudioRenderClient_AddRef(IAudioRenderClient
*iface
)
1600 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1601 return AudioClient_AddRef(&This
->IAudioClient_iface
);
1604 static ULONG WINAPI
AudioRenderClient_Release(IAudioRenderClient
*iface
)
1606 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1607 return AudioClient_Release(&This
->IAudioClient_iface
);
1610 static HRESULT WINAPI
AudioRenderClient_GetBuffer(IAudioRenderClient
*iface
,
1611 UINT32 frames
, BYTE
**data
)
1613 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1614 UINT32 pad
, write_pos
;
1617 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
1622 EnterCriticalSection(&This
->lock
);
1624 if(This
->buf_state
!= NOT_LOCKED
){
1625 LeaveCriticalSection(&This
->lock
);
1626 return AUDCLNT_E_OUT_OF_ORDER
;
1630 This
->buf_state
= LOCKED_NORMAL
;
1631 LeaveCriticalSection(&This
->lock
);
1635 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
1637 LeaveCriticalSection(&This
->lock
);
1641 if(pad
+ frames
> This
->bufsize_frames
){
1642 LeaveCriticalSection(&This
->lock
);
1643 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1647 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1648 if(write_pos
+ frames
> This
->bufsize_frames
){
1649 if(This
->tmp_buffer_frames
< frames
){
1650 if(This
->tmp_buffer
)
1651 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1652 This
->tmp_buffer
, frames
* This
->fmt
->nBlockAlign
);
1654 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1655 frames
* This
->fmt
->nBlockAlign
);
1656 if(!This
->tmp_buffer
){
1657 LeaveCriticalSection(&This
->lock
);
1658 return E_OUTOFMEMORY
;
1660 This
->tmp_buffer_frames
= frames
;
1662 *data
= This
->tmp_buffer
;
1663 This
->buf_state
= LOCKED_WRAPPED
;
1665 *data
= This
->local_buffer
+ write_pos
* This
->fmt
->nBlockAlign
;
1666 This
->buf_state
= LOCKED_NORMAL
;
1669 LeaveCriticalSection(&This
->lock
);
1674 static void oss_wrap_buffer(ACImpl
*This
, BYTE
*buffer
, UINT32 written_frames
)
1676 UINT32 write_offs_frames
=
1677 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1678 UINT32 write_offs_bytes
= write_offs_frames
* This
->fmt
->nBlockAlign
;
1679 UINT32 chunk_frames
= This
->bufsize_frames
- write_offs_frames
;
1680 UINT32 chunk_bytes
= chunk_frames
* This
->fmt
->nBlockAlign
;
1681 UINT32 written_bytes
= written_frames
* This
->fmt
->nBlockAlign
;
1683 if(written_bytes
<= chunk_bytes
){
1684 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, written_bytes
);
1686 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, chunk_bytes
);
1687 memcpy(This
->local_buffer
, buffer
+ chunk_bytes
,
1688 written_bytes
- chunk_bytes
);
1692 static HRESULT WINAPI
AudioRenderClient_ReleaseBuffer(
1693 IAudioRenderClient
*iface
, UINT32 written_frames
, DWORD flags
)
1695 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1698 TRACE("(%p)->(%u, %x)\n", This
, written_frames
, flags
);
1700 EnterCriticalSection(&This
->lock
);
1702 if(This
->buf_state
== NOT_LOCKED
|| !written_frames
){
1703 This
->buf_state
= NOT_LOCKED
;
1704 LeaveCriticalSection(&This
->lock
);
1705 return written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1708 if(This
->buf_state
== LOCKED_NORMAL
)
1709 buffer
= This
->local_buffer
+ This
->fmt
->nBlockAlign
*
1710 ((This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
);
1712 buffer
= This
->tmp_buffer
;
1714 if(flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1715 oss_silence_buffer(This
, buffer
, written_frames
);
1717 if(This
->held_frames
){
1718 if(This
->buf_state
== LOCKED_WRAPPED
)
1719 oss_wrap_buffer(This
, buffer
, written_frames
);
1721 This
->held_frames
+= written_frames
;
1726 if(This
->session
->mute
)
1727 oss_silence_buffer(This
, buffer
, written_frames
);
1729 w_bytes
= write(This
->fd
, buffer
,
1730 written_frames
* This
->fmt
->nBlockAlign
);
1732 LeaveCriticalSection(&This
->lock
);
1733 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1736 w_frames
= w_bytes
/ This
->fmt
->nBlockAlign
;
1737 This
->inbuf_frames
+= w_frames
;
1739 if(w_frames
< written_frames
){
1740 if(This
->buf_state
== LOCKED_WRAPPED
)
1741 oss_wrap_buffer(This
, This
->tmp_buffer
+ w_bytes
,
1742 written_frames
- w_frames
);
1744 This
->lcl_offs_frames
+= w_frames
;
1745 This
->held_frames
= written_frames
- w_frames
;
1749 This
->written_frames
+= written_frames
;
1750 This
->buf_state
= NOT_LOCKED
;
1752 LeaveCriticalSection(&This
->lock
);
1757 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
1758 AudioRenderClient_QueryInterface
,
1759 AudioRenderClient_AddRef
,
1760 AudioRenderClient_Release
,
1761 AudioRenderClient_GetBuffer
,
1762 AudioRenderClient_ReleaseBuffer
1765 static HRESULT WINAPI
AudioCaptureClient_QueryInterface(
1766 IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1768 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1774 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1775 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1778 IUnknown_AddRef((IUnknown
*)*ppv
);
1782 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1783 return E_NOINTERFACE
;
1786 static ULONG WINAPI
AudioCaptureClient_AddRef(IAudioCaptureClient
*iface
)
1788 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1789 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1792 static ULONG WINAPI
AudioCaptureClient_Release(IAudioCaptureClient
*iface
)
1794 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1795 return IAudioClient_Release(&This
->IAudioClient_iface
);
1798 static HRESULT WINAPI
AudioCaptureClient_GetBuffer(IAudioCaptureClient
*iface
,
1799 BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
,
1802 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1805 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
1808 if(!data
|| !frames
|| !flags
)
1811 EnterCriticalSection(&This
->lock
);
1813 if(This
->buf_state
!= NOT_LOCKED
){
1814 LeaveCriticalSection(&This
->lock
);
1815 return AUDCLNT_E_OUT_OF_ORDER
;
1818 hr
= IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1820 LeaveCriticalSection(&This
->lock
);
1826 if(This
->lcl_offs_frames
+ *frames
> This
->bufsize_frames
){
1827 UINT32 chunk_bytes
, offs_bytes
, frames_bytes
;
1828 if(This
->tmp_buffer_frames
< *frames
){
1829 if(This
->tmp_buffer
)
1830 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1831 This
->tmp_buffer
, *frames
* This
->fmt
->nBlockAlign
);
1833 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1834 *frames
* This
->fmt
->nBlockAlign
);
1835 if(!This
->tmp_buffer
){
1836 LeaveCriticalSection(&This
->lock
);
1837 return E_OUTOFMEMORY
;
1839 This
->tmp_buffer_frames
= *frames
;
1842 *data
= This
->tmp_buffer
;
1843 chunk_bytes
= (This
->bufsize_frames
- This
->lcl_offs_frames
) *
1844 This
->fmt
->nBlockAlign
;
1845 offs_bytes
= This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1846 frames_bytes
= *frames
* This
->fmt
->nBlockAlign
;
1847 memcpy(This
->tmp_buffer
, This
->local_buffer
+ offs_bytes
, chunk_bytes
);
1848 memcpy(This
->tmp_buffer
, This
->local_buffer
,
1849 frames_bytes
- chunk_bytes
);
1851 *data
= This
->local_buffer
+
1852 This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1854 This
->buf_state
= LOCKED_NORMAL
;
1856 if(devpos
|| qpcpos
)
1857 IAudioClock_GetPosition(&This
->IAudioClock_iface
, devpos
, qpcpos
);
1859 LeaveCriticalSection(&This
->lock
);
1861 return *frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
1864 static HRESULT WINAPI
AudioCaptureClient_ReleaseBuffer(
1865 IAudioCaptureClient
*iface
, UINT32 done
)
1867 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1869 TRACE("(%p)->(%u)\n", This
, done
);
1871 EnterCriticalSection(&This
->lock
);
1873 if(This
->buf_state
== NOT_LOCKED
){
1874 LeaveCriticalSection(&This
->lock
);
1875 return AUDCLNT_E_OUT_OF_ORDER
;
1878 This
->held_frames
-= done
;
1879 This
->lcl_offs_frames
+= done
;
1880 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1882 This
->buf_state
= NOT_LOCKED
;
1884 LeaveCriticalSection(&This
->lock
);
1889 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
1890 IAudioCaptureClient
*iface
, UINT32
*frames
)
1892 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1894 TRACE("(%p)->(%p)\n", This
, frames
);
1896 return AudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, frames
);
1899 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
1901 AudioCaptureClient_QueryInterface
,
1902 AudioCaptureClient_AddRef
,
1903 AudioCaptureClient_Release
,
1904 AudioCaptureClient_GetBuffer
,
1905 AudioCaptureClient_ReleaseBuffer
,
1906 AudioCaptureClient_GetNextPacketSize
1909 static HRESULT WINAPI
AudioClock_QueryInterface(IAudioClock
*iface
,
1910 REFIID riid
, void **ppv
)
1912 ACImpl
*This
= impl_from_IAudioClock(iface
);
1914 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1920 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClock
))
1922 else if(IsEqualIID(riid
, &IID_IAudioClock2
))
1923 *ppv
= &This
->IAudioClock2_iface
;
1925 IUnknown_AddRef((IUnknown
*)*ppv
);
1929 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1930 return E_NOINTERFACE
;
1933 static ULONG WINAPI
AudioClock_AddRef(IAudioClock
*iface
)
1935 ACImpl
*This
= impl_from_IAudioClock(iface
);
1936 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1939 static ULONG WINAPI
AudioClock_Release(IAudioClock
*iface
)
1941 ACImpl
*This
= impl_from_IAudioClock(iface
);
1942 return IAudioClient_Release(&This
->IAudioClient_iface
);
1945 static HRESULT WINAPI
AudioClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1947 ACImpl
*This
= impl_from_IAudioClock(iface
);
1949 TRACE("(%p)->(%p)\n", This
, freq
);
1951 *freq
= This
->fmt
->nSamplesPerSec
;
1956 static HRESULT WINAPI
AudioClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
,
1959 ACImpl
*This
= impl_from_IAudioClock(iface
);
1963 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
1968 EnterCriticalSection(&This
->lock
);
1970 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
1972 LeaveCriticalSection(&This
->lock
);
1976 if(This
->dataflow
== eRender
)
1977 *pos
= This
->written_frames
- pad
;
1978 else if(This
->dataflow
== eCapture
)
1979 *pos
= This
->written_frames
+ pad
;
1981 LeaveCriticalSection(&This
->lock
);
1984 LARGE_INTEGER stamp
, freq
;
1985 QueryPerformanceCounter(&stamp
);
1986 QueryPerformanceFrequency(&freq
);
1987 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1993 static HRESULT WINAPI
AudioClock_GetCharacteristics(IAudioClock
*iface
,
1996 ACImpl
*This
= impl_from_IAudioClock(iface
);
1998 TRACE("(%p)->(%p)\n", This
, chars
);
2003 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
2008 static const IAudioClockVtbl AudioClock_Vtbl
=
2010 AudioClock_QueryInterface
,
2013 AudioClock_GetFrequency
,
2014 AudioClock_GetPosition
,
2015 AudioClock_GetCharacteristics
2018 static HRESULT WINAPI
AudioClock2_QueryInterface(IAudioClock2
*iface
,
2019 REFIID riid
, void **ppv
)
2021 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2022 return IAudioClock_QueryInterface(&This
->IAudioClock_iface
, riid
, ppv
);
2025 static ULONG WINAPI
AudioClock2_AddRef(IAudioClock2
*iface
)
2027 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2028 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2031 static ULONG WINAPI
AudioClock2_Release(IAudioClock2
*iface
)
2033 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2034 return IAudioClient_Release(&This
->IAudioClient_iface
);
2037 static HRESULT WINAPI
AudioClock2_GetDevicePosition(IAudioClock2
*iface
,
2038 UINT64
*pos
, UINT64
*qpctime
)
2040 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2042 FIXME("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
2047 static const IAudioClock2Vtbl AudioClock2_Vtbl
=
2049 AudioClock2_QueryInterface
,
2051 AudioClock2_Release
,
2052 AudioClock2_GetDevicePosition
2055 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
)
2057 AudioSessionWrapper
*ret
;
2059 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2060 sizeof(AudioSessionWrapper
));
2064 ret
->IAudioSessionControl2_iface
.lpVtbl
= &AudioSessionControl2_Vtbl
;
2065 ret
->ISimpleAudioVolume_iface
.lpVtbl
= &SimpleAudioVolume_Vtbl
;
2066 ret
->IChannelAudioVolume_iface
.lpVtbl
= &ChannelAudioVolume_Vtbl
;
2070 ret
->client
= client
;
2072 ret
->session
= client
->session
;
2073 AudioClient_AddRef(&client
->IAudioClient_iface
);
2079 static HRESULT WINAPI
AudioSessionControl_QueryInterface(
2080 IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
2082 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2088 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2089 IsEqualIID(riid
, &IID_IAudioSessionControl
) ||
2090 IsEqualIID(riid
, &IID_IAudioSessionControl2
))
2093 IUnknown_AddRef((IUnknown
*)*ppv
);
2097 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2098 return E_NOINTERFACE
;
2101 static ULONG WINAPI
AudioSessionControl_AddRef(IAudioSessionControl2
*iface
)
2103 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2105 ref
= InterlockedIncrement(&This
->ref
);
2106 TRACE("(%p) Refcount now %u\n", This
, ref
);
2110 static ULONG WINAPI
AudioSessionControl_Release(IAudioSessionControl2
*iface
)
2112 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2114 ref
= InterlockedDecrement(&This
->ref
);
2115 TRACE("(%p) Refcount now %u\n", This
, ref
);
2118 EnterCriticalSection(&This
->client
->lock
);
2119 This
->client
->session_wrapper
= NULL
;
2120 LeaveCriticalSection(&This
->client
->lock
);
2121 AudioClient_Release(&This
->client
->IAudioClient_iface
);
2123 HeapFree(GetProcessHeap(), 0, This
);
2128 static HRESULT WINAPI
AudioSessionControl_GetState(IAudioSessionControl2
*iface
,
2129 AudioSessionState
*state
)
2131 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2134 TRACE("(%p)->(%p)\n", This
, state
);
2137 return NULL_PTR_ERR
;
2139 EnterCriticalSection(&g_sessions_lock
);
2141 if(list_empty(&This
->session
->clients
)){
2142 *state
= AudioSessionStateExpired
;
2143 LeaveCriticalSection(&g_sessions_lock
);
2147 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
){
2148 EnterCriticalSection(&client
->lock
);
2149 if(client
->playing
){
2150 *state
= AudioSessionStateActive
;
2151 LeaveCriticalSection(&client
->lock
);
2152 LeaveCriticalSection(&g_sessions_lock
);
2155 LeaveCriticalSection(&client
->lock
);
2158 LeaveCriticalSection(&g_sessions_lock
);
2160 *state
= AudioSessionStateInactive
;
2165 static HRESULT WINAPI
AudioSessionControl_GetDisplayName(
2166 IAudioSessionControl2
*iface
, WCHAR
**name
)
2168 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2170 FIXME("(%p)->(%p) - stub\n", This
, name
);
2175 static HRESULT WINAPI
AudioSessionControl_SetDisplayName(
2176 IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
2178 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2180 FIXME("(%p)->(%p, %s) - stub\n", This
, name
, debugstr_guid(session
));
2185 static HRESULT WINAPI
AudioSessionControl_GetIconPath(
2186 IAudioSessionControl2
*iface
, WCHAR
**path
)
2188 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2190 FIXME("(%p)->(%p) - stub\n", This
, path
);
2195 static HRESULT WINAPI
AudioSessionControl_SetIconPath(
2196 IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
2198 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2200 FIXME("(%p)->(%p, %s) - stub\n", This
, path
, debugstr_guid(session
));
2205 static HRESULT WINAPI
AudioSessionControl_GetGroupingParam(
2206 IAudioSessionControl2
*iface
, GUID
*group
)
2208 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2210 FIXME("(%p)->(%p) - stub\n", This
, group
);
2215 static HRESULT WINAPI
AudioSessionControl_SetGroupingParam(
2216 IAudioSessionControl2
*iface
, const GUID
*group
, const GUID
*session
)
2218 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2220 FIXME("(%p)->(%s, %s) - stub\n", This
, debugstr_guid(group
),
2221 debugstr_guid(session
));
2226 static HRESULT WINAPI
AudioSessionControl_RegisterAudioSessionNotification(
2227 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2229 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2231 FIXME("(%p)->(%p) - stub\n", This
, events
);
2236 static HRESULT WINAPI
AudioSessionControl_UnregisterAudioSessionNotification(
2237 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2239 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2241 FIXME("(%p)->(%p) - stub\n", This
, events
);
2246 static HRESULT WINAPI
AudioSessionControl_GetSessionIdentifier(
2247 IAudioSessionControl2
*iface
, WCHAR
**id
)
2249 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2251 FIXME("(%p)->(%p) - stub\n", This
, id
);
2256 static HRESULT WINAPI
AudioSessionControl_GetSessionInstanceIdentifier(
2257 IAudioSessionControl2
*iface
, WCHAR
**id
)
2259 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2261 FIXME("(%p)->(%p) - stub\n", This
, id
);
2266 static HRESULT WINAPI
AudioSessionControl_GetProcessId(
2267 IAudioSessionControl2
*iface
, DWORD
*pid
)
2269 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2271 TRACE("(%p)->(%p)\n", This
, pid
);
2276 *pid
= GetCurrentProcessId();
2281 static HRESULT WINAPI
AudioSessionControl_IsSystemSoundsSession(
2282 IAudioSessionControl2
*iface
)
2284 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2286 TRACE("(%p)\n", This
);
2291 static HRESULT WINAPI
AudioSessionControl_SetDuckingPreference(
2292 IAudioSessionControl2
*iface
, BOOL optout
)
2294 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2296 TRACE("(%p)->(%d)\n", This
, optout
);
2301 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
=
2303 AudioSessionControl_QueryInterface
,
2304 AudioSessionControl_AddRef
,
2305 AudioSessionControl_Release
,
2306 AudioSessionControl_GetState
,
2307 AudioSessionControl_GetDisplayName
,
2308 AudioSessionControl_SetDisplayName
,
2309 AudioSessionControl_GetIconPath
,
2310 AudioSessionControl_SetIconPath
,
2311 AudioSessionControl_GetGroupingParam
,
2312 AudioSessionControl_SetGroupingParam
,
2313 AudioSessionControl_RegisterAudioSessionNotification
,
2314 AudioSessionControl_UnregisterAudioSessionNotification
,
2315 AudioSessionControl_GetSessionIdentifier
,
2316 AudioSessionControl_GetSessionInstanceIdentifier
,
2317 AudioSessionControl_GetProcessId
,
2318 AudioSessionControl_IsSystemSoundsSession
,
2319 AudioSessionControl_SetDuckingPreference
2322 /* index == -1 means set all channels, otherwise sets only the given channel */
2323 static HRESULT
oss_setvol(ACImpl
*This
, UINT32 index
)
2330 if(index
== (UINT32
)-1){
2333 for(i
= 0; i
< This
->fmt
->nChannels
; ++i
){
2335 hr
= oss_setvol(This
, i
);
2343 /* OSS doesn't support volume control past the first two channels */
2346 if(This
->dataflow
== eRender
){
2347 setreq
= SNDCTL_DSP_SETPLAYVOL
;
2348 getreq
= SNDCTL_DSP_GETPLAYVOL
;
2349 }else if(This
->dataflow
== eCapture
){
2350 setreq
= SNDCTL_DSP_SETRECVOL
;
2351 getreq
= SNDCTL_DSP_GETRECVOL
;
2353 return E_UNEXPECTED
;
2355 if(ioctl(This
->fd
, getreq
, &vol
) < 0){
2357 /* device doesn't support this call */
2360 WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2364 level
= This
->session
->master_vol
* This
->session
->channel_vols
[index
] *
2368 vol
= l
| (vol
& 0xFF00);
2370 vol
= (vol
& 0xFF) | (l
<< 8);
2372 if(ioctl(This
->fd
, setreq
, &vol
) < 0){
2374 /* device doesn't support this call */
2377 WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2384 static HRESULT
oss_session_setvol(AudioSession
*session
, UINT32 index
)
2389 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2391 hr
= oss_setvol(client
, index
);
2399 static HRESULT WINAPI
SimpleAudioVolume_QueryInterface(
2400 ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
2402 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2408 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2409 IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
2412 IUnknown_AddRef((IUnknown
*)*ppv
);
2416 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2417 return E_NOINTERFACE
;
2420 static ULONG WINAPI
SimpleAudioVolume_AddRef(ISimpleAudioVolume
*iface
)
2422 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2423 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2426 static ULONG WINAPI
SimpleAudioVolume_Release(ISimpleAudioVolume
*iface
)
2428 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2429 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2432 static HRESULT WINAPI
SimpleAudioVolume_SetMasterVolume(
2433 ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
2435 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2436 AudioSession
*session
= This
->session
;
2439 TRACE("(%p)->(%f, %s)\n", session
, level
, wine_dbgstr_guid(context
));
2441 if(level
< 0.f
|| level
> 1.f
)
2442 return E_INVALIDARG
;
2445 FIXME("Notifications not supported yet\n");
2447 EnterCriticalSection(&session
->lock
);
2449 session
->master_vol
= level
;
2451 ret
= oss_session_setvol(session
, -1);
2453 LeaveCriticalSection(&session
->lock
);
2458 static HRESULT WINAPI
SimpleAudioVolume_GetMasterVolume(
2459 ISimpleAudioVolume
*iface
, float *level
)
2461 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2462 AudioSession
*session
= This
->session
;
2464 TRACE("(%p)->(%p)\n", session
, level
);
2467 return NULL_PTR_ERR
;
2469 *level
= session
->master_vol
;
2474 static HRESULT WINAPI
SimpleAudioVolume_SetMute(ISimpleAudioVolume
*iface
,
2475 BOOL mute
, const GUID
*context
)
2477 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2478 AudioSession
*session
= This
->session
;
2480 TRACE("(%p)->(%u, %p)\n", session
, mute
, context
);
2482 EnterCriticalSection(&session
->lock
);
2484 if(!mute
&& session
->mute
){
2487 session
->mute
= mute
;
2489 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2490 EnterCriticalSection(&client
->lock
);
2491 if(ioctl(client
->fd
, SNDCTL_DSP_SKIP
) < 0)
2492 WARN("Error calling DSP_SKIP: %d (%s)\n", errno
,
2494 oss_write_data(client
);
2495 LeaveCriticalSection(&client
->lock
);
2498 session
->mute
= mute
;
2500 LeaveCriticalSection(&session
->lock
);
2505 static HRESULT WINAPI
SimpleAudioVolume_GetMute(ISimpleAudioVolume
*iface
,
2508 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2509 AudioSession
*session
= This
->session
;
2511 TRACE("(%p)->(%p)\n", session
, mute
);
2514 return NULL_PTR_ERR
;
2516 *mute
= This
->session
->mute
;
2521 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
=
2523 SimpleAudioVolume_QueryInterface
,
2524 SimpleAudioVolume_AddRef
,
2525 SimpleAudioVolume_Release
,
2526 SimpleAudioVolume_SetMasterVolume
,
2527 SimpleAudioVolume_GetMasterVolume
,
2528 SimpleAudioVolume_SetMute
,
2529 SimpleAudioVolume_GetMute
2532 static HRESULT WINAPI
AudioStreamVolume_QueryInterface(
2533 IAudioStreamVolume
*iface
, REFIID riid
, void **ppv
)
2535 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2541 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2542 IsEqualIID(riid
, &IID_IAudioStreamVolume
))
2545 IUnknown_AddRef((IUnknown
*)*ppv
);
2549 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2550 return E_NOINTERFACE
;
2553 static ULONG WINAPI
AudioStreamVolume_AddRef(IAudioStreamVolume
*iface
)
2555 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2556 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2559 static ULONG WINAPI
AudioStreamVolume_Release(IAudioStreamVolume
*iface
)
2561 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2562 return IAudioClient_Release(&This
->IAudioClient_iface
);
2565 static HRESULT WINAPI
AudioStreamVolume_GetChannelCount(
2566 IAudioStreamVolume
*iface
, UINT32
*out
)
2568 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2570 TRACE("(%p)->(%p)\n", This
, out
);
2575 *out
= This
->fmt
->nChannels
;
2580 static HRESULT WINAPI
AudioStreamVolume_SetChannelVolume(
2581 IAudioStreamVolume
*iface
, UINT32 index
, float level
)
2583 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2586 TRACE("(%p)->(%d, %f)\n", This
, index
, level
);
2588 if(level
< 0.f
|| level
> 1.f
)
2589 return E_INVALIDARG
;
2591 if(index
>= This
->fmt
->nChannels
)
2592 return E_INVALIDARG
;
2594 EnterCriticalSection(&This
->lock
);
2596 This
->vols
[index
] = level
;
2598 ret
= oss_setvol(This
, index
);
2600 LeaveCriticalSection(&This
->lock
);
2605 static HRESULT WINAPI
AudioStreamVolume_GetChannelVolume(
2606 IAudioStreamVolume
*iface
, UINT32 index
, float *level
)
2608 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2610 TRACE("(%p)->(%d, %p)\n", This
, index
, level
);
2615 if(index
>= This
->fmt
->nChannels
)
2616 return E_INVALIDARG
;
2618 *level
= This
->vols
[index
];
2623 static HRESULT WINAPI
AudioStreamVolume_SetAllVolumes(
2624 IAudioStreamVolume
*iface
, UINT32 count
, const float *levels
)
2626 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2630 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2635 if(count
!= This
->fmt
->nChannels
)
2636 return E_INVALIDARG
;
2638 EnterCriticalSection(&This
->lock
);
2640 for(i
= 0; i
< count
; ++i
)
2641 This
->vols
[i
] = levels
[i
];
2643 ret
= oss_setvol(This
, -1);
2645 LeaveCriticalSection(&This
->lock
);
2650 static HRESULT WINAPI
AudioStreamVolume_GetAllVolumes(
2651 IAudioStreamVolume
*iface
, UINT32 count
, float *levels
)
2653 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2656 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2661 if(count
!= This
->fmt
->nChannels
)
2662 return E_INVALIDARG
;
2664 EnterCriticalSection(&This
->lock
);
2666 for(i
= 0; i
< count
; ++i
)
2667 levels
[i
] = This
->vols
[i
];
2669 LeaveCriticalSection(&This
->lock
);
2674 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
=
2676 AudioStreamVolume_QueryInterface
,
2677 AudioStreamVolume_AddRef
,
2678 AudioStreamVolume_Release
,
2679 AudioStreamVolume_GetChannelCount
,
2680 AudioStreamVolume_SetChannelVolume
,
2681 AudioStreamVolume_GetChannelVolume
,
2682 AudioStreamVolume_SetAllVolumes
,
2683 AudioStreamVolume_GetAllVolumes
2686 static HRESULT WINAPI
ChannelAudioVolume_QueryInterface(
2687 IChannelAudioVolume
*iface
, REFIID riid
, void **ppv
)
2689 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2695 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2696 IsEqualIID(riid
, &IID_IChannelAudioVolume
))
2699 IUnknown_AddRef((IUnknown
*)*ppv
);
2703 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2704 return E_NOINTERFACE
;
2707 static ULONG WINAPI
ChannelAudioVolume_AddRef(IChannelAudioVolume
*iface
)
2709 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2710 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2713 static ULONG WINAPI
ChannelAudioVolume_Release(IChannelAudioVolume
*iface
)
2715 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2716 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2719 static HRESULT WINAPI
ChannelAudioVolume_GetChannelCount(
2720 IChannelAudioVolume
*iface
, UINT32
*out
)
2722 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2723 AudioSession
*session
= This
->session
;
2725 TRACE("(%p)->(%p)\n", session
, out
);
2728 return NULL_PTR_ERR
;
2730 *out
= session
->channel_count
;
2735 static HRESULT WINAPI
ChannelAudioVolume_SetChannelVolume(
2736 IChannelAudioVolume
*iface
, UINT32 index
, float level
,
2737 const GUID
*context
)
2739 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2740 AudioSession
*session
= This
->session
;
2743 TRACE("(%p)->(%d, %f, %s)\n", session
, index
, level
,
2744 wine_dbgstr_guid(context
));
2746 if(level
< 0.f
|| level
> 1.f
)
2747 return E_INVALIDARG
;
2749 if(index
>= session
->channel_count
)
2750 return E_INVALIDARG
;
2753 FIXME("Notifications not supported yet\n");
2755 EnterCriticalSection(&session
->lock
);
2757 session
->channel_vols
[index
] = level
;
2759 ret
= oss_session_setvol(session
, index
);
2761 LeaveCriticalSection(&session
->lock
);
2766 static HRESULT WINAPI
ChannelAudioVolume_GetChannelVolume(
2767 IChannelAudioVolume
*iface
, UINT32 index
, float *level
)
2769 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2770 AudioSession
*session
= This
->session
;
2772 TRACE("(%p)->(%d, %p)\n", session
, index
, level
);
2775 return NULL_PTR_ERR
;
2777 if(index
>= session
->channel_count
)
2778 return E_INVALIDARG
;
2780 *level
= session
->channel_vols
[index
];
2785 static HRESULT WINAPI
ChannelAudioVolume_SetAllVolumes(
2786 IChannelAudioVolume
*iface
, UINT32 count
, const float *levels
,
2787 const GUID
*context
)
2789 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2790 AudioSession
*session
= This
->session
;
2794 TRACE("(%p)->(%d, %p, %s)\n", session
, count
, levels
,
2795 wine_dbgstr_guid(context
));
2798 return NULL_PTR_ERR
;
2800 if(count
!= session
->channel_count
)
2801 return E_INVALIDARG
;
2804 FIXME("Notifications not supported yet\n");
2806 EnterCriticalSection(&session
->lock
);
2808 for(i
= 0; i
< count
; ++i
)
2809 session
->channel_vols
[i
] = levels
[i
];
2811 ret
= oss_session_setvol(session
, -1);
2813 LeaveCriticalSection(&session
->lock
);
2818 static HRESULT WINAPI
ChannelAudioVolume_GetAllVolumes(
2819 IChannelAudioVolume
*iface
, UINT32 count
, float *levels
)
2821 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2822 AudioSession
*session
= This
->session
;
2825 TRACE("(%p)->(%d, %p)\n", session
, count
, levels
);
2828 return NULL_PTR_ERR
;
2830 if(count
!= session
->channel_count
)
2831 return E_INVALIDARG
;
2833 for(i
= 0; i
< count
; ++i
)
2834 levels
[i
] = session
->channel_vols
[i
];
2839 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
=
2841 ChannelAudioVolume_QueryInterface
,
2842 ChannelAudioVolume_AddRef
,
2843 ChannelAudioVolume_Release
,
2844 ChannelAudioVolume_GetChannelCount
,
2845 ChannelAudioVolume_SetChannelVolume
,
2846 ChannelAudioVolume_GetChannelVolume
,
2847 ChannelAudioVolume_SetAllVolumes
,
2848 ChannelAudioVolume_GetAllVolumes
2851 static HRESULT WINAPI
AudioSessionManager_QueryInterface(IAudioSessionManager2
*iface
,
2852 REFIID riid
, void **ppv
)
2854 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2860 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2861 IsEqualIID(riid
, &IID_IAudioSessionManager
) ||
2862 IsEqualIID(riid
, &IID_IAudioSessionManager2
))
2865 IUnknown_AddRef((IUnknown
*)*ppv
);
2869 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2870 return E_NOINTERFACE
;
2873 static ULONG WINAPI
AudioSessionManager_AddRef(IAudioSessionManager2
*iface
)
2875 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2877 ref
= InterlockedIncrement(&This
->ref
);
2878 TRACE("(%p) Refcount now %u\n", This
, ref
);
2882 static ULONG WINAPI
AudioSessionManager_Release(IAudioSessionManager2
*iface
)
2884 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2886 ref
= InterlockedDecrement(&This
->ref
);
2887 TRACE("(%p) Refcount now %u\n", This
, ref
);
2889 HeapFree(GetProcessHeap(), 0, This
);
2893 static HRESULT WINAPI
AudioSessionManager_GetAudioSessionControl(
2894 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2895 IAudioSessionControl
**out
)
2897 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2898 AudioSession
*session
;
2899 AudioSessionWrapper
*wrapper
;
2902 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2905 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2909 wrapper
= AudioSessionWrapper_Create(NULL
);
2911 return E_OUTOFMEMORY
;
2913 wrapper
->session
= session
;
2915 *out
= (IAudioSessionControl
*)&wrapper
->IAudioSessionControl2_iface
;
2920 static HRESULT WINAPI
AudioSessionManager_GetSimpleAudioVolume(
2921 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2922 ISimpleAudioVolume
**out
)
2924 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2925 AudioSession
*session
;
2926 AudioSessionWrapper
*wrapper
;
2929 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2932 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2936 wrapper
= AudioSessionWrapper_Create(NULL
);
2938 return E_OUTOFMEMORY
;
2940 wrapper
->session
= session
;
2942 *out
= &wrapper
->ISimpleAudioVolume_iface
;
2947 static HRESULT WINAPI
AudioSessionManager_GetSessionEnumerator(
2948 IAudioSessionManager2
*iface
, IAudioSessionEnumerator
**out
)
2950 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2951 FIXME("(%p)->(%p) - stub\n", This
, out
);
2955 static HRESULT WINAPI
AudioSessionManager_RegisterSessionNotification(
2956 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
2958 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2959 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2963 static HRESULT WINAPI
AudioSessionManager_UnregisterSessionNotification(
2964 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
2966 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2967 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2971 static HRESULT WINAPI
AudioSessionManager_RegisterDuckNotification(
2972 IAudioSessionManager2
*iface
, const WCHAR
*session_id
,
2973 IAudioVolumeDuckNotification
*notification
)
2975 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2976 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2980 static HRESULT WINAPI
AudioSessionManager_UnregisterDuckNotification(
2981 IAudioSessionManager2
*iface
,
2982 IAudioVolumeDuckNotification
*notification
)
2984 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2985 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2989 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
=
2991 AudioSessionManager_QueryInterface
,
2992 AudioSessionManager_AddRef
,
2993 AudioSessionManager_Release
,
2994 AudioSessionManager_GetAudioSessionControl
,
2995 AudioSessionManager_GetSimpleAudioVolume
,
2996 AudioSessionManager_GetSessionEnumerator
,
2997 AudioSessionManager_RegisterSessionNotification
,
2998 AudioSessionManager_UnregisterSessionNotification
,
2999 AudioSessionManager_RegisterDuckNotification
,
3000 AudioSessionManager_UnregisterDuckNotification
3003 HRESULT WINAPI
AUDDRV_GetAudioSessionManager(IMMDevice
*device
,
3004 IAudioSessionManager2
**out
)
3008 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SessionMgr
));
3010 return E_OUTOFMEMORY
;
3012 This
->IAudioSessionManager2_iface
.lpVtbl
= &AudioSessionManager2_Vtbl
;
3013 This
->device
= device
;
3016 *out
= &This
->IAudioSessionManager2_iface
;