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
28 #include <sys/types.h>
30 #include <sys/ioctl.h>
34 #include <sys/soundcard.h>
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42 #include "wine/list.h"
45 #include "mmdeviceapi.h"
51 #include "endpointvolume.h"
52 #include "audiopolicy.h"
53 #include "audioclient.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(oss
);
57 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
59 static const REFERENCE_TIME DefaultPeriod
= 100000;
60 static const REFERENCE_TIME MinimumPeriod
= 50000;
63 typedef struct ACImpl ACImpl
;
65 typedef struct _AudioSession
{
76 CRITICAL_SECTION lock
;
81 typedef struct _AudioSessionWrapper
{
82 IAudioSessionControl2 IAudioSessionControl2_iface
;
83 IChannelAudioVolume IChannelAudioVolume_iface
;
84 ISimpleAudioVolume ISimpleAudioVolume_iface
;
89 AudioSession
*session
;
90 } AudioSessionWrapper
;
93 IAudioClient IAudioClient_iface
;
94 IAudioRenderClient IAudioRenderClient_iface
;
95 IAudioCaptureClient IAudioCaptureClient_iface
;
96 IAudioClock IAudioClock_iface
;
97 IAudioClock2 IAudioClock2_iface
;
98 IAudioStreamVolume IAudioStreamVolume_iface
;
103 IUnknown
*pUnkFTMarshal
;
109 AUDCLNT_SHAREMODE share
;
115 char devnode
[OSS_DEVNODE_SIZE
];
117 BOOL initted
, playing
;
118 UINT64 written_frames
, last_pos_frames
;
119 UINT32 period_us
, period_frames
, bufsize_frames
, held_frames
, tmp_buffer_frames
, in_oss_frames
;
120 UINT32 oss_bufsize_bytes
, lcl_offs_frames
; /* offs into local_buffer where valid data starts */
122 BYTE
*local_buffer
, *tmp_buffer
;
123 LONG32 getbuf_last
; /* <0 when using tmp_buffer */
126 CRITICAL_SECTION lock
;
128 AudioSession
*session
;
129 AudioSessionWrapper
*session_wrapper
;
134 typedef struct _SessionMgr
{
135 IAudioSessionManager2 IAudioSessionManager2_iface
;
142 typedef struct _OSSDevice
{
144 char devnode
[OSS_DEVNODE_SIZE
];
150 static struct list g_devices
= LIST_INIT(g_devices
);
152 static const WCHAR drv_key_devicesW
[] = {'S','o','f','t','w','a','r','e','\\',
153 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
154 'w','i','n','e','o','s','s','.','d','r','v','\\','d','e','v','i','c','e','s',0};
155 static const WCHAR guidW
[] = {'g','u','i','d',0};
157 static HANDLE g_timer_q
;
159 static CRITICAL_SECTION g_sessions_lock
;
160 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug
=
162 0, 0, &g_sessions_lock
,
163 { &g_sessions_lock_debug
.ProcessLocksList
, &g_sessions_lock_debug
.ProcessLocksList
},
164 0, 0, { (DWORD_PTR
)(__FILE__
": g_sessions_lock") }
166 static CRITICAL_SECTION g_sessions_lock
= { &g_sessions_lock_debug
, -1, 0, 0, 0, 0 };
167 static struct list g_sessions
= LIST_INIT(g_sessions
);
169 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
);
171 static const IAudioClientVtbl AudioClient_Vtbl
;
172 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
;
173 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
;
174 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
;
175 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
;
176 static const IAudioClockVtbl AudioClock_Vtbl
;
177 static const IAudioClock2Vtbl AudioClock2_Vtbl
;
178 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
;
179 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
;
180 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
;
182 static inline ACImpl
*impl_from_IAudioClient(IAudioClient
*iface
)
184 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClient_iface
);
187 static inline ACImpl
*impl_from_IAudioRenderClient(IAudioRenderClient
*iface
)
189 return CONTAINING_RECORD(iface
, ACImpl
, IAudioRenderClient_iface
);
192 static inline ACImpl
*impl_from_IAudioCaptureClient(IAudioCaptureClient
*iface
)
194 return CONTAINING_RECORD(iface
, ACImpl
, IAudioCaptureClient_iface
);
197 static inline AudioSessionWrapper
*impl_from_IAudioSessionControl2(IAudioSessionControl2
*iface
)
199 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IAudioSessionControl2_iface
);
202 static inline AudioSessionWrapper
*impl_from_ISimpleAudioVolume(ISimpleAudioVolume
*iface
)
204 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, ISimpleAudioVolume_iface
);
207 static inline AudioSessionWrapper
*impl_from_IChannelAudioVolume(IChannelAudioVolume
*iface
)
209 return CONTAINING_RECORD(iface
, AudioSessionWrapper
, IChannelAudioVolume_iface
);
212 static inline ACImpl
*impl_from_IAudioClock(IAudioClock
*iface
)
214 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock_iface
);
217 static inline ACImpl
*impl_from_IAudioClock2(IAudioClock2
*iface
)
219 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClock2_iface
);
222 static inline ACImpl
*impl_from_IAudioStreamVolume(IAudioStreamVolume
*iface
)
224 return CONTAINING_RECORD(iface
, ACImpl
, IAudioStreamVolume_iface
);
227 static inline SessionMgr
*impl_from_IAudioSessionManager2(IAudioSessionManager2
*iface
)
229 return CONTAINING_RECORD(iface
, SessionMgr
, IAudioSessionManager2_iface
);
232 BOOL WINAPI
DllMain(HINSTANCE dll
, DWORD reason
, void *reserved
)
236 case DLL_PROCESS_ATTACH
:
237 g_timer_q
= CreateTimerQueue();
242 case DLL_PROCESS_DETACH
:
245 OSSDevice
*iter
, *iter2
;
247 DeleteCriticalSection(&g_sessions_lock
);
249 LIST_FOR_EACH_ENTRY_SAFE(iter
, iter2
, &g_devices
, OSSDevice
, entry
){
250 HeapFree(GetProcessHeap(), 0, iter
);
258 /* From <dlls/mmdevapi/mmdevapi.h> */
259 enum DriverPriority
{
260 Priority_Unavailable
= 0,
266 int WINAPI
AUDDRV_GetPriority(void)
271 /* Attempt to determine if we are running on OSS or ALSA's OSS
272 * compatibility layer. There is no official way to do that, so just check
273 * for validity as best as possible, without rejecting valid OSS
274 * implementations. */
276 mixer_fd
= open("/dev/mixer", O_RDONLY
, 0);
278 TRACE("Priority_Unavailable: open failed\n");
279 return Priority_Unavailable
;
282 sysinfo
.version
[0] = 0xFF;
283 sysinfo
.versionnum
= ~0;
284 if(ioctl(mixer_fd
, SNDCTL_SYSINFO
, &sysinfo
) < 0){
285 TRACE("Priority_Unavailable: ioctl failed\n");
287 return Priority_Unavailable
;
292 if(sysinfo
.version
[0] < '4' || sysinfo
.version
[0] > '9'){
293 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo
.version
[0]);
296 if(sysinfo
.versionnum
& 0x80000000){
297 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo
.versionnum
);
301 TRACE("Priority_Preferred: Seems like valid OSS!\n");
303 return Priority_Preferred
;
306 static void set_device_guid(EDataFlow flow
, HKEY drv_key
, const WCHAR
*key_name
,
314 lr
= RegCreateKeyExW(HKEY_CURRENT_USER
, drv_key_devicesW
, 0, NULL
, 0, KEY_WRITE
,
315 NULL
, &drv_key
, NULL
);
316 if(lr
!= ERROR_SUCCESS
){
317 ERR("RegCreateKeyEx(drv_key) failed: %u\n", lr
);
323 lr
= RegCreateKeyExW(drv_key
, key_name
, 0, NULL
, 0, KEY_WRITE
,
325 if(lr
!= ERROR_SUCCESS
){
326 ERR("RegCreateKeyEx(%s) failed: %u\n", wine_dbgstr_w(key_name
), lr
);
330 lr
= RegSetValueExW(key
, guidW
, 0, REG_BINARY
, (BYTE
*)guid
,
332 if(lr
!= ERROR_SUCCESS
)
333 ERR("RegSetValueEx(%s\\guid) failed: %u\n", wine_dbgstr_w(key_name
), lr
);
338 RegCloseKey(drv_key
);
341 static void get_device_guid(EDataFlow flow
, const char *device
, GUID
*guid
)
343 HKEY key
= NULL
, dev_key
;
344 DWORD type
, size
= sizeof(*guid
);
352 MultiByteToWideChar(CP_UNIXCP
, 0, device
, -1, key_name
+ 2, ARRAY_SIZE(key_name
) - 2);
354 if(RegOpenKeyExW(HKEY_CURRENT_USER
, drv_key_devicesW
, 0, KEY_WRITE
|KEY_READ
, &key
) == ERROR_SUCCESS
){
355 if(RegOpenKeyExW(key
, key_name
, 0, KEY_READ
, &dev_key
) == ERROR_SUCCESS
){
356 if(RegQueryValueExW(dev_key
, guidW
, 0, &type
,
357 (BYTE
*)guid
, &size
) == ERROR_SUCCESS
){
358 if(type
== REG_BINARY
){
359 RegCloseKey(dev_key
);
363 ERR("Invalid type for device %s GUID: %u; ignoring and overwriting\n",
364 wine_dbgstr_w(key_name
), type
);
366 RegCloseKey(dev_key
);
372 set_device_guid(flow
, key
, key_name
, guid
);
378 static const char *oss_clean_devnode(const char *devnode
)
380 static char ret
[OSS_DEVNODE_SIZE
];
382 const char *dot
, *slash
;
385 dot
= strrchr(devnode
, '.');
389 slash
= strrchr(devnode
, '/');
390 if(slash
&& dot
< slash
)
395 memcpy(ret
, devnode
, len
);
401 static UINT
get_default_index(EDataFlow flow
)
410 fd
= open("/dev/dsp", O_WRONLY
| O_NONBLOCK
);
412 fd
= open("/dev/dsp", O_RDONLY
| O_NONBLOCK
);
415 WARN("Couldn't open default device!\n");
420 if((err
= ioctl(fd
, SNDCTL_ENGINEINFO
, &ai
)) < 0){
421 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err
, strerror(errno
));
428 TRACE("Default devnode: %s\n", ai
.devnode
);
429 devnode
= oss_clean_devnode(ai
.devnode
);
431 LIST_FOR_EACH_ENTRY(dev_item
, &g_devices
, OSSDevice
, entry
){
432 if(dev_item
->flow
== flow
){
433 if(!strcmp(devnode
, dev_item
->devnode
))
439 WARN("Couldn't find default device! Choosing first.\n");
443 HRESULT WINAPI
AUDDRV_GetEndpointIDs(EDataFlow flow
, WCHAR
***ids
, GUID
**guids
,
444 UINT
*num
, UINT
*def_index
)
448 static int print_once
= 0;
450 static const WCHAR outW
[] = {'O','u','t',':',' ',0};
451 static const WCHAR inW
[] = {'I','n',':',' ',0};
453 TRACE("%d %p %p %p %p\n", flow
, ids
, guids
, num
, def_index
);
455 mixer_fd
= open("/dev/mixer", O_RDONLY
, 0);
457 ERR("OSS /dev/mixer doesn't seem to exist\n");
458 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
461 if(ioctl(mixer_fd
, SNDCTL_SYSINFO
, &sysinfo
) < 0){
465 ERR("OSS version too old, need at least OSSv4\n");
466 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
469 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno
, strerror(errno
));
474 TRACE("OSS sysinfo:\n");
475 TRACE("product: %s\n", sysinfo
.product
);
476 TRACE("version: %s\n", sysinfo
.version
);
477 TRACE("versionnum: %x\n", sysinfo
.versionnum
);
478 TRACE("numaudios: %d\n", sysinfo
.numaudios
);
479 TRACE("nummixers: %d\n", sysinfo
.nummixers
);
480 TRACE("numcards: %d\n", sysinfo
.numcards
);
481 TRACE("numaudioengines: %d\n", sysinfo
.numaudioengines
);
485 if(sysinfo
.numaudios
<= 0){
486 WARN("No audio devices!\n");
488 return AUDCLNT_E_SERVICE_NOT_RUNNING
;
491 *ids
= HeapAlloc(GetProcessHeap(), 0, sysinfo
.numaudios
* sizeof(WCHAR
*));
492 *guids
= HeapAlloc(GetProcessHeap(), 0, sysinfo
.numaudios
* sizeof(GUID
));
495 for(i
= 0; i
< sysinfo
.numaudios
; ++i
){
496 oss_audioinfo ai
= {0};
502 if(ioctl(mixer_fd
, SNDCTL_AUDIOINFO
, &ai
) < 0){
503 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i
, errno
,
508 devnode
= oss_clean_devnode(ai
.devnode
);
510 /* check for duplicates */
511 LIST_FOR_EACH_ENTRY(dev_item
, &g_devices
, OSSDevice
, entry
){
512 if(dev_item
->flow
== flow
&& !strcmp(devnode
, dev_item
->devnode
))
515 if(&dev_item
->entry
!= &g_devices
)
519 fd
= open(devnode
, O_WRONLY
| O_NONBLOCK
, 0);
521 fd
= open(devnode
, O_RDONLY
| O_NONBLOCK
, 0);
523 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
524 devnode
, errno
, strerror(errno
));
529 if((flow
== eCapture
&& (ai
.caps
& PCM_CAP_INPUT
)) ||
530 (flow
== eRender
&& (ai
.caps
& PCM_CAP_OUTPUT
))){
531 size_t len
, prefix_len
;
534 dev_item
= HeapAlloc(GetProcessHeap(), 0, sizeof(*dev_item
));
536 dev_item
->flow
= flow
;
537 get_device_guid(flow
, devnode
, &dev_item
->guid
);
538 strcpy(dev_item
->devnode
, devnode
);
540 (*guids
)[*num
] = dev_item
->guid
;
542 len
= MultiByteToWideChar(CP_UNIXCP
, 0, ai
.name
, -1, NULL
, 0);
545 prefix_len
= ARRAY_SIZE(outW
) - 1;
549 prefix_len
= ARRAY_SIZE(inW
) - 1;
552 (*ids
)[*num
] = HeapAlloc(GetProcessHeap(), 0,
553 len
* sizeof(WCHAR
));
555 for(i
= 0; i
< *num
; ++i
)
556 HeapFree(GetProcessHeap(), 0, (*ids
)[i
]);
557 HeapFree(GetProcessHeap(), 0, *ids
);
558 HeapFree(GetProcessHeap(), 0, *guids
);
559 HeapFree(GetProcessHeap(), 0, dev_item
);
561 return E_OUTOFMEMORY
;
563 memcpy((*ids
)[*num
], prefix
, prefix_len
* sizeof(WCHAR
));
564 MultiByteToWideChar(CP_UNIXCP
, 0, ai
.name
, -1,
565 (*ids
)[*num
] + prefix_len
, len
- prefix_len
);
567 list_add_tail(&g_devices
, &dev_item
->entry
);
575 *def_index
= get_default_index(flow
);
580 static const OSSDevice
*get_ossdevice_from_guid(const GUID
*guid
)
583 LIST_FOR_EACH_ENTRY(dev_item
, &g_devices
, OSSDevice
, entry
)
584 if(IsEqualGUID(guid
, &dev_item
->guid
))
589 HRESULT WINAPI
AUDDRV_GetAudioEndpoint(GUID
*guid
, IMMDevice
*dev
,
593 const OSSDevice
*oss_dev
;
596 TRACE("%s %p %p\n", debugstr_guid(guid
), dev
, out
);
598 oss_dev
= get_ossdevice_from_guid(guid
);
600 WARN("Unknown GUID: %s\n", debugstr_guid(guid
));
601 return AUDCLNT_E_DEVICE_INVALIDATED
;
604 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ACImpl
));
606 return E_OUTOFMEMORY
;
608 hr
= CoCreateFreeThreadedMarshaler((IUnknown
*)&This
->IAudioClient_iface
, &This
->pUnkFTMarshal
);
610 HeapFree(GetProcessHeap(), 0, This
);
614 if(oss_dev
->flow
== eRender
)
615 This
->fd
= open(oss_dev
->devnode
, O_WRONLY
| O_NONBLOCK
, 0);
616 else if(oss_dev
->flow
== eCapture
)
617 This
->fd
= open(oss_dev
->devnode
, O_RDONLY
| O_NONBLOCK
, 0);
619 HeapFree(GetProcessHeap(), 0, This
);
623 WARN("Unable to open device %s: %d (%s)\n", oss_dev
->devnode
, errno
,
625 HeapFree(GetProcessHeap(), 0, This
);
626 return AUDCLNT_E_DEVICE_INVALIDATED
;
629 This
->dataflow
= oss_dev
->flow
;
632 if(ioctl(This
->fd
, SNDCTL_ENGINEINFO
, &This
->ai
) < 0){
633 WARN("Unable to get audio info for device %s: %d (%s)\n", oss_dev
->devnode
,
634 errno
, strerror(errno
));
636 HeapFree(GetProcessHeap(), 0, This
);
640 strcpy(This
->devnode
, oss_dev
->devnode
);
642 TRACE("OSS audioinfo:\n");
643 TRACE("devnode: %s\n", This
->ai
.devnode
);
644 TRACE("name: %s\n", This
->ai
.name
);
645 TRACE("busy: %x\n", This
->ai
.busy
);
646 TRACE("caps: %x\n", This
->ai
.caps
);
647 TRACE("iformats: %x\n", This
->ai
.iformats
);
648 TRACE("oformats: %x\n", This
->ai
.oformats
);
649 TRACE("enabled: %d\n", This
->ai
.enabled
);
650 TRACE("min_rate: %d\n", This
->ai
.min_rate
);
651 TRACE("max_rate: %d\n", This
->ai
.max_rate
);
652 TRACE("min_channels: %d\n", This
->ai
.min_channels
);
653 TRACE("max_channels: %d\n", This
->ai
.max_channels
);
655 This
->IAudioClient_iface
.lpVtbl
= &AudioClient_Vtbl
;
656 This
->IAudioRenderClient_iface
.lpVtbl
= &AudioRenderClient_Vtbl
;
657 This
->IAudioCaptureClient_iface
.lpVtbl
= &AudioCaptureClient_Vtbl
;
658 This
->IAudioClock_iface
.lpVtbl
= &AudioClock_Vtbl
;
659 This
->IAudioClock2_iface
.lpVtbl
= &AudioClock2_Vtbl
;
660 This
->IAudioStreamVolume_iface
.lpVtbl
= &AudioStreamVolume_Vtbl
;
662 InitializeCriticalSection(&This
->lock
);
663 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": ACImpl.lock");
666 IMMDevice_AddRef(This
->parent
);
668 IAudioClient_AddRef(&This
->IAudioClient_iface
);
670 *out
= &This
->IAudioClient_iface
;
675 static HRESULT WINAPI
AudioClient_QueryInterface(IAudioClient
*iface
,
676 REFIID riid
, void **ppv
)
678 ACImpl
*This
= impl_from_IAudioClient(iface
);
679 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
684 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClient
))
686 else if(IsEqualIID(riid
, &IID_IMarshal
))
687 return IUnknown_QueryInterface(This
->pUnkFTMarshal
, riid
, ppv
);
689 IUnknown_AddRef((IUnknown
*)*ppv
);
692 WARN("Unknown interface %s\n", debugstr_guid(riid
));
693 return E_NOINTERFACE
;
696 static ULONG WINAPI
AudioClient_AddRef(IAudioClient
*iface
)
698 ACImpl
*This
= impl_from_IAudioClient(iface
);
700 ref
= InterlockedIncrement(&This
->ref
);
701 TRACE("(%p) Refcount now %u\n", This
, ref
);
705 static ULONG WINAPI
AudioClient_Release(IAudioClient
*iface
)
707 ACImpl
*This
= impl_from_IAudioClient(iface
);
710 ref
= InterlockedDecrement(&This
->ref
);
711 TRACE("(%p) Refcount now %u\n", This
, ref
);
716 event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
717 wait
= !DeleteTimerQueueTimer(g_timer_q
, This
->timer
, event
);
718 wait
= wait
&& GetLastError() == ERROR_IO_PENDING
;
720 WaitForSingleObject(event
, INFINITE
);
724 IAudioClient_Stop(iface
);
725 IMMDevice_Release(This
->parent
);
726 IUnknown_Release(This
->pUnkFTMarshal
);
727 This
->lock
.DebugInfo
->Spare
[0] = 0;
728 DeleteCriticalSection(&This
->lock
);
731 EnterCriticalSection(&g_sessions_lock
);
732 list_remove(&This
->entry
);
733 LeaveCriticalSection(&g_sessions_lock
);
735 HeapFree(GetProcessHeap(), 0, This
->vols
);
736 HeapFree(GetProcessHeap(), 0, This
->local_buffer
);
737 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
738 CoTaskMemFree(This
->fmt
);
739 HeapFree(GetProcessHeap(), 0, This
);
744 static void dump_fmt(const WAVEFORMATEX
*fmt
)
746 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
747 switch(fmt
->wFormatTag
){
748 case WAVE_FORMAT_PCM
:
749 TRACE("WAVE_FORMAT_PCM");
751 case WAVE_FORMAT_IEEE_FLOAT
:
752 TRACE("WAVE_FORMAT_IEEE_FLOAT");
754 case WAVE_FORMAT_EXTENSIBLE
:
755 TRACE("WAVE_FORMAT_EXTENSIBLE");
763 TRACE("nChannels: %u\n", fmt
->nChannels
);
764 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
765 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
766 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
767 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
768 TRACE("cbSize: %u\n", fmt
->cbSize
);
770 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
771 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
772 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
773 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
774 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
778 static DWORD
get_channel_mask(unsigned int channels
)
784 return KSAUDIO_SPEAKER_MONO
;
786 return KSAUDIO_SPEAKER_STEREO
;
788 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
790 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
792 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
794 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
796 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
798 return KSAUDIO_SPEAKER_7POINT1_SURROUND
; /* Vista deprecates 7POINT1 */
800 FIXME("Unknown speaker configuration: %u\n", channels
);
804 static int get_oss_format(const WAVEFORMATEX
*fmt
)
806 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)fmt
;
808 if(fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
809 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
810 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))){
811 switch(fmt
->wBitsPerSample
){
825 if(fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
||
826 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
827 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))){
828 if(fmt
->wBitsPerSample
!= 32)
838 static WAVEFORMATEX
*clone_format(const WAVEFORMATEX
*fmt
)
843 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
844 size
= sizeof(WAVEFORMATEXTENSIBLE
);
846 size
= sizeof(WAVEFORMATEX
);
848 ret
= CoTaskMemAlloc(size
);
852 memcpy(ret
, fmt
, size
);
854 ret
->cbSize
= size
- sizeof(WAVEFORMATEX
);
859 static HRESULT
setup_oss_device(AUDCLNT_SHAREMODE mode
, int fd
,
860 const WAVEFORMATEX
*fmt
, WAVEFORMATEX
**out
)
865 WAVEFORMATEX
*closest
= NULL
;
867 tmp
= oss_format
= get_oss_format(fmt
);
869 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
870 if(ioctl(fd
, SNDCTL_DSP_SETFMT
, &tmp
) < 0){
871 WARN("SETFMT failed: %d (%s)\n", errno
, strerror(errno
));
874 if(tmp
!= oss_format
){
875 TRACE("Format unsupported by this OSS version: %x\n", oss_format
);
876 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
879 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
880 (fmt
->nAvgBytesPerSec
== 0 ||
881 fmt
->nBlockAlign
== 0 ||
882 ((WAVEFORMATEXTENSIBLE
*)fmt
)->Samples
.wValidBitsPerSample
> fmt
->wBitsPerSample
))
885 if(fmt
->nChannels
== 0)
886 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
888 closest
= clone_format(fmt
);
890 return E_OUTOFMEMORY
;
892 tmp
= fmt
->nSamplesPerSec
;
893 if(ioctl(fd
, SNDCTL_DSP_SPEED
, &tmp
) < 0){
894 WARN("SPEED failed: %d (%s)\n", errno
, strerror(errno
));
895 CoTaskMemFree(closest
);
898 tenth
= fmt
->nSamplesPerSec
* 0.1;
899 if(tmp
> fmt
->nSamplesPerSec
+ tenth
|| tmp
< fmt
->nSamplesPerSec
- tenth
){
901 closest
->nSamplesPerSec
= tmp
;
904 tmp
= fmt
->nChannels
;
905 if(ioctl(fd
, SNDCTL_DSP_CHANNELS
, &tmp
) < 0){
906 WARN("CHANNELS failed: %d (%s)\n", errno
, strerror(errno
));
907 CoTaskMemFree(closest
);
910 if(tmp
!= fmt
->nChannels
){
912 closest
->nChannels
= tmp
;
915 if(closest
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
916 ((WAVEFORMATEXTENSIBLE
*)closest
)->dwChannelMask
= get_channel_mask(closest
->nChannels
);
918 if(fmt
->nBlockAlign
!= fmt
->nChannels
* fmt
->wBitsPerSample
/ 8 ||
919 fmt
->nAvgBytesPerSec
!= fmt
->nBlockAlign
* fmt
->nSamplesPerSec
||
920 (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
921 ((WAVEFORMATEXTENSIBLE
*)fmt
)->Samples
.wValidBitsPerSample
< fmt
->wBitsPerSample
))
924 if(mode
== AUDCLNT_SHAREMODE_EXCLUSIVE
&&
925 fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
926 if(((WAVEFORMATEXTENSIBLE
*)fmt
)->dwChannelMask
== 0 ||
927 ((WAVEFORMATEXTENSIBLE
*)fmt
)->dwChannelMask
& SPEAKER_RESERVED
)
931 if(ret
== S_FALSE
&& !out
)
932 ret
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
934 if(ret
== S_FALSE
&& out
){
935 closest
->nBlockAlign
=
936 closest
->nChannels
* closest
->wBitsPerSample
/ 8;
937 closest
->nAvgBytesPerSec
=
938 closest
->nBlockAlign
* closest
->nSamplesPerSec
;
939 if(closest
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
940 ((WAVEFORMATEXTENSIBLE
*)closest
)->Samples
.wValidBitsPerSample
= closest
->wBitsPerSample
;
943 CoTaskMemFree(closest
);
945 TRACE("returning: %08x\n", ret
);
949 static void session_init_vols(AudioSession
*session
, UINT channels
)
951 if(session
->channel_count
< channels
){
954 if(session
->channel_vols
)
955 session
->channel_vols
= HeapReAlloc(GetProcessHeap(), 0,
956 session
->channel_vols
, sizeof(float) * channels
);
958 session
->channel_vols
= HeapAlloc(GetProcessHeap(), 0,
959 sizeof(float) * channels
);
960 if(!session
->channel_vols
)
963 for(i
= session
->channel_count
; i
< channels
; ++i
)
964 session
->channel_vols
[i
] = 1.f
;
966 session
->channel_count
= channels
;
970 static AudioSession
*create_session(const GUID
*guid
, IMMDevice
*device
,
975 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AudioSession
));
979 memcpy(&ret
->guid
, guid
, sizeof(GUID
));
981 ret
->device
= device
;
983 list_init(&ret
->clients
);
985 list_add_head(&g_sessions
, &ret
->entry
);
987 InitializeCriticalSection(&ret
->lock
);
988 ret
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": AudioSession.lock");
990 session_init_vols(ret
, num_channels
);
992 ret
->master_vol
= 1.f
;
997 /* if channels == 0, then this will return or create a session with
998 * matching dataflow and GUID. otherwise, channels must also match */
999 static HRESULT
get_audio_session(const GUID
*sessionguid
,
1000 IMMDevice
*device
, UINT channels
, AudioSession
**out
)
1002 AudioSession
*session
;
1004 if(!sessionguid
|| IsEqualGUID(sessionguid
, &GUID_NULL
)){
1005 *out
= create_session(&GUID_NULL
, device
, channels
);
1007 return E_OUTOFMEMORY
;
1013 LIST_FOR_EACH_ENTRY(session
, &g_sessions
, AudioSession
, entry
){
1014 if(session
->device
== device
&&
1015 IsEqualGUID(sessionguid
, &session
->guid
)){
1016 session_init_vols(session
, channels
);
1023 *out
= create_session(sessionguid
, device
, channels
);
1025 return E_OUTOFMEMORY
;
1031 static HRESULT WINAPI
AudioClient_Initialize(IAudioClient
*iface
,
1032 AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
,
1033 REFERENCE_TIME period
, const WAVEFORMATEX
*fmt
,
1034 const GUID
*sessionguid
)
1036 ACImpl
*This
= impl_from_IAudioClient(iface
);
1040 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This
, mode
, flags
,
1041 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(period
), fmt
, debugstr_guid(sessionguid
));
1048 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
1049 return E_INVALIDARG
;
1051 if(flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
|
1052 AUDCLNT_STREAMFLAGS_LOOPBACK
|
1053 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
1054 AUDCLNT_STREAMFLAGS_NOPERSIST
|
1055 AUDCLNT_STREAMFLAGS_RATEADJUST
|
1056 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
|
1057 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
|
1058 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
)){
1059 TRACE("Unknown flags: %08x\n", flags
);
1060 return E_INVALIDARG
;
1063 if(mode
== AUDCLNT_SHAREMODE_SHARED
){
1064 period
= DefaultPeriod
;
1065 if( duration
< 3 * period
)
1066 duration
= 3 * period
;
1069 period
= DefaultPeriod
; /* not minimum */
1070 if(period
< MinimumPeriod
|| period
> 5000000)
1071 return AUDCLNT_E_INVALID_DEVICE_PERIOD
;
1072 if(duration
> 20000000) /* the smaller the period, the lower this limit */
1073 return AUDCLNT_E_BUFFER_SIZE_ERROR
;
1074 if(flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
){
1075 if(duration
!= period
)
1076 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL
;
1077 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
1078 return AUDCLNT_E_DEVICE_IN_USE
;
1080 if( duration
< 8 * period
)
1081 duration
= 8 * period
; /* may grow above 2s */
1085 EnterCriticalSection(&This
->lock
);
1088 LeaveCriticalSection(&This
->lock
);
1089 return AUDCLNT_E_ALREADY_INITIALIZED
;
1092 hr
= setup_oss_device(mode
, This
->fd
, fmt
, NULL
);
1094 LeaveCriticalSection(&This
->lock
);
1098 This
->fmt
= clone_format(fmt
);
1100 LeaveCriticalSection(&This
->lock
);
1101 return E_OUTOFMEMORY
;
1104 This
->period_us
= period
/ 10;
1105 This
->period_frames
= MulDiv(fmt
->nSamplesPerSec
, period
, 10000000);
1107 This
->bufsize_frames
= MulDiv(duration
, fmt
->nSamplesPerSec
, 10000000);
1108 if(mode
== AUDCLNT_SHAREMODE_EXCLUSIVE
)
1109 This
->bufsize_frames
-= This
->bufsize_frames
% This
->period_frames
;
1110 This
->local_buffer
= HeapAlloc(GetProcessHeap(), 0,
1111 This
->bufsize_frames
* fmt
->nBlockAlign
);
1112 if(!This
->local_buffer
){
1113 CoTaskMemFree(This
->fmt
);
1115 LeaveCriticalSection(&This
->lock
);
1116 return E_OUTOFMEMORY
;
1119 This
->vols
= HeapAlloc(GetProcessHeap(), 0, fmt
->nChannels
* sizeof(float));
1121 CoTaskMemFree(This
->fmt
);
1123 LeaveCriticalSection(&This
->lock
);
1124 return E_OUTOFMEMORY
;
1127 for(i
= 0; i
< fmt
->nChannels
; ++i
)
1128 This
->vols
[i
] = 1.f
;
1131 This
->flags
= flags
;
1132 This
->oss_bufsize_bytes
= 0;
1134 EnterCriticalSection(&g_sessions_lock
);
1136 hr
= get_audio_session(sessionguid
, This
->parent
, fmt
->nChannels
,
1139 LeaveCriticalSection(&g_sessions_lock
);
1140 HeapFree(GetProcessHeap(), 0, This
->vols
);
1142 CoTaskMemFree(This
->fmt
);
1144 LeaveCriticalSection(&This
->lock
);
1148 list_add_tail(&This
->session
->clients
, &This
->entry
);
1150 LeaveCriticalSection(&g_sessions_lock
);
1152 This
->initted
= TRUE
;
1154 LeaveCriticalSection(&This
->lock
);
1159 static HRESULT WINAPI
AudioClient_GetBufferSize(IAudioClient
*iface
,
1162 ACImpl
*This
= impl_from_IAudioClient(iface
);
1164 TRACE("(%p)->(%p)\n", This
, frames
);
1169 EnterCriticalSection(&This
->lock
);
1172 LeaveCriticalSection(&This
->lock
);
1173 return AUDCLNT_E_NOT_INITIALIZED
;
1176 *frames
= This
->bufsize_frames
;
1178 TRACE("buffer size: %u\n", *frames
);
1180 LeaveCriticalSection(&This
->lock
);
1185 static HRESULT WINAPI
AudioClient_GetStreamLatency(IAudioClient
*iface
,
1186 REFERENCE_TIME
*latency
)
1188 ACImpl
*This
= impl_from_IAudioClient(iface
);
1190 TRACE("(%p)->(%p)\n", This
, latency
);
1195 EnterCriticalSection(&This
->lock
);
1198 LeaveCriticalSection(&This
->lock
);
1199 return AUDCLNT_E_NOT_INITIALIZED
;
1202 /* pretend we process audio in Period chunks, so max latency includes
1203 * the period time. Some native machines add .6666ms in shared mode. */
1204 *latency
= (REFERENCE_TIME
)This
->period_us
* 10 + 6666;
1206 LeaveCriticalSection(&This
->lock
);
1211 static HRESULT WINAPI
AudioClient_GetCurrentPadding(IAudioClient
*iface
,
1214 ACImpl
*This
= impl_from_IAudioClient(iface
);
1216 TRACE("(%p)->(%p)\n", This
, numpad
);
1221 EnterCriticalSection(&This
->lock
);
1224 LeaveCriticalSection(&This
->lock
);
1225 return AUDCLNT_E_NOT_INITIALIZED
;
1228 *numpad
= This
->held_frames
;
1230 TRACE("padding: %u\n", *numpad
);
1232 LeaveCriticalSection(&This
->lock
);
1237 static HRESULT WINAPI
AudioClient_IsFormatSupported(IAudioClient
*iface
,
1238 AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
,
1239 WAVEFORMATEX
**outpwfx
)
1241 ACImpl
*This
= impl_from_IAudioClient(iface
);
1245 TRACE("(%p)->(%x, %p, %p)\n", This
, mode
, pwfx
, outpwfx
);
1247 if(!pwfx
|| (mode
== AUDCLNT_SHAREMODE_SHARED
&& !outpwfx
))
1250 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
1251 return E_INVALIDARG
;
1253 if(pwfx
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1254 pwfx
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
))
1255 return E_INVALIDARG
;
1261 if(mode
!= AUDCLNT_SHAREMODE_SHARED
)
1265 if(This
->dataflow
== eRender
)
1266 fd
= open(This
->devnode
, O_WRONLY
| O_NONBLOCK
, 0);
1267 else if(This
->dataflow
== eCapture
)
1268 fd
= open(This
->devnode
, O_RDONLY
| O_NONBLOCK
, 0);
1271 WARN("Unable to open device %s: %d (%s)\n", This
->devnode
, errno
,
1273 return AUDCLNT_E_DEVICE_INVALIDATED
;
1276 ret
= setup_oss_device(mode
, fd
, pwfx
, outpwfx
);
1283 static HRESULT WINAPI
AudioClient_GetMixFormat(IAudioClient
*iface
,
1284 WAVEFORMATEX
**pwfx
)
1286 ACImpl
*This
= impl_from_IAudioClient(iface
);
1287 WAVEFORMATEXTENSIBLE
*fmt
;
1290 TRACE("(%p)->(%p)\n", This
, pwfx
);
1296 if(This
->dataflow
== eRender
)
1297 formats
= This
->ai
.oformats
;
1298 else if(This
->dataflow
== eCapture
)
1299 formats
= This
->ai
.iformats
;
1301 return E_UNEXPECTED
;
1303 fmt
= CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE
));
1305 return E_OUTOFMEMORY
;
1307 fmt
->Format
.wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
1308 if(formats
& AFMT_S16_LE
){
1309 fmt
->Format
.wBitsPerSample
= 16;
1310 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1312 }else if(formats
& AFMT_FLOAT
){
1313 fmt
->Format
.wBitsPerSample
= 32;
1314 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
1316 }else if(formats
& AFMT_U8
){
1317 fmt
->Format
.wBitsPerSample
= 8;
1318 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1319 }else if(formats
& AFMT_S32_LE
){
1320 fmt
->Format
.wBitsPerSample
= 32;
1321 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1322 }else if(formats
& AFMT_S24_LE
){
1323 fmt
->Format
.wBitsPerSample
= 24;
1324 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
1326 WARN("Didn't recognize any available OSS formats: %x\n", formats
);
1331 /* some OSS drivers are buggy, so set reasonable defaults if
1332 * the reported values seem wacky */
1333 fmt
->Format
.nChannels
= max(This
->ai
.max_channels
, This
->ai
.min_channels
);
1334 if(fmt
->Format
.nChannels
== 0 || fmt
->Format
.nChannels
> 8)
1335 fmt
->Format
.nChannels
= 2;
1337 /* For most hardware on Windows, users must choose a configuration with an even
1338 * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
1339 * channels, but those channels are still reported to applications from
1340 * GetMixFormat! Some applications behave badly if given an odd number of
1341 * channels (e.g. 2.1). */
1342 if(fmt
->Format
.nChannels
> 1 && (fmt
->Format
.nChannels
& 0x1))
1344 if(fmt
->Format
.nChannels
< This
->ai
.max_channels
)
1345 fmt
->Format
.nChannels
+= 1;
1347 /* We could "fake" more channels and downmix the emulated channels,
1348 * but at that point you really ought to tweak your OSS setup or
1349 * just use PulseAudio. */
1350 WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt
->Format
.nChannels
);
1353 if(This
->ai
.max_rate
== 0)
1354 fmt
->Format
.nSamplesPerSec
= 44100;
1356 fmt
->Format
.nSamplesPerSec
= min(This
->ai
.max_rate
, 44100);
1357 if(fmt
->Format
.nSamplesPerSec
< This
->ai
.min_rate
)
1358 fmt
->Format
.nSamplesPerSec
= This
->ai
.min_rate
;
1360 fmt
->dwChannelMask
= get_channel_mask(fmt
->Format
.nChannels
);
1362 fmt
->Format
.nBlockAlign
= (fmt
->Format
.wBitsPerSample
*
1363 fmt
->Format
.nChannels
) / 8;
1364 fmt
->Format
.nAvgBytesPerSec
= fmt
->Format
.nSamplesPerSec
*
1365 fmt
->Format
.nBlockAlign
;
1367 fmt
->Samples
.wValidBitsPerSample
= fmt
->Format
.wBitsPerSample
;
1368 fmt
->Format
.cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
1370 *pwfx
= (WAVEFORMATEX
*)fmt
;
1376 static HRESULT WINAPI
AudioClient_GetDevicePeriod(IAudioClient
*iface
,
1377 REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
1379 ACImpl
*This
= impl_from_IAudioClient(iface
);
1381 TRACE("(%p)->(%p, %p)\n", This
, defperiod
, minperiod
);
1383 if(!defperiod
&& !minperiod
)
1387 *defperiod
= DefaultPeriod
;
1389 *minperiod
= MinimumPeriod
;
1394 static void silence_buffer(ACImpl
*This
, BYTE
*buffer
, UINT32 frames
)
1396 WAVEFORMATEXTENSIBLE
*fmtex
= (WAVEFORMATEXTENSIBLE
*)This
->fmt
;
1397 if((This
->fmt
->wFormatTag
== WAVE_FORMAT_PCM
||
1398 (This
->fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1399 IsEqualGUID(&fmtex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
))) &&
1400 This
->fmt
->wBitsPerSample
== 8)
1401 memset(buffer
, 128, frames
* This
->fmt
->nBlockAlign
);
1403 memset(buffer
, 0, frames
* This
->fmt
->nBlockAlign
);
1406 static void oss_write_data(ACImpl
*This
)
1408 ssize_t written_bytes
;
1409 UINT32 written_frames
, in_oss_frames
, write_limit
, max_period
, write_offs_frames
, new_frames
;
1410 SIZE_T to_write_frames
, to_write_bytes
, advanced
;
1414 if(ioctl(This
->fd
, SNDCTL_DSP_GETOSPACE
, &bi
) < 0){
1415 WARN("GETOSPACE failed: %d (%s)\n", errno
, strerror(errno
));
1419 max_period
= max(bi
.fragsize
/ This
->fmt
->nBlockAlign
, This
->period_frames
);
1421 if(bi
.bytes
> This
->oss_bufsize_bytes
){
1422 TRACE("New buffer size (%u) is larger than old buffer size (%u)\n",
1423 bi
.bytes
, This
->oss_bufsize_bytes
);
1424 This
->oss_bufsize_bytes
= bi
.bytes
;
1427 in_oss_frames
= (This
->oss_bufsize_bytes
- bi
.bytes
) / This
->fmt
->nBlockAlign
;
1429 if(in_oss_frames
> This
->in_oss_frames
){
1430 TRACE("Capping reported frames from %u to %u\n",
1431 in_oss_frames
, This
->in_oss_frames
);
1432 in_oss_frames
= This
->in_oss_frames
;
1436 while(write_limit
+ in_oss_frames
< max_period
* 3)
1437 write_limit
+= max_period
;
1438 if(write_limit
== 0)
1441 /* vvvvvv - in_oss_frames
1444 * ^^^^^^^^^^ - held_frames
1445 * ^ - lcl_offs_frames
1447 advanced
= This
->in_oss_frames
- in_oss_frames
;
1448 if(advanced
> This
->held_frames
)
1449 advanced
= This
->held_frames
;
1450 This
->lcl_offs_frames
+= advanced
;
1451 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1452 This
->held_frames
-= advanced
;
1453 This
->in_oss_frames
= in_oss_frames
;
1454 TRACE("advanced by %lu, lcl_offs: %u, held: %u, in_oss: %u\n",
1455 advanced
, This
->lcl_offs_frames
, This
->held_frames
, This
->in_oss_frames
);
1458 if(This
->held_frames
== This
->in_oss_frames
)
1461 write_offs_frames
= (This
->lcl_offs_frames
+ This
->in_oss_frames
) % This
->bufsize_frames
;
1462 new_frames
= This
->held_frames
- This
->in_oss_frames
;
1464 if(write_offs_frames
+ new_frames
> This
->bufsize_frames
)
1465 to_write_frames
= This
->bufsize_frames
- write_offs_frames
;
1467 to_write_frames
= new_frames
;
1469 to_write_frames
= min(to_write_frames
, write_limit
);
1470 to_write_bytes
= to_write_frames
* This
->fmt
->nBlockAlign
;
1471 TRACE("going to write %lu frames from %u (%lu of %u)\n", to_write_frames
,
1472 write_offs_frames
, to_write_frames
+ write_offs_frames
,
1473 This
->bufsize_frames
);
1475 buf
= This
->local_buffer
+ write_offs_frames
* This
->fmt
->nBlockAlign
;
1477 if(This
->session
->mute
)
1478 silence_buffer(This
, buf
, to_write_frames
);
1480 written_bytes
= write(This
->fd
, buf
, to_write_bytes
);
1481 if(written_bytes
< 0){
1482 /* EAGAIN is OSS buffer full, log that too */
1483 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1486 written_frames
= written_bytes
/ This
->fmt
->nBlockAlign
;
1488 This
->in_oss_frames
+= written_frames
;
1490 if(written_frames
< to_write_frames
){
1491 /* OSS buffer probably full */
1495 if(new_frames
> written_frames
&& written_frames
< write_limit
){
1496 /* wrapped and have some data back at the start to write */
1498 to_write_frames
= min(write_limit
- written_frames
, new_frames
- written_frames
);
1499 to_write_bytes
= to_write_frames
* This
->fmt
->nBlockAlign
;
1501 if(This
->session
->mute
)
1502 silence_buffer(This
, This
->local_buffer
, to_write_frames
);
1504 TRACE("wrapping to write %lu frames from beginning\n", to_write_frames
);
1506 written_bytes
= write(This
->fd
, This
->local_buffer
, to_write_bytes
);
1507 if(written_bytes
< 0){
1508 WARN("write failed: %d (%s)\n", errno
, strerror(errno
));
1511 written_frames
= written_bytes
/ This
->fmt
->nBlockAlign
;
1512 This
->in_oss_frames
+= written_frames
;
1516 static void oss_read_data(ACImpl
*This
)
1518 UINT64 pos
, readable
;
1521 pos
= (This
->held_frames
+ This
->lcl_offs_frames
) % This
->bufsize_frames
;
1522 readable
= (This
->bufsize_frames
- pos
) * This
->fmt
->nBlockAlign
;
1524 nread
= read(This
->fd
, This
->local_buffer
+ pos
* This
->fmt
->nBlockAlign
,
1527 WARN("read failed: %d (%s)\n", errno
, strerror(errno
));
1531 This
->held_frames
+= nread
/ This
->fmt
->nBlockAlign
;
1533 if(This
->held_frames
> This
->bufsize_frames
){
1534 WARN("Overflow of unread data\n");
1535 This
->lcl_offs_frames
+= This
->held_frames
;
1536 This
->lcl_offs_frames
%= This
->bufsize_frames
;
1537 This
->held_frames
= This
->bufsize_frames
;
1541 static void CALLBACK
oss_period_callback(void *user
, BOOLEAN timer
)
1543 ACImpl
*This
= user
;
1545 EnterCriticalSection(&This
->lock
);
1548 if(This
->dataflow
== eRender
&& This
->held_frames
)
1549 oss_write_data(This
);
1550 else if(This
->dataflow
== eCapture
)
1551 oss_read_data(This
);
1554 LeaveCriticalSection(&This
->lock
);
1557 SetEvent(This
->event
);
1560 static HRESULT WINAPI
AudioClient_Start(IAudioClient
*iface
)
1562 ACImpl
*This
= impl_from_IAudioClient(iface
);
1564 TRACE("(%p)\n", This
);
1566 EnterCriticalSection(&This
->lock
);
1569 LeaveCriticalSection(&This
->lock
);
1570 return AUDCLNT_E_NOT_INITIALIZED
;
1573 if((This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !This
->event
){
1574 LeaveCriticalSection(&This
->lock
);
1575 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1579 LeaveCriticalSection(&This
->lock
);
1580 return AUDCLNT_E_NOT_STOPPED
;
1584 if(!CreateTimerQueueTimer(&This
->timer
, g_timer_q
,
1585 oss_period_callback
, This
, 0, This
->period_us
/ 1000,
1586 WT_EXECUTEINTIMERTHREAD
))
1587 ERR("Unable to create period timer: %u\n", GetLastError());
1590 This
->playing
= TRUE
;
1592 LeaveCriticalSection(&This
->lock
);
1597 static HRESULT WINAPI
AudioClient_Stop(IAudioClient
*iface
)
1599 ACImpl
*This
= impl_from_IAudioClient(iface
);
1601 TRACE("(%p)\n", This
);
1603 EnterCriticalSection(&This
->lock
);
1606 LeaveCriticalSection(&This
->lock
);
1607 return AUDCLNT_E_NOT_INITIALIZED
;
1611 LeaveCriticalSection(&This
->lock
);
1615 This
->playing
= FALSE
;
1616 This
->in_oss_frames
= 0;
1618 LeaveCriticalSection(&This
->lock
);
1623 static HRESULT WINAPI
AudioClient_Reset(IAudioClient
*iface
)
1625 ACImpl
*This
= impl_from_IAudioClient(iface
);
1627 TRACE("(%p)\n", This
);
1629 EnterCriticalSection(&This
->lock
);
1632 LeaveCriticalSection(&This
->lock
);
1633 return AUDCLNT_E_NOT_INITIALIZED
;
1637 LeaveCriticalSection(&This
->lock
);
1638 return AUDCLNT_E_NOT_STOPPED
;
1641 if(This
->getbuf_last
){
1642 LeaveCriticalSection(&This
->lock
);
1643 return AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1646 if(This
->dataflow
== eRender
){
1647 This
->written_frames
= 0;
1648 This
->last_pos_frames
= 0;
1650 This
->written_frames
+= This
->held_frames
;
1652 This
->held_frames
= 0;
1653 This
->lcl_offs_frames
= 0;
1654 This
->in_oss_frames
= 0;
1656 LeaveCriticalSection(&This
->lock
);
1661 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient
*iface
,
1664 ACImpl
*This
= impl_from_IAudioClient(iface
);
1666 TRACE("(%p)->(%p)\n", This
, event
);
1669 return E_INVALIDARG
;
1671 EnterCriticalSection(&This
->lock
);
1674 LeaveCriticalSection(&This
->lock
);
1675 return AUDCLNT_E_NOT_INITIALIZED
;
1678 if(!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
)){
1679 LeaveCriticalSection(&This
->lock
);
1680 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1684 LeaveCriticalSection(&This
->lock
);
1685 FIXME("called twice\n");
1686 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
1689 This
->event
= event
;
1691 LeaveCriticalSection(&This
->lock
);
1696 static HRESULT WINAPI
AudioClient_GetService(IAudioClient
*iface
, REFIID riid
,
1699 ACImpl
*This
= impl_from_IAudioClient(iface
);
1701 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1707 EnterCriticalSection(&This
->lock
);
1710 LeaveCriticalSection(&This
->lock
);
1711 return AUDCLNT_E_NOT_INITIALIZED
;
1714 if(IsEqualIID(riid
, &IID_IAudioRenderClient
)){
1715 if(This
->dataflow
!= eRender
){
1716 LeaveCriticalSection(&This
->lock
);
1717 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1719 IAudioRenderClient_AddRef(&This
->IAudioRenderClient_iface
);
1720 *ppv
= &This
->IAudioRenderClient_iface
;
1721 }else if(IsEqualIID(riid
, &IID_IAudioCaptureClient
)){
1722 if(This
->dataflow
!= eCapture
){
1723 LeaveCriticalSection(&This
->lock
);
1724 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1726 IAudioCaptureClient_AddRef(&This
->IAudioCaptureClient_iface
);
1727 *ppv
= &This
->IAudioCaptureClient_iface
;
1728 }else if(IsEqualIID(riid
, &IID_IAudioClock
)){
1729 IAudioClock_AddRef(&This
->IAudioClock_iface
);
1730 *ppv
= &This
->IAudioClock_iface
;
1731 }else if(IsEqualIID(riid
, &IID_IAudioStreamVolume
)){
1732 IAudioStreamVolume_AddRef(&This
->IAudioStreamVolume_iface
);
1733 *ppv
= &This
->IAudioStreamVolume_iface
;
1734 }else if(IsEqualIID(riid
, &IID_IAudioSessionControl
)){
1735 if(!This
->session_wrapper
){
1736 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1737 if(!This
->session_wrapper
){
1738 LeaveCriticalSection(&This
->lock
);
1739 return E_OUTOFMEMORY
;
1742 IAudioSessionControl2_AddRef(&This
->session_wrapper
->IAudioSessionControl2_iface
);
1744 *ppv
= &This
->session_wrapper
->IAudioSessionControl2_iface
;
1745 }else if(IsEqualIID(riid
, &IID_IChannelAudioVolume
)){
1746 if(!This
->session_wrapper
){
1747 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1748 if(!This
->session_wrapper
){
1749 LeaveCriticalSection(&This
->lock
);
1750 return E_OUTOFMEMORY
;
1753 IChannelAudioVolume_AddRef(&This
->session_wrapper
->IChannelAudioVolume_iface
);
1755 *ppv
= &This
->session_wrapper
->IChannelAudioVolume_iface
;
1756 }else if(IsEqualIID(riid
, &IID_ISimpleAudioVolume
)){
1757 if(!This
->session_wrapper
){
1758 This
->session_wrapper
= AudioSessionWrapper_Create(This
);
1759 if(!This
->session_wrapper
){
1760 LeaveCriticalSection(&This
->lock
);
1761 return E_OUTOFMEMORY
;
1764 ISimpleAudioVolume_AddRef(&This
->session_wrapper
->ISimpleAudioVolume_iface
);
1766 *ppv
= &This
->session_wrapper
->ISimpleAudioVolume_iface
;
1770 LeaveCriticalSection(&This
->lock
);
1774 LeaveCriticalSection(&This
->lock
);
1776 FIXME("stub %s\n", debugstr_guid(riid
));
1777 return E_NOINTERFACE
;
1780 static const IAudioClientVtbl AudioClient_Vtbl
=
1782 AudioClient_QueryInterface
,
1784 AudioClient_Release
,
1785 AudioClient_Initialize
,
1786 AudioClient_GetBufferSize
,
1787 AudioClient_GetStreamLatency
,
1788 AudioClient_GetCurrentPadding
,
1789 AudioClient_IsFormatSupported
,
1790 AudioClient_GetMixFormat
,
1791 AudioClient_GetDevicePeriod
,
1795 AudioClient_SetEventHandle
,
1796 AudioClient_GetService
1799 static HRESULT WINAPI
AudioRenderClient_QueryInterface(
1800 IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1802 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1803 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1809 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1810 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1812 else if(IsEqualIID(riid
, &IID_IMarshal
))
1813 return IUnknown_QueryInterface(This
->pUnkFTMarshal
, riid
, ppv
);
1815 IUnknown_AddRef((IUnknown
*)*ppv
);
1819 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1820 return E_NOINTERFACE
;
1823 static ULONG WINAPI
AudioRenderClient_AddRef(IAudioRenderClient
*iface
)
1825 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1826 return AudioClient_AddRef(&This
->IAudioClient_iface
);
1829 static ULONG WINAPI
AudioRenderClient_Release(IAudioRenderClient
*iface
)
1831 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1832 return AudioClient_Release(&This
->IAudioClient_iface
);
1835 static HRESULT WINAPI
AudioRenderClient_GetBuffer(IAudioRenderClient
*iface
,
1836 UINT32 frames
, BYTE
**data
)
1838 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1841 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
1848 EnterCriticalSection(&This
->lock
);
1850 if(This
->getbuf_last
){
1851 LeaveCriticalSection(&This
->lock
);
1852 return AUDCLNT_E_OUT_OF_ORDER
;
1856 LeaveCriticalSection(&This
->lock
);
1860 if(This
->held_frames
+ frames
> This
->bufsize_frames
){
1861 LeaveCriticalSection(&This
->lock
);
1862 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1866 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1867 if(write_pos
+ frames
> This
->bufsize_frames
){
1868 if(This
->tmp_buffer_frames
< frames
){
1869 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
1870 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
1871 frames
* This
->fmt
->nBlockAlign
);
1872 if(!This
->tmp_buffer
){
1873 LeaveCriticalSection(&This
->lock
);
1874 return E_OUTOFMEMORY
;
1876 This
->tmp_buffer_frames
= frames
;
1878 *data
= This
->tmp_buffer
;
1879 This
->getbuf_last
= -frames
;
1881 *data
= This
->local_buffer
+ write_pos
* This
->fmt
->nBlockAlign
;
1882 This
->getbuf_last
= frames
;
1885 silence_buffer(This
, *data
, frames
);
1887 LeaveCriticalSection(&This
->lock
);
1892 static void oss_wrap_buffer(ACImpl
*This
, BYTE
*buffer
, UINT32 written_frames
)
1894 UINT32 write_offs_frames
=
1895 (This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
;
1896 UINT32 write_offs_bytes
= write_offs_frames
* This
->fmt
->nBlockAlign
;
1897 UINT32 chunk_frames
= This
->bufsize_frames
- write_offs_frames
;
1898 UINT32 chunk_bytes
= chunk_frames
* This
->fmt
->nBlockAlign
;
1899 UINT32 written_bytes
= written_frames
* This
->fmt
->nBlockAlign
;
1901 if(written_bytes
<= chunk_bytes
){
1902 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, written_bytes
);
1904 memcpy(This
->local_buffer
+ write_offs_bytes
, buffer
, chunk_bytes
);
1905 memcpy(This
->local_buffer
, buffer
+ chunk_bytes
,
1906 written_bytes
- chunk_bytes
);
1910 static HRESULT WINAPI
AudioRenderClient_ReleaseBuffer(
1911 IAudioRenderClient
*iface
, UINT32 written_frames
, DWORD flags
)
1913 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1916 TRACE("(%p)->(%u, %x)\n", This
, written_frames
, flags
);
1918 EnterCriticalSection(&This
->lock
);
1920 if(!written_frames
){
1921 This
->getbuf_last
= 0;
1922 LeaveCriticalSection(&This
->lock
);
1926 if(!This
->getbuf_last
){
1927 LeaveCriticalSection(&This
->lock
);
1928 return AUDCLNT_E_OUT_OF_ORDER
;
1931 if(written_frames
> (This
->getbuf_last
>= 0 ? This
->getbuf_last
: -This
->getbuf_last
)){
1932 LeaveCriticalSection(&This
->lock
);
1933 return AUDCLNT_E_INVALID_SIZE
;
1936 if(This
->getbuf_last
>= 0)
1937 buffer
= This
->local_buffer
+ This
->fmt
->nBlockAlign
*
1938 ((This
->lcl_offs_frames
+ This
->held_frames
) % This
->bufsize_frames
);
1940 buffer
= This
->tmp_buffer
;
1942 if(flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1943 silence_buffer(This
, buffer
, written_frames
);
1945 if(This
->getbuf_last
< 0)
1946 oss_wrap_buffer(This
, buffer
, written_frames
);
1948 This
->held_frames
+= written_frames
;
1949 This
->written_frames
+= written_frames
;
1950 This
->getbuf_last
= 0;
1952 LeaveCriticalSection(&This
->lock
);
1957 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
1958 AudioRenderClient_QueryInterface
,
1959 AudioRenderClient_AddRef
,
1960 AudioRenderClient_Release
,
1961 AudioRenderClient_GetBuffer
,
1962 AudioRenderClient_ReleaseBuffer
1965 static HRESULT WINAPI
AudioCaptureClient_QueryInterface(
1966 IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1968 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1969 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1975 if(IsEqualIID(riid
, &IID_IUnknown
) ||
1976 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1978 else if(IsEqualIID(riid
, &IID_IMarshal
))
1979 return IUnknown_QueryInterface(This
->pUnkFTMarshal
, riid
, ppv
);
1981 IUnknown_AddRef((IUnknown
*)*ppv
);
1985 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1986 return E_NOINTERFACE
;
1989 static ULONG WINAPI
AudioCaptureClient_AddRef(IAudioCaptureClient
*iface
)
1991 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1992 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1995 static ULONG WINAPI
AudioCaptureClient_Release(IAudioCaptureClient
*iface
)
1997 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1998 return IAudioClient_Release(&This
->IAudioClient_iface
);
2001 static HRESULT WINAPI
AudioCaptureClient_GetBuffer(IAudioCaptureClient
*iface
,
2002 BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
,
2005 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
2007 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
2015 if(!frames
|| !flags
)
2018 EnterCriticalSection(&This
->lock
);
2020 if(This
->getbuf_last
){
2021 LeaveCriticalSection(&This
->lock
);
2022 return AUDCLNT_E_OUT_OF_ORDER
;
2025 if(This
->held_frames
< This
->period_frames
){
2027 LeaveCriticalSection(&This
->lock
);
2028 return AUDCLNT_S_BUFFER_EMPTY
;
2033 *frames
= This
->period_frames
;
2035 if(This
->lcl_offs_frames
+ *frames
> This
->bufsize_frames
){
2036 UINT32 chunk_bytes
, offs_bytes
, frames_bytes
;
2037 if(This
->tmp_buffer_frames
< *frames
){
2038 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
2039 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0,
2040 *frames
* This
->fmt
->nBlockAlign
);
2041 if(!This
->tmp_buffer
){
2042 LeaveCriticalSection(&This
->lock
);
2043 return E_OUTOFMEMORY
;
2045 This
->tmp_buffer_frames
= *frames
;
2048 *data
= This
->tmp_buffer
;
2049 chunk_bytes
= (This
->bufsize_frames
- This
->lcl_offs_frames
) *
2050 This
->fmt
->nBlockAlign
;
2051 offs_bytes
= This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
2052 frames_bytes
= *frames
* This
->fmt
->nBlockAlign
;
2053 memcpy(This
->tmp_buffer
, This
->local_buffer
+ offs_bytes
, chunk_bytes
);
2054 memcpy(This
->tmp_buffer
+ chunk_bytes
, This
->local_buffer
,
2055 frames_bytes
- chunk_bytes
);
2057 *data
= This
->local_buffer
+
2058 This
->lcl_offs_frames
* This
->fmt
->nBlockAlign
;
2060 This
->getbuf_last
= *frames
;
2063 *devpos
= This
->written_frames
;
2065 LARGE_INTEGER stamp
, freq
;
2066 QueryPerformanceCounter(&stamp
);
2067 QueryPerformanceFrequency(&freq
);
2068 *qpcpos
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
2071 LeaveCriticalSection(&This
->lock
);
2073 return *frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
2076 static HRESULT WINAPI
AudioCaptureClient_ReleaseBuffer(
2077 IAudioCaptureClient
*iface
, UINT32 done
)
2079 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
2081 TRACE("(%p)->(%u)\n", This
, done
);
2083 EnterCriticalSection(&This
->lock
);
2086 This
->getbuf_last
= 0;
2087 LeaveCriticalSection(&This
->lock
);
2091 if(!This
->getbuf_last
){
2092 LeaveCriticalSection(&This
->lock
);
2093 return AUDCLNT_E_OUT_OF_ORDER
;
2096 if(This
->getbuf_last
!= done
){
2097 LeaveCriticalSection(&This
->lock
);
2098 return AUDCLNT_E_INVALID_SIZE
;
2101 This
->written_frames
+= done
;
2102 This
->held_frames
-= done
;
2103 This
->lcl_offs_frames
+= done
;
2104 This
->lcl_offs_frames
%= This
->bufsize_frames
;
2105 This
->getbuf_last
= 0;
2107 LeaveCriticalSection(&This
->lock
);
2112 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
2113 IAudioCaptureClient
*iface
, UINT32
*frames
)
2115 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
2117 TRACE("(%p)->(%p)\n", This
, frames
);
2122 EnterCriticalSection(&This
->lock
);
2124 *frames
= This
->held_frames
< This
->period_frames
? 0 : This
->period_frames
;
2126 LeaveCriticalSection(&This
->lock
);
2131 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
2133 AudioCaptureClient_QueryInterface
,
2134 AudioCaptureClient_AddRef
,
2135 AudioCaptureClient_Release
,
2136 AudioCaptureClient_GetBuffer
,
2137 AudioCaptureClient_ReleaseBuffer
,
2138 AudioCaptureClient_GetNextPacketSize
2141 static HRESULT WINAPI
AudioClock_QueryInterface(IAudioClock
*iface
,
2142 REFIID riid
, void **ppv
)
2144 ACImpl
*This
= impl_from_IAudioClock(iface
);
2146 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2152 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClock
))
2154 else if(IsEqualIID(riid
, &IID_IAudioClock2
))
2155 *ppv
= &This
->IAudioClock2_iface
;
2157 IUnknown_AddRef((IUnknown
*)*ppv
);
2161 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2162 return E_NOINTERFACE
;
2165 static ULONG WINAPI
AudioClock_AddRef(IAudioClock
*iface
)
2167 ACImpl
*This
= impl_from_IAudioClock(iface
);
2168 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2171 static ULONG WINAPI
AudioClock_Release(IAudioClock
*iface
)
2173 ACImpl
*This
= impl_from_IAudioClock(iface
);
2174 return IAudioClient_Release(&This
->IAudioClient_iface
);
2177 static HRESULT WINAPI
AudioClock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
2179 ACImpl
*This
= impl_from_IAudioClock(iface
);
2181 TRACE("(%p)->(%p)\n", This
, freq
);
2183 if(This
->share
== AUDCLNT_SHAREMODE_SHARED
)
2184 *freq
= (UINT64
)This
->fmt
->nSamplesPerSec
* This
->fmt
->nBlockAlign
;
2186 *freq
= This
->fmt
->nSamplesPerSec
;
2191 static HRESULT WINAPI
AudioClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
,
2194 ACImpl
*This
= impl_from_IAudioClock(iface
);
2196 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
2201 EnterCriticalSection(&This
->lock
);
2203 if(This
->dataflow
== eRender
){
2204 *pos
= This
->written_frames
- This
->held_frames
;
2205 if(*pos
< This
->last_pos_frames
)
2206 *pos
= This
->last_pos_frames
;
2207 }else if(This
->dataflow
== eCapture
){
2211 if(ioctl(This
->fd
, SNDCTL_DSP_GETISPACE
, &bi
) < 0){
2212 TRACE("GETISPACE failed: %d (%s)\n", errno
, strerror(errno
));
2215 if(bi
.bytes
<= bi
.fragsize
)
2218 held
= bi
.bytes
/ This
->fmt
->nBlockAlign
;
2221 *pos
= This
->written_frames
+ held
;
2224 This
->last_pos_frames
= *pos
;
2226 TRACE("returning: %s\n", wine_dbgstr_longlong(*pos
));
2227 if(This
->share
== AUDCLNT_SHAREMODE_SHARED
)
2228 *pos
*= This
->fmt
->nBlockAlign
;
2230 LeaveCriticalSection(&This
->lock
);
2233 LARGE_INTEGER stamp
, freq
;
2234 QueryPerformanceCounter(&stamp
);
2235 QueryPerformanceFrequency(&freq
);
2236 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
2242 static HRESULT WINAPI
AudioClock_GetCharacteristics(IAudioClock
*iface
,
2245 ACImpl
*This
= impl_from_IAudioClock(iface
);
2247 TRACE("(%p)->(%p)\n", This
, chars
);
2252 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
2257 static const IAudioClockVtbl AudioClock_Vtbl
=
2259 AudioClock_QueryInterface
,
2262 AudioClock_GetFrequency
,
2263 AudioClock_GetPosition
,
2264 AudioClock_GetCharacteristics
2267 static HRESULT WINAPI
AudioClock2_QueryInterface(IAudioClock2
*iface
,
2268 REFIID riid
, void **ppv
)
2270 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2271 return IAudioClock_QueryInterface(&This
->IAudioClock_iface
, riid
, ppv
);
2274 static ULONG WINAPI
AudioClock2_AddRef(IAudioClock2
*iface
)
2276 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2277 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2280 static ULONG WINAPI
AudioClock2_Release(IAudioClock2
*iface
)
2282 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2283 return IAudioClient_Release(&This
->IAudioClient_iface
);
2286 static HRESULT WINAPI
AudioClock2_GetDevicePosition(IAudioClock2
*iface
,
2287 UINT64
*pos
, UINT64
*qpctime
)
2289 ACImpl
*This
= impl_from_IAudioClock2(iface
);
2291 FIXME("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
2296 static const IAudioClock2Vtbl AudioClock2_Vtbl
=
2298 AudioClock2_QueryInterface
,
2300 AudioClock2_Release
,
2301 AudioClock2_GetDevicePosition
2304 static AudioSessionWrapper
*AudioSessionWrapper_Create(ACImpl
*client
)
2306 AudioSessionWrapper
*ret
;
2308 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
2309 sizeof(AudioSessionWrapper
));
2313 ret
->IAudioSessionControl2_iface
.lpVtbl
= &AudioSessionControl2_Vtbl
;
2314 ret
->ISimpleAudioVolume_iface
.lpVtbl
= &SimpleAudioVolume_Vtbl
;
2315 ret
->IChannelAudioVolume_iface
.lpVtbl
= &ChannelAudioVolume_Vtbl
;
2319 ret
->client
= client
;
2321 ret
->session
= client
->session
;
2322 AudioClient_AddRef(&client
->IAudioClient_iface
);
2328 static HRESULT WINAPI
AudioSessionControl_QueryInterface(
2329 IAudioSessionControl2
*iface
, REFIID riid
, void **ppv
)
2331 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2337 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2338 IsEqualIID(riid
, &IID_IAudioSessionControl
) ||
2339 IsEqualIID(riid
, &IID_IAudioSessionControl2
))
2342 IUnknown_AddRef((IUnknown
*)*ppv
);
2346 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2347 return E_NOINTERFACE
;
2350 static ULONG WINAPI
AudioSessionControl_AddRef(IAudioSessionControl2
*iface
)
2352 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2354 ref
= InterlockedIncrement(&This
->ref
);
2355 TRACE("(%p) Refcount now %u\n", This
, ref
);
2359 static ULONG WINAPI
AudioSessionControl_Release(IAudioSessionControl2
*iface
)
2361 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2363 ref
= InterlockedDecrement(&This
->ref
);
2364 TRACE("(%p) Refcount now %u\n", This
, ref
);
2367 EnterCriticalSection(&This
->client
->lock
);
2368 This
->client
->session_wrapper
= NULL
;
2369 LeaveCriticalSection(&This
->client
->lock
);
2370 AudioClient_Release(&This
->client
->IAudioClient_iface
);
2372 HeapFree(GetProcessHeap(), 0, This
);
2377 static HRESULT WINAPI
AudioSessionControl_GetState(IAudioSessionControl2
*iface
,
2378 AudioSessionState
*state
)
2380 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2383 TRACE("(%p)->(%p)\n", This
, state
);
2386 return NULL_PTR_ERR
;
2388 EnterCriticalSection(&g_sessions_lock
);
2390 if(list_empty(&This
->session
->clients
)){
2391 *state
= AudioSessionStateExpired
;
2392 LeaveCriticalSection(&g_sessions_lock
);
2396 LIST_FOR_EACH_ENTRY(client
, &This
->session
->clients
, ACImpl
, entry
){
2397 EnterCriticalSection(&client
->lock
);
2398 if(client
->playing
){
2399 *state
= AudioSessionStateActive
;
2400 LeaveCriticalSection(&client
->lock
);
2401 LeaveCriticalSection(&g_sessions_lock
);
2404 LeaveCriticalSection(&client
->lock
);
2407 LeaveCriticalSection(&g_sessions_lock
);
2409 *state
= AudioSessionStateInactive
;
2414 static HRESULT WINAPI
AudioSessionControl_GetDisplayName(
2415 IAudioSessionControl2
*iface
, WCHAR
**name
)
2417 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2419 FIXME("(%p)->(%p) - stub\n", This
, name
);
2424 static HRESULT WINAPI
AudioSessionControl_SetDisplayName(
2425 IAudioSessionControl2
*iface
, const WCHAR
*name
, const GUID
*session
)
2427 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2429 FIXME("(%p)->(%p, %s) - stub\n", This
, name
, debugstr_guid(session
));
2434 static HRESULT WINAPI
AudioSessionControl_GetIconPath(
2435 IAudioSessionControl2
*iface
, WCHAR
**path
)
2437 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2439 FIXME("(%p)->(%p) - stub\n", This
, path
);
2444 static HRESULT WINAPI
AudioSessionControl_SetIconPath(
2445 IAudioSessionControl2
*iface
, const WCHAR
*path
, const GUID
*session
)
2447 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2449 FIXME("(%p)->(%p, %s) - stub\n", This
, path
, debugstr_guid(session
));
2454 static HRESULT WINAPI
AudioSessionControl_GetGroupingParam(
2455 IAudioSessionControl2
*iface
, GUID
*group
)
2457 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2459 FIXME("(%p)->(%p) - stub\n", This
, group
);
2464 static HRESULT WINAPI
AudioSessionControl_SetGroupingParam(
2465 IAudioSessionControl2
*iface
, const GUID
*group
, const GUID
*session
)
2467 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2469 FIXME("(%p)->(%s, %s) - stub\n", This
, debugstr_guid(group
),
2470 debugstr_guid(session
));
2475 static HRESULT WINAPI
AudioSessionControl_RegisterAudioSessionNotification(
2476 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2478 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2480 FIXME("(%p)->(%p) - stub\n", This
, events
);
2485 static HRESULT WINAPI
AudioSessionControl_UnregisterAudioSessionNotification(
2486 IAudioSessionControl2
*iface
, IAudioSessionEvents
*events
)
2488 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2490 FIXME("(%p)->(%p) - stub\n", This
, events
);
2495 static HRESULT WINAPI
AudioSessionControl_GetSessionIdentifier(
2496 IAudioSessionControl2
*iface
, WCHAR
**id
)
2498 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2500 FIXME("(%p)->(%p) - stub\n", This
, id
);
2505 static HRESULT WINAPI
AudioSessionControl_GetSessionInstanceIdentifier(
2506 IAudioSessionControl2
*iface
, WCHAR
**id
)
2508 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2510 FIXME("(%p)->(%p) - stub\n", This
, id
);
2515 static HRESULT WINAPI
AudioSessionControl_GetProcessId(
2516 IAudioSessionControl2
*iface
, DWORD
*pid
)
2518 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2520 TRACE("(%p)->(%p)\n", This
, pid
);
2525 *pid
= GetCurrentProcessId();
2530 static HRESULT WINAPI
AudioSessionControl_IsSystemSoundsSession(
2531 IAudioSessionControl2
*iface
)
2533 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2535 TRACE("(%p)\n", This
);
2540 static HRESULT WINAPI
AudioSessionControl_SetDuckingPreference(
2541 IAudioSessionControl2
*iface
, BOOL optout
)
2543 AudioSessionWrapper
*This
= impl_from_IAudioSessionControl2(iface
);
2545 TRACE("(%p)->(%d)\n", This
, optout
);
2550 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
=
2552 AudioSessionControl_QueryInterface
,
2553 AudioSessionControl_AddRef
,
2554 AudioSessionControl_Release
,
2555 AudioSessionControl_GetState
,
2556 AudioSessionControl_GetDisplayName
,
2557 AudioSessionControl_SetDisplayName
,
2558 AudioSessionControl_GetIconPath
,
2559 AudioSessionControl_SetIconPath
,
2560 AudioSessionControl_GetGroupingParam
,
2561 AudioSessionControl_SetGroupingParam
,
2562 AudioSessionControl_RegisterAudioSessionNotification
,
2563 AudioSessionControl_UnregisterAudioSessionNotification
,
2564 AudioSessionControl_GetSessionIdentifier
,
2565 AudioSessionControl_GetSessionInstanceIdentifier
,
2566 AudioSessionControl_GetProcessId
,
2567 AudioSessionControl_IsSystemSoundsSession
,
2568 AudioSessionControl_SetDuckingPreference
2571 static HRESULT WINAPI
SimpleAudioVolume_QueryInterface(
2572 ISimpleAudioVolume
*iface
, REFIID riid
, void **ppv
)
2574 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2580 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2581 IsEqualIID(riid
, &IID_ISimpleAudioVolume
))
2584 IUnknown_AddRef((IUnknown
*)*ppv
);
2588 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2589 return E_NOINTERFACE
;
2592 static ULONG WINAPI
SimpleAudioVolume_AddRef(ISimpleAudioVolume
*iface
)
2594 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2595 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2598 static ULONG WINAPI
SimpleAudioVolume_Release(ISimpleAudioVolume
*iface
)
2600 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2601 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2604 static HRESULT WINAPI
SimpleAudioVolume_SetMasterVolume(
2605 ISimpleAudioVolume
*iface
, float level
, const GUID
*context
)
2607 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2608 AudioSession
*session
= This
->session
;
2610 TRACE("(%p)->(%f, %s)\n", session
, level
, wine_dbgstr_guid(context
));
2612 if(level
< 0.f
|| level
> 1.f
)
2613 return E_INVALIDARG
;
2616 FIXME("Notifications not supported yet\n");
2618 EnterCriticalSection(&session
->lock
);
2620 session
->master_vol
= level
;
2622 TRACE("OSS doesn't support setting volume\n");
2624 LeaveCriticalSection(&session
->lock
);
2629 static HRESULT WINAPI
SimpleAudioVolume_GetMasterVolume(
2630 ISimpleAudioVolume
*iface
, float *level
)
2632 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2633 AudioSession
*session
= This
->session
;
2635 TRACE("(%p)->(%p)\n", session
, level
);
2638 return NULL_PTR_ERR
;
2640 *level
= session
->master_vol
;
2645 static HRESULT WINAPI
SimpleAudioVolume_SetMute(ISimpleAudioVolume
*iface
,
2646 BOOL mute
, const GUID
*context
)
2648 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2649 AudioSession
*session
= This
->session
;
2651 TRACE("(%p)->(%u, %s)\n", session
, mute
, debugstr_guid(context
));
2653 EnterCriticalSection(&session
->lock
);
2655 session
->mute
= mute
;
2657 LeaveCriticalSection(&session
->lock
);
2662 static HRESULT WINAPI
SimpleAudioVolume_GetMute(ISimpleAudioVolume
*iface
,
2665 AudioSessionWrapper
*This
= impl_from_ISimpleAudioVolume(iface
);
2666 AudioSession
*session
= This
->session
;
2668 TRACE("(%p)->(%p)\n", session
, mute
);
2671 return NULL_PTR_ERR
;
2673 *mute
= This
->session
->mute
;
2678 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
=
2680 SimpleAudioVolume_QueryInterface
,
2681 SimpleAudioVolume_AddRef
,
2682 SimpleAudioVolume_Release
,
2683 SimpleAudioVolume_SetMasterVolume
,
2684 SimpleAudioVolume_GetMasterVolume
,
2685 SimpleAudioVolume_SetMute
,
2686 SimpleAudioVolume_GetMute
2689 static HRESULT WINAPI
AudioStreamVolume_QueryInterface(
2690 IAudioStreamVolume
*iface
, REFIID riid
, void **ppv
)
2692 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2698 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2699 IsEqualIID(riid
, &IID_IAudioStreamVolume
))
2702 IUnknown_AddRef((IUnknown
*)*ppv
);
2706 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2707 return E_NOINTERFACE
;
2710 static ULONG WINAPI
AudioStreamVolume_AddRef(IAudioStreamVolume
*iface
)
2712 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2713 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
2716 static ULONG WINAPI
AudioStreamVolume_Release(IAudioStreamVolume
*iface
)
2718 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2719 return IAudioClient_Release(&This
->IAudioClient_iface
);
2722 static HRESULT WINAPI
AudioStreamVolume_GetChannelCount(
2723 IAudioStreamVolume
*iface
, UINT32
*out
)
2725 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2727 TRACE("(%p)->(%p)\n", This
, out
);
2732 *out
= This
->fmt
->nChannels
;
2737 static HRESULT WINAPI
AudioStreamVolume_SetChannelVolume(
2738 IAudioStreamVolume
*iface
, UINT32 index
, float level
)
2740 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2742 TRACE("(%p)->(%d, %f)\n", This
, index
, level
);
2744 if(level
< 0.f
|| level
> 1.f
)
2745 return E_INVALIDARG
;
2747 if(index
>= This
->fmt
->nChannels
)
2748 return E_INVALIDARG
;
2750 EnterCriticalSection(&This
->lock
);
2752 This
->vols
[index
] = level
;
2754 TRACE("OSS doesn't support setting volume\n");
2756 LeaveCriticalSection(&This
->lock
);
2761 static HRESULT WINAPI
AudioStreamVolume_GetChannelVolume(
2762 IAudioStreamVolume
*iface
, UINT32 index
, float *level
)
2764 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2766 TRACE("(%p)->(%d, %p)\n", This
, index
, level
);
2771 if(index
>= This
->fmt
->nChannels
)
2772 return E_INVALIDARG
;
2774 *level
= This
->vols
[index
];
2779 static HRESULT WINAPI
AudioStreamVolume_SetAllVolumes(
2780 IAudioStreamVolume
*iface
, UINT32 count
, const float *levels
)
2782 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2785 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2790 if(count
!= This
->fmt
->nChannels
)
2791 return E_INVALIDARG
;
2793 EnterCriticalSection(&This
->lock
);
2795 for(i
= 0; i
< count
; ++i
)
2796 This
->vols
[i
] = levels
[i
];
2798 TRACE("OSS doesn't support setting volume\n");
2800 LeaveCriticalSection(&This
->lock
);
2805 static HRESULT WINAPI
AudioStreamVolume_GetAllVolumes(
2806 IAudioStreamVolume
*iface
, UINT32 count
, float *levels
)
2808 ACImpl
*This
= impl_from_IAudioStreamVolume(iface
);
2811 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
2816 if(count
!= This
->fmt
->nChannels
)
2817 return E_INVALIDARG
;
2819 EnterCriticalSection(&This
->lock
);
2821 for(i
= 0; i
< count
; ++i
)
2822 levels
[i
] = This
->vols
[i
];
2824 LeaveCriticalSection(&This
->lock
);
2829 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
=
2831 AudioStreamVolume_QueryInterface
,
2832 AudioStreamVolume_AddRef
,
2833 AudioStreamVolume_Release
,
2834 AudioStreamVolume_GetChannelCount
,
2835 AudioStreamVolume_SetChannelVolume
,
2836 AudioStreamVolume_GetChannelVolume
,
2837 AudioStreamVolume_SetAllVolumes
,
2838 AudioStreamVolume_GetAllVolumes
2841 static HRESULT WINAPI
ChannelAudioVolume_QueryInterface(
2842 IChannelAudioVolume
*iface
, REFIID riid
, void **ppv
)
2844 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
2850 if(IsEqualIID(riid
, &IID_IUnknown
) ||
2851 IsEqualIID(riid
, &IID_IChannelAudioVolume
))
2854 IUnknown_AddRef((IUnknown
*)*ppv
);
2858 WARN("Unknown interface %s\n", debugstr_guid(riid
));
2859 return E_NOINTERFACE
;
2862 static ULONG WINAPI
ChannelAudioVolume_AddRef(IChannelAudioVolume
*iface
)
2864 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2865 return AudioSessionControl_AddRef(&This
->IAudioSessionControl2_iface
);
2868 static ULONG WINAPI
ChannelAudioVolume_Release(IChannelAudioVolume
*iface
)
2870 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2871 return AudioSessionControl_Release(&This
->IAudioSessionControl2_iface
);
2874 static HRESULT WINAPI
ChannelAudioVolume_GetChannelCount(
2875 IChannelAudioVolume
*iface
, UINT32
*out
)
2877 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2878 AudioSession
*session
= This
->session
;
2880 TRACE("(%p)->(%p)\n", session
, out
);
2883 return NULL_PTR_ERR
;
2885 *out
= session
->channel_count
;
2890 static HRESULT WINAPI
ChannelAudioVolume_SetChannelVolume(
2891 IChannelAudioVolume
*iface
, UINT32 index
, float level
,
2892 const GUID
*context
)
2894 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2895 AudioSession
*session
= This
->session
;
2897 TRACE("(%p)->(%d, %f, %s)\n", session
, index
, level
,
2898 wine_dbgstr_guid(context
));
2900 if(level
< 0.f
|| level
> 1.f
)
2901 return E_INVALIDARG
;
2903 if(index
>= session
->channel_count
)
2904 return E_INVALIDARG
;
2907 FIXME("Notifications not supported yet\n");
2909 EnterCriticalSection(&session
->lock
);
2911 session
->channel_vols
[index
] = level
;
2913 TRACE("OSS doesn't support setting volume\n");
2915 LeaveCriticalSection(&session
->lock
);
2920 static HRESULT WINAPI
ChannelAudioVolume_GetChannelVolume(
2921 IChannelAudioVolume
*iface
, UINT32 index
, float *level
)
2923 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2924 AudioSession
*session
= This
->session
;
2926 TRACE("(%p)->(%d, %p)\n", session
, index
, level
);
2929 return NULL_PTR_ERR
;
2931 if(index
>= session
->channel_count
)
2932 return E_INVALIDARG
;
2934 *level
= session
->channel_vols
[index
];
2939 static HRESULT WINAPI
ChannelAudioVolume_SetAllVolumes(
2940 IChannelAudioVolume
*iface
, UINT32 count
, const float *levels
,
2941 const GUID
*context
)
2943 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2944 AudioSession
*session
= This
->session
;
2947 TRACE("(%p)->(%d, %p, %s)\n", session
, count
, levels
,
2948 wine_dbgstr_guid(context
));
2951 return NULL_PTR_ERR
;
2953 if(count
!= session
->channel_count
)
2954 return E_INVALIDARG
;
2957 FIXME("Notifications not supported yet\n");
2959 EnterCriticalSection(&session
->lock
);
2961 for(i
= 0; i
< count
; ++i
)
2962 session
->channel_vols
[i
] = levels
[i
];
2964 TRACE("OSS doesn't support setting volume\n");
2966 LeaveCriticalSection(&session
->lock
);
2971 static HRESULT WINAPI
ChannelAudioVolume_GetAllVolumes(
2972 IChannelAudioVolume
*iface
, UINT32 count
, float *levels
)
2974 AudioSessionWrapper
*This
= impl_from_IChannelAudioVolume(iface
);
2975 AudioSession
*session
= This
->session
;
2978 TRACE("(%p)->(%d, %p)\n", session
, count
, levels
);
2981 return NULL_PTR_ERR
;
2983 if(count
!= session
->channel_count
)
2984 return E_INVALIDARG
;
2986 for(i
= 0; i
< count
; ++i
)
2987 levels
[i
] = session
->channel_vols
[i
];
2992 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
=
2994 ChannelAudioVolume_QueryInterface
,
2995 ChannelAudioVolume_AddRef
,
2996 ChannelAudioVolume_Release
,
2997 ChannelAudioVolume_GetChannelCount
,
2998 ChannelAudioVolume_SetChannelVolume
,
2999 ChannelAudioVolume_GetChannelVolume
,
3000 ChannelAudioVolume_SetAllVolumes
,
3001 ChannelAudioVolume_GetAllVolumes
3004 static HRESULT WINAPI
AudioSessionManager_QueryInterface(IAudioSessionManager2
*iface
,
3005 REFIID riid
, void **ppv
)
3007 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
3013 if(IsEqualIID(riid
, &IID_IUnknown
) ||
3014 IsEqualIID(riid
, &IID_IAudioSessionManager
) ||
3015 IsEqualIID(riid
, &IID_IAudioSessionManager2
))
3018 IUnknown_AddRef((IUnknown
*)*ppv
);
3022 WARN("Unknown interface %s\n", debugstr_guid(riid
));
3023 return E_NOINTERFACE
;
3026 static ULONG WINAPI
AudioSessionManager_AddRef(IAudioSessionManager2
*iface
)
3028 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3030 ref
= InterlockedIncrement(&This
->ref
);
3031 TRACE("(%p) Refcount now %u\n", This
, ref
);
3035 static ULONG WINAPI
AudioSessionManager_Release(IAudioSessionManager2
*iface
)
3037 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3039 ref
= InterlockedDecrement(&This
->ref
);
3040 TRACE("(%p) Refcount now %u\n", This
, ref
);
3042 HeapFree(GetProcessHeap(), 0, This
);
3046 static HRESULT WINAPI
AudioSessionManager_GetAudioSessionControl(
3047 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
3048 IAudioSessionControl
**out
)
3050 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3051 AudioSession
*session
;
3052 AudioSessionWrapper
*wrapper
;
3055 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
3058 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
3062 wrapper
= AudioSessionWrapper_Create(NULL
);
3064 return E_OUTOFMEMORY
;
3066 wrapper
->session
= session
;
3068 *out
= (IAudioSessionControl
*)&wrapper
->IAudioSessionControl2_iface
;
3073 static HRESULT WINAPI
AudioSessionManager_GetSimpleAudioVolume(
3074 IAudioSessionManager2
*iface
, const GUID
*session_guid
, DWORD flags
,
3075 ISimpleAudioVolume
**out
)
3077 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3078 AudioSession
*session
;
3079 AudioSessionWrapper
*wrapper
;
3082 TRACE("(%p)->(%s, %x, %p)\n", This
, debugstr_guid(session_guid
),
3085 hr
= get_audio_session(session_guid
, This
->device
, 0, &session
);
3089 wrapper
= AudioSessionWrapper_Create(NULL
);
3091 return E_OUTOFMEMORY
;
3093 wrapper
->session
= session
;
3095 *out
= &wrapper
->ISimpleAudioVolume_iface
;
3100 static HRESULT WINAPI
AudioSessionManager_GetSessionEnumerator(
3101 IAudioSessionManager2
*iface
, IAudioSessionEnumerator
**out
)
3103 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3104 FIXME("(%p)->(%p) - stub\n", This
, out
);
3108 static HRESULT WINAPI
AudioSessionManager_RegisterSessionNotification(
3109 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
3111 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3112 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3116 static HRESULT WINAPI
AudioSessionManager_UnregisterSessionNotification(
3117 IAudioSessionManager2
*iface
, IAudioSessionNotification
*notification
)
3119 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3120 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3124 static HRESULT WINAPI
AudioSessionManager_RegisterDuckNotification(
3125 IAudioSessionManager2
*iface
, const WCHAR
*session_id
,
3126 IAudioVolumeDuckNotification
*notification
)
3128 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3129 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3133 static HRESULT WINAPI
AudioSessionManager_UnregisterDuckNotification(
3134 IAudioSessionManager2
*iface
,
3135 IAudioVolumeDuckNotification
*notification
)
3137 SessionMgr
*This
= impl_from_IAudioSessionManager2(iface
);
3138 FIXME("(%p)->(%p) - stub\n", This
, notification
);
3142 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl
=
3144 AudioSessionManager_QueryInterface
,
3145 AudioSessionManager_AddRef
,
3146 AudioSessionManager_Release
,
3147 AudioSessionManager_GetAudioSessionControl
,
3148 AudioSessionManager_GetSimpleAudioVolume
,
3149 AudioSessionManager_GetSessionEnumerator
,
3150 AudioSessionManager_RegisterSessionNotification
,
3151 AudioSessionManager_UnregisterSessionNotification
,
3152 AudioSessionManager_RegisterDuckNotification
,
3153 AudioSessionManager_UnregisterDuckNotification
3156 HRESULT WINAPI
AUDDRV_GetAudioSessionManager(IMMDevice
*device
,
3157 IAudioSessionManager2
**out
)
3161 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SessionMgr
));
3163 return E_OUTOFMEMORY
;
3165 This
->IAudioSessionManager2_iface
.lpVtbl
= &AudioSessionManager2_Vtbl
;
3166 This
->device
= device
;
3169 *out
= &This
->IAudioSessionManager2_iface
;