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
)
1256 ssize_t written_bytes
;
1257 UINT32 written_frames
;
1258 size_t to_write_frames
, to_write_bytes
;
1261 This
->local_buffer
+ (This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
);
1263 if(This
->lcl_offs_frames
+ This
->held_frames
> This
->bufsize_frames
)
1264 to_write_frames
= This
->bufsize_frames
- This
->lcl_offs_frames
;
1266 to_write_frames
= This
->held_frames
;
1267 to_write_bytes
= to_write_frames
* This
->fmt
->nBlockAlign
;
1269 if(ioctl(This
->fd
, SNDCTL_DSP_GETOSPACE
, &bi
) < 0){
1270 WARN("GETOSPACE failed: %d (%s)\n", errno
, strerror(errno
));
1274 if(bi
.bytes
< to_write_bytes
){
1275 to_write_frames
= bi
.bytes
/ This
->fmt
->nBlockAlign
;
1276 to_write_bytes
= to_write_frames
* This
->fmt
->nBlockAlign
;
1279 if(This
->session
->mute
)
1280 oss_silence_buffer(This
, buf
, to_write_frames
);
1282 written_bytes
= write(This
->fd
, buf
, to_write_bytes
);
1283 if(written_bytes
< 0){
1284 /* EAGAIN is OSS buffer full, log that too */
1285 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1288 written_frames
= written_bytes
/ This
->fmt
->nBlockAlign
;
1290 This
->lcl_offs_frames
+= written_frames
;
1291 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1292 This
->held_frames
-= written_frames
;
1293 This
->inbuf_frames
+= written_frames
;
1295 if(written_frames
< to_write_frames
){
1296 /* OSS buffer probably full */
1300 bi
.bytes
-= written_bytes
;
1301 if(This
->held_frames
&& bi
.bytes
>= This
->fmt
->nBlockAlign
){
1302 /* wrapped and have some data back at the start to write */
1304 to_write_frames
= bi
.bytes
/ This
->fmt
->nBlockAlign
;
1305 to_write_bytes
= to_write_frames
* This
->fmt
->nBlockAlign
;
1307 if(This
->session
->mute
)
1308 oss_silence_buffer(This
, This
->local_buffer
, to_write_frames
);
1310 written_bytes
= write(This
->fd
, This
->local_buffer
, to_write_bytes
);
1311 if(written_bytes
< 0){
1312 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1315 written_frames
= written_bytes
/ This
->fmt
->nBlockAlign
;
1317 This
->lcl_offs_frames
+= written_frames
;
1318 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1319 This
->held_frames
-= written_frames
;
1320 This
->inbuf_frames
+= written_frames
;
1324 static void oss_read_data(ACImpl
*This
)
1326 UINT64 pos
, readable
;
1330 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
1331 WARN("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
1335 pos
= (This
->held_frames
+ This
->lcl_offs_frames
) % This
->bufsize_frames
;
1336 readable
= (This
->bufsize_frames
- pos
) * This
->fmt
->nBlockAlign
;
1338 if(bi
.bytes
< readable
)
1339 readable
= bi
.bytes
;
1341 nread
= read(This
->fd
, This
->local_buffer
+ pos
* This
->fmt
->nBlockAlign
,
1344 WARN("read failed: %d (%s)\n", errno
, strerror(errno
));
1348 This
->held_frames
+= nread
/ This
->fmt
->nBlockAlign
;
1350 if(This
->held_frames
> This
->bufsize_frames
){
1351 WARN("Overflow of unread data\n");
1352 This
->lcl_offs_frames
+= This
->held_frames
;
1353 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1354 This
->held_frames
= This
->bufsize_frames
;
1358 static void CALLBACK
oss_period_callback(void *user
, BOOLEAN timer
)
1360 ACImpl
*This
= user
;
1362 EnterCriticalSection(&This
->lock
);
1364 if(This
->dataflow
== eRender
&& This
->held_frames
)
1365 oss_write_data(This
);
1366 else if(This
->dataflow
== eCapture
)
1367 oss_read_data(This
);
1370 SetEvent(This
->event
);
1372 LeaveCriticalSection(&This
->lock
);
1375 static HRESULT WINAPI
AudioClient_Start(IAudioClient
*iface
)
1377 ACImpl
*This
= impl_from_IAudioClient(iface
);
1380 TRACE("(%p)\n", This
);
1382 EnterCriticalSection(&This
->lock
);
1385 LeaveCriticalSection(&This
->lock
);
1386 return AUDCLNT_E_NOT_INITIALIZED
;
1389 if((This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !This
->event
){
1390 LeaveCriticalSection(&This
->lock
);
1391 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1395 LeaveCriticalSection(&This
->lock
);
1396 return AUDCLNT_E_NOT_STOPPED
;
1399 if(This
->dataflow
== eRender
)
1400 mask
= PCM_ENABLE_OUTPUT
;
1401 else if(This
->dataflow
== eCapture
)
1402 mask
= PCM_ENABLE_INPUT
;
1404 LeaveCriticalSection(&This
->lock
);
1405 return E_UNEXPECTED
;
1408 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1409 LeaveCriticalSection(&This
->lock
);
1410 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1414 if(!CreateTimerQueueTimer(&This
->timer
, g_timer_q
,
1415 oss_period_callback
, This
, 0, This
->period_us
/ 1000,
1416 WT_EXECUTEINTIMERTHREAD
))
1417 ERR("Unable to create period timer: %u\n", GetLastError());
1419 This
->playing
= TRUE
;
1421 LeaveCriticalSection(&This
->lock
);
1426 static HRESULT WINAPI
AudioClient_Stop(IAudioClient
*iface
)
1428 ACImpl
*This
= impl_from_IAudioClient(iface
);
1431 TRACE("(%p)\n", This
);
1433 EnterCriticalSection(&This
->lock
);
1436 LeaveCriticalSection(&This
->lock
);
1437 return AUDCLNT_E_NOT_INITIALIZED
;
1441 LeaveCriticalSection(&This
->lock
);
1445 if(This
->timer
&& This
->timer
!= INVALID_HANDLE_VALUE
){
1446 DeleteTimerQueueTimer(g_timer_q
, This
->timer
,
1447 INVALID_HANDLE_VALUE
);
1451 if(ioctl(This
->fd
, SNDCTL_DSP_HALT
, NULL
) < 0){
1452 LeaveCriticalSection(&This
->lock
);
1453 WARN("HALT failed: %d (%s)\n", errno
, strerror(errno
));
1458 if(ioctl(This
->fd
, SNDCTL_DSP_SETTRIGGER
, &mask
) < 0){
1459 LeaveCriticalSection(&This
->lock
);
1460 WARN("SETTRIGGER failed: %d (%s)\n", errno
, strerror(errno
));
1464 This
->playing
= FALSE
;
1466 LeaveCriticalSection(&This
->lock
);
1471 static HRESULT WINAPI
AudioClient_Reset(IAudioClient
*iface
)
1473 ACImpl
*This
= impl_from_IAudioClient(iface
);
1475 TRACE("(%p)\n", This
);
1477 EnterCriticalSection(&This
->lock
);
1480 LeaveCriticalSection(&This
->lock
);
1481 return AUDCLNT_E_NOT_INITIALIZED
;
1485 LeaveCriticalSection(&This
->lock
);
1486 return AUDCLNT_E_NOT_STOPPED
;
1489 if(This
->buf_state
!= NOT_LOCKED
){
1490 LeaveCriticalSection(&This
->lock
);
1491 return AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1494 This
->written_frames
= 0;
1495 This
->inbuf_frames
= 0;
1496 This
->held_frames
= 0;
1498 if(ioctl(This
->fd
, SNDCTL_DSP_SKIP
, NULL
) < 0)
1499 WARN("SKIP failed: %d (%s)\n", errno
, strerror(errno
));
1501 LeaveCriticalSection(&This
->lock
);
1506 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient
*iface
,
1509 ACImpl
*This
= impl_from_IAudioClient(iface
);
1511 TRACE("(%p)->(%p)\n", This
, event
);
1514 return E_INVALIDARG
;
1516 EnterCriticalSection(&This
->lock
);
1519 LeaveCriticalSection(&This
->lock
);
1520 return AUDCLNT_E_NOT_INITIALIZED
;
1523 if(!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
)){
1524 LeaveCriticalSection(&This
->lock
);
1525 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1528 This
->event
= event
;
1530 LeaveCriticalSection(&This
->lock
);
1535 static HRESULT WINAPI
AudioClient_GetService(IAudioClient
*iface
, REFIID riid
,
1538 ACImpl
*This
= impl_from_IAudioClient(iface
);
1540 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1546 EnterCriticalSection(&This
->lock
);
1549 LeaveCriticalSection(&This
->lock
);
1550 return AUDCLNT_E_NOT_INITIALIZED
;
1553 if(IsEqualIID(riid
, &IID_IAudioRenderClient
)){
1554 if(This
->dataflow
!= eRender
){
1555 LeaveCriticalSection(&This
->lock
);
1556 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1558 IAudioRenderClient_AddRef(&This
->IAudioRenderClient_iface
);
1559 *ppv
= &This
->IAudioRenderClient_iface
;
1560 }else if(IsEqualIID(riid
, &IID_IAudioCaptureClient
)){
1561 if(This
->dataflow
!= eCapture
){
1562 LeaveCriticalSection(&This
->lock
);
1563 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1565 IAudioCaptureClient_AddRef(&This
->IAudioCaptureClient_iface
);
1566 *ppv
= &This
->IAudioCaptureClient_iface
;
1567 }else if(IsEqualIID(riid
, &IID_IAudioClock
)){
1568 IAudioClock_AddRef(&This
->IAudioClock_iface
);
1569 *ppv
= &This
->IAudioClock_iface
;
1570 }else if(IsEqualIID(riid
, &IID_IAudioStreamVolume
)){
1571 IAudioStreamVolume_AddRef(&This
->IAudioStreamVolume_iface
);
1572 *ppv
= &This
->IAudioStreamVolume_iface
;
1573 }else if(IsEqualIID(riid
, &IID_IAudioSessionControl
)){
1574 if(!This
->session_wrapper
){
1575 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1576 if(!This
->session_wrapper
){
1577 LeaveCriticalSection(&This
->lock
);
1578 return E_OUTOFMEMORY
;
1581 IAudioSessionControl2_AddRef(&This
->session_wrapper
->IAudioSessionControl2_iface
);
1583 *ppv
= &This
->session_wrapper
->IAudioSessionControl2_iface
;
1584 }else if(IsEqualIID(riid
, &IID_IChannelAudioVolume
)){
1585 if(!This
->session_wrapper
){
1586 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1587 if(!This
->session_wrapper
){
1588 LeaveCriticalSection(&This
->lock
);
1589 return E_OUTOFMEMORY
;
1592 IChannelAudioVolume_AddRef(&This
->session_wrapper
->IChannelAudioVolume_iface
);
1594 *ppv
= &This
->session_wrapper
->IChannelAudioVolume_iface
;
1595 }else if(IsEqualIID(riid
, &IID_ISimpleAudioVolume
)){
1596 if(!This
->session_wrapper
){
1597 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1598 if(!This
->session_wrapper
){
1599 LeaveCriticalSection(&This
->lock
);
1600 return E_OUTOFMEMORY
;
1603 ISimpleAudioVolume_AddRef(&This
->session_wrapper
->ISimpleAudioVolume_iface
);
1605 *ppv
= &This
->session_wrapper
->ISimpleAudioVolume_iface
;
1609 LeaveCriticalSection(&This
->lock
);
1613 LeaveCriticalSection(&This
->lock
);
1615 FIXME("stub %s\n", debugstr_guid(riid
));
1616 return E_NOINTERFACE
;
1619 static const IAudioClientVtbl AudioClient_Vtbl
=
1621 AudioClient_QueryInterface
,
1623 AudioClient_Release
,
1624 AudioClient_Initialize
,
1625 AudioClient_GetBufferSize
,
1626 AudioClient_GetStreamLatency
,
1627 AudioClient_GetCurrentPadding
,
1628 AudioClient_IsFormatSupported
,
1629 AudioClient_GetMixFormat
,
1630 AudioClient_GetDevicePeriod
,
1634 AudioClient_SetEventHandle
,
1635 AudioClient_GetService
1638 static HRESULT WINAPI
AudioRenderClient_QueryInterface(
1639 IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1641 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1647 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1648 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1651 IUnknown_AddRef((IUnknown
*)*ppv
);
1655 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1656 return E_NOINTERFACE
;
1659 static ULONG WINAPI
AudioRenderClient_AddRef(IAudioRenderClient
*iface
)
1661 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1662 return AudioClient_AddRef(&This
->IAudioClient_iface
);
1665 static ULONG WINAPI
AudioRenderClient_Release(IAudioRenderClient
*iface
)
1667 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1668 return AudioClient_Release(&This
->IAudioClient_iface
);
1671 static HRESULT WINAPI
AudioRenderClient_GetBuffer(IAudioRenderClient
*iface
,
1672 UINT32 frames
, BYTE
**data
)
1674 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1675 UINT32 pad
, write_pos
;
1678 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
1683 EnterCriticalSection(&This
->lock
);
1685 if(This
->buf_state
!= NOT_LOCKED
){
1686 LeaveCriticalSection(&This
->lock
);
1687 return AUDCLNT_E_OUT_OF_ORDER
;
1691 This
->buf_state
= LOCKED_NORMAL
;
1692 LeaveCriticalSection(&This
->lock
);
1696 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
1698 LeaveCriticalSection(&This
->lock
);
1702 if(pad
+ frames
> This
->bufsize_frames
){
1703 LeaveCriticalSection(&This
->lock
);
1704 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1708 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1709 if(write_pos
+ frames
> This
->bufsize_frames
){
1710 if(This
->tmp_buffer_frames
< frames
){
1711 if(This
->tmp_buffer
)
1712 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1713 This
->tmp_buffer
, frames
* This
->fmt
->nBlockAlign
);
1715 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1716 frames
* This
->fmt
->nBlockAlign
);
1717 if(!This
->tmp_buffer
){
1718 LeaveCriticalSection(&This
->lock
);
1719 return E_OUTOFMEMORY
;
1721 This
->tmp_buffer_frames
= frames
;
1723 *data
= This
->tmp_buffer
;
1724 This
->buf_state
= LOCKED_WRAPPED
;
1726 *data
= This
->local_buffer
+ write_pos
* This
->fmt
->nBlockAlign
;
1727 This
->buf_state
= LOCKED_NORMAL
;
1730 LeaveCriticalSection(&This
->lock
);
1735 static void oss_wrap_buffer(ACImpl
*This
, BYTE
*buffer
, UINT32 written_frames
)
1737 UINT32 write_offs_frames
=
1738 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1739 UINT32 write_offs_bytes
= write_offs_frames
* This
->fmt
->nBlockAlign
;
1740 UINT32 chunk_frames
= This
->bufsize_frames
- write_offs_frames
;
1741 UINT32 chunk_bytes
= chunk_frames
* This
->fmt
->nBlockAlign
;
1742 UINT32 written_bytes
= written_frames
* This
->fmt
->nBlockAlign
;
1744 if(written_bytes
<= chunk_bytes
){
1745 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, written_bytes
);
1747 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, chunk_bytes
);
1748 memcpy(This
->local_buffer
, buffer
+ chunk_bytes
,
1749 written_bytes
- chunk_bytes
);
1753 static HRESULT WINAPI
AudioRenderClient_ReleaseBuffer(
1754 IAudioRenderClient
*iface
, UINT32 written_frames
, DWORD flags
)
1756 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1759 TRACE("(%p)->(%u, %x)\n", This
, written_frames
, flags
);
1761 EnterCriticalSection(&This
->lock
);
1763 if(This
->buf_state
== NOT_LOCKED
|| !written_frames
){
1764 This
->buf_state
= NOT_LOCKED
;
1765 LeaveCriticalSection(&This
->lock
);
1766 return written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1769 if(This
->buf_state
== LOCKED_NORMAL
)
1770 buffer
= This
->local_buffer
+ This
->fmt
->nBlockAlign
*
1771 ((This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
);
1773 buffer
= This
->tmp_buffer
;
1775 if(flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1776 oss_silence_buffer(This
, buffer
, written_frames
);
1778 if(This
->held_frames
){
1779 if(This
->buf_state
== LOCKED_WRAPPED
)
1780 oss_wrap_buffer(This
, buffer
, written_frames
);
1782 This
->held_frames
+= written_frames
;
1787 if(This
->session
->mute
)
1788 oss_silence_buffer(This
, buffer
, written_frames
);
1790 w_bytes
= write(This
->fd
, buffer
,
1791 written_frames
* This
->fmt
->nBlockAlign
);
1793 if(errno
!= EAGAIN
){
1794 This
->buf_state
= NOT_LOCKED
;
1795 LeaveCriticalSection(&This
->lock
);
1796 ERR("write failed: %d (%s)\n", errno
, strerror(errno
));
1798 }else /* OSS buffer full */
1801 w_frames
= w_bytes
/ This
->fmt
->nBlockAlign
;
1802 This
->inbuf_frames
+= w_frames
;
1804 if(w_frames
< written_frames
){
1805 if(This
->buf_state
== LOCKED_WRAPPED
)
1806 oss_wrap_buffer(This
, This
->tmp_buffer
+ w_bytes
,
1807 written_frames
- w_frames
);
1809 This
->lcl_offs_frames
+= w_frames
;
1810 This
->held_frames
= written_frames
- w_frames
;
1814 This
->written_frames
+= written_frames
;
1815 This
->buf_state
= NOT_LOCKED
;
1817 LeaveCriticalSection(&This
->lock
);
1822 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
1823 AudioRenderClient_QueryInterface
,
1824 AudioRenderClient_AddRef
,
1825 AudioRenderClient_Release
,
1826 AudioRenderClient_GetBuffer
,
1827 AudioRenderClient_ReleaseBuffer
1830 static HRESULT WINAPI
AudioCaptureClient_QueryInterface(
1831 IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1833 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1839 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1840 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1843 IUnknown_AddRef((IUnknown
*)*ppv
);
1847 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1848 return E_NOINTERFACE
;
1851 static ULONG WINAPI
AudioCaptureClient_AddRef(IAudioCaptureClient
*iface
)
1853 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1854 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1857 static ULONG WINAPI
AudioCaptureClient_Release(IAudioCaptureClient
*iface
)
1859 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1860 return IAudioClient_Release(&This
->IAudioClient_iface
);
1863 static HRESULT WINAPI
AudioCaptureClient_GetBuffer(IAudioCaptureClient
*iface
,
1864 BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
,
1867 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1870 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
1873 if(!data
|| !frames
|| !flags
)
1876 EnterCriticalSection(&This
->lock
);
1878 if(This
->buf_state
!= NOT_LOCKED
){
1879 LeaveCriticalSection(&This
->lock
);
1880 return AUDCLNT_E_OUT_OF_ORDER
;
1883 hr
= IAudioCaptureClient_GetNextPacketSize(iface
, frames
);
1885 LeaveCriticalSection(&This
->lock
);
1891 if(This
->lcl_offs_frames
+ *frames
> This
->bufsize_frames
){
1892 UINT32 chunk_bytes
, offs_bytes
, frames_bytes
;
1893 if(This
->tmp_buffer_frames
< *frames
){
1894 if(This
->tmp_buffer
)
1895 This
->tmp_buffer
= HeapReAlloc(GetProcessHeap(), 0,
1896 This
->tmp_buffer
, *frames
* This
->fmt
->nBlockAlign
);
1898 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1899 *frames
* This
->fmt
->nBlockAlign
);
1900 if(!This
->tmp_buffer
){
1901 LeaveCriticalSection(&This
->lock
);
1902 return E_OUTOFMEMORY
;
1904 This
->tmp_buffer_frames
= *frames
;
1907 *data
= This
->tmp_buffer
;
1908 chunk_bytes
= (This
->bufsize_frames
- This
->lcl_offs_frames
) *
1909 This
->fmt
->nBlockAlign
;
1910 offs_bytes
= This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1911 frames_bytes
= *frames
* This
->fmt
->nBlockAlign
;
1912 memcpy(This
->tmp_buffer
, This
->local_buffer
+ offs_bytes
, chunk_bytes
);
1913 memcpy(This
->tmp_buffer
, This
->local_buffer
,
1914 frames_bytes
- chunk_bytes
);
1916 *data
= This
->local_buffer
+
1917 This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
1919 This
->buf_state
= LOCKED_NORMAL
;
1921 if(devpos
|| qpcpos
)
1922 IAudioClock_GetPosition(&This
->IAudioClock_iface
, devpos
, qpcpos
);
1924 LeaveCriticalSection(&This
->lock
);
1926 return *frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
1929 static HRESULT WINAPI
AudioCaptureClient_ReleaseBuffer(
1930 IAudioCaptureClient
*iface
, UINT32 done
)
1932 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1934 TRACE("(%p)->(%u)\n", This
, done
);
1936 EnterCriticalSection(&This
->lock
);
1938 if(This
->buf_state
== NOT_LOCKED
){
1939 LeaveCriticalSection(&This
->lock
);
1940 return AUDCLNT_E_OUT_OF_ORDER
;
1943 This
->held_frames
-= done
;
1944 This
->lcl_offs_frames
+= done
;
1945 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1947 This
->buf_state
= NOT_LOCKED
;
1949 LeaveCriticalSection(&This
->lock
);
1954 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
1955 IAudioCaptureClient
*iface
, UINT32
*frames
)
1957 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1959 TRACE("(%p)->(%p)\n", This
, frames
);
1961 return AudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, frames
);
1964 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
1966 AudioCaptureClient_QueryInterface
,
1967 AudioCaptureClient_AddRef
,
1968 AudioCaptureClient_Release
,
1969 AudioCaptureClient_GetBuffer
,
1970 AudioCaptureClient_ReleaseBuffer
,
1971 AudioCaptureClient_GetNextPacketSize
1974 static HRESULT WINAPI
AudioClock_QueryInterface(IAudioClock
*iface
,
1975 REFIID riid
, void **ppv
)
1977 ACImpl
*This
= impl_from_IAudioClock(iface
);
1979 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1985 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClock
))
1987 else if(IsEqualIID(riid
, &IID_IAudioClock2
))
1988 *ppv
= &This
->IAudioClock2_iface
;
1990 IUnknown_AddRef((IUnknown
*)*ppv
);
1994 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1995 return E_NOINTERFACE
;
1998 static ULONG WINAPI
AudioClock_AddRef(IAudioClock
*iface
)
2000 ACImpl
*This
= impl_from_IAudioClock(iface
);
2001 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2004 static ULONG WINAPI
AudioClock_Release(IAudioClock
*iface
)
2006 ACImpl
*This
= impl_from_IAudioClock(iface
);
2007 return IAudioClient_Release(&This
->IAudioClient_iface
);
2010 static HRESULT WINAPI
AudioClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
2012 ACImpl
*This
= impl_from_IAudioClock(iface
);
2014 TRACE("(%p)->(%p)\n", This
, freq
);
2016 *freq
= This
->fmt
->nSamplesPerSec
;
2021 static HRESULT WINAPI
AudioClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
,
2024 ACImpl
*This
= impl_from_IAudioClock(iface
);
2028 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
2033 EnterCriticalSection(&This
->lock
);
2035 hr
= IAudioClient_GetCurrentPadding(&This
->IAudioClient_iface
, &pad
);
2037 LeaveCriticalSection(&This
->lock
);
2041 if(This
->dataflow
== eRender
)
2042 *pos
= This
->written_frames
- pad
;
2043 else if(This
->dataflow
== eCapture
)
2044 *pos
= This
->written_frames
+ pad
;
2046 LeaveCriticalSection(&This
->lock
);
2049 LARGE_INTEGER stamp
, freq
;
2050 QueryPerformanceCounter(&stamp
);
2051 QueryPerformanceFrequency(&freq
);
2052 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
2058 static HRESULT WINAPI
AudioClock_GetCharacteristics(IAudioClock
*iface
,
2061 ACImpl
*This
= impl_from_IAudioClock(iface
);
2063 TRACE("(%p)->(%p)\n", This
, chars
);
2068 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
2073 static const IAudioClockVtbl AudioClock_Vtbl
=
2075 AudioClock_QueryInterface
,
2078 AudioClock_GetFrequency
,
2079 AudioClock_GetPosition
,
2080 AudioClock_GetCharacteristics
2083 static HRESULT WINAPI
AudioClock2_QueryInterface(IAudioClock2
*iface
,
2084 REFIID riid
, void **ppv
)
2086 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2087 return IAudioClock_QueryInterface(&This
->IAudioClock_iface
, riid
, ppv
);
2090 static ULONG WINAPI
AudioClock2_AddRef(IAudioClock2
*iface
)
2092 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2093 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2096 static ULONG WINAPI
AudioClock2_Release(IAudioClock2
*iface
)
2098 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2099 return IAudioClient_Release(&This
->IAudioClient_iface
);
2102 static HRESULT WINAPI
AudioClock2_GetDevicePosition(IAudioClock2
*iface
,
2103 UINT64
*pos
, UINT64
*qpctime
)
2105 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2107 FIXME("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
2112 static const IAudioClock2Vtbl AudioClock2_Vtbl
=
2114 AudioClock2_QueryInterface
,
2116 AudioClock2_Release
,
2117 AudioClock2_GetDevicePosition
2120 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
)
2122 AudioSessionWrapper
*ret
;
2124 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2125 sizeof(AudioSessionWrapper
));
2129 ret
->IAudioSessionControl2_iface
.lpVtbl
= &AudioSessionControl2_Vtbl
;
2130 ret
->ISimpleAudioVolume_iface
.lpVtbl
= &SimpleAudioVolume_Vtbl
;
2131 ret
->IChannelAudioVolume_iface
.lpVtbl
= &ChannelAudioVolume_Vtbl
;
2135 ret
->client
= client
;
2137 ret
->session
= client
->session
;
2138 AudioClient_AddRef(&client
->IAudioClient_iface
);
2144 static HRESULT WINAPI
AudioSessionControl_QueryInterface(
2145 IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
2147 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2153 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2154 IsEqualIID(riid
, &IID_IAudioSessionControl
) ||
2155 IsEqualIID(riid
, &IID_IAudioSessionControl2
))
2158 IUnknown_AddRef((IUnknown
*)*ppv
);
2162 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2163 return E_NOINTERFACE
;
2166 static ULONG WINAPI
AudioSessionControl_AddRef(IAudioSessionControl2
*iface
)
2168 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2170 ref
= InterlockedIncrement(&This
->ref
);
2171 TRACE("(%p) Refcount now %u\n", This
, ref
);
2175 static ULONG WINAPI
AudioSessionControl_Release(IAudioSessionControl2
*iface
)
2177 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2179 ref
= InterlockedDecrement(&This
->ref
);
2180 TRACE("(%p) Refcount now %u\n", This
, ref
);
2183 EnterCriticalSection(&This
->client
->lock
);
2184 This
->client
->session_wrapper
= NULL
;
2185 LeaveCriticalSection(&This
->client
->lock
);
2186 AudioClient_Release(&This
->client
->IAudioClient_iface
);
2188 HeapFree(GetProcessHeap(), 0, This
);
2193 static HRESULT WINAPI
AudioSessionControl_GetState(IAudioSessionControl2
*iface
,
2194 AudioSessionState
*state
)
2196 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2199 TRACE("(%p)->(%p)\n", This
, state
);
2202 return NULL_PTR_ERR
;
2204 EnterCriticalSection(&g_sessions_lock
);
2206 if(list_empty(&This
->session
->clients
)){
2207 *state
= AudioSessionStateExpired
;
2208 LeaveCriticalSection(&g_sessions_lock
);
2212 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
){
2213 EnterCriticalSection(&client
->lock
);
2214 if(client
->playing
){
2215 *state
= AudioSessionStateActive
;
2216 LeaveCriticalSection(&client
->lock
);
2217 LeaveCriticalSection(&g_sessions_lock
);
2220 LeaveCriticalSection(&client
->lock
);
2223 LeaveCriticalSection(&g_sessions_lock
);
2225 *state
= AudioSessionStateInactive
;
2230 static HRESULT WINAPI
AudioSessionControl_GetDisplayName(
2231 IAudioSessionControl2
*iface
, WCHAR
**name
)
2233 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2235 FIXME("(%p)->(%p) - stub\n", This
, name
);
2240 static HRESULT WINAPI
AudioSessionControl_SetDisplayName(
2241 IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
2243 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2245 FIXME("(%p)->(%p, %s) - stub\n", This
, name
, debugstr_guid(session
));
2250 static HRESULT WINAPI
AudioSessionControl_GetIconPath(
2251 IAudioSessionControl2
*iface
, WCHAR
**path
)
2253 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2255 FIXME("(%p)->(%p) - stub\n", This
, path
);
2260 static HRESULT WINAPI
AudioSessionControl_SetIconPath(
2261 IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
2263 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2265 FIXME("(%p)->(%p, %s) - stub\n", This
, path
, debugstr_guid(session
));
2270 static HRESULT WINAPI
AudioSessionControl_GetGroupingParam(
2271 IAudioSessionControl2
*iface
, GUID
*group
)
2273 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2275 FIXME("(%p)->(%p) - stub\n", This
, group
);
2280 static HRESULT WINAPI
AudioSessionControl_SetGroupingParam(
2281 IAudioSessionControl2
*iface
, const GUID
*group
, const GUID
*session
)
2283 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2285 FIXME("(%p)->(%s, %s) - stub\n", This
, debugstr_guid(group
),
2286 debugstr_guid(session
));
2291 static HRESULT WINAPI
AudioSessionControl_RegisterAudioSessionNotification(
2292 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2294 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2296 FIXME("(%p)->(%p) - stub\n", This
, events
);
2301 static HRESULT WINAPI
AudioSessionControl_UnregisterAudioSessionNotification(
2302 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2304 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2306 FIXME("(%p)->(%p) - stub\n", This
, events
);
2311 static HRESULT WINAPI
AudioSessionControl_GetSessionIdentifier(
2312 IAudioSessionControl2
*iface
, WCHAR
**id
)
2314 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2316 FIXME("(%p)->(%p) - stub\n", This
, id
);
2321 static HRESULT WINAPI
AudioSessionControl_GetSessionInstanceIdentifier(
2322 IAudioSessionControl2
*iface
, WCHAR
**id
)
2324 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2326 FIXME("(%p)->(%p) - stub\n", This
, id
);
2331 static HRESULT WINAPI
AudioSessionControl_GetProcessId(
2332 IAudioSessionControl2
*iface
, DWORD
*pid
)
2334 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2336 TRACE("(%p)->(%p)\n", This
, pid
);
2341 *pid
= GetCurrentProcessId();
2346 static HRESULT WINAPI
AudioSessionControl_IsSystemSoundsSession(
2347 IAudioSessionControl2
*iface
)
2349 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2351 TRACE("(%p)\n", This
);
2356 static HRESULT WINAPI
AudioSessionControl_SetDuckingPreference(
2357 IAudioSessionControl2
*iface
, BOOL optout
)
2359 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2361 TRACE("(%p)->(%d)\n", This
, optout
);
2366 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
=
2368 AudioSessionControl_QueryInterface
,
2369 AudioSessionControl_AddRef
,
2370 AudioSessionControl_Release
,
2371 AudioSessionControl_GetState
,
2372 AudioSessionControl_GetDisplayName
,
2373 AudioSessionControl_SetDisplayName
,
2374 AudioSessionControl_GetIconPath
,
2375 AudioSessionControl_SetIconPath
,
2376 AudioSessionControl_GetGroupingParam
,
2377 AudioSessionControl_SetGroupingParam
,
2378 AudioSessionControl_RegisterAudioSessionNotification
,
2379 AudioSessionControl_UnregisterAudioSessionNotification
,
2380 AudioSessionControl_GetSessionIdentifier
,
2381 AudioSessionControl_GetSessionInstanceIdentifier
,
2382 AudioSessionControl_GetProcessId
,
2383 AudioSessionControl_IsSystemSoundsSession
,
2384 AudioSessionControl_SetDuckingPreference
2387 /* index == -1 means set all channels, otherwise sets only the given channel */
2388 static HRESULT
oss_setvol(ACImpl
*This
, UINT32 index
)
2395 if(index
== (UINT32
)-1){
2398 for(i
= 0; i
< This
->fmt
->nChannels
; ++i
){
2400 hr
= oss_setvol(This
, i
);
2408 /* OSS doesn't support volume control past the first two channels */
2411 if(This
->dataflow
== eRender
){
2412 setreq
= SNDCTL_DSP_SETPLAYVOL
;
2413 getreq
= SNDCTL_DSP_GETPLAYVOL
;
2414 }else if(This
->dataflow
== eCapture
){
2415 setreq
= SNDCTL_DSP_SETRECVOL
;
2416 getreq
= SNDCTL_DSP_GETRECVOL
;
2418 return E_UNEXPECTED
;
2420 if(ioctl(This
->fd
, getreq
, &vol
) < 0){
2422 /* device doesn't support this call */
2425 WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2429 level
= This
->session
->master_vol
* This
->session
->channel_vols
[index
] *
2433 vol
= l
| (vol
& 0xFF00);
2435 vol
= (vol
& 0xFF) | (l
<< 8);
2437 if(ioctl(This
->fd
, setreq
, &vol
) < 0){
2439 /* device doesn't support this call */
2442 WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno
, strerror(errno
));
2449 static HRESULT
oss_session_setvol(AudioSession
*session
, UINT32 index
)
2454 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2456 hr
= oss_setvol(client
, index
);
2464 static HRESULT WINAPI
SimpleAudioVolume_QueryInterface(
2465 ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
2467 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2473 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2474 IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
2477 IUnknown_AddRef((IUnknown
*)*ppv
);
2481 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2482 return E_NOINTERFACE
;
2485 static ULONG WINAPI
SimpleAudioVolume_AddRef(ISimpleAudioVolume
*iface
)
2487 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2488 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2491 static ULONG WINAPI
SimpleAudioVolume_Release(ISimpleAudioVolume
*iface
)
2493 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2494 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2497 static HRESULT WINAPI
SimpleAudioVolume_SetMasterVolume(
2498 ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
2500 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2501 AudioSession
*session
= This
->session
;
2504 TRACE("(%p)->(%f, %s)\n", session
, level
, wine_dbgstr_guid(context
));
2506 if(level
< 0.f
|| level
> 1.f
)
2507 return E_INVALIDARG
;
2510 FIXME("Notifications not supported yet\n");
2512 EnterCriticalSection(&session
->lock
);
2514 session
->master_vol
= level
;
2516 ret
= oss_session_setvol(session
, -1);
2518 LeaveCriticalSection(&session
->lock
);
2523 static HRESULT WINAPI
SimpleAudioVolume_GetMasterVolume(
2524 ISimpleAudioVolume
*iface
, float *level
)
2526 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2527 AudioSession
*session
= This
->session
;
2529 TRACE("(%p)->(%p)\n", session
, level
);
2532 return NULL_PTR_ERR
;
2534 *level
= session
->master_vol
;
2539 static HRESULT WINAPI
SimpleAudioVolume_SetMute(ISimpleAudioVolume
*iface
,
2540 BOOL mute
, const GUID
*context
)
2542 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2543 AudioSession
*session
= This
->session
;
2545 TRACE("(%p)->(%u, %p)\n", session
, mute
, context
);
2547 EnterCriticalSection(&session
->lock
);
2549 if(!mute
&& session
->mute
){
2552 session
->mute
= mute
;
2554 LIST_FOR_EACH_ENTRY(client
, &session
->clients
, ACImpl
, entry
){
2555 EnterCriticalSection(&client
->lock
);
2556 if(ioctl(client
->fd
, SNDCTL_DSP_SKIP
) < 0)
2557 WARN("Error calling DSP_SKIP: %d (%s)\n", errno
,
2559 oss_write_data(client
);
2560 LeaveCriticalSection(&client
->lock
);
2563 session
->mute
= mute
;
2565 LeaveCriticalSection(&session
->lock
);
2570 static HRESULT WINAPI
SimpleAudioVolume_GetMute(ISimpleAudioVolume
*iface
,
2573 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2574 AudioSession
*session
= This
->session
;
2576 TRACE("(%p)->(%p)\n", session
, mute
);
2579 return NULL_PTR_ERR
;
2581 *mute
= This
->session
->mute
;
2586 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
=
2588 SimpleAudioVolume_QueryInterface
,
2589 SimpleAudioVolume_AddRef
,
2590 SimpleAudioVolume_Release
,
2591 SimpleAudioVolume_SetMasterVolume
,
2592 SimpleAudioVolume_GetMasterVolume
,
2593 SimpleAudioVolume_SetMute
,
2594 SimpleAudioVolume_GetMute
2597 static HRESULT WINAPI
AudioStreamVolume_QueryInterface(
2598 IAudioStreamVolume
*iface
, REFIID riid
, void **ppv
)
2600 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2606 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2607 IsEqualIID(riid
, &IID_IAudioStreamVolume
))
2610 IUnknown_AddRef((IUnknown
*)*ppv
);
2614 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2615 return E_NOINTERFACE
;
2618 static ULONG WINAPI
AudioStreamVolume_AddRef(IAudioStreamVolume
*iface
)
2620 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2621 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2624 static ULONG WINAPI
AudioStreamVolume_Release(IAudioStreamVolume
*iface
)
2626 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2627 return IAudioClient_Release(&This
->IAudioClient_iface
);
2630 static HRESULT WINAPI
AudioStreamVolume_GetChannelCount(
2631 IAudioStreamVolume
*iface
, UINT32
*out
)
2633 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2635 TRACE("(%p)->(%p)\n", This
, out
);
2640 *out
= This
->fmt
->nChannels
;
2645 static HRESULT WINAPI
AudioStreamVolume_SetChannelVolume(
2646 IAudioStreamVolume
*iface
, UINT32 index
, float level
)
2648 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2651 TRACE("(%p)->(%d, %f)\n", This
, index
, level
);
2653 if(level
< 0.f
|| level
> 1.f
)
2654 return E_INVALIDARG
;
2656 if(index
>= This
->fmt
->nChannels
)
2657 return E_INVALIDARG
;
2659 EnterCriticalSection(&This
->lock
);
2661 This
->vols
[index
] = level
;
2663 ret
= oss_setvol(This
, index
);
2665 LeaveCriticalSection(&This
->lock
);
2670 static HRESULT WINAPI
AudioStreamVolume_GetChannelVolume(
2671 IAudioStreamVolume
*iface
, UINT32 index
, float *level
)
2673 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2675 TRACE("(%p)->(%d, %p)\n", This
, index
, level
);
2680 if(index
>= This
->fmt
->nChannels
)
2681 return E_INVALIDARG
;
2683 *level
= This
->vols
[index
];
2688 static HRESULT WINAPI
AudioStreamVolume_SetAllVolumes(
2689 IAudioStreamVolume
*iface
, UINT32 count
, const float *levels
)
2691 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2695 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2700 if(count
!= This
->fmt
->nChannels
)
2701 return E_INVALIDARG
;
2703 EnterCriticalSection(&This
->lock
);
2705 for(i
= 0; i
< count
; ++i
)
2706 This
->vols
[i
] = levels
[i
];
2708 ret
= oss_setvol(This
, -1);
2710 LeaveCriticalSection(&This
->lock
);
2715 static HRESULT WINAPI
AudioStreamVolume_GetAllVolumes(
2716 IAudioStreamVolume
*iface
, UINT32 count
, float *levels
)
2718 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2721 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2726 if(count
!= This
->fmt
->nChannels
)
2727 return E_INVALIDARG
;
2729 EnterCriticalSection(&This
->lock
);
2731 for(i
= 0; i
< count
; ++i
)
2732 levels
[i
] = This
->vols
[i
];
2734 LeaveCriticalSection(&This
->lock
);
2739 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
=
2741 AudioStreamVolume_QueryInterface
,
2742 AudioStreamVolume_AddRef
,
2743 AudioStreamVolume_Release
,
2744 AudioStreamVolume_GetChannelCount
,
2745 AudioStreamVolume_SetChannelVolume
,
2746 AudioStreamVolume_GetChannelVolume
,
2747 AudioStreamVolume_SetAllVolumes
,
2748 AudioStreamVolume_GetAllVolumes
2751 static HRESULT WINAPI
ChannelAudioVolume_QueryInterface(
2752 IChannelAudioVolume
*iface
, REFIID riid
, void **ppv
)
2754 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2760 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2761 IsEqualIID(riid
, &IID_IChannelAudioVolume
))
2764 IUnknown_AddRef((IUnknown
*)*ppv
);
2768 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2769 return E_NOINTERFACE
;
2772 static ULONG WINAPI
ChannelAudioVolume_AddRef(IChannelAudioVolume
*iface
)
2774 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2775 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2778 static ULONG WINAPI
ChannelAudioVolume_Release(IChannelAudioVolume
*iface
)
2780 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2781 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2784 static HRESULT WINAPI
ChannelAudioVolume_GetChannelCount(
2785 IChannelAudioVolume
*iface
, UINT32
*out
)
2787 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2788 AudioSession
*session
= This
->session
;
2790 TRACE("(%p)->(%p)\n", session
, out
);
2793 return NULL_PTR_ERR
;
2795 *out
= session
->channel_count
;
2800 static HRESULT WINAPI
ChannelAudioVolume_SetChannelVolume(
2801 IChannelAudioVolume
*iface
, UINT32 index
, float level
,
2802 const GUID
*context
)
2804 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2805 AudioSession
*session
= This
->session
;
2808 TRACE("(%p)->(%d, %f, %s)\n", session
, index
, level
,
2809 wine_dbgstr_guid(context
));
2811 if(level
< 0.f
|| level
> 1.f
)
2812 return E_INVALIDARG
;
2814 if(index
>= session
->channel_count
)
2815 return E_INVALIDARG
;
2818 FIXME("Notifications not supported yet\n");
2820 EnterCriticalSection(&session
->lock
);
2822 session
->channel_vols
[index
] = level
;
2824 ret
= oss_session_setvol(session
, index
);
2826 LeaveCriticalSection(&session
->lock
);
2831 static HRESULT WINAPI
ChannelAudioVolume_GetChannelVolume(
2832 IChannelAudioVolume
*iface
, UINT32 index
, float *level
)
2834 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2835 AudioSession
*session
= This
->session
;
2837 TRACE("(%p)->(%d, %p)\n", session
, index
, level
);
2840 return NULL_PTR_ERR
;
2842 if(index
>= session
->channel_count
)
2843 return E_INVALIDARG
;
2845 *level
= session
->channel_vols
[index
];
2850 static HRESULT WINAPI
ChannelAudioVolume_SetAllVolumes(
2851 IChannelAudioVolume
*iface
, UINT32 count
, const float *levels
,
2852 const GUID
*context
)
2854 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2855 AudioSession
*session
= This
->session
;
2859 TRACE("(%p)->(%d, %p, %s)\n", session
, count
, levels
,
2860 wine_dbgstr_guid(context
));
2863 return NULL_PTR_ERR
;
2865 if(count
!= session
->channel_count
)
2866 return E_INVALIDARG
;
2869 FIXME("Notifications not supported yet\n");
2871 EnterCriticalSection(&session
->lock
);
2873 for(i
= 0; i
< count
; ++i
)
2874 session
->channel_vols
[i
] = levels
[i
];
2876 ret
= oss_session_setvol(session
, -1);
2878 LeaveCriticalSection(&session
->lock
);
2883 static HRESULT WINAPI
ChannelAudioVolume_GetAllVolumes(
2884 IChannelAudioVolume
*iface
, UINT32 count
, float *levels
)
2886 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2887 AudioSession
*session
= This
->session
;
2890 TRACE("(%p)->(%d, %p)\n", session
, count
, levels
);
2893 return NULL_PTR_ERR
;
2895 if(count
!= session
->channel_count
)
2896 return E_INVALIDARG
;
2898 for(i
= 0; i
< count
; ++i
)
2899 levels
[i
] = session
->channel_vols
[i
];
2904 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
=
2906 ChannelAudioVolume_QueryInterface
,
2907 ChannelAudioVolume_AddRef
,
2908 ChannelAudioVolume_Release
,
2909 ChannelAudioVolume_GetChannelCount
,
2910 ChannelAudioVolume_SetChannelVolume
,
2911 ChannelAudioVolume_GetChannelVolume
,
2912 ChannelAudioVolume_SetAllVolumes
,
2913 ChannelAudioVolume_GetAllVolumes
2916 static HRESULT WINAPI
AudioSessionManager_QueryInterface(IAudioSessionManager2
*iface
,
2917 REFIID riid
, void **ppv
)
2919 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2925 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2926 IsEqualIID(riid
, &IID_IAudioSessionManager
) ||
2927 IsEqualIID(riid
, &IID_IAudioSessionManager2
))
2930 IUnknown_AddRef((IUnknown
*)*ppv
);
2934 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2935 return E_NOINTERFACE
;
2938 static ULONG WINAPI
AudioSessionManager_AddRef(IAudioSessionManager2
*iface
)
2940 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2942 ref
= InterlockedIncrement(&This
->ref
);
2943 TRACE("(%p) Refcount now %u\n", This
, ref
);
2947 static ULONG WINAPI
AudioSessionManager_Release(IAudioSessionManager2
*iface
)
2949 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2951 ref
= InterlockedDecrement(&This
->ref
);
2952 TRACE("(%p) Refcount now %u\n", This
, ref
);
2954 HeapFree(GetProcessHeap(), 0, This
);
2958 static HRESULT WINAPI
AudioSessionManager_GetAudioSessionControl(
2959 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2960 IAudioSessionControl
**out
)
2962 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2963 AudioSession
*session
;
2964 AudioSessionWrapper
*wrapper
;
2967 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2970 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
2974 wrapper
= AudioSessionWrapper_Create(NULL
);
2976 return E_OUTOFMEMORY
;
2978 wrapper
->session
= session
;
2980 *out
= (IAudioSessionControl
*)&wrapper
->IAudioSessionControl2_iface
;
2985 static HRESULT WINAPI
AudioSessionManager_GetSimpleAudioVolume(
2986 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
2987 ISimpleAudioVolume
**out
)
2989 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
2990 AudioSession
*session
;
2991 AudioSessionWrapper
*wrapper
;
2994 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
2997 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
3001 wrapper
= AudioSessionWrapper_Create(NULL
);
3003 return E_OUTOFMEMORY
;
3005 wrapper
->session
= session
;
3007 *out
= &wrapper
->ISimpleAudioVolume_iface
;
3012 static HRESULT WINAPI
AudioSessionManager_GetSessionEnumerator(
3013 IAudioSessionManager2
*iface
, IAudioSessionEnumerator
**out
)
3015 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3016 FIXME("(%p)->(%p) - stub\n", This
, out
);
3020 static HRESULT WINAPI
AudioSessionManager_RegisterSessionNotification(
3021 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
3023 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3024 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3028 static HRESULT WINAPI
AudioSessionManager_UnregisterSessionNotification(
3029 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
3031 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3032 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3036 static HRESULT WINAPI
AudioSessionManager_RegisterDuckNotification(
3037 IAudioSessionManager2
*iface
, const WCHAR
*session_id
,
3038 IAudioVolumeDuckNotification
*notification
)
3040 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3041 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3045 static HRESULT WINAPI
AudioSessionManager_UnregisterDuckNotification(
3046 IAudioSessionManager2
*iface
,
3047 IAudioVolumeDuckNotification
*notification
)
3049 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3050 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3054 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
=
3056 AudioSessionManager_QueryInterface
,
3057 AudioSessionManager_AddRef
,
3058 AudioSessionManager_Release
,
3059 AudioSessionManager_GetAudioSessionControl
,
3060 AudioSessionManager_GetSimpleAudioVolume
,
3061 AudioSessionManager_GetSessionEnumerator
,
3062 AudioSessionManager_RegisterSessionNotification
,
3063 AudioSessionManager_UnregisterSessionNotification
,
3064 AudioSessionManager_RegisterDuckNotification
,
3065 AudioSessionManager_UnregisterDuckNotification
3068 HRESULT WINAPI
AUDDRV_GetAudioSessionManager(IMMDevice
*device
,
3069 IAudioSessionManager2
**out
)
3073 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SessionMgr
));
3075 return E_OUTOFMEMORY
;
3077 This
->IAudioSessionManager2_iface
.lpVtbl
= &AudioSessionManager2_Vtbl
;
3078 This
->device
= device
;
3081 *out
= &This
->IAudioSessionManager2_iface
;