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 /* EAGAIN is OSS buffer full, log that too */
1228 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1231 written_frames
= written
/ This
->fmt
->nBlockAlign
;
1233 This
->lcl_offs_frames
+= written_frames
;
1234 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1235 This
->held_frames
-= written_frames
;
1236 This
->inbuf_frames
+= written_frames
;
1238 if(written_frames
< to_write
){
1239 /* OSS buffer probably full */
1243 if(This
->held_frames
){
1244 /* wrapped and have some data back at the start to write */
1246 if(This
->session
->mute
)
1247 oss_silence_buffer(This
, This
->local_buffer
, This
->held_frames
);
1249 written
= write(This
->fd
, This
->local_buffer
,
1250 This
->held_frames
* This
->fmt
->nBlockAlign
);
1252 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1255 written_frames
= written
/ This
->fmt
->nBlockAlign
;
1257 This
->lcl_offs_frames
+= written_frames
;
1258 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1259 This
->held_frames
-= written_frames
;
1260 This
->inbuf_frames
+= written_frames
;
1264 static void oss_read_data(ACImpl
*This
)
1266 UINT64 pos
, readable
;
1270 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
1271 WARN("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
1275 pos
= (This
->held_frames
+ This
->lcl_offs_frames
) % This
->bufsize_frames
;
1276 readable
= (This
->bufsize_frames
- pos
) * This
->fmt
->nBlockAlign
;
1278 if(bi
.bytes
< readable
)
1279 readable
= bi
.bytes
;
1281 nread
= read(This
->fd
, This
->local_buffer
+ pos
* This
->fmt
->nBlockAlign
,
1284 WARN("read failed: %d (%s)\n", errno
, strerror(errno
));
1288 This
->held_frames
+= nread
/ This
->fmt
->nBlockAlign
;
1290 if(This
->held_frames
> This
->bufsize_frames
){
1291 WARN("Overflow of unread data\n");
1292 This
->lcl_offs_frames
+= This
->held_frames
;
1293 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1294 This
->held_frames
= This
->bufsize_frames
;
1298 static void CALLBACK
oss_period_callback(void *user
, BOOLEAN timer
)
1300 ACImpl
*This
= user
;
1302 EnterCriticalSection(&This
->lock
);
1304 if(This
->dataflow
== eRender
&& This
->held_frames
)
1305 oss_write_data(This
);
1306 else if(This
->dataflow
== eCapture
)
1307 oss_read_data(This
);
1310 SetEvent(This
->event
);
1312 LeaveCriticalSection(&This
->lock
);
1315 static HRESULT WINAPI
AudioClient_Start(IAudioClient
*iface
)
1317 ACImpl
*This
= impl_from_IAudioClient(iface
);
1320 TRACE("(%p)\n", This
);
1322 EnterCriticalSection(&This
->lock
);
1325 LeaveCriticalSection(&This
->lock
);
1326 return AUDCLNT_E_NOT_INITIALIZED
;
1329 if((This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !This
->event
){
1330 LeaveCriticalSection(&This
->lock
);
1331 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1335 LeaveCriticalSection(&This
->lock
);
1336 return AUDCLNT_E_NOT_STOPPED
;
1339 if(This
->dataflow
== eRender
)
1340 mask
= PCM_ENABLE_OUTPUT
;
1341 else if(This
->dataflow
== eCapture
)
1342 mask
= PCM_ENABLE_INPUT
;
1344 LeaveCriticalSection(&This
->lock
);
1345 return E_UNEXPECTED
;
1348 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1349 LeaveCriticalSection(&This
->lock
);
1350 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1354 if(!CreateTimerQueueTimer(&This
->timer
, g_timer_q
,
1355 oss_period_callback
, This
, 0, This
->period_us
/ 1000,
1356 WT_EXECUTEINTIMERTHREAD
))
1357 ERR("Unable to create period timer: %u\n", GetLastError());
1359 This
->playing
= TRUE
;
1361 LeaveCriticalSection(&This
->lock
);
1366 static HRESULT WINAPI
AudioClient_Stop(IAudioClient
*iface
)
1368 ACImpl
*This
= impl_from_IAudioClient(iface
);
1371 TRACE("(%p)\n", This
);
1373 EnterCriticalSection(&This
->lock
);
1376 LeaveCriticalSection(&This
->lock
);
1377 return AUDCLNT_E_NOT_INITIALIZED
;
1381 LeaveCriticalSection(&This
->lock
);
1385 if(This
->timer
&& This
->timer
!= INVALID_HANDLE_VALUE
){
1386 DeleteTimerQueueTimer(g_timer_q
, This
->timer
,
1387 INVALID_HANDLE_VALUE
);
1391 if(ioctl(This
->fd
, SNDCTL_DSP_HALT
, NULL
) < 0){
1392 LeaveCriticalSection(&This
->lock
);
1393 WARN("HALT failed: %d (%s)\n", errno
, strerror(errno
));
1398 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1399 LeaveCriticalSection(&This
->lock
);
1400 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1404 This
->playing
= FALSE
;
1406 LeaveCriticalSection(&This
->lock
);
1411 static HRESULT WINAPI
AudioClient_Reset(IAudioClient
*iface
)
1413 ACImpl
*This
= impl_from_IAudioClient(iface
);
1415 TRACE("(%p)\n", This
);
1417 EnterCriticalSection(&This
->lock
);
1420 LeaveCriticalSection(&This
->lock
);
1421 return AUDCLNT_E_NOT_INITIALIZED
;
1425 LeaveCriticalSection(&This
->lock
);
1426 return AUDCLNT_E_NOT_STOPPED
;
1429 if(This
->buf_state
!= NOT_LOCKED
){
1430 LeaveCriticalSection(&This
->lock
);
1431 return AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1434 This
->written_frames
= 0;
1435 This
->inbuf_frames
= 0;
1436 This
->held_frames
= 0;
1438 if(ioctl(This
->fd
, SNDCTL_DSP_SKIP
, NULL
) < 0)
1439 WARN("SKIP failed: %d (%s)\n", errno
, strerror(errno
));
1441 LeaveCriticalSection(&This
->lock
);
1446 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient
*iface
,
1449 ACImpl
*This
= impl_from_IAudioClient(iface
);
1451 TRACE("(%p)->(%p)\n", This
, event
);
1454 return E_INVALIDARG
;
1456 EnterCriticalSection(&This
->lock
);
1459 LeaveCriticalSection(&This
->lock
);
1460 return AUDCLNT_E_NOT_INITIALIZED
;
1463 if(!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
)){
1464 LeaveCriticalSection(&This
->lock
);
1465 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1468 This
->event
= event
;
1470 LeaveCriticalSection(&This
->lock
);
1475 static HRESULT WINAPI
AudioClient_GetService(IAudioClient
*iface
, REFIID riid
,
1478 ACImpl
*This
= impl_from_IAudioClient(iface
);
1480 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1486 EnterCriticalSection(&This
->lock
);
1489 LeaveCriticalSection(&This
->lock
);
1490 return AUDCLNT_E_NOT_INITIALIZED
;
1493 if(IsEqualIID(riid
, &IID_IAudioRenderClient
)){
1494 if(This
->dataflow
!= eRender
){
1495 LeaveCriticalSection(&This
->lock
);
1496 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1498 IAudioRenderClient_AddRef(&This
->IAudioRenderClient_iface
);
1499 *ppv
= &This
->IAudioRenderClient_iface
;
1500 }else if(IsEqualIID(riid
, &IID_IAudioCaptureClient
)){
1501 if(This
->dataflow
!= eCapture
){
1502 LeaveCriticalSection(&This
->lock
);
1503 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1505 IAudioCaptureClient_AddRef(&This
->IAudioCaptureClient_iface
);
1506 *ppv
= &This
->IAudioCaptureClient_iface
;
1507 }else if(IsEqualIID(riid
, &IID_IAudioClock
)){
1508 IAudioClock_AddRef(&This
->IAudioClock_iface
);
1509 *ppv
= &This
->IAudioClock_iface
;
1510 }else if(IsEqualIID(riid
, &IID_IAudioStreamVolume
)){
1511 IAudioStreamVolume_AddRef(&This
->IAudioStreamVolume_iface
);
1512 *ppv
= &This
->IAudioStreamVolume_iface
;
1513 }else if(IsEqualIID(riid
, &IID_IAudioSessionControl
)){
1514 if(!This
->session_wrapper
){
1515 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1516 if(!This
->session_wrapper
){
1517 LeaveCriticalSection(&This
->lock
);
1518 return E_OUTOFMEMORY
;
1521 IAudioSessionControl2_AddRef(&This
->session_wrapper
->IAudioSessionControl2_iface
);
1523 *ppv
= &This
->session_wrapper
->IAudioSessionControl2_iface
;
1524 }else if(IsEqualIID(riid
, &IID_IChannelAudioVolume
)){
1525 if(!This
->session_wrapper
){
1526 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1527 if(!This
->session_wrapper
){
1528 LeaveCriticalSection(&This
->lock
);
1529 return E_OUTOFMEMORY
;
1532 IChannelAudioVolume_AddRef(&This
->session_wrapper
->IChannelAudioVolume_iface
);
1534 *ppv
= &This
->session_wrapper
->IChannelAudioVolume_iface
;
1535 }else if(IsEqualIID(riid
, &IID_ISimpleAudioVolume
)){
1536 if(!This
->session_wrapper
){
1537 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1538 if(!This
->session_wrapper
){
1539 LeaveCriticalSection(&This
->lock
);
1540 return E_OUTOFMEMORY
;
1543 ISimpleAudioVolume_AddRef(&This
->session_wrapper
->ISimpleAudioVolume_iface
);
1545 *ppv
= &This
->session_wrapper
->ISimpleAudioVolume_iface
;
1549 LeaveCriticalSection(&This
->lock
);
1553 LeaveCriticalSection(&This
->lock
);
1555 FIXME("stub %s\n", debugstr_guid(riid
));
1556 return E_NOINTERFACE
;
1559 static const IAudioClientVtbl AudioClient_Vtbl
=
1561 AudioClient_QueryInterface
,
1563 AudioClient_Release
,
1564 AudioClient_Initialize
,
1565 AudioClient_GetBufferSize
,
1566 AudioClient_GetStreamLatency
,
1567 AudioClient_GetCurrentPadding
,
1568 AudioClient_IsFormatSupported
,
1569 AudioClient_GetMixFormat
,
1570 AudioClient_GetDevicePeriod
,
1574 AudioClient_SetEventHandle
,
1575 AudioClient_GetService
1578 static HRESULT WINAPI
AudioRenderClient_QueryInterface(
1579 IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1581 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1587 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1588 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1591 IUnknown_AddRef((IUnknown
*)*ppv
);
1595 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1596 return E_NOINTERFACE
;
1599 static ULONG WINAPI
AudioRenderClient_AddRef(IAudioRenderClient
*iface
)
1601 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1602 return AudioClient_AddRef(&This
->IAudioClient_iface
);
1605 static ULONG WINAPI
AudioRenderClient_Release(IAudioRenderClient
*iface
)
1607 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1608 return AudioClient_Release(&This
->IAudioClient_iface
);
1611 static HRESULT WINAPI
AudioRenderClient_GetBuffer(IAudioRenderClient
*iface
,
1612 UINT32 frames
, BYTE
**data
)
1614 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1615 UINT32 pad
, write_pos
;
1618 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
1623 EnterCriticalSection(&This
->lock
);
1625 if(This
->buf_state
!= NOT_LOCKED
){
1626 LeaveCriticalSection(&This
->lock
);
1627 return AUDCLNT_E_OUT_OF_ORDER
;
1631 This
->buf_state
= LOCKED_NORMAL
;
1632 LeaveCriticalSection(&This
->lock
);
1636 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
1638 LeaveCriticalSection(&This
->lock
);
1642 if(pad
+ frames
> This
->bufsize_frames
){
1643 LeaveCriticalSection(&This
->lock
);
1644 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1648 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1649 if(write_pos
+ frames
> This
->bufsize_frames
){
1650 if(This
->tmp_buffer_frames
< frames
){
1651 if(This
->tmp_buffer
)
1652 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1653 This
->tmp_buffer
, frames
* This
->fmt
->nBlockAlign
);
1655 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1656 frames
* This
->fmt
->nBlockAlign
);
1657 if(!This
->tmp_buffer
){
1658 LeaveCriticalSection(&This
->lock
);
1659 return E_OUTOFMEMORY
;
1661 This
->tmp_buffer_frames
= frames
;
1663 *data
= This
->tmp_buffer
;
1664 This
->buf_state
= LOCKED_WRAPPED
;
1666 *data
= This
->local_buffer
+ write_pos
* This
->fmt
->nBlockAlign
;
1667 This
->buf_state
= LOCKED_NORMAL
;
1670 LeaveCriticalSection(&This
->lock
);
1675 static void oss_wrap_buffer(ACImpl
*This
, BYTE
*buffer
, UINT32 written_frames
)
1677 UINT32 write_offs_frames
=
1678 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1679 UINT32 write_offs_bytes
= write_offs_frames
* This
->fmt
->nBlockAlign
;
1680 UINT32 chunk_frames
= This
->bufsize_frames
- write_offs_frames
;
1681 UINT32 chunk_bytes
= chunk_frames
* This
->fmt
->nBlockAlign
;
1682 UINT32 written_bytes
= written_frames
* This
->fmt
->nBlockAlign
;
1684 if(written_bytes
<= chunk_bytes
){
1685 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, written_bytes
);
1687 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, chunk_bytes
);
1688 memcpy(This
->local_buffer
, buffer
+ chunk_bytes
,
1689 written_bytes
- chunk_bytes
);
1693 static HRESULT WINAPI
AudioRenderClient_ReleaseBuffer(
1694 IAudioRenderClient
*iface
, UINT32 written_frames
, DWORD flags
)
1696 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1699 TRACE("(%p)->(%u, %x)\n", This
, written_frames
, flags
);
1701 EnterCriticalSection(&This
->lock
);
1703 if(This
->buf_state
== NOT_LOCKED
|| !written_frames
){
1704 This
->buf_state
= NOT_LOCKED
;
1705 LeaveCriticalSection(&This
->lock
);
1706 return written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1709 if(This
->buf_state
== LOCKED_NORMAL
)
1710 buffer
= This
->local_buffer
+ This
->fmt
->nBlockAlign
*
1711 ((This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
);
1713 buffer
= This
->tmp_buffer
;
1715 if(flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1716 oss_silence_buffer(This
, buffer
, written_frames
);
1718 if(This
->held_frames
){
1719 if(This
->buf_state
== LOCKED_WRAPPED
)
1720 oss_wrap_buffer(This
, buffer
, written_frames
);
1722 This
->held_frames
+= written_frames
;
1727 if(This
->session
->mute
)
1728 oss_silence_buffer(This
, buffer
, written_frames
);
1730 w_bytes
= write(This
->fd
, buffer
,
1731 written_frames
* This
->fmt
->nBlockAlign
);
1733 if(errno
!= EAGAIN
){
1734 This
->buf_state
= NOT_LOCKED
;
1735 LeaveCriticalSection(&This
->lock
);
1736 ERR("write failed: %d (%s)\n", errno
, strerror(errno
));
1738 }else /* OSS buffer full */
1741 w_frames
= w_bytes
/ This
->fmt
->nBlockAlign
;
1742 This
->inbuf_frames
+= w_frames
;
1744 if(w_frames
< written_frames
){
1745 if(This
->buf_state
== LOCKED_WRAPPED
)
1746 oss_wrap_buffer(This
, This
->tmp_buffer
+ w_bytes
,
1747 written_frames
- w_frames
);
1749 This
->lcl_offs_frames
+= w_frames
;
1750 This
->held_frames
= written_frames
- w_frames
;
1754 This
->written_frames
+= written_frames
;
1755 This
->buf_state
= NOT_LOCKED
;
1757 LeaveCriticalSection(&This
->lock
);
1762 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
1763 AudioRenderClient_QueryInterface
,
1764 AudioRenderClient_AddRef
,
1765 AudioRenderClient_Release
,
1766 AudioRenderClient_GetBuffer
,
1767 AudioRenderClient_ReleaseBuffer
1770 static HRESULT WINAPI
AudioCaptureClient_QueryInterface(
1771 IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1773 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1779 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1780 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1783 IUnknown_AddRef((IUnknown
*)*ppv
);
1787 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1788 return E_NOINTERFACE
;
1791 static ULONG WINAPI
AudioCaptureClient_AddRef(IAudioCaptureClient
*iface
)
1793 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1794 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1797 static ULONG WINAPI
AudioCaptureClient_Release(IAudioCaptureClient
*iface
)
1799 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1800 return IAudioClient_Release(&This
->IAudioClient_iface
);
1803 static HRESULT WINAPI
AudioCaptureClient_GetBuffer(IAudioCaptureClient
*iface
,
1804 BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
,
1807 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1810 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
1813 if(!data
|| !frames
|| !flags
)
1816 EnterCriticalSection(&This
->lock
);
1818 if(This
->buf_state
!= NOT_LOCKED
){
1819 LeaveCriticalSection(&This
->lock
);
1820 return AUDCLNT_E_OUT_OF_ORDER
;
1823 hr
= IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1825 LeaveCriticalSection(&This
->lock
);
1831 if(This
->lcl_offs_frames
+ *frames
> This
->bufsize_frames
){
1832 UINT32 chunk_bytes
, offs_bytes
, frames_bytes
;
1833 if(This
->tmp_buffer_frames
< *frames
){
1834 if(This
->tmp_buffer
)
1835 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1836 This
->tmp_buffer
, *frames
* This
->fmt
->nBlockAlign
);
1838 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1839 *frames
* This
->fmt
->nBlockAlign
);
1840 if(!This
->tmp_buffer
){
1841 LeaveCriticalSection(&This
->lock
);
1842 return E_OUTOFMEMORY
;
1844 This
->tmp_buffer_frames
= *frames
;
1847 *data
= This
->tmp_buffer
;
1848 chunk_bytes
= (This
->bufsize_frames
- This
->lcl_offs_frames
) *
1849 This
->fmt
->nBlockAlign
;
1850 offs_bytes
= This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1851 frames_bytes
= *frames
* This
->fmt
->nBlockAlign
;
1852 memcpy(This
->tmp_buffer
, This
->local_buffer
+ offs_bytes
, chunk_bytes
);
1853 memcpy(This
->tmp_buffer
, This
->local_buffer
,
1854 frames_bytes
- chunk_bytes
);
1856 *data
= This
->local_buffer
+
1857 This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1859 This
->buf_state
= LOCKED_NORMAL
;
1861 if(devpos
|| qpcpos
)
1862 IAudioClock_GetPosition(&This
->IAudioClock_iface
, devpos
, qpcpos
);
1864 LeaveCriticalSection(&This
->lock
);
1866 return *frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
1869 static HRESULT WINAPI
AudioCaptureClient_ReleaseBuffer(
1870 IAudioCaptureClient
*iface
, UINT32 done
)
1872 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1874 TRACE("(%p)->(%u)\n", This
, done
);
1876 EnterCriticalSection(&This
->lock
);
1878 if(This
->buf_state
== NOT_LOCKED
){
1879 LeaveCriticalSection(&This
->lock
);
1880 return AUDCLNT_E_OUT_OF_ORDER
;
1883 This
->held_frames
-= done
;
1884 This
->lcl_offs_frames
+= done
;
1885 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1887 This
->buf_state
= NOT_LOCKED
;
1889 LeaveCriticalSection(&This
->lock
);
1894 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
1895 IAudioCaptureClient
*iface
, UINT32
*frames
)
1897 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1899 TRACE("(%p)->(%p)\n", This
, frames
);
1901 return AudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, frames
);
1904 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
1906 AudioCaptureClient_QueryInterface
,
1907 AudioCaptureClient_AddRef
,
1908 AudioCaptureClient_Release
,
1909 AudioCaptureClient_GetBuffer
,
1910 AudioCaptureClient_ReleaseBuffer
,
1911 AudioCaptureClient_GetNextPacketSize
1914 static HRESULT WINAPI
AudioClock_QueryInterface(IAudioClock
*iface
,
1915 REFIID riid
, void **ppv
)
1917 ACImpl
*This
= impl_from_IAudioClock(iface
);
1919 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1925 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClock
))
1927 else if(IsEqualIID(riid
, &IID_IAudioClock2
))
1928 *ppv
= &This
->IAudioClock2_iface
;
1930 IUnknown_AddRef((IUnknown
*)*ppv
);
1934 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1935 return E_NOINTERFACE
;
1938 static ULONG WINAPI
AudioClock_AddRef(IAudioClock
*iface
)
1940 ACImpl
*This
= impl_from_IAudioClock(iface
);
1941 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1944 static ULONG WINAPI
AudioClock_Release(IAudioClock
*iface
)
1946 ACImpl
*This
= impl_from_IAudioClock(iface
);
1947 return IAudioClient_Release(&This
->IAudioClient_iface
);
1950 static HRESULT WINAPI
AudioClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1952 ACImpl
*This
= impl_from_IAudioClock(iface
);
1954 TRACE("(%p)->(%p)\n", This
, freq
);
1956 *freq
= This
->fmt
->nSamplesPerSec
;
1961 static HRESULT WINAPI
AudioClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
,
1964 ACImpl
*This
= impl_from_IAudioClock(iface
);
1968 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
1973 EnterCriticalSection(&This
->lock
);
1975 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
1977 LeaveCriticalSection(&This
->lock
);
1981 if(This
->dataflow
== eRender
)
1982 *pos
= This
->written_frames
- pad
;
1983 else if(This
->dataflow
== eCapture
)
1984 *pos
= This
->written_frames
+ pad
;
1986 LeaveCriticalSection(&This
->lock
);
1989 LARGE_INTEGER stamp
, freq
;
1990 QueryPerformanceCounter(&stamp
);
1991 QueryPerformanceFrequency(&freq
);
1992 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1998 static HRESULT WINAPI
AudioClock_GetCharacteristics(IAudioClock
*iface
,
2001 ACImpl
*This
= impl_from_IAudioClock(iface
);
2003 TRACE("(%p)->(%p)\n", This
, chars
);
2008 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
2013 static const IAudioClockVtbl AudioClock_Vtbl
=
2015 AudioClock_QueryInterface
,
2018 AudioClock_GetFrequency
,
2019 AudioClock_GetPosition
,
2020 AudioClock_GetCharacteristics
2023 static HRESULT WINAPI
AudioClock2_QueryInterface(IAudioClock2
*iface
,
2024 REFIID riid
, void **ppv
)
2026 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2027 return IAudioClock_QueryInterface(&This
->IAudioClock_iface
, riid
, ppv
);
2030 static ULONG WINAPI
AudioClock2_AddRef(IAudioClock2
*iface
)
2032 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2033 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2036 static ULONG WINAPI
AudioClock2_Release(IAudioClock2
*iface
)
2038 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2039 return IAudioClient_Release(&This
->IAudioClient_iface
);
2042 static HRESULT WINAPI
AudioClock2_GetDevicePosition(IAudioClock2
*iface
,
2043 UINT64
*pos
, UINT64
*qpctime
)
2045 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2047 FIXME("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
2052 static const IAudioClock2Vtbl AudioClock2_Vtbl
=
2054 AudioClock2_QueryInterface
,
2056 AudioClock2_Release
,
2057 AudioClock2_GetDevicePosition
2060 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
)
2062 AudioSessionWrapper
*ret
;
2064 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2065 sizeof(AudioSessionWrapper
));
2069 ret
->IAudioSessionControl2_iface
.lpVtbl
= &AudioSessionControl2_Vtbl
;
2070 ret
->ISimpleAudioVolume_iface
.lpVtbl
= &SimpleAudioVolume_Vtbl
;
2071 ret
->IChannelAudioVolume_iface
.lpVtbl
= &ChannelAudioVolume_Vtbl
;
2075 ret
->client
= client
;
2077 ret
->session
= client
->session
;
2078 AudioClient_AddRef(&client
->IAudioClient_iface
);
2084 static HRESULT WINAPI
AudioSessionControl_QueryInterface(
2085 IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
2087 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2093 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2094 IsEqualIID(riid
, &IID_IAudioSessionControl
) ||
2095 IsEqualIID(riid
, &IID_IAudioSessionControl2
))
2098 IUnknown_AddRef((IUnknown
*)*ppv
);
2102 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2103 return E_NOINTERFACE
;
2106 static ULONG WINAPI
AudioSessionControl_AddRef(IAudioSessionControl2
*iface
)
2108 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2110 ref
= InterlockedIncrement(&This
->ref
);
2111 TRACE("(%p) Refcount now %u\n", This
, ref
);
2115 static ULONG WINAPI
AudioSessionControl_Release(IAudioSessionControl2
*iface
)
2117 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2119 ref
= InterlockedDecrement(&This
->ref
);
2120 TRACE("(%p) Refcount now %u\n", This
, ref
);
2123 EnterCriticalSection(&This
->client
->lock
);
2124 This
->client
->session_wrapper
= NULL
;
2125 LeaveCriticalSection(&This
->client
->lock
);
2126 AudioClient_Release(&This
->client
->IAudioClient_iface
);
2128 HeapFree(GetProcessHeap(), 0, This
);
2133 static HRESULT WINAPI
AudioSessionControl_GetState(IAudioSessionControl2
*iface
,
2134 AudioSessionState
*state
)
2136 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2139 TRACE("(%p)->(%p)\n", This
, state
);
2142 return NULL_PTR_ERR
;
2144 EnterCriticalSection(&g_sessions_lock
);
2146 if(list_empty(&This
->session
->clients
)){
2147 *state
= AudioSessionStateExpired
;
2148 LeaveCriticalSection(&g_sessions_lock
);
2152 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
){
2153 EnterCriticalSection(&client
->lock
);
2154 if(client
->playing
){
2155 *state
= AudioSessionStateActive
;
2156 LeaveCriticalSection(&client
->lock
);
2157 LeaveCriticalSection(&g_sessions_lock
);
2160 LeaveCriticalSection(&client
->lock
);
2163 LeaveCriticalSection(&g_sessions_lock
);
2165 *state
= AudioSessionStateInactive
;
2170 static HRESULT WINAPI
AudioSessionControl_GetDisplayName(
2171 IAudioSessionControl2
*iface
, WCHAR
**name
)
2173 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2175 FIXME("(%p)->(%p) - stub\n", This
, name
);
2180 static HRESULT WINAPI
AudioSessionControl_SetDisplayName(
2181 IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
2183 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2185 FIXME("(%p)->(%p, %s) - stub\n", This
, name
, debugstr_guid(session
));
2190 static HRESULT WINAPI
AudioSessionControl_GetIconPath(
2191 IAudioSessionControl2
*iface
, WCHAR
**path
)
2193 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2195 FIXME("(%p)->(%p) - stub\n", This
, path
);
2200 static HRESULT WINAPI
AudioSessionControl_SetIconPath(
2201 IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
2203 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2205 FIXME("(%p)->(%p, %s) - stub\n", This
, path
, debugstr_guid(session
));
2210 static HRESULT WINAPI
AudioSessionControl_GetGroupingParam(
2211 IAudioSessionControl2
*iface
, GUID
*group
)
2213 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2215 FIXME("(%p)->(%p) - stub\n", This
, group
);
2220 static HRESULT WINAPI
AudioSessionControl_SetGroupingParam(
2221 IAudioSessionControl2
*iface
, const GUID
*group
, const GUID
*session
)
2223 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2225 FIXME("(%p)->(%s, %s) - stub\n", This
, debugstr_guid(group
),
2226 debugstr_guid(session
));
2231 static HRESULT WINAPI
AudioSessionControl_RegisterAudioSessionNotification(
2232 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2234 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2236 FIXME("(%p)->(%p) - stub\n", This
, events
);
2241 static HRESULT WINAPI
AudioSessionControl_UnregisterAudioSessionNotification(
2242 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2244 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2246 FIXME("(%p)->(%p) - stub\n", This
, events
);
2251 static HRESULT WINAPI
AudioSessionControl_GetSessionIdentifier(
2252 IAudioSessionControl2
*iface
, WCHAR
**id
)
2254 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2256 FIXME("(%p)->(%p) - stub\n", This
, id
);
2261 static HRESULT WINAPI
AudioSessionControl_GetSessionInstanceIdentifier(
2262 IAudioSessionControl2
*iface
, WCHAR
**id
)
2264 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2266 FIXME("(%p)->(%p) - stub\n", This
, id
);
2271 static HRESULT WINAPI
AudioSessionControl_GetProcessId(
2272 IAudioSessionControl2
*iface
, DWORD
*pid
)
2274 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2276 TRACE("(%p)->(%p)\n", This
, pid
);
2281 *pid
= GetCurrentProcessId();
2286 static HRESULT WINAPI
AudioSessionControl_IsSystemSoundsSession(
2287 IAudioSessionControl2
*iface
)
2289 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2291 TRACE("(%p)\n", This
);
2296 static HRESULT WINAPI
AudioSessionControl_SetDuckingPreference(
2297 IAudioSessionControl2
*iface
, BOOL optout
)
2299 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2301 TRACE("(%p)->(%d)\n", This
, optout
);
2306 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
=
2308 AudioSessionControl_QueryInterface
,
2309 AudioSessionControl_AddRef
,
2310 AudioSessionControl_Release
,
2311 AudioSessionControl_GetState
,
2312 AudioSessionControl_GetDisplayName
,
2313 AudioSessionControl_SetDisplayName
,
2314 AudioSessionControl_GetIconPath
,
2315 AudioSessionControl_SetIconPath
,
2316 AudioSessionControl_GetGroupingParam
,
2317 AudioSessionControl_SetGroupingParam
,
2318 AudioSessionControl_RegisterAudioSessionNotification
,
2319 AudioSessionControl_UnregisterAudioSessionNotification
,
2320 AudioSessionControl_GetSessionIdentifier
,
2321 AudioSessionControl_GetSessionInstanceIdentifier
,
2322 AudioSessionControl_GetProcessId
,
2323 AudioSessionControl_IsSystemSoundsSession
,
2324 AudioSessionControl_SetDuckingPreference
2327 /* index == -1 means set all channels, otherwise sets only the given channel */
2328 static HRESULT
oss_setvol(ACImpl
*This
, UINT32 index
)
2335 if(index
== (UINT32
)-1){
2338 for(i
= 0; i
< This
->fmt
->nChannels
; ++i
){
2340 hr
= oss_setvol(This
, i
);
2348 /* OSS doesn't support volume control past the first two channels */
2351 if(This
->dataflow
== eRender
){
2352 setreq
= SNDCTL_DSP_SETPLAYVOL
;
2353 getreq
= SNDCTL_DSP_GETPLAYVOL
;
2354 }else if(This
->dataflow
== eCapture
){
2355 setreq
= SNDCTL_DSP_SETRECVOL
;
2356 getreq
= SNDCTL_DSP_GETRECVOL
;
2358 return E_UNEXPECTED
;
2360 if(ioctl(This
->fd
, getreq
, &vol
) < 0){
2362 /* device doesn't support this call */
2365 WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2369 level
= This
->session
->master_vol
* This
->session
->channel_vols
[index
] *
2373 vol
= l
| (vol
& 0xFF00);
2375 vol
= (vol
& 0xFF) | (l
<< 8);
2377 if(ioctl(This
->fd
, setreq
, &vol
) < 0){
2379 /* device doesn't support this call */
2382 WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2389 static HRESULT
oss_session_setvol(AudioSession
*session
, UINT32 index
)
2394 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2396 hr
= oss_setvol(client
, index
);
2404 static HRESULT WINAPI
SimpleAudioVolume_QueryInterface(
2405 ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
2407 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2413 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2414 IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
2417 IUnknown_AddRef((IUnknown
*)*ppv
);
2421 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2422 return E_NOINTERFACE
;
2425 static ULONG WINAPI
SimpleAudioVolume_AddRef(ISimpleAudioVolume
*iface
)
2427 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2428 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2431 static ULONG WINAPI
SimpleAudioVolume_Release(ISimpleAudioVolume
*iface
)
2433 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2434 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2437 static HRESULT WINAPI
SimpleAudioVolume_SetMasterVolume(
2438 ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
2440 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2441 AudioSession
*session
= This
->session
;
2444 TRACE("(%p)->(%f, %s)\n", session
, level
, wine_dbgstr_guid(context
));
2446 if(level
< 0.f
|| level
> 1.f
)
2447 return E_INVALIDARG
;
2450 FIXME("Notifications not supported yet\n");
2452 EnterCriticalSection(&session
->lock
);
2454 session
->master_vol
= level
;
2456 ret
= oss_session_setvol(session
, -1);
2458 LeaveCriticalSection(&session
->lock
);
2463 static HRESULT WINAPI
SimpleAudioVolume_GetMasterVolume(
2464 ISimpleAudioVolume
*iface
, float *level
)
2466 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2467 AudioSession
*session
= This
->session
;
2469 TRACE("(%p)->(%p)\n", session
, level
);
2472 return NULL_PTR_ERR
;
2474 *level
= session
->master_vol
;
2479 static HRESULT WINAPI
SimpleAudioVolume_SetMute(ISimpleAudioVolume
*iface
,
2480 BOOL mute
, const GUID
*context
)
2482 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2483 AudioSession
*session
= This
->session
;
2485 TRACE("(%p)->(%u, %p)\n", session
, mute
, context
);
2487 EnterCriticalSection(&session
->lock
);
2489 if(!mute
&& session
->mute
){
2492 session
->mute
= mute
;
2494 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2495 EnterCriticalSection(&client
->lock
);
2496 if(ioctl(client
->fd
, SNDCTL_DSP_SKIP
) < 0)
2497 WARN("Error calling DSP_SKIP: %d (%s)\n", errno
,
2499 oss_write_data(client
);
2500 LeaveCriticalSection(&client
->lock
);
2503 session
->mute
= mute
;
2505 LeaveCriticalSection(&session
->lock
);
2510 static HRESULT WINAPI
SimpleAudioVolume_GetMute(ISimpleAudioVolume
*iface
,
2513 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2514 AudioSession
*session
= This
->session
;
2516 TRACE("(%p)->(%p)\n", session
, mute
);
2519 return NULL_PTR_ERR
;
2521 *mute
= This
->session
->mute
;
2526 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
=
2528 SimpleAudioVolume_QueryInterface
,
2529 SimpleAudioVolume_AddRef
,
2530 SimpleAudioVolume_Release
,
2531 SimpleAudioVolume_SetMasterVolume
,
2532 SimpleAudioVolume_GetMasterVolume
,
2533 SimpleAudioVolume_SetMute
,
2534 SimpleAudioVolume_GetMute
2537 static HRESULT WINAPI
AudioStreamVolume_QueryInterface(
2538 IAudioStreamVolume
*iface
, REFIID riid
, void **ppv
)
2540 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2546 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2547 IsEqualIID(riid
, &IID_IAudioStreamVolume
))
2550 IUnknown_AddRef((IUnknown
*)*ppv
);
2554 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2555 return E_NOINTERFACE
;
2558 static ULONG WINAPI
AudioStreamVolume_AddRef(IAudioStreamVolume
*iface
)
2560 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2561 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2564 static ULONG WINAPI
AudioStreamVolume_Release(IAudioStreamVolume
*iface
)
2566 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2567 return IAudioClient_Release(&This
->IAudioClient_iface
);
2570 static HRESULT WINAPI
AudioStreamVolume_GetChannelCount(
2571 IAudioStreamVolume
*iface
, UINT32
*out
)
2573 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2575 TRACE("(%p)->(%p)\n", This
, out
);
2580 *out
= This
->fmt
->nChannels
;
2585 static HRESULT WINAPI
AudioStreamVolume_SetChannelVolume(
2586 IAudioStreamVolume
*iface
, UINT32 index
, float level
)
2588 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2591 TRACE("(%p)->(%d, %f)\n", This
, index
, level
);
2593 if(level
< 0.f
|| level
> 1.f
)
2594 return E_INVALIDARG
;
2596 if(index
>= This
->fmt
->nChannels
)
2597 return E_INVALIDARG
;
2599 EnterCriticalSection(&This
->lock
);
2601 This
->vols
[index
] = level
;
2603 ret
= oss_setvol(This
, index
);
2605 LeaveCriticalSection(&This
->lock
);
2610 static HRESULT WINAPI
AudioStreamVolume_GetChannelVolume(
2611 IAudioStreamVolume
*iface
, UINT32 index
, float *level
)
2613 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2615 TRACE("(%p)->(%d, %p)\n", This
, index
, level
);
2620 if(index
>= This
->fmt
->nChannels
)
2621 return E_INVALIDARG
;
2623 *level
= This
->vols
[index
];
2628 static HRESULT WINAPI
AudioStreamVolume_SetAllVolumes(
2629 IAudioStreamVolume
*iface
, UINT32 count
, const float *levels
)
2631 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2635 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2640 if(count
!= This
->fmt
->nChannels
)
2641 return E_INVALIDARG
;
2643 EnterCriticalSection(&This
->lock
);
2645 for(i
= 0; i
< count
; ++i
)
2646 This
->vols
[i
] = levels
[i
];
2648 ret
= oss_setvol(This
, -1);
2650 LeaveCriticalSection(&This
->lock
);
2655 static HRESULT WINAPI
AudioStreamVolume_GetAllVolumes(
2656 IAudioStreamVolume
*iface
, UINT32 count
, float *levels
)
2658 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2661 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2666 if(count
!= This
->fmt
->nChannels
)
2667 return E_INVALIDARG
;
2669 EnterCriticalSection(&This
->lock
);
2671 for(i
= 0; i
< count
; ++i
)
2672 levels
[i
] = This
->vols
[i
];
2674 LeaveCriticalSection(&This
->lock
);
2679 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
=
2681 AudioStreamVolume_QueryInterface
,
2682 AudioStreamVolume_AddRef
,
2683 AudioStreamVolume_Release
,
2684 AudioStreamVolume_GetChannelCount
,
2685 AudioStreamVolume_SetChannelVolume
,
2686 AudioStreamVolume_GetChannelVolume
,
2687 AudioStreamVolume_SetAllVolumes
,
2688 AudioStreamVolume_GetAllVolumes
2691 static HRESULT WINAPI
ChannelAudioVolume_QueryInterface(
2692 IChannelAudioVolume
*iface
, REFIID riid
, void **ppv
)
2694 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2700 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2701 IsEqualIID(riid
, &IID_IChannelAudioVolume
))
2704 IUnknown_AddRef((IUnknown
*)*ppv
);
2708 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2709 return E_NOINTERFACE
;
2712 static ULONG WINAPI
ChannelAudioVolume_AddRef(IChannelAudioVolume
*iface
)
2714 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2715 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2718 static ULONG WINAPI
ChannelAudioVolume_Release(IChannelAudioVolume
*iface
)
2720 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2721 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2724 static HRESULT WINAPI
ChannelAudioVolume_GetChannelCount(
2725 IChannelAudioVolume
*iface
, UINT32
*out
)
2727 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2728 AudioSession
*session
= This
->session
;
2730 TRACE("(%p)->(%p)\n", session
, out
);
2733 return NULL_PTR_ERR
;
2735 *out
= session
->channel_count
;
2740 static HRESULT WINAPI
ChannelAudioVolume_SetChannelVolume(
2741 IChannelAudioVolume
*iface
, UINT32 index
, float level
,
2742 const GUID
*context
)
2744 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2745 AudioSession
*session
= This
->session
;
2748 TRACE("(%p)->(%d, %f, %s)\n", session
, index
, level
,
2749 wine_dbgstr_guid(context
));
2751 if(level
< 0.f
|| level
> 1.f
)
2752 return E_INVALIDARG
;
2754 if(index
>= session
->channel_count
)
2755 return E_INVALIDARG
;
2758 FIXME("Notifications not supported yet\n");
2760 EnterCriticalSection(&session
->lock
);
2762 session
->channel_vols
[index
] = level
;
2764 ret
= oss_session_setvol(session
, index
);
2766 LeaveCriticalSection(&session
->lock
);
2771 static HRESULT WINAPI
ChannelAudioVolume_GetChannelVolume(
2772 IChannelAudioVolume
*iface
, UINT32 index
, float *level
)
2774 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2775 AudioSession
*session
= This
->session
;
2777 TRACE("(%p)->(%d, %p)\n", session
, index
, level
);
2780 return NULL_PTR_ERR
;
2782 if(index
>= session
->channel_count
)
2783 return E_INVALIDARG
;
2785 *level
= session
->channel_vols
[index
];
2790 static HRESULT WINAPI
ChannelAudioVolume_SetAllVolumes(
2791 IChannelAudioVolume
*iface
, UINT32 count
, const float *levels
,
2792 const GUID
*context
)
2794 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2795 AudioSession
*session
= This
->session
;
2799 TRACE("(%p)->(%d, %p, %s)\n", session
, count
, levels
,
2800 wine_dbgstr_guid(context
));
2803 return NULL_PTR_ERR
;
2805 if(count
!= session
->channel_count
)
2806 return E_INVALIDARG
;
2809 FIXME("Notifications not supported yet\n");
2811 EnterCriticalSection(&session
->lock
);
2813 for(i
= 0; i
< count
; ++i
)
2814 session
->channel_vols
[i
] = levels
[i
];
2816 ret
= oss_session_setvol(session
, -1);
2818 LeaveCriticalSection(&session
->lock
);
2823 static HRESULT WINAPI
ChannelAudioVolume_GetAllVolumes(
2824 IChannelAudioVolume
*iface
, UINT32 count
, float *levels
)
2826 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2827 AudioSession
*session
= This
->session
;
2830 TRACE("(%p)->(%d, %p)\n", session
, count
, levels
);
2833 return NULL_PTR_ERR
;
2835 if(count
!= session
->channel_count
)
2836 return E_INVALIDARG
;
2838 for(i
= 0; i
< count
; ++i
)
2839 levels
[i
] = session
->channel_vols
[i
];
2844 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
=
2846 ChannelAudioVolume_QueryInterface
,
2847 ChannelAudioVolume_AddRef
,
2848 ChannelAudioVolume_Release
,
2849 ChannelAudioVolume_GetChannelCount
,
2850 ChannelAudioVolume_SetChannelVolume
,
2851 ChannelAudioVolume_GetChannelVolume
,
2852 ChannelAudioVolume_SetAllVolumes
,
2853 ChannelAudioVolume_GetAllVolumes
2856 static HRESULT WINAPI
AudioSessionManager_QueryInterface(IAudioSessionManager2
*iface
,
2857 REFIID riid
, void **ppv
)
2859 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2865 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2866 IsEqualIID(riid
, &IID_IAudioSessionManager
) ||
2867 IsEqualIID(riid
, &IID_IAudioSessionManager2
))
2870 IUnknown_AddRef((IUnknown
*)*ppv
);
2874 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2875 return E_NOINTERFACE
;
2878 static ULONG WINAPI
AudioSessionManager_AddRef(IAudioSessionManager2
*iface
)
2880 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2882 ref
= InterlockedIncrement(&This
->ref
);
2883 TRACE("(%p) Refcount now %u\n", This
, ref
);
2887 static ULONG WINAPI
AudioSessionManager_Release(IAudioSessionManager2
*iface
)
2889 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2891 ref
= InterlockedDecrement(&This
->ref
);
2892 TRACE("(%p) Refcount now %u\n", This
, ref
);
2894 HeapFree(GetProcessHeap(), 0, This
);
2898 static HRESULT WINAPI
AudioSessionManager_GetAudioSessionControl(
2899 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2900 IAudioSessionControl
**out
)
2902 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2903 AudioSession
*session
;
2904 AudioSessionWrapper
*wrapper
;
2907 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2910 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2914 wrapper
= AudioSessionWrapper_Create(NULL
);
2916 return E_OUTOFMEMORY
;
2918 wrapper
->session
= session
;
2920 *out
= (IAudioSessionControl
*)&wrapper
->IAudioSessionControl2_iface
;
2925 static HRESULT WINAPI
AudioSessionManager_GetSimpleAudioVolume(
2926 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2927 ISimpleAudioVolume
**out
)
2929 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2930 AudioSession
*session
;
2931 AudioSessionWrapper
*wrapper
;
2934 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2937 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2941 wrapper
= AudioSessionWrapper_Create(NULL
);
2943 return E_OUTOFMEMORY
;
2945 wrapper
->session
= session
;
2947 *out
= &wrapper
->ISimpleAudioVolume_iface
;
2952 static HRESULT WINAPI
AudioSessionManager_GetSessionEnumerator(
2953 IAudioSessionManager2
*iface
, IAudioSessionEnumerator
**out
)
2955 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2956 FIXME("(%p)->(%p) - stub\n", This
, out
);
2960 static HRESULT WINAPI
AudioSessionManager_RegisterSessionNotification(
2961 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
2963 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2964 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2968 static HRESULT WINAPI
AudioSessionManager_UnregisterSessionNotification(
2969 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
2971 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2972 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2976 static HRESULT WINAPI
AudioSessionManager_RegisterDuckNotification(
2977 IAudioSessionManager2
*iface
, const WCHAR
*session_id
,
2978 IAudioVolumeDuckNotification
*notification
)
2980 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2981 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2985 static HRESULT WINAPI
AudioSessionManager_UnregisterDuckNotification(
2986 IAudioSessionManager2
*iface
,
2987 IAudioVolumeDuckNotification
*notification
)
2989 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2990 FIXME("(%p)->(%p) - stub\n", This
, notification
);
2994 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
=
2996 AudioSessionManager_QueryInterface
,
2997 AudioSessionManager_AddRef
,
2998 AudioSessionManager_Release
,
2999 AudioSessionManager_GetAudioSessionControl
,
3000 AudioSessionManager_GetSimpleAudioVolume
,
3001 AudioSessionManager_GetSessionEnumerator
,
3002 AudioSessionManager_RegisterSessionNotification
,
3003 AudioSessionManager_UnregisterSessionNotification
,
3004 AudioSessionManager_RegisterDuckNotification
,
3005 AudioSessionManager_UnregisterDuckNotification
3008 HRESULT WINAPI
AUDDRV_GetAudioSessionManager(IMMDevice
*device
,
3009 IAudioSessionManager2
**out
)
3013 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SessionMgr
));
3015 return E_OUTOFMEMORY
;
3017 This
->IAudioSessionManager2_iface
.lpVtbl
= &AudioSessionManager2_Vtbl
;
3018 This
->device
= device
;
3021 *out
= &This
->IAudioSessionManager2_iface
;