mmdevapi: Automatically select the correct driver.
[wine/multimedia.git] / dlls / winecoreaudio.drv / mmdevdrv.c
bloba951673ef6a6f1010ed8b8a192cc31c124302799
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 IMMDevice *device;
82 float master_vol;
83 UINT32 channel_count;
84 float *channel_vols;
85 BOOL mute;
87 CRITICAL_SECTION lock;
89 struct list entry;
90 } AudioSession;
92 typedef struct _AudioSessionWrapper {
93 IAudioSessionControl2 IAudioSessionControl2_iface;
94 IChannelAudioVolume IChannelAudioVolume_iface;
95 ISimpleAudioVolume ISimpleAudioVolume_iface;
97 LONG ref;
99 ACImpl *client;
100 AudioSession *session;
101 } AudioSessionWrapper;
103 struct ACImpl {
104 IAudioClient IAudioClient_iface;
105 IAudioRenderClient IAudioRenderClient_iface;
106 IAudioCaptureClient IAudioCaptureClient_iface;
107 IAudioClock IAudioClock_iface;
108 IAudioClock2 IAudioClock2_iface;
109 IAudioStreamVolume IAudioStreamVolume_iface;
111 LONG ref;
113 IMMDevice *parent;
115 WAVEFORMATEX *fmt;
117 EDataFlow dataflow;
118 DWORD flags;
119 AUDCLNT_SHAREMODE share;
120 HANDLE event;
121 float *vols;
123 AudioDeviceID adevid;
124 AudioQueueRef aqueue;
125 AudioObjectPropertyScope scope;
126 HANDLE timer;
127 UINT32 period_ms, bufsize_frames, inbuf_frames, written_frames;
128 UINT64 last_time;
129 AudioQueueBufferRef public_buffer;
130 BOOL getbuf_last;
131 int playing;
133 AudioSession *session;
134 AudioSessionWrapper *session_wrapper;
136 struct list entry;
138 struct list avail_buffers;
140 /* We can't use debug printing or {Enter,Leave}CriticalSection from
141 * OSX callback threads, so we use OSX's OSSpinLock for synchronization
142 * instead. OSSpinLock is not a recursive lock, so don't call
143 * synchronized functions while holding the lock. */
144 OSSpinLock lock;
147 enum PlayingStates {
148 StateStopped = 0,
149 StatePlaying,
150 StateInTransition
153 static const IAudioClientVtbl AudioClient_Vtbl;
154 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
155 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
156 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
157 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
158 static const IAudioClockVtbl AudioClock_Vtbl;
159 static const IAudioClock2Vtbl AudioClock2_Vtbl;
160 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
161 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
162 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
164 typedef struct _SessionMgr {
165 IAudioSessionManager2 IAudioSessionManager2_iface;
167 LONG ref;
169 IMMDevice *device;
170 } SessionMgr;
172 static HANDLE g_timer_q;
174 static CRITICAL_SECTION g_sessions_lock;
175 static struct list g_sessions = LIST_INIT(g_sessions);
177 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This, UINT64 *pos,
178 UINT64 *qpctime, BOOL raw);
179 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
180 static HRESULT ca_setvol(ACImpl *This, UINT32 index);
182 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
184 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
187 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
189 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
192 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
194 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
197 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
199 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
202 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
204 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
207 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
209 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
212 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
214 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
217 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
219 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
222 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
224 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
227 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
229 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
232 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
234 if(reason == DLL_PROCESS_ATTACH){
235 g_timer_q = CreateTimerQueue();
236 if(!g_timer_q)
237 return FALSE;
239 InitializeCriticalSection(&g_sessions_lock);
242 return TRUE;
245 /* From <dlls/mmdevapi/mmdevapi.h> */
246 enum DriverPriority {
247 Priority_Unavailable = 0,
248 Priority_Low,
249 Priority_Neutral,
250 Priority_Preferred
253 int WINAPI AUDDRV_GetPriority(void)
255 return Priority_Neutral;
258 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
259 AudioDeviceID ***keys, UINT *num, UINT *def_index)
261 UInt32 devsize, size;
262 AudioDeviceID *devices;
263 AudioDeviceID default_id;
264 AudioObjectPropertyAddress addr;
265 OSStatus sc;
266 int i, ndevices;
268 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
270 addr.mScope = kAudioObjectPropertyScopeGlobal;
271 addr.mElement = kAudioObjectPropertyElementMaster;
272 if(flow == eRender)
273 addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
274 else if(flow == eCapture)
275 addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
276 else
277 return E_INVALIDARG;
279 size = sizeof(default_id);
280 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
281 NULL, &size, &default_id);
282 if(sc != noErr){
283 WARN("Getting _DefaultInputDevice property failed: %lx\n", sc);
284 default_id = -1;
287 addr.mSelector = kAudioHardwarePropertyDevices;
288 sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
289 NULL, &devsize);
290 if(sc != noErr){
291 WARN("Getting _Devices property size failed: %lx\n", sc);
292 return E_FAIL;
295 devices = HeapAlloc(GetProcessHeap(), 0, devsize);
296 if(!devices)
297 return E_OUTOFMEMORY;
299 sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
300 &devsize, devices);
301 if(sc != noErr){
302 WARN("Getting _Devices property failed: %lx\n", sc);
303 HeapFree(GetProcessHeap(), 0, devices);
304 return E_FAIL;
307 ndevices = devsize / sizeof(AudioDeviceID);
309 *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
310 if(!*ids){
311 HeapFree(GetProcessHeap(), 0, devices);
312 return E_OUTOFMEMORY;
315 *keys = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(AudioDeviceID *));
316 if(!*ids){
317 HeapFree(GetProcessHeap(), 0, *ids);
318 HeapFree(GetProcessHeap(), 0, devices);
319 return E_OUTOFMEMORY;
322 *num = 0;
323 *def_index = (UINT)-1;
324 for(i = 0; i < ndevices; ++i){
325 AudioBufferList *buffers;
326 CFStringRef name;
327 SIZE_T len;
328 char nameA[256];
329 int j;
331 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
332 if(flow == eRender)
333 addr.mScope = kAudioDevicePropertyScopeOutput;
334 else
335 addr.mScope = kAudioDevicePropertyScopeInput;
336 addr.mElement = 0;
337 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
338 if(sc != noErr){
339 WARN("Unable to get _StreamConfiguration property size for "
340 "device %lu: %lx\n", devices[i], sc);
341 continue;
344 buffers = HeapAlloc(GetProcessHeap(), 0, size);
345 if(!buffers){
346 HeapFree(GetProcessHeap(), 0, devices);
347 for(j = 0; j < *num; ++j)
348 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
349 HeapFree(GetProcessHeap(), 0, *keys);
350 HeapFree(GetProcessHeap(), 0, *ids);
351 return E_OUTOFMEMORY;
354 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
355 &size, buffers);
356 if(sc != noErr){
357 WARN("Unable to get _StreamConfiguration property for "
358 "device %lu: %lx\n", devices[i], sc);
359 HeapFree(GetProcessHeap(), 0, buffers);
360 continue;
363 /* check that there's at least one channel in this device before
364 * we claim it as usable */
365 for(j = 0; j < buffers->mNumberBuffers; ++j)
366 if(buffers->mBuffers[j].mNumberChannels > 0)
367 break;
368 if(j >= buffers->mNumberBuffers){
369 HeapFree(GetProcessHeap(), 0, buffers);
370 continue;
373 HeapFree(GetProcessHeap(), 0, buffers);
375 size = sizeof(name);
376 addr.mSelector = kAudioObjectPropertyName;
377 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
378 &size, &name);
379 if(sc != noErr){
380 WARN("Unable to get _Name property for device %lu: %lx\n",
381 devices[i], sc);
382 continue;
385 if(!CFStringGetCString(name, nameA, sizeof(nameA),
386 kCFStringEncodingUTF8)){
387 WARN("Error converting string to UTF8\n");
388 CFRelease(name);
389 continue;
392 CFRelease(name);
394 len = MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, NULL, 0);
395 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
396 if(!(*ids)[*num]){
397 HeapFree(GetProcessHeap(), 0, devices);
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 MultiByteToWideChar(CP_UNIXCP, 0, nameA, -1, (*ids)[*num], len);
408 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
409 if(!(*ids)[*num]){
410 HeapFree(GetProcessHeap(), 0, devices);
411 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
412 for(j = 0; j < *num; ++j){
413 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
414 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
416 HeapFree(GetProcessHeap(), 0, *ids);
417 HeapFree(GetProcessHeap(), 0, *keys);
418 return E_OUTOFMEMORY;
420 *(*keys)[*num] = devices[i];
422 if(*def_index == (UINT)-1 && devices[i] == default_id)
423 *def_index = *num;
425 (*num)++;
428 if(*def_index == (UINT)-1)
429 *def_index = 0;
431 HeapFree(GetProcessHeap(), 0, devices);
433 return S_OK;
436 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
437 EDataFlow dataflow, IAudioClient **out)
439 ACImpl *This;
441 TRACE("%p %d %p\n", dev, dataflow, out);
443 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
444 if(!This)
445 return E_OUTOFMEMORY;
447 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
448 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
449 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
450 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
451 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
452 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
454 This->dataflow = dataflow;
456 if(dataflow == eRender)
457 This->scope = kAudioDevicePropertyScopeOutput;
458 else if(dataflow == eCapture)
459 This->scope = kAudioDevicePropertyScopeInput;
460 else{
461 HeapFree(GetProcessHeap(), 0, This);
462 return E_INVALIDARG;
465 This->lock = 0;
467 This->parent = dev;
468 IMMDevice_AddRef(This->parent);
470 list_init(&This->avail_buffers);
472 This->adevid = *adevid;
474 *out = &This->IAudioClient_iface;
475 IAudioClient_AddRef(&This->IAudioClient_iface);
477 return S_OK;
480 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
481 REFIID riid, void **ppv)
483 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
485 if(!ppv)
486 return E_POINTER;
487 *ppv = NULL;
488 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
489 *ppv = iface;
490 if(*ppv){
491 IUnknown_AddRef((IUnknown*)*ppv);
492 return S_OK;
494 WARN("Unknown interface %s\n", debugstr_guid(riid));
495 return E_NOINTERFACE;
498 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
500 ACImpl *This = impl_from_IAudioClient(iface);
501 ULONG ref;
502 ref = InterlockedIncrement(&This->ref);
503 TRACE("(%p) Refcount now %u\n", This, ref);
504 return ref;
507 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
509 ACImpl *This = impl_from_IAudioClient(iface);
510 ULONG ref;
511 ref = InterlockedDecrement(&This->ref);
512 TRACE("(%p) Refcount now %u\n", This, ref);
513 if(!ref){
514 IAudioClient_Stop(iface);
515 if(This->aqueue)
516 AudioQueueDispose(This->aqueue, 1);
517 if(This->session){
518 EnterCriticalSection(&g_sessions_lock);
519 list_remove(&This->entry);
520 LeaveCriticalSection(&g_sessions_lock);
522 HeapFree(GetProcessHeap(), 0, This->vols);
523 HeapFree(GetProcessHeap(), 0, This->public_buffer);
524 CoTaskMemFree(This->fmt);
525 IMMDevice_Release(This->parent);
526 HeapFree(GetProcessHeap(), 0, This);
528 return ref;
531 static void dump_fmt(const WAVEFORMATEX *fmt)
533 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
534 switch(fmt->wFormatTag){
535 case WAVE_FORMAT_PCM:
536 TRACE("WAVE_FORMAT_PCM");
537 break;
538 case WAVE_FORMAT_IEEE_FLOAT:
539 TRACE("WAVE_FORMAT_IEEE_FLOAT");
540 break;
541 case WAVE_FORMAT_EXTENSIBLE:
542 TRACE("WAVE_FORMAT_EXTENSIBLE");
543 break;
544 default:
545 TRACE("Unknown");
546 break;
548 TRACE(")\n");
550 TRACE("nChannels: %u\n", fmt->nChannels);
551 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
552 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
553 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
554 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
555 TRACE("cbSize: %u\n", fmt->cbSize);
557 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
558 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
559 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
560 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
561 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
565 static DWORD get_channel_mask(unsigned int channels)
567 switch(channels){
568 case 0:
569 return 0;
570 case 1:
571 return SPEAKER_FRONT_CENTER;
572 case 2:
573 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
574 case 3:
575 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
576 SPEAKER_LOW_FREQUENCY;
577 case 4:
578 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
579 SPEAKER_BACK_RIGHT;
580 case 5:
581 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
582 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
583 case 6:
584 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
585 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
586 case 7:
587 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
588 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
589 SPEAKER_BACK_CENTER;
591 FIXME("Unknown speaker configuration: %u\n", channels);
592 return 0;
595 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
597 WAVEFORMATEX *ret;
598 size_t size;
600 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
601 size = sizeof(WAVEFORMATEXTENSIBLE);
602 else
603 size = sizeof(WAVEFORMATEX);
605 ret = CoTaskMemAlloc(size);
606 if(!ret)
607 return NULL;
609 memcpy(ret, fmt, size);
611 ret->cbSize = size - sizeof(WAVEFORMATEX);
613 return ret;
616 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
617 const WAVEFORMATEX *fmt)
619 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
621 desc->mFormatFlags = 0;
623 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
624 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
625 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
626 desc->mFormatID = kAudioFormatLinearPCM;
627 if(fmt->wBitsPerSample > 8)
628 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
629 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
630 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
631 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
632 desc->mFormatID = kAudioFormatLinearPCM;
633 desc->mFormatFlags = kAudioFormatFlagIsFloat;
634 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
635 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
636 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
637 desc->mFormatID = kAudioFormatULaw;
638 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
639 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
640 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
641 desc->mFormatID = kAudioFormatALaw;
642 }else
643 return AUDCLNT_E_UNSUPPORTED_FORMAT;
645 desc->mSampleRate = fmt->nSamplesPerSec;
646 desc->mBytesPerPacket = fmt->nBlockAlign;
647 desc->mFramesPerPacket = 1;
648 desc->mBytesPerFrame = fmt->nBlockAlign;
649 desc->mChannelsPerFrame = fmt->nChannels;
650 desc->mBitsPerChannel = fmt->wBitsPerSample;
651 desc->mReserved = 0;
653 return S_OK;
656 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
657 AudioQueueBufferRef buffer)
659 ACImpl *This = user;
660 AQBuffer *buf = buffer->mUserData;
662 OSSpinLockLock(&This->lock);
663 list_add_tail(&This->avail_buffers, &buf->entry);
664 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
665 OSSpinLockUnlock(&This->lock);
668 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
669 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
670 UInt32 ndesc, const AudioStreamPacketDescription *descs)
672 ACImpl *This = user;
673 AQBuffer *buf = buffer->mUserData;
675 OSSpinLockLock(&This->lock);
676 list_add_tail(&This->avail_buffers, &buf->entry);
677 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
678 OSSpinLockUnlock(&This->lock);
681 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
682 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
684 AudioStreamBasicDescription desc;
685 AudioObjectPropertyAddress addr;
686 CFStringRef uid;
687 OSStatus sc;
688 HRESULT hr;
689 UInt32 size;
691 addr.mScope = kAudioObjectPropertyScopeGlobal;
692 addr.mElement = 0;
693 addr.mSelector = kAudioDevicePropertyDeviceUID;
695 size = sizeof(uid);
696 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
697 if(sc != noErr){
698 WARN("Unable to get _DeviceUID property: %lx\n", sc);
699 return E_FAIL;
702 hr = ca_get_audiodesc(&desc, fmt);
703 if(FAILED(hr)){
704 CFRelease(uid);
705 return hr;
708 if(flow == eRender)
709 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
710 aqueue);
711 else if(flow == eCapture)
712 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
713 aqueue);
714 else{
715 CFRelease(uid);
716 return E_UNEXPECTED;
718 if(sc != noErr){
719 WARN("Unable to create AudioQueue: %lx\n", sc);
720 CFRelease(uid);
721 return E_FAIL;
724 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
725 &uid, sizeof(uid));
726 if(sc != noErr){
727 CFRelease(uid);
728 return E_FAIL;
731 CFRelease(uid);
733 return S_OK;
736 static void session_init_vols(AudioSession *session, UINT channels)
738 if(session->channel_count < channels){
739 UINT i;
741 if(session->channel_vols)
742 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
743 session->channel_vols, sizeof(float) * channels);
744 else
745 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
746 sizeof(float) * channels);
747 if(!session->channel_vols)
748 return;
750 for(i = session->channel_count; i < channels; ++i)
751 session->channel_vols[i] = 1.f;
753 session->channel_count = channels;
757 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
758 UINT num_channels)
760 AudioSession *ret;
762 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
763 if(!ret)
764 return NULL;
766 memcpy(&ret->guid, guid, sizeof(GUID));
768 ret->device = device;
770 list_init(&ret->clients);
772 list_add_head(&g_sessions, &ret->entry);
774 InitializeCriticalSection(&ret->lock);
776 session_init_vols(ret, num_channels);
778 ret->master_vol = 1.f;
780 return ret;
783 /* if channels == 0, then this will return or create a session with
784 * matching dataflow and GUID. otherwise, channels must also match */
785 static HRESULT get_audio_session(const GUID *sessionguid,
786 IMMDevice *device, UINT channels, AudioSession **out)
788 AudioSession *session;
790 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
791 *out = create_session(&GUID_NULL, device, channels);
792 if(!*out)
793 return E_OUTOFMEMORY;
795 return S_OK;
798 *out = NULL;
799 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
800 if(session->device == device &&
801 IsEqualGUID(sessionguid, &session->guid)){
802 session_init_vols(session, channels);
803 *out = session;
804 break;
808 if(!*out){
809 *out = create_session(sessionguid, device, channels);
810 if(!*out)
811 return E_OUTOFMEMORY;
814 return S_OK;
817 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
818 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
819 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
820 const GUID *sessionguid)
822 ACImpl *This = impl_from_IAudioClient(iface);
823 HRESULT hr;
824 OSStatus sc;
825 int i;
827 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
828 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
830 if(!fmt)
831 return E_POINTER;
833 dump_fmt(fmt);
835 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
836 return AUDCLNT_E_NOT_INITIALIZED;
838 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
839 AUDCLNT_STREAMFLAGS_LOOPBACK |
840 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
841 AUDCLNT_STREAMFLAGS_NOPERSIST |
842 AUDCLNT_STREAMFLAGS_RATEADJUST |
843 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
844 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
845 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
846 TRACE("Unknown flags: %08x\n", flags);
847 return E_INVALIDARG;
850 OSSpinLockLock(&This->lock);
852 if(This->aqueue){
853 OSSpinLockUnlock(&This->lock);
854 return AUDCLNT_E_ALREADY_INITIALIZED;
857 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
858 if(FAILED(hr)){
859 OSSpinLockUnlock(&This->lock);
860 return hr;
863 This->fmt = clone_format(fmt);
864 if(!This->fmt){
865 AudioQueueDispose(This->aqueue, 1);
866 This->aqueue = NULL;
867 OSSpinLockUnlock(&This->lock);
868 return E_OUTOFMEMORY;
871 if(period){
872 This->period_ms = period / 10000;
873 if(This->period_ms == 0)
874 This->period_ms = 1;
875 }else
876 This->period_ms = MinimumPeriod / 10000;
878 if(!duration)
879 duration = 300000; /* 0.03s */
880 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
882 if(This->dataflow == eCapture){
883 int i;
884 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
885 This->fmt->nBlockAlign);
886 for(i = 0; i < CAPTURE_BUFFERS; ++i){
887 AQBuffer *buf;
889 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
890 if(!buf){
891 AudioQueueDispose(This->aqueue, 1);
892 This->aqueue = NULL;
893 CoTaskMemFree(This->fmt);
894 This->fmt = NULL;
895 OSSpinLockUnlock(&This->lock);
896 return E_OUTOFMEMORY;
899 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
900 if(sc != noErr){
901 AudioQueueDispose(This->aqueue, 1);
902 This->aqueue = NULL;
903 CoTaskMemFree(This->fmt);
904 This->fmt = NULL;
905 OSSpinLockUnlock(&This->lock);
906 WARN("Couldn't allocate buffer: %lx\n", sc);
907 return E_FAIL;
910 buf->buf->mUserData = buf;
912 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
913 if(sc != noErr){
914 ERR("Couldn't enqueue buffer: %lx\n", sc);
915 break;
920 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
921 if(!This->vols){
922 AudioQueueDispose(This->aqueue, 1);
923 This->aqueue = NULL;
924 CoTaskMemFree(This->fmt);
925 This->fmt = NULL;
926 OSSpinLockUnlock(&This->lock);
927 return E_OUTOFMEMORY;
930 for(i = 0; i < fmt->nChannels; ++i)
931 This->vols[i] = 1.f;
933 This->share = mode;
934 This->flags = flags;
936 EnterCriticalSection(&g_sessions_lock);
938 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
939 &This->session);
940 if(FAILED(hr)){
941 LeaveCriticalSection(&g_sessions_lock);
942 AudioQueueDispose(This->aqueue, 1);
943 This->aqueue = NULL;
944 CoTaskMemFree(This->fmt);
945 This->fmt = NULL;
946 HeapFree(GetProcessHeap(), 0, This->vols);
947 This->vols = NULL;
948 OSSpinLockUnlock(&This->lock);
949 return E_INVALIDARG;
952 list_add_tail(&This->session->clients, &This->entry);
954 LeaveCriticalSection(&g_sessions_lock);
956 ca_setvol(This, -1);
958 OSSpinLockUnlock(&This->lock);
960 return S_OK;
963 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
964 UINT32 *frames)
966 ACImpl *This = impl_from_IAudioClient(iface);
968 TRACE("(%p)->(%p)\n", This, frames);
970 if(!frames)
971 return E_POINTER;
973 OSSpinLockLock(&This->lock);
975 if(!This->aqueue){
976 OSSpinLockUnlock(&This->lock);
977 return AUDCLNT_E_NOT_INITIALIZED;
980 *frames = This->bufsize_frames;
982 OSSpinLockUnlock(&This->lock);
984 return S_OK;
987 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
989 AudioObjectPropertyAddress addr;
990 AudioStreamID *ids;
991 UInt32 size;
992 OSStatus sc;
993 int nstreams, i;
995 addr.mScope = This->scope;
996 addr.mElement = 0;
997 addr.mSelector = kAudioDevicePropertyStreams;
999 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
1000 &size);
1001 if(sc != noErr){
1002 WARN("Unable to get size for _Streams property: %lx\n", sc);
1003 return E_FAIL;
1006 ids = HeapAlloc(GetProcessHeap(), 0, size);
1007 if(!ids)
1008 return E_OUTOFMEMORY;
1010 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
1011 if(sc != noErr){
1012 WARN("Unable to get _Streams property: %lx\n", sc);
1013 HeapFree(GetProcessHeap(), 0, ids);
1014 return E_FAIL;
1017 nstreams = size / sizeof(AudioStreamID);
1018 *max = 0;
1020 addr.mSelector = kAudioStreamPropertyLatency;
1021 for(i = 0; i < nstreams; ++i){
1022 UInt32 latency;
1024 size = sizeof(latency);
1025 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1026 &size, &latency);
1027 if(sc != noErr){
1028 WARN("Unable to get _Latency property: %lx\n", sc);
1029 continue;
1032 if(latency > *max)
1033 *max = latency;
1036 HeapFree(GetProcessHeap(), 0, ids);
1038 return S_OK;
1041 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1042 REFERENCE_TIME *out)
1044 ACImpl *This = impl_from_IAudioClient(iface);
1045 UInt32 latency, stream_latency, size;
1046 AudioObjectPropertyAddress addr;
1047 OSStatus sc;
1048 HRESULT hr;
1050 TRACE("(%p)->(%p)\n", This, out);
1052 if(!out)
1053 return E_POINTER;
1055 OSSpinLockLock(&This->lock);
1057 if(!This->aqueue){
1058 OSSpinLockUnlock(&This->lock);
1059 return AUDCLNT_E_NOT_INITIALIZED;
1062 addr.mScope = This->scope;
1063 addr.mSelector = kAudioDevicePropertyLatency;
1064 addr.mElement = 0;
1066 size = sizeof(latency);
1067 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1068 &size, &latency);
1069 if(sc != noErr){
1070 WARN("Couldn't get _Latency property: %lx\n", sc);
1071 OSSpinLockUnlock(&This->lock);
1072 return E_FAIL;
1075 hr = ca_get_max_stream_latency(This, &stream_latency);
1076 if(FAILED(hr)){
1077 OSSpinLockUnlock(&This->lock);
1078 return hr;
1081 latency += stream_latency;
1082 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
1084 OSSpinLockUnlock(&This->lock);
1086 return S_OK;
1089 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1090 UINT32 *numpad)
1092 if(!This->aqueue)
1093 return AUDCLNT_E_NOT_INITIALIZED;
1095 *numpad = This->inbuf_frames;
1097 return S_OK;
1100 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1101 UINT32 *numpad)
1103 ACImpl *This = impl_from_IAudioClient(iface);
1104 HRESULT hr;
1106 TRACE("(%p)->(%p)\n", This, numpad);
1108 if(!numpad)
1109 return E_POINTER;
1111 OSSpinLockLock(&This->lock);
1113 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1115 OSSpinLockUnlock(&This->lock);
1117 return hr;
1120 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1121 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1122 WAVEFORMATEX **outpwfx)
1124 ACImpl *This = impl_from_IAudioClient(iface);
1125 AudioQueueRef aqueue;
1126 HRESULT hr;
1128 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1130 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1131 return E_POINTER;
1133 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1134 return E_INVALIDARG;
1136 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1137 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1138 return E_INVALIDARG;
1140 dump_fmt(pwfx);
1142 OSSpinLockLock(&This->lock);
1144 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1145 if(SUCCEEDED(hr)){
1146 AudioQueueDispose(aqueue, 1);
1147 OSSpinLockUnlock(&This->lock);
1148 if(outpwfx)
1149 *outpwfx = NULL;
1150 TRACE("returning %08x\n", S_OK);
1151 return S_OK;
1154 OSSpinLockUnlock(&This->lock);
1156 if(outpwfx)
1157 *outpwfx = NULL;
1159 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1160 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1163 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1164 WAVEFORMATEX **pwfx)
1166 ACImpl *This = impl_from_IAudioClient(iface);
1167 WAVEFORMATEXTENSIBLE *fmt;
1168 OSStatus sc;
1169 UInt32 size;
1170 Float64 rate;
1171 AudioBufferList *buffers;
1172 AudioObjectPropertyAddress addr;
1173 int i;
1175 TRACE("(%p)->(%p)\n", This, pwfx);
1177 if(!pwfx)
1178 return E_POINTER;
1179 *pwfx = NULL;
1181 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1182 if(!fmt)
1183 return E_OUTOFMEMORY;
1185 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1187 addr.mScope = This->scope;
1188 addr.mElement = 0;
1189 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1191 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1192 if(sc != noErr){
1193 CoTaskMemFree(fmt);
1194 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1195 return E_FAIL;
1198 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1199 if(!buffers){
1200 CoTaskMemFree(fmt);
1201 return E_OUTOFMEMORY;
1204 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1205 &size, buffers);
1206 if(sc != noErr){
1207 CoTaskMemFree(fmt);
1208 HeapFree(GetProcessHeap(), 0, buffers);
1209 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1210 return E_FAIL;
1213 fmt->Format.nChannels = 0;
1214 for(i = 0; i < buffers->mNumberBuffers; ++i)
1215 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1217 HeapFree(GetProcessHeap(), 0, buffers);
1219 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1221 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1222 size = sizeof(Float64);
1223 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1224 if(sc != noErr){
1225 CoTaskMemFree(fmt);
1226 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1227 return E_FAIL;
1229 fmt->Format.nSamplesPerSec = rate;
1231 fmt->Format.wBitsPerSample = 32;
1232 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1234 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1235 fmt->Format.nChannels) / 8;
1236 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1237 fmt->Format.nBlockAlign;
1239 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1240 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1242 *pwfx = (WAVEFORMATEX*)fmt;
1243 dump_fmt(*pwfx);
1245 return S_OK;
1248 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1249 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1251 ACImpl *This = impl_from_IAudioClient(iface);
1253 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1255 if(!defperiod && !minperiod)
1256 return E_POINTER;
1258 OSSpinLockLock(&This->lock);
1260 if(This->period_ms){
1261 if(defperiod)
1262 *defperiod = This->period_ms * 10000;
1263 if(minperiod)
1264 *minperiod = This->period_ms * 10000;
1265 }else{
1266 if(defperiod)
1267 *defperiod = DefaultPeriod;
1268 if(minperiod)
1269 *minperiod = MinimumPeriod;
1272 OSSpinLockUnlock(&This->lock);
1274 return S_OK;
1277 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1279 ACImpl *This = user;
1281 OSSpinLockLock(&This->lock);
1282 if(This->event)
1283 SetEvent(This->event);
1284 OSSpinLockUnlock(&This->lock);
1287 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1289 ACImpl *This = impl_from_IAudioClient(iface);
1290 OSStatus sc;
1292 TRACE("(%p)\n", This);
1294 OSSpinLockLock(&This->lock);
1296 if(!This->aqueue){
1297 OSSpinLockUnlock(&This->lock);
1298 return AUDCLNT_E_NOT_INITIALIZED;
1301 if(This->playing != StateStopped){
1302 OSSpinLockUnlock(&This->lock);
1303 return AUDCLNT_E_NOT_STOPPED;
1306 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1307 OSSpinLockUnlock(&This->lock);
1308 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1311 if(This->event)
1312 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1313 ca_period_cb, This, 0, This->period_ms, 0))
1314 ERR("Unable to create timer: %u\n", GetLastError());
1316 This->playing = StateInTransition;
1318 OSSpinLockUnlock(&This->lock);
1320 sc = AudioQueueStart(This->aqueue, NULL);
1321 if(sc != noErr){
1322 WARN("Unable to start audio queue: %lx\n", sc);
1323 return E_FAIL;
1326 OSSpinLockLock(&This->lock);
1328 This->playing = StatePlaying;
1330 OSSpinLockUnlock(&This->lock);
1332 return S_OK;
1335 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1337 ACImpl *This = impl_from_IAudioClient(iface);
1338 OSStatus sc;
1340 TRACE("(%p)\n", This);
1342 OSSpinLockLock(&This->lock);
1344 if(!This->aqueue){
1345 OSSpinLockUnlock(&This->lock);
1346 return AUDCLNT_E_NOT_INITIALIZED;
1349 if(This->playing == StateStopped){
1350 OSSpinLockUnlock(&This->lock);
1351 return S_FALSE;
1354 if(This->playing == StateInTransition){
1355 OSSpinLockUnlock(&This->lock);
1356 return S_OK;
1359 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1360 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1361 This->timer = NULL;
1364 This->playing = StateInTransition;
1366 OSSpinLockUnlock(&This->lock);
1368 sc = AudioQueueFlush(This->aqueue);
1369 if(sc != noErr)
1370 WARN("Unable to flush audio queue: %lx\n", sc);
1372 sc = AudioQueuePause(This->aqueue);
1373 if(sc != noErr){
1374 WARN("Unable to pause audio queue: %lx\n", sc);
1375 return E_FAIL;
1378 OSSpinLockLock(&This->lock);
1380 This->playing = StateStopped;
1382 OSSpinLockUnlock(&This->lock);
1384 return S_OK;
1387 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1389 ACImpl *This = impl_from_IAudioClient(iface);
1390 HRESULT hr;
1391 OSStatus sc;
1393 TRACE("(%p)\n", This);
1395 OSSpinLockLock(&This->lock);
1397 if(!This->aqueue){
1398 OSSpinLockUnlock(&This->lock);
1399 return AUDCLNT_E_NOT_INITIALIZED;
1402 if(This->playing != StateStopped){
1403 OSSpinLockUnlock(&This->lock);
1404 return AUDCLNT_E_NOT_STOPPED;
1407 if(This->getbuf_last){
1408 OSSpinLockUnlock(&This->lock);
1409 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1412 This->written_frames = 0;
1414 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1415 if(FAILED(hr)){
1416 OSSpinLockUnlock(&This->lock);
1417 return hr;
1420 OSSpinLockUnlock(&This->lock);
1422 sc = AudioQueueReset(This->aqueue);
1423 if(sc != noErr){
1424 WARN("Unable to reset audio queue: %lx\n", sc);
1425 return E_FAIL;
1428 return S_OK;
1431 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1432 HANDLE event)
1434 ACImpl *This = impl_from_IAudioClient(iface);
1436 TRACE("(%p)->(%p)\n", This, event);
1438 if(!event)
1439 return E_INVALIDARG;
1441 OSSpinLockLock(&This->lock);
1443 if(!This->aqueue){
1444 OSSpinLockUnlock(&This->lock);
1445 return AUDCLNT_E_NOT_INITIALIZED;
1448 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1449 OSSpinLockUnlock(&This->lock);
1450 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1453 This->event = event;
1455 OSSpinLockUnlock(&This->lock);
1457 return S_OK;
1460 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1461 void **ppv)
1463 ACImpl *This = impl_from_IAudioClient(iface);
1465 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1467 if(!ppv)
1468 return E_POINTER;
1469 *ppv = NULL;
1471 OSSpinLockLock(&This->lock);
1473 if(!This->aqueue){
1474 OSSpinLockUnlock(&This->lock);
1475 return AUDCLNT_E_NOT_INITIALIZED;
1478 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1479 if(This->dataflow != eRender){
1480 OSSpinLockUnlock(&This->lock);
1481 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1483 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1484 *ppv = &This->IAudioRenderClient_iface;
1485 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1486 if(This->dataflow != eCapture){
1487 OSSpinLockUnlock(&This->lock);
1488 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1490 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1491 *ppv = &This->IAudioCaptureClient_iface;
1492 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1493 IAudioClock_AddRef(&This->IAudioClock_iface);
1494 *ppv = &This->IAudioClock_iface;
1495 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1496 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1497 *ppv = &This->IAudioStreamVolume_iface;
1498 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1499 if(!This->session_wrapper){
1500 This->session_wrapper = AudioSessionWrapper_Create(This);
1501 if(!This->session_wrapper){
1502 OSSpinLockUnlock(&This->lock);
1503 return E_OUTOFMEMORY;
1505 }else
1506 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1508 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1509 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1510 if(!This->session_wrapper){
1511 This->session_wrapper = AudioSessionWrapper_Create(This);
1512 if(!This->session_wrapper){
1513 OSSpinLockUnlock(&This->lock);
1514 return E_OUTOFMEMORY;
1516 }else
1517 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1519 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1520 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1521 if(!This->session_wrapper){
1522 This->session_wrapper = AudioSessionWrapper_Create(This);
1523 if(!This->session_wrapper){
1524 OSSpinLockUnlock(&This->lock);
1525 return E_OUTOFMEMORY;
1527 }else
1528 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1530 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1533 if(*ppv){
1534 OSSpinLockUnlock(&This->lock);
1535 return S_OK;
1538 OSSpinLockUnlock(&This->lock);
1540 FIXME("stub %s\n", debugstr_guid(riid));
1541 return E_NOINTERFACE;
1544 static const IAudioClientVtbl AudioClient_Vtbl =
1546 AudioClient_QueryInterface,
1547 AudioClient_AddRef,
1548 AudioClient_Release,
1549 AudioClient_Initialize,
1550 AudioClient_GetBufferSize,
1551 AudioClient_GetStreamLatency,
1552 AudioClient_GetCurrentPadding,
1553 AudioClient_IsFormatSupported,
1554 AudioClient_GetMixFormat,
1555 AudioClient_GetDevicePeriod,
1556 AudioClient_Start,
1557 AudioClient_Stop,
1558 AudioClient_Reset,
1559 AudioClient_SetEventHandle,
1560 AudioClient_GetService
1563 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1564 IAudioRenderClient *iface, REFIID riid, void **ppv)
1566 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1568 if(!ppv)
1569 return E_POINTER;
1570 *ppv = NULL;
1572 if(IsEqualIID(riid, &IID_IUnknown) ||
1573 IsEqualIID(riid, &IID_IAudioRenderClient))
1574 *ppv = iface;
1575 if(*ppv){
1576 IUnknown_AddRef((IUnknown*)*ppv);
1577 return S_OK;
1580 WARN("Unknown interface %s\n", debugstr_guid(riid));
1581 return E_NOINTERFACE;
1584 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1586 ACImpl *This = impl_from_IAudioRenderClient(iface);
1587 return AudioClient_AddRef(&This->IAudioClient_iface);
1590 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1592 ACImpl *This = impl_from_IAudioRenderClient(iface);
1593 return AudioClient_Release(&This->IAudioClient_iface);
1596 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1597 UINT32 frames, BYTE **data)
1599 ACImpl *This = impl_from_IAudioRenderClient(iface);
1600 AQBuffer *buf;
1601 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1602 HRESULT hr;
1603 OSStatus sc;
1605 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1607 if(!data)
1608 return E_POINTER;
1610 OSSpinLockLock(&This->lock);
1612 if(This->getbuf_last){
1613 OSSpinLockUnlock(&This->lock);
1614 return AUDCLNT_E_OUT_OF_ORDER;
1617 if(!frames){
1618 This->getbuf_last = TRUE;
1619 OSSpinLockUnlock(&This->lock);
1620 return S_OK;
1623 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1624 if(FAILED(hr)){
1625 OSSpinLockUnlock(&This->lock);
1626 return hr;
1629 if(pad + frames > This->bufsize_frames){
1630 OSSpinLockUnlock(&This->lock);
1631 return AUDCLNT_E_BUFFER_TOO_LARGE;
1634 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1635 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1636 This->public_buffer = buf->buf;
1637 list_remove(&buf->entry);
1638 break;
1642 if(&buf->entry == &This->avail_buffers){
1643 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1644 &This->public_buffer);
1645 if(sc != noErr){
1646 OSSpinLockUnlock(&This->lock);
1647 WARN("Unable to allocate buffer: %lx\n", sc);
1648 return E_FAIL;
1650 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1651 if(!buf){
1652 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1653 This->public_buffer = NULL;
1654 OSSpinLockUnlock(&This->lock);
1655 return E_OUTOFMEMORY;
1657 buf->buf = This->public_buffer;
1658 This->public_buffer->mUserData = buf;
1661 *data = This->public_buffer->mAudioData;
1663 This->getbuf_last = TRUE;
1665 OSSpinLockUnlock(&This->lock);
1667 return S_OK;
1670 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1671 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1673 ACImpl *This = impl_from_IAudioRenderClient(iface);
1674 OSStatus sc;
1676 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1678 OSSpinLockLock(&This->lock);
1680 if(!This->getbuf_last){
1681 OSSpinLockUnlock(&This->lock);
1682 return AUDCLNT_E_OUT_OF_ORDER;
1685 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1686 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1687 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1688 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1689 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1690 This->fmt->wBitsPerSample == 8)
1691 memset(This->public_buffer->mAudioData, 128,
1692 frames * This->fmt->nBlockAlign);
1693 else
1694 memset(This->public_buffer->mAudioData, 0,
1695 frames * This->fmt->nBlockAlign);
1698 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1700 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1701 if(sc != noErr){
1702 OSSpinLockUnlock(&This->lock);
1703 WARN("Unable to enqueue buffer: %lx\n", sc);
1704 return E_FAIL;
1707 if(This->playing == StateStopped)
1708 AudioQueuePrime(This->aqueue, 0, NULL);
1710 This->public_buffer = NULL;
1711 This->getbuf_last = FALSE;
1712 This->written_frames += frames;
1713 This->inbuf_frames += frames;
1715 OSSpinLockUnlock(&This->lock);
1717 return S_OK;
1720 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1721 AudioRenderClient_QueryInterface,
1722 AudioRenderClient_AddRef,
1723 AudioRenderClient_Release,
1724 AudioRenderClient_GetBuffer,
1725 AudioRenderClient_ReleaseBuffer
1728 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1729 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1731 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1733 if(!ppv)
1734 return E_POINTER;
1735 *ppv = NULL;
1737 if(IsEqualIID(riid, &IID_IUnknown) ||
1738 IsEqualIID(riid, &IID_IAudioCaptureClient))
1739 *ppv = iface;
1740 if(*ppv){
1741 IUnknown_AddRef((IUnknown*)*ppv);
1742 return S_OK;
1745 WARN("Unknown interface %s\n", debugstr_guid(riid));
1746 return E_NOINTERFACE;
1749 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1751 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1752 return IAudioClient_AddRef(&This->IAudioClient_iface);
1755 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1757 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1758 return IAudioClient_Release(&This->IAudioClient_iface);
1761 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1762 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1763 UINT64 *qpcpos)
1765 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1767 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1768 devpos, qpcpos);
1770 if(!data || !frames || !flags)
1771 return E_POINTER;
1773 OSSpinLockLock(&This->lock);
1775 if(This->getbuf_last){
1776 OSSpinLockUnlock(&This->lock);
1777 return AUDCLNT_E_OUT_OF_ORDER;
1780 if(This->public_buffer){
1781 *data = This->public_buffer->mAudioData;
1782 *frames =
1783 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1784 }else{
1785 struct list *head = list_head(&This->avail_buffers);
1786 if(!head){
1787 *data = NULL;
1788 *frames = 0;
1789 }else{
1790 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1791 This->public_buffer = buf->buf;
1792 *data = This->public_buffer->mAudioData;
1793 *frames =
1794 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1795 list_remove(&buf->entry);
1799 *flags = 0;
1800 This->written_frames += *frames;
1801 This->inbuf_frames -= *frames;
1802 This->getbuf_last = TRUE;
1804 if(devpos || qpcpos)
1805 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1807 OSSpinLockUnlock(&This->lock);
1809 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1812 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1813 IAudioCaptureClient *iface, UINT32 done)
1815 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1816 UINT32 pbuf_frames =
1817 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1818 OSStatus sc;
1820 TRACE("(%p)->(%u)\n", This, done);
1822 OSSpinLockLock(&This->lock);
1824 if(!This->getbuf_last){
1825 OSSpinLockUnlock(&This->lock);
1826 return AUDCLNT_E_OUT_OF_ORDER;
1829 if(done != 0 && done != pbuf_frames){
1830 OSSpinLockUnlock(&This->lock);
1831 return AUDCLNT_E_INVALID_SIZE;
1834 if(done){
1835 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1836 0, NULL);
1837 if(sc != noErr)
1838 WARN("Unable to enqueue buffer: %lx\n", sc);
1839 This->public_buffer = NULL;
1842 This->getbuf_last = FALSE;
1844 OSSpinLockUnlock(&This->lock);
1846 return S_OK;
1849 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1850 IAudioCaptureClient *iface, UINT32 *frames)
1852 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1853 struct list *head;
1854 AQBuffer *buf;
1856 TRACE("(%p)->(%p)\n", This, frames);
1858 if(!frames)
1859 return E_POINTER;
1861 OSSpinLockLock(&This->lock);
1863 head = list_head(&This->avail_buffers);
1865 if(!head){
1866 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1867 OSSpinLockUnlock(&This->lock);
1868 return S_OK;
1871 buf = LIST_ENTRY(head, AQBuffer, entry);
1872 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1874 OSSpinLockUnlock(&This->lock);
1876 return S_OK;
1879 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1881 AudioCaptureClient_QueryInterface,
1882 AudioCaptureClient_AddRef,
1883 AudioCaptureClient_Release,
1884 AudioCaptureClient_GetBuffer,
1885 AudioCaptureClient_ReleaseBuffer,
1886 AudioCaptureClient_GetNextPacketSize
1889 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1890 REFIID riid, void **ppv)
1892 ACImpl *This = impl_from_IAudioClock(iface);
1894 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1896 if(!ppv)
1897 return E_POINTER;
1898 *ppv = NULL;
1900 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1901 *ppv = iface;
1902 else if(IsEqualIID(riid, &IID_IAudioClock2))
1903 *ppv = &This->IAudioClock2_iface;
1904 if(*ppv){
1905 IUnknown_AddRef((IUnknown*)*ppv);
1906 return S_OK;
1909 WARN("Unknown interface %s\n", debugstr_guid(riid));
1910 return E_NOINTERFACE;
1913 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1915 ACImpl *This = impl_from_IAudioClock(iface);
1916 return IAudioClient_AddRef(&This->IAudioClient_iface);
1919 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1921 ACImpl *This = impl_from_IAudioClock(iface);
1922 return IAudioClient_Release(&This->IAudioClient_iface);
1925 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1927 ACImpl *This = impl_from_IAudioClock(iface);
1929 TRACE("(%p)->(%p)\n", This, freq);
1931 *freq = This->fmt->nSamplesPerSec;
1933 return S_OK;
1936 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1937 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1939 AudioTimeStamp time;
1940 OSStatus sc;
1942 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1943 if(sc == kAudioQueueErr_InvalidRunState){
1944 *pos = 0;
1945 }else if(sc == noErr){
1946 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1947 FIXME("Sample time not valid, should calculate from something else\n");
1948 return E_FAIL;
1951 if(raw)
1952 *pos = time.mSampleTime;
1953 else
1954 *pos = time.mSampleTime - This->last_time;
1955 }else{
1956 WARN("Unable to get current time: %lx\n", sc);
1957 return E_FAIL;
1960 if(qpctime){
1961 LARGE_INTEGER stamp, freq;
1962 QueryPerformanceCounter(&stamp);
1963 QueryPerformanceFrequency(&freq);
1964 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1967 return S_OK;
1970 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1971 UINT64 *qpctime)
1973 ACImpl *This = impl_from_IAudioClock(iface);
1974 HRESULT hr;
1976 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1978 if(!pos)
1979 return E_POINTER;
1981 OSSpinLockLock(&This->lock);
1983 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
1985 OSSpinLockUnlock(&This->lock);
1987 return hr;
1990 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1991 DWORD *chars)
1993 ACImpl *This = impl_from_IAudioClock(iface);
1995 TRACE("(%p)->(%p)\n", This, chars);
1997 if(!chars)
1998 return E_POINTER;
2000 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2002 return S_OK;
2005 static const IAudioClockVtbl AudioClock_Vtbl =
2007 AudioClock_QueryInterface,
2008 AudioClock_AddRef,
2009 AudioClock_Release,
2010 AudioClock_GetFrequency,
2011 AudioClock_GetPosition,
2012 AudioClock_GetCharacteristics
2015 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2016 REFIID riid, void **ppv)
2018 ACImpl *This = impl_from_IAudioClock2(iface);
2019 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2022 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2024 ACImpl *This = impl_from_IAudioClock2(iface);
2025 return IAudioClient_AddRef(&This->IAudioClient_iface);
2028 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2030 ACImpl *This = impl_from_IAudioClock2(iface);
2031 return IAudioClient_Release(&This->IAudioClient_iface);
2034 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2035 UINT64 *pos, UINT64 *qpctime)
2037 ACImpl *This = impl_from_IAudioClock2(iface);
2039 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2041 return E_NOTIMPL;
2044 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2046 AudioClock2_QueryInterface,
2047 AudioClock2_AddRef,
2048 AudioClock2_Release,
2049 AudioClock2_GetDevicePosition
2052 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2054 AudioSessionWrapper *ret;
2056 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2057 sizeof(AudioSessionWrapper));
2058 if(!ret)
2059 return NULL;
2061 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2062 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2063 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2065 ret->ref = 1;
2067 ret->client = client;
2068 if(client){
2069 ret->session = client->session;
2070 AudioClient_AddRef(&client->IAudioClient_iface);
2073 return ret;
2076 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2077 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2079 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2081 if(!ppv)
2082 return E_POINTER;
2083 *ppv = NULL;
2085 if(IsEqualIID(riid, &IID_IUnknown) ||
2086 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2087 IsEqualIID(riid, &IID_IAudioSessionControl2))
2088 *ppv = iface;
2089 if(*ppv){
2090 IUnknown_AddRef((IUnknown*)*ppv);
2091 return S_OK;
2094 WARN("Unknown interface %s\n", debugstr_guid(riid));
2095 return E_NOINTERFACE;
2098 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2100 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2101 ULONG ref;
2102 ref = InterlockedIncrement(&This->ref);
2103 TRACE("(%p) Refcount now %u\n", This, ref);
2104 return ref;
2107 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2109 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2110 ULONG ref;
2111 ref = InterlockedDecrement(&This->ref);
2112 TRACE("(%p) Refcount now %u\n", This, ref);
2113 if(!ref){
2114 if(This->client){
2115 OSSpinLockLock(&This->client->lock);
2116 This->client->session_wrapper = NULL;
2117 OSSpinLockUnlock(&This->client->lock);
2118 AudioClient_Release(&This->client->IAudioClient_iface);
2120 HeapFree(GetProcessHeap(), 0, This);
2122 return ref;
2125 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2126 AudioSessionState *state)
2128 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2129 ACImpl *client;
2131 TRACE("(%p)->(%p)\n", This, state);
2133 if(!state)
2134 return NULL_PTR_ERR;
2136 EnterCriticalSection(&g_sessions_lock);
2138 if(list_empty(&This->session->clients)){
2139 *state = AudioSessionStateExpired;
2140 LeaveCriticalSection(&g_sessions_lock);
2141 return S_OK;
2144 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2145 OSSpinLockLock(&client->lock);
2146 if(client->playing == StatePlaying ||
2147 client->playing == StateInTransition){
2148 *state = AudioSessionStateActive;
2149 OSSpinLockUnlock(&client->lock);
2150 LeaveCriticalSection(&g_sessions_lock);
2151 return S_OK;
2153 OSSpinLockUnlock(&client->lock);
2156 LeaveCriticalSection(&g_sessions_lock);
2158 *state = AudioSessionStateInactive;
2160 return S_OK;
2163 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2164 IAudioSessionControl2 *iface, WCHAR **name)
2166 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2168 FIXME("(%p)->(%p) - stub\n", This, name);
2170 return E_NOTIMPL;
2173 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2174 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2176 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2178 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2180 return E_NOTIMPL;
2183 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2184 IAudioSessionControl2 *iface, WCHAR **path)
2186 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2188 FIXME("(%p)->(%p) - stub\n", This, path);
2190 return E_NOTIMPL;
2193 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2194 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2196 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2198 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2200 return E_NOTIMPL;
2203 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2204 IAudioSessionControl2 *iface, GUID *group)
2206 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2208 FIXME("(%p)->(%p) - stub\n", This, group);
2210 return E_NOTIMPL;
2213 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2214 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2216 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2218 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2219 debugstr_guid(session));
2221 return E_NOTIMPL;
2224 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2225 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2227 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2229 FIXME("(%p)->(%p) - stub\n", This, events);
2231 return S_OK;
2234 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2235 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2237 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2239 FIXME("(%p)->(%p) - stub\n", This, events);
2241 return S_OK;
2244 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2245 IAudioSessionControl2 *iface, WCHAR **id)
2247 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2249 FIXME("(%p)->(%p) - stub\n", This, id);
2251 return E_NOTIMPL;
2254 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2255 IAudioSessionControl2 *iface, WCHAR **id)
2257 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2259 FIXME("(%p)->(%p) - stub\n", This, id);
2261 return E_NOTIMPL;
2264 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2265 IAudioSessionControl2 *iface, DWORD *pid)
2267 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2269 TRACE("(%p)->(%p)\n", This, pid);
2271 if(!pid)
2272 return E_POINTER;
2274 *pid = GetCurrentProcessId();
2276 return S_OK;
2279 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2280 IAudioSessionControl2 *iface)
2282 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2284 TRACE("(%p)\n", This);
2286 return S_FALSE;
2289 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2290 IAudioSessionControl2 *iface, BOOL optout)
2292 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2294 TRACE("(%p)->(%d)\n", This, optout);
2296 return S_OK;
2299 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2301 AudioSessionControl_QueryInterface,
2302 AudioSessionControl_AddRef,
2303 AudioSessionControl_Release,
2304 AudioSessionControl_GetState,
2305 AudioSessionControl_GetDisplayName,
2306 AudioSessionControl_SetDisplayName,
2307 AudioSessionControl_GetIconPath,
2308 AudioSessionControl_SetIconPath,
2309 AudioSessionControl_GetGroupingParam,
2310 AudioSessionControl_SetGroupingParam,
2311 AudioSessionControl_RegisterAudioSessionNotification,
2312 AudioSessionControl_UnregisterAudioSessionNotification,
2313 AudioSessionControl_GetSessionIdentifier,
2314 AudioSessionControl_GetSessionInstanceIdentifier,
2315 AudioSessionControl_GetProcessId,
2316 AudioSessionControl_IsSystemSoundsSession,
2317 AudioSessionControl_SetDuckingPreference
2320 /* index == -1 means set all channels, otherwise sets only the given channel */
2321 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2323 float level;
2324 OSStatus sc;
2326 if(index == (UINT32)-1){
2327 HRESULT ret = S_OK;
2328 UINT32 i;
2329 for(i = 0; i < This->fmt->nChannels; ++i){
2330 HRESULT hr;
2331 hr = ca_setvol(This, i);
2332 if(FAILED(hr))
2333 ret = hr;
2335 return ret;
2338 if(This->session->mute)
2339 level = 0;
2340 else
2341 level = This->session->master_vol *
2342 This->session->channel_vols[index] * This->vols[index];
2344 sc = AudioQueueSetParameter(This->aqueue, kAudioQueueParam_Volume, level);
2345 if(sc != noErr){
2346 WARN("Setting _Volume property failed: %lx\n", sc);
2347 return E_FAIL;
2350 return S_OK;
2353 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2355 HRESULT ret = S_OK;
2356 ACImpl *client;
2358 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2359 HRESULT hr;
2360 hr = ca_setvol(client, index);
2361 if(FAILED(hr))
2362 ret = hr;
2365 return ret;
2368 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2369 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2371 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2373 if(!ppv)
2374 return E_POINTER;
2375 *ppv = NULL;
2377 if(IsEqualIID(riid, &IID_IUnknown) ||
2378 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2379 *ppv = iface;
2380 if(*ppv){
2381 IUnknown_AddRef((IUnknown*)*ppv);
2382 return S_OK;
2385 WARN("Unknown interface %s\n", debugstr_guid(riid));
2386 return E_NOINTERFACE;
2389 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2391 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2392 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2395 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2397 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2398 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2401 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2402 ISimpleAudioVolume *iface, float level, const GUID *context)
2404 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2405 AudioSession *session = This->session;
2406 HRESULT ret;
2408 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2410 if(level < 0.f || level > 1.f)
2411 return E_INVALIDARG;
2413 if(context)
2414 FIXME("Notifications not supported yet\n");
2416 EnterCriticalSection(&session->lock);
2418 session->master_vol = level;
2420 ret = ca_session_setvol(session, -1);
2422 LeaveCriticalSection(&session->lock);
2424 return ret;
2427 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2428 ISimpleAudioVolume *iface, float *level)
2430 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2431 AudioSession *session = This->session;
2433 TRACE("(%p)->(%p)\n", session, level);
2435 if(!level)
2436 return NULL_PTR_ERR;
2438 *level = session->master_vol;
2440 return S_OK;
2443 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2444 BOOL mute, const GUID *context)
2446 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2447 AudioSession *session = This->session;
2449 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2451 if(context)
2452 FIXME("Notifications not supported yet\n");
2454 EnterCriticalSection(&session->lock);
2456 session->mute = mute;
2458 ca_session_setvol(session, -1);
2460 LeaveCriticalSection(&session->lock);
2462 return S_OK;
2465 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2466 BOOL *mute)
2468 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2469 AudioSession *session = This->session;
2471 TRACE("(%p)->(%p)\n", session, mute);
2473 if(!mute)
2474 return NULL_PTR_ERR;
2476 *mute = session->mute;
2478 return S_OK;
2481 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2483 SimpleAudioVolume_QueryInterface,
2484 SimpleAudioVolume_AddRef,
2485 SimpleAudioVolume_Release,
2486 SimpleAudioVolume_SetMasterVolume,
2487 SimpleAudioVolume_GetMasterVolume,
2488 SimpleAudioVolume_SetMute,
2489 SimpleAudioVolume_GetMute
2492 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2493 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2495 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2497 if(!ppv)
2498 return E_POINTER;
2499 *ppv = NULL;
2501 if(IsEqualIID(riid, &IID_IUnknown) ||
2502 IsEqualIID(riid, &IID_IAudioStreamVolume))
2503 *ppv = iface;
2504 if(*ppv){
2505 IUnknown_AddRef((IUnknown*)*ppv);
2506 return S_OK;
2509 WARN("Unknown interface %s\n", debugstr_guid(riid));
2510 return E_NOINTERFACE;
2513 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2515 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2516 return IAudioClient_AddRef(&This->IAudioClient_iface);
2519 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2521 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2522 return IAudioClient_Release(&This->IAudioClient_iface);
2525 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2526 IAudioStreamVolume *iface, UINT32 *out)
2528 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2530 TRACE("(%p)->(%p)\n", This, out);
2532 if(!out)
2533 return E_POINTER;
2535 *out = This->fmt->nChannels;
2537 return S_OK;
2540 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2541 IAudioStreamVolume *iface, UINT32 index, float level)
2543 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2544 HRESULT ret;
2546 TRACE("(%p)->(%d, %f)\n", This, index, level);
2548 if(level < 0.f || level > 1.f)
2549 return E_INVALIDARG;
2551 if(index >= This->fmt->nChannels)
2552 return E_INVALIDARG;
2554 OSSpinLockLock(&This->lock);
2556 This->vols[index] = level;
2558 WARN("AudioQueue doesn't support per-channel volume control\n");
2559 ret = ca_setvol(This, index);
2561 OSSpinLockUnlock(&This->lock);
2563 return ret;
2566 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2567 IAudioStreamVolume *iface, UINT32 index, float *level)
2569 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2571 TRACE("(%p)->(%d, %p)\n", This, index, level);
2573 if(!level)
2574 return E_POINTER;
2576 if(index >= This->fmt->nChannels)
2577 return E_INVALIDARG;
2579 *level = This->vols[index];
2581 return S_OK;
2584 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2585 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2587 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2588 int i;
2589 HRESULT ret;
2591 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2593 if(!levels)
2594 return E_POINTER;
2596 if(count != This->fmt->nChannels)
2597 return E_INVALIDARG;
2599 OSSpinLockLock(&This->lock);
2601 for(i = 0; i < count; ++i)
2602 This->vols[i] = levels[i];
2604 ret = ca_setvol(This, -1);
2606 OSSpinLockUnlock(&This->lock);
2608 return ret;
2611 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2612 IAudioStreamVolume *iface, UINT32 count, float *levels)
2614 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2615 int i;
2617 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2619 if(!levels)
2620 return E_POINTER;
2622 if(count != This->fmt->nChannels)
2623 return E_INVALIDARG;
2625 OSSpinLockLock(&This->lock);
2627 for(i = 0; i < count; ++i)
2628 levels[i] = This->vols[i];
2630 OSSpinLockUnlock(&This->lock);
2632 return S_OK;
2635 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2637 AudioStreamVolume_QueryInterface,
2638 AudioStreamVolume_AddRef,
2639 AudioStreamVolume_Release,
2640 AudioStreamVolume_GetChannelCount,
2641 AudioStreamVolume_SetChannelVolume,
2642 AudioStreamVolume_GetChannelVolume,
2643 AudioStreamVolume_SetAllVolumes,
2644 AudioStreamVolume_GetAllVolumes
2647 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2648 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2650 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2652 if(!ppv)
2653 return E_POINTER;
2654 *ppv = NULL;
2656 if(IsEqualIID(riid, &IID_IUnknown) ||
2657 IsEqualIID(riid, &IID_IChannelAudioVolume))
2658 *ppv = iface;
2659 if(*ppv){
2660 IUnknown_AddRef((IUnknown*)*ppv);
2661 return S_OK;
2664 WARN("Unknown interface %s\n", debugstr_guid(riid));
2665 return E_NOINTERFACE;
2668 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2670 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2671 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2674 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2676 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2677 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2680 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2681 IChannelAudioVolume *iface, UINT32 *out)
2683 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2684 AudioSession *session = This->session;
2686 TRACE("(%p)->(%p)\n", session, out);
2688 if(!out)
2689 return NULL_PTR_ERR;
2691 *out = session->channel_count;
2693 return S_OK;
2696 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2697 IChannelAudioVolume *iface, UINT32 index, float level,
2698 const GUID *context)
2700 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2701 AudioSession *session = This->session;
2702 HRESULT ret;
2704 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2705 wine_dbgstr_guid(context));
2707 if(level < 0.f || level > 1.f)
2708 return E_INVALIDARG;
2710 if(index >= session->channel_count)
2711 return E_INVALIDARG;
2713 if(context)
2714 FIXME("Notifications not supported yet\n");
2716 EnterCriticalSection(&session->lock);
2718 session->channel_vols[index] = level;
2720 WARN("AudioQueue doesn't support per-channel volume control\n");
2721 ret = ca_session_setvol(session, index);
2723 LeaveCriticalSection(&session->lock);
2725 return ret;
2728 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2729 IChannelAudioVolume *iface, UINT32 index, float *level)
2731 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2732 AudioSession *session = This->session;
2734 TRACE("(%p)->(%d, %p)\n", session, index, level);
2736 if(!level)
2737 return NULL_PTR_ERR;
2739 if(index >= session->channel_count)
2740 return E_INVALIDARG;
2742 *level = session->channel_vols[index];
2744 return S_OK;
2747 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2748 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2749 const GUID *context)
2751 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2752 AudioSession *session = This->session;
2753 int i;
2754 HRESULT ret;
2756 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2757 wine_dbgstr_guid(context));
2759 if(!levels)
2760 return NULL_PTR_ERR;
2762 if(count != session->channel_count)
2763 return E_INVALIDARG;
2765 if(context)
2766 FIXME("Notifications not supported yet\n");
2768 EnterCriticalSection(&session->lock);
2770 for(i = 0; i < count; ++i)
2771 session->channel_vols[i] = levels[i];
2773 ret = ca_session_setvol(session, -1);
2775 LeaveCriticalSection(&session->lock);
2777 return ret;
2780 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2781 IChannelAudioVolume *iface, UINT32 count, float *levels)
2783 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2784 AudioSession *session = This->session;
2785 int i;
2787 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2789 if(!levels)
2790 return NULL_PTR_ERR;
2792 if(count != session->channel_count)
2793 return E_INVALIDARG;
2795 for(i = 0; i < count; ++i)
2796 levels[i] = session->channel_vols[i];
2798 return S_OK;
2801 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2803 ChannelAudioVolume_QueryInterface,
2804 ChannelAudioVolume_AddRef,
2805 ChannelAudioVolume_Release,
2806 ChannelAudioVolume_GetChannelCount,
2807 ChannelAudioVolume_SetChannelVolume,
2808 ChannelAudioVolume_GetChannelVolume,
2809 ChannelAudioVolume_SetAllVolumes,
2810 ChannelAudioVolume_GetAllVolumes
2813 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2814 REFIID riid, void **ppv)
2816 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2818 if(!ppv)
2819 return E_POINTER;
2820 *ppv = NULL;
2822 if(IsEqualIID(riid, &IID_IUnknown) ||
2823 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2824 IsEqualIID(riid, &IID_IAudioSessionManager2))
2825 *ppv = iface;
2826 if(*ppv){
2827 IUnknown_AddRef((IUnknown*)*ppv);
2828 return S_OK;
2831 WARN("Unknown interface %s\n", debugstr_guid(riid));
2832 return E_NOINTERFACE;
2835 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2837 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2838 ULONG ref;
2839 ref = InterlockedIncrement(&This->ref);
2840 TRACE("(%p) Refcount now %u\n", This, ref);
2841 return ref;
2844 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2846 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2847 ULONG ref;
2848 ref = InterlockedDecrement(&This->ref);
2849 TRACE("(%p) Refcount now %u\n", This, ref);
2850 if(!ref)
2851 HeapFree(GetProcessHeap(), 0, This);
2852 return ref;
2855 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2856 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2857 IAudioSessionControl **out)
2859 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2860 AudioSession *session;
2861 AudioSessionWrapper *wrapper;
2862 HRESULT hr;
2864 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2865 flags, out);
2867 hr = get_audio_session(session_guid, This->device, 0, &session);
2868 if(FAILED(hr))
2869 return hr;
2871 wrapper = AudioSessionWrapper_Create(NULL);
2872 if(!wrapper)
2873 return E_OUTOFMEMORY;
2875 wrapper->session = session;
2877 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2879 return S_OK;
2882 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2883 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2884 ISimpleAudioVolume **out)
2886 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2887 AudioSession *session;
2888 AudioSessionWrapper *wrapper;
2889 HRESULT hr;
2891 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2892 flags, out);
2894 hr = get_audio_session(session_guid, This->device, 0, &session);
2895 if(FAILED(hr))
2896 return hr;
2898 wrapper = AudioSessionWrapper_Create(NULL);
2899 if(!wrapper)
2900 return E_OUTOFMEMORY;
2902 wrapper->session = session;
2904 *out = &wrapper->ISimpleAudioVolume_iface;
2906 return S_OK;
2909 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2910 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2912 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2913 FIXME("(%p)->(%p) - stub\n", This, out);
2914 return E_NOTIMPL;
2917 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2918 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2920 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2921 FIXME("(%p)->(%p) - stub\n", This, notification);
2922 return E_NOTIMPL;
2925 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2926 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2928 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2929 FIXME("(%p)->(%p) - stub\n", This, notification);
2930 return E_NOTIMPL;
2933 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2934 IAudioSessionManager2 *iface, const WCHAR *session_id,
2935 IAudioVolumeDuckNotification *notification)
2937 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2938 FIXME("(%p)->(%p) - stub\n", This, notification);
2939 return E_NOTIMPL;
2942 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2943 IAudioSessionManager2 *iface,
2944 IAudioVolumeDuckNotification *notification)
2946 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2947 FIXME("(%p)->(%p) - stub\n", This, notification);
2948 return E_NOTIMPL;
2951 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2953 AudioSessionManager_QueryInterface,
2954 AudioSessionManager_AddRef,
2955 AudioSessionManager_Release,
2956 AudioSessionManager_GetAudioSessionControl,
2957 AudioSessionManager_GetSimpleAudioVolume,
2958 AudioSessionManager_GetSessionEnumerator,
2959 AudioSessionManager_RegisterSessionNotification,
2960 AudioSessionManager_UnregisterSessionNotification,
2961 AudioSessionManager_RegisterDuckNotification,
2962 AudioSessionManager_UnregisterDuckNotification
2965 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2966 IAudioSessionManager2 **out)
2968 SessionMgr *This;
2970 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2971 if(!This)
2972 return E_OUTOFMEMORY;
2974 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2975 This->device = device;
2976 This->ref = 1;
2978 *out = &This->IAudioSessionManager2_iface;
2980 return S_OK;