2 * Copyright 2011-2012 Maarten Lankhorst
3 * Copyright 2010-2011 Maarten Lankhorst for CodeWeavers
4 * Copyright 2011 Andrew Eikum for CodeWeavers
5 * Copyright 2022 Huw Davies
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <audiopolicy.h>
25 #include <mmdeviceapi.h>
28 #include <wine/debug.h>
29 #include <wine/unixlib.h>
34 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi
);
36 extern void sessions_lock(void) DECLSPEC_HIDDEN
;
37 extern void sessions_unlock(void) DECLSPEC_HIDDEN
;
39 void set_stream_volumes(struct audio_client
*This
)
41 struct set_volumes_params params
;
43 params
.stream
= This
->stream
;
44 params
.master_volume
= (This
->session
->mute
? 0.0f
: This
->session
->master_vol
);
45 params
.volumes
= This
->vols
;
46 params
.session_volumes
= This
->session
->channel_vols
;
48 WINE_UNIX_CALL(set_volumes
, ¶ms
);
51 static inline struct audio_client
*impl_from_IAudioCaptureClient(IAudioCaptureClient
*iface
)
53 return CONTAINING_RECORD(iface
, struct audio_client
, IAudioCaptureClient_iface
);
56 static inline struct audio_client
*impl_from_IAudioClient3(IAudioClient3
*iface
)
58 return CONTAINING_RECORD(iface
, struct audio_client
, IAudioClient3_iface
);
61 static inline struct audio_client
*impl_from_IAudioClock(IAudioClock
*iface
)
63 return CONTAINING_RECORD(iface
, struct audio_client
, IAudioClock_iface
);
66 static inline struct audio_client
*impl_from_IAudioClock2(IAudioClock2
*iface
)
68 return CONTAINING_RECORD(iface
, struct audio_client
, IAudioClock2_iface
);
71 static inline struct audio_client
*impl_from_IAudioRenderClient(IAudioRenderClient
*iface
)
73 return CONTAINING_RECORD(iface
, struct audio_client
, IAudioRenderClient_iface
);
76 static inline struct audio_client
*impl_from_IAudioStreamVolume(IAudioStreamVolume
*iface
)
78 return CONTAINING_RECORD(iface
, struct audio_client
, IAudioStreamVolume_iface
);
81 static HRESULT WINAPI
capture_QueryInterface(IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
83 struct audio_client
*This
= impl_from_IAudioCaptureClient(iface
);
85 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
90 if (IsEqualIID(riid
, &IID_IUnknown
) ||
91 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
93 else if (IsEqualIID(riid
, &IID_IMarshal
)) {
94 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
100 IUnknown_AddRef((IUnknown
*)*ppv
);
105 static ULONG WINAPI
capture_AddRef(IAudioCaptureClient
*iface
)
107 struct audio_client
*This
= impl_from_IAudioCaptureClient(iface
);
108 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
111 static ULONG WINAPI
capture_Release(IAudioCaptureClient
*iface
)
113 struct audio_client
*This
= impl_from_IAudioCaptureClient(iface
);
114 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
117 static HRESULT WINAPI
capture_GetBuffer(IAudioCaptureClient
*iface
, BYTE
**data
, UINT32
*frames
,
118 DWORD
*flags
, UINT64
*devpos
, UINT64
*qpcpos
)
120 struct audio_client
*This
= impl_from_IAudioCaptureClient(iface
);
121 struct get_capture_buffer_params params
;
123 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
, devpos
, qpcpos
);
130 if (!frames
|| !flags
)
134 return AUDCLNT_E_NOT_INITIALIZED
;
136 params
.stream
= This
->stream
;
138 params
.frames
= frames
;
139 params
.flags
= (UINT
*)flags
;
140 params
.devpos
= devpos
;
141 params
.qpcpos
= qpcpos
;
143 WINE_UNIX_CALL(get_capture_buffer
, ¶ms
);
145 return params
.result
;
148 static HRESULT WINAPI
capture_ReleaseBuffer(IAudioCaptureClient
*iface
, UINT32 done
)
150 struct audio_client
*This
= impl_from_IAudioCaptureClient(iface
);
151 struct release_capture_buffer_params params
;
153 TRACE("(%p)->(%u)\n", This
, done
);
156 return AUDCLNT_E_NOT_INITIALIZED
;
158 params
.stream
= This
->stream
;
161 WINE_UNIX_CALL(release_capture_buffer
, ¶ms
);
163 return params
.result
;
166 static HRESULT WINAPI
capture_GetNextPacketSize(IAudioCaptureClient
*iface
, UINT32
*frames
)
168 struct audio_client
*This
= impl_from_IAudioCaptureClient(iface
);
169 struct get_next_packet_size_params params
;
171 TRACE("(%p)->(%p)\n", This
, frames
);
177 return AUDCLNT_E_NOT_INITIALIZED
;
179 params
.stream
= This
->stream
;
180 params
.frames
= frames
;
182 WINE_UNIX_CALL(get_next_packet_size
, ¶ms
);
184 return params
.result
;
187 const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
189 capture_QueryInterface
,
193 capture_ReleaseBuffer
,
194 capture_GetNextPacketSize
197 HRESULT WINAPI
client_IsOffloadCapable(IAudioClient3
*iface
, AUDIO_STREAM_CATEGORY category
,
198 BOOL
*offload_capable
)
200 struct audio_client
*This
= impl_from_IAudioClient3(iface
);
202 TRACE("(%p)->(0x%x, %p)\n", This
, category
, offload_capable
);
204 if (!offload_capable
)
207 *offload_capable
= FALSE
;
212 HRESULT WINAPI
client_SetClientProperties(IAudioClient3
*iface
,
213 const AudioClientProperties
*prop
)
215 struct audio_client
*This
= impl_from_IAudioClient3(iface
);
216 const Win8AudioClientProperties
*legacy_prop
= (const Win8AudioClientProperties
*)prop
;
218 TRACE("(%p)->(%p)\n", This
, prop
);
223 if (legacy_prop
->cbSize
== sizeof(AudioClientProperties
)) {
224 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n", legacy_prop
->bIsOffload
,
225 legacy_prop
->eCategory
,
227 } else if(legacy_prop
->cbSize
== sizeof(Win8AudioClientProperties
)) {
228 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n", legacy_prop
->bIsOffload
,
229 legacy_prop
->eCategory
);
231 WARN("Unsupported Size = %d\n", legacy_prop
->cbSize
);
235 if (legacy_prop
->bIsOffload
)
236 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE
;
241 HRESULT WINAPI
client_GetBufferSizeLimits(IAudioClient3
*iface
, const WAVEFORMATEX
*format
,
242 BOOL event_driven
, REFERENCE_TIME
*min_duration
,
243 REFERENCE_TIME
*max_duration
)
245 struct audio_client
*This
= impl_from_IAudioClient3(iface
);
246 FIXME("(%p)->(%p, %u, %p, %p) - stub\n", This
, format
, event_driven
, min_duration
, max_duration
);
250 HRESULT WINAPI
client_GetSharedModeEnginePeriod(IAudioClient3
*iface
,
251 const WAVEFORMATEX
*format
,
252 UINT32
*default_period_frames
,
253 UINT32
*unit_period_frames
,
254 UINT32
*min_period_frames
,
255 UINT32
*max_period_frames
)
257 struct audio_client
*This
= impl_from_IAudioClient3(iface
);
258 FIXME("(%p)->(%p, %p, %p, %p, %p) - stub\n", This
, format
, default_period_frames
,
259 unit_period_frames
, min_period_frames
,
264 HRESULT WINAPI
client_GetCurrentSharedModeEnginePeriod(IAudioClient3
*iface
,
265 WAVEFORMATEX
**cur_format
,
266 UINT32
*cur_period_frames
)
268 struct audio_client
*This
= impl_from_IAudioClient3(iface
);
269 FIXME("(%p)->(%p, %p) - stub\n", This
, cur_format
, cur_period_frames
);
273 HRESULT WINAPI
client_InitializeSharedAudioStream(IAudioClient3
*iface
, DWORD flags
,
274 UINT32 period_frames
,
275 const WAVEFORMATEX
*format
,
276 const GUID
*session_guid
)
278 struct audio_client
*This
= impl_from_IAudioClient3(iface
);
279 FIXME("(%p)->(0x%lx, %u, %p, %s) - stub\n", This
, flags
, period_frames
, format
, debugstr_guid(session_guid
));
283 static HRESULT WINAPI
clock_QueryInterface(IAudioClock
*iface
, REFIID riid
, void **ppv
)
285 struct audio_client
*This
= impl_from_IAudioClock(iface
);
287 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
292 if (IsEqualIID(riid
, &IID_IUnknown
) ||
293 IsEqualIID(riid
, &IID_IAudioClock
))
295 else if (IsEqualIID(riid
, &IID_IAudioClock2
))
296 *ppv
= &This
->IAudioClock2_iface
;
297 else if (IsEqualIID(riid
, &IID_IMarshal
)) {
298 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
301 return E_NOINTERFACE
;
304 IUnknown_AddRef((IUnknown
*)*ppv
);
309 static ULONG WINAPI
clock_AddRef(IAudioClock
*iface
)
311 struct audio_client
*This
= impl_from_IAudioClock(iface
);
312 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
315 static ULONG WINAPI
clock_Release(IAudioClock
*iface
)
317 struct audio_client
*This
= impl_from_IAudioClock(iface
);
318 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
321 static HRESULT WINAPI
clock_GetFrequency(IAudioClock
*iface
, UINT64
*freq
)
323 struct audio_client
*This
= impl_from_IAudioClock(iface
);
324 struct get_frequency_params params
;
326 TRACE("(%p)->(%p)\n", This
, freq
);
329 return AUDCLNT_E_NOT_INITIALIZED
;
331 params
.stream
= This
->stream
;
334 WINE_UNIX_CALL(get_frequency
, ¶ms
);
336 return params
.result
;
339 static HRESULT WINAPI
clock_GetPosition(IAudioClock
*iface
, UINT64
*pos
, UINT64
*qpctime
)
341 struct audio_client
*This
= impl_from_IAudioClock(iface
);
342 struct get_position_params params
;
344 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
350 return AUDCLNT_E_NOT_INITIALIZED
;
352 params
.stream
= This
->stream
;
353 params
.device
= FALSE
;
355 params
.qpctime
= qpctime
;
357 WINE_UNIX_CALL(get_position
, ¶ms
);
359 return params
.result
;
362 static HRESULT WINAPI
clock_GetCharacteristics(IAudioClock
*iface
, DWORD
*chars
)
364 struct audio_client
*This
= impl_from_IAudioClock(iface
);
366 TRACE("(%p)->(%p)\n", This
, chars
);
371 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
376 const IAudioClockVtbl AudioClock_Vtbl
=
378 clock_QueryInterface
,
383 clock_GetCharacteristics
386 static HRESULT WINAPI
clock2_QueryInterface(IAudioClock2
*iface
, REFIID riid
, void **ppv
)
388 struct audio_client
*This
= impl_from_IAudioClock2(iface
);
389 return IAudioClock_QueryInterface(&This
->IAudioClock_iface
, riid
, ppv
);
392 static ULONG WINAPI
clock2_AddRef(IAudioClock2
*iface
)
394 struct audio_client
*This
= impl_from_IAudioClock2(iface
);
395 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
398 static ULONG WINAPI
clock2_Release(IAudioClock2
*iface
)
400 struct audio_client
*This
= impl_from_IAudioClock2(iface
);
401 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
404 static HRESULT WINAPI
clock2_GetDevicePosition(IAudioClock2
*iface
, UINT64
*pos
, UINT64
*qpctime
)
406 struct audio_client
*This
= impl_from_IAudioClock2(iface
);
407 struct get_position_params params
;
409 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
415 return AUDCLNT_E_NOT_INITIALIZED
;
417 params
.stream
= This
->stream
;
418 params
.device
= TRUE
;
420 params
.qpctime
= qpctime
;
422 WINE_UNIX_CALL(get_position
, ¶ms
);
424 return params
.result
;
427 const IAudioClock2Vtbl AudioClock2_Vtbl
=
429 clock2_QueryInterface
,
432 clock2_GetDevicePosition
435 static HRESULT WINAPI
render_QueryInterface(IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
437 struct audio_client
*This
= impl_from_IAudioRenderClient(iface
);
439 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
444 if (IsEqualIID(riid
, &IID_IUnknown
) ||
445 IsEqualIID(riid
, &IID_IAudioRenderClient
))
447 else if (IsEqualIID(riid
, &IID_IMarshal
)) {
448 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
451 return E_NOINTERFACE
;
454 IUnknown_AddRef((IUnknown
*)*ppv
);
459 static ULONG WINAPI
render_AddRef(IAudioRenderClient
*iface
)
461 struct audio_client
*This
= impl_from_IAudioRenderClient(iface
);
462 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
465 static ULONG WINAPI
render_Release(IAudioRenderClient
*iface
)
467 struct audio_client
*This
= impl_from_IAudioRenderClient(iface
);
468 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
471 static HRESULT WINAPI
render_GetBuffer(IAudioRenderClient
*iface
, UINT32 frames
, BYTE
**data
)
473 struct audio_client
*This
= impl_from_IAudioRenderClient(iface
);
474 struct get_render_buffer_params params
;
476 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
482 return AUDCLNT_E_NOT_INITIALIZED
;
486 params
.stream
= This
->stream
;
487 params
.frames
= frames
;
490 WINE_UNIX_CALL(get_render_buffer
, ¶ms
);
492 return params
.result
;
495 static HRESULT WINAPI
render_ReleaseBuffer(IAudioRenderClient
*iface
, UINT32 written_frames
,
498 struct audio_client
*This
= impl_from_IAudioRenderClient(iface
);
499 struct release_render_buffer_params params
;
501 TRACE("(%p)->(%u, %lx)\n", This
, written_frames
, flags
);
504 return AUDCLNT_E_NOT_INITIALIZED
;
506 params
.stream
= This
->stream
;
507 params
.written_frames
= written_frames
;
508 params
.flags
= flags
;
510 WINE_UNIX_CALL(release_render_buffer
, ¶ms
);
512 return params
.result
;
515 const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
516 render_QueryInterface
,
523 static HRESULT WINAPI
streamvolume_QueryInterface(IAudioStreamVolume
*iface
, REFIID riid
,
526 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
531 if (IsEqualIID(riid
, &IID_IUnknown
) ||
532 IsEqualIID(riid
, &IID_IAudioStreamVolume
))
534 else if (IsEqualIID(riid
, &IID_IMarshal
)) {
535 struct audio_client
*This
= impl_from_IAudioStreamVolume(iface
);
536 return IUnknown_QueryInterface(This
->marshal
, riid
, ppv
);
539 return E_NOINTERFACE
;
542 IUnknown_AddRef((IUnknown
*)*ppv
);
547 static ULONG WINAPI
streamvolume_AddRef(IAudioStreamVolume
*iface
)
549 struct audio_client
*This
= impl_from_IAudioStreamVolume(iface
);
550 return IAudioClient3_AddRef(&This
->IAudioClient3_iface
);
553 static ULONG WINAPI
streamvolume_Release(IAudioStreamVolume
*iface
)
555 struct audio_client
*This
= impl_from_IAudioStreamVolume(iface
);
556 return IAudioClient3_Release(&This
->IAudioClient3_iface
);
559 static HRESULT WINAPI
streamvolume_GetChannelCount(IAudioStreamVolume
*iface
, UINT32
*out
)
561 struct audio_client
*This
= impl_from_IAudioStreamVolume(iface
);
563 TRACE("(%p)->(%p)\n", This
, out
);
568 *out
= This
->channel_count
;
573 static HRESULT WINAPI
streamvolume_SetChannelVolume(IAudioStreamVolume
*iface
, UINT32 index
,
576 struct audio_client
*This
= impl_from_IAudioStreamVolume(iface
);
578 TRACE("(%p)->(%d, %f)\n", This
, index
, level
);
580 if (level
< 0.f
|| level
> 1.f
)
584 return AUDCLNT_E_NOT_INITIALIZED
;
586 if (index
>= This
->channel_count
)
591 This
->vols
[index
] = level
;
592 set_stream_volumes(This
);
599 static HRESULT WINAPI
streamvolume_GetChannelVolume(IAudioStreamVolume
*iface
, UINT32 index
,
602 struct audio_client
*This
= impl_from_IAudioStreamVolume(iface
);
604 TRACE("(%p)->(%d, %p)\n", This
, index
, level
);
610 return AUDCLNT_E_NOT_INITIALIZED
;
612 if (index
>= This
->channel_count
)
615 *level
= This
->vols
[index
];
620 static HRESULT WINAPI
streamvolume_SetAllVolumes(IAudioStreamVolume
*iface
, UINT32 count
,
623 struct audio_client
*This
= impl_from_IAudioStreamVolume(iface
);
626 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
632 return AUDCLNT_E_NOT_INITIALIZED
;
634 if (count
!= This
->channel_count
)
639 for (i
= 0; i
< count
; ++i
)
640 This
->vols
[i
] = levels
[i
];
641 set_stream_volumes(This
);
648 static HRESULT WINAPI
streamvolume_GetAllVolumes(IAudioStreamVolume
*iface
, UINT32 count
,
651 struct audio_client
*This
= impl_from_IAudioStreamVolume(iface
);
654 TRACE("(%p)->(%d, %p)\n", This
, count
, levels
);
660 return AUDCLNT_E_NOT_INITIALIZED
;
662 if (count
!= This
->channel_count
)
667 for (i
= 0; i
< count
; ++i
)
668 levels
[i
] = This
->vols
[i
];
675 const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl
=
677 streamvolume_QueryInterface
,
679 streamvolume_Release
,
680 streamvolume_GetChannelCount
,
681 streamvolume_SetChannelVolume
,
682 streamvolume_GetChannelVolume
,
683 streamvolume_SetAllVolumes
,
684 streamvolume_GetAllVolumes