wininet: A small netconn_secure_verify code clean up.
[wine/multimedia.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blobed97e9924b98b3a4e43dd653fe2f401b3a568a23
1 /*
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
19 #define NONAMELESSUNION
20 #define COBJMACROS
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnls.h"
28 #include "winreg.h"
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
31 #include "wine/list.h"
33 #include "ole2.h"
34 #include "mmdeviceapi.h"
35 #include "devpkey.h"
36 #include "dshow.h"
37 #include "dsound.h"
38 #include "endpointvolume.h"
40 #include "initguid.h"
41 #include "audioclient.h"
42 #include "audiopolicy.h"
44 #include <errno.h>
45 #include <limits.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52 #include <fcntl.h>
53 #include <unistd.h>
55 #include <libkern/OSAtomic.h>
56 #include <CoreAudio/CoreAudio.h>
57 #include <AudioToolbox/AudioQueue.h>
59 WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
61 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
63 #define CAPTURE_BUFFERS 5
65 static const REFERENCE_TIME DefaultPeriod = 200000;
66 static const REFERENCE_TIME MinimumPeriod = 100000;
68 typedef struct _AQBuffer {
69 AudioQueueBufferRef buf;
70 struct list entry;
71 } AQBuffer;
73 struct ACImpl;
74 typedef struct ACImpl ACImpl;
76 typedef struct _AudioSession {
77 GUID guid;
78 struct list clients;
80 EDataFlow dataflow;
82 float master_vol;
83 UINT32 channel_count;
84 float *channel_vols;
86 CRITICAL_SECTION lock;
88 struct list entry;
89 } AudioSession;
91 typedef struct _AudioSessionWrapper {
92 IAudioSessionControl2 IAudioSessionControl2_iface;
93 IChannelAudioVolume IChannelAudioVolume_iface;
94 ISimpleAudioVolume ISimpleAudioVolume_iface;
96 LONG ref;
98 ACImpl *client;
99 AudioSession *session;
100 } AudioSessionWrapper;
102 struct ACImpl {
103 IAudioClient IAudioClient_iface;
104 IAudioRenderClient IAudioRenderClient_iface;
105 IAudioCaptureClient IAudioCaptureClient_iface;
106 IAudioClock IAudioClock_iface;
107 IAudioClock2 IAudioClock2_iface;
108 IAudioStreamVolume IAudioStreamVolume_iface;
110 LONG ref;
112 IMMDevice *parent;
114 WAVEFORMATEX *fmt;
116 EDataFlow dataflow;
117 DWORD flags;
118 AUDCLNT_SHAREMODE share;
119 HANDLE event;
120 float *vols;
122 AudioDeviceID adevid;
123 AudioQueueRef aqueue;
124 AudioObjectPropertyScope scope;
125 HANDLE timer;
126 UINT32 period_ms, bufsize_frames, inbuf_frames, written_frames;
127 UINT64 last_time;
128 AudioQueueBufferRef public_buffer;
129 BOOL getbuf_last;
130 int playing;
132 AudioSession *session;
133 AudioSessionWrapper *session_wrapper;
135 struct list entry;
137 struct list avail_buffers;
139 /* We can't use debug printing or {Enter,Leave}CriticalSection from
140 * OSX callback threads, so we use OSX's OSSpinLock for synchronization
141 * instead. OSSpinLock is not a recursive lock, so don't call
142 * synchronized functions while holding the lock. */
143 OSSpinLock lock;
146 enum PlayingStates {
147 StateStopped = 0,
148 StatePlaying,
149 StateInTransition
152 static const IAudioClientVtbl AudioClient_Vtbl;
153 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
154 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
155 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
156 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
157 static const IAudioClockVtbl AudioClock_Vtbl;
158 static const IAudioClock2Vtbl AudioClock2_Vtbl;
159 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
160 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
161 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
163 typedef struct _SessionMgr {
164 IAudioSessionManager2 IAudioSessionManager2_iface;
166 LONG ref;
168 EDataFlow flow;
169 } SessionMgr;
171 static HANDLE g_timer_q;
173 static CRITICAL_SECTION g_sessions_lock;
174 static struct list g_sessions = LIST_INIT(g_sessions);
176 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
177 UINT64 *qpctime, BOOL raw);
178 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
179 static HRESULT ca_setvol(ACImpl *This, UINT32 index);
181 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
183 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
186 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
188 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
191 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
193 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
196 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
198 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
201 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
203 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
206 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
208 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
211 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
213 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
216 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
218 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
221 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
223 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
226 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
228 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
231 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
233 if(reason == DLL_PROCESS_ATTACH){
234 g_timer_q = CreateTimerQueue();
235 if(!g_timer_q)
236 return FALSE;
238 InitializeCriticalSection(&g_sessions_lock);
241 return TRUE;
244 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
245 AudioDeviceID ***keys, UINT *num, UINT *def_index)
247 UInt32 devsize, size;
248 AudioDeviceID *devices;
249 AudioDeviceID default_id;
250 AudioObjectPropertyAddress addr;
251 OSStatus sc;
252 int i, ndevices;
254 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
256 addr.mScope = kAudioObjectPropertyScopeGlobal;
257 addr.mElement = kAudioObjectPropertyElementMaster;
258 if(flow == eRender)
259 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
260 else if(flow == eCapture)
261 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
262 else
263 return E_INVALIDARG;
265 size = sizeof(default_id);
266 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
267 NULL, &size, &default_id);
268 if(sc != noErr){
269 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
270 default_id = -1;
273 addr.mSelector = kAudioHardwarePropertyDevices;
274 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
275 NULL, &devsize);
276 if(sc != noErr){
277 WARN("Getting _Devices property size failed: %lx\n", sc);
278 return E_FAIL;
281 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
282 if(!devices)
283 return E_OUTOFMEMORY;
285 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
286 &devsize, devices);
287 if(sc != noErr){
288 WARN("Getting _Devices property failed: %lx\n", sc);
289 HeapFree(GetProcessHeap(), 0, devices);
290 return E_FAIL;
293 ndevices = devsize / sizeof(AudioDeviceID);
295 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
296 if(!*ids){
297 HeapFree(GetProcessHeap(), 0, devices);
298 return E_OUTOFMEMORY;
301 *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
302 if(!*ids){
303 HeapFree(GetProcessHeap(), 0, *ids);
304 HeapFree(GetProcessHeap(), 0, devices);
305 return E_OUTOFMEMORY;
308 *num = 0;
309 *def_index = (UINT)-1;
310 for(i = 0; i < ndevices; ++i){
311 AudioBufferList *buffers;
312 CFStringRef name;
313 SIZE_T len;
314 char nameA[256];
315 int j;
317 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
318 if(flow == eRender)
319 addr.mScope = kAudioDevicePropertyScopeOutput;
320 else
321 addr.mScope = kAudioDevicePropertyScopeInput;
322 addr.mElement = 0;
323 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
324 if(sc != noErr){
325 WARN("Unable to get _StreamConfiguration property size for "
326 "device %lu: %lx\n", devices[i], sc);
327 continue;
330 buffers = HeapAlloc(GetProcessHeap(), 0, size);
331 if(!buffers){
332 HeapFree(GetProcessHeap(), 0, devices);
333 for(j = 0; j < *num; ++j)
334 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
335 HeapFree(GetProcessHeap(), 0, *keys);
336 HeapFree(GetProcessHeap(), 0, *ids);
337 return E_OUTOFMEMORY;
340 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
341 &size, buffers);
342 if(sc != noErr){
343 WARN("Unable to get _StreamConfiguration property for "
344 "device %lu: %lx\n", devices[i], sc);
345 HeapFree(GetProcessHeap(), 0, buffers);
346 continue;
349 /* check that there's at least one channel in this device before
350 * we claim it as usable */
351 for(j = 0; j < buffers->mNumberBuffers; ++j)
352 if(buffers->mBuffers[j].mNumberChannels > 0)
353 break;
354 if(j >= buffers->mNumberBuffers){
355 HeapFree(GetProcessHeap(), 0, buffers);
356 continue;
359 HeapFree(GetProcessHeap(), 0, buffers);
361 size = sizeof(name);
362 addr.mSelector = kAudioObjectPropertyName;
363 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
364 &size, &name);
365 if(sc != noErr){
366 WARN("Unable to get _Name property for device %lu: %lx\n",
367 devices[i], sc);
368 continue;
371 if(!CFStringGetCString(name, nameA, sizeof(nameA),
372 kCFStringEncodingUTF8)){
373 WARN("Error converting string to UTF8\n");
374 CFRelease(name);
375 continue;
378 CFRelease(name);
380 len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
381 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
382 if(!(*ids)[*num]){
383 HeapFree(GetProcessHeap(), 0, devices);
384 for(j = 0; j < *num; ++j){
385 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
386 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
388 HeapFree(GetProcessHeap(), 0, *ids);
389 HeapFree(GetProcessHeap(), 0, *keys);
390 return E_OUTOFMEMORY;
392 MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
394 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
395 if(!(*ids)[*num]){
396 HeapFree(GetProcessHeap(), 0, devices);
397 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
398 for(j = 0; j < *num; ++j){
399 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
400 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
402 HeapFree(GetProcessHeap(), 0, *ids);
403 HeapFree(GetProcessHeap(), 0, *keys);
404 return E_OUTOFMEMORY;
406 *(*keys)[*num] = devices[i];
408 if(*def_index == (UINT)-1 && devices[i] == default_id)
409 *def_index = *num;
411 (*num)++;
414 if(*def_index == (UINT)-1)
415 *def_index = 0;
417 HeapFree(GetProcessHeap(), 0, devices);
419 return S_OK;
422 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
423 EDataFlow dataflow, IAudioClient **out)
425 ACImpl *This;
427 TRACE("%p %d %p\n", dev, dataflow, out);
429 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
430 if(!This)
431 return E_OUTOFMEMORY;
433 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
434 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
435 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
436 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
437 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
438 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
440 This->dataflow = dataflow;
442 if(dataflow == eRender)
443 This->scope = kAudioDevicePropertyScopeOutput;
444 else if(dataflow == eCapture)
445 This->scope = kAudioDevicePropertyScopeInput;
446 else{
447 HeapFree(GetProcessHeap(), 0, This);
448 return E_INVALIDARG;
451 This->lock = 0;
453 This->parent = dev;
454 IMMDevice_AddRef(This->parent);
456 list_init(&This->avail_buffers);
458 This->adevid = *adevid;
460 *out = &This->IAudioClient_iface;
461 IAudioClient_AddRef(&This->IAudioClient_iface);
463 return S_OK;
466 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
467 REFIID riid, void **ppv)
469 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
471 if(!ppv)
472 return E_POINTER;
473 *ppv = NULL;
474 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
475 *ppv = iface;
476 if(*ppv){
477 IUnknown_AddRef((IUnknown*)*ppv);
478 return S_OK;
480 WARN("Unknown interface %s\n", debugstr_guid(riid));
481 return E_NOINTERFACE;
484 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
486 ACImpl *This = impl_from_IAudioClient(iface);
487 ULONG ref;
488 ref = InterlockedIncrement(&This->ref);
489 TRACE("(%p) Refcount now %u\n", This, ref);
490 return ref;
493 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
495 ACImpl *This = impl_from_IAudioClient(iface);
496 ULONG ref;
497 ref = InterlockedDecrement(&This->ref);
498 TRACE("(%p) Refcount now %u\n", This, ref);
499 if(!ref){
500 IAudioClient_Stop(iface);
501 if(This->aqueue)
502 AudioQueueDispose(This->aqueue, 1);
503 if(This->session){
504 EnterCriticalSection(&g_sessions_lock);
505 list_remove(&This->entry);
506 LeaveCriticalSection(&g_sessions_lock);
508 HeapFree(GetProcessHeap(), 0, This->vols);
509 HeapFree(GetProcessHeap(), 0, This->public_buffer);
510 CoTaskMemFree(This->fmt);
511 IMMDevice_Release(This->parent);
512 HeapFree(GetProcessHeap(), 0, This);
514 return ref;
517 static void dump_fmt(const WAVEFORMATEX *fmt)
519 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
520 switch(fmt->wFormatTag){
521 case WAVE_FORMAT_PCM:
522 TRACE("WAVE_FORMAT_PCM");
523 break;
524 case WAVE_FORMAT_IEEE_FLOAT:
525 TRACE("WAVE_FORMAT_IEEE_FLOAT");
526 break;
527 case WAVE_FORMAT_EXTENSIBLE:
528 TRACE("WAVE_FORMAT_EXTENSIBLE");
529 break;
530 default:
531 TRACE("Unknown");
532 break;
534 TRACE(")\n");
536 TRACE("nChannels: %u\n", fmt->nChannels);
537 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
538 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
539 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
540 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
541 TRACE("cbSize: %u\n", fmt->cbSize);
543 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
544 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
545 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
546 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
547 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
551 static DWORD get_channel_mask(unsigned int channels)
553 switch(channels){
554 case 0:
555 return 0;
556 case 1:
557 return SPEAKER_FRONT_CENTER;
558 case 2:
559 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
560 case 3:
561 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
562 SPEAKER_LOW_FREQUENCY;
563 case 4:
564 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
565 SPEAKER_BACK_RIGHT;
566 case 5:
567 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
568 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
569 case 6:
570 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
571 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
572 case 7:
573 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
574 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
575 SPEAKER_BACK_CENTER;
577 FIXME("Unknown speaker configuration: %u\n", channels);
578 return 0;
581 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
583 WAVEFORMATEX *ret;
584 size_t size;
586 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
587 size = sizeof(WAVEFORMATEXTENSIBLE);
588 else
589 size = sizeof(WAVEFORMATEX);
591 ret = CoTaskMemAlloc(size);
592 if(!ret)
593 return NULL;
595 memcpy(ret, fmt, size);
597 ret->cbSize = size - sizeof(WAVEFORMATEX);
599 return ret;
602 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
603 const WAVEFORMATEX *fmt)
605 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
607 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
608 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
609 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
610 desc->mFormatID = kAudioFormatLinearPCM;
611 if(fmt->wBitsPerSample > 8)
612 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
613 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
614 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
615 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
616 desc->mFormatID = kAudioFormatLinearPCM;
617 desc->mFormatFlags = kAudioFormatFlagIsFloat;
618 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
619 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
620 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
621 desc->mFormatID = kAudioFormatULaw;
622 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
623 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
624 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
625 desc->mFormatID = kAudioFormatALaw;
626 }else
627 return AUDCLNT_E_UNSUPPORTED_FORMAT;
629 desc->mSampleRate = fmt->nSamplesPerSec;
630 desc->mBytesPerPacket = fmt->nBlockAlign;
631 desc->mFramesPerPacket = 1;
632 desc->mBytesPerFrame = fmt->nBlockAlign;
633 desc->mChannelsPerFrame = fmt->nChannels;
634 desc->mBitsPerChannel = fmt->wBitsPerSample;
635 desc->mReserved = 0;
637 return S_OK;
640 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
641 AudioQueueBufferRef buffer)
643 ACImpl *This = user;
644 AQBuffer *buf = buffer->mUserData;
646 OSSpinLockLock(&This->lock);
647 list_add_tail(&This->avail_buffers, &buf->entry);
648 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
649 OSSpinLockUnlock(&This->lock);
652 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
653 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
654 UInt32 ndesc, const AudioStreamPacketDescription *descs)
656 ACImpl *This = user;
657 AQBuffer *buf = buffer->mUserData;
659 OSSpinLockLock(&This->lock);
660 list_add_tail(&This->avail_buffers, &buf->entry);
661 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
662 OSSpinLockUnlock(&This->lock);
665 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
666 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
668 AudioStreamBasicDescription desc;
669 AudioObjectPropertyAddress addr;
670 CFStringRef uid;
671 OSStatus sc;
672 HRESULT hr;
673 UInt32 size;
675 addr.mScope = kAudioObjectPropertyScopeGlobal;
676 addr.mElement = 0;
677 addr.mSelector = kAudioDevicePropertyDeviceUID;
679 size = sizeof(uid);
680 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
681 if(sc != noErr){
682 WARN("Unable to get _DeviceUID property: %lx\n", sc);
683 return E_FAIL;
686 hr = ca_get_audiodesc(&desc, fmt);
687 if(FAILED(hr)){
688 CFRelease(uid);
689 return hr;
692 if(flow == eRender)
693 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
694 aqueue);
695 else if(flow == eCapture)
696 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
697 aqueue);
698 else{
699 CFRelease(uid);
700 return E_UNEXPECTED;
702 if(sc != noErr){
703 WARN("Unable to create AudioQueue: %lx\n", sc);
704 CFRelease(uid);
705 return E_FAIL;
708 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
709 &uid, sizeof(uid));
710 if(sc != noErr){
711 CFRelease(uid);
712 return E_FAIL;
715 CFRelease(uid);
717 return S_OK;
720 static void session_init_vols(AudioSession *session, UINT channels)
722 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
723 sizeof(float) * channels);
724 if(!session->channel_vols)
725 return;
727 session->channel_count = channels;
729 for(; channels > 0; --channels)
730 session->channel_vols[channels - 1] = 1.f;
733 static AudioSession *create_session(const GUID *guid, EDataFlow flow,
734 UINT num_channels)
736 AudioSession *ret;
738 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
739 if(!ret)
740 return NULL;
742 memcpy(&ret->guid, guid, sizeof(GUID));
744 ret->dataflow = flow;
746 list_init(&ret->clients);
748 list_add_head(&g_sessions, &ret->entry);
750 InitializeCriticalSection(&ret->lock);
752 if(num_channels > 0)
753 session_init_vols(ret, num_channels);
755 ret->master_vol = 1.f;
757 return ret;
760 /* if channels == 0, then this will return or create a session with
761 * matching dataflow and GUID. otherwise, channels must also match */
762 static HRESULT get_audio_session(const GUID *sessionguid,
763 EDataFlow flow, UINT channels, AudioSession **out)
765 AudioSession *session;
767 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
768 *out = create_session(&GUID_NULL, flow, channels);
769 if(!*out)
770 return E_OUTOFMEMORY;
772 return S_OK;
775 *out = NULL;
776 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
777 if(IsEqualGUID(sessionguid, &session->guid) &&
778 session->dataflow == flow){
779 if(session->channel_count > 0){
780 if(channels > 0 && session->channel_count != channels)
781 return E_INVALIDARG;
782 }else if(channels > 0)
783 session_init_vols(session, channels);
784 *out = session;
785 break;
789 if(!*out){
790 *out = create_session(sessionguid, flow, channels);
791 if(!*out)
792 return E_OUTOFMEMORY;
795 return S_OK;
798 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
799 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
800 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
801 const GUID *sessionguid)
803 ACImpl *This = impl_from_IAudioClient(iface);
804 HRESULT hr;
805 OSStatus sc;
806 int i;
808 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
809 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
811 if(!fmt)
812 return E_POINTER;
814 dump_fmt(fmt);
816 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
817 return AUDCLNT_E_NOT_INITIALIZED;
819 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
820 AUDCLNT_STREAMFLAGS_LOOPBACK |
821 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
822 AUDCLNT_STREAMFLAGS_NOPERSIST |
823 AUDCLNT_STREAMFLAGS_RATEADJUST |
824 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
825 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
826 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
827 TRACE("Unknown flags: %08x\n", flags);
828 return E_INVALIDARG;
831 OSSpinLockLock(&This->lock);
833 if(This->aqueue){
834 OSSpinLockUnlock(&This->lock);
835 return AUDCLNT_E_ALREADY_INITIALIZED;
838 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
839 if(FAILED(hr)){
840 OSSpinLockUnlock(&This->lock);
841 return hr;
844 This->fmt = clone_format(fmt);
845 if(!This->fmt){
846 AudioQueueDispose(This->aqueue, 1);
847 This->aqueue = NULL;
848 OSSpinLockUnlock(&This->lock);
849 return E_OUTOFMEMORY;
852 if(period){
853 This->period_ms = period / 10000;
854 if(This->period_ms == 0)
855 This->period_ms = 1;
856 }else
857 This->period_ms = MinimumPeriod / 10000;
859 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
861 if(This->dataflow == eCapture){
862 int i;
863 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
864 This->fmt->nBlockAlign);
865 for(i = 0; i < CAPTURE_BUFFERS; ++i){
866 AQBuffer *buf;
868 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
869 if(!buf){
870 AudioQueueDispose(This->aqueue, 1);
871 This->aqueue = NULL;
872 CoTaskMemFree(This->fmt);
873 This->fmt = NULL;
874 OSSpinLockUnlock(&This->lock);
875 return E_OUTOFMEMORY;
878 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
879 if(sc != noErr){
880 AudioQueueDispose(This->aqueue, 1);
881 This->aqueue = NULL;
882 CoTaskMemFree(This->fmt);
883 This->fmt = NULL;
884 OSSpinLockUnlock(&This->lock);
885 WARN("Couldn't allocate buffer: %lx\n", sc);
886 return E_FAIL;
889 buf->buf->mUserData = buf;
891 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
892 if(sc != noErr){
893 ERR("Couldn't enqueue buffer: %lx\n", sc);
894 break;
899 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
900 if(!This->vols){
901 AudioQueueDispose(This->aqueue, 1);
902 This->aqueue = NULL;
903 CoTaskMemFree(This->fmt);
904 This->fmt = NULL;
905 OSSpinLockUnlock(&This->lock);
906 return E_OUTOFMEMORY;
909 for(i = 0; i < fmt->nChannels; ++i)
910 This->vols[i] = 1.f;
912 This->share = mode;
913 This->flags = flags;
915 EnterCriticalSection(&g_sessions_lock);
917 hr = get_audio_session(sessionguid, This->dataflow, fmt->nChannels,
918 &This->session);
919 if(FAILED(hr)){
920 LeaveCriticalSection(&g_sessions_lock);
921 AudioQueueDispose(This->aqueue, 1);
922 This->aqueue = NULL;
923 CoTaskMemFree(This->fmt);
924 This->fmt = NULL;
925 HeapFree(GetProcessHeap(), 0, This->vols);
926 This->vols = NULL;
927 OSSpinLockUnlock(&This->lock);
928 return E_INVALIDARG;
931 list_add_tail(&This->session->clients, &This->entry);
933 LeaveCriticalSection(&g_sessions_lock);
935 ca_setvol(This, -1);
937 OSSpinLockUnlock(&This->lock);
939 return S_OK;
942 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
943 UINT32 *frames)
945 ACImpl *This = impl_from_IAudioClient(iface);
947 TRACE("(%p)->(%p)\n", This, frames);
949 if(!frames)
950 return E_POINTER;
952 OSSpinLockLock(&This->lock);
954 if(!This->aqueue){
955 OSSpinLockUnlock(&This->lock);
956 return AUDCLNT_E_NOT_INITIALIZED;
959 *frames = This->bufsize_frames;
961 OSSpinLockUnlock(&This->lock);
963 return S_OK;
966 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
968 AudioObjectPropertyAddress addr;
969 AudioStreamID *ids;
970 UInt32 size;
971 OSStatus sc;
972 int nstreams, i;
974 addr.mScope = This->scope;
975 addr.mElement = 0;
976 addr.mSelector = kAudioDevicePropertyStreams;
978 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
979 &size);
980 if(sc != noErr){
981 WARN("Unable to get size for _Streams property: %lx\n", sc);
982 return E_FAIL;
985 ids = HeapAlloc(GetProcessHeap(), 0, size);
986 if(!ids)
987 return E_OUTOFMEMORY;
989 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
990 if(sc != noErr){
991 WARN("Unable to get _Streams property: %lx\n", sc);
992 HeapFree(GetProcessHeap(), 0, ids);
993 return E_FAIL;
996 nstreams = size / sizeof(AudioStreamID);
997 *max = 0;
999 addr.mSelector = kAudioStreamPropertyLatency;
1000 for(i = 0; i < nstreams; ++i){
1001 UInt32 latency;
1003 size = sizeof(latency);
1004 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1005 &size, &latency);
1006 if(sc != noErr){
1007 WARN("Unable to get _Latency property: %lx\n", sc);
1008 continue;
1011 if(latency > *max)
1012 *max = latency;
1015 HeapFree(GetProcessHeap(), 0, ids);
1017 return S_OK;
1020 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1021 REFERENCE_TIME *out)
1023 ACImpl *This = impl_from_IAudioClient(iface);
1024 UInt32 latency, stream_latency, size;
1025 AudioObjectPropertyAddress addr;
1026 OSStatus sc;
1027 HRESULT hr;
1029 TRACE("(%p)->(%p)\n", This, out);
1031 if(!out)
1032 return E_POINTER;
1034 OSSpinLockLock(&This->lock);
1036 if(!This->aqueue){
1037 OSSpinLockUnlock(&This->lock);
1038 return AUDCLNT_E_NOT_INITIALIZED;
1041 addr.mScope = This->scope;
1042 addr.mSelector = kAudioDevicePropertyLatency;
1043 addr.mElement = 0;
1045 size = sizeof(latency);
1046 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1047 &size, &latency);
1048 if(sc != noErr){
1049 WARN("Couldn't get _Latency property: %lx\n", sc);
1050 OSSpinLockUnlock(&This->lock);
1051 return E_FAIL;
1054 hr = ca_get_max_stream_latency(This, &stream_latency);
1055 if(FAILED(hr)){
1056 OSSpinLockUnlock(&This->lock);
1057 return hr;
1060 latency += stream_latency;
1061 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
1063 OSSpinLockUnlock(&This->lock);
1065 return S_OK;
1068 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1069 UINT32 *numpad)
1071 if(!This->aqueue)
1072 return AUDCLNT_E_NOT_INITIALIZED;
1074 *numpad = This->inbuf_frames;
1076 return S_OK;
1079 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1080 UINT32 *numpad)
1082 ACImpl *This = impl_from_IAudioClient(iface);
1083 HRESULT hr;
1085 TRACE("(%p)->(%p)\n", This, numpad);
1087 if(!numpad)
1088 return E_POINTER;
1090 OSSpinLockLock(&This->lock);
1092 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1094 OSSpinLockUnlock(&This->lock);
1096 return hr;
1099 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1100 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1101 WAVEFORMATEX **outpwfx)
1103 ACImpl *This = impl_from_IAudioClient(iface);
1104 AudioQueueRef aqueue;
1105 HRESULT hr;
1107 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1109 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1110 return E_POINTER;
1112 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1113 return E_INVALIDARG;
1115 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1116 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1117 return E_INVALIDARG;
1119 dump_fmt(pwfx);
1121 OSSpinLockLock(&This->lock);
1123 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1124 if(SUCCEEDED(hr)){
1125 AudioQueueDispose(aqueue, 1);
1126 OSSpinLockUnlock(&This->lock);
1127 if(outpwfx)
1128 *outpwfx = NULL;
1129 TRACE("returning %08x\n", S_OK);
1130 return S_OK;
1133 OSSpinLockUnlock(&This->lock);
1135 if(outpwfx)
1136 *outpwfx = NULL;
1138 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1139 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1142 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1143 WAVEFORMATEX **pwfx)
1145 ACImpl *This = impl_from_IAudioClient(iface);
1146 WAVEFORMATEXTENSIBLE *fmt;
1147 OSStatus sc;
1148 UInt32 size;
1149 Float64 rate;
1150 AudioBufferList *buffers;
1151 AudioObjectPropertyAddress addr;
1152 int i;
1154 TRACE("(%p)->(%p)\n", This, pwfx);
1156 if(!pwfx)
1157 return E_POINTER;
1158 *pwfx = NULL;
1160 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1161 if(!fmt)
1162 return E_OUTOFMEMORY;
1164 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1166 addr.mScope = This->scope;
1167 addr.mElement = 0;
1168 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1170 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1171 if(sc != noErr){
1172 CoTaskMemFree(fmt);
1173 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1174 return E_FAIL;
1177 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1178 if(!buffers){
1179 CoTaskMemFree(fmt);
1180 return E_OUTOFMEMORY;
1183 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1184 &size, buffers);
1185 if(sc != noErr){
1186 CoTaskMemFree(fmt);
1187 HeapFree(GetProcessHeap(), 0, buffers);
1188 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1189 return E_FAIL;
1192 fmt->Format.nChannels = 0;
1193 for(i = 0; i < buffers->mNumberBuffers; ++i)
1194 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1196 HeapFree(GetProcessHeap(), 0, buffers);
1198 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1200 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1201 size = sizeof(Float64);
1202 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1203 if(sc != noErr){
1204 CoTaskMemFree(fmt);
1205 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1206 return E_FAIL;
1208 fmt->Format.nSamplesPerSec = rate;
1210 fmt->Format.wBitsPerSample = 32;
1211 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1213 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1214 fmt->Format.nChannels) / 8;
1215 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1216 fmt->Format.nBlockAlign;
1218 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1219 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1221 *pwfx = (WAVEFORMATEX*)fmt;
1222 dump_fmt(*pwfx);
1224 return S_OK;
1227 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1228 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1230 ACImpl *This = impl_from_IAudioClient(iface);
1232 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1234 if(!defperiod && !minperiod)
1235 return E_POINTER;
1237 OSSpinLockLock(&This->lock);
1239 if(This->period_ms){
1240 if(defperiod)
1241 *defperiod = This->period_ms * 10000;
1242 if(minperiod)
1243 *minperiod = This->period_ms * 10000;
1244 }else{
1245 if(defperiod)
1246 *defperiod = DefaultPeriod;
1247 if(minperiod)
1248 *minperiod = MinimumPeriod;
1251 OSSpinLockUnlock(&This->lock);
1253 return S_OK;
1256 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1258 ACImpl *This = user;
1260 OSSpinLockLock(&This->lock);
1261 if(This->event)
1262 SetEvent(This->event);
1263 OSSpinLockUnlock(&This->lock);
1266 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1268 ACImpl *This = impl_from_IAudioClient(iface);
1269 OSStatus sc;
1271 TRACE("(%p)\n", This);
1273 OSSpinLockLock(&This->lock);
1275 if(!This->aqueue){
1276 OSSpinLockUnlock(&This->lock);
1277 return AUDCLNT_E_NOT_INITIALIZED;
1280 if(This->playing != StateStopped){
1281 OSSpinLockUnlock(&This->lock);
1282 return AUDCLNT_E_NOT_STOPPED;
1285 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1286 OSSpinLockUnlock(&This->lock);
1287 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1290 if(This->event)
1291 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1292 ca_period_cb, This, 0, This->period_ms, 0))
1293 ERR("Unable to create timer: %u\n", GetLastError());
1295 This->playing = StateInTransition;
1297 OSSpinLockUnlock(&This->lock);
1299 sc = AudioQueueStart(This->aqueue, NULL);
1300 if(sc != noErr){
1301 WARN("Unable to start audio queue: %lx\n", sc);
1302 return E_FAIL;
1305 OSSpinLockLock(&This->lock);
1307 This->playing = StatePlaying;
1309 OSSpinLockUnlock(&This->lock);
1311 return S_OK;
1314 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1316 ACImpl *This = impl_from_IAudioClient(iface);
1317 OSStatus sc;
1319 TRACE("(%p)\n", This);
1321 OSSpinLockLock(&This->lock);
1323 if(!This->aqueue){
1324 OSSpinLockUnlock(&This->lock);
1325 return AUDCLNT_E_NOT_INITIALIZED;
1328 if(This->playing == StateStopped){
1329 OSSpinLockUnlock(&This->lock);
1330 return S_FALSE;
1333 if(This->playing == StateInTransition){
1334 OSSpinLockUnlock(&This->lock);
1335 return S_OK;
1338 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1339 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1340 This->timer = NULL;
1343 This->playing = StateInTransition;
1345 OSSpinLockUnlock(&This->lock);
1347 sc = AudioQueueFlush(This->aqueue);
1348 if(sc != noErr)
1349 WARN("Unable to flush audio queue: %lx\n", sc);
1351 sc = AudioQueuePause(This->aqueue);
1352 if(sc != noErr){
1353 WARN("Unable to pause audio queue: %lx\n", sc);
1354 return E_FAIL;
1357 OSSpinLockLock(&This->lock);
1359 This->playing = StateStopped;
1361 OSSpinLockUnlock(&This->lock);
1363 return S_OK;
1366 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1368 ACImpl *This = impl_from_IAudioClient(iface);
1369 HRESULT hr;
1370 OSStatus sc;
1372 TRACE("(%p)\n", This);
1374 OSSpinLockLock(&This->lock);
1376 if(!This->aqueue){
1377 OSSpinLockUnlock(&This->lock);
1378 return AUDCLNT_E_NOT_INITIALIZED;
1381 if(This->playing != StateStopped){
1382 OSSpinLockUnlock(&This->lock);
1383 return AUDCLNT_E_NOT_STOPPED;
1386 This->written_frames = 0;
1388 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1389 if(FAILED(hr)){
1390 OSSpinLockUnlock(&This->lock);
1391 return hr;
1394 OSSpinLockUnlock(&This->lock);
1396 sc = AudioQueueReset(This->aqueue);
1397 if(sc != noErr){
1398 WARN("Unable to reset audio queue: %lx\n", sc);
1399 return E_FAIL;
1402 return S_OK;
1405 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1406 HANDLE event)
1408 ACImpl *This = impl_from_IAudioClient(iface);
1410 TRACE("(%p)->(%p)\n", This, event);
1412 if(!event)
1413 return E_INVALIDARG;
1415 OSSpinLockLock(&This->lock);
1417 if(!This->aqueue){
1418 OSSpinLockUnlock(&This->lock);
1419 return AUDCLNT_E_NOT_INITIALIZED;
1422 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1423 OSSpinLockUnlock(&This->lock);
1424 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1427 This->event = event;
1429 OSSpinLockUnlock(&This->lock);
1431 return S_OK;
1434 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1435 void **ppv)
1437 ACImpl *This = impl_from_IAudioClient(iface);
1439 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1441 if(!ppv)
1442 return E_POINTER;
1443 *ppv = NULL;
1445 OSSpinLockLock(&This->lock);
1447 if(!This->aqueue){
1448 OSSpinLockUnlock(&This->lock);
1449 return AUDCLNT_E_NOT_INITIALIZED;
1452 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1453 if(This->dataflow != eRender){
1454 OSSpinLockUnlock(&This->lock);
1455 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1457 *ppv = &This->IAudioRenderClient_iface;
1458 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1459 if(This->dataflow != eCapture){
1460 OSSpinLockUnlock(&This->lock);
1461 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1463 *ppv = &This->IAudioCaptureClient_iface;
1464 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1465 *ppv = &This->IAudioClock_iface;
1466 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1467 *ppv = &This->IAudioStreamVolume_iface;
1468 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1469 if(!This->session_wrapper){
1470 This->session_wrapper = AudioSessionWrapper_Create(This);
1471 if(!This->session_wrapper){
1472 OSSpinLockUnlock(&This->lock);
1473 return E_OUTOFMEMORY;
1477 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1478 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1479 if(!This->session_wrapper){
1480 This->session_wrapper = AudioSessionWrapper_Create(This);
1481 if(!This->session_wrapper){
1482 OSSpinLockUnlock(&This->lock);
1483 return E_OUTOFMEMORY;
1487 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1488 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1489 if(!This->session_wrapper){
1490 This->session_wrapper = AudioSessionWrapper_Create(This);
1491 if(!This->session_wrapper){
1492 OSSpinLockUnlock(&This->lock);
1493 return E_OUTOFMEMORY;
1497 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1500 if(*ppv){
1501 IUnknown_AddRef((IUnknown*)*ppv);
1502 OSSpinLockUnlock(&This->lock);
1503 return S_OK;
1506 OSSpinLockUnlock(&This->lock);
1508 FIXME("stub %s\n", debugstr_guid(riid));
1509 return E_NOINTERFACE;
1512 static const IAudioClientVtbl AudioClient_Vtbl =
1514 AudioClient_QueryInterface,
1515 AudioClient_AddRef,
1516 AudioClient_Release,
1517 AudioClient_Initialize,
1518 AudioClient_GetBufferSize,
1519 AudioClient_GetStreamLatency,
1520 AudioClient_GetCurrentPadding,
1521 AudioClient_IsFormatSupported,
1522 AudioClient_GetMixFormat,
1523 AudioClient_GetDevicePeriod,
1524 AudioClient_Start,
1525 AudioClient_Stop,
1526 AudioClient_Reset,
1527 AudioClient_SetEventHandle,
1528 AudioClient_GetService
1531 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1532 IAudioRenderClient *iface, REFIID riid, void **ppv)
1534 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1536 if(!ppv)
1537 return E_POINTER;
1538 *ppv = NULL;
1540 if(IsEqualIID(riid, &IID_IUnknown) ||
1541 IsEqualIID(riid, &IID_IAudioRenderClient))
1542 *ppv = iface;
1543 if(*ppv){
1544 IUnknown_AddRef((IUnknown*)*ppv);
1545 return S_OK;
1548 WARN("Unknown interface %s\n", debugstr_guid(riid));
1549 return E_NOINTERFACE;
1552 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1554 ACImpl *This = impl_from_IAudioRenderClient(iface);
1555 return AudioClient_AddRef(&This->IAudioClient_iface);
1558 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1560 ACImpl *This = impl_from_IAudioRenderClient(iface);
1561 return AudioClient_Release(&This->IAudioClient_iface);
1564 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1565 UINT32 frames, BYTE **data)
1567 ACImpl *This = impl_from_IAudioRenderClient(iface);
1568 AQBuffer *buf;
1569 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1570 HRESULT hr;
1571 OSStatus sc;
1573 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1575 if(!data)
1576 return E_POINTER;
1578 OSSpinLockLock(&This->lock);
1580 if(This->getbuf_last){
1581 OSSpinLockUnlock(&This->lock);
1582 return AUDCLNT_E_OUT_OF_ORDER;
1585 if(!frames){
1586 This->getbuf_last = TRUE;
1587 OSSpinLockUnlock(&This->lock);
1588 return S_OK;
1591 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1592 if(FAILED(hr)){
1593 OSSpinLockUnlock(&This->lock);
1594 return hr;
1597 if(pad + frames > This->bufsize_frames){
1598 OSSpinLockUnlock(&This->lock);
1599 return AUDCLNT_E_BUFFER_TOO_LARGE;
1602 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1603 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1604 This->public_buffer = buf->buf;
1605 list_remove(&buf->entry);
1606 break;
1610 if(&buf->entry == &This->avail_buffers){
1611 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1612 &This->public_buffer);
1613 if(sc != noErr){
1614 OSSpinLockUnlock(&This->lock);
1615 WARN("Unable to allocate buffer: %lx\n", sc);
1616 return E_FAIL;
1618 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1619 if(!buf){
1620 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1621 This->public_buffer = NULL;
1622 OSSpinLockUnlock(&This->lock);
1623 return E_OUTOFMEMORY;
1625 buf->buf = This->public_buffer;
1626 This->public_buffer->mUserData = buf;
1629 *data = This->public_buffer->mAudioData;
1631 This->getbuf_last = TRUE;
1633 OSSpinLockUnlock(&This->lock);
1635 return S_OK;
1638 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1639 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1641 ACImpl *This = impl_from_IAudioRenderClient(iface);
1642 OSStatus sc;
1644 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1646 OSSpinLockLock(&This->lock);
1648 if(!This->getbuf_last){
1649 OSSpinLockUnlock(&This->lock);
1650 return AUDCLNT_E_OUT_OF_ORDER;
1653 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1654 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1655 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1656 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1657 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1658 This->fmt->wBitsPerSample == 8)
1659 memset(This->public_buffer->mAudioData, 128,
1660 frames * This->fmt->nBlockAlign);
1661 else
1662 memset(This->public_buffer->mAudioData, 0,
1663 frames * This->fmt->nBlockAlign);
1666 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1668 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1669 if(sc != noErr){
1670 OSSpinLockUnlock(&This->lock);
1671 WARN("Unable to enqueue buffer: %lx\n", sc);
1672 return E_FAIL;
1675 if(This->playing == StateStopped)
1676 AudioQueuePrime(This->aqueue, 0, NULL);
1678 This->public_buffer = NULL;
1679 This->getbuf_last = FALSE;
1680 This->written_frames += frames;
1681 This->inbuf_frames += frames;
1683 OSSpinLockUnlock(&This->lock);
1685 return S_OK;
1688 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1689 AudioRenderClient_QueryInterface,
1690 AudioRenderClient_AddRef,
1691 AudioRenderClient_Release,
1692 AudioRenderClient_GetBuffer,
1693 AudioRenderClient_ReleaseBuffer
1696 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1697 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1699 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1701 if(!ppv)
1702 return E_POINTER;
1703 *ppv = NULL;
1705 if(IsEqualIID(riid, &IID_IUnknown) ||
1706 IsEqualIID(riid, &IID_IAudioCaptureClient))
1707 *ppv = iface;
1708 if(*ppv){
1709 IUnknown_AddRef((IUnknown*)*ppv);
1710 return S_OK;
1713 WARN("Unknown interface %s\n", debugstr_guid(riid));
1714 return E_NOINTERFACE;
1717 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1719 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1720 return IAudioClient_AddRef(&This->IAudioClient_iface);
1723 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1725 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1726 return IAudioClient_Release(&This->IAudioClient_iface);
1729 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1730 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1731 UINT64 *qpcpos)
1733 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1735 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1736 devpos, qpcpos);
1738 if(!data || !frames || !flags)
1739 return E_POINTER;
1741 OSSpinLockLock(&This->lock);
1743 if(This->getbuf_last){
1744 OSSpinLockUnlock(&This->lock);
1745 return AUDCLNT_E_OUT_OF_ORDER;
1748 if(This->public_buffer){
1749 *data = This->public_buffer->mAudioData;
1750 *frames =
1751 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1752 }else{
1753 struct list *head = list_head(&This->avail_buffers);
1754 if(!head){
1755 *data = NULL;
1756 *frames = 0;
1757 }else{
1758 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1759 This->public_buffer = buf->buf;
1760 *data = This->public_buffer->mAudioData;
1761 *frames =
1762 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1763 list_remove(&buf->entry);
1767 *flags = 0;
1768 This->written_frames += *frames;
1769 This->inbuf_frames -= *frames;
1770 This->getbuf_last = TRUE;
1772 if(devpos || qpcpos)
1773 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1775 OSSpinLockUnlock(&This->lock);
1777 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1780 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1781 IAudioCaptureClient *iface, UINT32 done)
1783 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1784 UINT32 pbuf_frames =
1785 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1786 OSStatus sc;
1788 TRACE("(%p)->(%u)\n", This, done);
1790 OSSpinLockLock(&This->lock);
1792 if(!This->getbuf_last){
1793 OSSpinLockUnlock(&This->lock);
1794 return AUDCLNT_E_OUT_OF_ORDER;
1797 if(done != 0 && done != pbuf_frames){
1798 OSSpinLockUnlock(&This->lock);
1799 return AUDCLNT_E_INVALID_SIZE;
1802 if(done){
1803 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1804 0, NULL);
1805 if(sc != noErr)
1806 WARN("Unable to enqueue buffer: %lx\n", sc);
1807 This->public_buffer = NULL;
1810 This->getbuf_last = FALSE;
1812 OSSpinLockUnlock(&This->lock);
1814 return S_OK;
1817 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1818 IAudioCaptureClient *iface, UINT32 *frames)
1820 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1821 struct list *head;
1822 AQBuffer *buf;
1824 TRACE("(%p)->(%p)\n", This, frames);
1826 if(!frames)
1827 return E_POINTER;
1829 OSSpinLockLock(&This->lock);
1831 head = list_head(&This->avail_buffers);
1833 if(!head){
1834 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1835 OSSpinLockUnlock(&This->lock);
1836 return S_OK;
1839 buf = LIST_ENTRY(head, AQBuffer, entry);
1840 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1842 OSSpinLockUnlock(&This->lock);
1844 return S_OK;
1847 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1849 AudioCaptureClient_QueryInterface,
1850 AudioCaptureClient_AddRef,
1851 AudioCaptureClient_Release,
1852 AudioCaptureClient_GetBuffer,
1853 AudioCaptureClient_ReleaseBuffer,
1854 AudioCaptureClient_GetNextPacketSize
1857 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1858 REFIID riid, void **ppv)
1860 ACImpl *This = impl_from_IAudioClock(iface);
1862 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1864 if(!ppv)
1865 return E_POINTER;
1866 *ppv = NULL;
1868 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1869 *ppv = iface;
1870 else if(IsEqualIID(riid, &IID_IAudioClock2))
1871 *ppv = &This->IAudioClock2_iface;
1872 if(*ppv){
1873 IUnknown_AddRef((IUnknown*)*ppv);
1874 return S_OK;
1877 WARN("Unknown interface %s\n", debugstr_guid(riid));
1878 return E_NOINTERFACE;
1881 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1883 ACImpl *This = impl_from_IAudioClock(iface);
1884 return IAudioClient_AddRef(&This->IAudioClient_iface);
1887 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1889 ACImpl *This = impl_from_IAudioClock(iface);
1890 return IAudioClient_Release(&This->IAudioClient_iface);
1893 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1895 ACImpl *This = impl_from_IAudioClock(iface);
1897 TRACE("(%p)->(%p)\n", This, freq);
1899 *freq = This->fmt->nSamplesPerSec;
1901 return S_OK;
1904 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1905 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1907 AudioTimeStamp time;
1908 OSStatus sc;
1910 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1911 if(sc == kAudioQueueErr_InvalidRunState){
1912 *pos = 0;
1913 }else if(sc == noErr){
1914 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1915 FIXME("Sample time not valid, should calculate from something else\n");
1916 return E_FAIL;
1919 if(raw)
1920 *pos = time.mSampleTime;
1921 else
1922 *pos = time.mSampleTime - This->last_time;
1923 }else{
1924 WARN("Unable to get current time: %lx\n", sc);
1925 return E_FAIL;
1928 if(qpctime){
1929 LARGE_INTEGER stamp, freq;
1930 QueryPerformanceCounter(&stamp);
1931 QueryPerformanceFrequency(&freq);
1932 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1935 return S_OK;
1938 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1939 UINT64 *qpctime)
1941 ACImpl *This = impl_from_IAudioClock(iface);
1942 HRESULT hr;
1944 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1946 if(!pos)
1947 return E_POINTER;
1949 OSSpinLockLock(&This->lock);
1951 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
1953 OSSpinLockUnlock(&This->lock);
1955 return hr;
1958 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1959 DWORD *chars)
1961 ACImpl *This = impl_from_IAudioClock(iface);
1963 TRACE("(%p)->(%p)\n", This, chars);
1965 if(!chars)
1966 return E_POINTER;
1968 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1970 return S_OK;
1973 static const IAudioClockVtbl AudioClock_Vtbl =
1975 AudioClock_QueryInterface,
1976 AudioClock_AddRef,
1977 AudioClock_Release,
1978 AudioClock_GetFrequency,
1979 AudioClock_GetPosition,
1980 AudioClock_GetCharacteristics
1983 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1984 REFIID riid, void **ppv)
1986 ACImpl *This = impl_from_IAudioClock2(iface);
1987 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1990 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1992 ACImpl *This = impl_from_IAudioClock2(iface);
1993 return IAudioClient_AddRef(&This->IAudioClient_iface);
1996 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1998 ACImpl *This = impl_from_IAudioClock2(iface);
1999 return IAudioClient_Release(&This->IAudioClient_iface);
2002 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2003 UINT64 *pos, UINT64 *qpctime)
2005 ACImpl *This = impl_from_IAudioClock2(iface);
2007 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2009 return E_NOTIMPL;
2012 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2014 AudioClock2_QueryInterface,
2015 AudioClock2_AddRef,
2016 AudioClock2_Release,
2017 AudioClock2_GetDevicePosition
2020 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2022 AudioSessionWrapper *ret;
2024 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2025 sizeof(AudioSessionWrapper));
2026 if(!ret)
2027 return NULL;
2029 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2030 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2031 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2033 ret->client = client;
2034 if(client){
2035 ret->session = client->session;
2036 AudioClient_AddRef(&client->IAudioClient_iface);
2039 return ret;
2042 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2043 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2045 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2047 if(!ppv)
2048 return E_POINTER;
2049 *ppv = NULL;
2051 if(IsEqualIID(riid, &IID_IUnknown) ||
2052 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2053 IsEqualIID(riid, &IID_IAudioSessionControl2))
2054 *ppv = iface;
2055 if(*ppv){
2056 IUnknown_AddRef((IUnknown*)*ppv);
2057 return S_OK;
2060 WARN("Unknown interface %s\n", debugstr_guid(riid));
2061 return E_NOINTERFACE;
2064 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2066 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2067 ULONG ref;
2068 ref = InterlockedIncrement(&This->ref);
2069 TRACE("(%p) Refcount now %u\n", This, ref);
2070 return ref;
2073 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2075 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2076 ULONG ref;
2077 ref = InterlockedDecrement(&This->ref);
2078 TRACE("(%p) Refcount now %u\n", This, ref);
2079 if(!ref){
2080 OSSpinLockLock(&This->client->lock);
2081 This->client->session_wrapper = NULL;
2082 OSSpinLockUnlock(&This->client->lock);
2083 AudioClient_Release(&This->client->IAudioClient_iface);
2084 HeapFree(GetProcessHeap(), 0, This);
2086 return ref;
2089 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2090 AudioSessionState *state)
2092 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2093 ACImpl *client;
2095 TRACE("(%p)->(%p)\n", This, state);
2097 if(!state)
2098 return NULL_PTR_ERR;
2100 EnterCriticalSection(&g_sessions_lock);
2102 if(list_empty(&This->session->clients)){
2103 *state = AudioSessionStateExpired;
2104 LeaveCriticalSection(&g_sessions_lock);
2105 return S_OK;
2108 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2109 OSSpinLockLock(&client->lock);
2110 if(client->playing == StatePlaying ||
2111 client->playing == StateInTransition){
2112 *state = AudioSessionStateActive;
2113 OSSpinLockUnlock(&client->lock);
2114 LeaveCriticalSection(&g_sessions_lock);
2115 return S_OK;
2117 OSSpinLockUnlock(&client->lock);
2120 LeaveCriticalSection(&g_sessions_lock);
2122 *state = AudioSessionStateInactive;
2124 return S_OK;
2127 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2128 IAudioSessionControl2 *iface, WCHAR **name)
2130 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2132 FIXME("(%p)->(%p) - stub\n", This, name);
2134 return E_NOTIMPL;
2137 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2138 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2140 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2142 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2144 return E_NOTIMPL;
2147 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2148 IAudioSessionControl2 *iface, WCHAR **path)
2150 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2152 FIXME("(%p)->(%p) - stub\n", This, path);
2154 return E_NOTIMPL;
2157 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2158 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2160 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2162 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2164 return E_NOTIMPL;
2167 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2168 IAudioSessionControl2 *iface, GUID *group)
2170 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2172 FIXME("(%p)->(%p) - stub\n", This, group);
2174 return E_NOTIMPL;
2177 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2178 IAudioSessionControl2 *iface, GUID *group, const GUID *session)
2180 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2182 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2183 debugstr_guid(session));
2185 return E_NOTIMPL;
2188 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2189 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2191 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2193 FIXME("(%p)->(%p) - stub\n", This, events);
2195 return S_OK;
2198 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2199 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2201 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2203 FIXME("(%p)->(%p) - stub\n", This, events);
2205 return S_OK;
2208 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2209 IAudioSessionControl2 *iface, WCHAR **id)
2211 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2213 FIXME("(%p)->(%p) - stub\n", This, id);
2215 return E_NOTIMPL;
2218 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2219 IAudioSessionControl2 *iface, WCHAR **id)
2221 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2223 FIXME("(%p)->(%p) - stub\n", This, id);
2225 return E_NOTIMPL;
2228 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2229 IAudioSessionControl2 *iface, DWORD *pid)
2231 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2233 TRACE("(%p)->(%p)\n", This, pid);
2235 if(!pid)
2236 return E_POINTER;
2238 *pid = GetCurrentProcessId();
2240 return S_OK;
2243 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2244 IAudioSessionControl2 *iface)
2246 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2248 TRACE("(%p)\n", This);
2250 return S_FALSE;
2253 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2254 IAudioSessionControl2 *iface, BOOL optout)
2256 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2258 TRACE("(%p)->(%d)\n", This, optout);
2260 return S_OK;
2263 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2265 AudioSessionControl_QueryInterface,
2266 AudioSessionControl_AddRef,
2267 AudioSessionControl_Release,
2268 AudioSessionControl_GetState,
2269 AudioSessionControl_GetDisplayName,
2270 AudioSessionControl_SetDisplayName,
2271 AudioSessionControl_GetIconPath,
2272 AudioSessionControl_SetIconPath,
2273 AudioSessionControl_GetGroupingParam,
2274 AudioSessionControl_SetGroupingParam,
2275 AudioSessionControl_RegisterAudioSessionNotification,
2276 AudioSessionControl_UnregisterAudioSessionNotification,
2277 AudioSessionControl_GetSessionIdentifier,
2278 AudioSessionControl_GetSessionInstanceIdentifier,
2279 AudioSessionControl_GetProcessId,
2280 AudioSessionControl_IsSystemSoundsSession,
2281 AudioSessionControl_SetDuckingPreference
2284 /* index == -1 means set all channels, otherwise sets only the given channel */
2285 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2287 AudioObjectPropertyAddress addr;
2288 float level;
2289 OSStatus sc;
2291 if(index == (UINT32)-1){
2292 HRESULT ret = S_OK;
2293 UINT32 i;
2294 for(i = 0; i < This->fmt->nChannels; ++i){
2295 HRESULT hr;
2296 hr = ca_setvol(This, i);
2297 if(FAILED(hr))
2298 ret = hr;
2300 return ret;
2303 level = This->session->master_vol * This->session->channel_vols[index] *
2304 This->vols[index];
2306 addr.mScope = This->scope;
2307 addr.mSelector = kAudioDevicePropertyVolumeScalar;
2308 addr.mElement = index + 1;
2310 sc = AudioObjectSetPropertyData(This->adevid, &addr, 0, NULL,
2311 sizeof(float), &level);
2312 if(sc != noErr){
2313 WARN("Setting _VolumeScalar property failed: %lx\n", sc);
2314 return E_FAIL;
2317 return S_OK;
2320 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2322 HRESULT ret = S_OK;
2323 ACImpl *client;
2325 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2326 HRESULT hr;
2327 hr = ca_setvol(client, index);
2328 if(FAILED(hr))
2329 ret = hr;
2332 return ret;
2335 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2336 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2338 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2340 if(!ppv)
2341 return E_POINTER;
2342 *ppv = NULL;
2344 if(IsEqualIID(riid, &IID_IUnknown) ||
2345 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2346 *ppv = iface;
2347 if(*ppv){
2348 IUnknown_AddRef((IUnknown*)*ppv);
2349 return S_OK;
2352 WARN("Unknown interface %s\n", debugstr_guid(riid));
2353 return E_NOINTERFACE;
2356 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2358 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2359 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2362 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2364 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2365 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2368 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2369 ISimpleAudioVolume *iface, float level, const GUID *context)
2371 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2372 AudioSession *session = This->session;
2373 HRESULT ret;
2375 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2377 if(level < 0.f || level > 1.f)
2378 return E_INVALIDARG;
2380 if(context)
2381 FIXME("Notifications not supported yet\n");
2383 EnterCriticalSection(&session->lock);
2385 session->master_vol = level;
2387 ret = ca_session_setvol(session, -1);
2389 LeaveCriticalSection(&session->lock);
2391 return ret;
2394 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2395 ISimpleAudioVolume *iface, float *level)
2397 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2398 AudioSession *session = This->session;
2400 TRACE("(%p)->(%p)\n", session, level);
2402 if(!level)
2403 return NULL_PTR_ERR;
2405 *level = session->master_vol;
2407 return S_OK;
2410 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2411 BOOL mute, const GUID *context)
2413 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2414 AudioSession *session = This->session;
2416 FIXME("(%p)->(%u, %p) - stub\n", session, mute, context);
2418 return E_NOTIMPL;
2421 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2422 BOOL *mute)
2424 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2425 AudioSession *session = This->session;
2427 FIXME("(%p)->(%p) - stub\n", session, mute);
2429 if(!mute)
2430 return NULL_PTR_ERR;
2432 return E_NOTIMPL;
2435 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2437 SimpleAudioVolume_QueryInterface,
2438 SimpleAudioVolume_AddRef,
2439 SimpleAudioVolume_Release,
2440 SimpleAudioVolume_SetMasterVolume,
2441 SimpleAudioVolume_GetMasterVolume,
2442 SimpleAudioVolume_SetMute,
2443 SimpleAudioVolume_GetMute
2446 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2447 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2449 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2451 if(!ppv)
2452 return E_POINTER;
2453 *ppv = NULL;
2455 if(IsEqualIID(riid, &IID_IUnknown) ||
2456 IsEqualIID(riid, &IID_IAudioStreamVolume))
2457 *ppv = iface;
2458 if(*ppv){
2459 IUnknown_AddRef((IUnknown*)*ppv);
2460 return S_OK;
2463 WARN("Unknown interface %s\n", debugstr_guid(riid));
2464 return E_NOINTERFACE;
2467 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2469 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2470 return IAudioClient_AddRef(&This->IAudioClient_iface);
2473 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2475 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2476 return IAudioClient_Release(&This->IAudioClient_iface);
2479 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2480 IAudioStreamVolume *iface, UINT32 *out)
2482 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2484 TRACE("(%p)->(%p)\n", This, out);
2486 if(!out)
2487 return E_POINTER;
2489 *out = This->fmt->nChannels;
2491 return S_OK;
2494 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2495 IAudioStreamVolume *iface, UINT32 index, float level)
2497 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2498 HRESULT ret;
2500 TRACE("(%p)->(%d, %f)\n", This, index, level);
2502 if(level < 0.f || level > 1.f)
2503 return E_INVALIDARG;
2505 if(index >= This->fmt->nChannels)
2506 return E_INVALIDARG;
2508 OSSpinLockLock(&This->lock);
2510 This->vols[index] = level;
2512 ret = ca_setvol(This, index);
2514 OSSpinLockUnlock(&This->lock);
2516 return ret;
2519 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2520 IAudioStreamVolume *iface, UINT32 index, float *level)
2522 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2524 TRACE("(%p)->(%d, %p)\n", This, index, level);
2526 if(!level)
2527 return E_POINTER;
2529 if(index >= This->fmt->nChannels)
2530 return E_INVALIDARG;
2532 *level = This->vols[index];
2534 return S_OK;
2537 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2538 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2540 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2541 int i;
2542 HRESULT ret;
2544 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2546 if(!levels)
2547 return E_POINTER;
2549 if(count != This->fmt->nChannels)
2550 return E_INVALIDARG;
2552 OSSpinLockLock(&This->lock);
2554 for(i = 0; i < count; ++i)
2555 This->vols[i] = levels[i];
2557 ret = ca_setvol(This, -1);
2559 OSSpinLockUnlock(&This->lock);
2561 return ret;
2564 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2565 IAudioStreamVolume *iface, UINT32 count, float *levels)
2567 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2568 int i;
2570 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2572 if(!levels)
2573 return E_POINTER;
2575 if(count != This->fmt->nChannels)
2576 return E_INVALIDARG;
2578 OSSpinLockLock(&This->lock);
2580 for(i = 0; i < count; ++i)
2581 levels[i] = This->vols[i];
2583 OSSpinLockUnlock(&This->lock);
2585 return S_OK;
2588 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2590 AudioStreamVolume_QueryInterface,
2591 AudioStreamVolume_AddRef,
2592 AudioStreamVolume_Release,
2593 AudioStreamVolume_GetChannelCount,
2594 AudioStreamVolume_SetChannelVolume,
2595 AudioStreamVolume_GetChannelVolume,
2596 AudioStreamVolume_SetAllVolumes,
2597 AudioStreamVolume_GetAllVolumes
2600 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2601 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2603 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2605 if(!ppv)
2606 return E_POINTER;
2607 *ppv = NULL;
2609 if(IsEqualIID(riid, &IID_IUnknown) ||
2610 IsEqualIID(riid, &IID_IChannelAudioVolume))
2611 *ppv = iface;
2612 if(*ppv){
2613 IUnknown_AddRef((IUnknown*)*ppv);
2614 return S_OK;
2617 WARN("Unknown interface %s\n", debugstr_guid(riid));
2618 return E_NOINTERFACE;
2621 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2623 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2624 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2627 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2629 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2630 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2633 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2634 IChannelAudioVolume *iface, UINT32 *out)
2636 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2637 AudioSession *session = This->session;
2639 TRACE("(%p)->(%p)\n", session, out);
2641 if(!out)
2642 return NULL_PTR_ERR;
2644 *out = session->channel_count;
2646 return S_OK;
2649 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2650 IChannelAudioVolume *iface, UINT32 index, float level,
2651 const GUID *context)
2653 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2654 AudioSession *session = This->session;
2655 HRESULT ret;
2657 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2658 wine_dbgstr_guid(context));
2660 if(level < 0.f || level > 1.f)
2661 return E_INVALIDARG;
2663 if(index >= session->channel_count)
2664 return E_INVALIDARG;
2666 if(context)
2667 FIXME("Notifications not supported yet\n");
2669 EnterCriticalSection(&session->lock);
2671 session->channel_vols[index] = level;
2673 ret = ca_session_setvol(session, index);
2675 LeaveCriticalSection(&session->lock);
2677 return ret;
2680 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2681 IChannelAudioVolume *iface, UINT32 index, float *level)
2683 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2684 AudioSession *session = This->session;
2686 TRACE("(%p)->(%d, %p)\n", session, index, level);
2688 if(!level)
2689 return NULL_PTR_ERR;
2691 if(index >= session->channel_count)
2692 return E_INVALIDARG;
2694 *level = session->channel_vols[index];
2696 return S_OK;
2699 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2700 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2701 const GUID *context)
2703 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2704 AudioSession *session = This->session;
2705 int i;
2706 HRESULT ret;
2708 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2709 wine_dbgstr_guid(context));
2711 if(!levels)
2712 return NULL_PTR_ERR;
2714 if(count != session->channel_count)
2715 return E_INVALIDARG;
2717 if(context)
2718 FIXME("Notifications not supported yet\n");
2720 EnterCriticalSection(&session->lock);
2722 for(i = 0; i < count; ++i)
2723 session->channel_vols[i] = levels[i];
2725 ret = ca_session_setvol(session, -1);
2727 LeaveCriticalSection(&session->lock);
2729 return ret;
2732 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2733 IChannelAudioVolume *iface, UINT32 count, float *levels)
2735 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2736 AudioSession *session = This->session;
2737 int i;
2739 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2741 if(!levels)
2742 return NULL_PTR_ERR;
2744 if(count != session->channel_count)
2745 return E_INVALIDARG;
2747 for(i = 0; i < count; ++i)
2748 levels[i] = session->channel_vols[i];
2750 return S_OK;
2753 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2755 ChannelAudioVolume_QueryInterface,
2756 ChannelAudioVolume_AddRef,
2757 ChannelAudioVolume_Release,
2758 ChannelAudioVolume_GetChannelCount,
2759 ChannelAudioVolume_SetChannelVolume,
2760 ChannelAudioVolume_GetChannelVolume,
2761 ChannelAudioVolume_SetAllVolumes,
2762 ChannelAudioVolume_GetAllVolumes
2765 HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2766 REFIID riid, void **ppv)
2768 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2770 if(!ppv)
2771 return E_POINTER;
2772 *ppv = NULL;
2774 if(IsEqualIID(riid, &IID_IUnknown) ||
2775 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2776 IsEqualIID(riid, &IID_IAudioSessionManager2))
2777 *ppv = iface;
2778 if(*ppv){
2779 IUnknown_AddRef((IUnknown*)*ppv);
2780 return S_OK;
2783 WARN("Unknown interface %s\n", debugstr_guid(riid));
2784 return E_NOINTERFACE;
2787 ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2789 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2790 ULONG ref;
2791 ref = InterlockedIncrement(&This->ref);
2792 TRACE("(%p) Refcount now %u\n", This, ref);
2793 return ref;
2796 ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2798 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2799 ULONG ref;
2800 ref = InterlockedDecrement(&This->ref);
2801 TRACE("(%p) Refcount now %u\n", This, ref);
2802 if(!ref)
2803 HeapFree(GetProcessHeap(), 0, This);
2804 return ref;
2807 HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2808 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2809 IAudioSessionControl **out)
2811 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2812 AudioSession *session;
2813 AudioSessionWrapper *wrapper;
2814 HRESULT hr;
2816 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2817 flags, out);
2819 hr = get_audio_session(session_guid, This->flow, 0, &session);
2820 if(FAILED(hr))
2821 return hr;
2823 wrapper = AudioSessionWrapper_Create(NULL);
2824 if(!wrapper)
2825 return E_OUTOFMEMORY;
2827 wrapper->session = session;
2829 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2831 return S_OK;
2834 HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2835 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2836 ISimpleAudioVolume **out)
2838 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2839 AudioSession *session;
2840 AudioSessionWrapper *wrapper;
2841 HRESULT hr;
2843 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2844 flags, out);
2846 hr = get_audio_session(session_guid, This->flow, 0, &session);
2847 if(FAILED(hr))
2848 return hr;
2850 wrapper = AudioSessionWrapper_Create(NULL);
2851 if(!wrapper)
2852 return E_OUTOFMEMORY;
2854 wrapper->session = session;
2856 *out = &wrapper->ISimpleAudioVolume_iface;
2858 return S_OK;
2861 HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2862 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2864 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2865 FIXME("(%p)->(%p) - stub\n", This, out);
2866 return E_NOTIMPL;
2869 HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2870 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2872 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2873 FIXME("(%p)->(%p) - stub\n", This, notification);
2874 return E_NOTIMPL;
2877 HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2878 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2880 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2881 FIXME("(%p)->(%p) - stub\n", This, notification);
2882 return E_NOTIMPL;
2885 HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2886 IAudioSessionManager2 *iface, const WCHAR *session_id,
2887 IAudioVolumeDuckNotification *notification)
2889 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2890 FIXME("(%p)->(%p) - stub\n", This, notification);
2891 return E_NOTIMPL;
2894 HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2895 IAudioSessionManager2 *iface,
2896 IAudioVolumeDuckNotification *notification)
2898 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2899 FIXME("(%p)->(%p) - stub\n", This, notification);
2900 return E_NOTIMPL;
2903 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2905 AudioSessionManager_QueryInterface,
2906 AudioSessionManager_AddRef,
2907 AudioSessionManager_Release,
2908 AudioSessionManager_GetAudioSessionControl,
2909 AudioSessionManager_GetSimpleAudioVolume,
2910 AudioSessionManager_GetSessionEnumerator,
2911 AudioSessionManager_RegisterSessionNotification,
2912 AudioSessionManager_UnregisterSessionNotification,
2913 AudioSessionManager_RegisterDuckNotification,
2914 AudioSessionManager_UnregisterDuckNotification
2917 HRESULT WINAPI AUDDRV_GetAudioSessionManager(EDataFlow dataflow,
2918 IAudioSessionManager2 **out)
2920 SessionMgr *This;
2922 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2923 if(!*out)
2924 return E_OUTOFMEMORY;
2926 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2927 This->flow = dataflow;
2928 This->ref = 1;
2930 *out = &This->IAudioSessionManager2_iface;
2932 return S_OK;