winepulse: Lock sessions in AudioClient's GetService.
[wine.git] / dlls / mmdevapi / client.c
blob87bc3fef0e57804cf6e2191324416ffe7d2d008e
1 /*
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
22 #define COBJMACROS
24 #include <audiopolicy.h>
25 #include <mmdeviceapi.h>
26 #include <winternl.h>
28 #include <wine/debug.h>
29 #include <wine/unixlib.h>
31 #include "mmdevdrv.h"
32 #include "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, &params);
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);
87 if (!ppv)
88 return E_POINTER;
90 if (IsEqualIID(riid, &IID_IUnknown) ||
91 IsEqualIID(riid, &IID_IAudioCaptureClient))
92 *ppv = iface;
93 else if (IsEqualIID(riid, &IID_IMarshal)) {
94 return IUnknown_QueryInterface(This->marshal, riid, ppv);
95 } else {
96 *ppv = NULL;
97 return E_NOINTERFACE;
100 IUnknown_AddRef((IUnknown *)*ppv);
102 return S_OK;
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);
125 if (!data)
126 return E_POINTER;
128 *data = NULL;
130 if (!frames || !flags)
131 return E_POINTER;
133 if (!This->stream)
134 return AUDCLNT_E_NOT_INITIALIZED;
136 params.stream = This->stream;
137 params.data = data;
138 params.frames = frames;
139 params.flags = (UINT *)flags;
140 params.devpos = devpos;
141 params.qpcpos = qpcpos;
143 WINE_UNIX_CALL(get_capture_buffer, &params);
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);
155 if (!This->stream)
156 return AUDCLNT_E_NOT_INITIALIZED;
158 params.stream = This->stream;
159 params.done = done;
161 WINE_UNIX_CALL(release_capture_buffer, &params);
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);
173 if (!frames)
174 return E_POINTER;
176 if (!This->stream)
177 return AUDCLNT_E_NOT_INITIALIZED;
179 params.stream = This->stream;
180 params.frames = frames;
182 WINE_UNIX_CALL(get_next_packet_size, &params);
184 return params.result;
187 const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
189 capture_QueryInterface,
190 capture_AddRef,
191 capture_Release,
192 capture_GetBuffer,
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)
205 return E_INVALIDARG;
207 *offload_capable = FALSE;
209 return S_OK;
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);
220 if (!legacy_prop)
221 return E_POINTER;
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,
226 prop->Options);
227 } else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)) {
228 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n", legacy_prop->bIsOffload,
229 legacy_prop->eCategory);
230 } else {
231 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
232 return E_INVALIDARG;
235 if (legacy_prop->bIsOffload)
236 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
238 return S_OK;
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);
247 return E_NOTIMPL;
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,
260 max_period_frames);
261 return E_NOTIMPL;
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);
270 return E_NOTIMPL;
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));
280 return E_NOTIMPL;
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);
289 if (!ppv)
290 return E_POINTER;
292 if (IsEqualIID(riid, &IID_IUnknown) ||
293 IsEqualIID(riid, &IID_IAudioClock))
294 *ppv = iface;
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);
299 } else {
300 *ppv = NULL;
301 return E_NOINTERFACE;
304 IUnknown_AddRef((IUnknown *)*ppv);
306 return S_OK;
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);
328 if (!This->stream)
329 return AUDCLNT_E_NOT_INITIALIZED;
331 params.stream = This->stream;
332 params.freq = freq;
334 WINE_UNIX_CALL(get_frequency, &params);
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);
346 if (!pos)
347 return E_POINTER;
349 if (!This->stream)
350 return AUDCLNT_E_NOT_INITIALIZED;
352 params.stream = This->stream;
353 params.device = FALSE;
354 params.pos = pos;
355 params.qpctime = qpctime;
357 WINE_UNIX_CALL(get_position, &params);
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);
368 if (!chars)
369 return E_POINTER;
371 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
373 return S_OK;
376 const IAudioClockVtbl AudioClock_Vtbl =
378 clock_QueryInterface,
379 clock_AddRef,
380 clock_Release,
381 clock_GetFrequency,
382 clock_GetPosition,
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);
411 if (!pos)
412 return E_POINTER;
414 if (!This->stream)
415 return AUDCLNT_E_NOT_INITIALIZED;
417 params.stream = This->stream;
418 params.device = TRUE;
419 params.pos = pos;
420 params.qpctime = qpctime;
422 WINE_UNIX_CALL(get_position, &params);
424 return params.result;
427 const IAudioClock2Vtbl AudioClock2_Vtbl =
429 clock2_QueryInterface,
430 clock2_AddRef,
431 clock2_Release,
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);
441 if (!ppv)
442 return E_POINTER;
444 if (IsEqualIID(riid, &IID_IUnknown) ||
445 IsEqualIID(riid, &IID_IAudioRenderClient))
446 *ppv = iface;
447 else if (IsEqualIID(riid, &IID_IMarshal)) {
448 return IUnknown_QueryInterface(This->marshal, riid, ppv);
449 } else {
450 *ppv = NULL;
451 return E_NOINTERFACE;
454 IUnknown_AddRef((IUnknown *)*ppv);
456 return S_OK;
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);
478 if (!data)
479 return E_POINTER;
481 if (!This->stream)
482 return AUDCLNT_E_NOT_INITIALIZED;
484 *data = NULL;
486 params.stream = This->stream;
487 params.frames = frames;
488 params.data = data;
490 WINE_UNIX_CALL(get_render_buffer, &params);
492 return params.result;
495 static HRESULT WINAPI render_ReleaseBuffer(IAudioRenderClient *iface, UINT32 written_frames,
496 DWORD flags)
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);
503 if (!This->stream)
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, &params);
512 return params.result;
515 const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
516 render_QueryInterface,
517 render_AddRef,
518 render_Release,
519 render_GetBuffer,
520 render_ReleaseBuffer
523 static HRESULT WINAPI streamvolume_QueryInterface(IAudioStreamVolume *iface, REFIID riid,
524 void **ppv)
526 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
528 if (!ppv)
529 return E_POINTER;
531 if (IsEqualIID(riid, &IID_IUnknown) ||
532 IsEqualIID(riid, &IID_IAudioStreamVolume))
533 *ppv = iface;
534 else if (IsEqualIID(riid, &IID_IMarshal)) {
535 struct audio_client *This = impl_from_IAudioStreamVolume(iface);
536 return IUnknown_QueryInterface(This->marshal, riid, ppv);
537 } else {
538 *ppv = NULL;
539 return E_NOINTERFACE;
542 IUnknown_AddRef((IUnknown *)*ppv);
544 return S_OK;
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);
565 if (!out)
566 return E_POINTER;
568 *out = This->channel_count;
570 return S_OK;
573 static HRESULT WINAPI streamvolume_SetChannelVolume(IAudioStreamVolume *iface, UINT32 index,
574 float level)
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)
581 return E_INVALIDARG;
583 if (!This->stream)
584 return AUDCLNT_E_NOT_INITIALIZED;
586 if (index >= This->channel_count)
587 return E_INVALIDARG;
589 sessions_lock();
591 This->vols[index] = level;
592 set_stream_volumes(This);
594 sessions_unlock();
596 return S_OK;
599 static HRESULT WINAPI streamvolume_GetChannelVolume(IAudioStreamVolume *iface, UINT32 index,
600 float *level)
602 struct audio_client *This = impl_from_IAudioStreamVolume(iface);
604 TRACE("(%p)->(%d, %p)\n", This, index, level);
606 if (!level)
607 return E_POINTER;
609 if (!This->stream)
610 return AUDCLNT_E_NOT_INITIALIZED;
612 if (index >= This->channel_count)
613 return E_INVALIDARG;
615 *level = This->vols[index];
617 return S_OK;
620 static HRESULT WINAPI streamvolume_SetAllVolumes(IAudioStreamVolume *iface, UINT32 count,
621 const float *levels)
623 struct audio_client *This = impl_from_IAudioStreamVolume(iface);
624 unsigned int i;
626 TRACE("(%p)->(%d, %p)\n", This, count, levels);
628 if (!levels)
629 return E_POINTER;
631 if (!This->stream)
632 return AUDCLNT_E_NOT_INITIALIZED;
634 if (count != This->channel_count)
635 return E_INVALIDARG;
637 sessions_lock();
639 for (i = 0; i < count; ++i)
640 This->vols[i] = levels[i];
641 set_stream_volumes(This);
643 sessions_unlock();
645 return S_OK;
648 static HRESULT WINAPI streamvolume_GetAllVolumes(IAudioStreamVolume *iface, UINT32 count,
649 float *levels)
651 struct audio_client *This = impl_from_IAudioStreamVolume(iface);
652 unsigned int i;
654 TRACE("(%p)->(%d, %p)\n", This, count, levels);
656 if (!levels)
657 return E_POINTER;
659 if (!This->stream)
660 return AUDCLNT_E_NOT_INITIALIZED;
662 if (count != This->channel_count)
663 return E_INVALIDARG;
665 sessions_lock();
667 for (i = 0; i < count; ++i)
668 levels[i] = This->vols[i];
670 sessions_unlock();
672 return S_OK;
675 const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
677 streamvolume_QueryInterface,
678 streamvolume_AddRef,
679 streamvolume_Release,
680 streamvolume_GetChannelCount,
681 streamvolume_SetChannelVolume,
682 streamvolume_GetChannelVolume,
683 streamvolume_SetAllVolumes,
684 streamvolume_GetAllVolumes