winecoreaudio: Release buffer memory.
[wine/multimedia.git] / dlls / winecoreaudio.drv / mmdevdrv.c
blob79cf5e39ea08a7fe1c48dd8013d2ee24e76eab0a
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"
39 #include "initguid.h"
40 #include "endpointvolume.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;
128 UINT64 last_time, written_frames;
129 AudioQueueBufferRef public_buffer;
130 UINT32 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 int j;
330 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
331 if(flow == eRender)
332 addr.mScope = kAudioDevicePropertyScopeOutput;
333 else
334 addr.mScope = kAudioDevicePropertyScopeInput;
335 addr.mElement = 0;
336 sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
337 if(sc != noErr){
338 WARN("Unable to get _StreamConfiguration property size for "
339 "device %lu: %lx\n", devices[i], sc);
340 continue;
343 buffers = HeapAlloc(GetProcessHeap(), 0, size);
344 if(!buffers){
345 HeapFree(GetProcessHeap(), 0, devices);
346 for(j = 0; j < *num; ++j){
347 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
348 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
350 HeapFree(GetProcessHeap(), 0, *keys);
351 HeapFree(GetProcessHeap(), 0, *ids);
352 return E_OUTOFMEMORY;
355 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
356 &size, buffers);
357 if(sc != noErr){
358 WARN("Unable to get _StreamConfiguration property for "
359 "device %lu: %lx\n", devices[i], sc);
360 HeapFree(GetProcessHeap(), 0, buffers);
361 continue;
364 /* check that there's at least one channel in this device before
365 * we claim it as usable */
366 for(j = 0; j < buffers->mNumberBuffers; ++j)
367 if(buffers->mBuffers[j].mNumberChannels > 0)
368 break;
369 if(j >= buffers->mNumberBuffers){
370 HeapFree(GetProcessHeap(), 0, buffers);
371 continue;
374 HeapFree(GetProcessHeap(), 0, buffers);
376 size = sizeof(name);
377 addr.mSelector = kAudioObjectPropertyName;
378 sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
379 &size, &name);
380 if(sc != noErr){
381 WARN("Unable to get _Name property for device %lu: %lx\n",
382 devices[i], sc);
383 continue;
386 len = CFStringGetLength(name) + 1;
387 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
388 if(!(*ids)[*num]){
389 CFRelease(name);
390 HeapFree(GetProcessHeap(), 0, devices);
391 for(j = 0; j < *num; ++j){
392 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
393 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
395 HeapFree(GetProcessHeap(), 0, *ids);
396 HeapFree(GetProcessHeap(), 0, *keys);
397 return E_OUTOFMEMORY;
399 CFStringGetCharacters(name, CFRangeMake(0, len - 1), (UniChar*)(*ids)[*num]);
400 ((*ids)[*num])[len - 1] = 0;
401 CFRelease(name);
403 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0, sizeof(AudioDeviceID));
404 if(!(*keys)[*num]){
405 HeapFree(GetProcessHeap(), 0, devices);
406 HeapFree(GetProcessHeap(), 0, (*ids)[*num]);
407 for(j = 0; j < *num; ++j){
408 HeapFree(GetProcessHeap(), 0, (*ids)[j]);
409 HeapFree(GetProcessHeap(), 0, (*keys)[j]);
411 HeapFree(GetProcessHeap(), 0, *ids);
412 HeapFree(GetProcessHeap(), 0, *keys);
413 return E_OUTOFMEMORY;
415 *(*keys)[*num] = devices[i];
417 if(*def_index == (UINT)-1 && devices[i] == default_id)
418 *def_index = *num;
420 TRACE("device %u: id %s key %u%s\n", *num, debugstr_w((*ids)[*num]),
421 (unsigned int)*(*keys)[*num], (*def_index == *num) ? " (default)" : "");
423 (*num)++;
426 if(*def_index == (UINT)-1)
427 *def_index = 0;
429 HeapFree(GetProcessHeap(), 0, devices);
431 return S_OK;
434 HRESULT WINAPI AUDDRV_GetAudioEndpoint(AudioDeviceID *adevid, IMMDevice *dev,
435 EDataFlow dataflow, IAudioClient **out)
437 ACImpl *This;
439 TRACE("%u %p %d %p\n", (unsigned int)*adevid, dev, dataflow, out);
441 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
442 if(!This)
443 return E_OUTOFMEMORY;
445 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
446 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
447 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
448 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
449 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
450 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
452 This->dataflow = dataflow;
454 if(dataflow == eRender)
455 This->scope = kAudioDevicePropertyScopeOutput;
456 else if(dataflow == eCapture)
457 This->scope = kAudioDevicePropertyScopeInput;
458 else{
459 HeapFree(GetProcessHeap(), 0, This);
460 return E_INVALIDARG;
463 This->lock = 0;
465 This->parent = dev;
466 IMMDevice_AddRef(This->parent);
468 list_init(&This->avail_buffers);
470 This->adevid = *adevid;
472 *out = &This->IAudioClient_iface;
473 IAudioClient_AddRef(&This->IAudioClient_iface);
475 return S_OK;
478 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
479 REFIID riid, void **ppv)
481 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
483 if(!ppv)
484 return E_POINTER;
485 *ppv = NULL;
486 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
487 *ppv = iface;
488 if(*ppv){
489 IUnknown_AddRef((IUnknown*)*ppv);
490 return S_OK;
492 WARN("Unknown interface %s\n", debugstr_guid(riid));
493 return E_NOINTERFACE;
496 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
498 ACImpl *This = impl_from_IAudioClient(iface);
499 ULONG ref;
500 ref = InterlockedIncrement(&This->ref);
501 TRACE("(%p) Refcount now %u\n", This, ref);
502 return ref;
505 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
507 ACImpl *This = impl_from_IAudioClient(iface);
508 ULONG ref;
509 ref = InterlockedDecrement(&This->ref);
510 TRACE("(%p) Refcount now %u\n", This, ref);
511 if(!ref){
512 if(This->aqueue){
513 AQBuffer *buf, *next;
514 if(This->public_buffer){
515 buf = This->public_buffer->mUserData;
516 list_add_tail(&This->avail_buffers, &buf->entry);
518 IAudioClient_Stop(iface);
519 AudioQueueStop(This->aqueue, 1);
520 /* Stopped synchronously, all buffers returned. */
521 LIST_FOR_EACH_ENTRY_SAFE(buf, next, &This->avail_buffers, AQBuffer, entry){
522 AudioQueueFreeBuffer(This->aqueue, buf->buf);
523 HeapFree(GetProcessHeap(), 0, buf);
525 AudioQueueDispose(This->aqueue, 1);
527 if(This->session){
528 EnterCriticalSection(&g_sessions_lock);
529 list_remove(&This->entry);
530 LeaveCriticalSection(&g_sessions_lock);
532 HeapFree(GetProcessHeap(), 0, This->vols);
533 CoTaskMemFree(This->fmt);
534 IMMDevice_Release(This->parent);
535 HeapFree(GetProcessHeap(), 0, This);
537 return ref;
540 static void dump_fmt(const WAVEFORMATEX *fmt)
542 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
543 switch(fmt->wFormatTag){
544 case WAVE_FORMAT_PCM:
545 TRACE("WAVE_FORMAT_PCM");
546 break;
547 case WAVE_FORMAT_IEEE_FLOAT:
548 TRACE("WAVE_FORMAT_IEEE_FLOAT");
549 break;
550 case WAVE_FORMAT_EXTENSIBLE:
551 TRACE("WAVE_FORMAT_EXTENSIBLE");
552 break;
553 default:
554 TRACE("Unknown");
555 break;
557 TRACE(")\n");
559 TRACE("nChannels: %u\n", fmt->nChannels);
560 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
561 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
562 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
563 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
564 TRACE("cbSize: %u\n", fmt->cbSize);
566 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
567 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
568 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
569 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
570 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
574 static DWORD get_channel_mask(unsigned int channels)
576 switch(channels){
577 case 0:
578 return 0;
579 case 1:
580 return KSAUDIO_SPEAKER_MONO;
581 case 2:
582 return KSAUDIO_SPEAKER_STEREO;
583 case 3:
584 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
585 case 4:
586 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
587 case 5:
588 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
589 case 6:
590 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
591 case 7:
592 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
593 case 8:
594 return KSAUDIO_SPEAKER_7POINT1; /* not 7POINT1_SURROUND */
596 FIXME("Unknown speaker configuration: %u\n", channels);
597 return 0;
600 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
602 WAVEFORMATEX *ret;
603 size_t size;
605 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
606 size = sizeof(WAVEFORMATEXTENSIBLE);
607 else
608 size = sizeof(WAVEFORMATEX);
610 ret = CoTaskMemAlloc(size);
611 if(!ret)
612 return NULL;
614 memcpy(ret, fmt, size);
616 ret->cbSize = size - sizeof(WAVEFORMATEX);
618 return ret;
621 static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc,
622 const WAVEFORMATEX *fmt)
624 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
626 desc->mFormatFlags = 0;
628 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
629 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
630 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
631 desc->mFormatID = kAudioFormatLinearPCM;
632 if(fmt->wBitsPerSample > 8)
633 desc->mFormatFlags = kAudioFormatFlagIsSignedInteger;
634 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
635 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
636 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
637 desc->mFormatID = kAudioFormatLinearPCM;
638 desc->mFormatFlags = kAudioFormatFlagIsFloat;
639 }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW ||
640 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
641 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){
642 desc->mFormatID = kAudioFormatULaw;
643 }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW ||
644 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
645 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){
646 desc->mFormatID = kAudioFormatALaw;
647 }else
648 return AUDCLNT_E_UNSUPPORTED_FORMAT;
650 desc->mSampleRate = fmt->nSamplesPerSec;
651 desc->mBytesPerPacket = fmt->nBlockAlign;
652 desc->mFramesPerPacket = 1;
653 desc->mBytesPerFrame = fmt->nBlockAlign;
654 desc->mChannelsPerFrame = fmt->nChannels;
655 desc->mBitsPerChannel = fmt->wBitsPerSample;
656 desc->mReserved = 0;
658 return S_OK;
661 static void ca_out_buffer_cb(void *user, AudioQueueRef aqueue,
662 AudioQueueBufferRef buffer)
664 ACImpl *This = user;
665 AQBuffer *buf = buffer->mUserData;
667 OSSpinLockLock(&This->lock);
668 list_add_tail(&This->avail_buffers, &buf->entry);
669 This->inbuf_frames -= buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
670 OSSpinLockUnlock(&This->lock);
673 static void ca_in_buffer_cb(void *user, AudioQueueRef aqueue,
674 AudioQueueBufferRef buffer, const AudioTimeStamp *start,
675 UInt32 ndesc, const AudioStreamPacketDescription *descs)
677 ACImpl *This = user;
678 AQBuffer *buf = buffer->mUserData;
680 OSSpinLockLock(&This->lock);
681 list_add_tail(&This->avail_buffers, &buf->entry);
682 This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
683 OSSpinLockUnlock(&This->lock);
686 static HRESULT ca_setup_aqueue(AudioDeviceID did, EDataFlow flow,
687 const WAVEFORMATEX *fmt, void *user, AudioQueueRef *aqueue)
689 AudioStreamBasicDescription desc;
690 AudioObjectPropertyAddress addr;
691 CFStringRef uid;
692 OSStatus sc;
693 HRESULT hr;
694 UInt32 size;
696 addr.mScope = kAudioObjectPropertyScopeGlobal;
697 addr.mElement = 0;
698 addr.mSelector = kAudioDevicePropertyDeviceUID;
700 size = sizeof(uid);
701 sc = AudioObjectGetPropertyData(did, &addr, 0, NULL, &size, &uid);
702 if(sc != noErr){
703 WARN("Unable to get _DeviceUID property: %lx\n", sc);
704 return E_FAIL;
707 hr = ca_get_audiodesc(&desc, fmt);
708 if(FAILED(hr)){
709 CFRelease(uid);
710 return hr;
713 if(flow == eRender)
714 sc = AudioQueueNewOutput(&desc, ca_out_buffer_cb, user, NULL, NULL, 0,
715 aqueue);
716 else if(flow == eCapture)
717 sc = AudioQueueNewInput(&desc, ca_in_buffer_cb, user, NULL, NULL, 0,
718 aqueue);
719 else{
720 CFRelease(uid);
721 return E_UNEXPECTED;
723 if(sc != noErr){
724 WARN("Unable to create AudioQueue: %lx\n", sc);
725 CFRelease(uid);
726 return E_FAIL;
729 sc = AudioQueueSetProperty(*aqueue, kAudioQueueProperty_CurrentDevice,
730 &uid, sizeof(uid));
731 if(sc != noErr){
732 CFRelease(uid);
733 return E_FAIL;
736 CFRelease(uid);
738 return S_OK;
741 static void session_init_vols(AudioSession *session, UINT channels)
743 if(session->channel_count < channels){
744 UINT i;
746 if(session->channel_vols)
747 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
748 session->channel_vols, sizeof(float) * channels);
749 else
750 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
751 sizeof(float) * channels);
752 if(!session->channel_vols)
753 return;
755 for(i = session->channel_count; i < channels; ++i)
756 session->channel_vols[i] = 1.f;
758 session->channel_count = channels;
762 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
763 UINT num_channels)
765 AudioSession *ret;
767 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
768 if(!ret)
769 return NULL;
771 memcpy(&ret->guid, guid, sizeof(GUID));
773 ret->device = device;
775 list_init(&ret->clients);
777 list_add_head(&g_sessions, &ret->entry);
779 InitializeCriticalSection(&ret->lock);
781 session_init_vols(ret, num_channels);
783 ret->master_vol = 1.f;
785 return ret;
788 /* if channels == 0, then this will return or create a session with
789 * matching dataflow and GUID. otherwise, channels must also match */
790 static HRESULT get_audio_session(const GUID *sessionguid,
791 IMMDevice *device, UINT channels, AudioSession **out)
793 AudioSession *session;
795 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
796 *out = create_session(&GUID_NULL, device, channels);
797 if(!*out)
798 return E_OUTOFMEMORY;
800 return S_OK;
803 *out = NULL;
804 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
805 if(session->device == device &&
806 IsEqualGUID(sessionguid, &session->guid)){
807 session_init_vols(session, channels);
808 *out = session;
809 break;
813 if(!*out){
814 *out = create_session(sessionguid, device, channels);
815 if(!*out)
816 return E_OUTOFMEMORY;
819 return S_OK;
822 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
823 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
824 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
825 const GUID *sessionguid)
827 ACImpl *This = impl_from_IAudioClient(iface);
828 HRESULT hr;
829 OSStatus sc;
830 int i;
832 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
833 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
835 if(!fmt)
836 return E_POINTER;
838 dump_fmt(fmt);
840 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
841 return AUDCLNT_E_NOT_INITIALIZED;
843 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
844 AUDCLNT_STREAMFLAGS_LOOPBACK |
845 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
846 AUDCLNT_STREAMFLAGS_NOPERSIST |
847 AUDCLNT_STREAMFLAGS_RATEADJUST |
848 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
849 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
850 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
851 TRACE("Unknown flags: %08x\n", flags);
852 return E_INVALIDARG;
855 OSSpinLockLock(&This->lock);
857 if(This->aqueue){
858 OSSpinLockUnlock(&This->lock);
859 return AUDCLNT_E_ALREADY_INITIALIZED;
862 hr = ca_setup_aqueue(This->adevid, This->dataflow, fmt, This, &This->aqueue);
863 if(FAILED(hr)){
864 OSSpinLockUnlock(&This->lock);
865 return hr;
868 This->fmt = clone_format(fmt);
869 if(!This->fmt){
870 AudioQueueDispose(This->aqueue, 1);
871 This->aqueue = NULL;
872 OSSpinLockUnlock(&This->lock);
873 return E_OUTOFMEMORY;
876 if(period){
877 This->period_ms = period / 10000;
878 if(This->period_ms == 0)
879 This->period_ms = 1;
880 }else
881 This->period_ms = MinimumPeriod / 10000;
883 if(!duration)
884 duration = 300000; /* 0.03s */
885 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
887 if(This->dataflow == eCapture){
888 int i;
889 UInt32 bsize = ceil((This->bufsize_frames / (double)CAPTURE_BUFFERS) *
890 This->fmt->nBlockAlign);
891 for(i = 0; i < CAPTURE_BUFFERS; ++i){
892 AQBuffer *buf;
894 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
895 if(!buf){
896 AudioQueueDispose(This->aqueue, 1);
897 This->aqueue = NULL;
898 CoTaskMemFree(This->fmt);
899 This->fmt = NULL;
900 OSSpinLockUnlock(&This->lock);
901 return E_OUTOFMEMORY;
904 sc = AudioQueueAllocateBuffer(This->aqueue, bsize, &buf->buf);
905 if(sc != noErr){
906 AudioQueueDispose(This->aqueue, 1);
907 This->aqueue = NULL;
908 CoTaskMemFree(This->fmt);
909 This->fmt = NULL;
910 OSSpinLockUnlock(&This->lock);
911 WARN("Couldn't allocate buffer: %lx\n", sc);
912 return E_FAIL;
915 buf->buf->mUserData = buf;
917 sc = AudioQueueEnqueueBuffer(This->aqueue, buf->buf, 0, NULL);
918 if(sc != noErr){
919 ERR("Couldn't enqueue buffer: %lx\n", sc);
920 break;
925 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
926 if(!This->vols){
927 AudioQueueDispose(This->aqueue, 1);
928 This->aqueue = NULL;
929 CoTaskMemFree(This->fmt);
930 This->fmt = NULL;
931 OSSpinLockUnlock(&This->lock);
932 return E_OUTOFMEMORY;
935 for(i = 0; i < fmt->nChannels; ++i)
936 This->vols[i] = 1.f;
938 This->share = mode;
939 This->flags = flags;
941 EnterCriticalSection(&g_sessions_lock);
943 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
944 &This->session);
945 if(FAILED(hr)){
946 LeaveCriticalSection(&g_sessions_lock);
947 AudioQueueDispose(This->aqueue, 1);
948 This->aqueue = NULL;
949 CoTaskMemFree(This->fmt);
950 This->fmt = NULL;
951 HeapFree(GetProcessHeap(), 0, This->vols);
952 This->vols = NULL;
953 OSSpinLockUnlock(&This->lock);
954 return E_INVALIDARG;
957 list_add_tail(&This->session->clients, &This->entry);
959 LeaveCriticalSection(&g_sessions_lock);
961 ca_setvol(This, -1);
963 OSSpinLockUnlock(&This->lock);
965 return S_OK;
968 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
969 UINT32 *frames)
971 ACImpl *This = impl_from_IAudioClient(iface);
973 TRACE("(%p)->(%p)\n", This, frames);
975 if(!frames)
976 return E_POINTER;
978 OSSpinLockLock(&This->lock);
980 if(!This->aqueue){
981 OSSpinLockUnlock(&This->lock);
982 return AUDCLNT_E_NOT_INITIALIZED;
985 *frames = This->bufsize_frames;
987 OSSpinLockUnlock(&This->lock);
989 return S_OK;
992 static HRESULT ca_get_max_stream_latency(ACImpl *This, UInt32 *max)
994 AudioObjectPropertyAddress addr;
995 AudioStreamID *ids;
996 UInt32 size;
997 OSStatus sc;
998 int nstreams, i;
1000 addr.mScope = This->scope;
1001 addr.mElement = 0;
1002 addr.mSelector = kAudioDevicePropertyStreams;
1004 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL,
1005 &size);
1006 if(sc != noErr){
1007 WARN("Unable to get size for _Streams property: %lx\n", sc);
1008 return E_FAIL;
1011 ids = HeapAlloc(GetProcessHeap(), 0, size);
1012 if(!ids)
1013 return E_OUTOFMEMORY;
1015 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, ids);
1016 if(sc != noErr){
1017 WARN("Unable to get _Streams property: %lx\n", sc);
1018 HeapFree(GetProcessHeap(), 0, ids);
1019 return E_FAIL;
1022 nstreams = size / sizeof(AudioStreamID);
1023 *max = 0;
1025 addr.mSelector = kAudioStreamPropertyLatency;
1026 for(i = 0; i < nstreams; ++i){
1027 UInt32 latency;
1029 size = sizeof(latency);
1030 sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL,
1031 &size, &latency);
1032 if(sc != noErr){
1033 WARN("Unable to get _Latency property: %lx\n", sc);
1034 continue;
1037 if(latency > *max)
1038 *max = latency;
1041 HeapFree(GetProcessHeap(), 0, ids);
1043 return S_OK;
1046 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1047 REFERENCE_TIME *out)
1049 ACImpl *This = impl_from_IAudioClient(iface);
1050 UInt32 latency, stream_latency, size;
1051 AudioObjectPropertyAddress addr;
1052 OSStatus sc;
1053 HRESULT hr;
1055 TRACE("(%p)->(%p)\n", This, out);
1057 if(!out)
1058 return E_POINTER;
1060 OSSpinLockLock(&This->lock);
1062 if(!This->aqueue){
1063 OSSpinLockUnlock(&This->lock);
1064 return AUDCLNT_E_NOT_INITIALIZED;
1067 addr.mScope = This->scope;
1068 addr.mSelector = kAudioDevicePropertyLatency;
1069 addr.mElement = 0;
1071 size = sizeof(latency);
1072 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1073 &size, &latency);
1074 if(sc != noErr){
1075 WARN("Couldn't get _Latency property: %lx\n", sc);
1076 OSSpinLockUnlock(&This->lock);
1077 return E_FAIL;
1080 hr = ca_get_max_stream_latency(This, &stream_latency);
1081 if(FAILED(hr)){
1082 OSSpinLockUnlock(&This->lock);
1083 return hr;
1086 latency += stream_latency;
1087 *out = (latency / (double)This->fmt->nSamplesPerSec) * 10000000;
1089 OSSpinLockUnlock(&This->lock);
1091 return S_OK;
1094 static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
1095 UINT32 *numpad)
1097 if(!This->aqueue)
1098 return AUDCLNT_E_NOT_INITIALIZED;
1100 *numpad = This->inbuf_frames;
1102 return S_OK;
1105 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1106 UINT32 *numpad)
1108 ACImpl *This = impl_from_IAudioClient(iface);
1109 HRESULT hr;
1111 TRACE("(%p)->(%p)\n", This, numpad);
1113 if(!numpad)
1114 return E_POINTER;
1116 OSSpinLockLock(&This->lock);
1118 hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
1120 OSSpinLockUnlock(&This->lock);
1122 return hr;
1125 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1126 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1127 WAVEFORMATEX **outpwfx)
1129 ACImpl *This = impl_from_IAudioClient(iface);
1130 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)pwfx;
1131 AudioQueueRef aqueue;
1132 HRESULT hr;
1134 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1136 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1137 return E_POINTER;
1139 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1140 return E_INVALIDARG;
1142 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1143 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1144 return E_INVALIDARG;
1146 dump_fmt(pwfx);
1148 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1149 fmtex->dwChannelMask != 0 &&
1150 fmtex->dwChannelMask != get_channel_mask(pwfx->nChannels))
1151 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1153 OSSpinLockLock(&This->lock);
1155 hr = ca_setup_aqueue(This->adevid, This->dataflow, pwfx, NULL, &aqueue);
1156 if(SUCCEEDED(hr)){
1157 AudioQueueDispose(aqueue, 1);
1158 OSSpinLockUnlock(&This->lock);
1159 if(outpwfx)
1160 *outpwfx = NULL;
1161 TRACE("returning %08x\n", S_OK);
1162 return S_OK;
1165 OSSpinLockUnlock(&This->lock);
1167 if(outpwfx)
1168 *outpwfx = NULL;
1170 TRACE("returning %08x\n", AUDCLNT_E_UNSUPPORTED_FORMAT);
1171 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1174 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1175 WAVEFORMATEX **pwfx)
1177 ACImpl *This = impl_from_IAudioClient(iface);
1178 WAVEFORMATEXTENSIBLE *fmt;
1179 OSStatus sc;
1180 UInt32 size;
1181 Float64 rate;
1182 AudioBufferList *buffers;
1183 AudioObjectPropertyAddress addr;
1184 int i;
1186 TRACE("(%p)->(%p)\n", This, pwfx);
1188 if(!pwfx)
1189 return E_POINTER;
1190 *pwfx = NULL;
1192 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1193 if(!fmt)
1194 return E_OUTOFMEMORY;
1196 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1198 addr.mScope = This->scope;
1199 addr.mElement = 0;
1200 addr.mSelector = kAudioDevicePropertyStreamConfiguration;
1202 sc = AudioObjectGetPropertyDataSize(This->adevid, &addr, 0, NULL, &size);
1203 if(sc != noErr){
1204 CoTaskMemFree(fmt);
1205 WARN("Unable to get size for _StreamConfiguration property: %lx\n", sc);
1206 return E_FAIL;
1209 buffers = HeapAlloc(GetProcessHeap(), 0, size);
1210 if(!buffers){
1211 CoTaskMemFree(fmt);
1212 return E_OUTOFMEMORY;
1215 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL,
1216 &size, buffers);
1217 if(sc != noErr){
1218 CoTaskMemFree(fmt);
1219 HeapFree(GetProcessHeap(), 0, buffers);
1220 WARN("Unable to get _StreamConfiguration property: %lx\n", sc);
1221 return E_FAIL;
1224 fmt->Format.nChannels = 0;
1225 for(i = 0; i < buffers->mNumberBuffers; ++i)
1226 fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels;
1228 HeapFree(GetProcessHeap(), 0, buffers);
1230 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1232 addr.mSelector = kAudioDevicePropertyNominalSampleRate;
1233 size = sizeof(Float64);
1234 sc = AudioObjectGetPropertyData(This->adevid, &addr, 0, NULL, &size, &rate);
1235 if(sc != noErr){
1236 CoTaskMemFree(fmt);
1237 WARN("Unable to get _NominalSampleRate property: %lx\n", sc);
1238 return E_FAIL;
1240 fmt->Format.nSamplesPerSec = rate;
1242 fmt->Format.wBitsPerSample = 32;
1243 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1245 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1246 fmt->Format.nChannels) / 8;
1247 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1248 fmt->Format.nBlockAlign;
1250 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1251 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1253 *pwfx = (WAVEFORMATEX*)fmt;
1254 dump_fmt(*pwfx);
1256 return S_OK;
1259 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1260 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1262 ACImpl *This = impl_from_IAudioClient(iface);
1264 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1266 if(!defperiod && !minperiod)
1267 return E_POINTER;
1269 OSSpinLockLock(&This->lock);
1271 if(This->period_ms){
1272 if(defperiod)
1273 *defperiod = This->period_ms * 10000;
1274 if(minperiod)
1275 *minperiod = This->period_ms * 10000;
1276 }else{
1277 if(defperiod)
1278 *defperiod = DefaultPeriod;
1279 if(minperiod)
1280 *minperiod = MinimumPeriod;
1283 OSSpinLockUnlock(&This->lock);
1285 return S_OK;
1288 void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
1290 ACImpl *This = user;
1292 OSSpinLockLock(&This->lock);
1293 if(This->event)
1294 SetEvent(This->event);
1295 OSSpinLockUnlock(&This->lock);
1298 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1300 ACImpl *This = impl_from_IAudioClient(iface);
1301 OSStatus sc;
1303 TRACE("(%p)\n", This);
1305 OSSpinLockLock(&This->lock);
1307 if(!This->aqueue){
1308 OSSpinLockUnlock(&This->lock);
1309 return AUDCLNT_E_NOT_INITIALIZED;
1312 if(This->playing != StateStopped){
1313 OSSpinLockUnlock(&This->lock);
1314 return AUDCLNT_E_NOT_STOPPED;
1317 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1318 OSSpinLockUnlock(&This->lock);
1319 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1322 if(This->event)
1323 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1324 ca_period_cb, This, 0, This->period_ms, 0))
1325 ERR("Unable to create timer: %u\n", GetLastError());
1327 This->playing = StateInTransition;
1329 OSSpinLockUnlock(&This->lock);
1331 sc = AudioQueueStart(This->aqueue, NULL);
1332 if(sc != noErr){
1333 WARN("Unable to start audio queue: %lx\n", sc);
1334 return E_FAIL;
1337 OSSpinLockLock(&This->lock);
1339 This->playing = StatePlaying;
1341 OSSpinLockUnlock(&This->lock);
1343 return S_OK;
1346 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1348 ACImpl *This = impl_from_IAudioClient(iface);
1349 OSStatus sc;
1351 TRACE("(%p)\n", This);
1353 OSSpinLockLock(&This->lock);
1355 if(!This->aqueue){
1356 OSSpinLockUnlock(&This->lock);
1357 return AUDCLNT_E_NOT_INITIALIZED;
1360 if(This->playing == StateStopped){
1361 OSSpinLockUnlock(&This->lock);
1362 return S_FALSE;
1365 if(This->playing == StateInTransition){
1366 OSSpinLockUnlock(&This->lock);
1367 return S_OK;
1370 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1371 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1372 This->timer = NULL;
1375 This->playing = StateInTransition;
1377 OSSpinLockUnlock(&This->lock);
1379 sc = AudioQueueFlush(This->aqueue);
1380 if(sc != noErr)
1381 WARN("Unable to flush audio queue: %lx\n", sc);
1383 sc = AudioQueuePause(This->aqueue);
1384 if(sc != noErr){
1385 WARN("Unable to pause audio queue: %lx\n", sc);
1386 return E_FAIL;
1389 OSSpinLockLock(&This->lock);
1391 This->playing = StateStopped;
1393 OSSpinLockUnlock(&This->lock);
1395 return S_OK;
1398 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1400 ACImpl *This = impl_from_IAudioClient(iface);
1401 HRESULT hr;
1402 OSStatus sc;
1404 TRACE("(%p)\n", This);
1406 OSSpinLockLock(&This->lock);
1408 if(!This->aqueue){
1409 OSSpinLockUnlock(&This->lock);
1410 return AUDCLNT_E_NOT_INITIALIZED;
1413 if(This->playing != StateStopped){
1414 OSSpinLockUnlock(&This->lock);
1415 return AUDCLNT_E_NOT_STOPPED;
1418 if(This->getbuf_last){
1419 OSSpinLockUnlock(&This->lock);
1420 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1423 This->written_frames = 0;
1425 hr = AudioClock_GetPosition_nolock(This, &This->last_time, NULL, TRUE);
1426 if(FAILED(hr)){
1427 OSSpinLockUnlock(&This->lock);
1428 return hr;
1431 OSSpinLockUnlock(&This->lock);
1433 sc = AudioQueueReset(This->aqueue);
1434 if(sc != noErr){
1435 WARN("Unable to reset audio queue: %lx\n", sc);
1436 return E_FAIL;
1439 return S_OK;
1442 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1443 HANDLE event)
1445 ACImpl *This = impl_from_IAudioClient(iface);
1447 TRACE("(%p)->(%p)\n", This, event);
1449 if(!event)
1450 return E_INVALIDARG;
1452 OSSpinLockLock(&This->lock);
1454 if(!This->aqueue){
1455 OSSpinLockUnlock(&This->lock);
1456 return AUDCLNT_E_NOT_INITIALIZED;
1459 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1460 OSSpinLockUnlock(&This->lock);
1461 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1464 This->event = event;
1466 OSSpinLockUnlock(&This->lock);
1468 return S_OK;
1471 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1472 void **ppv)
1474 ACImpl *This = impl_from_IAudioClient(iface);
1476 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1478 if(!ppv)
1479 return E_POINTER;
1480 *ppv = NULL;
1482 OSSpinLockLock(&This->lock);
1484 if(!This->aqueue){
1485 OSSpinLockUnlock(&This->lock);
1486 return AUDCLNT_E_NOT_INITIALIZED;
1489 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1490 if(This->dataflow != eRender){
1491 OSSpinLockUnlock(&This->lock);
1492 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1494 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1495 *ppv = &This->IAudioRenderClient_iface;
1496 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1497 if(This->dataflow != eCapture){
1498 OSSpinLockUnlock(&This->lock);
1499 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1501 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1502 *ppv = &This->IAudioCaptureClient_iface;
1503 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1504 IAudioClock_AddRef(&This->IAudioClock_iface);
1505 *ppv = &This->IAudioClock_iface;
1506 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1507 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1508 *ppv = &This->IAudioStreamVolume_iface;
1509 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
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 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1519 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1520 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
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 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1530 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1531 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1532 if(!This->session_wrapper){
1533 This->session_wrapper = AudioSessionWrapper_Create(This);
1534 if(!This->session_wrapper){
1535 OSSpinLockUnlock(&This->lock);
1536 return E_OUTOFMEMORY;
1538 }else
1539 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1541 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1544 if(*ppv){
1545 OSSpinLockUnlock(&This->lock);
1546 return S_OK;
1549 OSSpinLockUnlock(&This->lock);
1551 FIXME("stub %s\n", debugstr_guid(riid));
1552 return E_NOINTERFACE;
1555 static const IAudioClientVtbl AudioClient_Vtbl =
1557 AudioClient_QueryInterface,
1558 AudioClient_AddRef,
1559 AudioClient_Release,
1560 AudioClient_Initialize,
1561 AudioClient_GetBufferSize,
1562 AudioClient_GetStreamLatency,
1563 AudioClient_GetCurrentPadding,
1564 AudioClient_IsFormatSupported,
1565 AudioClient_GetMixFormat,
1566 AudioClient_GetDevicePeriod,
1567 AudioClient_Start,
1568 AudioClient_Stop,
1569 AudioClient_Reset,
1570 AudioClient_SetEventHandle,
1571 AudioClient_GetService
1574 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1575 IAudioRenderClient *iface, REFIID riid, void **ppv)
1577 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1579 if(!ppv)
1580 return E_POINTER;
1581 *ppv = NULL;
1583 if(IsEqualIID(riid, &IID_IUnknown) ||
1584 IsEqualIID(riid, &IID_IAudioRenderClient))
1585 *ppv = iface;
1586 if(*ppv){
1587 IUnknown_AddRef((IUnknown*)*ppv);
1588 return S_OK;
1591 WARN("Unknown interface %s\n", debugstr_guid(riid));
1592 return E_NOINTERFACE;
1595 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1597 ACImpl *This = impl_from_IAudioRenderClient(iface);
1598 return AudioClient_AddRef(&This->IAudioClient_iface);
1601 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1603 ACImpl *This = impl_from_IAudioRenderClient(iface);
1604 return AudioClient_Release(&This->IAudioClient_iface);
1607 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1608 UINT32 frames, BYTE **data)
1610 ACImpl *This = impl_from_IAudioRenderClient(iface);
1611 AQBuffer *buf;
1612 UINT32 pad, bytes = frames * This->fmt->nBlockAlign;
1613 HRESULT hr;
1614 OSStatus sc;
1616 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1618 if(!data)
1619 return E_POINTER;
1620 *data = NULL;
1622 OSSpinLockLock(&This->lock);
1624 if(This->getbuf_last){
1625 OSSpinLockUnlock(&This->lock);
1626 return AUDCLNT_E_OUT_OF_ORDER;
1629 if(!frames){
1630 OSSpinLockUnlock(&This->lock);
1631 return S_OK;
1634 hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
1635 if(FAILED(hr)){
1636 OSSpinLockUnlock(&This->lock);
1637 return hr;
1640 if(pad + frames > This->bufsize_frames){
1641 OSSpinLockUnlock(&This->lock);
1642 return AUDCLNT_E_BUFFER_TOO_LARGE;
1645 LIST_FOR_EACH_ENTRY(buf, &This->avail_buffers, AQBuffer, entry){
1646 if(buf->buf->mAudioDataBytesCapacity >= bytes){
1647 This->public_buffer = buf->buf;
1648 list_remove(&buf->entry);
1649 break;
1653 if(&buf->entry == &This->avail_buffers){
1654 sc = AudioQueueAllocateBuffer(This->aqueue, bytes,
1655 &This->public_buffer);
1656 if(sc != noErr){
1657 OSSpinLockUnlock(&This->lock);
1658 WARN("Unable to allocate buffer: %lx\n", sc);
1659 return E_FAIL;
1661 buf = HeapAlloc(GetProcessHeap(), 0, sizeof(AQBuffer));
1662 if(!buf){
1663 AudioQueueFreeBuffer(This->aqueue, This->public_buffer);
1664 This->public_buffer = NULL;
1665 OSSpinLockUnlock(&This->lock);
1666 return E_OUTOFMEMORY;
1668 buf->buf = This->public_buffer;
1669 This->public_buffer->mUserData = buf;
1672 *data = This->public_buffer->mAudioData;
1674 This->getbuf_last = frames;
1676 OSSpinLockUnlock(&This->lock);
1678 return S_OK;
1681 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1682 IAudioRenderClient *iface, UINT32 frames, DWORD flags)
1684 ACImpl *This = impl_from_IAudioRenderClient(iface);
1685 OSStatus sc;
1687 TRACE("(%p)->(%u, %x)\n", This, frames, flags);
1689 OSSpinLockLock(&This->lock);
1691 if(!frames){
1692 This->getbuf_last = 0;
1693 if(This->public_buffer){
1694 AQBuffer *buf = This->public_buffer->mUserData;
1695 list_add_tail(&This->avail_buffers, &buf->entry);
1696 This->public_buffer = NULL;
1698 OSSpinLockUnlock(&This->lock);
1699 return S_OK;
1702 if(!This->getbuf_last){
1703 OSSpinLockUnlock(&This->lock);
1704 return AUDCLNT_E_OUT_OF_ORDER;
1707 if(frames > This->getbuf_last){
1708 OSSpinLockUnlock(&This->lock);
1709 return AUDCLNT_E_INVALID_SIZE;
1712 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1713 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1714 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1715 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1716 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1717 This->fmt->wBitsPerSample == 8)
1718 memset(This->public_buffer->mAudioData, 128,
1719 frames * This->fmt->nBlockAlign);
1720 else
1721 memset(This->public_buffer->mAudioData, 0,
1722 frames * This->fmt->nBlockAlign);
1725 This->public_buffer->mAudioDataByteSize = frames * This->fmt->nBlockAlign;
1727 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer, 0, NULL);
1728 if(sc != noErr){
1729 OSSpinLockUnlock(&This->lock);
1730 WARN("Unable to enqueue buffer: %lx\n", sc);
1731 return E_FAIL;
1734 if(This->playing == StateStopped)
1735 AudioQueuePrime(This->aqueue, 0, NULL);
1737 This->public_buffer = NULL;
1738 This->getbuf_last = 0;
1739 This->written_frames += frames;
1740 This->inbuf_frames += frames;
1742 OSSpinLockUnlock(&This->lock);
1744 return S_OK;
1747 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1748 AudioRenderClient_QueryInterface,
1749 AudioRenderClient_AddRef,
1750 AudioRenderClient_Release,
1751 AudioRenderClient_GetBuffer,
1752 AudioRenderClient_ReleaseBuffer
1755 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1756 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1758 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1760 if(!ppv)
1761 return E_POINTER;
1762 *ppv = NULL;
1764 if(IsEqualIID(riid, &IID_IUnknown) ||
1765 IsEqualIID(riid, &IID_IAudioCaptureClient))
1766 *ppv = iface;
1767 if(*ppv){
1768 IUnknown_AddRef((IUnknown*)*ppv);
1769 return S_OK;
1772 WARN("Unknown interface %s\n", debugstr_guid(riid));
1773 return E_NOINTERFACE;
1776 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1778 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1779 return IAudioClient_AddRef(&This->IAudioClient_iface);
1782 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1784 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1785 return IAudioClient_Release(&This->IAudioClient_iface);
1788 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1789 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1790 UINT64 *qpcpos)
1792 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1794 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1795 devpos, qpcpos);
1797 if(!data || !frames || !flags)
1798 return E_POINTER;
1800 OSSpinLockLock(&This->lock);
1802 if(This->getbuf_last){
1803 OSSpinLockUnlock(&This->lock);
1804 return AUDCLNT_E_OUT_OF_ORDER;
1807 if(This->public_buffer){
1808 *data = This->public_buffer->mAudioData;
1809 *frames =
1810 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1811 }else{
1812 struct list *head = list_head(&This->avail_buffers);
1813 if(!head){
1814 *data = NULL;
1815 *frames = 0;
1816 }else{
1817 AQBuffer *buf = LIST_ENTRY(head, AQBuffer, entry);
1818 This->public_buffer = buf->buf;
1819 *data = This->public_buffer->mAudioData;
1820 *frames =
1821 This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1822 list_remove(&buf->entry);
1826 *flags = 0;
1827 This->written_frames += *frames;
1828 This->inbuf_frames -= *frames;
1829 This->getbuf_last = 1;
1831 if(devpos || qpcpos)
1832 AudioClock_GetPosition_nolock(This, devpos, qpcpos, FALSE);
1834 OSSpinLockUnlock(&This->lock);
1836 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1839 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1840 IAudioCaptureClient *iface, UINT32 done)
1842 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1843 UINT32 pbuf_frames;
1844 OSStatus sc;
1846 TRACE("(%p)->(%u)\n", This, done);
1848 OSSpinLockLock(&This->lock);
1850 if(!This->getbuf_last){
1851 OSSpinLockUnlock(&This->lock);
1852 return AUDCLNT_E_OUT_OF_ORDER;
1855 pbuf_frames = This->public_buffer->mAudioDataByteSize / This->fmt->nBlockAlign;
1856 if(done != 0 && done != pbuf_frames){
1857 OSSpinLockUnlock(&This->lock);
1858 return AUDCLNT_E_INVALID_SIZE;
1861 if(done){
1862 sc = AudioQueueEnqueueBuffer(This->aqueue, This->public_buffer,
1863 0, NULL);
1864 if(sc != noErr)
1865 WARN("Unable to enqueue buffer: %lx\n", sc);
1866 This->public_buffer = NULL;
1869 This->getbuf_last = 0;
1871 OSSpinLockUnlock(&This->lock);
1873 return S_OK;
1876 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1877 IAudioCaptureClient *iface, UINT32 *frames)
1879 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1880 struct list *head;
1881 AQBuffer *buf;
1883 TRACE("(%p)->(%p)\n", This, frames);
1885 if(!frames)
1886 return E_POINTER;
1888 OSSpinLockLock(&This->lock);
1890 head = list_head(&This->avail_buffers);
1892 if(!head){
1893 *frames = This->bufsize_frames / CAPTURE_BUFFERS;
1894 OSSpinLockUnlock(&This->lock);
1895 return S_OK;
1898 buf = LIST_ENTRY(head, AQBuffer, entry);
1899 *frames = buf->buf->mAudioDataByteSize / This->fmt->nBlockAlign;
1901 OSSpinLockUnlock(&This->lock);
1903 return S_OK;
1906 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1908 AudioCaptureClient_QueryInterface,
1909 AudioCaptureClient_AddRef,
1910 AudioCaptureClient_Release,
1911 AudioCaptureClient_GetBuffer,
1912 AudioCaptureClient_ReleaseBuffer,
1913 AudioCaptureClient_GetNextPacketSize
1916 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1917 REFIID riid, void **ppv)
1919 ACImpl *This = impl_from_IAudioClock(iface);
1921 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1923 if(!ppv)
1924 return E_POINTER;
1925 *ppv = NULL;
1927 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1928 *ppv = iface;
1929 else if(IsEqualIID(riid, &IID_IAudioClock2))
1930 *ppv = &This->IAudioClock2_iface;
1931 if(*ppv){
1932 IUnknown_AddRef((IUnknown*)*ppv);
1933 return S_OK;
1936 WARN("Unknown interface %s\n", debugstr_guid(riid));
1937 return E_NOINTERFACE;
1940 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1942 ACImpl *This = impl_from_IAudioClock(iface);
1943 return IAudioClient_AddRef(&This->IAudioClient_iface);
1946 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1948 ACImpl *This = impl_from_IAudioClock(iface);
1949 return IAudioClient_Release(&This->IAudioClient_iface);
1952 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1954 ACImpl *This = impl_from_IAudioClock(iface);
1956 TRACE("(%p)->(%p)\n", This, freq);
1958 *freq = This->fmt->nSamplesPerSec;
1960 return S_OK;
1963 static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
1964 UINT64 *pos, UINT64 *qpctime, BOOL raw)
1966 AudioTimeStamp time;
1967 OSStatus sc;
1969 sc = AudioQueueGetCurrentTime(This->aqueue, NULL, &time, NULL);
1970 if(sc == kAudioQueueErr_InvalidRunState){
1971 *pos = 0;
1972 }else if(sc == noErr){
1973 if(!(time.mFlags & kAudioTimeStampSampleTimeValid)){
1974 FIXME("Sample time not valid, should calculate from something else\n");
1975 return E_FAIL;
1978 if(raw)
1979 *pos = time.mSampleTime;
1980 else
1981 *pos = time.mSampleTime - This->last_time;
1982 }else{
1983 WARN("Unable to get current time: %lx\n", sc);
1984 return E_FAIL;
1987 if(qpctime){
1988 LARGE_INTEGER stamp, freq;
1989 QueryPerformanceCounter(&stamp);
1990 QueryPerformanceFrequency(&freq);
1991 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1994 return S_OK;
1997 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1998 UINT64 *qpctime)
2000 ACImpl *This = impl_from_IAudioClock(iface);
2001 HRESULT hr;
2003 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2005 if(!pos)
2006 return E_POINTER;
2008 OSSpinLockLock(&This->lock);
2010 hr = AudioClock_GetPosition_nolock(This, pos, qpctime, FALSE);
2012 OSSpinLockUnlock(&This->lock);
2014 return hr;
2017 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2018 DWORD *chars)
2020 ACImpl *This = impl_from_IAudioClock(iface);
2022 TRACE("(%p)->(%p)\n", This, chars);
2024 if(!chars)
2025 return E_POINTER;
2027 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2029 return S_OK;
2032 static const IAudioClockVtbl AudioClock_Vtbl =
2034 AudioClock_QueryInterface,
2035 AudioClock_AddRef,
2036 AudioClock_Release,
2037 AudioClock_GetFrequency,
2038 AudioClock_GetPosition,
2039 AudioClock_GetCharacteristics
2042 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2043 REFIID riid, void **ppv)
2045 ACImpl *This = impl_from_IAudioClock2(iface);
2046 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2049 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2051 ACImpl *This = impl_from_IAudioClock2(iface);
2052 return IAudioClient_AddRef(&This->IAudioClient_iface);
2055 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2057 ACImpl *This = impl_from_IAudioClock2(iface);
2058 return IAudioClient_Release(&This->IAudioClient_iface);
2061 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2062 UINT64 *pos, UINT64 *qpctime)
2064 ACImpl *This = impl_from_IAudioClock2(iface);
2066 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2068 return E_NOTIMPL;
2071 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2073 AudioClock2_QueryInterface,
2074 AudioClock2_AddRef,
2075 AudioClock2_Release,
2076 AudioClock2_GetDevicePosition
2079 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2081 AudioSessionWrapper *ret;
2083 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2084 sizeof(AudioSessionWrapper));
2085 if(!ret)
2086 return NULL;
2088 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2089 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2090 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2092 ret->ref = 1;
2094 ret->client = client;
2095 if(client){
2096 ret->session = client->session;
2097 AudioClient_AddRef(&client->IAudioClient_iface);
2100 return ret;
2103 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2104 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2106 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2108 if(!ppv)
2109 return E_POINTER;
2110 *ppv = NULL;
2112 if(IsEqualIID(riid, &IID_IUnknown) ||
2113 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2114 IsEqualIID(riid, &IID_IAudioSessionControl2))
2115 *ppv = iface;
2116 if(*ppv){
2117 IUnknown_AddRef((IUnknown*)*ppv);
2118 return S_OK;
2121 WARN("Unknown interface %s\n", debugstr_guid(riid));
2122 return E_NOINTERFACE;
2125 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2127 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2128 ULONG ref;
2129 ref = InterlockedIncrement(&This->ref);
2130 TRACE("(%p) Refcount now %u\n", This, ref);
2131 return ref;
2134 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2136 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2137 ULONG ref;
2138 ref = InterlockedDecrement(&This->ref);
2139 TRACE("(%p) Refcount now %u\n", This, ref);
2140 if(!ref){
2141 if(This->client){
2142 OSSpinLockLock(&This->client->lock);
2143 This->client->session_wrapper = NULL;
2144 OSSpinLockUnlock(&This->client->lock);
2145 AudioClient_Release(&This->client->IAudioClient_iface);
2147 HeapFree(GetProcessHeap(), 0, This);
2149 return ref;
2152 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2153 AudioSessionState *state)
2155 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2156 ACImpl *client;
2158 TRACE("(%p)->(%p)\n", This, state);
2160 if(!state)
2161 return NULL_PTR_ERR;
2163 EnterCriticalSection(&g_sessions_lock);
2165 if(list_empty(&This->session->clients)){
2166 *state = AudioSessionStateExpired;
2167 LeaveCriticalSection(&g_sessions_lock);
2168 return S_OK;
2171 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2172 OSSpinLockLock(&client->lock);
2173 if(client->playing == StatePlaying ||
2174 client->playing == StateInTransition){
2175 *state = AudioSessionStateActive;
2176 OSSpinLockUnlock(&client->lock);
2177 LeaveCriticalSection(&g_sessions_lock);
2178 return S_OK;
2180 OSSpinLockUnlock(&client->lock);
2183 LeaveCriticalSection(&g_sessions_lock);
2185 *state = AudioSessionStateInactive;
2187 return S_OK;
2190 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2191 IAudioSessionControl2 *iface, WCHAR **name)
2193 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2195 FIXME("(%p)->(%p) - stub\n", This, name);
2197 return E_NOTIMPL;
2200 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2201 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2203 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2205 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2207 return E_NOTIMPL;
2210 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2211 IAudioSessionControl2 *iface, WCHAR **path)
2213 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2215 FIXME("(%p)->(%p) - stub\n", This, path);
2217 return E_NOTIMPL;
2220 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2221 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2223 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2225 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2227 return E_NOTIMPL;
2230 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2231 IAudioSessionControl2 *iface, GUID *group)
2233 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2235 FIXME("(%p)->(%p) - stub\n", This, group);
2237 return E_NOTIMPL;
2240 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2241 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2243 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2245 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2246 debugstr_guid(session));
2248 return E_NOTIMPL;
2251 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2252 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2254 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2256 FIXME("(%p)->(%p) - stub\n", This, events);
2258 return S_OK;
2261 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2262 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2264 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2266 FIXME("(%p)->(%p) - stub\n", This, events);
2268 return S_OK;
2271 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2272 IAudioSessionControl2 *iface, WCHAR **id)
2274 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2276 FIXME("(%p)->(%p) - stub\n", This, id);
2278 return E_NOTIMPL;
2281 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2282 IAudioSessionControl2 *iface, WCHAR **id)
2284 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2286 FIXME("(%p)->(%p) - stub\n", This, id);
2288 return E_NOTIMPL;
2291 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2292 IAudioSessionControl2 *iface, DWORD *pid)
2294 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2296 TRACE("(%p)->(%p)\n", This, pid);
2298 if(!pid)
2299 return E_POINTER;
2301 *pid = GetCurrentProcessId();
2303 return S_OK;
2306 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2307 IAudioSessionControl2 *iface)
2309 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2311 TRACE("(%p)\n", This);
2313 return S_FALSE;
2316 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2317 IAudioSessionControl2 *iface, BOOL optout)
2319 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2321 TRACE("(%p)->(%d)\n", This, optout);
2323 return S_OK;
2326 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2328 AudioSessionControl_QueryInterface,
2329 AudioSessionControl_AddRef,
2330 AudioSessionControl_Release,
2331 AudioSessionControl_GetState,
2332 AudioSessionControl_GetDisplayName,
2333 AudioSessionControl_SetDisplayName,
2334 AudioSessionControl_GetIconPath,
2335 AudioSessionControl_SetIconPath,
2336 AudioSessionControl_GetGroupingParam,
2337 AudioSessionControl_SetGroupingParam,
2338 AudioSessionControl_RegisterAudioSessionNotification,
2339 AudioSessionControl_UnregisterAudioSessionNotification,
2340 AudioSessionControl_GetSessionIdentifier,
2341 AudioSessionControl_GetSessionInstanceIdentifier,
2342 AudioSessionControl_GetProcessId,
2343 AudioSessionControl_IsSystemSoundsSession,
2344 AudioSessionControl_SetDuckingPreference
2347 /* index == -1 means set all channels, otherwise sets only the given channel */
2348 static HRESULT ca_setvol(ACImpl *This, UINT32 index)
2350 float level;
2351 OSStatus sc;
2353 if(index == (UINT32)-1){
2354 HRESULT ret = S_OK;
2355 UINT32 i;
2356 for(i = 0; i < This->fmt->nChannels; ++i){
2357 HRESULT hr;
2358 hr = ca_setvol(This, i);
2359 if(FAILED(hr))
2360 ret = hr;
2362 return ret;
2365 if(This->session->mute)
2366 level = 0;
2367 else
2368 level = This->session->master_vol *
2369 This->session->channel_vols[index] * This->vols[index];
2371 sc = AudioQueueSetParameter(This->aqueue, kAudioQueueParam_Volume, level);
2372 if(sc != noErr)
2373 WARN("Setting _Volume property failed: %lx\n", sc);
2375 return S_OK;
2378 static HRESULT ca_session_setvol(AudioSession *session, UINT32 index)
2380 HRESULT ret = S_OK;
2381 ACImpl *client;
2383 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2384 HRESULT hr;
2385 hr = ca_setvol(client, index);
2386 if(FAILED(hr))
2387 ret = hr;
2390 return ret;
2393 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2394 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2396 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2398 if(!ppv)
2399 return E_POINTER;
2400 *ppv = NULL;
2402 if(IsEqualIID(riid, &IID_IUnknown) ||
2403 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2404 *ppv = iface;
2405 if(*ppv){
2406 IUnknown_AddRef((IUnknown*)*ppv);
2407 return S_OK;
2410 WARN("Unknown interface %s\n", debugstr_guid(riid));
2411 return E_NOINTERFACE;
2414 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2416 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2417 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2420 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2422 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2423 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2426 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2427 ISimpleAudioVolume *iface, float level, const GUID *context)
2429 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2430 AudioSession *session = This->session;
2431 HRESULT ret;
2433 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2435 if(level < 0.f || level > 1.f)
2436 return E_INVALIDARG;
2438 if(context)
2439 FIXME("Notifications not supported yet\n");
2441 EnterCriticalSection(&session->lock);
2443 session->master_vol = level;
2445 ret = ca_session_setvol(session, -1);
2447 LeaveCriticalSection(&session->lock);
2449 return ret;
2452 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2453 ISimpleAudioVolume *iface, float *level)
2455 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2456 AudioSession *session = This->session;
2458 TRACE("(%p)->(%p)\n", session, level);
2460 if(!level)
2461 return NULL_PTR_ERR;
2463 *level = session->master_vol;
2465 return S_OK;
2468 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2469 BOOL mute, const GUID *context)
2471 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2472 AudioSession *session = This->session;
2474 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2476 if(context)
2477 FIXME("Notifications not supported yet\n");
2479 EnterCriticalSection(&session->lock);
2481 session->mute = mute;
2483 ca_session_setvol(session, -1);
2485 LeaveCriticalSection(&session->lock);
2487 return S_OK;
2490 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2491 BOOL *mute)
2493 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2494 AudioSession *session = This->session;
2496 TRACE("(%p)->(%p)\n", session, mute);
2498 if(!mute)
2499 return NULL_PTR_ERR;
2501 *mute = session->mute;
2503 return S_OK;
2506 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2508 SimpleAudioVolume_QueryInterface,
2509 SimpleAudioVolume_AddRef,
2510 SimpleAudioVolume_Release,
2511 SimpleAudioVolume_SetMasterVolume,
2512 SimpleAudioVolume_GetMasterVolume,
2513 SimpleAudioVolume_SetMute,
2514 SimpleAudioVolume_GetMute
2517 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2518 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2520 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2522 if(!ppv)
2523 return E_POINTER;
2524 *ppv = NULL;
2526 if(IsEqualIID(riid, &IID_IUnknown) ||
2527 IsEqualIID(riid, &IID_IAudioStreamVolume))
2528 *ppv = iface;
2529 if(*ppv){
2530 IUnknown_AddRef((IUnknown*)*ppv);
2531 return S_OK;
2534 WARN("Unknown interface %s\n", debugstr_guid(riid));
2535 return E_NOINTERFACE;
2538 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2540 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2541 return IAudioClient_AddRef(&This->IAudioClient_iface);
2544 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2546 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2547 return IAudioClient_Release(&This->IAudioClient_iface);
2550 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2551 IAudioStreamVolume *iface, UINT32 *out)
2553 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2555 TRACE("(%p)->(%p)\n", This, out);
2557 if(!out)
2558 return E_POINTER;
2560 *out = This->fmt->nChannels;
2562 return S_OK;
2565 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2566 IAudioStreamVolume *iface, UINT32 index, float level)
2568 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2569 HRESULT ret;
2571 TRACE("(%p)->(%d, %f)\n", This, index, level);
2573 if(level < 0.f || level > 1.f)
2574 return E_INVALIDARG;
2576 if(index >= This->fmt->nChannels)
2577 return E_INVALIDARG;
2579 OSSpinLockLock(&This->lock);
2581 This->vols[index] = level;
2583 WARN("AudioQueue doesn't support per-channel volume control\n");
2584 ret = ca_setvol(This, index);
2586 OSSpinLockUnlock(&This->lock);
2588 return ret;
2591 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2592 IAudioStreamVolume *iface, UINT32 index, float *level)
2594 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2596 TRACE("(%p)->(%d, %p)\n", This, index, level);
2598 if(!level)
2599 return E_POINTER;
2601 if(index >= This->fmt->nChannels)
2602 return E_INVALIDARG;
2604 *level = This->vols[index];
2606 return S_OK;
2609 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2610 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2612 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2613 int i;
2614 HRESULT ret;
2616 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2618 if(!levels)
2619 return E_POINTER;
2621 if(count != This->fmt->nChannels)
2622 return E_INVALIDARG;
2624 OSSpinLockLock(&This->lock);
2626 for(i = 0; i < count; ++i)
2627 This->vols[i] = levels[i];
2629 ret = ca_setvol(This, -1);
2631 OSSpinLockUnlock(&This->lock);
2633 return ret;
2636 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2637 IAudioStreamVolume *iface, UINT32 count, float *levels)
2639 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2640 int i;
2642 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2644 if(!levels)
2645 return E_POINTER;
2647 if(count != This->fmt->nChannels)
2648 return E_INVALIDARG;
2650 OSSpinLockLock(&This->lock);
2652 for(i = 0; i < count; ++i)
2653 levels[i] = This->vols[i];
2655 OSSpinLockUnlock(&This->lock);
2657 return S_OK;
2660 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2662 AudioStreamVolume_QueryInterface,
2663 AudioStreamVolume_AddRef,
2664 AudioStreamVolume_Release,
2665 AudioStreamVolume_GetChannelCount,
2666 AudioStreamVolume_SetChannelVolume,
2667 AudioStreamVolume_GetChannelVolume,
2668 AudioStreamVolume_SetAllVolumes,
2669 AudioStreamVolume_GetAllVolumes
2672 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2673 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2675 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2677 if(!ppv)
2678 return E_POINTER;
2679 *ppv = NULL;
2681 if(IsEqualIID(riid, &IID_IUnknown) ||
2682 IsEqualIID(riid, &IID_IChannelAudioVolume))
2683 *ppv = iface;
2684 if(*ppv){
2685 IUnknown_AddRef((IUnknown*)*ppv);
2686 return S_OK;
2689 WARN("Unknown interface %s\n", debugstr_guid(riid));
2690 return E_NOINTERFACE;
2693 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2695 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2696 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2699 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2701 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2702 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2705 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2706 IChannelAudioVolume *iface, UINT32 *out)
2708 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2709 AudioSession *session = This->session;
2711 TRACE("(%p)->(%p)\n", session, out);
2713 if(!out)
2714 return NULL_PTR_ERR;
2716 *out = session->channel_count;
2718 return S_OK;
2721 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2722 IChannelAudioVolume *iface, UINT32 index, float level,
2723 const GUID *context)
2725 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2726 AudioSession *session = This->session;
2727 HRESULT ret;
2729 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2730 wine_dbgstr_guid(context));
2732 if(level < 0.f || level > 1.f)
2733 return E_INVALIDARG;
2735 if(index >= session->channel_count)
2736 return E_INVALIDARG;
2738 if(context)
2739 FIXME("Notifications not supported yet\n");
2741 EnterCriticalSection(&session->lock);
2743 session->channel_vols[index] = level;
2745 WARN("AudioQueue doesn't support per-channel volume control\n");
2746 ret = ca_session_setvol(session, index);
2748 LeaveCriticalSection(&session->lock);
2750 return ret;
2753 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2754 IChannelAudioVolume *iface, UINT32 index, float *level)
2756 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2757 AudioSession *session = This->session;
2759 TRACE("(%p)->(%d, %p)\n", session, index, level);
2761 if(!level)
2762 return NULL_PTR_ERR;
2764 if(index >= session->channel_count)
2765 return E_INVALIDARG;
2767 *level = session->channel_vols[index];
2769 return S_OK;
2772 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2773 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2774 const GUID *context)
2776 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2777 AudioSession *session = This->session;
2778 int i;
2779 HRESULT ret;
2781 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2782 wine_dbgstr_guid(context));
2784 if(!levels)
2785 return NULL_PTR_ERR;
2787 if(count != session->channel_count)
2788 return E_INVALIDARG;
2790 if(context)
2791 FIXME("Notifications not supported yet\n");
2793 EnterCriticalSection(&session->lock);
2795 for(i = 0; i < count; ++i)
2796 session->channel_vols[i] = levels[i];
2798 ret = ca_session_setvol(session, -1);
2800 LeaveCriticalSection(&session->lock);
2802 return ret;
2805 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2806 IChannelAudioVolume *iface, UINT32 count, float *levels)
2808 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2809 AudioSession *session = This->session;
2810 int i;
2812 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2814 if(!levels)
2815 return NULL_PTR_ERR;
2817 if(count != session->channel_count)
2818 return E_INVALIDARG;
2820 for(i = 0; i < count; ++i)
2821 levels[i] = session->channel_vols[i];
2823 return S_OK;
2826 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2828 ChannelAudioVolume_QueryInterface,
2829 ChannelAudioVolume_AddRef,
2830 ChannelAudioVolume_Release,
2831 ChannelAudioVolume_GetChannelCount,
2832 ChannelAudioVolume_SetChannelVolume,
2833 ChannelAudioVolume_GetChannelVolume,
2834 ChannelAudioVolume_SetAllVolumes,
2835 ChannelAudioVolume_GetAllVolumes
2838 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2839 REFIID riid, void **ppv)
2841 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2843 if(!ppv)
2844 return E_POINTER;
2845 *ppv = NULL;
2847 if(IsEqualIID(riid, &IID_IUnknown) ||
2848 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2849 IsEqualIID(riid, &IID_IAudioSessionManager2))
2850 *ppv = iface;
2851 if(*ppv){
2852 IUnknown_AddRef((IUnknown*)*ppv);
2853 return S_OK;
2856 WARN("Unknown interface %s\n", debugstr_guid(riid));
2857 return E_NOINTERFACE;
2860 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2862 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2863 ULONG ref;
2864 ref = InterlockedIncrement(&This->ref);
2865 TRACE("(%p) Refcount now %u\n", This, ref);
2866 return ref;
2869 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2871 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2872 ULONG ref;
2873 ref = InterlockedDecrement(&This->ref);
2874 TRACE("(%p) Refcount now %u\n", This, ref);
2875 if(!ref)
2876 HeapFree(GetProcessHeap(), 0, This);
2877 return ref;
2880 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2881 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2882 IAudioSessionControl **out)
2884 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2885 AudioSession *session;
2886 AudioSessionWrapper *wrapper;
2887 HRESULT hr;
2889 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2890 flags, out);
2892 hr = get_audio_session(session_guid, This->device, 0, &session);
2893 if(FAILED(hr))
2894 return hr;
2896 wrapper = AudioSessionWrapper_Create(NULL);
2897 if(!wrapper)
2898 return E_OUTOFMEMORY;
2900 wrapper->session = session;
2902 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2904 return S_OK;
2907 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2908 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2909 ISimpleAudioVolume **out)
2911 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2912 AudioSession *session;
2913 AudioSessionWrapper *wrapper;
2914 HRESULT hr;
2916 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2917 flags, out);
2919 hr = get_audio_session(session_guid, This->device, 0, &session);
2920 if(FAILED(hr))
2921 return hr;
2923 wrapper = AudioSessionWrapper_Create(NULL);
2924 if(!wrapper)
2925 return E_OUTOFMEMORY;
2927 wrapper->session = session;
2929 *out = &wrapper->ISimpleAudioVolume_iface;
2931 return S_OK;
2934 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2935 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2937 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2938 FIXME("(%p)->(%p) - stub\n", This, out);
2939 return E_NOTIMPL;
2942 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2943 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2945 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2946 FIXME("(%p)->(%p) - stub\n", This, notification);
2947 return E_NOTIMPL;
2950 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2951 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2953 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2954 FIXME("(%p)->(%p) - stub\n", This, notification);
2955 return E_NOTIMPL;
2958 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2959 IAudioSessionManager2 *iface, const WCHAR *session_id,
2960 IAudioVolumeDuckNotification *notification)
2962 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2963 FIXME("(%p)->(%p) - stub\n", This, notification);
2964 return E_NOTIMPL;
2967 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2968 IAudioSessionManager2 *iface,
2969 IAudioVolumeDuckNotification *notification)
2971 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2972 FIXME("(%p)->(%p) - stub\n", This, notification);
2973 return E_NOTIMPL;
2976 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2978 AudioSessionManager_QueryInterface,
2979 AudioSessionManager_AddRef,
2980 AudioSessionManager_Release,
2981 AudioSessionManager_GetAudioSessionControl,
2982 AudioSessionManager_GetSimpleAudioVolume,
2983 AudioSessionManager_GetSessionEnumerator,
2984 AudioSessionManager_RegisterSessionNotification,
2985 AudioSessionManager_UnregisterSessionNotification,
2986 AudioSessionManager_RegisterDuckNotification,
2987 AudioSessionManager_UnregisterDuckNotification
2990 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2991 IAudioSessionManager2 **out)
2993 SessionMgr *This;
2995 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2996 if(!This)
2997 return E_OUTOFMEMORY;
2999 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3000 This->device = device;
3001 This->ref = 1;
3003 *out = &This->IAudioSessionManager2_iface;
3005 return S_OK;