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"
52 #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
;
122 char devnode
[OSS_DEVNODE_SIZE
];
124 BOOL initted
, playing
;
125 UINT64 written_frames
;
126 UINT32 period_us
, bufsize_frames
, held_frames
, tmp_buffer_frames
, inbuf_frames
;
127 UINT32 lcl_offs_frames
; /* offs into local_buffer where valid data starts */
129 BYTE
*local_buffer
, *tmp_buffer
;
133 CRITICAL_SECTION lock
;
135 AudioSession
*session
;
136 AudioSessionWrapper
*session_wrapper
;
143 LOCKED_NORMAL
, /* public buffer piece is from local_buffer */
144 LOCKED_WRAPPED
/* public buffer piece is in tmp_buffer */
147 typedef struct _SessionMgr
{
148 IAudioSessionManager2 IAudioSessionManager2_iface
;
155 static HANDLE g_timer_q
;
157 static CRITICAL_SECTION g_sessions_lock
;
158 static struct list g_sessions
= LIST_INIT(g_sessions
);
160 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
);
161 static HRESULT
oss_setvol(ACImpl
*This
, UINT32 index
);
163 static const IAudioClientVtbl AudioClient_Vtbl
;
164 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
;
165 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
;
166 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
;
167 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
;
168 static const IAudioClockVtbl AudioClock_Vtbl
;
169 static const IAudioClock2Vtbl AudioClock2_Vtbl
;
170 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
;
171 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
;
172 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
;
174 static inline ACImpl
*impl_from_IAudioClient(IAudioClient
*iface
)
176 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClient_iface
);
179 static inline ACImpl
*impl_from_IAudioRenderClient(IAudioRenderClient
*iface
)
181 return CONTAINING_RECORD(iface
, ACImpl
, IAudioRenderClient_iface
);
184 static inline ACImpl
*impl_from_IAudioCaptureClient(IAudioCaptureClient
*iface
)
186 return CONTAINING_RECORD(iface
, ACImpl
, IAudioCaptureClient_iface
);
189 static inline AudioSessionWrapper
*impl_from_IAudioSessionControl2(IAudioSessionControl2
*iface
)
191 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IAudioSessionControl2_iface
);
194 static inline AudioSessionWrapper
*impl_from_ISimpleAudioVolume(ISimpleAudioVolume
*iface
)
196 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, ISimpleAudioVolume_iface
);
199 static inline AudioSessionWrapper
*impl_from_IChannelAudioVolume(IChannelAudioVolume
*iface
)
201 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IChannelAudioVolume_iface
);
204 static inline ACImpl
*impl_from_IAudioClock(IAudioClock
*iface
)
206 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock_iface
);
209 static inline ACImpl
*impl_from_IAudioClock2(IAudioClock2
*iface
)
211 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock2_iface
);
214 static inline ACImpl
*impl_from_IAudioStreamVolume(IAudioStreamVolume
*iface
)
216 return CONTAINING_RECORD(iface
, ACImpl
, IAudioStreamVolume_iface
);
219 static inline SessionMgr
*impl_from_IAudioSessionManager2(IAudioSessionManager2
*iface
)
221 return CONTAINING_RECORD(iface
, SessionMgr
, IAudioSessionManager2_iface
);
224 BOOL WINAPI
DllMain(HINSTANCE dll
, DWORD reason
, void *reserved
)
226 if(reason
== DLL_PROCESS_ATTACH
){
227 g_timer_q
= CreateTimerQueue();
231 InitializeCriticalSection(&g_sessions_lock
);
237 /* From <dlls/mmdevapi/mmdevapi.h> */
238 enum DriverPriority
{
239 Priority_Unavailable
= 0,
245 int WINAPI
AUDDRV_GetPriority(void)
250 /* Attempt to determine if we are running on OSS or ALSA's OSS
251 * compatibility layer. There is no official way to do that, so just check
252 * for validity as best as possible, without rejecting valid OSS
253 * implementations. */
255 mixer_fd
= open("/dev/mixer", O_RDONLY
, 0);
257 TRACE("Priority_Unavailable: open failed\n");
258 return Priority_Unavailable
;
261 sysinfo
.version
[0] = 0xFF;
262 sysinfo
.versionnum
= ~0;
263 if(ioctl(mixer_fd
, SNDCTL_SYSINFO
, &sysinfo
) < 0){
264 TRACE("Priority_Unavailable: ioctl failed\n");
266 return Priority_Unavailable
;
271 if(sysinfo
.version
[0] < '4' || sysinfo
.version
[0] > '9'){
272 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo
.version
[0]);
275 if(sysinfo
.versionnum
& 0x80000000){
276 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo
.versionnum
);
280 TRACE("Priority_Preferred: Seems like valid OSS!\n");
282 return Priority_Preferred
;
285 static const char *oss_clean_devnode(const char *devnode
)
287 static char ret
[OSS_DEVNODE_SIZE
];
289 const char *dot
, *slash
;
292 dot
= strrchr(devnode
, '.');
296 slash
= strrchr(devnode
, '/');
297 if(slash
&& dot
< slash
)
302 memcpy(ret
, devnode
, len
);
308 static UINT
get_default_index(EDataFlow flow
, char **keys
, UINT num
)
315 fd
= open("/dev/dsp", O_WRONLY
);
317 fd
= open("/dev/dsp", O_RDONLY
);
320 WARN("Couldn't open default device!\n");
325 if((err
= ioctl(fd
, SNDCTL_ENGINEINFO
, &ai
)) < 0){
326 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err
, strerror(errno
));
333 TRACE("Default devnode: %s\n", ai
.devnode
);
334 devnode
= oss_clean_devnode(ai
.devnode
);
335 for(i
= 0; i
< num
; ++i
)
336 if(!strcmp(devnode
, keys
[i
]))
339 WARN("Couldn't find default device! Choosing first.\n");
343 HRESULT WINAPI
AUDDRV_GetEndpointIDs(EDataFlow flow
, WCHAR
***ids
, char ***keys
,
344 UINT
*num
, UINT
*def_index
)
348 static int print_once
= 0;
350 TRACE("%d %p %p %p\n", flow
, ids
, num
, def_index
);
352 mixer_fd
= open("/dev/mixer", O_RDONLY
, 0);
354 ERR("OSS /dev/mixer doesn't seem to exist\n");
355 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
358 if(ioctl(mixer_fd
, SNDCTL_SYSINFO
, &sysinfo
) < 0){
362 ERR("OSS version too old, need at least OSSv4\n");
363 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
366 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno
, strerror(errno
));
371 TRACE("OSS sysinfo:\n");
372 TRACE("product: %s\n", sysinfo
.product
);
373 TRACE("version: %s\n", sysinfo
.version
);
374 TRACE("versionnum: %x\n", sysinfo
.versionnum
);
375 TRACE("numaudios: %d\n", sysinfo
.numaudios
);
376 TRACE("nummixers: %d\n", sysinfo
.nummixers
);
377 TRACE("numcards: %d\n", sysinfo
.numcards
);
378 TRACE("numaudioengines: %d\n", sysinfo
.numaudioengines
);
382 if(sysinfo
.numaudios
<= 0){
383 WARN("No audio devices!\n");
385 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
388 *ids
= HeapAlloc(GetProcessHeap(), 0, sysinfo
.numaudios
* sizeof(WCHAR
*));
389 *keys
= HeapAlloc(GetProcessHeap(), 0, sysinfo
.numaudios
* sizeof(char *));
392 for(i
= 0; i
< sysinfo
.numaudios
; ++i
){
393 oss_audioinfo ai
= {0};
398 if(ioctl(mixer_fd
, SNDCTL_AUDIOINFO
, &ai
) < 0){
399 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i
, errno
,
404 devnode
= oss_clean_devnode(ai
.devnode
);
406 /* check for duplicates */
407 for(j
= 0; j
< *num
; ++j
)
408 if(!strcmp(devnode
, (*keys
)[j
]))
414 fd
= open(devnode
, O_WRONLY
, 0);
416 fd
= open(devnode
, O_RDONLY
, 0);
418 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
419 devnode
, errno
, strerror(errno
));
424 if((flow
== eCapture
&& (ai
.caps
& PCM_CAP_INPUT
)) ||
425 (flow
== eRender
&& (ai
.caps
& PCM_CAP_OUTPUT
))){
428 (*keys
)[*num
] = HeapAlloc(GetProcessHeap(), 0,
429 strlen(devnode
) + 1);
431 for(i
= 0; i
< *num
; ++i
){
432 HeapFree(GetProcessHeap(), 0, (*ids
)[i
]);
433 HeapFree(GetProcessHeap(), 0, (*keys
)[i
]);
435 HeapFree(GetProcessHeap(), 0, *ids
);
436 HeapFree(GetProcessHeap(), 0, *keys
);
438 return E_OUTOFMEMORY
;
440 strcpy((*keys
)[*num
], devnode
);
442 len
= MultiByteToWideChar(CP_UNIXCP
, 0, ai
.name
, -1, NULL
, 0);
443 (*ids
)[*num
] = HeapAlloc(GetProcessHeap(), 0,
444 len
* sizeof(WCHAR
));
446 HeapFree(GetProcessHeap(), 0, (*keys
)[*num
]);
447 for(i
= 0; i
< *num
; ++i
){
448 HeapFree(GetProcessHeap(), 0, (*ids
)[i
]);
449 HeapFree(GetProcessHeap(), 0, (*keys
)[i
]);
451 HeapFree(GetProcessHeap(), 0, *ids
);
452 HeapFree(GetProcessHeap(), 0, *keys
);
454 return E_OUTOFMEMORY
;
456 MultiByteToWideChar(CP_UNIXCP
, 0, ai
.name
, -1,
465 *def_index
= get_default_index(flow
, *keys
, *num
);
470 HRESULT WINAPI
AUDDRV_GetAudioEndpoint(char *devnode
, IMMDevice
*dev
,
471 EDataFlow dataflow
, IAudioClient
**out
)
475 TRACE("%s %p %d %p\n", devnode
, dev
, dataflow
, out
);
477 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ACImpl
));
479 return E_OUTOFMEMORY
;
481 if(dataflow
== eRender
)
482 This
->fd
= open(devnode
, O_WRONLY
, 0);
483 else if(dataflow
== eCapture
)
484 This
->fd
= open(devnode
, O_RDONLY
, 0);
486 HeapFree(GetProcessHeap(), 0, This
);
490 ERR("Unable to open device %s: %d (%s)\n", devnode
, errno
,
492 HeapFree(GetProcessHeap(), 0, This
);
493 return AUDCLNT_E_DEVICE_INVALIDATED
;
496 This
->dataflow
= dataflow
;
499 if(ioctl(This
->fd
, SNDCTL_ENGINEINFO
, &This
->ai
) < 0){
500 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode
,
501 errno
, strerror(errno
));
503 HeapFree(GetProcessHeap(), 0, This
);
507 strcpy(This
->devnode
, devnode
);
509 TRACE("OSS audioinfo:\n");
510 TRACE("devnode: %s\n", This
->ai
.devnode
);
511 TRACE("name: %s\n", This
->ai
.name
);
512 TRACE("busy: %x\n", This
->ai
.busy
);
513 TRACE("caps: %x\n", This
->ai
.caps
);
514 TRACE("iformats: %x\n", This
->ai
.iformats
);
515 TRACE("oformats: %x\n", This
->ai
.oformats
);
516 TRACE("enabled: %d\n", This
->ai
.enabled
);
517 TRACE("min_rate: %d\n", This
->ai
.min_rate
);
518 TRACE("max_rate: %d\n", This
->ai
.max_rate
);
519 TRACE("min_channels: %d\n", This
->ai
.min_channels
);
520 TRACE("max_channels: %d\n", This
->ai
.max_channels
);
522 This
->IAudioClient_iface
.lpVtbl
= &AudioClient_Vtbl
;
523 This
->IAudioRenderClient_iface
.lpVtbl
= &AudioRenderClient_Vtbl
;
524 This
->IAudioCaptureClient_iface
.lpVtbl
= &AudioCaptureClient_Vtbl
;
525 This
->IAudioClock_iface
.lpVtbl
= &AudioClock_Vtbl
;
526 This
->IAudioClock2_iface
.lpVtbl
= &AudioClock2_Vtbl
;
527 This
->IAudioStreamVolume_iface
.lpVtbl
= &AudioStreamVolume_Vtbl
;
529 InitializeCriticalSection(&This
->lock
);
532 IMMDevice_AddRef(This
->parent
);
534 IAudioClient_AddRef(&This
->IAudioClient_iface
);
536 *out
= &This
->IAudioClient_iface
;
541 static HRESULT WINAPI
AudioClient_QueryInterface(IAudioClient
*iface
,
542 REFIID riid
, void **ppv
)
544 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
549 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClient
))
552 IUnknown_AddRef((IUnknown
*)*ppv
);
555 WARN("Unknown interface %s\n", debugstr_guid(riid
));
556 return E_NOINTERFACE
;
559 static ULONG WINAPI
AudioClient_AddRef(IAudioClient
*iface
)
561 ACImpl
*This
= impl_from_IAudioClient(iface
);
563 ref
= InterlockedIncrement(&This
->ref
);
564 TRACE("(%p) Refcount now %u\n", This
, ref
);
568 static ULONG WINAPI
AudioClient_Release(IAudioClient
*iface
)
570 ACImpl
*This
= impl_from_IAudioClient(iface
);
572 ref
= InterlockedDecrement(&This
->ref
);
573 TRACE("(%p) Refcount now %u\n", This
, ref
);
575 IAudioClient_Stop(iface
);
576 IMMDevice_Release(This
->parent
);
577 DeleteCriticalSection(&This
->lock
);
580 EnterCriticalSection(&g_sessions_lock
);
581 list_remove(&This
->entry
);
582 LeaveCriticalSection(&g_sessions_lock
);
584 HeapFree(GetProcessHeap(), 0, This
->vols
);
585 HeapFree(GetProcessHeap(), 0, This
->local_buffer
);
586 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
587 CoTaskMemFree(This
->fmt
);
588 HeapFree(GetProcessHeap(), 0, This
);
593 static void dump_fmt(const WAVEFORMATEX
*fmt
)
595 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
596 switch(fmt
->wFormatTag
){
597 case WAVE_FORMAT_PCM
:
598 TRACE("WAVE_FORMAT_PCM");
600 case WAVE_FORMAT_IEEE_FLOAT
:
601 TRACE("WAVE_FORMAT_IEEE_FLOAT");
603 case WAVE_FORMAT_EXTENSIBLE
:
604 TRACE("WAVE_FORMAT_EXTENSIBLE");
612 TRACE("nChannels: %u\n", fmt
->nChannels
);
613 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
614 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
615 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
616 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
617 TRACE("cbSize: %u\n", fmt
->cbSize
);
619 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
620 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
621 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
622 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
623 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
627 static DWORD
get_channel_mask(unsigned int channels
)
633 return KSAUDIO_SPEAKER_MONO
;
635 return KSAUDIO_SPEAKER_STEREO
;
637 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
639 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
641 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
643 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
645 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
647 return KSAUDIO_SPEAKER_7POINT1
; /* not 7POINT1_SURROUND */
649 FIXME("Unknown speaker configuration: %u\n", channels
);
653 static int get_oss_format(const WAVEFORMATEX
*fmt
)
655 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)fmt
;
657 if(fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
658 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
659 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
660 switch(fmt
->wBitsPerSample
){
674 if(fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
675 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
676 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
677 if(fmt
->wBitsPerSample
!= 32)
687 static WAVEFORMATEX
*clone_format(const WAVEFORMATEX
*fmt
)
692 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
693 size
= sizeof(WAVEFORMATEXTENSIBLE
);
695 size
= sizeof(WAVEFORMATEX
);
697 ret
= CoTaskMemAlloc(size
);
701 memcpy(ret
, fmt
, size
);
703 ret
->cbSize
= size
- sizeof(WAVEFORMATEX
);
708 static HRESULT
setup_oss_device(int fd
, const WAVEFORMATEX
*fmt
,
709 WAVEFORMATEX
**out
, BOOL query
)
714 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
715 WAVEFORMATEX
*closest
= NULL
;
720 tmp
= oss_format
= get_oss_format(fmt
);
722 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
723 if(ioctl(fd
, SNDCTL_DSP_SETFMT
, &tmp
) < 0){
724 WARN("SETFMT failed: %d (%s)\n", errno
, strerror(errno
));
727 if(tmp
!= oss_format
){
728 TRACE("Format unsupported by this OSS version: %x\n", oss_format
);
729 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
732 closest
= clone_format(fmt
);
734 return E_OUTOFMEMORY
;
736 tmp
= fmt
->nSamplesPerSec
;
737 if(ioctl(fd
, SNDCTL_DSP_SPEED
, &tmp
) < 0){
738 WARN("SPEED failed: %d (%s)\n", errno
, strerror(errno
));
739 CoTaskMemFree(closest
);
742 tenth
= fmt
->nSamplesPerSec
* 0.1;
743 if(tmp
> fmt
->nSamplesPerSec
+ tenth
|| tmp
< fmt
->nSamplesPerSec
- tenth
){
745 closest
->nSamplesPerSec
= tmp
;
748 tmp
= fmt
->nChannels
;
749 if(ioctl(fd
, SNDCTL_DSP_CHANNELS
, &tmp
) < 0){
750 WARN("CHANNELS failed: %d (%s)\n", errno
, strerror(errno
));
751 CoTaskMemFree(closest
);
754 if(tmp
!= fmt
->nChannels
){
756 closest
->nChannels
= tmp
;
759 if(closest
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
760 DWORD mask
= get_channel_mask(closest
->nChannels
);
762 ((WAVEFORMATEXTENSIBLE
*)closest
)->dwChannelMask
= mask
;
764 if(query
&& fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
765 fmtex
->dwChannelMask
!= 0 &&
766 fmtex
->dwChannelMask
!= mask
)
770 if(ret
== S_FALSE
&& out
){
771 closest
->nBlockAlign
=
772 closest
->nChannels
* closest
->wBitsPerSample
/ 8;
773 closest
->nAvgBytesPerSec
=
774 closest
->nBlockAlign
* closest
->nSamplesPerSec
;
777 CoTaskMemFree(closest
);
779 TRACE("returning: %08x\n", ret
);
783 static void session_init_vols(AudioSession
*session
, UINT channels
)
785 if(session
->channel_count
< channels
){
788 if(session
->channel_vols
)
789 session
->channel_vols
= HeapReAlloc(GetProcessHeap(), 0,
790 session
->channel_vols
, sizeof(float) * channels
);
792 session
->channel_vols
= HeapAlloc(GetProcessHeap(), 0,
793 sizeof(float) * channels
);
794 if(!session
->channel_vols
)
797 for(i
= session
->channel_count
; i
< channels
; ++i
)
798 session
->channel_vols
[i
] = 1.f
;
800 session
->channel_count
= channels
;
804 static AudioSession
*create_session(const GUID
*guid
, IMMDevice
*device
,
809 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AudioSession
));
813 memcpy(&ret
->guid
, guid
, sizeof(GUID
));
815 ret
->device
= device
;
817 list_init(&ret
->clients
);
819 list_add_head(&g_sessions
, &ret
->entry
);
821 InitializeCriticalSection(&ret
->lock
);
823 session_init_vols(ret
, num_channels
);
825 ret
->master_vol
= 1.f
;
830 /* if channels == 0, then this will return or create a session with
831 * matching dataflow and GUID. otherwise, channels must also match */
832 static HRESULT
get_audio_session(const GUID
*sessionguid
,
833 IMMDevice
*device
, UINT channels
, AudioSession
**out
)
835 AudioSession
*session
;
837 if(!sessionguid
|| IsEqualGUID(sessionguid
, &GUID_NULL
)){
838 *out
= create_session(&GUID_NULL
, device
, channels
);
840 return E_OUTOFMEMORY
;
846 LIST_FOR_EACH_ENTRY(session
, &g_sessions
, AudioSession
, entry
){
847 if(session
->device
== device
&&
848 IsEqualGUID(sessionguid
, &session
->guid
)){
849 session_init_vols(session
, channels
);
856 *out
= create_session(sessionguid
, device
, channels
);
858 return E_OUTOFMEMORY
;
864 static HRESULT WINAPI
AudioClient_Initialize(IAudioClient
*iface
,
865 AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
,
866 REFERENCE_TIME period
, const WAVEFORMATEX
*fmt
,
867 const GUID
*sessionguid
)
869 ACImpl
*This
= impl_from_IAudioClient(iface
);
873 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This
, mode
, flags
,
874 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(period
), fmt
, debugstr_guid(sessionguid
));
881 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
882 return AUDCLNT_E_NOT_INITIALIZED
;
884 if(flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
|
885 AUDCLNT_STREAMFLAGS_LOOPBACK
|
886 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
887 AUDCLNT_STREAMFLAGS_NOPERSIST
|
888 AUDCLNT_STREAMFLAGS_RATEADJUST
|
889 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
|
890 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
|
891 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
)){
892 TRACE("Unknown flags: %08x\n", flags
);
896 EnterCriticalSection(&This
->lock
);
899 LeaveCriticalSection(&This
->lock
);
900 return AUDCLNT_E_ALREADY_INITIALIZED
;
903 hr
= setup_oss_device(This
->fd
, fmt
, NULL
, FALSE
);
905 LeaveCriticalSection(&This
->lock
);
906 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
909 LeaveCriticalSection(&This
->lock
);
914 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
915 LeaveCriticalSection(&This
->lock
);
916 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
920 mask
= (100 << 8) | 100;
921 if(ioctl(This
->fd
, SNDCTL_DSP_SETPLAYVOL
, &mask
) < 0)
922 WARN("SETPLAYVOL failed: %d (%s)\n", errno
, strerror(errno
));
924 This
->fmt
= clone_format(fmt
);
926 LeaveCriticalSection(&This
->lock
);
927 return E_OUTOFMEMORY
;
931 This
->period_us
= period
/ 10;
933 This
->period_us
= DefaultPeriod
/ 10;
936 duration
= 300000; /* 0.03s */
937 This
->bufsize_frames
= ceil(fmt
->nSamplesPerSec
* (duration
/ 10000000.));
938 This
->local_buffer
= HeapAlloc(GetProcessHeap(), 0,
939 This
->bufsize_frames
* fmt
->nBlockAlign
);
940 if(!This
->local_buffer
){
941 CoTaskMemFree(This
->fmt
);
943 LeaveCriticalSection(&This
->lock
);
944 return E_OUTOFMEMORY
;
947 This
->vols
= HeapAlloc(GetProcessHeap(), 0, fmt
->nChannels
* sizeof(float));
949 CoTaskMemFree(This
->fmt
);
951 LeaveCriticalSection(&This
->lock
);
952 return E_OUTOFMEMORY
;
955 for(i
= 0; i
< fmt
->nChannels
; ++i
)
961 EnterCriticalSection(&g_sessions_lock
);
963 hr
= get_audio_session(sessionguid
, This
->parent
, fmt
->nChannels
,
966 LeaveCriticalSection(&g_sessions_lock
);
967 HeapFree(GetProcessHeap(), 0, This
->vols
);
969 CoTaskMemFree(This
->fmt
);
971 LeaveCriticalSection(&This
->lock
);
975 list_add_tail(&This
->session
->clients
, &This
->entry
);
977 LeaveCriticalSection(&g_sessions_lock
);
979 This
->initted
= TRUE
;
981 oss_setvol(This
, -1);
983 LeaveCriticalSection(&This
->lock
);
988 static HRESULT WINAPI
AudioClient_GetBufferSize(IAudioClient
*iface
,
991 ACImpl
*This
= impl_from_IAudioClient(iface
);
993 TRACE("(%p)->(%p)\n", This
, frames
);
998 EnterCriticalSection(&This
->lock
);
1001 LeaveCriticalSection(&This
->lock
);
1002 return AUDCLNT_E_NOT_INITIALIZED
;
1005 *frames
= This
->bufsize_frames
;
1007 LeaveCriticalSection(&This
->lock
);
1012 static HRESULT WINAPI
AudioClient_GetStreamLatency(IAudioClient
*iface
,
1013 REFERENCE_TIME
*latency
)
1015 ACImpl
*This
= impl_from_IAudioClient(iface
);
1017 TRACE("(%p)->(%p)\n", This
, latency
);
1022 EnterCriticalSection(&This
->lock
);
1025 LeaveCriticalSection(&This
->lock
);
1026 return AUDCLNT_E_NOT_INITIALIZED
;
1029 if(This
->dataflow
== eRender
){
1033 if(ioctl(This
->fd
, SNDCTL_DSP_GETODELAY
, &delay_bytes
) < 0){
1034 LeaveCriticalSection(&This
->lock
);
1035 WARN("GETODELAY failed: %d (%s)\n", errno
, strerror(errno
));
1039 delay_s
= delay_bytes
/ (double)(This
->fmt
->nSamplesPerSec
*
1040 This
->fmt
->nBlockAlign
);
1042 *latency
= delay_s
* 10000000;
1044 *latency
= 10000; /* OSS doesn't provide input latency */
1046 LeaveCriticalSection(&This
->lock
);
1051 static HRESULT WINAPI
AudioClient_GetCurrentPadding(IAudioClient
*iface
,
1054 ACImpl
*This
= impl_from_IAudioClient(iface
);
1057 TRACE("(%p)->(%p)\n", This
, numpad
);
1062 EnterCriticalSection(&This
->lock
);
1065 LeaveCriticalSection(&This
->lock
);
1066 return AUDCLNT_E_NOT_INITIALIZED
;
1069 if(This
->dataflow
== eRender
){
1070 if(ioctl(This
->fd
, SNDCTL_DSP_GETOSPACE
, &bi
) < 0){
1071 LeaveCriticalSection(&This
->lock
);
1072 WARN("GETOSPACE failed: %d (%s)\n", errno
, strerror(errno
));
1076 *numpad
= (bi
.fragstotal
* bi
.fragsize
- bi
.bytes
) /
1077 This
->fmt
->nBlockAlign
;
1079 /* when the OSS buffer has less than one fragment of data, including
1080 * no data, it often reports it as some non-zero portion of a
1081 * fragment. when it has more than one fragment of data, it reports
1082 * it as some multiple of that portion of the fragment size.
1084 * so, we have to do some ugly workarounds to report the timing
1085 * as accurately as possible */
1086 if(*numpad
< bi
.fragsize
/ This
->fmt
->nBlockAlign
){
1087 *numpad
= This
->inbuf_frames
;
1088 This
->inbuf_frames
= 0;
1090 if(*numpad
< This
->inbuf_frames
)
1091 This
->inbuf_frames
= *numpad
;
1093 *numpad
= This
->inbuf_frames
;
1095 }else if(This
->dataflow
== eCapture
){
1096 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
1097 LeaveCriticalSection(&This
->lock
);
1098 WARN("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
1102 if(bi
.bytes
<= bi
.fragsize
)
1105 *numpad
= bi
.bytes
/ This
->fmt
->nBlockAlign
;
1107 LeaveCriticalSection(&This
->lock
);
1108 return E_UNEXPECTED
;
1111 *numpad
+= This
->held_frames
;
1113 LeaveCriticalSection(&This
->lock
);
1118 static HRESULT WINAPI
AudioClient_IsFormatSupported(IAudioClient
*iface
,
1119 AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
,
1120 WAVEFORMATEX
**outpwfx
)
1122 ACImpl
*This
= impl_from_IAudioClient(iface
);
1126 TRACE("(%p)->(%x, %p, %p)\n", This
, mode
, pwfx
, outpwfx
);
1128 if(!pwfx
|| (mode
== AUDCLNT_SHAREMODE_SHARED
&& !outpwfx
))
1131 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
1132 return E_INVALIDARG
;
1134 if(pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1135 pwfx
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
))
1136 return E_INVALIDARG
;
1140 if(This
->dataflow
== eRender
)
1141 fd
= open(This
->devnode
, O_WRONLY
, 0);
1142 else if(This
->dataflow
== eCapture
)
1143 fd
= open(This
->devnode
, O_RDONLY
, 0);
1146 ERR("Unable to open device %s: %d (%s)\n", This
->devnode
, errno
,
1148 return AUDCLNT_E_DEVICE_INVALIDATED
;
1151 ret
= setup_oss_device(fd
, pwfx
, outpwfx
, TRUE
);
1158 static HRESULT WINAPI
AudioClient_GetMixFormat(IAudioClient
*iface
,
1159 WAVEFORMATEX
**pwfx
)
1161 ACImpl
*This
= impl_from_IAudioClient(iface
);
1162 WAVEFORMATEXTENSIBLE
*fmt
;
1165 TRACE("(%p)->(%p)\n", This
, pwfx
);
1171 if(This
->dataflow
== eRender
)
1172 formats
= This
->ai
.oformats
;
1173 else if(This
->dataflow
== eCapture
)
1174 formats
= This
->ai
.iformats
;
1176 return E_UNEXPECTED
;
1178 fmt
= CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE
));
1180 return E_OUTOFMEMORY
;
1182 fmt
->Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
1183 if(formats
& AFMT_S16_LE
){
1184 fmt
->Format
.wBitsPerSample
= 16;
1185 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1187 }else if(formats
& AFMT_FLOAT
){
1188 fmt
->Format
.wBitsPerSample
= 32;
1189 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
1191 }else if(formats
& AFMT_U8
){
1192 fmt
->Format
.wBitsPerSample
= 8;
1193 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1194 }else if(formats
& AFMT_S32_LE
){
1195 fmt
->Format
.wBitsPerSample
= 32;
1196 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1197 }else if(formats
& AFMT_S24_LE
){
1198 fmt
->Format
.wBitsPerSample
= 24;
1199 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1201 ERR("Didn't recognize any available OSS formats: %x\n", formats
);
1206 fmt
->Format
.nChannels
= This
->ai
.max_channels
;
1207 fmt
->Format
.nSamplesPerSec
= This
->ai
.max_rate
;
1208 fmt
->dwChannelMask
= get_channel_mask(fmt
->Format
.nChannels
);
1210 fmt
->Format
.nBlockAlign
= (fmt
->Format
.wBitsPerSample
*
1211 fmt
->Format
.nChannels
) / 8;
1212 fmt
->Format
.nAvgBytesPerSec
= fmt
->Format
.nSamplesPerSec
*
1213 fmt
->Format
.nBlockAlign
;
1215 fmt
->Samples
.wValidBitsPerSample
= fmt
->Format
.wBitsPerSample
;
1216 fmt
->Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
1218 *pwfx
= (WAVEFORMATEX
*)fmt
;
1224 static HRESULT WINAPI
AudioClient_GetDevicePeriod(IAudioClient
*iface
,
1225 REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
1227 ACImpl
*This
= impl_from_IAudioClient(iface
);
1229 TRACE("(%p)->(%p, %p)\n", This
, defperiod
, minperiod
);
1231 if(!defperiod
&& !minperiod
)
1234 EnterCriticalSection(&This
->lock
);
1237 *defperiod
= DefaultPeriod
;
1239 *minperiod
= MinimumPeriod
;
1241 LeaveCriticalSection(&This
->lock
);
1246 static void oss_silence_buffer(ACImpl
*This
, BYTE
*buf
, UINT32 frames
)
1248 if(This
->fmt
->wBitsPerSample
== 8)
1249 memset(buf
, 128, frames
* This
->fmt
->nBlockAlign
);
1251 memset(buf
, 0, frames
* This
->fmt
->nBlockAlign
);
1254 static void oss_write_data(ACImpl
*This
)
1257 UINT32 written_frames
;
1260 This
->local_buffer
+ (This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
);
1262 if(This
->lcl_offs_frames
+ This
->held_frames
> This
->bufsize_frames
)
1263 to_write
= This
->bufsize_frames
- This
->lcl_offs_frames
;
1265 to_write
= This
->held_frames
;
1267 if(This
->session
->mute
)
1268 oss_silence_buffer(This
, buf
, to_write
);
1270 written
= write(This
->fd
, buf
, to_write
* This
->fmt
->nBlockAlign
);
1272 /* EAGAIN is OSS buffer full, log that too */
1273 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1276 written_frames
= written
/ This
->fmt
->nBlockAlign
;
1278 This
->lcl_offs_frames
+= written_frames
;
1279 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1280 This
->held_frames
-= written_frames
;
1281 This
->inbuf_frames
+= written_frames
;
1283 if(written_frames
< to_write
){
1284 /* OSS buffer probably full */
1288 if(This
->held_frames
){
1289 /* wrapped and have some data back at the start to write */
1291 if(This
->session
->mute
)
1292 oss_silence_buffer(This
, This
->local_buffer
, This
->held_frames
);
1294 written
= write(This
->fd
, This
->local_buffer
,
1295 This
->held_frames
* This
->fmt
->nBlockAlign
);
1297 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1300 written_frames
= written
/ This
->fmt
->nBlockAlign
;
1302 This
->lcl_offs_frames
+= written_frames
;
1303 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1304 This
->held_frames
-= written_frames
;
1305 This
->inbuf_frames
+= written_frames
;
1309 static void oss_read_data(ACImpl
*This
)
1311 UINT64 pos
, readable
;
1315 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
1316 WARN("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
1320 pos
= (This
->held_frames
+ This
->lcl_offs_frames
) % This
->bufsize_frames
;
1321 readable
= (This
->bufsize_frames
- pos
) * This
->fmt
->nBlockAlign
;
1323 if(bi
.bytes
< readable
)
1324 readable
= bi
.bytes
;
1326 nread
= read(This
->fd
, This
->local_buffer
+ pos
* This
->fmt
->nBlockAlign
,
1329 WARN("read failed: %d (%s)\n", errno
, strerror(errno
));
1333 This
->held_frames
+= nread
/ This
->fmt
->nBlockAlign
;
1335 if(This
->held_frames
> This
->bufsize_frames
){
1336 WARN("Overflow of unread data\n");
1337 This
->lcl_offs_frames
+= This
->held_frames
;
1338 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1339 This
->held_frames
= This
->bufsize_frames
;
1343 static void CALLBACK
oss_period_callback(void *user
, BOOLEAN timer
)
1345 ACImpl
*This
= user
;
1347 EnterCriticalSection(&This
->lock
);
1349 if(This
->dataflow
== eRender
&& This
->held_frames
)
1350 oss_write_data(This
);
1351 else if(This
->dataflow
== eCapture
)
1352 oss_read_data(This
);
1355 SetEvent(This
->event
);
1357 LeaveCriticalSection(&This
->lock
);
1360 static HRESULT WINAPI
AudioClient_Start(IAudioClient
*iface
)
1362 ACImpl
*This
= impl_from_IAudioClient(iface
);
1365 TRACE("(%p)\n", This
);
1367 EnterCriticalSection(&This
->lock
);
1370 LeaveCriticalSection(&This
->lock
);
1371 return AUDCLNT_E_NOT_INITIALIZED
;
1374 if((This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !This
->event
){
1375 LeaveCriticalSection(&This
->lock
);
1376 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1380 LeaveCriticalSection(&This
->lock
);
1381 return AUDCLNT_E_NOT_STOPPED
;
1384 if(This
->dataflow
== eRender
)
1385 mask
= PCM_ENABLE_OUTPUT
;
1386 else if(This
->dataflow
== eCapture
)
1387 mask
= PCM_ENABLE_INPUT
;
1389 LeaveCriticalSection(&This
->lock
);
1390 return E_UNEXPECTED
;
1393 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1394 LeaveCriticalSection(&This
->lock
);
1395 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1399 if(!CreateTimerQueueTimer(&This
->timer
, g_timer_q
,
1400 oss_period_callback
, This
, 0, This
->period_us
/ 1000,
1401 WT_EXECUTEINTIMERTHREAD
))
1402 ERR("Unable to create period timer: %u\n", GetLastError());
1404 This
->playing
= TRUE
;
1406 LeaveCriticalSection(&This
->lock
);
1411 static HRESULT WINAPI
AudioClient_Stop(IAudioClient
*iface
)
1413 ACImpl
*This
= impl_from_IAudioClient(iface
);
1416 TRACE("(%p)\n", This
);
1418 EnterCriticalSection(&This
->lock
);
1421 LeaveCriticalSection(&This
->lock
);
1422 return AUDCLNT_E_NOT_INITIALIZED
;
1426 LeaveCriticalSection(&This
->lock
);
1430 if(This
->timer
&& This
->timer
!= INVALID_HANDLE_VALUE
){
1431 DeleteTimerQueueTimer(g_timer_q
, This
->timer
,
1432 INVALID_HANDLE_VALUE
);
1436 if(ioctl(This
->fd
, SNDCTL_DSP_HALT
, NULL
) < 0){
1437 LeaveCriticalSection(&This
->lock
);
1438 WARN("HALT failed: %d (%s)\n", errno
, strerror(errno
));
1443 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1444 LeaveCriticalSection(&This
->lock
);
1445 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1449 This
->playing
= FALSE
;
1451 LeaveCriticalSection(&This
->lock
);
1456 static HRESULT WINAPI
AudioClient_Reset(IAudioClient
*iface
)
1458 ACImpl
*This
= impl_from_IAudioClient(iface
);
1460 TRACE("(%p)\n", This
);
1462 EnterCriticalSection(&This
->lock
);
1465 LeaveCriticalSection(&This
->lock
);
1466 return AUDCLNT_E_NOT_INITIALIZED
;
1470 LeaveCriticalSection(&This
->lock
);
1471 return AUDCLNT_E_NOT_STOPPED
;
1474 if(This
->buf_state
!= NOT_LOCKED
){
1475 LeaveCriticalSection(&This
->lock
);
1476 return AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1479 This
->written_frames
= 0;
1480 This
->inbuf_frames
= 0;
1481 This
->held_frames
= 0;
1483 if(ioctl(This
->fd
, SNDCTL_DSP_SKIP
, NULL
) < 0)
1484 WARN("SKIP failed: %d (%s)\n", errno
, strerror(errno
));
1486 LeaveCriticalSection(&This
->lock
);
1491 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient
*iface
,
1494 ACImpl
*This
= impl_from_IAudioClient(iface
);
1496 TRACE("(%p)->(%p)\n", This
, event
);
1499 return E_INVALIDARG
;
1501 EnterCriticalSection(&This
->lock
);
1504 LeaveCriticalSection(&This
->lock
);
1505 return AUDCLNT_E_NOT_INITIALIZED
;
1508 if(!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
)){
1509 LeaveCriticalSection(&This
->lock
);
1510 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1513 This
->event
= event
;
1515 LeaveCriticalSection(&This
->lock
);
1520 static HRESULT WINAPI
AudioClient_GetService(IAudioClient
*iface
, REFIID riid
,
1523 ACImpl
*This
= impl_from_IAudioClient(iface
);
1525 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1531 EnterCriticalSection(&This
->lock
);
1534 LeaveCriticalSection(&This
->lock
);
1535 return AUDCLNT_E_NOT_INITIALIZED
;
1538 if(IsEqualIID(riid
, &IID_IAudioRenderClient
)){
1539 if(This
->dataflow
!= eRender
){
1540 LeaveCriticalSection(&This
->lock
);
1541 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1543 IAudioRenderClient_AddRef(&This
->IAudioRenderClient_iface
);
1544 *ppv
= &This
->IAudioRenderClient_iface
;
1545 }else if(IsEqualIID(riid
, &IID_IAudioCaptureClient
)){
1546 if(This
->dataflow
!= eCapture
){
1547 LeaveCriticalSection(&This
->lock
);
1548 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1550 IAudioCaptureClient_AddRef(&This
->IAudioCaptureClient_iface
);
1551 *ppv
= &This
->IAudioCaptureClient_iface
;
1552 }else if(IsEqualIID(riid
, &IID_IAudioClock
)){
1553 IAudioClock_AddRef(&This
->IAudioClock_iface
);
1554 *ppv
= &This
->IAudioClock_iface
;
1555 }else if(IsEqualIID(riid
, &IID_IAudioStreamVolume
)){
1556 IAudioStreamVolume_AddRef(&This
->IAudioStreamVolume_iface
);
1557 *ppv
= &This
->IAudioStreamVolume_iface
;
1558 }else if(IsEqualIID(riid
, &IID_IAudioSessionControl
)){
1559 if(!This
->session_wrapper
){
1560 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1561 if(!This
->session_wrapper
){
1562 LeaveCriticalSection(&This
->lock
);
1563 return E_OUTOFMEMORY
;
1566 IAudioSessionControl2_AddRef(&This
->session_wrapper
->IAudioSessionControl2_iface
);
1568 *ppv
= &This
->session_wrapper
->IAudioSessionControl2_iface
;
1569 }else if(IsEqualIID(riid
, &IID_IChannelAudioVolume
)){
1570 if(!This
->session_wrapper
){
1571 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1572 if(!This
->session_wrapper
){
1573 LeaveCriticalSection(&This
->lock
);
1574 return E_OUTOFMEMORY
;
1577 IChannelAudioVolume_AddRef(&This
->session_wrapper
->IChannelAudioVolume_iface
);
1579 *ppv
= &This
->session_wrapper
->IChannelAudioVolume_iface
;
1580 }else if(IsEqualIID(riid
, &IID_ISimpleAudioVolume
)){
1581 if(!This
->session_wrapper
){
1582 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1583 if(!This
->session_wrapper
){
1584 LeaveCriticalSection(&This
->lock
);
1585 return E_OUTOFMEMORY
;
1588 ISimpleAudioVolume_AddRef(&This
->session_wrapper
->ISimpleAudioVolume_iface
);
1590 *ppv
= &This
->session_wrapper
->ISimpleAudioVolume_iface
;
1594 LeaveCriticalSection(&This
->lock
);
1598 LeaveCriticalSection(&This
->lock
);
1600 FIXME("stub %s\n", debugstr_guid(riid
));
1601 return E_NOINTERFACE
;
1604 static const IAudioClientVtbl AudioClient_Vtbl
=
1606 AudioClient_QueryInterface
,
1608 AudioClient_Release
,
1609 AudioClient_Initialize
,
1610 AudioClient_GetBufferSize
,
1611 AudioClient_GetStreamLatency
,
1612 AudioClient_GetCurrentPadding
,
1613 AudioClient_IsFormatSupported
,
1614 AudioClient_GetMixFormat
,
1615 AudioClient_GetDevicePeriod
,
1619 AudioClient_SetEventHandle
,
1620 AudioClient_GetService
1623 static HRESULT WINAPI
AudioRenderClient_QueryInterface(
1624 IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1626 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1632 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1633 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1636 IUnknown_AddRef((IUnknown
*)*ppv
);
1640 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1641 return E_NOINTERFACE
;
1644 static ULONG WINAPI
AudioRenderClient_AddRef(IAudioRenderClient
*iface
)
1646 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1647 return AudioClient_AddRef(&This
->IAudioClient_iface
);
1650 static ULONG WINAPI
AudioRenderClient_Release(IAudioRenderClient
*iface
)
1652 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1653 return AudioClient_Release(&This
->IAudioClient_iface
);
1656 static HRESULT WINAPI
AudioRenderClient_GetBuffer(IAudioRenderClient
*iface
,
1657 UINT32 frames
, BYTE
**data
)
1659 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1660 UINT32 pad
, write_pos
;
1663 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
1668 EnterCriticalSection(&This
->lock
);
1670 if(This
->buf_state
!= NOT_LOCKED
){
1671 LeaveCriticalSection(&This
->lock
);
1672 return AUDCLNT_E_OUT_OF_ORDER
;
1676 This
->buf_state
= LOCKED_NORMAL
;
1677 LeaveCriticalSection(&This
->lock
);
1681 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
1683 LeaveCriticalSection(&This
->lock
);
1687 if(pad
+ frames
> This
->bufsize_frames
){
1688 LeaveCriticalSection(&This
->lock
);
1689 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1693 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1694 if(write_pos
+ frames
> This
->bufsize_frames
){
1695 if(This
->tmp_buffer_frames
< frames
){
1696 if(This
->tmp_buffer
)
1697 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1698 This
->tmp_buffer
, frames
* This
->fmt
->nBlockAlign
);
1700 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1701 frames
* This
->fmt
->nBlockAlign
);
1702 if(!This
->tmp_buffer
){
1703 LeaveCriticalSection(&This
->lock
);
1704 return E_OUTOFMEMORY
;
1706 This
->tmp_buffer_frames
= frames
;
1708 *data
= This
->tmp_buffer
;
1709 This
->buf_state
= LOCKED_WRAPPED
;
1711 *data
= This
->local_buffer
+ write_pos
* This
->fmt
->nBlockAlign
;
1712 This
->buf_state
= LOCKED_NORMAL
;
1715 LeaveCriticalSection(&This
->lock
);
1720 static void oss_wrap_buffer(ACImpl
*This
, BYTE
*buffer
, UINT32 written_frames
)
1722 UINT32 write_offs_frames
=
1723 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1724 UINT32 write_offs_bytes
= write_offs_frames
* This
->fmt
->nBlockAlign
;
1725 UINT32 chunk_frames
= This
->bufsize_frames
- write_offs_frames
;
1726 UINT32 chunk_bytes
= chunk_frames
* This
->fmt
->nBlockAlign
;
1727 UINT32 written_bytes
= written_frames
* This
->fmt
->nBlockAlign
;
1729 if(written_bytes
<= chunk_bytes
){
1730 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, written_bytes
);
1732 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, chunk_bytes
);
1733 memcpy(This
->local_buffer
, buffer
+ chunk_bytes
,
1734 written_bytes
- chunk_bytes
);
1738 static HRESULT WINAPI
AudioRenderClient_ReleaseBuffer(
1739 IAudioRenderClient
*iface
, UINT32 written_frames
, DWORD flags
)
1741 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1744 TRACE("(%p)->(%u, %x)\n", This
, written_frames
, flags
);
1746 EnterCriticalSection(&This
->lock
);
1748 if(This
->buf_state
== NOT_LOCKED
|| !written_frames
){
1749 This
->buf_state
= NOT_LOCKED
;
1750 LeaveCriticalSection(&This
->lock
);
1751 return written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1754 if(This
->buf_state
== LOCKED_NORMAL
)
1755 buffer
= This
->local_buffer
+ This
->fmt
->nBlockAlign
*
1756 ((This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
);
1758 buffer
= This
->tmp_buffer
;
1760 if(flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1761 oss_silence_buffer(This
, buffer
, written_frames
);
1763 if(This
->held_frames
){
1764 if(This
->buf_state
== LOCKED_WRAPPED
)
1765 oss_wrap_buffer(This
, buffer
, written_frames
);
1767 This
->held_frames
+= written_frames
;
1772 if(This
->session
->mute
)
1773 oss_silence_buffer(This
, buffer
, written_frames
);
1775 w_bytes
= write(This
->fd
, buffer
,
1776 written_frames
* This
->fmt
->nBlockAlign
);
1778 if(errno
!= EAGAIN
){
1779 This
->buf_state
= NOT_LOCKED
;
1780 LeaveCriticalSection(&This
->lock
);
1781 ERR("write failed: %d (%s)\n", errno
, strerror(errno
));
1783 }else /* OSS buffer full */
1786 w_frames
= w_bytes
/ This
->fmt
->nBlockAlign
;
1787 This
->inbuf_frames
+= w_frames
;
1789 if(w_frames
< written_frames
){
1790 if(This
->buf_state
== LOCKED_WRAPPED
)
1791 oss_wrap_buffer(This
, This
->tmp_buffer
+ w_bytes
,
1792 written_frames
- w_frames
);
1794 This
->lcl_offs_frames
+= w_frames
;
1795 This
->held_frames
= written_frames
- w_frames
;
1799 This
->written_frames
+= written_frames
;
1800 This
->buf_state
= NOT_LOCKED
;
1802 LeaveCriticalSection(&This
->lock
);
1807 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
1808 AudioRenderClient_QueryInterface
,
1809 AudioRenderClient_AddRef
,
1810 AudioRenderClient_Release
,
1811 AudioRenderClient_GetBuffer
,
1812 AudioRenderClient_ReleaseBuffer
1815 static HRESULT WINAPI
AudioCaptureClient_QueryInterface(
1816 IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1818 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1824 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1825 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1828 IUnknown_AddRef((IUnknown
*)*ppv
);
1832 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1833 return E_NOINTERFACE
;
1836 static ULONG WINAPI
AudioCaptureClient_AddRef(IAudioCaptureClient
*iface
)
1838 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1839 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1842 static ULONG WINAPI
AudioCaptureClient_Release(IAudioCaptureClient
*iface
)
1844 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1845 return IAudioClient_Release(&This
->IAudioClient_iface
);
1848 static HRESULT WINAPI
AudioCaptureClient_GetBuffer(IAudioCaptureClient
*iface
,
1849 BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
,
1852 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1855 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
1858 if(!data
|| !frames
|| !flags
)
1861 EnterCriticalSection(&This
->lock
);
1863 if(This
->buf_state
!= NOT_LOCKED
){
1864 LeaveCriticalSection(&This
->lock
);
1865 return AUDCLNT_E_OUT_OF_ORDER
;
1868 hr
= IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1870 LeaveCriticalSection(&This
->lock
);
1876 if(This
->lcl_offs_frames
+ *frames
> This
->bufsize_frames
){
1877 UINT32 chunk_bytes
, offs_bytes
, frames_bytes
;
1878 if(This
->tmp_buffer_frames
< *frames
){
1879 if(This
->tmp_buffer
)
1880 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1881 This
->tmp_buffer
, *frames
* This
->fmt
->nBlockAlign
);
1883 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1884 *frames
* This
->fmt
->nBlockAlign
);
1885 if(!This
->tmp_buffer
){
1886 LeaveCriticalSection(&This
->lock
);
1887 return E_OUTOFMEMORY
;
1889 This
->tmp_buffer_frames
= *frames
;
1892 *data
= This
->tmp_buffer
;
1893 chunk_bytes
= (This
->bufsize_frames
- This
->lcl_offs_frames
) *
1894 This
->fmt
->nBlockAlign
;
1895 offs_bytes
= This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1896 frames_bytes
= *frames
* This
->fmt
->nBlockAlign
;
1897 memcpy(This
->tmp_buffer
, This
->local_buffer
+ offs_bytes
, chunk_bytes
);
1898 memcpy(This
->tmp_buffer
, This
->local_buffer
,
1899 frames_bytes
- chunk_bytes
);
1901 *data
= This
->local_buffer
+
1902 This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1904 This
->buf_state
= LOCKED_NORMAL
;
1906 if(devpos
|| qpcpos
)
1907 IAudioClock_GetPosition(&This
->IAudioClock_iface
, devpos
, qpcpos
);
1909 LeaveCriticalSection(&This
->lock
);
1911 return *frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
1914 static HRESULT WINAPI
AudioCaptureClient_ReleaseBuffer(
1915 IAudioCaptureClient
*iface
, UINT32 done
)
1917 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1919 TRACE("(%p)->(%u)\n", This
, done
);
1921 EnterCriticalSection(&This
->lock
);
1923 if(This
->buf_state
== NOT_LOCKED
){
1924 LeaveCriticalSection(&This
->lock
);
1925 return AUDCLNT_E_OUT_OF_ORDER
;
1928 This
->held_frames
-= done
;
1929 This
->lcl_offs_frames
+= done
;
1930 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1932 This
->buf_state
= NOT_LOCKED
;
1934 LeaveCriticalSection(&This
->lock
);
1939 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
1940 IAudioCaptureClient
*iface
, UINT32
*frames
)
1942 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1944 TRACE("(%p)->(%p)\n", This
, frames
);
1946 return AudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, frames
);
1949 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
1951 AudioCaptureClient_QueryInterface
,
1952 AudioCaptureClient_AddRef
,
1953 AudioCaptureClient_Release
,
1954 AudioCaptureClient_GetBuffer
,
1955 AudioCaptureClient_ReleaseBuffer
,
1956 AudioCaptureClient_GetNextPacketSize
1959 static HRESULT WINAPI
AudioClock_QueryInterface(IAudioClock
*iface
,
1960 REFIID riid
, void **ppv
)
1962 ACImpl
*This
= impl_from_IAudioClock(iface
);
1964 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1970 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClock
))
1972 else if(IsEqualIID(riid
, &IID_IAudioClock2
))
1973 *ppv
= &This
->IAudioClock2_iface
;
1975 IUnknown_AddRef((IUnknown
*)*ppv
);
1979 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1980 return E_NOINTERFACE
;
1983 static ULONG WINAPI
AudioClock_AddRef(IAudioClock
*iface
)
1985 ACImpl
*This
= impl_from_IAudioClock(iface
);
1986 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1989 static ULONG WINAPI
AudioClock_Release(IAudioClock
*iface
)
1991 ACImpl
*This
= impl_from_IAudioClock(iface
);
1992 return IAudioClient_Release(&This
->IAudioClient_iface
);
1995 static HRESULT WINAPI
AudioClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
1997 ACImpl
*This
= impl_from_IAudioClock(iface
);
1999 TRACE("(%p)->(%p)\n", This
, freq
);
2001 *freq
= This
->fmt
->nSamplesPerSec
;
2006 static HRESULT WINAPI
AudioClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
,
2009 ACImpl
*This
= impl_from_IAudioClock(iface
);
2013 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
2018 EnterCriticalSection(&This
->lock
);
2020 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
2022 LeaveCriticalSection(&This
->lock
);
2026 if(This
->dataflow
== eRender
)
2027 *pos
= This
->written_frames
- pad
;
2028 else if(This
->dataflow
== eCapture
)
2029 *pos
= This
->written_frames
+ pad
;
2031 LeaveCriticalSection(&This
->lock
);
2034 LARGE_INTEGER stamp
, freq
;
2035 QueryPerformanceCounter(&stamp
);
2036 QueryPerformanceFrequency(&freq
);
2037 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
2043 static HRESULT WINAPI
AudioClock_GetCharacteristics(IAudioClock
*iface
,
2046 ACImpl
*This
= impl_from_IAudioClock(iface
);
2048 TRACE("(%p)->(%p)\n", This
, chars
);
2053 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
2058 static const IAudioClockVtbl AudioClock_Vtbl
=
2060 AudioClock_QueryInterface
,
2063 AudioClock_GetFrequency
,
2064 AudioClock_GetPosition
,
2065 AudioClock_GetCharacteristics
2068 static HRESULT WINAPI
AudioClock2_QueryInterface(IAudioClock2
*iface
,
2069 REFIID riid
, void **ppv
)
2071 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2072 return IAudioClock_QueryInterface(&This
->IAudioClock_iface
, riid
, ppv
);
2075 static ULONG WINAPI
AudioClock2_AddRef(IAudioClock2
*iface
)
2077 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2078 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2081 static ULONG WINAPI
AudioClock2_Release(IAudioClock2
*iface
)
2083 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2084 return IAudioClient_Release(&This
->IAudioClient_iface
);
2087 static HRESULT WINAPI
AudioClock2_GetDevicePosition(IAudioClock2
*iface
,
2088 UINT64
*pos
, UINT64
*qpctime
)
2090 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2092 FIXME("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
2097 static const IAudioClock2Vtbl AudioClock2_Vtbl
=
2099 AudioClock2_QueryInterface
,
2101 AudioClock2_Release
,
2102 AudioClock2_GetDevicePosition
2105 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
)
2107 AudioSessionWrapper
*ret
;
2109 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2110 sizeof(AudioSessionWrapper
));
2114 ret
->IAudioSessionControl2_iface
.lpVtbl
= &AudioSessionControl2_Vtbl
;
2115 ret
->ISimpleAudioVolume_iface
.lpVtbl
= &SimpleAudioVolume_Vtbl
;
2116 ret
->IChannelAudioVolume_iface
.lpVtbl
= &ChannelAudioVolume_Vtbl
;
2120 ret
->client
= client
;
2122 ret
->session
= client
->session
;
2123 AudioClient_AddRef(&client
->IAudioClient_iface
);
2129 static HRESULT WINAPI
AudioSessionControl_QueryInterface(
2130 IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
2132 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2138 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2139 IsEqualIID(riid
, &IID_IAudioSessionControl
) ||
2140 IsEqualIID(riid
, &IID_IAudioSessionControl2
))
2143 IUnknown_AddRef((IUnknown
*)*ppv
);
2147 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2148 return E_NOINTERFACE
;
2151 static ULONG WINAPI
AudioSessionControl_AddRef(IAudioSessionControl2
*iface
)
2153 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2155 ref
= InterlockedIncrement(&This
->ref
);
2156 TRACE("(%p) Refcount now %u\n", This
, ref
);
2160 static ULONG WINAPI
AudioSessionControl_Release(IAudioSessionControl2
*iface
)
2162 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2164 ref
= InterlockedDecrement(&This
->ref
);
2165 TRACE("(%p) Refcount now %u\n", This
, ref
);
2168 EnterCriticalSection(&This
->client
->lock
);
2169 This
->client
->session_wrapper
= NULL
;
2170 LeaveCriticalSection(&This
->client
->lock
);
2171 AudioClient_Release(&This
->client
->IAudioClient_iface
);
2173 HeapFree(GetProcessHeap(), 0, This
);
2178 static HRESULT WINAPI
AudioSessionControl_GetState(IAudioSessionControl2
*iface
,
2179 AudioSessionState
*state
)
2181 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2184 TRACE("(%p)->(%p)\n", This
, state
);
2187 return NULL_PTR_ERR
;
2189 EnterCriticalSection(&g_sessions_lock
);
2191 if(list_empty(&This
->session
->clients
)){
2192 *state
= AudioSessionStateExpired
;
2193 LeaveCriticalSection(&g_sessions_lock
);
2197 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
){
2198 EnterCriticalSection(&client
->lock
);
2199 if(client
->playing
){
2200 *state
= AudioSessionStateActive
;
2201 LeaveCriticalSection(&client
->lock
);
2202 LeaveCriticalSection(&g_sessions_lock
);
2205 LeaveCriticalSection(&client
->lock
);
2208 LeaveCriticalSection(&g_sessions_lock
);
2210 *state
= AudioSessionStateInactive
;
2215 static HRESULT WINAPI
AudioSessionControl_GetDisplayName(
2216 IAudioSessionControl2
*iface
, WCHAR
**name
)
2218 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2220 FIXME("(%p)->(%p) - stub\n", This
, name
);
2225 static HRESULT WINAPI
AudioSessionControl_SetDisplayName(
2226 IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
2228 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2230 FIXME("(%p)->(%p, %s) - stub\n", This
, name
, debugstr_guid(session
));
2235 static HRESULT WINAPI
AudioSessionControl_GetIconPath(
2236 IAudioSessionControl2
*iface
, WCHAR
**path
)
2238 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2240 FIXME("(%p)->(%p) - stub\n", This
, path
);
2245 static HRESULT WINAPI
AudioSessionControl_SetIconPath(
2246 IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
2248 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2250 FIXME("(%p)->(%p, %s) - stub\n", This
, path
, debugstr_guid(session
));
2255 static HRESULT WINAPI
AudioSessionControl_GetGroupingParam(
2256 IAudioSessionControl2
*iface
, GUID
*group
)
2258 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2260 FIXME("(%p)->(%p) - stub\n", This
, group
);
2265 static HRESULT WINAPI
AudioSessionControl_SetGroupingParam(
2266 IAudioSessionControl2
*iface
, const GUID
*group
, const GUID
*session
)
2268 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2270 FIXME("(%p)->(%s, %s) - stub\n", This
, debugstr_guid(group
),
2271 debugstr_guid(session
));
2276 static HRESULT WINAPI
AudioSessionControl_RegisterAudioSessionNotification(
2277 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2279 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2281 FIXME("(%p)->(%p) - stub\n", This
, events
);
2286 static HRESULT WINAPI
AudioSessionControl_UnregisterAudioSessionNotification(
2287 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2289 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2291 FIXME("(%p)->(%p) - stub\n", This
, events
);
2296 static HRESULT WINAPI
AudioSessionControl_GetSessionIdentifier(
2297 IAudioSessionControl2
*iface
, WCHAR
**id
)
2299 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2301 FIXME("(%p)->(%p) - stub\n", This
, id
);
2306 static HRESULT WINAPI
AudioSessionControl_GetSessionInstanceIdentifier(
2307 IAudioSessionControl2
*iface
, WCHAR
**id
)
2309 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2311 FIXME("(%p)->(%p) - stub\n", This
, id
);
2316 static HRESULT WINAPI
AudioSessionControl_GetProcessId(
2317 IAudioSessionControl2
*iface
, DWORD
*pid
)
2319 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2321 TRACE("(%p)->(%p)\n", This
, pid
);
2326 *pid
= GetCurrentProcessId();
2331 static HRESULT WINAPI
AudioSessionControl_IsSystemSoundsSession(
2332 IAudioSessionControl2
*iface
)
2334 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2336 TRACE("(%p)\n", This
);
2341 static HRESULT WINAPI
AudioSessionControl_SetDuckingPreference(
2342 IAudioSessionControl2
*iface
, BOOL optout
)
2344 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2346 TRACE("(%p)->(%d)\n", This
, optout
);
2351 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
=
2353 AudioSessionControl_QueryInterface
,
2354 AudioSessionControl_AddRef
,
2355 AudioSessionControl_Release
,
2356 AudioSessionControl_GetState
,
2357 AudioSessionControl_GetDisplayName
,
2358 AudioSessionControl_SetDisplayName
,
2359 AudioSessionControl_GetIconPath
,
2360 AudioSessionControl_SetIconPath
,
2361 AudioSessionControl_GetGroupingParam
,
2362 AudioSessionControl_SetGroupingParam
,
2363 AudioSessionControl_RegisterAudioSessionNotification
,
2364 AudioSessionControl_UnregisterAudioSessionNotification
,
2365 AudioSessionControl_GetSessionIdentifier
,
2366 AudioSessionControl_GetSessionInstanceIdentifier
,
2367 AudioSessionControl_GetProcessId
,
2368 AudioSessionControl_IsSystemSoundsSession
,
2369 AudioSessionControl_SetDuckingPreference
2372 /* index == -1 means set all channels, otherwise sets only the given channel */
2373 static HRESULT
oss_setvol(ACImpl
*This
, UINT32 index
)
2380 if(index
== (UINT32
)-1){
2383 for(i
= 0; i
< This
->fmt
->nChannels
; ++i
){
2385 hr
= oss_setvol(This
, i
);
2393 /* OSS doesn't support volume control past the first two channels */
2396 if(This
->dataflow
== eRender
){
2397 setreq
= SNDCTL_DSP_SETPLAYVOL
;
2398 getreq
= SNDCTL_DSP_GETPLAYVOL
;
2399 }else if(This
->dataflow
== eCapture
){
2400 setreq
= SNDCTL_DSP_SETRECVOL
;
2401 getreq
= SNDCTL_DSP_GETRECVOL
;
2403 return E_UNEXPECTED
;
2405 if(ioctl(This
->fd
, getreq
, &vol
) < 0){
2407 /* device doesn't support this call */
2410 WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2414 level
= This
->session
->master_vol
* This
->session
->channel_vols
[index
] *
2418 vol
= l
| (vol
& 0xFF00);
2420 vol
= (vol
& 0xFF) | (l
<< 8);
2422 if(ioctl(This
->fd
, setreq
, &vol
) < 0){
2424 /* device doesn't support this call */
2427 WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2434 static HRESULT
oss_session_setvol(AudioSession
*session
, UINT32 index
)
2439 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2441 hr
= oss_setvol(client
, index
);
2449 static HRESULT WINAPI
SimpleAudioVolume_QueryInterface(
2450 ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
2452 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2458 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2459 IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
2462 IUnknown_AddRef((IUnknown
*)*ppv
);
2466 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2467 return E_NOINTERFACE
;
2470 static ULONG WINAPI
SimpleAudioVolume_AddRef(ISimpleAudioVolume
*iface
)
2472 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2473 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2476 static ULONG WINAPI
SimpleAudioVolume_Release(ISimpleAudioVolume
*iface
)
2478 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2479 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2482 static HRESULT WINAPI
SimpleAudioVolume_SetMasterVolume(
2483 ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
2485 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2486 AudioSession
*session
= This
->session
;
2489 TRACE("(%p)->(%f, %s)\n", session
, level
, wine_dbgstr_guid(context
));
2491 if(level
< 0.f
|| level
> 1.f
)
2492 return E_INVALIDARG
;
2495 FIXME("Notifications not supported yet\n");
2497 EnterCriticalSection(&session
->lock
);
2499 session
->master_vol
= level
;
2501 ret
= oss_session_setvol(session
, -1);
2503 LeaveCriticalSection(&session
->lock
);
2508 static HRESULT WINAPI
SimpleAudioVolume_GetMasterVolume(
2509 ISimpleAudioVolume
*iface
, float *level
)
2511 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2512 AudioSession
*session
= This
->session
;
2514 TRACE("(%p)->(%p)\n", session
, level
);
2517 return NULL_PTR_ERR
;
2519 *level
= session
->master_vol
;
2524 static HRESULT WINAPI
SimpleAudioVolume_SetMute(ISimpleAudioVolume
*iface
,
2525 BOOL mute
, const GUID
*context
)
2527 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2528 AudioSession
*session
= This
->session
;
2530 TRACE("(%p)->(%u, %p)\n", session
, mute
, context
);
2532 EnterCriticalSection(&session
->lock
);
2534 if(!mute
&& session
->mute
){
2537 session
->mute
= mute
;
2539 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2540 EnterCriticalSection(&client
->lock
);
2541 if(ioctl(client
->fd
, SNDCTL_DSP_SKIP
) < 0)
2542 WARN("Error calling DSP_SKIP: %d (%s)\n", errno
,
2544 oss_write_data(client
);
2545 LeaveCriticalSection(&client
->lock
);
2548 session
->mute
= mute
;
2550 LeaveCriticalSection(&session
->lock
);
2555 static HRESULT WINAPI
SimpleAudioVolume_GetMute(ISimpleAudioVolume
*iface
,
2558 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2559 AudioSession
*session
= This
->session
;
2561 TRACE("(%p)->(%p)\n", session
, mute
);
2564 return NULL_PTR_ERR
;
2566 *mute
= This
->session
->mute
;
2571 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
=
2573 SimpleAudioVolume_QueryInterface
,
2574 SimpleAudioVolume_AddRef
,
2575 SimpleAudioVolume_Release
,
2576 SimpleAudioVolume_SetMasterVolume
,
2577 SimpleAudioVolume_GetMasterVolume
,
2578 SimpleAudioVolume_SetMute
,
2579 SimpleAudioVolume_GetMute
2582 static HRESULT WINAPI
AudioStreamVolume_QueryInterface(
2583 IAudioStreamVolume
*iface
, REFIID riid
, void **ppv
)
2585 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2591 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2592 IsEqualIID(riid
, &IID_IAudioStreamVolume
))
2595 IUnknown_AddRef((IUnknown
*)*ppv
);
2599 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2600 return E_NOINTERFACE
;
2603 static ULONG WINAPI
AudioStreamVolume_AddRef(IAudioStreamVolume
*iface
)
2605 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2606 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2609 static ULONG WINAPI
AudioStreamVolume_Release(IAudioStreamVolume
*iface
)
2611 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2612 return IAudioClient_Release(&This
->IAudioClient_iface
);
2615 static HRESULT WINAPI
AudioStreamVolume_GetChannelCount(
2616 IAudioStreamVolume
*iface
, UINT32
*out
)
2618 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2620 TRACE("(%p)->(%p)\n", This
, out
);
2625 *out
= This
->fmt
->nChannels
;
2630 static HRESULT WINAPI
AudioStreamVolume_SetChannelVolume(
2631 IAudioStreamVolume
*iface
, UINT32 index
, float level
)
2633 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2636 TRACE("(%p)->(%d, %f)\n", This
, index
, level
);
2638 if(level
< 0.f
|| level
> 1.f
)
2639 return E_INVALIDARG
;
2641 if(index
>= This
->fmt
->nChannels
)
2642 return E_INVALIDARG
;
2644 EnterCriticalSection(&This
->lock
);
2646 This
->vols
[index
] = level
;
2648 ret
= oss_setvol(This
, index
);
2650 LeaveCriticalSection(&This
->lock
);
2655 static HRESULT WINAPI
AudioStreamVolume_GetChannelVolume(
2656 IAudioStreamVolume
*iface
, UINT32 index
, float *level
)
2658 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2660 TRACE("(%p)->(%d, %p)\n", This
, index
, level
);
2665 if(index
>= This
->fmt
->nChannels
)
2666 return E_INVALIDARG
;
2668 *level
= This
->vols
[index
];
2673 static HRESULT WINAPI
AudioStreamVolume_SetAllVolumes(
2674 IAudioStreamVolume
*iface
, UINT32 count
, const float *levels
)
2676 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2680 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2685 if(count
!= This
->fmt
->nChannels
)
2686 return E_INVALIDARG
;
2688 EnterCriticalSection(&This
->lock
);
2690 for(i
= 0; i
< count
; ++i
)
2691 This
->vols
[i
] = levels
[i
];
2693 ret
= oss_setvol(This
, -1);
2695 LeaveCriticalSection(&This
->lock
);
2700 static HRESULT WINAPI
AudioStreamVolume_GetAllVolumes(
2701 IAudioStreamVolume
*iface
, UINT32 count
, float *levels
)
2703 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2706 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2711 if(count
!= This
->fmt
->nChannels
)
2712 return E_INVALIDARG
;
2714 EnterCriticalSection(&This
->lock
);
2716 for(i
= 0; i
< count
; ++i
)
2717 levels
[i
] = This
->vols
[i
];
2719 LeaveCriticalSection(&This
->lock
);
2724 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
=
2726 AudioStreamVolume_QueryInterface
,
2727 AudioStreamVolume_AddRef
,
2728 AudioStreamVolume_Release
,
2729 AudioStreamVolume_GetChannelCount
,
2730 AudioStreamVolume_SetChannelVolume
,
2731 AudioStreamVolume_GetChannelVolume
,
2732 AudioStreamVolume_SetAllVolumes
,
2733 AudioStreamVolume_GetAllVolumes
2736 static HRESULT WINAPI
ChannelAudioVolume_QueryInterface(
2737 IChannelAudioVolume
*iface
, REFIID riid
, void **ppv
)
2739 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2745 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2746 IsEqualIID(riid
, &IID_IChannelAudioVolume
))
2749 IUnknown_AddRef((IUnknown
*)*ppv
);
2753 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2754 return E_NOINTERFACE
;
2757 static ULONG WINAPI
ChannelAudioVolume_AddRef(IChannelAudioVolume
*iface
)
2759 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2760 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2763 static ULONG WINAPI
ChannelAudioVolume_Release(IChannelAudioVolume
*iface
)
2765 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2766 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2769 static HRESULT WINAPI
ChannelAudioVolume_GetChannelCount(
2770 IChannelAudioVolume
*iface
, UINT32
*out
)
2772 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2773 AudioSession
*session
= This
->session
;
2775 TRACE("(%p)->(%p)\n", session
, out
);
2778 return NULL_PTR_ERR
;
2780 *out
= session
->channel_count
;
2785 static HRESULT WINAPI
ChannelAudioVolume_SetChannelVolume(
2786 IChannelAudioVolume
*iface
, UINT32 index
, float level
,
2787 const GUID
*context
)
2789 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2790 AudioSession
*session
= This
->session
;
2793 TRACE("(%p)->(%d, %f, %s)\n", session
, index
, level
,
2794 wine_dbgstr_guid(context
));
2796 if(level
< 0.f
|| level
> 1.f
)
2797 return E_INVALIDARG
;
2799 if(index
>= session
->channel_count
)
2800 return E_INVALIDARG
;
2803 FIXME("Notifications not supported yet\n");
2805 EnterCriticalSection(&session
->lock
);
2807 session
->channel_vols
[index
] = level
;
2809 ret
= oss_session_setvol(session
, index
);
2811 LeaveCriticalSection(&session
->lock
);
2816 static HRESULT WINAPI
ChannelAudioVolume_GetChannelVolume(
2817 IChannelAudioVolume
*iface
, UINT32 index
, float *level
)
2819 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2820 AudioSession
*session
= This
->session
;
2822 TRACE("(%p)->(%d, %p)\n", session
, index
, level
);
2825 return NULL_PTR_ERR
;
2827 if(index
>= session
->channel_count
)
2828 return E_INVALIDARG
;
2830 *level
= session
->channel_vols
[index
];
2835 static HRESULT WINAPI
ChannelAudioVolume_SetAllVolumes(
2836 IChannelAudioVolume
*iface
, UINT32 count
, const float *levels
,
2837 const GUID
*context
)
2839 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2840 AudioSession
*session
= This
->session
;
2844 TRACE("(%p)->(%d, %p, %s)\n", session
, count
, levels
,
2845 wine_dbgstr_guid(context
));
2848 return NULL_PTR_ERR
;
2850 if(count
!= session
->channel_count
)
2851 return E_INVALIDARG
;
2854 FIXME("Notifications not supported yet\n");
2856 EnterCriticalSection(&session
->lock
);
2858 for(i
= 0; i
< count
; ++i
)
2859 session
->channel_vols
[i
] = levels
[i
];
2861 ret
= oss_session_setvol(session
, -1);
2863 LeaveCriticalSection(&session
->lock
);
2868 static HRESULT WINAPI
ChannelAudioVolume_GetAllVolumes(
2869 IChannelAudioVolume
*iface
, UINT32 count
, float *levels
)
2871 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2872 AudioSession
*session
= This
->session
;
2875 TRACE("(%p)->(%d, %p)\n", session
, count
, levels
);
2878 return NULL_PTR_ERR
;
2880 if(count
!= session
->channel_count
)
2881 return E_INVALIDARG
;
2883 for(i
= 0; i
< count
; ++i
)
2884 levels
[i
] = session
->channel_vols
[i
];
2889 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
=
2891 ChannelAudioVolume_QueryInterface
,
2892 ChannelAudioVolume_AddRef
,
2893 ChannelAudioVolume_Release
,
2894 ChannelAudioVolume_GetChannelCount
,
2895 ChannelAudioVolume_SetChannelVolume
,
2896 ChannelAudioVolume_GetChannelVolume
,
2897 ChannelAudioVolume_SetAllVolumes
,
2898 ChannelAudioVolume_GetAllVolumes
2901 static HRESULT WINAPI
AudioSessionManager_QueryInterface(IAudioSessionManager2
*iface
,
2902 REFIID riid
, void **ppv
)
2904 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2910 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2911 IsEqualIID(riid
, &IID_IAudioSessionManager
) ||
2912 IsEqualIID(riid
, &IID_IAudioSessionManager2
))
2915 IUnknown_AddRef((IUnknown
*)*ppv
);
2919 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2920 return E_NOINTERFACE
;
2923 static ULONG WINAPI
AudioSessionManager_AddRef(IAudioSessionManager2
*iface
)
2925 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2927 ref
= InterlockedIncrement(&This
->ref
);
2928 TRACE("(%p) Refcount now %u\n", This
, ref
);
2932 static ULONG WINAPI
AudioSessionManager_Release(IAudioSessionManager2
*iface
)
2934 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2936 ref
= InterlockedDecrement(&This
->ref
);
2937 TRACE("(%p) Refcount now %u\n", This
, ref
);
2939 HeapFree(GetProcessHeap(), 0, This
);
2943 static HRESULT WINAPI
AudioSessionManager_GetAudioSessionControl(
2944 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2945 IAudioSessionControl
**out
)
2947 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2948 AudioSession
*session
;
2949 AudioSessionWrapper
*wrapper
;
2952 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2955 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2959 wrapper
= AudioSessionWrapper_Create(NULL
);
2961 return E_OUTOFMEMORY
;
2963 wrapper
->session
= session
;
2965 *out
= (IAudioSessionControl
*)&wrapper
->IAudioSessionControl2_iface
;
2970 static HRESULT WINAPI
AudioSessionManager_GetSimpleAudioVolume(
2971 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2972 ISimpleAudioVolume
**out
)
2974 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2975 AudioSession
*session
;
2976 AudioSessionWrapper
*wrapper
;
2979 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2982 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2986 wrapper
= AudioSessionWrapper_Create(NULL
);
2988 return E_OUTOFMEMORY
;
2990 wrapper
->session
= session
;
2992 *out
= &wrapper
->ISimpleAudioVolume_iface
;
2997 static HRESULT WINAPI
AudioSessionManager_GetSessionEnumerator(
2998 IAudioSessionManager2
*iface
, IAudioSessionEnumerator
**out
)
3000 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3001 FIXME("(%p)->(%p) - stub\n", This
, out
);
3005 static HRESULT WINAPI
AudioSessionManager_RegisterSessionNotification(
3006 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
3008 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3009 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3013 static HRESULT WINAPI
AudioSessionManager_UnregisterSessionNotification(
3014 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
3016 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3017 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3021 static HRESULT WINAPI
AudioSessionManager_RegisterDuckNotification(
3022 IAudioSessionManager2
*iface
, const WCHAR
*session_id
,
3023 IAudioVolumeDuckNotification
*notification
)
3025 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3026 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3030 static HRESULT WINAPI
AudioSessionManager_UnregisterDuckNotification(
3031 IAudioSessionManager2
*iface
,
3032 IAudioVolumeDuckNotification
*notification
)
3034 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3035 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3039 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
=
3041 AudioSessionManager_QueryInterface
,
3042 AudioSessionManager_AddRef
,
3043 AudioSessionManager_Release
,
3044 AudioSessionManager_GetAudioSessionControl
,
3045 AudioSessionManager_GetSimpleAudioVolume
,
3046 AudioSessionManager_GetSessionEnumerator
,
3047 AudioSessionManager_RegisterSessionNotification
,
3048 AudioSessionManager_UnregisterSessionNotification
,
3049 AudioSessionManager_RegisterDuckNotification
,
3050 AudioSessionManager_UnregisterDuckNotification
3053 HRESULT WINAPI
AUDDRV_GetAudioSessionManager(IMMDevice
*device
,
3054 IAudioSessionManager2
**out
)
3058 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SessionMgr
));
3060 return E_OUTOFMEMORY
;
3062 This
->IAudioSessionManager2_iface
.lpVtbl
= &AudioSessionManager2_Vtbl
;
3063 This
->device
= device
;
3066 *out
= &This
->IAudioSessionManager2_iface
;