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 "wine/debug.h"
29 #include "wine/heap.h"
30 #include "wine/list.h"
31 #include "wine/unixlib.h"
34 #include "mmdeviceapi.h"
40 #include "endpointvolume.h"
41 #include "audioclient.h"
42 #include "audiopolicy.h"
45 #include "../mmdevapi/mmdevdrv.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio
);
49 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
51 static const IAudioClient3Vtbl AudioClient3_Vtbl
;
52 extern const IAudioRenderClientVtbl AudioRenderClient_Vtbl
;
53 extern const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
;
54 extern const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl
;
55 extern const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl
;
56 extern const IAudioClockVtbl AudioClock_Vtbl
;
57 extern const IAudioClock2Vtbl AudioClock2_Vtbl
;
58 extern const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
;
59 extern const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl
;
61 static WCHAR drv_key_devicesW
[256];
63 static CRITICAL_SECTION g_sessions_lock
;
64 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug
=
66 0, 0, &g_sessions_lock
,
67 { &g_sessions_lock_debug
.ProcessLocksList
, &g_sessions_lock_debug
.ProcessLocksList
},
68 0, 0, { (DWORD_PTR
)(__FILE__
": g_sessions_lock") }
70 static CRITICAL_SECTION g_sessions_lock
= { &g_sessions_lock_debug
, -1, 0, 0, 0, 0 };
71 static struct list g_sessions
= LIST_INIT(g_sessions
);
73 extern struct audio_session_wrapper
*session_wrapper_create(
74 struct audio_client
*client
) DECLSPEC_HIDDEN
;
76 void DECLSPEC_HIDDEN
sessions_lock(void)
78 EnterCriticalSection(&g_sessions_lock
);
81 void DECLSPEC_HIDDEN
sessions_unlock(void)
83 LeaveCriticalSection(&g_sessions_lock
);
86 static inline ACImpl
*impl_from_IAudioClient3(IAudioClient3
*iface
)
88 return CONTAINING_RECORD(iface
, ACImpl
, IAudioClient3_iface
);
91 BOOL WINAPI
DllMain(HINSTANCE dll
, DWORD reason
, void *reserved
)
95 case DLL_PROCESS_ATTACH
:
100 DisableThreadLibraryCalls(dll
);
101 if (__wine_init_unix_call())
104 GetModuleFileNameW(dll
, buf
, ARRAY_SIZE(buf
));
106 filename
= wcsrchr(buf
, '\\');
107 filename
= filename
? filename
+ 1 : buf
;
109 swprintf(drv_key_devicesW
, ARRAY_SIZE(drv_key_devicesW
),
110 L
"Software\\Wine\\Drivers\\%s\\devices", filename
);
114 case DLL_PROCESS_DETACH
:
116 DeleteCriticalSection(&g_sessions_lock
);
122 static void set_device_guid(EDataFlow flow
, HKEY drv_key
, const WCHAR
*key_name
,
130 lr
= RegCreateKeyExW(HKEY_CURRENT_USER
, drv_key_devicesW
, 0, NULL
, 0, KEY_WRITE
,
131 NULL
, &drv_key
, NULL
);
132 if(lr
!= ERROR_SUCCESS
){
133 ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr
);
139 lr
= RegCreateKeyExW(drv_key
, key_name
, 0, NULL
, 0, KEY_WRITE
,
141 if(lr
!= ERROR_SUCCESS
){
142 ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name
), lr
);
146 lr
= RegSetValueExW(key
, L
"guid", 0, REG_BINARY
, (BYTE
*)guid
,
148 if(lr
!= ERROR_SUCCESS
)
149 ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name
), lr
);
154 RegCloseKey(drv_key
);
157 static void get_device_guid(EDataFlow flow
, const char *dev
, GUID
*guid
)
159 HKEY key
= NULL
, dev_key
;
160 DWORD type
, size
= sizeof(*guid
);
169 MultiByteToWideChar(CP_UNIXCP
, 0, dev
, -1, key_name
+ 2, ARRAY_SIZE(key_name
) - 2);
171 if(RegOpenKeyExW(HKEY_CURRENT_USER
, drv_key_devicesW
, 0, KEY_WRITE
|KEY_READ
, &key
) == ERROR_SUCCESS
){
172 if(RegOpenKeyExW(key
, key_name
, 0, KEY_READ
, &dev_key
) == ERROR_SUCCESS
){
173 if(RegQueryValueExW(dev_key
, L
"guid", 0, &type
,
174 (BYTE
*)guid
, &size
) == ERROR_SUCCESS
){
175 if(type
== REG_BINARY
){
176 RegCloseKey(dev_key
);
180 ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n",
181 wine_dbgstr_w(key_name
), type
);
183 RegCloseKey(dev_key
);
189 set_device_guid(flow
, key
, key_name
, guid
);
195 static void set_stream_volumes(ACImpl
*This
)
197 struct set_volumes_params params
;
199 params
.stream
= This
->stream
;
200 params
.master_volume
= This
->session
->mute
? 0.0f
: This
->session
->master_vol
;
201 params
.volumes
= This
->vols
;
202 params
.session_volumes
= This
->session
->channel_vols
;
204 UNIX_CALL(set_volumes
, ¶ms
);
207 HRESULT WINAPI
AUDDRV_GetEndpointIDs(EDataFlow flow
, WCHAR
***ids_out
,
208 GUID
**guids_out
, UINT
*num
, UINT
*def_index
)
210 struct get_endpoint_ids_params params
;
215 TRACE("%d %p %p %p\n", flow
, ids_out
, num
, def_index
);
219 params
.endpoints
= NULL
;
221 heap_free(params
.endpoints
);
222 params
.endpoints
= heap_alloc(params
.size
);
223 UNIX_CALL(get_endpoint_ids
, ¶ms
);
224 }while(params
.result
== HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
));
226 if(FAILED(params
.result
)) goto end
;
228 ids
= heap_alloc_zero(params
.num
* sizeof(*ids
));
229 guids
= heap_alloc(params
.num
* sizeof(*guids
));
231 params
.result
= E_OUTOFMEMORY
;
235 for(i
= 0; i
< params
.num
; i
++){
236 const WCHAR
*name
= (WCHAR
*)((char *)params
.endpoints
+ params
.endpoints
[i
].name
);
237 const char *device
= (char *)params
.endpoints
+ params
.endpoints
[i
].device
;
238 const unsigned int size
= (wcslen(name
) + 1) * sizeof(WCHAR
);
240 ids
[i
] = heap_alloc(size
);
242 params
.result
= E_OUTOFMEMORY
;
245 memcpy(ids
[i
], name
, size
);
246 get_device_guid(flow
, device
, guids
+ i
);
248 *def_index
= params
.default_idx
;
251 heap_free(params
.endpoints
);
252 if(FAILED(params
.result
)){
255 for(i
= 0; i
< params
.num
; i
++) heap_free(ids
[i
]);
264 return params
.result
;
267 static BOOL
get_device_name_by_guid(const GUID
*guid
, char *name
, const SIZE_T name_size
, EDataFlow
*flow
)
274 if(RegOpenKeyExW(HKEY_CURRENT_USER
, drv_key_devicesW
, 0, KEY_READ
, &devices_key
) != ERROR_SUCCESS
){
275 ERR("No devices in registry?\n");
284 key_name_size
= ARRAY_SIZE(key_name
);
285 if(RegEnumKeyExW(devices_key
, i
++, key_name
, &key_name_size
, NULL
,
286 NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
289 if(RegOpenKeyExW(devices_key
, key_name
, 0, KEY_READ
, &key
) != ERROR_SUCCESS
){
290 WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name
));
294 size
= sizeof(reg_guid
);
295 if(RegQueryValueExW(key
, L
"guid", 0, &type
,
296 (BYTE
*)®_guid
, &size
) == ERROR_SUCCESS
){
297 if(IsEqualGUID(®_guid
, guid
)){
299 RegCloseKey(devices_key
);
301 TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name
));
303 if(key_name
[0] == '0')
305 else if(key_name
[0] == '1')
308 ERR("Unknown device type: %c\n", key_name
[0]);
312 WideCharToMultiByte(CP_UNIXCP
, 0, key_name
+ 2, -1, name
, name_size
, NULL
, NULL
);
321 RegCloseKey(devices_key
);
323 WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid
));
328 HRESULT WINAPI
AUDDRV_GetAudioEndpoint(GUID
*guid
, IMMDevice
*dev
, IAudioClient
**out
)
336 TRACE("%s %p %p\n", debugstr_guid(guid
), dev
, out
);
338 if(!get_device_name_by_guid(guid
, name
, sizeof(name
), &dataflow
))
339 return AUDCLNT_E_DEVICE_INVALIDATED
;
341 if(dataflow
!= eRender
&& dataflow
!= eCapture
)
344 name_len
= strlen(name
);
345 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, offsetof(ACImpl
, device_name
[name_len
+ 1]));
347 return E_OUTOFMEMORY
;
349 This
->IAudioClient3_iface
.lpVtbl
= &AudioClient3_Vtbl
;
350 This
->IAudioRenderClient_iface
.lpVtbl
= &AudioRenderClient_Vtbl
;
351 This
->IAudioCaptureClient_iface
.lpVtbl
= &AudioCaptureClient_Vtbl
;
352 This
->IAudioClock_iface
.lpVtbl
= &AudioClock_Vtbl
;
353 This
->IAudioClock2_iface
.lpVtbl
= &AudioClock2_Vtbl
;
354 This
->IAudioStreamVolume_iface
.lpVtbl
= &AudioStreamVolume_Vtbl
;
356 This
->dataflow
= dataflow
;
357 memcpy(This
->device_name
, name
, name_len
+ 1);
359 hr
= CoCreateFreeThreadedMarshaler((IUnknown
*)&This
->IAudioClient3_iface
, &This
->marshal
);
361 HeapFree(GetProcessHeap(), 0, This
);
366 IMMDevice_AddRef(This
->parent
);
368 *out
= (IAudioClient
*)&This
->IAudioClient3_iface
;
369 IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
374 static HRESULT WINAPI
AudioClient_QueryInterface(IAudioClient3
*iface
,
375 REFIID riid
, void **ppv
)
377 ACImpl
*This
= impl_from_IAudioClient3(iface
);
378 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
383 if(IsEqualIID(riid
, &IID_IUnknown
) ||
384 IsEqualIID(riid
, &IID_IAudioClient
) ||
385 IsEqualIID(riid
, &IID_IAudioClient2
) ||
386 IsEqualIID(riid
, &IID_IAudioClient3
))
388 else if(IsEqualIID(riid
, &IID_IMarshal
))
389 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
392 IUnknown_AddRef((IUnknown
*)*ppv
);
395 WARN("Unknown interface %s\n", debugstr_guid(riid
));
396 return E_NOINTERFACE
;
399 static ULONG WINAPI
AudioClient_AddRef(IAudioClient3
*iface
)
401 ACImpl
*This
= impl_from_IAudioClient3(iface
);
403 ref
= InterlockedIncrement(&This
->ref
);
404 TRACE("(%p) Refcount now %lu\n", This
, ref
);
408 static ULONG WINAPI
AudioClient_Release(IAudioClient3
*iface
)
410 ACImpl
*This
= impl_from_IAudioClient3(iface
);
412 ref
= InterlockedDecrement(&This
->ref
);
413 TRACE("(%p) Refcount now %lu\n", This
, ref
);
416 struct release_stream_params params
;
417 params
.stream
= This
->stream
;
418 params
.timer_thread
= This
->timer_thread
;
419 UNIX_CALL(release_stream
, ¶ms
);
423 list_remove(&This
->entry
);
426 HeapFree(GetProcessHeap(), 0, This
->vols
);
427 IMMDevice_Release(This
->parent
);
428 IUnknown_Release(This
->marshal
);
429 HeapFree(GetProcessHeap(), 0, This
);
434 static void dump_fmt(const WAVEFORMATEX
*fmt
)
436 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
437 switch(fmt
->wFormatTag
){
438 case WAVE_FORMAT_PCM
:
439 TRACE("WAVE_FORMAT_PCM");
441 case WAVE_FORMAT_IEEE_FLOAT
:
442 TRACE("WAVE_FORMAT_IEEE_FLOAT");
444 case WAVE_FORMAT_EXTENSIBLE
:
445 TRACE("WAVE_FORMAT_EXTENSIBLE");
453 TRACE("nChannels: %u\n", fmt
->nChannels
);
454 TRACE("nSamplesPerSec: %lu\n", fmt
->nSamplesPerSec
);
455 TRACE("nAvgBytesPerSec: %lu\n", fmt
->nAvgBytesPerSec
);
456 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
457 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
458 TRACE("cbSize: %u\n", fmt
->cbSize
);
460 if(fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
){
461 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
462 TRACE("dwChannelMask: %08lx\n", fmtex
->dwChannelMask
);
463 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
464 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
468 static void session_init_vols(AudioSession
*session
, UINT channels
)
470 if(session
->channel_count
< channels
){
473 if(session
->channel_vols
)
474 session
->channel_vols
= HeapReAlloc(GetProcessHeap(), 0,
475 session
->channel_vols
, sizeof(float) * channels
);
477 session
->channel_vols
= HeapAlloc(GetProcessHeap(), 0,
478 sizeof(float) * channels
);
479 if(!session
->channel_vols
)
482 for(i
= session
->channel_count
; i
< channels
; ++i
)
483 session
->channel_vols
[i
] = 1.f
;
485 session
->channel_count
= channels
;
489 static AudioSession
*create_session(const GUID
*guid
, IMMDevice
*device
,
494 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AudioSession
));
498 memcpy(&ret
->guid
, guid
, sizeof(GUID
));
500 ret
->device
= device
;
502 list_init(&ret
->clients
);
504 list_add_head(&g_sessions
, &ret
->entry
);
506 session_init_vols(ret
, num_channels
);
508 ret
->master_vol
= 1.f
;
513 /* if channels == 0, then this will return or create a session with
514 * matching dataflow and GUID. otherwise, channels must also match */
515 static HRESULT
get_audio_session(const GUID
*sessionguid
,
516 IMMDevice
*device
, UINT channels
, AudioSession
**out
)
518 AudioSession
*session
;
520 if(!sessionguid
|| IsEqualGUID(sessionguid
, &GUID_NULL
)){
521 *out
= create_session(&GUID_NULL
, device
, channels
);
523 return E_OUTOFMEMORY
;
529 LIST_FOR_EACH_ENTRY(session
, &g_sessions
, AudioSession
, entry
){
530 if(session
->device
== device
&&
531 IsEqualGUID(sessionguid
, &session
->guid
)){
532 session_init_vols(session
, channels
);
539 *out
= create_session(sessionguid
, device
, channels
);
541 return E_OUTOFMEMORY
;
547 static HRESULT WINAPI
AudioClient_Initialize(IAudioClient3
*iface
,
548 AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
,
549 REFERENCE_TIME period
, const WAVEFORMATEX
*fmt
,
550 const GUID
*sessionguid
)
552 ACImpl
*This
= impl_from_IAudioClient3(iface
);
553 struct release_stream_params release_params
;
554 struct create_stream_params params
;
555 stream_handle stream
;
558 TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This
, mode
, flags
,
559 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(period
), fmt
, debugstr_guid(sessionguid
));
566 if(mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
569 if(flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
|
570 AUDCLNT_STREAMFLAGS_LOOPBACK
|
571 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
572 AUDCLNT_STREAMFLAGS_NOPERSIST
|
573 AUDCLNT_STREAMFLAGS_RATEADJUST
|
574 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
|
575 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
|
576 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
|
577 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
|
578 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
)){
579 FIXME("Unknown flags: %08lx\n", flags
);
587 return AUDCLNT_E_ALREADY_INITIALIZED
;
591 params
.device
= This
->device_name
;
592 params
.flow
= This
->dataflow
;
594 params
.flags
= flags
;
595 params
.duration
= duration
;
596 params
.period
= period
;
598 params
.channel_count
= NULL
;
599 params
.stream
= &stream
;
601 UNIX_CALL(create_stream
, ¶ms
);
602 if(FAILED(params
.result
)){
604 return params
.result
;
607 This
->channel_count
= fmt
->nChannels
;
609 This
->vols
= HeapAlloc(GetProcessHeap(), 0, This
->channel_count
* sizeof(float));
611 params
.result
= E_OUTOFMEMORY
;
615 for(i
= 0; i
< This
->channel_count
; ++i
)
618 params
.result
= get_audio_session(sessionguid
, This
->parent
, fmt
->nChannels
, &This
->session
);
619 if(FAILED(params
.result
)) goto end
;
621 list_add_tail(&This
->session
->clients
, &This
->entry
);
624 if(FAILED(params
.result
)){
625 release_params
.stream
= stream
;
626 UNIX_CALL(release_stream
, &release_params
);
627 HeapFree(GetProcessHeap(), 0, This
->vols
);
630 This
->stream
= stream
;
631 set_stream_volumes(This
);
636 return params
.result
;
639 static HRESULT WINAPI
AudioClient_GetBufferSize(IAudioClient3
*iface
,
642 ACImpl
*This
= impl_from_IAudioClient3(iface
);
643 struct get_buffer_size_params params
;
645 TRACE("(%p)->(%p)\n", This
, frames
);
651 return AUDCLNT_E_NOT_INITIALIZED
;
653 params
.stream
= This
->stream
;
654 params
.frames
= frames
;
655 UNIX_CALL(get_buffer_size
, ¶ms
);
656 return params
.result
;
659 static HRESULT WINAPI
AudioClient_GetStreamLatency(IAudioClient3
*iface
,
662 ACImpl
*This
= impl_from_IAudioClient3(iface
);
663 struct get_latency_params params
;
665 TRACE("(%p)->(%p)\n", This
, out
);
671 return AUDCLNT_E_NOT_INITIALIZED
;
673 params
.stream
= This
->stream
;
674 params
.latency
= out
;
675 UNIX_CALL(get_latency
, ¶ms
);
676 return params
.result
;
679 static HRESULT WINAPI
AudioClient_GetCurrentPadding(IAudioClient3
*iface
,
682 ACImpl
*This
= impl_from_IAudioClient3(iface
);
683 struct get_current_padding_params params
;
685 TRACE("(%p)->(%p)\n", This
, numpad
);
691 return AUDCLNT_E_NOT_INITIALIZED
;
693 params
.stream
= This
->stream
;
694 params
.padding
= numpad
;
695 UNIX_CALL(get_current_padding
, ¶ms
);
696 return params
.result
;
699 static HRESULT WINAPI
AudioClient_IsFormatSupported(IAudioClient3
*iface
,
700 AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*pwfx
,
701 WAVEFORMATEX
**outpwfx
)
703 ACImpl
*This
= impl_from_IAudioClient3(iface
);
704 struct is_format_supported_params params
;
706 TRACE("(%p)->(%x, %p, %p)\n", This
, mode
, pwfx
, outpwfx
);
707 if(pwfx
) dump_fmt(pwfx
);
709 params
.device
= This
->device_name
;
710 params
.flow
= This
->dataflow
;
712 params
.fmt_in
= pwfx
;
713 params
.fmt_out
= NULL
;
717 if(mode
== AUDCLNT_SHAREMODE_SHARED
)
718 params
.fmt_out
= CoTaskMemAlloc(sizeof(*params
.fmt_out
));
720 UNIX_CALL(is_format_supported
, ¶ms
);
722 if(params
.result
== S_FALSE
)
723 *outpwfx
= ¶ms
.fmt_out
->Format
;
725 CoTaskMemFree(params
.fmt_out
);
727 return params
.result
;
730 static HRESULT WINAPI
AudioClient_GetMixFormat(IAudioClient3
*iface
,
733 ACImpl
*This
= impl_from_IAudioClient3(iface
);
734 struct get_mix_format_params params
;
736 TRACE("(%p)->(%p)\n", This
, pwfx
);
742 params
.device
= This
->device_name
;
743 params
.flow
= This
->dataflow
;
744 params
.fmt
= CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE
));
746 return E_OUTOFMEMORY
;
748 UNIX_CALL(get_mix_format
, ¶ms
);
750 if(SUCCEEDED(params
.result
)){
751 *pwfx
= ¶ms
.fmt
->Format
;
754 CoTaskMemFree(params
.fmt
);
756 return params
.result
;
759 static HRESULT WINAPI
AudioClient_GetDevicePeriod(IAudioClient3
*iface
,
760 REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
762 ACImpl
*This
= impl_from_IAudioClient3(iface
);
763 struct get_device_period_params params
;
765 TRACE("(%p)->(%p, %p)\n", This
, defperiod
, minperiod
);
767 if (!defperiod
&& !minperiod
)
770 params
.device
= This
->device_name
;
771 params
.flow
= This
->dataflow
;
772 params
.def_period
= defperiod
;
773 params
.min_period
= minperiod
;
775 UNIX_CALL(get_device_period
, ¶ms
);
777 return params
.result
;
780 static DWORD WINAPI
ca_timer_thread(void *user
)
782 struct timer_loop_params params
;
784 params
.stream
= This
->stream
;
785 SetThreadDescription(GetCurrentThread(), L
"winecoreaudio_timer_loop");
786 UNIX_CALL(timer_loop
, ¶ms
);
790 static HRESULT WINAPI
AudioClient_Start(IAudioClient3
*iface
)
792 ACImpl
*This
= impl_from_IAudioClient3(iface
);
793 struct start_params params
;
796 TRACE("(%p)\n", This
);
799 return AUDCLNT_E_NOT_INITIALIZED
;
801 params
.stream
= This
->stream
;
802 UNIX_CALL(start
, ¶ms
);
803 if(FAILED(hr
= params
.result
))
806 if(!This
->timer_thread
) {
807 This
->timer_thread
= CreateThread(NULL
, 0, ca_timer_thread
, This
, 0, NULL
);
808 SetThreadPriority(This
->timer_thread
, THREAD_PRIORITY_TIME_CRITICAL
);
814 static HRESULT WINAPI
AudioClient_Stop(IAudioClient3
*iface
)
816 ACImpl
*This
= impl_from_IAudioClient3(iface
);
817 struct stop_params params
;
819 TRACE("(%p)\n", This
);
822 return AUDCLNT_E_NOT_INITIALIZED
;
824 params
.stream
= This
->stream
;
825 UNIX_CALL(stop
, ¶ms
);
826 return params
.result
;
829 static HRESULT WINAPI
AudioClient_Reset(IAudioClient3
*iface
)
831 ACImpl
*This
= impl_from_IAudioClient3(iface
);
832 struct reset_params params
;
834 TRACE("(%p)\n", This
);
837 return AUDCLNT_E_NOT_INITIALIZED
;
839 params
.stream
= This
->stream
;
840 UNIX_CALL(reset
, ¶ms
);
841 return params
.result
;
844 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient3
*iface
,
847 ACImpl
*This
= impl_from_IAudioClient3(iface
);
848 struct set_event_handle_params params
;
850 TRACE("(%p)->(%p)\n", This
, event
);
856 return AUDCLNT_E_NOT_INITIALIZED
;
858 params
.stream
= This
->stream
;
859 params
.event
= event
;
860 UNIX_CALL(set_event_handle
, ¶ms
);
861 return params
.result
;
864 static HRESULT WINAPI
AudioClient_GetService(IAudioClient3
*iface
, REFIID riid
,
867 ACImpl
*This
= impl_from_IAudioClient3(iface
);
870 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
877 return AUDCLNT_E_NOT_INITIALIZED
;
881 if(IsEqualIID(riid
, &IID_IAudioRenderClient
)){
882 if(This
->dataflow
!= eRender
){
883 hr
= AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
886 IAudioRenderClient_AddRef(&This
->IAudioRenderClient_iface
);
887 *ppv
= &This
->IAudioRenderClient_iface
;
888 }else if(IsEqualIID(riid
, &IID_IAudioCaptureClient
)){
889 if(This
->dataflow
!= eCapture
){
890 hr
= AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
893 IAudioCaptureClient_AddRef(&This
->IAudioCaptureClient_iface
);
894 *ppv
= &This
->IAudioCaptureClient_iface
;
895 }else if(IsEqualIID(riid
, &IID_IAudioClock
)){
896 IAudioClock_AddRef(&This
->IAudioClock_iface
);
897 *ppv
= &This
->IAudioClock_iface
;
898 }else if(IsEqualIID(riid
, &IID_IAudioStreamVolume
)){
899 IAudioStreamVolume_AddRef(&This
->IAudioStreamVolume_iface
);
900 *ppv
= &This
->IAudioStreamVolume_iface
;
901 }else if(IsEqualIID(riid
, &IID_IAudioSessionControl
)){
902 if(!This
->session_wrapper
){
903 This
->session_wrapper
= session_wrapper_create(This
);
904 if(!This
->session_wrapper
){
909 IAudioSessionControl2_AddRef(&This
->session_wrapper
->IAudioSessionControl2_iface
);
911 *ppv
= &This
->session_wrapper
->IAudioSessionControl2_iface
;
912 }else if(IsEqualIID(riid
, &IID_IChannelAudioVolume
)){
913 if(!This
->session_wrapper
){
914 This
->session_wrapper
= session_wrapper_create(This
);
915 if(!This
->session_wrapper
){
920 IChannelAudioVolume_AddRef(&This
->session_wrapper
->IChannelAudioVolume_iface
);
922 *ppv
= &This
->session_wrapper
->IChannelAudioVolume_iface
;
923 }else if(IsEqualIID(riid
, &IID_ISimpleAudioVolume
)){
924 if(!This
->session_wrapper
){
925 This
->session_wrapper
= session_wrapper_create(This
);
926 if(!This
->session_wrapper
){
931 ISimpleAudioVolume_AddRef(&This
->session_wrapper
->ISimpleAudioVolume_iface
);
933 *ppv
= &This
->session_wrapper
->ISimpleAudioVolume_iface
;
938 FIXME("stub %s\n", debugstr_guid(riid
));
947 extern HRESULT WINAPI
client_IsOffloadCapable(IAudioClient3
*iface
,
948 AUDIO_STREAM_CATEGORY category
, BOOL
*offload_capable
);
950 extern HRESULT WINAPI
client_SetClientProperties(IAudioClient3
*iface
,
951 const AudioClientProperties
*prop
);
953 extern HRESULT WINAPI
client_GetBufferSizeLimits(IAudioClient3
*iface
,
954 const WAVEFORMATEX
*format
, BOOL event_driven
, REFERENCE_TIME
*min_duration
,
955 REFERENCE_TIME
*max_duration
);
957 extern HRESULT WINAPI
client_GetSharedModeEnginePeriod(IAudioClient3
*iface
,
958 const WAVEFORMATEX
*format
, UINT32
*default_period_frames
, UINT32
*unit_period_frames
,
959 UINT32
*min_period_frames
, UINT32
*max_period_frames
);
961 extern HRESULT WINAPI
client_GetCurrentSharedModeEnginePeriod(IAudioClient3
*iface
,
962 WAVEFORMATEX
**cur_format
, UINT32
*cur_period_frames
);
964 extern HRESULT WINAPI
client_InitializeSharedAudioStream(IAudioClient3
*iface
,
965 DWORD flags
, UINT32 period_frames
, const WAVEFORMATEX
*format
,
966 const GUID
*session_guid
);
968 static const IAudioClient3Vtbl AudioClient3_Vtbl
=
970 AudioClient_QueryInterface
,
973 AudioClient_Initialize
,
974 AudioClient_GetBufferSize
,
975 AudioClient_GetStreamLatency
,
976 AudioClient_GetCurrentPadding
,
977 AudioClient_IsFormatSupported
,
978 AudioClient_GetMixFormat
,
979 AudioClient_GetDevicePeriod
,
983 AudioClient_SetEventHandle
,
984 AudioClient_GetService
,
985 client_IsOffloadCapable
,
986 client_SetClientProperties
,
987 client_GetBufferSizeLimits
,
988 client_GetSharedModeEnginePeriod
,
989 client_GetCurrentSharedModeEnginePeriod
,
990 client_InitializeSharedAudioStream
,
993 HRESULT WINAPI
AUDDRV_GetAudioSessionWrapper(const GUID
*guid
, IMMDevice
*device
,
994 AudioSessionWrapper
**out
)
996 AudioSession
*session
;
998 HRESULT hr
= get_audio_session(guid
, device
, 0, &session
);
1002 *out
= session_wrapper_create(NULL
);
1004 return E_OUTOFMEMORY
;
1006 (*out
)->session
= session
;