ntoskrnl.exe/tests: Add some IOCTL_HID_WRITE_REPORT tests.
[wine.git] / dlls / wineandroid.drv / mmdevdrv.c
blobd9b7cde2c80af90cf44cfe33945a2a43fa41dd4b
1 /*
2 * Copyright 2015 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"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/ioctl.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <math.h>
37 #include <SLES/OpenSLES.h>
38 #include <SLES/OpenSLES_Android.h>
40 #include "android.h"
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winnls.h"
45 #include "winreg.h"
46 #include "wine/debug.h"
47 #include "wine/unicode.h"
48 #include "wine/list.h"
50 #include "ole2.h"
51 #include "mmdeviceapi.h"
52 #include "devpkey.h"
53 #include "dshow.h"
54 #include "dsound.h"
56 #include "initguid.h"
57 #include "endpointvolume.h"
58 #include "audiopolicy.h"
59 #include "audioclient.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(androidaudio);
63 #define DECL_FUNCPTR(f) static typeof(f) * p##f
64 DECL_FUNCPTR( slCreateEngine );
65 DECL_FUNCPTR( SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
66 DECL_FUNCPTR( SL_IID_ENGINE );
67 DECL_FUNCPTR( SL_IID_PLAY );
68 DECL_FUNCPTR( SL_IID_PLAYBACKRATE );
69 DECL_FUNCPTR( SL_IID_RECORD );
71 #define SLCALL_N(obj, func) (*obj)->func(obj)
72 #define SLCALL(obj, func, ...) (*obj)->func(obj, __VA_ARGS__)
74 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
76 static const REFERENCE_TIME DefaultPeriod = 100000;
77 static const REFERENCE_TIME MinimumPeriod = 50000;
79 struct ACImpl;
80 typedef struct ACImpl ACImpl;
82 typedef struct _AudioSession {
83 GUID guid;
84 struct list clients;
86 IMMDevice *device;
88 float master_vol;
89 UINT32 channel_count;
90 float *channel_vols;
91 BOOL mute;
93 CRITICAL_SECTION lock;
95 struct list entry;
96 } AudioSession;
98 typedef struct _AudioSessionWrapper {
99 IAudioSessionControl2 IAudioSessionControl2_iface;
100 IChannelAudioVolume IChannelAudioVolume_iface;
101 ISimpleAudioVolume ISimpleAudioVolume_iface;
103 LONG ref;
105 ACImpl *client;
106 AudioSession *session;
107 } AudioSessionWrapper;
109 struct ACImpl {
110 IAudioClient3 IAudioClient3_iface;
111 IAudioRenderClient IAudioRenderClient_iface;
112 IAudioCaptureClient IAudioCaptureClient_iface;
113 IAudioClock IAudioClock_iface;
114 IAudioClock2 IAudioClock2_iface;
115 IAudioStreamVolume IAudioStreamVolume_iface;
117 LONG ref;
119 IMMDevice *parent;
120 IUnknown *pUnkFTMarshal;
122 WAVEFORMATEX *fmt;
124 EDataFlow dataflow;
125 DWORD flags;
126 AUDCLNT_SHAREMODE share;
127 HANDLE event;
128 float *vols;
130 SLObjectItf player;
131 SLObjectItf recorder;
132 SLAndroidSimpleBufferQueueItf bufq;
133 SLPlayItf playitf;
134 SLRecordItf recorditf;
136 BOOL initted, playing;
137 UINT64 written_frames, last_pos_frames;
138 UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames, wrap_buffer_frames, in_sl_frames;
139 UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
141 BYTE *local_buffer, *tmp_buffer, *wrap_buffer;
142 LONG32 getbuf_last; /* <0 when using tmp_buffer */
143 HANDLE timer;
145 CRITICAL_SECTION lock;
147 AudioSession *session;
148 AudioSessionWrapper *session_wrapper;
150 struct list entry;
153 typedef struct _SessionMgr {
154 IAudioSessionManager2 IAudioSessionManager2_iface;
156 LONG ref;
158 IMMDevice *device;
159 } SessionMgr;
161 static struct list g_devices = LIST_INIT(g_devices);
163 static HANDLE g_timer_q;
165 static CRITICAL_SECTION g_sessions_lock;
166 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
168 0, 0, &g_sessions_lock,
169 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
170 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
172 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
173 static struct list g_sessions = LIST_INIT(g_sessions);
175 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
177 static const IAudioClient3Vtbl AudioClient3_Vtbl;
178 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
179 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
180 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
181 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
182 static const IAudioClockVtbl AudioClock_Vtbl;
183 static const IAudioClock2Vtbl AudioClock2_Vtbl;
184 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
185 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
186 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
188 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
190 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
193 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
195 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
198 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
200 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
203 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
205 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
208 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
210 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
213 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
215 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
218 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
220 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
223 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
225 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
228 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
230 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
233 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
235 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
238 #define LOAD_FUNCPTR(lib, func) do { \
239 if ((p##func = dlsym( lib, #func )) == NULL) \
240 { ERR( "can't find symbol %s\n", #func); return FALSE; } \
241 } while(0)
243 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
245 static BOOL WINAPI load_opensles( INIT_ONCE *once, void *param, void **context )
247 void *libopensles;
249 if (!(libopensles = dlopen( "libOpenSLES.so", RTLD_GLOBAL )))
251 ERR( "failed to load libOpenSLES.so: %s\n", dlerror() );
252 return FALSE;
254 LOAD_FUNCPTR( libopensles, slCreateEngine );
255 LOAD_FUNCPTR( libopensles, SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
256 LOAD_FUNCPTR( libopensles, SL_IID_ENGINE );
257 LOAD_FUNCPTR( libopensles, SL_IID_PLAY );
258 LOAD_FUNCPTR( libopensles, SL_IID_PLAYBACKRATE );
259 LOAD_FUNCPTR( libopensles, SL_IID_RECORD );
261 if (!(g_timer_q = CreateTimerQueue())) return FALSE;
263 return TRUE;
266 /* From <dlls/mmdevapi/mmdevapi.h> */
267 enum DriverPriority {
268 Priority_Unavailable = 0,
269 Priority_Low,
270 Priority_Neutral,
271 Priority_Preferred
274 int WINAPI AUDDRV_GetPriority(void)
276 if (!InitOnceExecuteOnce( &init_once, load_opensles, NULL, NULL ))
277 return Priority_Unavailable;
279 return Priority_Preferred;
282 static SLObjectItf sl;
283 static SLEngineItf engine;
284 static SLObjectItf outputmix;
286 HRESULT AUDDRV_Init(void)
288 static const SLEngineOption options[] = { {SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE} };
289 SLresult sr;
291 sr = pslCreateEngine(&sl, 1, options, 0, NULL, NULL);
292 if(sr != SL_RESULT_SUCCESS){
293 WARN("slCreateEngine failed: 0x%x\n", sr);
294 return E_FAIL;
297 sr = SLCALL(sl, Realize, SL_BOOLEAN_FALSE);
298 if(sr != SL_RESULT_SUCCESS){
299 SLCALL_N(sl, Destroy);
300 WARN("Engine Realize failed: 0x%x\n", sr);
301 return E_FAIL;
304 sr = SLCALL(sl, GetInterface, *pSL_IID_ENGINE, (void*)&engine);
305 if(sr != SL_RESULT_SUCCESS){
306 SLCALL_N(sl, Destroy);
307 WARN("GetInterface failed: 0x%x\n", sr);
308 return E_FAIL;
311 sr = SLCALL(engine, CreateOutputMix, &outputmix, 0, NULL, NULL);
312 if(sr != SL_RESULT_SUCCESS){
313 SLCALL_N(sl, Destroy);
314 WARN("CreateOutputMix failed: 0x%x\n", sr);
315 return E_FAIL;
318 sr = SLCALL(outputmix, Realize, SL_BOOLEAN_FALSE);
319 if(sr != SL_RESULT_SUCCESS){
320 SLCALL_N(outputmix, Destroy);
321 SLCALL_N(sl, Destroy);
322 WARN("outputmix Realize failed: 0x%x\n", sr);
323 return E_FAIL;
326 return S_OK;
329 static const GUID outGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x00}};
330 static const GUID inGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x01}};
332 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids,
333 UINT *num, UINT *def_index)
335 static const WCHAR outName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','O','u','t',0};
336 static const WCHAR inName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','I','n',0};
338 TRACE("%u %p %p %p %p\n", flow, ids, guids, num, def_index);
340 *def_index = 0;
341 *num = 1;
342 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
343 *guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
344 if(flow == eRender){
345 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(outName));
346 memcpy((*ids)[0], outName, sizeof(outName));
347 memcpy(&(*guids)[0], &outGuid, sizeof(outGuid));
348 }else{
349 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(inName));
350 memcpy((*ids)[0], inName, sizeof(inName));
351 memcpy(&(*guids)[0], &inGuid, sizeof(inGuid));
354 return S_OK;
357 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
358 IAudioClient **out)
360 ACImpl *This;
361 HRESULT hr;
362 EDataFlow flow;
364 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
366 if(!sl)
367 AUDDRV_Init();
369 if(IsEqualGUID(guid, &outGuid))
370 flow = eRender;
371 else if(IsEqualGUID(guid, &inGuid))
372 flow = eCapture;
373 else
374 return AUDCLNT_E_DEVICE_INVALIDATED;
376 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
377 if(!This)
378 return E_OUTOFMEMORY;
380 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
381 if (FAILED(hr)) {
382 HeapFree(GetProcessHeap(), 0, This);
383 return hr;
386 This->dataflow = flow;
388 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
389 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
390 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
391 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
392 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
393 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
395 InitializeCriticalSection(&This->lock);
396 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
398 This->parent = dev;
399 IMMDevice_AddRef(This->parent);
401 *out = (IAudioClient *)&This->IAudioClient3_iface;
402 IAudioClient3_AddRef(&This->IAudioClient3_iface);
404 return S_OK;
407 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
408 REFIID riid, void **ppv)
410 ACImpl *This = impl_from_IAudioClient3(iface);
411 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
413 if(!ppv)
414 return E_POINTER;
415 *ppv = NULL;
416 if(IsEqualIID(riid, &IID_IUnknown) ||
417 IsEqualIID(riid, &IID_IAudioClient) ||
418 IsEqualIID(riid, &IID_IAudioClient2) ||
419 IsEqualIID(riid, &IID_IAudioClient3))
420 *ppv = iface;
421 else if(IsEqualIID(riid, &IID_IMarshal))
422 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
423 if(*ppv){
424 IUnknown_AddRef((IUnknown*)*ppv);
425 return S_OK;
427 WARN("Unknown interface %s\n", debugstr_guid(riid));
428 return E_NOINTERFACE;
431 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
433 ACImpl *This = impl_from_IAudioClient3(iface);
434 ULONG ref;
435 ref = InterlockedIncrement(&This->ref);
436 TRACE("(%p) Refcount now %u\n", This, ref);
437 return ref;
440 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
442 ACImpl *This = impl_from_IAudioClient3(iface);
443 ULONG ref;
445 ref = InterlockedDecrement(&This->ref);
446 TRACE("(%p) Refcount now %u\n", This, ref);
447 if(!ref){
448 if(This->timer){
449 HANDLE event;
450 DWORD wait;
451 event = CreateEventW(NULL, TRUE, FALSE, NULL);
452 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
453 wait = wait && GetLastError() == ERROR_IO_PENDING;
454 if(event && wait)
455 WaitForSingleObject(event, INFINITE);
456 CloseHandle(event);
459 IAudioClient3_Stop(iface);
461 IMMDevice_Release(This->parent);
462 IUnknown_Release(This->pUnkFTMarshal);
463 This->lock.DebugInfo->Spare[0] = 0;
464 DeleteCriticalSection(&This->lock);
466 if(This->recorder)
467 SLCALL_N(This->recorder, Destroy);
468 if(This->player)
469 SLCALL_N(This->player, Destroy);
471 if(This->initted){
472 EnterCriticalSection(&g_sessions_lock);
473 list_remove(&This->entry);
474 LeaveCriticalSection(&g_sessions_lock);
476 HeapFree(GetProcessHeap(), 0, This->vols);
477 HeapFree(GetProcessHeap(), 0, This->local_buffer);
478 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
479 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
480 CoTaskMemFree(This->fmt);
481 HeapFree(GetProcessHeap(), 0, This);
483 return ref;
486 static void dump_fmt(const WAVEFORMATEX *fmt)
488 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
489 switch(fmt->wFormatTag){
490 case WAVE_FORMAT_PCM:
491 TRACE("WAVE_FORMAT_PCM");
492 break;
493 case WAVE_FORMAT_IEEE_FLOAT:
494 TRACE("WAVE_FORMAT_IEEE_FLOAT");
495 break;
496 case WAVE_FORMAT_EXTENSIBLE:
497 TRACE("WAVE_FORMAT_EXTENSIBLE");
498 break;
499 default:
500 TRACE("Unknown");
501 break;
503 TRACE(")\n");
505 TRACE("nChannels: %u\n", fmt->nChannels);
506 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
507 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
508 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
509 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
510 TRACE("cbSize: %u\n", fmt->cbSize);
512 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
513 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
514 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
515 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
516 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
520 static DWORD get_channel_mask(unsigned int channels)
522 switch(channels){
523 case 0:
524 return 0;
525 case 1:
526 return KSAUDIO_SPEAKER_MONO;
527 case 2:
528 return KSAUDIO_SPEAKER_STEREO;
529 case 3:
530 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
531 case 4:
532 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
533 case 5:
534 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
535 case 6:
536 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
537 case 7:
538 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
539 case 8:
540 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
542 FIXME("Unknown speaker configuration: %u\n", channels);
543 return 0;
546 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
548 WAVEFORMATEX *ret;
549 size_t size;
551 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
552 size = sizeof(WAVEFORMATEXTENSIBLE);
553 else
554 size = sizeof(WAVEFORMATEX);
556 ret = CoTaskMemAlloc(size);
557 if(!ret)
558 return NULL;
560 memcpy(ret, fmt, size);
562 ret->cbSize = size - sizeof(WAVEFORMATEX);
564 return ret;
567 static void session_init_vols(AudioSession *session, UINT channels)
569 if(session->channel_count < channels){
570 UINT i;
572 if(session->channel_vols)
573 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
574 session->channel_vols, sizeof(float) * channels);
575 else
576 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
577 sizeof(float) * channels);
578 if(!session->channel_vols)
579 return;
581 for(i = session->channel_count; i < channels; ++i)
582 session->channel_vols[i] = 1.f;
584 session->channel_count = channels;
588 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
589 UINT num_channels)
591 AudioSession *ret;
593 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
594 if(!ret)
595 return NULL;
597 memcpy(&ret->guid, guid, sizeof(GUID));
599 ret->device = device;
601 list_init(&ret->clients);
603 list_add_head(&g_sessions, &ret->entry);
605 InitializeCriticalSection(&ret->lock);
606 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
608 session_init_vols(ret, num_channels);
610 ret->master_vol = 1.f;
612 return ret;
615 /* if channels == 0, then this will return or create a session with
616 * matching dataflow and GUID. otherwise, channels must also match */
617 static HRESULT get_audio_session(const GUID *sessionguid,
618 IMMDevice *device, UINT channels, AudioSession **out)
620 AudioSession *session;
622 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
623 *out = create_session(&GUID_NULL, device, channels);
624 if(!*out)
625 return E_OUTOFMEMORY;
627 return S_OK;
630 *out = NULL;
631 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
632 if(session->device == device &&
633 IsEqualGUID(sessionguid, &session->guid)){
634 session_init_vols(session, channels);
635 *out = session;
636 break;
640 if(!*out){
641 *out = create_session(sessionguid, device, channels);
642 if(!*out)
643 return E_OUTOFMEMORY;
646 return S_OK;
649 static HRESULT waveformat_to_pcm(ACImpl *This, const WAVEFORMATEX *fmt, SLAndroidDataFormat_PCM_EX *pcm)
651 if(fmt->nSamplesPerSec < 8000 || fmt->nSamplesPerSec > 48000)
652 return AUDCLNT_E_UNSUPPORTED_FORMAT;
654 pcm->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
656 pcm->sampleRate = fmt->nSamplesPerSec * 1000; /* sampleRate is in milli-Hz */
657 pcm->bitsPerSample = fmt->wBitsPerSample;
658 pcm->containerSize = fmt->wBitsPerSample;
660 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
661 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
662 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
663 if(pcm->bitsPerSample == 8)
664 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
665 else if(pcm->bitsPerSample == 16)
666 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
667 else
668 return AUDCLNT_E_UNSUPPORTED_FORMAT;
669 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
670 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
671 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
672 if(pcm->bitsPerSample == 32)
673 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
674 else
675 return AUDCLNT_E_UNSUPPORTED_FORMAT;
676 }else
677 return AUDCLNT_E_UNSUPPORTED_FORMAT;
679 /* only up to stereo */
680 pcm->numChannels = fmt->nChannels;
681 if(pcm->numChannels == 1)
682 pcm->channelMask = SL_SPEAKER_FRONT_CENTER;
683 else if(This->dataflow == eRender && pcm->numChannels == 2)
684 pcm->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
685 else
686 return AUDCLNT_E_UNSUPPORTED_FORMAT;
688 pcm->endianness = SL_BYTEORDER_LITTLEENDIAN;
690 return S_OK;
693 static HRESULT try_open_render_device(SLAndroidDataFormat_PCM_EX *pcm, unsigned int num_buffers, SLObjectItf *out)
695 SLresult sr;
696 SLDataSource source;
697 SLDataSink sink;
698 SLDataLocator_OutputMix loc_outmix;
699 SLboolean required[2];
700 SLInterfaceID iids[2];
701 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
702 SLObjectItf player;
704 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
705 loc_bq.numBuffers = num_buffers;
706 source.pLocator = &loc_bq;
707 source.pFormat = pcm;
709 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
710 loc_outmix.outputMix = outputmix;
711 sink.pLocator = &loc_outmix;
712 sink.pFormat = NULL;
714 required[0] = SL_BOOLEAN_TRUE;
715 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
716 required[1] = SL_BOOLEAN_TRUE;
717 iids[1] = *pSL_IID_PLAYBACKRATE;
719 sr = SLCALL(engine, CreateAudioPlayer, &player, &source, &sink,
720 2, iids, required);
721 if(sr != SL_RESULT_SUCCESS){
722 WARN("CreateAudioPlayer failed: 0x%x\n", sr);
723 return E_FAIL;
726 sr = SLCALL(player, Realize, SL_BOOLEAN_FALSE);
727 if(sr != SL_RESULT_SUCCESS){
728 SLCALL_N(player, Destroy);
729 WARN("Player Realize failed: 0x%x\n", sr);
730 return E_FAIL;
733 if(out)
734 *out = player;
735 else
736 SLCALL_N(player, Destroy);
738 return S_OK;
741 static HRESULT try_open_capture_device(SLAndroidDataFormat_PCM_EX *pcm, unsigned int num_buffers, SLObjectItf *out)
743 SLresult sr;
744 SLDataSource source;
745 SLDataSink sink;
746 SLDataLocator_IODevice loc_mic;
747 SLboolean required[1];
748 SLInterfaceID iids[1];
749 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
750 SLObjectItf recorder;
752 loc_mic.locatorType = SL_DATALOCATOR_IODEVICE;
753 loc_mic.deviceType = SL_IODEVICE_AUDIOINPUT;
754 loc_mic.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
755 loc_mic.device = NULL;
756 source.pLocator = &loc_mic;
757 source.pFormat = NULL;
759 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
760 loc_bq.numBuffers = num_buffers;
761 sink.pLocator = &loc_bq;
762 sink.pFormat = pcm;
764 required[0] = SL_BOOLEAN_TRUE;
765 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
767 sr = SLCALL(engine, CreateAudioRecorder, &recorder, &source, &sink,
768 1, iids, required);
769 if(sr != SL_RESULT_SUCCESS){
770 WARN("CreateAudioRecorder failed: 0x%x\n", sr);
771 return E_FAIL;
774 sr = SLCALL(recorder, Realize, SL_BOOLEAN_FALSE);
775 if(sr != SL_RESULT_SUCCESS){
776 SLCALL_N(recorder, Destroy);
777 WARN("Recorder Realize failed: 0x%x\n", sr);
778 return E_FAIL;
781 if(out)
782 *out = recorder;
783 else
784 SLCALL_N(recorder, Destroy);
786 return S_OK;
789 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
790 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
791 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
792 const GUID *sessionguid)
794 ACImpl *This = impl_from_IAudioClient3(iface);
795 int i, num_buffers;
796 HRESULT hr;
797 SLresult sr;
798 SLAndroidDataFormat_PCM_EX pcm;
800 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
801 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
803 if(!fmt)
804 return E_POINTER;
806 dump_fmt(fmt);
808 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
809 return E_INVALIDARG;
811 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
812 AUDCLNT_STREAMFLAGS_LOOPBACK |
813 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
814 AUDCLNT_STREAMFLAGS_NOPERSIST |
815 AUDCLNT_STREAMFLAGS_RATEADJUST |
816 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
817 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
818 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
819 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
820 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
821 FIXME("Unknown flags: %08x\n", flags);
822 return E_INVALIDARG;
825 if(mode == AUDCLNT_SHAREMODE_SHARED){
826 period = DefaultPeriod;
827 if( duration < 3 * period)
828 duration = 3 * period;
829 }else{
830 if(!period)
831 period = DefaultPeriod; /* not minimum */
832 if(period < MinimumPeriod || period > 5000000)
833 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
834 if(duration > 20000000) /* the smaller the period, the lower this limit */
835 return AUDCLNT_E_BUFFER_SIZE_ERROR;
836 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
837 if(duration != period)
838 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
839 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
840 return AUDCLNT_E_DEVICE_IN_USE;
841 }else{
842 if( duration < 8 * period)
843 duration = 8 * period; /* may grow above 2s */
847 EnterCriticalSection(&This->lock);
849 if(This->initted){
850 LeaveCriticalSection(&This->lock);
851 return AUDCLNT_E_ALREADY_INITIALIZED;
854 This->period_us = period / 10;
855 This->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
857 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
858 if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
859 This->bufsize_frames -= This->bufsize_frames % This->period_frames;
860 else if(This->bufsize_frames % This->period_frames != 0)
861 /* hack: round up to integer multiple */
862 This->bufsize_frames += This->period_frames - This->bufsize_frames % This->period_frames;
864 hr = waveformat_to_pcm(This, fmt, &pcm);
865 if(FAILED(hr)){
866 LeaveCriticalSection(&This->lock);
867 return hr;
870 num_buffers = This->bufsize_frames / This->period_frames;
872 if(This->dataflow == eRender){
873 hr = try_open_render_device(&pcm, num_buffers, &This->player);
874 if(FAILED(hr)){
875 LeaveCriticalSection(&This->lock);
876 return hr;
879 sr = SLCALL(This->player, GetInterface, *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE, &This->bufq);
880 if(sr != SL_RESULT_SUCCESS){
881 SLCALL_N(This->player, Destroy);
882 This->player = NULL;
883 WARN("Player GetInterface(BufferQueue) failed: 0x%x\n", sr);
884 LeaveCriticalSection(&This->lock);
885 return E_FAIL;
888 sr = SLCALL(This->player, GetInterface, *pSL_IID_PLAY, &This->playitf);
889 if(sr != SL_RESULT_SUCCESS){
890 SLCALL_N(This->player, Destroy);
891 This->player = NULL;
892 WARN("Player GetInterface(Play) failed: 0x%x\n", sr);
893 LeaveCriticalSection(&This->lock);
894 return E_FAIL;
896 }else{
897 hr = try_open_capture_device(&pcm, num_buffers, &This->recorder);
898 if(FAILED(hr)){
899 LeaveCriticalSection(&This->lock);
900 return hr;
903 sr = SLCALL(This->recorder, GetInterface, *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE, &This->bufq);
904 if(sr != SL_RESULT_SUCCESS){
905 SLCALL_N(This->recorder, Destroy);
906 This->recorder = NULL;
907 WARN("Recorder GetInterface(BufferQueue) failed: 0x%x\n", sr);
908 LeaveCriticalSection(&This->lock);
909 return E_FAIL;
912 sr = SLCALL(This->recorder, GetInterface, *pSL_IID_RECORD, &This->recorditf);
913 if(sr != SL_RESULT_SUCCESS){
914 SLCALL_N(This->recorder, Destroy);
915 This->recorder = NULL;
916 WARN("Recorder GetInterface(Record) failed: 0x%x\n", sr);
917 LeaveCriticalSection(&This->lock);
918 return E_FAIL;
922 This->fmt = clone_format(fmt);
923 if(!This->fmt){
924 if(This->player){
925 SLCALL_N(This->player, Destroy);
926 This->player = NULL;
928 if(This->recorder){
929 SLCALL_N(This->recorder, Destroy);
930 This->recorder = NULL;
932 LeaveCriticalSection(&This->lock);
933 return E_OUTOFMEMORY;
936 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
937 This->bufsize_frames * fmt->nBlockAlign);
938 if(!This->local_buffer){
939 CoTaskMemFree(This->fmt);
940 This->fmt = NULL;
941 if(This->player){
942 SLCALL_N(This->player, Destroy);
943 This->player = NULL;
945 if(This->recorder){
946 SLCALL_N(This->recorder, Destroy);
947 This->recorder = NULL;
949 LeaveCriticalSection(&This->lock);
950 return E_OUTOFMEMORY;
953 if(This->dataflow == eCapture){
954 while(This->in_sl_frames < This->bufsize_frames){
955 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
956 sr = SLCALL(This->bufq, Enqueue,
957 This->local_buffer + ((This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
958 This->period_frames * This->fmt->nBlockAlign);
959 if(sr != SL_RESULT_SUCCESS)
960 WARN("Enqueue failed: 0x%x\n", sr);
961 This->in_sl_frames += This->period_frames;
965 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
966 if(!This->vols){
967 CoTaskMemFree(This->fmt);
968 This->fmt = NULL;
969 if(This->player){
970 SLCALL_N(This->player, Destroy);
971 This->player = NULL;
973 if(This->recorder){
974 SLCALL_N(This->recorder, Destroy);
975 This->recorder = NULL;
977 LeaveCriticalSection(&This->lock);
978 return E_OUTOFMEMORY;
981 for(i = 0; i < fmt->nChannels; ++i)
982 This->vols[i] = 1.f;
984 This->share = mode;
985 This->flags = flags;
986 This->oss_bufsize_bytes = 0;
988 EnterCriticalSection(&g_sessions_lock);
990 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
991 &This->session);
992 if(FAILED(hr)){
993 LeaveCriticalSection(&g_sessions_lock);
994 HeapFree(GetProcessHeap(), 0, This->vols);
995 This->vols = NULL;
996 CoTaskMemFree(This->fmt);
997 This->fmt = NULL;
998 if(This->player){
999 SLCALL_N(This->player, Destroy);
1000 This->player = NULL;
1002 if(This->recorder){
1003 SLCALL_N(This->recorder, Destroy);
1004 This->recorder = NULL;
1006 LeaveCriticalSection(&This->lock);
1007 return hr;
1010 list_add_tail(&This->session->clients, &This->entry);
1012 LeaveCriticalSection(&g_sessions_lock);
1014 This->initted = TRUE;
1016 TRACE("numBuffers: %u, bufsize: %u, period: %u\n", num_buffers,
1017 This->bufsize_frames, This->period_frames);
1019 LeaveCriticalSection(&This->lock);
1021 return S_OK;
1024 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
1025 UINT32 *frames)
1027 ACImpl *This = impl_from_IAudioClient3(iface);
1029 TRACE("(%p)->(%p)\n", This, frames);
1031 if(!frames)
1032 return E_POINTER;
1034 EnterCriticalSection(&This->lock);
1036 if(!This->initted){
1037 LeaveCriticalSection(&This->lock);
1038 return AUDCLNT_E_NOT_INITIALIZED;
1041 *frames = This->bufsize_frames;
1043 TRACE("buffer size: %u\n", *frames);
1045 LeaveCriticalSection(&This->lock);
1047 return S_OK;
1050 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
1051 REFERENCE_TIME *latency)
1053 ACImpl *This = impl_from_IAudioClient3(iface);
1055 TRACE("(%p)->(%p)\n", This, latency);
1057 if(!latency)
1058 return E_POINTER;
1060 EnterCriticalSection(&This->lock);
1062 if(!This->initted){
1063 LeaveCriticalSection(&This->lock);
1064 return AUDCLNT_E_NOT_INITIALIZED;
1067 /* pretend we process audio in Period chunks, so max latency includes
1068 * the period time. Some native machines add .6666ms in shared mode. */
1069 *latency = This->period_us * 10 + 6666;
1071 LeaveCriticalSection(&This->lock);
1073 return S_OK;
1076 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
1077 UINT32 *numpad)
1079 ACImpl *This = impl_from_IAudioClient3(iface);
1081 TRACE("(%p)->(%p)\n", This, numpad);
1083 if(!numpad)
1084 return E_POINTER;
1086 EnterCriticalSection(&This->lock);
1088 if(!This->initted){
1089 LeaveCriticalSection(&This->lock);
1090 return AUDCLNT_E_NOT_INITIALIZED;
1093 *numpad = This->held_frames;
1095 TRACE("padding: %u\n", *numpad);
1097 LeaveCriticalSection(&This->lock);
1099 return S_OK;
1102 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
1103 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1104 WAVEFORMATEX **outpwfx)
1106 ACImpl *This = impl_from_IAudioClient3(iface);
1107 SLAndroidDataFormat_PCM_EX pcm;
1108 HRESULT hr;
1110 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1112 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1113 return E_POINTER;
1115 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1116 return E_INVALIDARG;
1118 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1119 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1120 return E_INVALIDARG;
1122 dump_fmt(pwfx);
1124 if(outpwfx)
1125 *outpwfx = NULL;
1127 hr = waveformat_to_pcm(This, pwfx, &pcm);
1128 if(SUCCEEDED(hr)){
1129 if(This->dataflow == eRender){
1130 hr = try_open_render_device(&pcm, 10, NULL);
1131 }else{
1132 hr = try_open_capture_device(&pcm, 10, NULL);
1136 if(FAILED(hr)){
1137 if(outpwfx){
1138 hr = IAudioClient3_GetMixFormat(iface, outpwfx);
1139 if(FAILED(hr))
1140 return hr;
1141 return S_FALSE;
1144 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1147 TRACE("returning: %08x\n", hr);
1149 return hr;
1152 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
1153 WAVEFORMATEX **pwfx)
1155 ACImpl *This = impl_from_IAudioClient3(iface);
1156 WAVEFORMATEXTENSIBLE *fmt;
1158 TRACE("(%p)->(%p)\n", This, pwfx);
1160 if(!pwfx)
1161 return E_POINTER;
1162 *pwfx = NULL;
1164 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1165 if(!fmt)
1166 return E_OUTOFMEMORY;
1168 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1169 fmt->Format.wBitsPerSample = 16;
1170 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1171 if(This->dataflow == eRender)
1172 fmt->Format.nChannels = 2;
1173 else
1174 fmt->Format.nChannels = 1;
1175 fmt->Format.nSamplesPerSec = 48000; /* TODO: query supported? recording? */
1176 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1177 fmt->Format.nChannels) / 8;
1178 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1179 fmt->Format.nBlockAlign;
1180 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1181 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1182 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1184 *pwfx = (WAVEFORMATEX*)fmt;
1185 dump_fmt(*pwfx);
1187 return S_OK;
1190 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
1191 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1193 ACImpl *This = impl_from_IAudioClient3(iface);
1195 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1197 if(!defperiod && !minperiod)
1198 return E_POINTER;
1200 if(defperiod)
1201 *defperiod = DefaultPeriod;
1202 if(minperiod)
1203 *minperiod = MinimumPeriod;
1205 return S_OK;
1208 static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
1210 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1211 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1212 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1213 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1214 This->fmt->wBitsPerSample == 8)
1215 memset(buffer, 128, frames * This->fmt->nBlockAlign);
1216 else
1217 memset(buffer, 0, frames * This->fmt->nBlockAlign);
1220 static void sl_read_data(ACImpl *This)
1222 SLAndroidSimpleBufferQueueState state;
1223 SLresult sr;
1224 SLuint32 elapsed;
1226 memset(&state, 0, sizeof(state));
1228 sr = SLCALL(This->bufq, GetState, &state);
1229 if(sr != SL_RESULT_SUCCESS){
1230 WARN("GetState failed: 0x%x\n", sr);
1231 return;
1233 TRACE("got: count: %u, index: %u, held: %u, in_sl: %u\n", state.count, state.index, This->held_frames, This->in_sl_frames);
1235 elapsed = This->in_sl_frames - state.count * This->period_frames;
1236 This->held_frames += elapsed;
1237 This->in_sl_frames = state.count * This->period_frames;
1239 if(This->held_frames == This->bufsize_frames){
1240 /* overrun */
1241 TRACE("overrun??\n");
1242 This->lcl_offs_frames += This->period_frames;
1243 This->held_frames -= This->period_frames;
1246 TRACE("good range: %u, %u\n", This->lcl_offs_frames, This->lcl_offs_frames + This->held_frames);
1247 TRACE("held: %u, in_sl: %u\n", This->held_frames, This->in_sl_frames);
1248 while(This->held_frames + This->in_sl_frames < This->bufsize_frames){
1249 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->held_frames + This->in_sl_frames) % This->bufsize_frames);
1250 sr = SLCALL(This->bufq, Enqueue,
1251 This->local_buffer + ((This->lcl_offs_frames + This->held_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
1252 This->period_frames * This->fmt->nBlockAlign);
1253 if(sr != SL_RESULT_SUCCESS)
1254 WARN("Enqueue failed: 0x%x\n", sr);
1255 This->in_sl_frames += This->period_frames;
1259 static DWORD wrap_enqueue(ACImpl *This)
1261 DWORD to_enqueue = min(This->held_frames, This->period_frames);
1262 DWORD offs = (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames;
1263 BYTE *buf = This->local_buffer + offs * This->fmt->nBlockAlign;
1265 if(offs + to_enqueue > This->bufsize_frames){
1266 DWORD chunk = This->bufsize_frames - offs;
1268 if(This->wrap_buffer_frames < to_enqueue){
1269 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
1270 This->wrap_buffer = HeapAlloc(GetProcessHeap(), 0, to_enqueue * This->fmt->nBlockAlign);
1271 This->wrap_buffer_frames = to_enqueue;
1274 memcpy(This->wrap_buffer, This->local_buffer + offs * This->fmt->nBlockAlign, chunk * This->fmt->nBlockAlign);
1275 memcpy(This->wrap_buffer + chunk * This->fmt->nBlockAlign, This->local_buffer, (to_enqueue - chunk) * This->fmt->nBlockAlign);
1277 buf = This->wrap_buffer;
1280 SLCALL(This->bufq, Enqueue, buf,
1281 to_enqueue * This->fmt->nBlockAlign);
1283 return to_enqueue;
1286 static void sl_write_data(ACImpl *This)
1288 SLAndroidSimpleBufferQueueState state;
1289 SLresult sr;
1290 SLuint32 elapsed;
1292 memset(&state, 0, sizeof(state));
1294 sr = SLCALL(This->bufq, GetState, &state);
1295 if(sr != SL_RESULT_SUCCESS){
1296 WARN("GetState failed: 0x%x\n", sr);
1297 return;
1299 TRACE("got: count: %u, index: %u\n", state.count, state.index);
1301 elapsed = This->in_sl_frames - state.count * This->period_frames;
1303 if(elapsed > This->held_frames)
1304 This->held_frames = 0;
1305 else
1306 This->held_frames -= elapsed;
1308 This->lcl_offs_frames += elapsed;
1309 This->lcl_offs_frames %= This->bufsize_frames;
1311 This->in_sl_frames = state.count * This->period_frames;
1313 while(This->held_frames >= This->in_sl_frames + This->period_frames){
1314 /* have at least a period to write, so write it */
1315 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1316 This->in_sl_frames += wrap_enqueue(This);
1319 if(This->held_frames && This->in_sl_frames < This->period_frames * 3){
1320 /* write out the last bit with a partial period */
1321 TRACE("enqueueing partial period: %u frames from %u\n", This->held_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1322 This->in_sl_frames += wrap_enqueue(This);
1325 TRACE("done with enqueue, lcl_offs: %u, in_sl: %u, held: %u\n", This->lcl_offs_frames, This->in_sl_frames, This->held_frames);
1328 static void CALLBACK sl_period_callback(void *user, BOOLEAN timer)
1330 ACImpl *This = user;
1332 EnterCriticalSection(&This->lock);
1334 if(This->playing){
1335 if(This->dataflow == eRender)
1336 sl_write_data(This);
1337 else if(This->dataflow == eCapture)
1338 sl_read_data(This);
1341 LeaveCriticalSection(&This->lock);
1343 if(This->event)
1344 SetEvent(This->event);
1347 static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
1349 ACImpl *This = impl_from_IAudioClient3(iface);
1350 SLresult sr;
1352 TRACE("(%p)\n", This);
1354 EnterCriticalSection(&This->lock);
1356 if(!This->initted){
1357 LeaveCriticalSection(&This->lock);
1358 return AUDCLNT_E_NOT_INITIALIZED;
1361 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1362 LeaveCriticalSection(&This->lock);
1363 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1366 if(This->playing){
1367 LeaveCriticalSection(&This->lock);
1368 return AUDCLNT_E_NOT_STOPPED;
1371 if(This->dataflow == eRender){
1372 sr = SLCALL(This->playitf, SetPlayState, SL_PLAYSTATE_PLAYING);
1373 if(sr != SL_RESULT_SUCCESS){
1374 WARN("SetPlayState failed: 0x%x\n", sr);
1375 LeaveCriticalSection(&This->lock);
1376 return E_FAIL;
1378 }else{
1379 sr = SLCALL(This->recorditf, SetRecordState, SL_RECORDSTATE_RECORDING);
1380 if(sr != SL_RESULT_SUCCESS){
1381 WARN("SetRecordState failed: 0x%x\n", sr);
1382 LeaveCriticalSection(&This->lock);
1383 return E_FAIL;
1387 if(!This->timer){
1388 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1389 sl_period_callback, This, 0, This->period_us / 1000,
1390 WT_EXECUTEINTIMERTHREAD))
1391 WARN("Unable to create period timer: %u\n", GetLastError());
1394 This->playing = TRUE;
1396 LeaveCriticalSection(&This->lock);
1398 return S_OK;
1401 static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
1403 ACImpl *This = impl_from_IAudioClient3(iface);
1404 SLresult sr;
1406 TRACE("(%p)\n", This);
1408 EnterCriticalSection(&This->lock);
1410 if(!This->initted){
1411 LeaveCriticalSection(&This->lock);
1412 return AUDCLNT_E_NOT_INITIALIZED;
1415 if(!This->playing){
1416 LeaveCriticalSection(&This->lock);
1417 return S_FALSE;
1420 if(This->dataflow == eRender){
1421 sr = SLCALL(This->playitf, SetPlayState, SL_PLAYSTATE_PAUSED);
1422 if(sr != SL_RESULT_SUCCESS){
1423 WARN("SetPlayState failed: 0x%x\n", sr);
1424 LeaveCriticalSection(&This->lock);
1425 return E_FAIL;
1427 }else{
1428 sr = SLCALL(This->recorditf, SetRecordState, SL_RECORDSTATE_STOPPED);
1429 if(sr != SL_RESULT_SUCCESS){
1430 WARN("SetRecordState failed: 0x%x\n", sr);
1431 LeaveCriticalSection(&This->lock);
1432 return E_FAIL;
1436 This->playing = FALSE;
1438 LeaveCriticalSection(&This->lock);
1440 return S_OK;
1443 static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
1445 ACImpl *This = impl_from_IAudioClient3(iface);
1446 SLresult sr;
1448 TRACE("(%p)\n", This);
1450 EnterCriticalSection(&This->lock);
1452 if(!This->initted){
1453 LeaveCriticalSection(&This->lock);
1454 return AUDCLNT_E_NOT_INITIALIZED;
1457 if(This->playing){
1458 LeaveCriticalSection(&This->lock);
1459 return AUDCLNT_E_NOT_STOPPED;
1462 if(This->getbuf_last){
1463 LeaveCriticalSection(&This->lock);
1464 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1467 sr = SLCALL_N(This->bufq, Clear);
1468 if(sr != SL_RESULT_SUCCESS){
1469 WARN("Clear failed: 0x%x\n", sr);
1470 LeaveCriticalSection(&This->lock);
1471 return E_FAIL;
1474 This->lcl_offs_frames = 0;
1475 This->in_sl_frames = 0;
1477 if(This->dataflow == eRender){
1478 This->written_frames = 0;
1479 This->last_pos_frames = 0;
1480 }else{
1481 This->written_frames += This->held_frames;
1482 while(This->in_sl_frames < This->bufsize_frames){
1483 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1484 sr = SLCALL(This->bufq, Enqueue,
1485 This->local_buffer + ((This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
1486 This->period_frames * This->fmt->nBlockAlign);
1487 if(sr != SL_RESULT_SUCCESS)
1488 WARN("Enqueue failed: 0x%x\n", sr);
1489 This->in_sl_frames += This->period_frames;
1493 This->held_frames = 0;
1495 LeaveCriticalSection(&This->lock);
1497 return S_OK;
1500 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
1501 HANDLE event)
1503 ACImpl *This = impl_from_IAudioClient3(iface);
1505 TRACE("(%p)->(%p)\n", This, event);
1507 if(!event)
1508 return E_INVALIDARG;
1510 EnterCriticalSection(&This->lock);
1512 if(!This->initted){
1513 LeaveCriticalSection(&This->lock);
1514 return AUDCLNT_E_NOT_INITIALIZED;
1517 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1518 LeaveCriticalSection(&This->lock);
1519 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1522 if (This->event){
1523 LeaveCriticalSection(&This->lock);
1524 FIXME("called twice\n");
1525 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1528 This->event = event;
1530 LeaveCriticalSection(&This->lock);
1532 return S_OK;
1535 static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
1536 void **ppv)
1538 ACImpl *This = impl_from_IAudioClient3(iface);
1540 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1542 if(!ppv)
1543 return E_POINTER;
1544 *ppv = NULL;
1546 EnterCriticalSection(&This->lock);
1548 if(!This->initted){
1549 LeaveCriticalSection(&This->lock);
1550 return AUDCLNT_E_NOT_INITIALIZED;
1553 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1554 if(This->dataflow != eRender){
1555 LeaveCriticalSection(&This->lock);
1556 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1558 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1559 *ppv = &This->IAudioRenderClient_iface;
1560 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1561 if(This->dataflow != eCapture){
1562 LeaveCriticalSection(&This->lock);
1563 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1565 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1566 *ppv = &This->IAudioCaptureClient_iface;
1567 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1568 IAudioClock_AddRef(&This->IAudioClock_iface);
1569 *ppv = &This->IAudioClock_iface;
1570 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1571 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1572 *ppv = &This->IAudioStreamVolume_iface;
1573 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1574 if(!This->session_wrapper){
1575 This->session_wrapper = AudioSessionWrapper_Create(This);
1576 if(!This->session_wrapper){
1577 LeaveCriticalSection(&This->lock);
1578 return E_OUTOFMEMORY;
1580 }else
1581 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1583 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1584 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1585 if(!This->session_wrapper){
1586 This->session_wrapper = AudioSessionWrapper_Create(This);
1587 if(!This->session_wrapper){
1588 LeaveCriticalSection(&This->lock);
1589 return E_OUTOFMEMORY;
1591 }else
1592 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1594 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1595 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1596 if(!This->session_wrapper){
1597 This->session_wrapper = AudioSessionWrapper_Create(This);
1598 if(!This->session_wrapper){
1599 LeaveCriticalSection(&This->lock);
1600 return E_OUTOFMEMORY;
1602 }else
1603 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1605 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1608 if(*ppv){
1609 LeaveCriticalSection(&This->lock);
1610 return S_OK;
1613 LeaveCriticalSection(&This->lock);
1615 FIXME("stub %s\n", debugstr_guid(riid));
1616 return E_NOINTERFACE;
1619 static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1620 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1622 ACImpl *This = impl_from_IAudioClient3(iface);
1624 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1626 if(!offload_capable)
1627 return E_INVALIDARG;
1629 *offload_capable = FALSE;
1631 return S_OK;
1634 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1635 const AudioClientProperties *prop)
1637 ACImpl *This = impl_from_IAudioClient3(iface);
1638 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1640 TRACE("(%p)->(%p)\n", This, prop);
1642 if(!legacy_prop)
1643 return E_POINTER;
1645 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1646 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1647 legacy_prop->bIsOffload,
1648 legacy_prop->eCategory,
1649 prop->Options);
1650 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1651 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1652 legacy_prop->bIsOffload,
1653 legacy_prop->eCategory);
1654 }else{
1655 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1656 return E_INVALIDARG;
1660 if(legacy_prop->bIsOffload)
1661 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1663 return S_OK;
1666 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1667 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1668 REFERENCE_TIME *max_duration)
1670 ACImpl *This = impl_from_IAudioClient3(iface);
1672 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1674 return E_NOTIMPL;
1677 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1678 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1679 UINT32 *min_period_frames, UINT32 *max_period_frames)
1681 ACImpl *This = impl_from_IAudioClient3(iface);
1683 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1684 min_period_frames, max_period_frames);
1686 return E_NOTIMPL;
1689 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1690 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1692 ACImpl *This = impl_from_IAudioClient3(iface);
1694 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1696 return E_NOTIMPL;
1699 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1700 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1701 const GUID *session_guid)
1703 ACImpl *This = impl_from_IAudioClient3(iface);
1705 FIXME("(%p)->(0x%x, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1707 return E_NOTIMPL;
1710 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1712 AudioClient_QueryInterface,
1713 AudioClient_AddRef,
1714 AudioClient_Release,
1715 AudioClient_Initialize,
1716 AudioClient_GetBufferSize,
1717 AudioClient_GetStreamLatency,
1718 AudioClient_GetCurrentPadding,
1719 AudioClient_IsFormatSupported,
1720 AudioClient_GetMixFormat,
1721 AudioClient_GetDevicePeriod,
1722 AudioClient_Start,
1723 AudioClient_Stop,
1724 AudioClient_Reset,
1725 AudioClient_SetEventHandle,
1726 AudioClient_GetService,
1727 AudioClient_IsOffloadCapable,
1728 AudioClient_SetClientProperties,
1729 AudioClient_GetBufferSizeLimits,
1730 AudioClient_GetSharedModeEnginePeriod,
1731 AudioClient_GetCurrentSharedModeEnginePeriod,
1732 AudioClient_InitializeSharedAudioStream,
1735 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1736 IAudioRenderClient *iface, REFIID riid, void **ppv)
1738 ACImpl *This = impl_from_IAudioRenderClient(iface);
1739 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1741 if(!ppv)
1742 return E_POINTER;
1743 *ppv = NULL;
1745 if(IsEqualIID(riid, &IID_IUnknown) ||
1746 IsEqualIID(riid, &IID_IAudioRenderClient))
1747 *ppv = iface;
1748 else if(IsEqualIID(riid, &IID_IMarshal))
1749 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1750 if(*ppv){
1751 IUnknown_AddRef((IUnknown*)*ppv);
1752 return S_OK;
1755 WARN("Unknown interface %s\n", debugstr_guid(riid));
1756 return E_NOINTERFACE;
1759 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1761 ACImpl *This = impl_from_IAudioRenderClient(iface);
1762 return AudioClient_AddRef(&This->IAudioClient3_iface);
1765 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1767 ACImpl *This = impl_from_IAudioRenderClient(iface);
1768 return AudioClient_Release(&This->IAudioClient3_iface);
1771 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1772 UINT32 frames, BYTE **data)
1774 ACImpl *This = impl_from_IAudioRenderClient(iface);
1775 UINT32 write_pos;
1777 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1779 if(!data)
1780 return E_POINTER;
1782 *data = NULL;
1784 EnterCriticalSection(&This->lock);
1786 if(This->getbuf_last){
1787 LeaveCriticalSection(&This->lock);
1788 return AUDCLNT_E_OUT_OF_ORDER;
1791 if(!frames){
1792 LeaveCriticalSection(&This->lock);
1793 return S_OK;
1796 if(This->held_frames + frames > This->bufsize_frames){
1797 LeaveCriticalSection(&This->lock);
1798 return AUDCLNT_E_BUFFER_TOO_LARGE;
1801 write_pos =
1802 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1803 if(write_pos + frames > This->bufsize_frames){
1804 if(This->tmp_buffer_frames < frames){
1805 DWORD alloc = frames < This->period_frames ? This->period_frames : frames;
1806 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1807 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1808 alloc * This->fmt->nBlockAlign);
1809 if(!This->tmp_buffer){
1810 LeaveCriticalSection(&This->lock);
1811 return E_OUTOFMEMORY;
1813 This->tmp_buffer_frames = alloc;
1815 *data = This->tmp_buffer;
1816 This->getbuf_last = -frames;
1817 }else{
1818 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1819 This->getbuf_last = frames;
1822 silence_buffer(This, *data, frames);
1824 LeaveCriticalSection(&This->lock);
1826 return S_OK;
1829 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1831 UINT32 write_offs_frames =
1832 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1833 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1834 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1835 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1836 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1838 if(written_bytes <= chunk_bytes){
1839 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1840 }else{
1841 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1842 memcpy(This->local_buffer, buffer + chunk_bytes,
1843 written_bytes - chunk_bytes);
1847 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1848 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1850 ACImpl *This = impl_from_IAudioRenderClient(iface);
1851 BYTE *buffer;
1853 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1855 EnterCriticalSection(&This->lock);
1857 if(!written_frames){
1858 This->getbuf_last = 0;
1859 LeaveCriticalSection(&This->lock);
1860 return S_OK;
1863 if(!This->getbuf_last){
1864 LeaveCriticalSection(&This->lock);
1865 return AUDCLNT_E_OUT_OF_ORDER;
1868 if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1869 LeaveCriticalSection(&This->lock);
1870 return AUDCLNT_E_INVALID_SIZE;
1873 if(This->getbuf_last >= 0)
1874 buffer = This->local_buffer + This->fmt->nBlockAlign *
1875 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1876 else
1877 buffer = This->tmp_buffer;
1879 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1880 silence_buffer(This, buffer, written_frames);
1882 if(This->getbuf_last < 0)
1883 oss_wrap_buffer(This, buffer, written_frames);
1885 This->held_frames += written_frames;
1886 This->written_frames += written_frames;
1887 This->getbuf_last = 0;
1889 LeaveCriticalSection(&This->lock);
1891 return S_OK;
1894 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1895 AudioRenderClient_QueryInterface,
1896 AudioRenderClient_AddRef,
1897 AudioRenderClient_Release,
1898 AudioRenderClient_GetBuffer,
1899 AudioRenderClient_ReleaseBuffer
1902 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1903 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1905 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1906 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1908 if(!ppv)
1909 return E_POINTER;
1910 *ppv = NULL;
1912 if(IsEqualIID(riid, &IID_IUnknown) ||
1913 IsEqualIID(riid, &IID_IAudioCaptureClient))
1914 *ppv = iface;
1915 else if(IsEqualIID(riid, &IID_IMarshal))
1916 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1917 if(*ppv){
1918 IUnknown_AddRef((IUnknown*)*ppv);
1919 return S_OK;
1922 WARN("Unknown interface %s\n", debugstr_guid(riid));
1923 return E_NOINTERFACE;
1926 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1928 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1929 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1932 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1934 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1935 return IAudioClient3_Release(&This->IAudioClient3_iface);
1938 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1939 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1940 UINT64 *qpcpos)
1942 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1944 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1945 devpos, qpcpos);
1947 if(!data)
1948 return E_POINTER;
1950 *data = NULL;
1952 if(!frames || !flags)
1953 return E_POINTER;
1955 EnterCriticalSection(&This->lock);
1957 if(This->getbuf_last){
1958 LeaveCriticalSection(&This->lock);
1959 return AUDCLNT_E_OUT_OF_ORDER;
1962 if(This->held_frames < This->period_frames){
1963 *frames = 0;
1964 LeaveCriticalSection(&This->lock);
1965 return AUDCLNT_S_BUFFER_EMPTY;
1968 *flags = 0;
1970 *frames = This->period_frames;
1972 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1973 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1974 if(This->tmp_buffer_frames < *frames){
1975 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1976 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1977 *frames * This->fmt->nBlockAlign);
1978 if(!This->tmp_buffer){
1979 LeaveCriticalSection(&This->lock);
1980 return E_OUTOFMEMORY;
1982 This->tmp_buffer_frames = *frames;
1985 *data = This->tmp_buffer;
1986 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1987 This->fmt->nBlockAlign;
1988 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1989 frames_bytes = *frames * This->fmt->nBlockAlign;
1990 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1991 memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
1992 frames_bytes - chunk_bytes);
1993 }else
1994 *data = This->local_buffer +
1995 This->lcl_offs_frames * This->fmt->nBlockAlign;
1996 TRACE("returning %u from %u\n", This->period_frames, This->lcl_offs_frames);
1998 This->getbuf_last = *frames;
2000 if(devpos)
2001 *devpos = This->written_frames;
2002 if(qpcpos){
2003 LARGE_INTEGER stamp, freq;
2004 QueryPerformanceCounter(&stamp);
2005 QueryPerformanceFrequency(&freq);
2006 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2009 LeaveCriticalSection(&This->lock);
2011 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2014 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2015 IAudioCaptureClient *iface, UINT32 done)
2017 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2019 TRACE("(%p)->(%u)\n", This, done);
2021 EnterCriticalSection(&This->lock);
2023 if(!done){
2024 This->getbuf_last = 0;
2025 LeaveCriticalSection(&This->lock);
2026 return S_OK;
2029 if(!This->getbuf_last){
2030 LeaveCriticalSection(&This->lock);
2031 return AUDCLNT_E_OUT_OF_ORDER;
2034 if(This->getbuf_last != done){
2035 LeaveCriticalSection(&This->lock);
2036 return AUDCLNT_E_INVALID_SIZE;
2039 This->written_frames += done;
2040 This->held_frames -= done;
2041 This->lcl_offs_frames += done;
2042 This->lcl_offs_frames %= This->bufsize_frames;
2043 This->getbuf_last = 0;
2044 TRACE("lcl: %u, held: %u\n", This->lcl_offs_frames, This->held_frames);
2046 LeaveCriticalSection(&This->lock);
2048 return S_OK;
2051 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2052 IAudioCaptureClient *iface, UINT32 *frames)
2054 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2056 TRACE("(%p)->(%p)\n", This, frames);
2058 if(!frames)
2059 return E_POINTER;
2061 EnterCriticalSection(&This->lock);
2063 *frames = This->held_frames < This->period_frames ? 0 : This->period_frames;
2065 LeaveCriticalSection(&This->lock);
2067 return S_OK;
2070 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2072 AudioCaptureClient_QueryInterface,
2073 AudioCaptureClient_AddRef,
2074 AudioCaptureClient_Release,
2075 AudioCaptureClient_GetBuffer,
2076 AudioCaptureClient_ReleaseBuffer,
2077 AudioCaptureClient_GetNextPacketSize
2080 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2081 REFIID riid, void **ppv)
2083 ACImpl *This = impl_from_IAudioClock(iface);
2085 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2087 if(!ppv)
2088 return E_POINTER;
2089 *ppv = NULL;
2091 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2092 *ppv = iface;
2093 else if(IsEqualIID(riid, &IID_IAudioClock2))
2094 *ppv = &This->IAudioClock2_iface;
2095 if(*ppv){
2096 IUnknown_AddRef((IUnknown*)*ppv);
2097 return S_OK;
2100 WARN("Unknown interface %s\n", debugstr_guid(riid));
2101 return E_NOINTERFACE;
2104 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2106 ACImpl *This = impl_from_IAudioClock(iface);
2107 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
2110 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2112 ACImpl *This = impl_from_IAudioClock(iface);
2113 return IAudioClient3_Release(&This->IAudioClient3_iface);
2116 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2118 ACImpl *This = impl_from_IAudioClock(iface);
2120 TRACE("(%p)->(%p)\n", This, freq);
2122 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2123 *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
2124 else
2125 *freq = This->fmt->nSamplesPerSec;
2127 return S_OK;
2130 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2131 UINT64 *qpctime)
2133 ACImpl *This = impl_from_IAudioClock(iface);
2135 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2137 if(!pos)
2138 return E_POINTER;
2140 EnterCriticalSection(&This->lock);
2142 if(This->dataflow == eRender){
2143 *pos = This->written_frames - This->held_frames;
2144 if(*pos < This->last_pos_frames)
2145 *pos = This->last_pos_frames;
2146 }else if(This->dataflow == eCapture){
2147 *pos = This->written_frames - This->held_frames;
2150 This->last_pos_frames = *pos;
2152 TRACE("returning: 0x%s\n", wine_dbgstr_longlong(*pos));
2153 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2154 *pos *= This->fmt->nBlockAlign;
2156 LeaveCriticalSection(&This->lock);
2158 if(qpctime){
2159 LARGE_INTEGER stamp, freq;
2160 QueryPerformanceCounter(&stamp);
2161 QueryPerformanceFrequency(&freq);
2162 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2165 return S_OK;
2168 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2169 DWORD *chars)
2171 ACImpl *This = impl_from_IAudioClock(iface);
2173 TRACE("(%p)->(%p)\n", This, chars);
2175 if(!chars)
2176 return E_POINTER;
2178 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2180 return S_OK;
2183 static const IAudioClockVtbl AudioClock_Vtbl =
2185 AudioClock_QueryInterface,
2186 AudioClock_AddRef,
2187 AudioClock_Release,
2188 AudioClock_GetFrequency,
2189 AudioClock_GetPosition,
2190 AudioClock_GetCharacteristics
2193 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2194 REFIID riid, void **ppv)
2196 ACImpl *This = impl_from_IAudioClock2(iface);
2197 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2200 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2202 ACImpl *This = impl_from_IAudioClock2(iface);
2203 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
2206 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2208 ACImpl *This = impl_from_IAudioClock2(iface);
2209 return IAudioClient3_Release(&This->IAudioClient3_iface);
2212 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2213 UINT64 *pos, UINT64 *qpctime)
2215 ACImpl *This = impl_from_IAudioClock2(iface);
2217 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2219 return E_NOTIMPL;
2222 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2224 AudioClock2_QueryInterface,
2225 AudioClock2_AddRef,
2226 AudioClock2_Release,
2227 AudioClock2_GetDevicePosition
2230 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2232 AudioSessionWrapper *ret;
2234 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2235 sizeof(AudioSessionWrapper));
2236 if(!ret)
2237 return NULL;
2239 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2240 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2241 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2243 ret->ref = 1;
2245 ret->client = client;
2246 if(client){
2247 ret->session = client->session;
2248 AudioClient_AddRef(&client->IAudioClient3_iface);
2251 return ret;
2254 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2255 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2257 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2259 if(!ppv)
2260 return E_POINTER;
2261 *ppv = NULL;
2263 if(IsEqualIID(riid, &IID_IUnknown) ||
2264 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2265 IsEqualIID(riid, &IID_IAudioSessionControl2))
2266 *ppv = iface;
2267 if(*ppv){
2268 IUnknown_AddRef((IUnknown*)*ppv);
2269 return S_OK;
2272 WARN("Unknown interface %s\n", debugstr_guid(riid));
2273 return E_NOINTERFACE;
2276 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2278 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2279 ULONG ref;
2280 ref = InterlockedIncrement(&This->ref);
2281 TRACE("(%p) Refcount now %u\n", This, ref);
2282 return ref;
2285 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2287 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2288 ULONG ref;
2289 ref = InterlockedDecrement(&This->ref);
2290 TRACE("(%p) Refcount now %u\n", This, ref);
2291 if(!ref){
2292 if(This->client){
2293 EnterCriticalSection(&This->client->lock);
2294 This->client->session_wrapper = NULL;
2295 LeaveCriticalSection(&This->client->lock);
2296 AudioClient_Release(&This->client->IAudioClient3_iface);
2298 HeapFree(GetProcessHeap(), 0, This);
2300 return ref;
2303 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2304 AudioSessionState *state)
2306 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2307 ACImpl *client;
2309 TRACE("(%p)->(%p)\n", This, state);
2311 if(!state)
2312 return NULL_PTR_ERR;
2314 EnterCriticalSection(&g_sessions_lock);
2316 if(list_empty(&This->session->clients)){
2317 *state = AudioSessionStateExpired;
2318 LeaveCriticalSection(&g_sessions_lock);
2319 return S_OK;
2322 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2323 EnterCriticalSection(&client->lock);
2324 if(client->playing){
2325 *state = AudioSessionStateActive;
2326 LeaveCriticalSection(&client->lock);
2327 LeaveCriticalSection(&g_sessions_lock);
2328 return S_OK;
2330 LeaveCriticalSection(&client->lock);
2333 LeaveCriticalSection(&g_sessions_lock);
2335 *state = AudioSessionStateInactive;
2337 return S_OK;
2340 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2341 IAudioSessionControl2 *iface, WCHAR **name)
2343 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2345 FIXME("(%p)->(%p) - stub\n", This, name);
2347 return E_NOTIMPL;
2350 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2351 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2353 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2355 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2357 return E_NOTIMPL;
2360 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2361 IAudioSessionControl2 *iface, WCHAR **path)
2363 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2365 FIXME("(%p)->(%p) - stub\n", This, path);
2367 return E_NOTIMPL;
2370 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2371 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2373 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2375 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2377 return E_NOTIMPL;
2380 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2381 IAudioSessionControl2 *iface, GUID *group)
2383 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2385 FIXME("(%p)->(%p) - stub\n", This, group);
2387 return E_NOTIMPL;
2390 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2391 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2393 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2395 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2396 debugstr_guid(session));
2398 return E_NOTIMPL;
2401 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2402 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2404 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2406 FIXME("(%p)->(%p) - stub\n", This, events);
2408 return S_OK;
2411 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2412 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2414 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2416 FIXME("(%p)->(%p) - stub\n", This, events);
2418 return S_OK;
2421 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2422 IAudioSessionControl2 *iface, WCHAR **id)
2424 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2426 FIXME("(%p)->(%p) - stub\n", This, id);
2428 return E_NOTIMPL;
2431 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2432 IAudioSessionControl2 *iface, WCHAR **id)
2434 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2436 FIXME("(%p)->(%p) - stub\n", This, id);
2438 return E_NOTIMPL;
2441 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2442 IAudioSessionControl2 *iface, DWORD *pid)
2444 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2446 TRACE("(%p)->(%p)\n", This, pid);
2448 if(!pid)
2449 return E_POINTER;
2451 *pid = GetCurrentProcessId();
2453 return S_OK;
2456 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2457 IAudioSessionControl2 *iface)
2459 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2461 TRACE("(%p)\n", This);
2463 return S_FALSE;
2466 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2467 IAudioSessionControl2 *iface, BOOL optout)
2469 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2471 TRACE("(%p)->(%d)\n", This, optout);
2473 return S_OK;
2476 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2478 AudioSessionControl_QueryInterface,
2479 AudioSessionControl_AddRef,
2480 AudioSessionControl_Release,
2481 AudioSessionControl_GetState,
2482 AudioSessionControl_GetDisplayName,
2483 AudioSessionControl_SetDisplayName,
2484 AudioSessionControl_GetIconPath,
2485 AudioSessionControl_SetIconPath,
2486 AudioSessionControl_GetGroupingParam,
2487 AudioSessionControl_SetGroupingParam,
2488 AudioSessionControl_RegisterAudioSessionNotification,
2489 AudioSessionControl_UnregisterAudioSessionNotification,
2490 AudioSessionControl_GetSessionIdentifier,
2491 AudioSessionControl_GetSessionInstanceIdentifier,
2492 AudioSessionControl_GetProcessId,
2493 AudioSessionControl_IsSystemSoundsSession,
2494 AudioSessionControl_SetDuckingPreference
2497 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2498 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2500 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2502 if(!ppv)
2503 return E_POINTER;
2504 *ppv = NULL;
2506 if(IsEqualIID(riid, &IID_IUnknown) ||
2507 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2508 *ppv = iface;
2509 if(*ppv){
2510 IUnknown_AddRef((IUnknown*)*ppv);
2511 return S_OK;
2514 WARN("Unknown interface %s\n", debugstr_guid(riid));
2515 return E_NOINTERFACE;
2518 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2520 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2521 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2524 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2526 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2527 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2530 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2531 ISimpleAudioVolume *iface, float level, const GUID *context)
2533 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2534 AudioSession *session = This->session;
2536 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2538 if(level < 0.f || level > 1.f)
2539 return E_INVALIDARG;
2541 if(context)
2542 FIXME("Notifications not supported yet\n");
2544 EnterCriticalSection(&session->lock);
2546 session->master_vol = level;
2548 TRACE("OSS doesn't support setting volume\n");
2550 LeaveCriticalSection(&session->lock);
2552 return S_OK;
2555 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2556 ISimpleAudioVolume *iface, float *level)
2558 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2559 AudioSession *session = This->session;
2561 TRACE("(%p)->(%p)\n", session, level);
2563 if(!level)
2564 return NULL_PTR_ERR;
2566 *level = session->master_vol;
2568 return S_OK;
2571 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2572 BOOL mute, const GUID *context)
2574 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2575 AudioSession *session = This->session;
2577 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2579 EnterCriticalSection(&session->lock);
2581 session->mute = mute;
2583 LeaveCriticalSection(&session->lock);
2585 return S_OK;
2588 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2589 BOOL *mute)
2591 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2592 AudioSession *session = This->session;
2594 TRACE("(%p)->(%p)\n", session, mute);
2596 if(!mute)
2597 return NULL_PTR_ERR;
2599 *mute = This->session->mute;
2601 return S_OK;
2604 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2606 SimpleAudioVolume_QueryInterface,
2607 SimpleAudioVolume_AddRef,
2608 SimpleAudioVolume_Release,
2609 SimpleAudioVolume_SetMasterVolume,
2610 SimpleAudioVolume_GetMasterVolume,
2611 SimpleAudioVolume_SetMute,
2612 SimpleAudioVolume_GetMute
2615 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2616 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2618 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2620 if(!ppv)
2621 return E_POINTER;
2622 *ppv = NULL;
2624 if(IsEqualIID(riid, &IID_IUnknown) ||
2625 IsEqualIID(riid, &IID_IAudioStreamVolume))
2626 *ppv = iface;
2627 if(*ppv){
2628 IUnknown_AddRef((IUnknown*)*ppv);
2629 return S_OK;
2632 WARN("Unknown interface %s\n", debugstr_guid(riid));
2633 return E_NOINTERFACE;
2636 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2638 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2639 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
2642 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2644 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2645 return IAudioClient3_Release(&This->IAudioClient3_iface);
2648 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2649 IAudioStreamVolume *iface, UINT32 *out)
2651 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2653 TRACE("(%p)->(%p)\n", This, out);
2655 if(!out)
2656 return E_POINTER;
2658 *out = This->fmt->nChannels;
2660 return S_OK;
2663 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2664 IAudioStreamVolume *iface, UINT32 index, float level)
2666 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2668 TRACE("(%p)->(%d, %f)\n", This, index, level);
2670 if(level < 0.f || level > 1.f)
2671 return E_INVALIDARG;
2673 if(index >= This->fmt->nChannels)
2674 return E_INVALIDARG;
2676 EnterCriticalSection(&This->lock);
2678 This->vols[index] = level;
2680 TRACE("OSS doesn't support setting volume\n");
2682 LeaveCriticalSection(&This->lock);
2684 return S_OK;
2687 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2688 IAudioStreamVolume *iface, UINT32 index, float *level)
2690 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2692 TRACE("(%p)->(%d, %p)\n", This, index, level);
2694 if(!level)
2695 return E_POINTER;
2697 if(index >= This->fmt->nChannels)
2698 return E_INVALIDARG;
2700 *level = This->vols[index];
2702 return S_OK;
2705 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2706 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2708 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2709 int i;
2711 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2713 if(!levels)
2714 return E_POINTER;
2716 if(count != This->fmt->nChannels)
2717 return E_INVALIDARG;
2719 EnterCriticalSection(&This->lock);
2721 for(i = 0; i < count; ++i)
2722 This->vols[i] = levels[i];
2724 TRACE("OSS doesn't support setting volume\n");
2726 LeaveCriticalSection(&This->lock);
2728 return S_OK;
2731 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2732 IAudioStreamVolume *iface, UINT32 count, float *levels)
2734 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2735 int i;
2737 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2739 if(!levels)
2740 return E_POINTER;
2742 if(count != This->fmt->nChannels)
2743 return E_INVALIDARG;
2745 EnterCriticalSection(&This->lock);
2747 for(i = 0; i < count; ++i)
2748 levels[i] = This->vols[i];
2750 LeaveCriticalSection(&This->lock);
2752 return S_OK;
2755 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2757 AudioStreamVolume_QueryInterface,
2758 AudioStreamVolume_AddRef,
2759 AudioStreamVolume_Release,
2760 AudioStreamVolume_GetChannelCount,
2761 AudioStreamVolume_SetChannelVolume,
2762 AudioStreamVolume_GetChannelVolume,
2763 AudioStreamVolume_SetAllVolumes,
2764 AudioStreamVolume_GetAllVolumes
2767 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2768 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2770 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2772 if(!ppv)
2773 return E_POINTER;
2774 *ppv = NULL;
2776 if(IsEqualIID(riid, &IID_IUnknown) ||
2777 IsEqualIID(riid, &IID_IChannelAudioVolume))
2778 *ppv = iface;
2779 if(*ppv){
2780 IUnknown_AddRef((IUnknown*)*ppv);
2781 return S_OK;
2784 WARN("Unknown interface %s\n", debugstr_guid(riid));
2785 return E_NOINTERFACE;
2788 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2790 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2791 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2794 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2796 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2797 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2800 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2801 IChannelAudioVolume *iface, UINT32 *out)
2803 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2804 AudioSession *session = This->session;
2806 TRACE("(%p)->(%p)\n", session, out);
2808 if(!out)
2809 return NULL_PTR_ERR;
2811 *out = session->channel_count;
2813 return S_OK;
2816 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2817 IChannelAudioVolume *iface, UINT32 index, float level,
2818 const GUID *context)
2820 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2821 AudioSession *session = This->session;
2823 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2824 wine_dbgstr_guid(context));
2826 if(level < 0.f || level > 1.f)
2827 return E_INVALIDARG;
2829 if(index >= session->channel_count)
2830 return E_INVALIDARG;
2832 if(context)
2833 FIXME("Notifications not supported yet\n");
2835 EnterCriticalSection(&session->lock);
2837 session->channel_vols[index] = level;
2839 TRACE("OSS doesn't support setting volume\n");
2841 LeaveCriticalSection(&session->lock);
2843 return S_OK;
2846 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2847 IChannelAudioVolume *iface, UINT32 index, float *level)
2849 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2850 AudioSession *session = This->session;
2852 TRACE("(%p)->(%d, %p)\n", session, index, level);
2854 if(!level)
2855 return NULL_PTR_ERR;
2857 if(index >= session->channel_count)
2858 return E_INVALIDARG;
2860 *level = session->channel_vols[index];
2862 return S_OK;
2865 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2866 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2867 const GUID *context)
2869 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2870 AudioSession *session = This->session;
2871 int i;
2873 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2874 wine_dbgstr_guid(context));
2876 if(!levels)
2877 return NULL_PTR_ERR;
2879 if(count != session->channel_count)
2880 return E_INVALIDARG;
2882 if(context)
2883 FIXME("Notifications not supported yet\n");
2885 EnterCriticalSection(&session->lock);
2887 for(i = 0; i < count; ++i)
2888 session->channel_vols[i] = levels[i];
2890 TRACE("OSS doesn't support setting volume\n");
2892 LeaveCriticalSection(&session->lock);
2894 return S_OK;
2897 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2898 IChannelAudioVolume *iface, UINT32 count, float *levels)
2900 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2901 AudioSession *session = This->session;
2902 int i;
2904 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2906 if(!levels)
2907 return NULL_PTR_ERR;
2909 if(count != session->channel_count)
2910 return E_INVALIDARG;
2912 for(i = 0; i < count; ++i)
2913 levels[i] = session->channel_vols[i];
2915 return S_OK;
2918 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2920 ChannelAudioVolume_QueryInterface,
2921 ChannelAudioVolume_AddRef,
2922 ChannelAudioVolume_Release,
2923 ChannelAudioVolume_GetChannelCount,
2924 ChannelAudioVolume_SetChannelVolume,
2925 ChannelAudioVolume_GetChannelVolume,
2926 ChannelAudioVolume_SetAllVolumes,
2927 ChannelAudioVolume_GetAllVolumes
2930 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2931 REFIID riid, void **ppv)
2933 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2935 if(!ppv)
2936 return E_POINTER;
2937 *ppv = NULL;
2939 if(IsEqualIID(riid, &IID_IUnknown) ||
2940 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2941 IsEqualIID(riid, &IID_IAudioSessionManager2))
2942 *ppv = iface;
2943 if(*ppv){
2944 IUnknown_AddRef((IUnknown*)*ppv);
2945 return S_OK;
2948 WARN("Unknown interface %s\n", debugstr_guid(riid));
2949 return E_NOINTERFACE;
2952 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2954 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2955 ULONG ref;
2956 ref = InterlockedIncrement(&This->ref);
2957 TRACE("(%p) Refcount now %u\n", This, ref);
2958 return ref;
2961 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2963 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2964 ULONG ref;
2965 ref = InterlockedDecrement(&This->ref);
2966 TRACE("(%p) Refcount now %u\n", This, ref);
2967 if(!ref)
2968 HeapFree(GetProcessHeap(), 0, This);
2969 return ref;
2972 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2973 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2974 IAudioSessionControl **out)
2976 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2977 AudioSession *session;
2978 AudioSessionWrapper *wrapper;
2979 HRESULT hr;
2981 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2982 flags, out);
2984 hr = get_audio_session(session_guid, This->device, 0, &session);
2985 if(FAILED(hr))
2986 return hr;
2988 wrapper = AudioSessionWrapper_Create(NULL);
2989 if(!wrapper)
2990 return E_OUTOFMEMORY;
2992 wrapper->session = session;
2994 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2996 return S_OK;
2999 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3000 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3001 ISimpleAudioVolume **out)
3003 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3004 AudioSession *session;
3005 AudioSessionWrapper *wrapper;
3006 HRESULT hr;
3008 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3009 flags, out);
3011 hr = get_audio_session(session_guid, This->device, 0, &session);
3012 if(FAILED(hr))
3013 return hr;
3015 wrapper = AudioSessionWrapper_Create(NULL);
3016 if(!wrapper)
3017 return E_OUTOFMEMORY;
3019 wrapper->session = session;
3021 *out = &wrapper->ISimpleAudioVolume_iface;
3023 return S_OK;
3026 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3027 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3029 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3030 FIXME("(%p)->(%p) - stub\n", This, out);
3031 return E_NOTIMPL;
3034 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3035 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3037 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3038 FIXME("(%p)->(%p) - stub\n", This, notification);
3039 return E_NOTIMPL;
3042 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3043 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3045 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3046 FIXME("(%p)->(%p) - stub\n", This, notification);
3047 return E_NOTIMPL;
3050 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3051 IAudioSessionManager2 *iface, const WCHAR *session_id,
3052 IAudioVolumeDuckNotification *notification)
3054 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3055 FIXME("(%p)->(%p) - stub\n", This, notification);
3056 return E_NOTIMPL;
3059 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3060 IAudioSessionManager2 *iface,
3061 IAudioVolumeDuckNotification *notification)
3063 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3064 FIXME("(%p)->(%p) - stub\n", This, notification);
3065 return E_NOTIMPL;
3068 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3070 AudioSessionManager_QueryInterface,
3071 AudioSessionManager_AddRef,
3072 AudioSessionManager_Release,
3073 AudioSessionManager_GetAudioSessionControl,
3074 AudioSessionManager_GetSimpleAudioVolume,
3075 AudioSessionManager_GetSessionEnumerator,
3076 AudioSessionManager_RegisterSessionNotification,
3077 AudioSessionManager_UnregisterSessionNotification,
3078 AudioSessionManager_RegisterDuckNotification,
3079 AudioSessionManager_UnregisterDuckNotification
3082 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3083 IAudioSessionManager2 **out)
3085 SessionMgr *This;
3087 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3088 if(!This)
3089 return E_OUTOFMEMORY;
3091 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3092 This->device = device;
3093 This->ref = 1;
3095 *out = &This->IAudioSessionManager2_iface;
3097 return S_OK;