wined3d/glsl: Flush NaN to zero in ftoi.
[wine.git] / dlls / mmdevapi / session.c
blob112c0c52fb95e9f80d58f5f08683e52146c5f6ec
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 "mmdevapi_private.h"
33 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
35 WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
37 extern void sessions_lock(void) DECLSPEC_HIDDEN;
38 extern void sessions_unlock(void) DECLSPEC_HIDDEN;
40 extern void set_stream_volumes(struct audio_client *This) DECLSPEC_HIDDEN;
42 static struct list sessions = LIST_INIT(sessions);
44 static inline struct audio_session_wrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
46 return CONTAINING_RECORD(iface, struct audio_session_wrapper, IAudioSessionControl2_iface);
49 static inline struct audio_session_wrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
51 return CONTAINING_RECORD(iface, struct audio_session_wrapper, IChannelAudioVolume_iface);
54 static inline struct audio_session_wrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
56 return CONTAINING_RECORD(iface, struct audio_session_wrapper, ISimpleAudioVolume_iface);
59 static HRESULT WINAPI control_QueryInterface(IAudioSessionControl2 *iface, REFIID riid, void **ppv)
61 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
63 if (!ppv)
64 return E_POINTER;
66 if (IsEqualIID(riid, &IID_IUnknown) ||
67 IsEqualIID(riid, &IID_IAudioSessionControl) ||
68 IsEqualIID(riid, &IID_IAudioSessionControl2))
69 *ppv = iface;
70 else {
71 *ppv = NULL;
72 return E_NOINTERFACE;
75 IUnknown_AddRef((IUnknown *)*ppv);
77 return S_OK;
80 static ULONG WINAPI control_AddRef(IAudioSessionControl2 *iface)
82 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
83 ULONG ref = InterlockedIncrement(&This->ref);
84 TRACE("(%p) Refcount now %lu\n", This, ref);
85 return ref;
88 static ULONG WINAPI control_Release(IAudioSessionControl2 *iface)
90 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
91 ULONG ref = InterlockedDecrement(&This->ref);
92 TRACE("(%p) Refcount now %lu\n", This, ref);
94 if (!ref) {
95 if (This->client) {
96 sessions_lock();
97 This->client->session_wrapper = NULL;
98 sessions_unlock();
99 IAudioClient3_Release(&This->client->IAudioClient3_iface);
102 free(This);
105 return ref;
108 static HRESULT WINAPI control_GetState(IAudioSessionControl2 *iface, AudioSessionState *state)
110 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
111 struct is_started_params params;
112 struct audio_client *client;
114 TRACE("(%p)->(%p)\n", This, state);
116 if (!state)
117 return NULL_PTR_ERR;
119 sessions_lock();
121 if (list_empty(&This->session->clients)) {
122 *state = AudioSessionStateExpired;
123 sessions_unlock();
124 return S_OK;
127 LIST_FOR_EACH_ENTRY(client, &This->session->clients, struct audio_client, entry) {
128 params.stream = client->stream;
129 wine_unix_call(is_started, &params);
130 if (params.result == S_OK) {
131 *state = AudioSessionStateActive;
132 sessions_unlock();
133 return S_OK;
137 sessions_unlock();
139 *state = AudioSessionStateInactive;
141 return S_OK;
144 static HRESULT WINAPI control_GetDisplayName(IAudioSessionControl2 *iface, WCHAR **name)
146 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
147 FIXME("(%p)->(%p) - stub\n", This, name);
148 return E_NOTIMPL;
151 static HRESULT WINAPI control_SetDisplayName(IAudioSessionControl2 *iface, const WCHAR *name,
152 const GUID *session)
154 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
155 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
156 return E_NOTIMPL;
159 static HRESULT WINAPI control_GetIconPath(IAudioSessionControl2 *iface, WCHAR **path)
161 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
162 FIXME("(%p)->(%p) - stub\n", This, path);
163 return E_NOTIMPL;
166 static HRESULT WINAPI control_SetIconPath(IAudioSessionControl2 *iface, const WCHAR *path,
167 const GUID *session)
169 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
170 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_w(path), debugstr_guid(session));
171 return E_NOTIMPL;
174 static HRESULT WINAPI control_GetGroupingParam(IAudioSessionControl2 *iface, GUID *group)
176 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
177 FIXME("(%p)->(%p) - stub\n", This, group);
178 return E_NOTIMPL;
181 static HRESULT WINAPI control_SetGroupingParam(IAudioSessionControl2 *iface, const GUID *group,
182 const GUID *session)
184 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
185 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group), debugstr_guid(session));
186 return E_NOTIMPL;
189 static HRESULT WINAPI control_RegisterAudioSessionNotification(IAudioSessionControl2 *iface,
190 IAudioSessionEvents *events)
192 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
193 FIXME("(%p)->(%p) - stub\n", This, events);
194 return S_OK;
197 static HRESULT WINAPI control_UnregisterAudioSessionNotification(IAudioSessionControl2 *iface,
198 IAudioSessionEvents *events)
200 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
201 FIXME("(%p)->(%p) - stub\n", This, events);
202 return S_OK;
205 static HRESULT WINAPI control_GetSessionIdentifier(IAudioSessionControl2 *iface, WCHAR **id)
207 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
208 FIXME("(%p)->(%p) - stub\n", This, id);
209 return E_NOTIMPL;
212 static HRESULT WINAPI control_GetSessionInstanceIdentifier(IAudioSessionControl2 *iface, WCHAR **id)
214 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
215 FIXME("(%p)->(%p) - stub\n", This, id);
216 return E_NOTIMPL;
219 static HRESULT WINAPI control_GetProcessId(IAudioSessionControl2 *iface, DWORD *pid)
221 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
223 TRACE("(%p)->(%p)\n", This, pid);
225 if (!pid)
226 return E_POINTER;
228 *pid = GetCurrentProcessId();
230 return S_OK;
233 static HRESULT WINAPI control_IsSystemSoundsSession(IAudioSessionControl2 *iface)
235 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
236 TRACE("(%p)\n", This);
237 return S_FALSE;
240 static HRESULT WINAPI control_SetDuckingPreference(IAudioSessionControl2 *iface, BOOL optout)
242 struct audio_session_wrapper *This = impl_from_IAudioSessionControl2(iface);
243 TRACE("(%p)->(%d)\n", This, optout);
244 return S_OK;
247 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
249 control_QueryInterface,
250 control_AddRef,
251 control_Release,
252 control_GetState,
253 control_GetDisplayName,
254 control_SetDisplayName,
255 control_GetIconPath,
256 control_SetIconPath,
257 control_GetGroupingParam,
258 control_SetGroupingParam,
259 control_RegisterAudioSessionNotification,
260 control_UnregisterAudioSessionNotification,
261 control_GetSessionIdentifier,
262 control_GetSessionInstanceIdentifier,
263 control_GetProcessId,
264 control_IsSystemSoundsSession,
265 control_SetDuckingPreference
268 static HRESULT WINAPI channelvolume_QueryInterface(IChannelAudioVolume *iface, REFIID riid,
269 void **ppv)
271 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
273 if (!ppv)
274 return E_POINTER;
276 if (IsEqualIID(riid, &IID_IUnknown) ||
277 IsEqualIID(riid, &IID_IChannelAudioVolume))
278 *ppv = iface;
279 else {
280 *ppv = NULL;
281 return E_NOINTERFACE;
284 IUnknown_AddRef((IUnknown *)*ppv);
286 return S_OK;
289 static ULONG WINAPI channelvolume_AddRef(IChannelAudioVolume *iface)
291 struct audio_session_wrapper *This = impl_from_IChannelAudioVolume(iface);
292 return IAudioSessionControl2_AddRef(&This->IAudioSessionControl2_iface);
295 static ULONG WINAPI channelvolume_Release(IChannelAudioVolume *iface)
297 struct audio_session_wrapper *This = impl_from_IChannelAudioVolume(iface);
298 return IAudioSessionControl2_Release(&This->IAudioSessionControl2_iface);
301 static HRESULT WINAPI channelvolume_GetChannelCount(IChannelAudioVolume *iface, UINT32 *out)
303 struct audio_session_wrapper *This = impl_from_IChannelAudioVolume(iface);
304 struct audio_session *session = This->session;
306 TRACE("(%p)->(%p)\n", session, out);
308 if (!out)
309 return NULL_PTR_ERR;
311 *out = session->channel_count;
313 return S_OK;
316 static HRESULT WINAPI channelvolume_SetChannelVolume(IChannelAudioVolume *iface, UINT32 index,
317 float level, const GUID *context)
319 struct audio_session_wrapper *This = impl_from_IChannelAudioVolume(iface);
320 struct audio_session *session = This->session;
321 struct audio_client *client;
323 TRACE("(%p)->(%d, %f, %s)\n", session, index, level, wine_dbgstr_guid(context));
325 if (level < 0.f || level > 1.f)
326 return E_INVALIDARG;
328 if (index >= session->channel_count)
329 return E_INVALIDARG;
331 if (context)
332 FIXME("Notifications not supported yet\n");
334 sessions_lock();
336 session->channel_vols[index] = level;
338 LIST_FOR_EACH_ENTRY(client, &session->clients, struct audio_client, entry)
339 set_stream_volumes(client);
341 sessions_unlock();
343 return S_OK;
346 static HRESULT WINAPI channelvolume_GetChannelVolume(IChannelAudioVolume *iface, UINT32 index,
347 float *level)
349 struct audio_session_wrapper *This = impl_from_IChannelAudioVolume(iface);
350 struct audio_session *session = This->session;
352 TRACE("(%p)->(%d, %p)\n", session, index, level);
354 if (!level)
355 return NULL_PTR_ERR;
357 if (index >= session->channel_count)
358 return E_INVALIDARG;
360 *level = session->channel_vols[index];
362 return S_OK;
365 static HRESULT WINAPI channelvolume_SetAllVolumes(IChannelAudioVolume *iface, UINT32 count,
366 const float *levels, const GUID *context)
368 struct audio_session_wrapper *This = impl_from_IChannelAudioVolume(iface);
369 struct audio_session *session = This->session;
370 struct audio_client *client;
371 unsigned int i;
373 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels, wine_dbgstr_guid(context));
375 if (!levels)
376 return NULL_PTR_ERR;
378 if (count != session->channel_count)
379 return E_INVALIDARG;
381 if (context)
382 FIXME("Notifications not supported yet\n");
384 sessions_lock();
386 for (i = 0; i < count; ++i)
387 session->channel_vols[i] = levels[i];
389 LIST_FOR_EACH_ENTRY(client, &session->clients, struct audio_client, entry)
390 set_stream_volumes(client);
392 sessions_unlock();
394 return S_OK;
397 static HRESULT WINAPI channelvolume_GetAllVolumes(IChannelAudioVolume *iface, UINT32 count,
398 float *levels)
400 struct audio_session_wrapper *This = impl_from_IChannelAudioVolume(iface);
401 struct audio_session *session = This->session;
402 unsigned int i;
404 TRACE("(%p)->(%d, %p)\n", session, count, levels);
406 if (!levels)
407 return NULL_PTR_ERR;
409 if (count != session->channel_count)
410 return E_INVALIDARG;
412 for (i = 0; i < count; ++i)
413 levels[i] = session->channel_vols[i];
415 return S_OK;
418 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
420 channelvolume_QueryInterface,
421 channelvolume_AddRef,
422 channelvolume_Release,
423 channelvolume_GetChannelCount,
424 channelvolume_SetChannelVolume,
425 channelvolume_GetChannelVolume,
426 channelvolume_SetAllVolumes,
427 channelvolume_GetAllVolumes
430 static HRESULT WINAPI simplevolume_QueryInterface(ISimpleAudioVolume *iface, REFIID riid,
431 void **ppv)
433 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
435 if (!ppv)
436 return E_POINTER;
438 if (IsEqualIID(riid, &IID_IUnknown) ||
439 IsEqualIID(riid, &IID_ISimpleAudioVolume))
440 *ppv = iface;
441 else {
442 *ppv = NULL;
443 return E_NOINTERFACE;
446 IUnknown_AddRef((IUnknown *)*ppv);
448 return S_OK;
451 static ULONG WINAPI simplevolume_AddRef(ISimpleAudioVolume *iface)
453 struct audio_session_wrapper *This = impl_from_ISimpleAudioVolume(iface);
454 return IAudioSessionControl2_AddRef(&This->IAudioSessionControl2_iface);
457 static ULONG WINAPI simplevolume_Release(ISimpleAudioVolume *iface)
459 struct audio_session_wrapper *This = impl_from_ISimpleAudioVolume(iface);
460 return IAudioSessionControl2_Release(&This->IAudioSessionControl2_iface);
463 static HRESULT WINAPI simplevolume_SetMasterVolume(ISimpleAudioVolume *iface, float level,
464 const GUID *context)
466 struct audio_session_wrapper *This = impl_from_ISimpleAudioVolume(iface);
467 struct audio_session *session = This->session;
468 struct audio_client *client;
470 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
472 if (level < 0.f || level > 1.f)
473 return E_INVALIDARG;
475 if (context)
476 FIXME("Notifications not supported yet\n");
478 sessions_lock();
480 session->master_vol = level;
482 LIST_FOR_EACH_ENTRY(client, &session->clients, struct audio_client, entry)
483 set_stream_volumes(client);
485 sessions_unlock();
487 return S_OK;
490 static HRESULT WINAPI simplevolume_GetMasterVolume(ISimpleAudioVolume *iface, float *level)
492 struct audio_session_wrapper *This = impl_from_ISimpleAudioVolume(iface);
493 struct audio_session *session = This->session;
495 TRACE("(%p)->(%p)\n", session, level);
497 if (!level)
498 return NULL_PTR_ERR;
500 *level = session->master_vol;
502 return S_OK;
505 static HRESULT WINAPI simplevolume_SetMute(ISimpleAudioVolume *iface, BOOL mute,
506 const GUID *context)
508 struct audio_session_wrapper *This = impl_from_ISimpleAudioVolume(iface);
509 struct audio_session *session = This->session;
510 struct audio_client *client;
512 TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context));
514 if (context)
515 FIXME("Notifications not supported yet\n");
517 sessions_lock();
519 session->mute = mute;
521 LIST_FOR_EACH_ENTRY(client, &session->clients, struct audio_client, entry)
522 set_stream_volumes(client);
524 sessions_unlock();
526 return S_OK;
529 static HRESULT WINAPI simplevolume_GetMute(ISimpleAudioVolume *iface, BOOL *mute)
531 struct audio_session_wrapper *This = impl_from_ISimpleAudioVolume(iface);
532 struct audio_session *session = This->session;
534 TRACE("(%p)->(%p)\n", session, mute);
536 if (!mute)
537 return NULL_PTR_ERR;
539 *mute = session->mute;
541 return S_OK;
544 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
546 simplevolume_QueryInterface,
547 simplevolume_AddRef,
548 simplevolume_Release,
549 simplevolume_SetMasterVolume,
550 simplevolume_GetMasterVolume,
551 simplevolume_SetMute,
552 simplevolume_GetMute
555 static void session_init_vols(struct audio_session *session, UINT channels)
557 if (session->channel_count < channels) {
558 UINT i;
560 session->channel_vols = realloc(session->channel_vols, sizeof(float) * channels);
561 if (!session->channel_vols)
562 return;
564 for (i = session->channel_count; i < channels; i++)
565 session->channel_vols[i] = 1.f;
567 session->channel_count = channels;
571 static struct audio_session *session_create(const GUID *guid, IMMDevice *device, UINT channels)
573 struct audio_session *ret = calloc(1, sizeof(struct audio_session));
574 if (!ret)
575 return NULL;
577 memcpy(&ret->guid, guid, sizeof(GUID));
579 ret->device = device;
581 list_init(&ret->clients);
583 list_add_head(&sessions, &ret->entry);
585 session_init_vols(ret, channels);
587 ret->master_vol = 1.f;
589 return ret;
592 struct audio_session_wrapper *session_wrapper_create(struct audio_client *client)
594 struct audio_session_wrapper *ret;
596 ret = calloc(1, sizeof(struct audio_session_wrapper));
597 if (!ret)
598 return NULL;
600 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
601 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
602 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
604 ret->ref = 1;
605 ret->client = client;
607 if (client) {
608 ret->session = client->session;
609 IAudioClient3_AddRef(&client->IAudioClient3_iface);
612 return ret;
615 /* If channels == 0, then this will return or create a session with
616 * matching dataflow and GUID. Otherwise, channels must also match. */
617 HRESULT get_audio_session(const GUID *guid, IMMDevice *device, UINT channels,
618 struct audio_session **out)
620 struct audio_session *session;
622 TRACE("(%s, %p, %u, %p)\n", debugstr_guid(guid), device, channels, out);
624 if (!guid || IsEqualGUID(guid, &GUID_NULL)) {
625 *out = session_create(&GUID_NULL, device, channels);
626 if (!*out)
627 return E_OUTOFMEMORY;
629 return S_OK;
632 *out = NULL;
633 LIST_FOR_EACH_ENTRY(session, &sessions, struct audio_session, entry) {
634 if (session->device == device && IsEqualGUID(guid, &session->guid)) {
635 session_init_vols(session, channels);
636 *out = session;
637 break;
641 if (!*out) {
642 *out = session_create(guid, device, channels);
643 if (!*out)
644 return E_OUTOFMEMORY;
647 return S_OK;
650 HRESULT get_audio_session_wrapper(const GUID *guid, IMMDevice *device,
651 struct audio_session_wrapper **out)
653 struct audio_session *session;
655 const HRESULT hr = get_audio_session(guid, device, 0, &session);
656 if (FAILED(hr))
657 return hr;
659 *out = session_wrapper_create(NULL);
660 if (!*out)
661 return E_OUTOFMEMORY;
663 (*out)->session = session;
665 return S_OK;