ddraw/tests: Add another invalid arguments test for surface QI.
[wine.git] / dlls / wineandroid.drv / mmdevdrv.c
blob8f428a88f4022c29df814a130a945e4e13784d30
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"
49 #include "wine/library.h"
51 #include "ole2.h"
52 #include "mmdeviceapi.h"
53 #include "devpkey.h"
54 #include "dshow.h"
55 #include "dsound.h"
57 #include "initguid.h"
58 #include "endpointvolume.h"
59 #include "audiopolicy.h"
60 #include "audioclient.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(androidaudio);
64 #define DECL_FUNCPTR(f) static typeof(f) * p##f
65 DECL_FUNCPTR( slCreateEngine );
66 DECL_FUNCPTR( SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
67 DECL_FUNCPTR( SL_IID_ENGINE );
68 DECL_FUNCPTR( SL_IID_PLAY );
69 DECL_FUNCPTR( SL_IID_PLAYBACKRATE );
70 DECL_FUNCPTR( SL_IID_RECORD );
72 #define SLCALL_N(obj, func) (*obj)->func(obj)
73 #define SLCALL(obj, func, ...) (*obj)->func(obj, __VA_ARGS__)
75 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
77 static const REFERENCE_TIME DefaultPeriod = 100000;
78 static const REFERENCE_TIME MinimumPeriod = 50000;
80 struct ACImpl;
81 typedef struct ACImpl ACImpl;
83 typedef struct _AudioSession {
84 GUID guid;
85 struct list clients;
87 IMMDevice *device;
89 float master_vol;
90 UINT32 channel_count;
91 float *channel_vols;
92 BOOL mute;
94 CRITICAL_SECTION lock;
96 struct list entry;
97 } AudioSession;
99 typedef struct _AudioSessionWrapper {
100 IAudioSessionControl2 IAudioSessionControl2_iface;
101 IChannelAudioVolume IChannelAudioVolume_iface;
102 ISimpleAudioVolume ISimpleAudioVolume_iface;
104 LONG ref;
106 ACImpl *client;
107 AudioSession *session;
108 } AudioSessionWrapper;
110 struct ACImpl {
111 IAudioClient IAudioClient_iface;
112 IAudioRenderClient IAudioRenderClient_iface;
113 IAudioCaptureClient IAudioCaptureClient_iface;
114 IAudioClock IAudioClock_iface;
115 IAudioClock2 IAudioClock2_iface;
116 IAudioStreamVolume IAudioStreamVolume_iface;
118 LONG ref;
120 IMMDevice *parent;
121 IUnknown *pUnkFTMarshal;
123 WAVEFORMATEX *fmt;
125 EDataFlow dataflow;
126 DWORD flags;
127 AUDCLNT_SHAREMODE share;
128 HANDLE event;
129 float *vols;
131 SLObjectItf player;
132 SLObjectItf recorder;
133 SLAndroidSimpleBufferQueueItf bufq;
134 SLPlayItf playitf;
135 SLRecordItf recorditf;
137 BOOL initted, playing;
138 UINT64 written_frames, last_pos_frames;
139 UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames, wrap_buffer_frames, in_sl_frames;
140 UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
142 BYTE *local_buffer, *tmp_buffer, *wrap_buffer;
143 LONG32 getbuf_last; /* <0 when using tmp_buffer */
144 HANDLE timer;
146 CRITICAL_SECTION lock;
148 AudioSession *session;
149 AudioSessionWrapper *session_wrapper;
151 struct list entry;
154 typedef struct _SessionMgr {
155 IAudioSessionManager2 IAudioSessionManager2_iface;
157 LONG ref;
159 IMMDevice *device;
160 } SessionMgr;
162 static struct list g_devices = LIST_INIT(g_devices);
164 static HANDLE g_timer_q;
166 static CRITICAL_SECTION g_sessions_lock;
167 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
169 0, 0, &g_sessions_lock,
170 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
171 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
173 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
174 static struct list g_sessions = LIST_INIT(g_sessions);
176 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
178 static const IAudioClientVtbl AudioClient_Vtbl;
179 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
180 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
181 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
182 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
183 static const IAudioClockVtbl AudioClock_Vtbl;
184 static const IAudioClock2Vtbl AudioClock2_Vtbl;
185 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
186 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
187 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
189 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
191 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
194 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
196 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
199 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
201 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
204 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
206 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
209 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
211 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
214 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
216 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
219 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
221 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
224 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
226 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
229 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
231 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
234 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
236 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
239 #define LOAD_FUNCPTR(lib, func) do { \
240 if ((p##func = wine_dlsym( lib, #func, NULL, 0 )) == NULL) \
241 { ERR( "can't find symbol %s\n", #func); return FALSE; } \
242 } while(0)
244 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
246 static BOOL WINAPI load_opensles( INIT_ONCE *once, void *param, void **context )
248 void *libopensles;
249 char error[1024];
251 if (!(libopensles = wine_dlopen( "libOpenSLES.so", RTLD_GLOBAL, error, sizeof(error) )))
253 ERR( "failed to load libOpenSLES.so: %s\n", error );
254 return FALSE;
256 LOAD_FUNCPTR( libopensles, slCreateEngine );
257 LOAD_FUNCPTR( libopensles, SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
258 LOAD_FUNCPTR( libopensles, SL_IID_ENGINE );
259 LOAD_FUNCPTR( libopensles, SL_IID_PLAY );
260 LOAD_FUNCPTR( libopensles, SL_IID_PLAYBACKRATE );
261 LOAD_FUNCPTR( libopensles, SL_IID_RECORD );
263 if (!(g_timer_q = CreateTimerQueue())) return FALSE;
265 return TRUE;
268 /* From <dlls/mmdevapi/mmdevapi.h> */
269 enum DriverPriority {
270 Priority_Unavailable = 0,
271 Priority_Low,
272 Priority_Neutral,
273 Priority_Preferred
276 int WINAPI AUDDRV_GetPriority(void)
278 if (!InitOnceExecuteOnce( &init_once, load_opensles, NULL, NULL ))
279 return Priority_Unavailable;
281 return Priority_Preferred;
284 static SLObjectItf sl;
285 static SLEngineItf engine;
286 static SLObjectItf outputmix;
288 HRESULT AUDDRV_Init(void)
290 SLresult sr;
291 SLEngineOption options[] = { {SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE} };
293 sr = pslCreateEngine(&sl, 1, options, 0, NULL, NULL);
294 if(sr != SL_RESULT_SUCCESS){
295 WARN("slCreateEngine failed: 0x%x\n", sr);
296 return E_FAIL;
299 sr = SLCALL(sl, Realize, SL_BOOLEAN_FALSE);
300 if(sr != SL_RESULT_SUCCESS){
301 SLCALL_N(sl, Destroy);
302 WARN("Engine Realize failed: 0x%x\n", sr);
303 return E_FAIL;
306 sr = SLCALL(sl, GetInterface, *pSL_IID_ENGINE, (void*)&engine);
307 if(sr != SL_RESULT_SUCCESS){
308 SLCALL_N(sl, Destroy);
309 WARN("GetInterface failed: 0x%x\n", sr);
310 return E_FAIL;
313 sr = SLCALL(engine, CreateOutputMix, &outputmix, 0, NULL, NULL);
314 if(sr != SL_RESULT_SUCCESS){
315 SLCALL_N(sl, Destroy);
316 WARN("CreateOutputMix failed: 0x%x\n", sr);
317 return E_FAIL;
320 sr = SLCALL(outputmix, Realize, SL_BOOLEAN_FALSE);
321 if(sr != SL_RESULT_SUCCESS){
322 SLCALL_N(outputmix, Destroy);
323 SLCALL_N(sl, Destroy);
324 WARN("outputmix Realize failed: 0x%x\n", sr);
325 return E_FAIL;
328 return S_OK;
331 static const GUID outGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x00}};
332 static const GUID inGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x01}};
334 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids,
335 UINT *num, UINT *def_index)
337 static const WCHAR outName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','O','u','t',0};
338 static const WCHAR inName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','I','n',0};
340 TRACE("%u %p %p %p %p\n", flow, ids, guids, num, def_index);
342 *def_index = 0;
343 *num = 1;
344 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
345 *guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
346 if(flow == eRender){
347 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(outName));
348 memcpy((*ids)[0], outName, sizeof(outName));
349 memcpy(&(*guids)[0], &outGuid, sizeof(outGuid));
350 }else{
351 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(inName));
352 memcpy((*ids)[0], inName, sizeof(inName));
353 memcpy(&(*guids)[0], &inGuid, sizeof(inGuid));
356 return S_OK;
359 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
360 IAudioClient **out)
362 ACImpl *This;
363 HRESULT hr;
364 EDataFlow flow;
366 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
368 if(!sl)
369 AUDDRV_Init();
371 if(IsEqualGUID(guid, &outGuid))
372 flow = eRender;
373 else if(IsEqualGUID(guid, &inGuid))
374 flow = eCapture;
375 else
376 return AUDCLNT_E_DEVICE_INVALIDATED;
378 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
379 if(!This)
380 return E_OUTOFMEMORY;
382 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient_iface,
383 (IUnknown **)&This->pUnkFTMarshal);
384 if (FAILED(hr)) {
385 HeapFree(GetProcessHeap(), 0, This);
386 return hr;
389 This->dataflow = flow;
391 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
392 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
393 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
394 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
395 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
396 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
398 InitializeCriticalSection(&This->lock);
399 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
401 This->parent = dev;
402 IMMDevice_AddRef(This->parent);
404 IAudioClient_AddRef(&This->IAudioClient_iface);
406 *out = &This->IAudioClient_iface;
408 return S_OK;
411 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
412 REFIID riid, void **ppv)
414 ACImpl *This = impl_from_IAudioClient(iface);
415 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
417 if(!ppv)
418 return E_POINTER;
419 *ppv = NULL;
420 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
421 *ppv = iface;
422 else if(IsEqualIID(riid, &IID_IMarshal))
423 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
424 if(*ppv){
425 IUnknown_AddRef((IUnknown*)*ppv);
426 return S_OK;
428 WARN("Unknown interface %s\n", debugstr_guid(riid));
429 return E_NOINTERFACE;
432 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
434 ACImpl *This = impl_from_IAudioClient(iface);
435 ULONG ref;
436 ref = InterlockedIncrement(&This->ref);
437 TRACE("(%p) Refcount now %u\n", This, ref);
438 return ref;
441 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
443 ACImpl *This = impl_from_IAudioClient(iface);
444 ULONG ref;
446 ref = InterlockedDecrement(&This->ref);
447 TRACE("(%p) Refcount now %u\n", This, ref);
448 if(!ref){
449 if(This->timer){
450 HANDLE event;
451 DWORD wait;
452 event = CreateEventW(NULL, TRUE, FALSE, NULL);
453 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
454 wait = wait && GetLastError() == ERROR_IO_PENDING;
455 if(event && wait)
456 WaitForSingleObject(event, INFINITE);
457 CloseHandle(event);
460 IAudioClient_Stop(iface);
462 IMMDevice_Release(This->parent);
463 IUnknown_Release(This->pUnkFTMarshal);
464 This->lock.DebugInfo->Spare[0] = 0;
465 DeleteCriticalSection(&This->lock);
467 if(This->recorder)
468 SLCALL_N(This->recorder, Destroy);
469 if(This->player)
470 SLCALL_N(This->player, Destroy);
472 if(This->initted){
473 EnterCriticalSection(&g_sessions_lock);
474 list_remove(&This->entry);
475 LeaveCriticalSection(&g_sessions_lock);
477 HeapFree(GetProcessHeap(), 0, This->vols);
478 HeapFree(GetProcessHeap(), 0, This->local_buffer);
479 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
480 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
481 CoTaskMemFree(This->fmt);
482 HeapFree(GetProcessHeap(), 0, This);
484 return ref;
487 static void dump_fmt(const WAVEFORMATEX *fmt)
489 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
490 switch(fmt->wFormatTag){
491 case WAVE_FORMAT_PCM:
492 TRACE("WAVE_FORMAT_PCM");
493 break;
494 case WAVE_FORMAT_IEEE_FLOAT:
495 TRACE("WAVE_FORMAT_IEEE_FLOAT");
496 break;
497 case WAVE_FORMAT_EXTENSIBLE:
498 TRACE("WAVE_FORMAT_EXTENSIBLE");
499 break;
500 default:
501 TRACE("Unknown");
502 break;
504 TRACE(")\n");
506 TRACE("nChannels: %u\n", fmt->nChannels);
507 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
508 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
509 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
510 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
511 TRACE("cbSize: %u\n", fmt->cbSize);
513 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
514 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
515 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
516 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
517 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
521 static DWORD get_channel_mask(unsigned int channels)
523 switch(channels){
524 case 0:
525 return 0;
526 case 1:
527 return KSAUDIO_SPEAKER_MONO;
528 case 2:
529 return KSAUDIO_SPEAKER_STEREO;
530 case 3:
531 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
532 case 4:
533 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
534 case 5:
535 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
536 case 6:
537 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
538 case 7:
539 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
540 case 8:
541 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
543 FIXME("Unknown speaker configuration: %u\n", channels);
544 return 0;
547 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
549 WAVEFORMATEX *ret;
550 size_t size;
552 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
553 size = sizeof(WAVEFORMATEXTENSIBLE);
554 else
555 size = sizeof(WAVEFORMATEX);
557 ret = CoTaskMemAlloc(size);
558 if(!ret)
559 return NULL;
561 memcpy(ret, fmt, size);
563 ret->cbSize = size - sizeof(WAVEFORMATEX);
565 return ret;
568 static void session_init_vols(AudioSession *session, UINT channels)
570 if(session->channel_count < channels){
571 UINT i;
573 if(session->channel_vols)
574 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
575 session->channel_vols, sizeof(float) * channels);
576 else
577 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
578 sizeof(float) * channels);
579 if(!session->channel_vols)
580 return;
582 for(i = session->channel_count; i < channels; ++i)
583 session->channel_vols[i] = 1.f;
585 session->channel_count = channels;
589 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
590 UINT num_channels)
592 AudioSession *ret;
594 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
595 if(!ret)
596 return NULL;
598 memcpy(&ret->guid, guid, sizeof(GUID));
600 ret->device = device;
602 list_init(&ret->clients);
604 list_add_head(&g_sessions, &ret->entry);
606 InitializeCriticalSection(&ret->lock);
607 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
609 session_init_vols(ret, num_channels);
611 ret->master_vol = 1.f;
613 return ret;
616 /* if channels == 0, then this will return or create a session with
617 * matching dataflow and GUID. otherwise, channels must also match */
618 static HRESULT get_audio_session(const GUID *sessionguid,
619 IMMDevice *device, UINT channels, AudioSession **out)
621 AudioSession *session;
623 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
624 *out = create_session(&GUID_NULL, device, channels);
625 if(!*out)
626 return E_OUTOFMEMORY;
628 return S_OK;
631 *out = NULL;
632 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
633 if(session->device == device &&
634 IsEqualGUID(sessionguid, &session->guid)){
635 session_init_vols(session, channels);
636 *out = session;
637 break;
641 if(!*out){
642 *out = create_session(sessionguid, device, channels);
643 if(!*out)
644 return E_OUTOFMEMORY;
647 return S_OK;
650 static HRESULT waveformat_to_pcm(ACImpl *This, const WAVEFORMATEX *fmt, SLAndroidDataFormat_PCM_EX *pcm)
652 if(fmt->nSamplesPerSec < 8000 || fmt->nSamplesPerSec > 48000)
653 return AUDCLNT_E_UNSUPPORTED_FORMAT;
655 pcm->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
657 pcm->sampleRate = fmt->nSamplesPerSec * 1000; /* sampleRate is in milli-Hz */
658 pcm->bitsPerSample = fmt->wBitsPerSample;
659 pcm->containerSize = fmt->wBitsPerSample;
661 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
662 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
663 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
664 if(pcm->bitsPerSample == 8)
665 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
666 else if(pcm->bitsPerSample == 16)
667 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
668 else
669 return AUDCLNT_E_UNSUPPORTED_FORMAT;
670 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
671 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
672 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
673 if(pcm->bitsPerSample == 32)
674 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
675 else
676 return AUDCLNT_E_UNSUPPORTED_FORMAT;
677 }else
678 return AUDCLNT_E_UNSUPPORTED_FORMAT;
680 /* only up to stereo */
681 pcm->numChannels = fmt->nChannels;
682 if(pcm->numChannels == 1)
683 pcm->channelMask = SL_SPEAKER_FRONT_CENTER;
684 else if(This->dataflow == eRender && pcm->numChannels == 2)
685 pcm->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
686 else
687 return AUDCLNT_E_UNSUPPORTED_FORMAT;
689 pcm->endianness = SL_BYTEORDER_LITTLEENDIAN;
691 return S_OK;
694 static HRESULT try_open_render_device(SLAndroidDataFormat_PCM_EX *pcm, unsigned int num_buffers, SLObjectItf *out)
696 SLresult sr;
697 SLDataSource source;
698 SLDataSink sink;
699 SLDataLocator_OutputMix loc_outmix;
700 SLboolean required[2];
701 SLInterfaceID iids[2];
702 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
703 SLObjectItf player;
705 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
706 loc_bq.numBuffers = num_buffers;
707 source.pLocator = &loc_bq;
708 source.pFormat = pcm;
710 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
711 loc_outmix.outputMix = outputmix;
712 sink.pLocator = &loc_outmix;
713 sink.pFormat = NULL;
715 required[0] = SL_BOOLEAN_TRUE;
716 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
717 required[1] = SL_BOOLEAN_TRUE;
718 iids[1] = *pSL_IID_PLAYBACKRATE;
720 sr = SLCALL(engine, CreateAudioPlayer, &player, &source, &sink,
721 2, iids, required);
722 if(sr != SL_RESULT_SUCCESS){
723 WARN("CreateAudioPlayer failed: 0x%x\n", sr);
724 return E_FAIL;
727 sr = SLCALL(player, Realize, SL_BOOLEAN_FALSE);
728 if(sr != SL_RESULT_SUCCESS){
729 SLCALL_N(player, Destroy);
730 WARN("Player Realize failed: 0x%x\n", sr);
731 return E_FAIL;
734 if(out)
735 *out = player;
736 else
737 SLCALL_N(player, Destroy);
739 return S_OK;
742 static HRESULT try_open_capture_device(SLAndroidDataFormat_PCM_EX *pcm, unsigned int num_buffers, SLObjectItf *out)
744 SLresult sr;
745 SLDataSource source;
746 SLDataSink sink;
747 SLDataLocator_IODevice loc_mic;
748 SLboolean required[1];
749 SLInterfaceID iids[1];
750 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
751 SLObjectItf recorder;
753 loc_mic.locatorType = SL_DATALOCATOR_IODEVICE;
754 loc_mic.deviceType = SL_IODEVICE_AUDIOINPUT;
755 loc_mic.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
756 loc_mic.device = NULL;
757 source.pLocator = &loc_mic;
758 source.pFormat = NULL;
760 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
761 loc_bq.numBuffers = num_buffers;
762 sink.pLocator = &loc_bq;
763 sink.pFormat = pcm;
765 required[0] = SL_BOOLEAN_TRUE;
766 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
768 sr = SLCALL(engine, CreateAudioRecorder, &recorder, &source, &sink,
769 1, iids, required);
770 if(sr != SL_RESULT_SUCCESS){
771 WARN("CreateAudioRecorder failed: 0x%x\n", sr);
772 return E_FAIL;
775 sr = SLCALL(recorder, Realize, SL_BOOLEAN_FALSE);
776 if(sr != SL_RESULT_SUCCESS){
777 SLCALL_N(recorder, Destroy);
778 WARN("Recorder Realize failed: 0x%x\n", sr);
779 return E_FAIL;
782 if(out)
783 *out = recorder;
784 else
785 SLCALL_N(recorder, Destroy);
787 return S_OK;
790 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
791 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
792 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
793 const GUID *sessionguid)
795 ACImpl *This = impl_from_IAudioClient(iface);
796 int i, num_buffers;
797 HRESULT hr;
798 SLresult sr;
799 SLAndroidDataFormat_PCM_EX pcm;
801 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
802 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
804 if(!fmt)
805 return E_POINTER;
807 dump_fmt(fmt);
809 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
810 return AUDCLNT_E_NOT_INITIALIZED;
812 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
813 AUDCLNT_STREAMFLAGS_LOOPBACK |
814 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
815 AUDCLNT_STREAMFLAGS_NOPERSIST |
816 AUDCLNT_STREAMFLAGS_RATEADJUST |
817 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
818 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
819 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
820 TRACE("Unknown flags: %08x\n", flags);
821 return E_INVALIDARG;
824 if(mode == AUDCLNT_SHAREMODE_SHARED){
825 period = DefaultPeriod;
826 if( duration < 3 * period)
827 duration = 3 * period;
828 }else{
829 if(!period)
830 period = DefaultPeriod; /* not minimum */
831 if(period < MinimumPeriod || period > 5000000)
832 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
833 if(duration > 20000000) /* the smaller the period, the lower this limit */
834 return AUDCLNT_E_BUFFER_SIZE_ERROR;
835 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
836 if(duration != period)
837 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
838 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
839 return AUDCLNT_E_DEVICE_IN_USE;
840 }else{
841 if( duration < 8 * period)
842 duration = 8 * period; /* may grow above 2s */
846 EnterCriticalSection(&This->lock);
848 if(This->initted){
849 LeaveCriticalSection(&This->lock);
850 return AUDCLNT_E_ALREADY_INITIALIZED;
853 This->period_us = period / 10;
854 This->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
856 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
857 if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
858 This->bufsize_frames -= This->bufsize_frames % This->period_frames;
859 else if(This->bufsize_frames % This->period_frames != 0)
860 /* hack: round up to integer multiple */
861 This->bufsize_frames += This->period_frames - This->bufsize_frames % This->period_frames;
863 hr = waveformat_to_pcm(This, fmt, &pcm);
864 if(FAILED(hr)){
865 LeaveCriticalSection(&This->lock);
866 return hr;
869 num_buffers = This->bufsize_frames / This->period_frames;
871 if(This->dataflow == eRender){
872 hr = try_open_render_device(&pcm, num_buffers, &This->player);
873 if(FAILED(hr)){
874 LeaveCriticalSection(&This->lock);
875 return hr;
878 sr = SLCALL(This->player, GetInterface, *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE, &This->bufq);
879 if(sr != SL_RESULT_SUCCESS){
880 SLCALL_N(This->player, Destroy);
881 This->player = NULL;
882 WARN("Player GetInterface(BufferQueue) failed: 0x%x\n", sr);
883 LeaveCriticalSection(&This->lock);
884 return E_FAIL;
887 sr = SLCALL(This->player, GetInterface, *pSL_IID_PLAY, &This->playitf);
888 if(sr != SL_RESULT_SUCCESS){
889 SLCALL_N(This->player, Destroy);
890 This->player = NULL;
891 WARN("Player GetInterface(Play) failed: 0x%x\n", sr);
892 LeaveCriticalSection(&This->lock);
893 return E_FAIL;
895 }else{
896 hr = try_open_capture_device(&pcm, num_buffers, &This->recorder);
897 if(FAILED(hr)){
898 LeaveCriticalSection(&This->lock);
899 return hr;
902 sr = SLCALL(This->recorder, GetInterface, *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE, &This->bufq);
903 if(sr != SL_RESULT_SUCCESS){
904 SLCALL_N(This->recorder, Destroy);
905 This->recorder = NULL;
906 WARN("Recorder GetInterface(BufferQueue) failed: 0x%x\n", sr);
907 LeaveCriticalSection(&This->lock);
908 return E_FAIL;
911 sr = SLCALL(This->recorder, GetInterface, *pSL_IID_RECORD, &This->recorditf);
912 if(sr != SL_RESULT_SUCCESS){
913 SLCALL_N(This->recorder, Destroy);
914 This->recorder = NULL;
915 WARN("Recorder GetInterface(Record) failed: 0x%x\n", sr);
916 LeaveCriticalSection(&This->lock);
917 return E_FAIL;
921 This->fmt = clone_format(fmt);
922 if(!This->fmt){
923 if(This->player){
924 SLCALL_N(This->player, Destroy);
925 This->player = NULL;
927 if(This->recorder){
928 SLCALL_N(This->recorder, Destroy);
929 This->recorder = NULL;
931 LeaveCriticalSection(&This->lock);
932 return E_OUTOFMEMORY;
935 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
936 This->bufsize_frames * fmt->nBlockAlign);
937 if(!This->local_buffer){
938 CoTaskMemFree(This->fmt);
939 This->fmt = NULL;
940 if(This->player){
941 SLCALL_N(This->player, Destroy);
942 This->player = NULL;
944 if(This->recorder){
945 SLCALL_N(This->recorder, Destroy);
946 This->recorder = NULL;
948 LeaveCriticalSection(&This->lock);
949 return E_OUTOFMEMORY;
952 if(This->dataflow == eCapture){
953 while(This->in_sl_frames < This->bufsize_frames){
954 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
955 sr = SLCALL(This->bufq, Enqueue,
956 This->local_buffer + ((This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
957 This->period_frames * This->fmt->nBlockAlign);
958 if(sr != SL_RESULT_SUCCESS)
959 WARN("Enqueue failed: 0x%x\n", sr);
960 This->in_sl_frames += This->period_frames;
964 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
965 if(!This->vols){
966 CoTaskMemFree(This->fmt);
967 This->fmt = NULL;
968 if(This->player){
969 SLCALL_N(This->player, Destroy);
970 This->player = NULL;
972 if(This->recorder){
973 SLCALL_N(This->recorder, Destroy);
974 This->recorder = NULL;
976 LeaveCriticalSection(&This->lock);
977 return E_OUTOFMEMORY;
980 for(i = 0; i < fmt->nChannels; ++i)
981 This->vols[i] = 1.f;
983 This->share = mode;
984 This->flags = flags;
985 This->oss_bufsize_bytes = 0;
987 EnterCriticalSection(&g_sessions_lock);
989 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
990 &This->session);
991 if(FAILED(hr)){
992 LeaveCriticalSection(&g_sessions_lock);
993 HeapFree(GetProcessHeap(), 0, This->vols);
994 This->vols = NULL;
995 CoTaskMemFree(This->fmt);
996 This->fmt = NULL;
997 if(This->player){
998 SLCALL_N(This->player, Destroy);
999 This->player = NULL;
1001 if(This->recorder){
1002 SLCALL_N(This->recorder, Destroy);
1003 This->recorder = NULL;
1005 LeaveCriticalSection(&This->lock);
1006 return hr;
1009 list_add_tail(&This->session->clients, &This->entry);
1011 LeaveCriticalSection(&g_sessions_lock);
1013 This->initted = TRUE;
1015 TRACE("numBuffers: %u, bufsize: %u, period: %u\n", num_buffers,
1016 This->bufsize_frames, This->period_frames);
1018 LeaveCriticalSection(&This->lock);
1020 return S_OK;
1023 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1024 UINT32 *frames)
1026 ACImpl *This = impl_from_IAudioClient(iface);
1028 TRACE("(%p)->(%p)\n", This, frames);
1030 if(!frames)
1031 return E_POINTER;
1033 EnterCriticalSection(&This->lock);
1035 if(!This->initted){
1036 LeaveCriticalSection(&This->lock);
1037 return AUDCLNT_E_NOT_INITIALIZED;
1040 *frames = This->bufsize_frames;
1042 TRACE("buffer size: %u\n", *frames);
1044 LeaveCriticalSection(&This->lock);
1046 return S_OK;
1049 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1050 REFERENCE_TIME *latency)
1052 ACImpl *This = impl_from_IAudioClient(iface);
1054 TRACE("(%p)->(%p)\n", This, latency);
1056 if(!latency)
1057 return E_POINTER;
1059 EnterCriticalSection(&This->lock);
1061 if(!This->initted){
1062 LeaveCriticalSection(&This->lock);
1063 return AUDCLNT_E_NOT_INITIALIZED;
1066 /* pretend we process audio in Period chunks, so max latency includes
1067 * the period time. Some native machines add .6666ms in shared mode. */
1068 *latency = This->period_us * 10 + 6666;
1070 LeaveCriticalSection(&This->lock);
1072 return S_OK;
1075 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1076 UINT32 *numpad)
1078 ACImpl *This = impl_from_IAudioClient(iface);
1080 TRACE("(%p)->(%p)\n", This, numpad);
1082 if(!numpad)
1083 return E_POINTER;
1085 EnterCriticalSection(&This->lock);
1087 if(!This->initted){
1088 LeaveCriticalSection(&This->lock);
1089 return AUDCLNT_E_NOT_INITIALIZED;
1092 *numpad = This->held_frames;
1094 TRACE("padding: %u\n", *numpad);
1096 LeaveCriticalSection(&This->lock);
1098 return S_OK;
1101 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1102 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1103 WAVEFORMATEX **outpwfx)
1105 ACImpl *This = impl_from_IAudioClient(iface);
1106 SLAndroidDataFormat_PCM_EX pcm;
1107 HRESULT hr;
1109 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1111 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1112 return E_POINTER;
1114 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1115 return E_INVALIDARG;
1117 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1118 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1119 return E_INVALIDARG;
1121 dump_fmt(pwfx);
1123 if(outpwfx)
1124 *outpwfx = NULL;
1126 hr = waveformat_to_pcm(This, pwfx, &pcm);
1127 if(SUCCEEDED(hr)){
1128 if(This->dataflow == eRender){
1129 hr = try_open_render_device(&pcm, 10, NULL);
1130 }else{
1131 hr = try_open_capture_device(&pcm, 10, NULL);
1135 if(FAILED(hr)){
1136 if(outpwfx){
1137 hr = IAudioClient_GetMixFormat(iface, outpwfx);
1138 if(FAILED(hr))
1139 return hr;
1140 return S_FALSE;
1143 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1146 TRACE("returning: %08x\n", hr);
1148 return hr;
1151 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1152 WAVEFORMATEX **pwfx)
1154 ACImpl *This = impl_from_IAudioClient(iface);
1155 WAVEFORMATEXTENSIBLE *fmt;
1157 TRACE("(%p)->(%p)\n", This, pwfx);
1159 if(!pwfx)
1160 return E_POINTER;
1161 *pwfx = NULL;
1163 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1164 if(!fmt)
1165 return E_OUTOFMEMORY;
1167 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1168 fmt->Format.wBitsPerSample = 16;
1169 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1170 if(This->dataflow == eRender)
1171 fmt->Format.nChannels = 2;
1172 else
1173 fmt->Format.nChannels = 1;
1174 fmt->Format.nSamplesPerSec = 48000; /* TODO: query supported? recording? */
1175 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1176 fmt->Format.nChannels) / 8;
1177 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1178 fmt->Format.nBlockAlign;
1179 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1180 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1181 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1183 *pwfx = (WAVEFORMATEX*)fmt;
1184 dump_fmt(*pwfx);
1186 return S_OK;
1189 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1190 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1192 ACImpl *This = impl_from_IAudioClient(iface);
1194 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1196 if(!defperiod && !minperiod)
1197 return E_POINTER;
1199 if(defperiod)
1200 *defperiod = DefaultPeriod;
1201 if(minperiod)
1202 *minperiod = MinimumPeriod;
1204 return S_OK;
1207 static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
1209 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1210 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1211 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1212 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1213 This->fmt->wBitsPerSample == 8)
1214 memset(buffer, 128, frames * This->fmt->nBlockAlign);
1215 else
1216 memset(buffer, 0, frames * This->fmt->nBlockAlign);
1219 static void sl_read_data(ACImpl *This)
1221 SLAndroidSimpleBufferQueueState state;
1222 SLresult sr;
1223 SLuint32 elapsed;
1225 memset(&state, 0, sizeof(state));
1227 sr = SLCALL(This->bufq, GetState, &state);
1228 if(sr != SL_RESULT_SUCCESS){
1229 WARN("GetState failed: 0x%x\n", sr);
1230 return;
1232 TRACE("got: count: %u, index: %u, held: %u, in_sl: %u\n", state.count, state.index, This->held_frames, This->in_sl_frames);
1234 elapsed = This->in_sl_frames - state.count * This->period_frames;
1235 This->held_frames += elapsed;
1236 This->in_sl_frames = state.count * This->period_frames;
1238 if(This->held_frames == This->bufsize_frames){
1239 /* overrun */
1240 TRACE("overrun??\n");
1241 This->lcl_offs_frames += This->period_frames;
1242 This->held_frames -= This->period_frames;
1245 TRACE("good range: %u, %u\n", This->lcl_offs_frames, This->lcl_offs_frames + This->held_frames);
1246 TRACE("held: %u, in_sl: %u\n", This->held_frames, This->in_sl_frames);
1247 while(This->held_frames + This->in_sl_frames < This->bufsize_frames){
1248 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->held_frames + This->in_sl_frames) % This->bufsize_frames);
1249 sr = SLCALL(This->bufq, Enqueue,
1250 This->local_buffer + ((This->lcl_offs_frames + This->held_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
1251 This->period_frames * This->fmt->nBlockAlign);
1252 if(sr != SL_RESULT_SUCCESS)
1253 WARN("Enqueue failed: 0x%x\n", sr);
1254 This->in_sl_frames += This->period_frames;
1258 static DWORD wrap_enqueue(ACImpl *This)
1260 DWORD to_enqueue = min(This->held_frames, This->period_frames);
1261 DWORD offs = (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames;
1262 BYTE *buf = This->local_buffer + offs * This->fmt->nBlockAlign;
1264 if(offs + to_enqueue > This->bufsize_frames){
1265 DWORD chunk = This->bufsize_frames - offs;
1267 if(This->wrap_buffer_frames < to_enqueue){
1268 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
1269 This->wrap_buffer = HeapAlloc(GetProcessHeap(), 0, to_enqueue * This->fmt->nBlockAlign);
1270 This->wrap_buffer_frames = to_enqueue;
1273 memcpy(This->wrap_buffer, This->local_buffer + offs * This->fmt->nBlockAlign, chunk * This->fmt->nBlockAlign);
1274 memcpy(This->wrap_buffer + chunk * This->fmt->nBlockAlign, This->local_buffer, (to_enqueue - chunk) * This->fmt->nBlockAlign);
1276 buf = This->wrap_buffer;
1279 SLCALL(This->bufq, Enqueue, buf,
1280 to_enqueue * This->fmt->nBlockAlign);
1282 return to_enqueue;
1285 static void sl_write_data(ACImpl *This)
1287 SLAndroidSimpleBufferQueueState state;
1288 SLresult sr;
1289 SLuint32 elapsed;
1291 memset(&state, 0, sizeof(state));
1293 sr = SLCALL(This->bufq, GetState, &state);
1294 if(sr != SL_RESULT_SUCCESS){
1295 WARN("GetState failed: 0x%x\n", sr);
1296 return;
1298 TRACE("got: count: %u, index: %u\n", state.count, state.index);
1300 elapsed = This->in_sl_frames - state.count * This->period_frames;
1302 if(elapsed > This->held_frames)
1303 This->held_frames = 0;
1304 else
1305 This->held_frames -= elapsed;
1307 This->lcl_offs_frames += elapsed;
1308 This->lcl_offs_frames %= This->bufsize_frames;
1310 This->in_sl_frames = state.count * This->period_frames;
1312 while(This->held_frames >= This->in_sl_frames + This->period_frames){
1313 /* have at least a period to write, so write it */
1314 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1315 This->in_sl_frames += wrap_enqueue(This);
1318 if(This->held_frames && This->in_sl_frames < This->period_frames * 3){
1319 /* write out the last bit with a partial period */
1320 TRACE("enqueueing partial period: %u frames from %u\n", This->held_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1321 This->in_sl_frames += wrap_enqueue(This);
1324 TRACE("done with enqueue, lcl_offs: %u, in_sl: %u, held: %u\n", This->lcl_offs_frames, This->in_sl_frames, This->held_frames);
1327 static void CALLBACK sl_period_callback(void *user, BOOLEAN timer)
1329 ACImpl *This = user;
1331 EnterCriticalSection(&This->lock);
1333 if(This->playing){
1334 if(This->dataflow == eRender)
1335 sl_write_data(This);
1336 else if(This->dataflow == eCapture)
1337 sl_read_data(This);
1340 LeaveCriticalSection(&This->lock);
1342 if(This->event)
1343 SetEvent(This->event);
1346 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1348 ACImpl *This = impl_from_IAudioClient(iface);
1349 SLresult sr;
1351 TRACE("(%p)\n", This);
1353 EnterCriticalSection(&This->lock);
1355 if(!This->initted){
1356 LeaveCriticalSection(&This->lock);
1357 return AUDCLNT_E_NOT_INITIALIZED;
1360 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1361 LeaveCriticalSection(&This->lock);
1362 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1365 if(This->playing){
1366 LeaveCriticalSection(&This->lock);
1367 return AUDCLNT_E_NOT_STOPPED;
1370 if(This->dataflow == eRender){
1371 sr = SLCALL(This->playitf, SetPlayState, SL_PLAYSTATE_PLAYING);
1372 if(sr != SL_RESULT_SUCCESS){
1373 WARN("SetPlayState failed: 0x%x\n", sr);
1374 LeaveCriticalSection(&This->lock);
1375 return E_FAIL;
1377 }else{
1378 sr = SLCALL(This->recorditf, SetRecordState, SL_RECORDSTATE_RECORDING);
1379 if(sr != SL_RESULT_SUCCESS){
1380 WARN("SetRecordState failed: 0x%x\n", sr);
1381 LeaveCriticalSection(&This->lock);
1382 return E_FAIL;
1386 if(!This->timer){
1387 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1388 sl_period_callback, This, 0, This->period_us / 1000,
1389 WT_EXECUTEINTIMERTHREAD))
1390 WARN("Unable to create period timer: %u\n", GetLastError());
1393 This->playing = TRUE;
1395 LeaveCriticalSection(&This->lock);
1397 return S_OK;
1400 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1402 ACImpl *This = impl_from_IAudioClient(iface);
1403 SLresult sr;
1405 TRACE("(%p)\n", This);
1407 EnterCriticalSection(&This->lock);
1409 if(!This->initted){
1410 LeaveCriticalSection(&This->lock);
1411 return AUDCLNT_E_NOT_INITIALIZED;
1414 if(!This->playing){
1415 LeaveCriticalSection(&This->lock);
1416 return S_FALSE;
1419 if(This->dataflow == eRender){
1420 sr = SLCALL(This->playitf, SetPlayState, SL_PLAYSTATE_PAUSED);
1421 if(sr != SL_RESULT_SUCCESS){
1422 WARN("SetPlayState failed: 0x%x\n", sr);
1423 LeaveCriticalSection(&This->lock);
1424 return E_FAIL;
1426 }else{
1427 sr = SLCALL(This->recorditf, SetRecordState, SL_RECORDSTATE_STOPPED);
1428 if(sr != SL_RESULT_SUCCESS){
1429 WARN("SetRecordState failed: 0x%x\n", sr);
1430 LeaveCriticalSection(&This->lock);
1431 return E_FAIL;
1435 This->playing = FALSE;
1437 LeaveCriticalSection(&This->lock);
1439 return S_OK;
1442 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1444 ACImpl *This = impl_from_IAudioClient(iface);
1445 SLresult sr;
1447 TRACE("(%p)\n", This);
1449 EnterCriticalSection(&This->lock);
1451 if(!This->initted){
1452 LeaveCriticalSection(&This->lock);
1453 return AUDCLNT_E_NOT_INITIALIZED;
1456 if(This->playing){
1457 LeaveCriticalSection(&This->lock);
1458 return AUDCLNT_E_NOT_STOPPED;
1461 if(This->getbuf_last){
1462 LeaveCriticalSection(&This->lock);
1463 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1466 sr = SLCALL_N(This->bufq, Clear);
1467 if(sr != SL_RESULT_SUCCESS){
1468 WARN("Clear failed: 0x%x\n", sr);
1469 LeaveCriticalSection(&This->lock);
1470 return E_FAIL;
1473 This->lcl_offs_frames = 0;
1474 This->in_sl_frames = 0;
1476 if(This->dataflow == eRender){
1477 This->written_frames = 0;
1478 This->last_pos_frames = 0;
1479 }else{
1480 This->written_frames += This->held_frames;
1481 while(This->in_sl_frames < This->bufsize_frames){
1482 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1483 sr = SLCALL(This->bufq, Enqueue,
1484 This->local_buffer + ((This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
1485 This->period_frames * This->fmt->nBlockAlign);
1486 if(sr != SL_RESULT_SUCCESS)
1487 WARN("Enqueue failed: 0x%x\n", sr);
1488 This->in_sl_frames += This->period_frames;
1492 This->held_frames = 0;
1494 LeaveCriticalSection(&This->lock);
1496 return S_OK;
1499 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1500 HANDLE event)
1502 ACImpl *This = impl_from_IAudioClient(iface);
1504 TRACE("(%p)->(%p)\n", This, event);
1506 if(!event)
1507 return E_INVALIDARG;
1509 EnterCriticalSection(&This->lock);
1511 if(!This->initted){
1512 LeaveCriticalSection(&This->lock);
1513 return AUDCLNT_E_NOT_INITIALIZED;
1516 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1517 LeaveCriticalSection(&This->lock);
1518 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1521 if (This->event){
1522 LeaveCriticalSection(&This->lock);
1523 FIXME("called twice\n");
1524 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1527 This->event = event;
1529 LeaveCriticalSection(&This->lock);
1531 return S_OK;
1534 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1535 void **ppv)
1537 ACImpl *This = impl_from_IAudioClient(iface);
1539 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1541 if(!ppv)
1542 return E_POINTER;
1543 *ppv = NULL;
1545 EnterCriticalSection(&This->lock);
1547 if(!This->initted){
1548 LeaveCriticalSection(&This->lock);
1549 return AUDCLNT_E_NOT_INITIALIZED;
1552 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1553 if(This->dataflow != eRender){
1554 LeaveCriticalSection(&This->lock);
1555 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1557 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1558 *ppv = &This->IAudioRenderClient_iface;
1559 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1560 if(This->dataflow != eCapture){
1561 LeaveCriticalSection(&This->lock);
1562 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1564 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1565 *ppv = &This->IAudioCaptureClient_iface;
1566 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1567 IAudioClock_AddRef(&This->IAudioClock_iface);
1568 *ppv = &This->IAudioClock_iface;
1569 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1570 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1571 *ppv = &This->IAudioStreamVolume_iface;
1572 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1573 if(!This->session_wrapper){
1574 This->session_wrapper = AudioSessionWrapper_Create(This);
1575 if(!This->session_wrapper){
1576 LeaveCriticalSection(&This->lock);
1577 return E_OUTOFMEMORY;
1579 }else
1580 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1582 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1583 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1584 if(!This->session_wrapper){
1585 This->session_wrapper = AudioSessionWrapper_Create(This);
1586 if(!This->session_wrapper){
1587 LeaveCriticalSection(&This->lock);
1588 return E_OUTOFMEMORY;
1590 }else
1591 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1593 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1594 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1595 if(!This->session_wrapper){
1596 This->session_wrapper = AudioSessionWrapper_Create(This);
1597 if(!This->session_wrapper){
1598 LeaveCriticalSection(&This->lock);
1599 return E_OUTOFMEMORY;
1601 }else
1602 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1604 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1607 if(*ppv){
1608 LeaveCriticalSection(&This->lock);
1609 return S_OK;
1612 LeaveCriticalSection(&This->lock);
1614 FIXME("stub %s\n", debugstr_guid(riid));
1615 return E_NOINTERFACE;
1618 static const IAudioClientVtbl AudioClient_Vtbl =
1620 AudioClient_QueryInterface,
1621 AudioClient_AddRef,
1622 AudioClient_Release,
1623 AudioClient_Initialize,
1624 AudioClient_GetBufferSize,
1625 AudioClient_GetStreamLatency,
1626 AudioClient_GetCurrentPadding,
1627 AudioClient_IsFormatSupported,
1628 AudioClient_GetMixFormat,
1629 AudioClient_GetDevicePeriod,
1630 AudioClient_Start,
1631 AudioClient_Stop,
1632 AudioClient_Reset,
1633 AudioClient_SetEventHandle,
1634 AudioClient_GetService
1637 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1638 IAudioRenderClient *iface, REFIID riid, void **ppv)
1640 ACImpl *This = impl_from_IAudioRenderClient(iface);
1641 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1643 if(!ppv)
1644 return E_POINTER;
1645 *ppv = NULL;
1647 if(IsEqualIID(riid, &IID_IUnknown) ||
1648 IsEqualIID(riid, &IID_IAudioRenderClient))
1649 *ppv = iface;
1650 else if(IsEqualIID(riid, &IID_IMarshal))
1651 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1652 if(*ppv){
1653 IUnknown_AddRef((IUnknown*)*ppv);
1654 return S_OK;
1657 WARN("Unknown interface %s\n", debugstr_guid(riid));
1658 return E_NOINTERFACE;
1661 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1663 ACImpl *This = impl_from_IAudioRenderClient(iface);
1664 return AudioClient_AddRef(&This->IAudioClient_iface);
1667 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1669 ACImpl *This = impl_from_IAudioRenderClient(iface);
1670 return AudioClient_Release(&This->IAudioClient_iface);
1673 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1674 UINT32 frames, BYTE **data)
1676 ACImpl *This = impl_from_IAudioRenderClient(iface);
1677 UINT32 write_pos;
1679 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1681 if(!data)
1682 return E_POINTER;
1684 *data = NULL;
1686 EnterCriticalSection(&This->lock);
1688 if(This->getbuf_last){
1689 LeaveCriticalSection(&This->lock);
1690 return AUDCLNT_E_OUT_OF_ORDER;
1693 if(!frames){
1694 LeaveCriticalSection(&This->lock);
1695 return S_OK;
1698 if(This->held_frames + frames > This->bufsize_frames){
1699 LeaveCriticalSection(&This->lock);
1700 return AUDCLNT_E_BUFFER_TOO_LARGE;
1703 write_pos =
1704 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1705 if(write_pos + frames > This->bufsize_frames){
1706 if(This->tmp_buffer_frames < frames){
1707 DWORD alloc = frames < This->period_frames ? This->period_frames : frames;
1708 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1709 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1710 alloc * This->fmt->nBlockAlign);
1711 if(!This->tmp_buffer){
1712 LeaveCriticalSection(&This->lock);
1713 return E_OUTOFMEMORY;
1715 This->tmp_buffer_frames = alloc;
1717 *data = This->tmp_buffer;
1718 This->getbuf_last = -frames;
1719 }else{
1720 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1721 This->getbuf_last = frames;
1724 silence_buffer(This, *data, frames);
1726 LeaveCriticalSection(&This->lock);
1728 return S_OK;
1731 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1733 UINT32 write_offs_frames =
1734 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1735 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1736 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1737 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1738 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1740 if(written_bytes <= chunk_bytes){
1741 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1742 }else{
1743 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1744 memcpy(This->local_buffer, buffer + chunk_bytes,
1745 written_bytes - chunk_bytes);
1749 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1750 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1752 ACImpl *This = impl_from_IAudioRenderClient(iface);
1753 BYTE *buffer;
1755 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1757 EnterCriticalSection(&This->lock);
1759 if(!written_frames){
1760 This->getbuf_last = 0;
1761 LeaveCriticalSection(&This->lock);
1762 return S_OK;
1765 if(!This->getbuf_last){
1766 LeaveCriticalSection(&This->lock);
1767 return AUDCLNT_E_OUT_OF_ORDER;
1770 if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1771 LeaveCriticalSection(&This->lock);
1772 return AUDCLNT_E_INVALID_SIZE;
1775 if(This->getbuf_last >= 0)
1776 buffer = This->local_buffer + This->fmt->nBlockAlign *
1777 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1778 else
1779 buffer = This->tmp_buffer;
1781 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1782 silence_buffer(This, buffer, written_frames);
1784 if(This->getbuf_last < 0)
1785 oss_wrap_buffer(This, buffer, written_frames);
1787 This->held_frames += written_frames;
1788 This->written_frames += written_frames;
1789 This->getbuf_last = 0;
1791 LeaveCriticalSection(&This->lock);
1793 return S_OK;
1796 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1797 AudioRenderClient_QueryInterface,
1798 AudioRenderClient_AddRef,
1799 AudioRenderClient_Release,
1800 AudioRenderClient_GetBuffer,
1801 AudioRenderClient_ReleaseBuffer
1804 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1805 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1807 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1808 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1810 if(!ppv)
1811 return E_POINTER;
1812 *ppv = NULL;
1814 if(IsEqualIID(riid, &IID_IUnknown) ||
1815 IsEqualIID(riid, &IID_IAudioCaptureClient))
1816 *ppv = iface;
1817 else if(IsEqualIID(riid, &IID_IMarshal))
1818 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1819 if(*ppv){
1820 IUnknown_AddRef((IUnknown*)*ppv);
1821 return S_OK;
1824 WARN("Unknown interface %s\n", debugstr_guid(riid));
1825 return E_NOINTERFACE;
1828 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1830 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1831 return IAudioClient_AddRef(&This->IAudioClient_iface);
1834 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1836 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1837 return IAudioClient_Release(&This->IAudioClient_iface);
1840 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1841 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1842 UINT64 *qpcpos)
1844 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1846 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1847 devpos, qpcpos);
1849 if(!data || !frames || !flags)
1850 return E_POINTER;
1852 EnterCriticalSection(&This->lock);
1854 if(This->getbuf_last){
1855 LeaveCriticalSection(&This->lock);
1856 return AUDCLNT_E_OUT_OF_ORDER;
1859 if(This->held_frames < This->period_frames){
1860 *frames = 0;
1861 LeaveCriticalSection(&This->lock);
1862 return AUDCLNT_S_BUFFER_EMPTY;
1865 *flags = 0;
1867 *frames = This->period_frames;
1869 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1870 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1871 if(This->tmp_buffer_frames < *frames){
1872 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1873 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1874 *frames * This->fmt->nBlockAlign);
1875 if(!This->tmp_buffer){
1876 LeaveCriticalSection(&This->lock);
1877 return E_OUTOFMEMORY;
1879 This->tmp_buffer_frames = *frames;
1882 *data = This->tmp_buffer;
1883 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1884 This->fmt->nBlockAlign;
1885 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1886 frames_bytes = *frames * This->fmt->nBlockAlign;
1887 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1888 memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
1889 frames_bytes - chunk_bytes);
1890 }else
1891 *data = This->local_buffer +
1892 This->lcl_offs_frames * This->fmt->nBlockAlign;
1893 TRACE("returning %u from %u\n", This->period_frames, This->lcl_offs_frames);
1895 This->getbuf_last = *frames;
1897 if(devpos)
1898 *devpos = This->written_frames;
1899 if(qpcpos){
1900 LARGE_INTEGER stamp, freq;
1901 QueryPerformanceCounter(&stamp);
1902 QueryPerformanceFrequency(&freq);
1903 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1906 LeaveCriticalSection(&This->lock);
1908 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1911 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1912 IAudioCaptureClient *iface, UINT32 done)
1914 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1916 TRACE("(%p)->(%u)\n", This, done);
1918 EnterCriticalSection(&This->lock);
1920 if(!done){
1921 This->getbuf_last = 0;
1922 LeaveCriticalSection(&This->lock);
1923 return S_OK;
1926 if(!This->getbuf_last){
1927 LeaveCriticalSection(&This->lock);
1928 return AUDCLNT_E_OUT_OF_ORDER;
1931 if(This->getbuf_last != done){
1932 LeaveCriticalSection(&This->lock);
1933 return AUDCLNT_E_INVALID_SIZE;
1936 This->written_frames += done;
1937 This->held_frames -= done;
1938 This->lcl_offs_frames += done;
1939 This->lcl_offs_frames %= This->bufsize_frames;
1940 This->getbuf_last = 0;
1941 TRACE("lcl: %u, held: %u\n", This->lcl_offs_frames, This->held_frames);
1943 LeaveCriticalSection(&This->lock);
1945 return S_OK;
1948 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1949 IAudioCaptureClient *iface, UINT32 *frames)
1951 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1953 TRACE("(%p)->(%p)\n", This, frames);
1955 if(!frames)
1956 return E_POINTER;
1958 EnterCriticalSection(&This->lock);
1960 *frames = This->held_frames < This->period_frames ? 0 : This->period_frames;
1962 LeaveCriticalSection(&This->lock);
1964 return S_OK;
1967 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1969 AudioCaptureClient_QueryInterface,
1970 AudioCaptureClient_AddRef,
1971 AudioCaptureClient_Release,
1972 AudioCaptureClient_GetBuffer,
1973 AudioCaptureClient_ReleaseBuffer,
1974 AudioCaptureClient_GetNextPacketSize
1977 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1978 REFIID riid, void **ppv)
1980 ACImpl *This = impl_from_IAudioClock(iface);
1982 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1984 if(!ppv)
1985 return E_POINTER;
1986 *ppv = NULL;
1988 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1989 *ppv = iface;
1990 else if(IsEqualIID(riid, &IID_IAudioClock2))
1991 *ppv = &This->IAudioClock2_iface;
1992 if(*ppv){
1993 IUnknown_AddRef((IUnknown*)*ppv);
1994 return S_OK;
1997 WARN("Unknown interface %s\n", debugstr_guid(riid));
1998 return E_NOINTERFACE;
2001 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2003 ACImpl *This = impl_from_IAudioClock(iface);
2004 return IAudioClient_AddRef(&This->IAudioClient_iface);
2007 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2009 ACImpl *This = impl_from_IAudioClock(iface);
2010 return IAudioClient_Release(&This->IAudioClient_iface);
2013 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2015 ACImpl *This = impl_from_IAudioClock(iface);
2017 TRACE("(%p)->(%p)\n", This, freq);
2019 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2020 *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
2021 else
2022 *freq = This->fmt->nSamplesPerSec;
2024 return S_OK;
2027 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2028 UINT64 *qpctime)
2030 ACImpl *This = impl_from_IAudioClock(iface);
2032 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2034 if(!pos)
2035 return E_POINTER;
2037 EnterCriticalSection(&This->lock);
2039 if(This->dataflow == eRender){
2040 *pos = This->written_frames - This->held_frames;
2041 if(*pos < This->last_pos_frames)
2042 *pos = This->last_pos_frames;
2043 }else if(This->dataflow == eCapture){
2044 *pos = This->written_frames - This->held_frames;
2047 This->last_pos_frames = *pos;
2049 TRACE("returning: 0x%s\n", wine_dbgstr_longlong(*pos));
2050 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2051 *pos *= This->fmt->nBlockAlign;
2053 LeaveCriticalSection(&This->lock);
2055 if(qpctime){
2056 LARGE_INTEGER stamp, freq;
2057 QueryPerformanceCounter(&stamp);
2058 QueryPerformanceFrequency(&freq);
2059 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2062 return S_OK;
2065 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2066 DWORD *chars)
2068 ACImpl *This = impl_from_IAudioClock(iface);
2070 TRACE("(%p)->(%p)\n", This, chars);
2072 if(!chars)
2073 return E_POINTER;
2075 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2077 return S_OK;
2080 static const IAudioClockVtbl AudioClock_Vtbl =
2082 AudioClock_QueryInterface,
2083 AudioClock_AddRef,
2084 AudioClock_Release,
2085 AudioClock_GetFrequency,
2086 AudioClock_GetPosition,
2087 AudioClock_GetCharacteristics
2090 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2091 REFIID riid, void **ppv)
2093 ACImpl *This = impl_from_IAudioClock2(iface);
2094 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2097 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2099 ACImpl *This = impl_from_IAudioClock2(iface);
2100 return IAudioClient_AddRef(&This->IAudioClient_iface);
2103 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2105 ACImpl *This = impl_from_IAudioClock2(iface);
2106 return IAudioClient_Release(&This->IAudioClient_iface);
2109 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2110 UINT64 *pos, UINT64 *qpctime)
2112 ACImpl *This = impl_from_IAudioClock2(iface);
2114 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2116 return E_NOTIMPL;
2119 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2121 AudioClock2_QueryInterface,
2122 AudioClock2_AddRef,
2123 AudioClock2_Release,
2124 AudioClock2_GetDevicePosition
2127 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2129 AudioSessionWrapper *ret;
2131 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2132 sizeof(AudioSessionWrapper));
2133 if(!ret)
2134 return NULL;
2136 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2137 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2138 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2140 ret->ref = 1;
2142 ret->client = client;
2143 if(client){
2144 ret->session = client->session;
2145 AudioClient_AddRef(&client->IAudioClient_iface);
2148 return ret;
2151 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2152 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2154 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2156 if(!ppv)
2157 return E_POINTER;
2158 *ppv = NULL;
2160 if(IsEqualIID(riid, &IID_IUnknown) ||
2161 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2162 IsEqualIID(riid, &IID_IAudioSessionControl2))
2163 *ppv = iface;
2164 if(*ppv){
2165 IUnknown_AddRef((IUnknown*)*ppv);
2166 return S_OK;
2169 WARN("Unknown interface %s\n", debugstr_guid(riid));
2170 return E_NOINTERFACE;
2173 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2175 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2176 ULONG ref;
2177 ref = InterlockedIncrement(&This->ref);
2178 TRACE("(%p) Refcount now %u\n", This, ref);
2179 return ref;
2182 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2184 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2185 ULONG ref;
2186 ref = InterlockedDecrement(&This->ref);
2187 TRACE("(%p) Refcount now %u\n", This, ref);
2188 if(!ref){
2189 if(This->client){
2190 EnterCriticalSection(&This->client->lock);
2191 This->client->session_wrapper = NULL;
2192 LeaveCriticalSection(&This->client->lock);
2193 AudioClient_Release(&This->client->IAudioClient_iface);
2195 HeapFree(GetProcessHeap(), 0, This);
2197 return ref;
2200 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2201 AudioSessionState *state)
2203 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2204 ACImpl *client;
2206 TRACE("(%p)->(%p)\n", This, state);
2208 if(!state)
2209 return NULL_PTR_ERR;
2211 EnterCriticalSection(&g_sessions_lock);
2213 if(list_empty(&This->session->clients)){
2214 *state = AudioSessionStateExpired;
2215 LeaveCriticalSection(&g_sessions_lock);
2216 return S_OK;
2219 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2220 EnterCriticalSection(&client->lock);
2221 if(client->playing){
2222 *state = AudioSessionStateActive;
2223 LeaveCriticalSection(&client->lock);
2224 LeaveCriticalSection(&g_sessions_lock);
2225 return S_OK;
2227 LeaveCriticalSection(&client->lock);
2230 LeaveCriticalSection(&g_sessions_lock);
2232 *state = AudioSessionStateInactive;
2234 return S_OK;
2237 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2238 IAudioSessionControl2 *iface, WCHAR **name)
2240 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2242 FIXME("(%p)->(%p) - stub\n", This, name);
2244 return E_NOTIMPL;
2247 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2248 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2250 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2252 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2254 return E_NOTIMPL;
2257 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2258 IAudioSessionControl2 *iface, WCHAR **path)
2260 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2262 FIXME("(%p)->(%p) - stub\n", This, path);
2264 return E_NOTIMPL;
2267 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2268 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2270 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2272 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2274 return E_NOTIMPL;
2277 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2278 IAudioSessionControl2 *iface, GUID *group)
2280 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2282 FIXME("(%p)->(%p) - stub\n", This, group);
2284 return E_NOTIMPL;
2287 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2288 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2290 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2292 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2293 debugstr_guid(session));
2295 return E_NOTIMPL;
2298 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2299 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2301 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2303 FIXME("(%p)->(%p) - stub\n", This, events);
2305 return S_OK;
2308 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2309 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2311 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2313 FIXME("(%p)->(%p) - stub\n", This, events);
2315 return S_OK;
2318 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2319 IAudioSessionControl2 *iface, WCHAR **id)
2321 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2323 FIXME("(%p)->(%p) - stub\n", This, id);
2325 return E_NOTIMPL;
2328 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2329 IAudioSessionControl2 *iface, WCHAR **id)
2331 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2333 FIXME("(%p)->(%p) - stub\n", This, id);
2335 return E_NOTIMPL;
2338 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2339 IAudioSessionControl2 *iface, DWORD *pid)
2341 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2343 TRACE("(%p)->(%p)\n", This, pid);
2345 if(!pid)
2346 return E_POINTER;
2348 *pid = GetCurrentProcessId();
2350 return S_OK;
2353 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2354 IAudioSessionControl2 *iface)
2356 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2358 TRACE("(%p)\n", This);
2360 return S_FALSE;
2363 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2364 IAudioSessionControl2 *iface, BOOL optout)
2366 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2368 TRACE("(%p)->(%d)\n", This, optout);
2370 return S_OK;
2373 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2375 AudioSessionControl_QueryInterface,
2376 AudioSessionControl_AddRef,
2377 AudioSessionControl_Release,
2378 AudioSessionControl_GetState,
2379 AudioSessionControl_GetDisplayName,
2380 AudioSessionControl_SetDisplayName,
2381 AudioSessionControl_GetIconPath,
2382 AudioSessionControl_SetIconPath,
2383 AudioSessionControl_GetGroupingParam,
2384 AudioSessionControl_SetGroupingParam,
2385 AudioSessionControl_RegisterAudioSessionNotification,
2386 AudioSessionControl_UnregisterAudioSessionNotification,
2387 AudioSessionControl_GetSessionIdentifier,
2388 AudioSessionControl_GetSessionInstanceIdentifier,
2389 AudioSessionControl_GetProcessId,
2390 AudioSessionControl_IsSystemSoundsSession,
2391 AudioSessionControl_SetDuckingPreference
2394 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2395 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2397 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2399 if(!ppv)
2400 return E_POINTER;
2401 *ppv = NULL;
2403 if(IsEqualIID(riid, &IID_IUnknown) ||
2404 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2405 *ppv = iface;
2406 if(*ppv){
2407 IUnknown_AddRef((IUnknown*)*ppv);
2408 return S_OK;
2411 WARN("Unknown interface %s\n", debugstr_guid(riid));
2412 return E_NOINTERFACE;
2415 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2417 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2418 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2421 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2423 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2424 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2427 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2428 ISimpleAudioVolume *iface, float level, const GUID *context)
2430 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2431 AudioSession *session = This->session;
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 TRACE("OSS doesn't support setting volume\n");
2447 LeaveCriticalSection(&session->lock);
2449 return S_OK;
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 EnterCriticalSection(&session->lock);
2478 session->mute = mute;
2480 LeaveCriticalSection(&session->lock);
2482 return S_OK;
2485 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2486 BOOL *mute)
2488 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2489 AudioSession *session = This->session;
2491 TRACE("(%p)->(%p)\n", session, mute);
2493 if(!mute)
2494 return NULL_PTR_ERR;
2496 *mute = This->session->mute;
2498 return S_OK;
2501 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2503 SimpleAudioVolume_QueryInterface,
2504 SimpleAudioVolume_AddRef,
2505 SimpleAudioVolume_Release,
2506 SimpleAudioVolume_SetMasterVolume,
2507 SimpleAudioVolume_GetMasterVolume,
2508 SimpleAudioVolume_SetMute,
2509 SimpleAudioVolume_GetMute
2512 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2513 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2515 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2517 if(!ppv)
2518 return E_POINTER;
2519 *ppv = NULL;
2521 if(IsEqualIID(riid, &IID_IUnknown) ||
2522 IsEqualIID(riid, &IID_IAudioStreamVolume))
2523 *ppv = iface;
2524 if(*ppv){
2525 IUnknown_AddRef((IUnknown*)*ppv);
2526 return S_OK;
2529 WARN("Unknown interface %s\n", debugstr_guid(riid));
2530 return E_NOINTERFACE;
2533 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2535 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2536 return IAudioClient_AddRef(&This->IAudioClient_iface);
2539 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2541 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2542 return IAudioClient_Release(&This->IAudioClient_iface);
2545 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2546 IAudioStreamVolume *iface, UINT32 *out)
2548 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2550 TRACE("(%p)->(%p)\n", This, out);
2552 if(!out)
2553 return E_POINTER;
2555 *out = This->fmt->nChannels;
2557 return S_OK;
2560 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2561 IAudioStreamVolume *iface, UINT32 index, float level)
2563 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2565 TRACE("(%p)->(%d, %f)\n", This, index, level);
2567 if(level < 0.f || level > 1.f)
2568 return E_INVALIDARG;
2570 if(index >= This->fmt->nChannels)
2571 return E_INVALIDARG;
2573 EnterCriticalSection(&This->lock);
2575 This->vols[index] = level;
2577 TRACE("OSS doesn't support setting volume\n");
2579 LeaveCriticalSection(&This->lock);
2581 return S_OK;
2584 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2585 IAudioStreamVolume *iface, UINT32 index, float *level)
2587 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2589 TRACE("(%p)->(%d, %p)\n", This, index, level);
2591 if(!level)
2592 return E_POINTER;
2594 if(index >= This->fmt->nChannels)
2595 return E_INVALIDARG;
2597 *level = This->vols[index];
2599 return S_OK;
2602 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2603 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2605 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2606 int i;
2608 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2610 if(!levels)
2611 return E_POINTER;
2613 if(count != This->fmt->nChannels)
2614 return E_INVALIDARG;
2616 EnterCriticalSection(&This->lock);
2618 for(i = 0; i < count; ++i)
2619 This->vols[i] = levels[i];
2621 TRACE("OSS doesn't support setting volume\n");
2623 LeaveCriticalSection(&This->lock);
2625 return S_OK;
2628 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2629 IAudioStreamVolume *iface, UINT32 count, float *levels)
2631 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2632 int i;
2634 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2636 if(!levels)
2637 return E_POINTER;
2639 if(count != This->fmt->nChannels)
2640 return E_INVALIDARG;
2642 EnterCriticalSection(&This->lock);
2644 for(i = 0; i < count; ++i)
2645 levels[i] = This->vols[i];
2647 LeaveCriticalSection(&This->lock);
2649 return S_OK;
2652 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2654 AudioStreamVolume_QueryInterface,
2655 AudioStreamVolume_AddRef,
2656 AudioStreamVolume_Release,
2657 AudioStreamVolume_GetChannelCount,
2658 AudioStreamVolume_SetChannelVolume,
2659 AudioStreamVolume_GetChannelVolume,
2660 AudioStreamVolume_SetAllVolumes,
2661 AudioStreamVolume_GetAllVolumes
2664 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2665 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2667 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2669 if(!ppv)
2670 return E_POINTER;
2671 *ppv = NULL;
2673 if(IsEqualIID(riid, &IID_IUnknown) ||
2674 IsEqualIID(riid, &IID_IChannelAudioVolume))
2675 *ppv = iface;
2676 if(*ppv){
2677 IUnknown_AddRef((IUnknown*)*ppv);
2678 return S_OK;
2681 WARN("Unknown interface %s\n", debugstr_guid(riid));
2682 return E_NOINTERFACE;
2685 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2687 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2688 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2691 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2693 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2694 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2697 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2698 IChannelAudioVolume *iface, UINT32 *out)
2700 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2701 AudioSession *session = This->session;
2703 TRACE("(%p)->(%p)\n", session, out);
2705 if(!out)
2706 return NULL_PTR_ERR;
2708 *out = session->channel_count;
2710 return S_OK;
2713 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2714 IChannelAudioVolume *iface, UINT32 index, float level,
2715 const GUID *context)
2717 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2718 AudioSession *session = This->session;
2720 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2721 wine_dbgstr_guid(context));
2723 if(level < 0.f || level > 1.f)
2724 return E_INVALIDARG;
2726 if(index >= session->channel_count)
2727 return E_INVALIDARG;
2729 if(context)
2730 FIXME("Notifications not supported yet\n");
2732 EnterCriticalSection(&session->lock);
2734 session->channel_vols[index] = level;
2736 TRACE("OSS doesn't support setting volume\n");
2738 LeaveCriticalSection(&session->lock);
2740 return S_OK;
2743 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2744 IChannelAudioVolume *iface, UINT32 index, float *level)
2746 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2747 AudioSession *session = This->session;
2749 TRACE("(%p)->(%d, %p)\n", session, index, level);
2751 if(!level)
2752 return NULL_PTR_ERR;
2754 if(index >= session->channel_count)
2755 return E_INVALIDARG;
2757 *level = session->channel_vols[index];
2759 return S_OK;
2762 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2763 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2764 const GUID *context)
2766 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2767 AudioSession *session = This->session;
2768 int i;
2770 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2771 wine_dbgstr_guid(context));
2773 if(!levels)
2774 return NULL_PTR_ERR;
2776 if(count != session->channel_count)
2777 return E_INVALIDARG;
2779 if(context)
2780 FIXME("Notifications not supported yet\n");
2782 EnterCriticalSection(&session->lock);
2784 for(i = 0; i < count; ++i)
2785 session->channel_vols[i] = levels[i];
2787 TRACE("OSS doesn't support setting volume\n");
2789 LeaveCriticalSection(&session->lock);
2791 return S_OK;
2794 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2795 IChannelAudioVolume *iface, UINT32 count, float *levels)
2797 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2798 AudioSession *session = This->session;
2799 int i;
2801 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2803 if(!levels)
2804 return NULL_PTR_ERR;
2806 if(count != session->channel_count)
2807 return E_INVALIDARG;
2809 for(i = 0; i < count; ++i)
2810 levels[i] = session->channel_vols[i];
2812 return S_OK;
2815 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2817 ChannelAudioVolume_QueryInterface,
2818 ChannelAudioVolume_AddRef,
2819 ChannelAudioVolume_Release,
2820 ChannelAudioVolume_GetChannelCount,
2821 ChannelAudioVolume_SetChannelVolume,
2822 ChannelAudioVolume_GetChannelVolume,
2823 ChannelAudioVolume_SetAllVolumes,
2824 ChannelAudioVolume_GetAllVolumes
2827 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2828 REFIID riid, void **ppv)
2830 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2832 if(!ppv)
2833 return E_POINTER;
2834 *ppv = NULL;
2836 if(IsEqualIID(riid, &IID_IUnknown) ||
2837 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2838 IsEqualIID(riid, &IID_IAudioSessionManager2))
2839 *ppv = iface;
2840 if(*ppv){
2841 IUnknown_AddRef((IUnknown*)*ppv);
2842 return S_OK;
2845 WARN("Unknown interface %s\n", debugstr_guid(riid));
2846 return E_NOINTERFACE;
2849 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2851 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2852 ULONG ref;
2853 ref = InterlockedIncrement(&This->ref);
2854 TRACE("(%p) Refcount now %u\n", This, ref);
2855 return ref;
2858 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2860 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2861 ULONG ref;
2862 ref = InterlockedDecrement(&This->ref);
2863 TRACE("(%p) Refcount now %u\n", This, ref);
2864 if(!ref)
2865 HeapFree(GetProcessHeap(), 0, This);
2866 return ref;
2869 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2870 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2871 IAudioSessionControl **out)
2873 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2874 AudioSession *session;
2875 AudioSessionWrapper *wrapper;
2876 HRESULT hr;
2878 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2879 flags, out);
2881 hr = get_audio_session(session_guid, This->device, 0, &session);
2882 if(FAILED(hr))
2883 return hr;
2885 wrapper = AudioSessionWrapper_Create(NULL);
2886 if(!wrapper)
2887 return E_OUTOFMEMORY;
2889 wrapper->session = session;
2891 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2893 return S_OK;
2896 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2897 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2898 ISimpleAudioVolume **out)
2900 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2901 AudioSession *session;
2902 AudioSessionWrapper *wrapper;
2903 HRESULT hr;
2905 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2906 flags, out);
2908 hr = get_audio_session(session_guid, This->device, 0, &session);
2909 if(FAILED(hr))
2910 return hr;
2912 wrapper = AudioSessionWrapper_Create(NULL);
2913 if(!wrapper)
2914 return E_OUTOFMEMORY;
2916 wrapper->session = session;
2918 *out = &wrapper->ISimpleAudioVolume_iface;
2920 return S_OK;
2923 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2924 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2926 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2927 FIXME("(%p)->(%p) - stub\n", This, out);
2928 return E_NOTIMPL;
2931 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2932 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2934 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2935 FIXME("(%p)->(%p) - stub\n", This, notification);
2936 return E_NOTIMPL;
2939 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2940 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2942 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2943 FIXME("(%p)->(%p) - stub\n", This, notification);
2944 return E_NOTIMPL;
2947 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2948 IAudioSessionManager2 *iface, const WCHAR *session_id,
2949 IAudioVolumeDuckNotification *notification)
2951 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2952 FIXME("(%p)->(%p) - stub\n", This, notification);
2953 return E_NOTIMPL;
2956 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2957 IAudioSessionManager2 *iface,
2958 IAudioVolumeDuckNotification *notification)
2960 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2961 FIXME("(%p)->(%p) - stub\n", This, notification);
2962 return E_NOTIMPL;
2965 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2967 AudioSessionManager_QueryInterface,
2968 AudioSessionManager_AddRef,
2969 AudioSessionManager_Release,
2970 AudioSessionManager_GetAudioSessionControl,
2971 AudioSessionManager_GetSimpleAudioVolume,
2972 AudioSessionManager_GetSessionEnumerator,
2973 AudioSessionManager_RegisterSessionNotification,
2974 AudioSessionManager_UnregisterSessionNotification,
2975 AudioSessionManager_RegisterDuckNotification,
2976 AudioSessionManager_UnregisterDuckNotification
2979 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2980 IAudioSessionManager2 **out)
2982 SessionMgr *This;
2984 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2985 if(!This)
2986 return E_OUTOFMEMORY;
2988 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2989 This->device = device;
2990 This->ref = 1;
2992 *out = &This->IAudioSessionManager2_iface;
2994 return S_OK;