wined3d: Use wined3d_bit_scan() in context_preload_textures().
[wine.git] / dlls / wineandroid.drv / mmdevdrv.c
blobd6ba1072b9cff9f9d2ab40db12c2667eb0d60ee9
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"
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/ioctl.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <math.h>
35 #include <dlfcn.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/list.h"
49 #include "ole2.h"
50 #include "mmdeviceapi.h"
51 #include "devpkey.h"
52 #include "dshow.h"
53 #include "dsound.h"
55 #include "initguid.h"
56 #include "endpointvolume.h"
57 #include "audiopolicy.h"
58 #include "audioclient.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(androidaudio);
62 #define DECL_FUNCPTR(f) static typeof(f) * p##f
63 DECL_FUNCPTR( slCreateEngine );
64 DECL_FUNCPTR( SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
65 DECL_FUNCPTR( SL_IID_ENGINE );
66 DECL_FUNCPTR( SL_IID_PLAY );
67 DECL_FUNCPTR( SL_IID_PLAYBACKRATE );
68 DECL_FUNCPTR( SL_IID_RECORD );
70 #define SLCALL_N(obj, func) (*obj)->func(obj)
71 #define SLCALL(obj, func, ...) (*obj)->func(obj, __VA_ARGS__)
73 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
75 static const REFERENCE_TIME DefaultPeriod = 100000;
76 static const REFERENCE_TIME MinimumPeriod = 50000;
78 struct ACImpl;
79 typedef struct ACImpl ACImpl;
81 typedef struct _AudioSession {
82 GUID guid;
83 struct list clients;
85 IMMDevice *device;
87 float master_vol;
88 UINT32 channel_count;
89 float *channel_vols;
90 BOOL mute;
92 CRITICAL_SECTION lock;
94 struct list entry;
95 } AudioSession;
97 typedef struct _AudioSessionWrapper {
98 IAudioSessionControl2 IAudioSessionControl2_iface;
99 IChannelAudioVolume IChannelAudioVolume_iface;
100 ISimpleAudioVolume ISimpleAudioVolume_iface;
102 LONG ref;
104 ACImpl *client;
105 AudioSession *session;
106 } AudioSessionWrapper;
108 struct ACImpl {
109 IAudioClient3 IAudioClient3_iface;
110 IAudioRenderClient IAudioRenderClient_iface;
111 IAudioCaptureClient IAudioCaptureClient_iface;
112 IAudioClock IAudioClock_iface;
113 IAudioClock2 IAudioClock2_iface;
114 IAudioStreamVolume IAudioStreamVolume_iface;
116 LONG ref;
118 IMMDevice *parent;
119 IUnknown *pUnkFTMarshal;
121 WAVEFORMATEX *fmt;
123 EDataFlow dataflow;
124 DWORD flags;
125 AUDCLNT_SHAREMODE share;
126 HANDLE event;
127 float *vols;
129 SLObjectItf player;
130 SLObjectItf recorder;
131 SLAndroidSimpleBufferQueueItf bufq;
132 SLPlayItf playitf;
133 SLRecordItf recorditf;
135 BOOL initted, playing;
136 UINT64 written_frames, last_pos_frames;
137 UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames, wrap_buffer_frames, in_sl_frames;
138 UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
140 BYTE *local_buffer, *tmp_buffer, *wrap_buffer;
141 LONG32 getbuf_last; /* <0 when using tmp_buffer */
142 HANDLE timer;
144 CRITICAL_SECTION lock;
146 AudioSession *session;
147 AudioSessionWrapper *session_wrapper;
149 struct list entry;
152 typedef struct _SessionMgr {
153 IAudioSessionManager2 IAudioSessionManager2_iface;
155 LONG ref;
157 IMMDevice *device;
158 } SessionMgr;
160 static struct list g_devices = LIST_INIT(g_devices);
162 static HANDLE g_timer_q;
164 static CRITICAL_SECTION g_sessions_lock;
165 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
167 0, 0, &g_sessions_lock,
168 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
169 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
171 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
172 static struct list g_sessions = LIST_INIT(g_sessions);
174 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
176 static const IAudioClient3Vtbl AudioClient3_Vtbl;
177 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
178 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
179 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
180 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
181 static const IAudioClockVtbl AudioClock_Vtbl;
182 static const IAudioClock2Vtbl AudioClock2_Vtbl;
183 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
184 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
185 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
187 static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface)
189 return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface);
192 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
194 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
197 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
199 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
202 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
204 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
207 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
209 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
212 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
214 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
217 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
219 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
222 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
224 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
227 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
229 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
232 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
234 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
237 #define LOAD_FUNCPTR(lib, func) do { \
238 if ((p##func = dlsym( lib, #func )) == NULL) \
239 { ERR( "can't find symbol %s\n", #func); return FALSE; } \
240 } while(0)
242 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
244 static BOOL WINAPI load_opensles( INIT_ONCE *once, void *param, void **context )
246 void *libopensles;
248 if (!(libopensles = dlopen( "libOpenSLES.so", RTLD_GLOBAL )))
250 ERR( "failed to load libOpenSLES.so: %s\n", dlerror() );
251 return FALSE;
253 LOAD_FUNCPTR( libopensles, slCreateEngine );
254 LOAD_FUNCPTR( libopensles, SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
255 LOAD_FUNCPTR( libopensles, SL_IID_ENGINE );
256 LOAD_FUNCPTR( libopensles, SL_IID_PLAY );
257 LOAD_FUNCPTR( libopensles, SL_IID_PLAYBACKRATE );
258 LOAD_FUNCPTR( libopensles, SL_IID_RECORD );
260 if (!(g_timer_q = CreateTimerQueue())) return FALSE;
262 return TRUE;
265 /* From <dlls/mmdevapi/mmdevapi.h> */
266 enum DriverPriority {
267 Priority_Unavailable = 0,
268 Priority_Low,
269 Priority_Neutral,
270 Priority_Preferred
273 int WINAPI AUDDRV_GetPriority(void)
275 if (!InitOnceExecuteOnce( &init_once, load_opensles, NULL, NULL ))
276 return Priority_Unavailable;
278 return Priority_Preferred;
281 static SLObjectItf sl;
282 static SLEngineItf engine;
283 static SLObjectItf outputmix;
285 HRESULT AUDDRV_Init(void)
287 static const SLEngineOption options[] = { {SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE} };
288 SLresult sr;
290 sr = pslCreateEngine(&sl, 1, options, 0, NULL, NULL);
291 if(sr != SL_RESULT_SUCCESS){
292 WARN("slCreateEngine failed: 0x%x\n", sr);
293 return E_FAIL;
296 sr = SLCALL(sl, Realize, SL_BOOLEAN_FALSE);
297 if(sr != SL_RESULT_SUCCESS){
298 SLCALL_N(sl, Destroy);
299 WARN("Engine Realize failed: 0x%x\n", sr);
300 return E_FAIL;
303 sr = SLCALL(sl, GetInterface, *pSL_IID_ENGINE, (void*)&engine);
304 if(sr != SL_RESULT_SUCCESS){
305 SLCALL_N(sl, Destroy);
306 WARN("GetInterface failed: 0x%x\n", sr);
307 return E_FAIL;
310 sr = SLCALL(engine, CreateOutputMix, &outputmix, 0, NULL, NULL);
311 if(sr != SL_RESULT_SUCCESS){
312 SLCALL_N(sl, Destroy);
313 WARN("CreateOutputMix failed: 0x%x\n", sr);
314 return E_FAIL;
317 sr = SLCALL(outputmix, Realize, SL_BOOLEAN_FALSE);
318 if(sr != SL_RESULT_SUCCESS){
319 SLCALL_N(outputmix, Destroy);
320 SLCALL_N(sl, Destroy);
321 WARN("outputmix Realize failed: 0x%x\n", sr);
322 return E_FAIL;
325 return S_OK;
328 static const GUID outGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x00}};
329 static const GUID inGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x01}};
331 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids,
332 UINT *num, UINT *def_index)
334 static const WCHAR outName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','O','u','t',0};
335 static const WCHAR inName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','I','n',0};
337 TRACE("%u %p %p %p %p\n", flow, ids, guids, num, def_index);
339 *def_index = 0;
340 *num = 1;
341 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
342 *guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
343 if(flow == eRender){
344 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(outName));
345 memcpy((*ids)[0], outName, sizeof(outName));
346 memcpy(&(*guids)[0], &outGuid, sizeof(outGuid));
347 }else{
348 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(inName));
349 memcpy((*ids)[0], inName, sizeof(inName));
350 memcpy(&(*guids)[0], &inGuid, sizeof(inGuid));
353 return S_OK;
356 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
357 IAudioClient **out)
359 ACImpl *This;
360 HRESULT hr;
361 EDataFlow flow;
363 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
365 if(!sl)
366 AUDDRV_Init();
368 if(IsEqualGUID(guid, &outGuid))
369 flow = eRender;
370 else if(IsEqualGUID(guid, &inGuid))
371 flow = eCapture;
372 else
373 return AUDCLNT_E_DEVICE_INVALIDATED;
375 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
376 if(!This)
377 return E_OUTOFMEMORY;
379 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
380 if (FAILED(hr)) {
381 HeapFree(GetProcessHeap(), 0, This);
382 return hr;
385 This->dataflow = flow;
387 This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
388 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
389 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
390 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
391 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
392 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
394 InitializeCriticalSection(&This->lock);
395 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
397 This->parent = dev;
398 IMMDevice_AddRef(This->parent);
400 *out = (IAudioClient *)&This->IAudioClient3_iface;
401 IAudioClient3_AddRef(&This->IAudioClient3_iface);
403 return S_OK;
406 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface,
407 REFIID riid, void **ppv)
409 ACImpl *This = impl_from_IAudioClient3(iface);
410 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
412 if(!ppv)
413 return E_POINTER;
414 *ppv = NULL;
415 if(IsEqualIID(riid, &IID_IUnknown) ||
416 IsEqualIID(riid, &IID_IAudioClient) ||
417 IsEqualIID(riid, &IID_IAudioClient2) ||
418 IsEqualIID(riid, &IID_IAudioClient3))
419 *ppv = iface;
420 else if(IsEqualIID(riid, &IID_IMarshal))
421 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
422 if(*ppv){
423 IUnknown_AddRef((IUnknown*)*ppv);
424 return S_OK;
426 WARN("Unknown interface %s\n", debugstr_guid(riid));
427 return E_NOINTERFACE;
430 static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
432 ACImpl *This = impl_from_IAudioClient3(iface);
433 ULONG ref;
434 ref = InterlockedIncrement(&This->ref);
435 TRACE("(%p) Refcount now %u\n", This, ref);
436 return ref;
439 static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
441 ACImpl *This = impl_from_IAudioClient3(iface);
442 ULONG ref;
444 ref = InterlockedDecrement(&This->ref);
445 TRACE("(%p) Refcount now %u\n", This, ref);
446 if(!ref){
447 if(This->timer){
448 HANDLE event;
449 DWORD wait;
450 event = CreateEventW(NULL, TRUE, FALSE, NULL);
451 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
452 wait = wait && GetLastError() == ERROR_IO_PENDING;
453 if(event && wait)
454 WaitForSingleObject(event, INFINITE);
455 CloseHandle(event);
458 IAudioClient3_Stop(iface);
460 IMMDevice_Release(This->parent);
461 IUnknown_Release(This->pUnkFTMarshal);
462 This->lock.DebugInfo->Spare[0] = 0;
463 DeleteCriticalSection(&This->lock);
465 if(This->recorder)
466 SLCALL_N(This->recorder, Destroy);
467 if(This->player)
468 SLCALL_N(This->player, Destroy);
470 if(This->initted){
471 EnterCriticalSection(&g_sessions_lock);
472 list_remove(&This->entry);
473 LeaveCriticalSection(&g_sessions_lock);
475 HeapFree(GetProcessHeap(), 0, This->vols);
476 HeapFree(GetProcessHeap(), 0, This->local_buffer);
477 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
478 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
479 CoTaskMemFree(This->fmt);
480 HeapFree(GetProcessHeap(), 0, This);
482 return ref;
485 static void dump_fmt(const WAVEFORMATEX *fmt)
487 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
488 switch(fmt->wFormatTag){
489 case WAVE_FORMAT_PCM:
490 TRACE("WAVE_FORMAT_PCM");
491 break;
492 case WAVE_FORMAT_IEEE_FLOAT:
493 TRACE("WAVE_FORMAT_IEEE_FLOAT");
494 break;
495 case WAVE_FORMAT_EXTENSIBLE:
496 TRACE("WAVE_FORMAT_EXTENSIBLE");
497 break;
498 default:
499 TRACE("Unknown");
500 break;
502 TRACE(")\n");
504 TRACE("nChannels: %u\n", fmt->nChannels);
505 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
506 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
507 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
508 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
509 TRACE("cbSize: %u\n", fmt->cbSize);
511 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
512 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
513 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
514 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
515 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
519 static DWORD get_channel_mask(unsigned int channels)
521 switch(channels){
522 case 0:
523 return 0;
524 case 1:
525 return KSAUDIO_SPEAKER_MONO;
526 case 2:
527 return KSAUDIO_SPEAKER_STEREO;
528 case 3:
529 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
530 case 4:
531 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
532 case 5:
533 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
534 case 6:
535 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
536 case 7:
537 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
538 case 8:
539 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
541 FIXME("Unknown speaker configuration: %u\n", channels);
542 return 0;
545 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
547 WAVEFORMATEX *ret;
548 size_t size;
550 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
551 size = sizeof(WAVEFORMATEXTENSIBLE);
552 else
553 size = sizeof(WAVEFORMATEX);
555 ret = CoTaskMemAlloc(size);
556 if(!ret)
557 return NULL;
559 memcpy(ret, fmt, size);
561 ret->cbSize = size - sizeof(WAVEFORMATEX);
563 return ret;
566 static void session_init_vols(AudioSession *session, UINT channels)
568 if(session->channel_count < channels){
569 UINT i;
571 if(session->channel_vols)
572 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
573 session->channel_vols, sizeof(float) * channels);
574 else
575 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
576 sizeof(float) * channels);
577 if(!session->channel_vols)
578 return;
580 for(i = session->channel_count; i < channels; ++i)
581 session->channel_vols[i] = 1.f;
583 session->channel_count = channels;
587 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
588 UINT num_channels)
590 AudioSession *ret;
592 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
593 if(!ret)
594 return NULL;
596 memcpy(&ret->guid, guid, sizeof(GUID));
598 ret->device = device;
600 list_init(&ret->clients);
602 list_add_head(&g_sessions, &ret->entry);
604 InitializeCriticalSection(&ret->lock);
605 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
607 session_init_vols(ret, num_channels);
609 ret->master_vol = 1.f;
611 return ret;
614 /* if channels == 0, then this will return or create a session with
615 * matching dataflow and GUID. otherwise, channels must also match */
616 static HRESULT get_audio_session(const GUID *sessionguid,
617 IMMDevice *device, UINT channels, AudioSession **out)
619 AudioSession *session;
621 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
622 *out = create_session(&GUID_NULL, device, channels);
623 if(!*out)
624 return E_OUTOFMEMORY;
626 return S_OK;
629 *out = NULL;
630 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
631 if(session->device == device &&
632 IsEqualGUID(sessionguid, &session->guid)){
633 session_init_vols(session, channels);
634 *out = session;
635 break;
639 if(!*out){
640 *out = create_session(sessionguid, device, channels);
641 if(!*out)
642 return E_OUTOFMEMORY;
645 return S_OK;
648 static HRESULT waveformat_to_pcm(ACImpl *This, const WAVEFORMATEX *fmt, SLAndroidDataFormat_PCM_EX *pcm)
650 if(fmt->nSamplesPerSec < 8000 || fmt->nSamplesPerSec > 48000)
651 return AUDCLNT_E_UNSUPPORTED_FORMAT;
653 pcm->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
655 pcm->sampleRate = fmt->nSamplesPerSec * 1000; /* sampleRate is in milli-Hz */
656 pcm->bitsPerSample = fmt->wBitsPerSample;
657 pcm->containerSize = fmt->wBitsPerSample;
659 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
660 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
661 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
662 if(pcm->bitsPerSample == 8)
663 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
664 else if(pcm->bitsPerSample == 16)
665 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
666 else
667 return AUDCLNT_E_UNSUPPORTED_FORMAT;
668 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
669 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
670 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
671 if(pcm->bitsPerSample == 32)
672 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
673 else
674 return AUDCLNT_E_UNSUPPORTED_FORMAT;
675 }else
676 return AUDCLNT_E_UNSUPPORTED_FORMAT;
678 /* only up to stereo */
679 pcm->numChannels = fmt->nChannels;
680 if(pcm->numChannels == 1)
681 pcm->channelMask = SL_SPEAKER_FRONT_CENTER;
682 else if(This->dataflow == eRender && pcm->numChannels == 2)
683 pcm->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
684 else
685 return AUDCLNT_E_UNSUPPORTED_FORMAT;
687 pcm->endianness = SL_BYTEORDER_LITTLEENDIAN;
689 return S_OK;
692 static HRESULT try_open_render_device(SLAndroidDataFormat_PCM_EX *pcm, unsigned int num_buffers, SLObjectItf *out)
694 SLresult sr;
695 SLDataSource source;
696 SLDataSink sink;
697 SLDataLocator_OutputMix loc_outmix;
698 SLboolean required[2];
699 SLInterfaceID iids[2];
700 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
701 SLObjectItf player;
703 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
704 loc_bq.numBuffers = num_buffers;
705 source.pLocator = &loc_bq;
706 source.pFormat = pcm;
708 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
709 loc_outmix.outputMix = outputmix;
710 sink.pLocator = &loc_outmix;
711 sink.pFormat = NULL;
713 required[0] = SL_BOOLEAN_TRUE;
714 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
715 required[1] = SL_BOOLEAN_TRUE;
716 iids[1] = *pSL_IID_PLAYBACKRATE;
718 sr = SLCALL(engine, CreateAudioPlayer, &player, &source, &sink,
719 2, iids, required);
720 if(sr != SL_RESULT_SUCCESS){
721 WARN("CreateAudioPlayer failed: 0x%x\n", sr);
722 return E_FAIL;
725 sr = SLCALL(player, Realize, SL_BOOLEAN_FALSE);
726 if(sr != SL_RESULT_SUCCESS){
727 SLCALL_N(player, Destroy);
728 WARN("Player Realize failed: 0x%x\n", sr);
729 return E_FAIL;
732 if(out)
733 *out = player;
734 else
735 SLCALL_N(player, Destroy);
737 return S_OK;
740 static HRESULT try_open_capture_device(SLAndroidDataFormat_PCM_EX *pcm, unsigned int num_buffers, SLObjectItf *out)
742 SLresult sr;
743 SLDataSource source;
744 SLDataSink sink;
745 SLDataLocator_IODevice loc_mic;
746 SLboolean required[1];
747 SLInterfaceID iids[1];
748 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
749 SLObjectItf recorder;
751 loc_mic.locatorType = SL_DATALOCATOR_IODEVICE;
752 loc_mic.deviceType = SL_IODEVICE_AUDIOINPUT;
753 loc_mic.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
754 loc_mic.device = NULL;
755 source.pLocator = &loc_mic;
756 source.pFormat = NULL;
758 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
759 loc_bq.numBuffers = num_buffers;
760 sink.pLocator = &loc_bq;
761 sink.pFormat = pcm;
763 required[0] = SL_BOOLEAN_TRUE;
764 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
766 sr = SLCALL(engine, CreateAudioRecorder, &recorder, &source, &sink,
767 1, iids, required);
768 if(sr != SL_RESULT_SUCCESS){
769 WARN("CreateAudioRecorder failed: 0x%x\n", sr);
770 return E_FAIL;
773 sr = SLCALL(recorder, Realize, SL_BOOLEAN_FALSE);
774 if(sr != SL_RESULT_SUCCESS){
775 SLCALL_N(recorder, Destroy);
776 WARN("Recorder Realize failed: 0x%x\n", sr);
777 return E_FAIL;
780 if(out)
781 *out = recorder;
782 else
783 SLCALL_N(recorder, Destroy);
785 return S_OK;
788 static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
789 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
790 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
791 const GUID *sessionguid)
793 ACImpl *This = impl_from_IAudioClient3(iface);
794 int i, num_buffers;
795 HRESULT hr;
796 SLresult sr;
797 SLAndroidDataFormat_PCM_EX pcm;
799 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
800 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
802 if(!fmt)
803 return E_POINTER;
805 dump_fmt(fmt);
807 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
808 return E_INVALIDARG;
810 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
811 AUDCLNT_STREAMFLAGS_LOOPBACK |
812 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
813 AUDCLNT_STREAMFLAGS_NOPERSIST |
814 AUDCLNT_STREAMFLAGS_RATEADJUST |
815 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
816 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
817 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED |
818 AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY |
819 AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){
820 FIXME("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(IAudioClient3 *iface,
1024 UINT32 *frames)
1026 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface,
1050 REFERENCE_TIME *latency)
1052 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface,
1076 UINT32 *numpad)
1078 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface,
1102 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1103 WAVEFORMATEX **outpwfx)
1105 ACImpl *This = impl_from_IAudioClient3(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 = IAudioClient3_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(IAudioClient3 *iface,
1152 WAVEFORMATEX **pwfx)
1154 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface,
1190 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1192 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface)
1348 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface)
1402 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface)
1444 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface,
1500 HANDLE event)
1502 ACImpl *This = impl_from_IAudioClient3(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(IAudioClient3 *iface, REFIID riid,
1535 void **ppv)
1537 ACImpl *This = impl_from_IAudioClient3(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 HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
1619 AUDIO_STREAM_CATEGORY category, BOOL *offload_capable)
1621 ACImpl *This = impl_from_IAudioClient3(iface);
1623 TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable);
1625 if(!offload_capable)
1626 return E_INVALIDARG;
1628 *offload_capable = FALSE;
1630 return S_OK;
1633 static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface,
1634 const AudioClientProperties *prop)
1636 ACImpl *This = impl_from_IAudioClient3(iface);
1637 const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop;
1639 TRACE("(%p)->(%p)\n", This, prop);
1641 if(!legacy_prop)
1642 return E_POINTER;
1644 if(legacy_prop->cbSize == sizeof(AudioClientProperties)){
1645 TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n",
1646 legacy_prop->bIsOffload,
1647 legacy_prop->eCategory,
1648 prop->Options);
1649 }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){
1650 TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n",
1651 legacy_prop->bIsOffload,
1652 legacy_prop->eCategory);
1653 }else{
1654 WARN("Unsupported Size = %d\n", legacy_prop->cbSize);
1655 return E_INVALIDARG;
1659 if(legacy_prop->bIsOffload)
1660 return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE;
1662 return S_OK;
1665 static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface,
1666 const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration,
1667 REFERENCE_TIME *max_duration)
1669 ACImpl *This = impl_from_IAudioClient3(iface);
1671 FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration);
1673 return E_NOTIMPL;
1676 static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface,
1677 const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames,
1678 UINT32 *min_period_frames, UINT32 *max_period_frames)
1680 ACImpl *This = impl_from_IAudioClient3(iface);
1682 FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames,
1683 min_period_frames, max_period_frames);
1685 return E_NOTIMPL;
1688 static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface,
1689 WAVEFORMATEX **cur_format, UINT32 *cur_period_frames)
1691 ACImpl *This = impl_from_IAudioClient3(iface);
1693 FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames);
1695 return E_NOTIMPL;
1698 static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface,
1699 DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format,
1700 const GUID *session_guid)
1702 ACImpl *This = impl_from_IAudioClient3(iface);
1704 FIXME("(%p)->(0x%x, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid));
1706 return E_NOTIMPL;
1709 static const IAudioClient3Vtbl AudioClient3_Vtbl =
1711 AudioClient_QueryInterface,
1712 AudioClient_AddRef,
1713 AudioClient_Release,
1714 AudioClient_Initialize,
1715 AudioClient_GetBufferSize,
1716 AudioClient_GetStreamLatency,
1717 AudioClient_GetCurrentPadding,
1718 AudioClient_IsFormatSupported,
1719 AudioClient_GetMixFormat,
1720 AudioClient_GetDevicePeriod,
1721 AudioClient_Start,
1722 AudioClient_Stop,
1723 AudioClient_Reset,
1724 AudioClient_SetEventHandle,
1725 AudioClient_GetService,
1726 AudioClient_IsOffloadCapable,
1727 AudioClient_SetClientProperties,
1728 AudioClient_GetBufferSizeLimits,
1729 AudioClient_GetSharedModeEnginePeriod,
1730 AudioClient_GetCurrentSharedModeEnginePeriod,
1731 AudioClient_InitializeSharedAudioStream,
1734 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1735 IAudioRenderClient *iface, REFIID riid, void **ppv)
1737 ACImpl *This = impl_from_IAudioRenderClient(iface);
1738 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1740 if(!ppv)
1741 return E_POINTER;
1742 *ppv = NULL;
1744 if(IsEqualIID(riid, &IID_IUnknown) ||
1745 IsEqualIID(riid, &IID_IAudioRenderClient))
1746 *ppv = iface;
1747 else if(IsEqualIID(riid, &IID_IMarshal))
1748 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1749 if(*ppv){
1750 IUnknown_AddRef((IUnknown*)*ppv);
1751 return S_OK;
1754 WARN("Unknown interface %s\n", debugstr_guid(riid));
1755 return E_NOINTERFACE;
1758 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1760 ACImpl *This = impl_from_IAudioRenderClient(iface);
1761 return AudioClient_AddRef(&This->IAudioClient3_iface);
1764 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1766 ACImpl *This = impl_from_IAudioRenderClient(iface);
1767 return AudioClient_Release(&This->IAudioClient3_iface);
1770 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1771 UINT32 frames, BYTE **data)
1773 ACImpl *This = impl_from_IAudioRenderClient(iface);
1774 UINT32 write_pos;
1776 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1778 if(!data)
1779 return E_POINTER;
1781 *data = NULL;
1783 EnterCriticalSection(&This->lock);
1785 if(This->getbuf_last){
1786 LeaveCriticalSection(&This->lock);
1787 return AUDCLNT_E_OUT_OF_ORDER;
1790 if(!frames){
1791 LeaveCriticalSection(&This->lock);
1792 return S_OK;
1795 if(This->held_frames + frames > This->bufsize_frames){
1796 LeaveCriticalSection(&This->lock);
1797 return AUDCLNT_E_BUFFER_TOO_LARGE;
1800 write_pos =
1801 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1802 if(write_pos + frames > This->bufsize_frames){
1803 if(This->tmp_buffer_frames < frames){
1804 DWORD alloc = frames < This->period_frames ? This->period_frames : frames;
1805 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1806 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1807 alloc * This->fmt->nBlockAlign);
1808 if(!This->tmp_buffer){
1809 LeaveCriticalSection(&This->lock);
1810 return E_OUTOFMEMORY;
1812 This->tmp_buffer_frames = alloc;
1814 *data = This->tmp_buffer;
1815 This->getbuf_last = -frames;
1816 }else{
1817 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1818 This->getbuf_last = frames;
1821 silence_buffer(This, *data, frames);
1823 LeaveCriticalSection(&This->lock);
1825 return S_OK;
1828 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1830 UINT32 write_offs_frames =
1831 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1832 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1833 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1834 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1835 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1837 if(written_bytes <= chunk_bytes){
1838 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1839 }else{
1840 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1841 memcpy(This->local_buffer, buffer + chunk_bytes,
1842 written_bytes - chunk_bytes);
1846 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1847 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1849 ACImpl *This = impl_from_IAudioRenderClient(iface);
1850 BYTE *buffer;
1852 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1854 EnterCriticalSection(&This->lock);
1856 if(!written_frames){
1857 This->getbuf_last = 0;
1858 LeaveCriticalSection(&This->lock);
1859 return S_OK;
1862 if(!This->getbuf_last){
1863 LeaveCriticalSection(&This->lock);
1864 return AUDCLNT_E_OUT_OF_ORDER;
1867 if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1868 LeaveCriticalSection(&This->lock);
1869 return AUDCLNT_E_INVALID_SIZE;
1872 if(This->getbuf_last >= 0)
1873 buffer = This->local_buffer + This->fmt->nBlockAlign *
1874 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1875 else
1876 buffer = This->tmp_buffer;
1878 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1879 silence_buffer(This, buffer, written_frames);
1881 if(This->getbuf_last < 0)
1882 oss_wrap_buffer(This, buffer, written_frames);
1884 This->held_frames += written_frames;
1885 This->written_frames += written_frames;
1886 This->getbuf_last = 0;
1888 LeaveCriticalSection(&This->lock);
1890 return S_OK;
1893 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1894 AudioRenderClient_QueryInterface,
1895 AudioRenderClient_AddRef,
1896 AudioRenderClient_Release,
1897 AudioRenderClient_GetBuffer,
1898 AudioRenderClient_ReleaseBuffer
1901 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1902 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1904 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1905 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1907 if(!ppv)
1908 return E_POINTER;
1909 *ppv = NULL;
1911 if(IsEqualIID(riid, &IID_IUnknown) ||
1912 IsEqualIID(riid, &IID_IAudioCaptureClient))
1913 *ppv = iface;
1914 else if(IsEqualIID(riid, &IID_IMarshal))
1915 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1916 if(*ppv){
1917 IUnknown_AddRef((IUnknown*)*ppv);
1918 return S_OK;
1921 WARN("Unknown interface %s\n", debugstr_guid(riid));
1922 return E_NOINTERFACE;
1925 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1927 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1928 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
1931 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1933 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1934 return IAudioClient3_Release(&This->IAudioClient3_iface);
1937 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1938 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1939 UINT64 *qpcpos)
1941 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1943 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1944 devpos, qpcpos);
1946 if(!data)
1947 return E_POINTER;
1949 *data = NULL;
1951 if(!frames || !flags)
1952 return E_POINTER;
1954 EnterCriticalSection(&This->lock);
1956 if(This->getbuf_last){
1957 LeaveCriticalSection(&This->lock);
1958 return AUDCLNT_E_OUT_OF_ORDER;
1961 if(This->held_frames < This->period_frames){
1962 *frames = 0;
1963 LeaveCriticalSection(&This->lock);
1964 return AUDCLNT_S_BUFFER_EMPTY;
1967 *flags = 0;
1969 *frames = This->period_frames;
1971 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1972 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1973 if(This->tmp_buffer_frames < *frames){
1974 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1975 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1976 *frames * This->fmt->nBlockAlign);
1977 if(!This->tmp_buffer){
1978 LeaveCriticalSection(&This->lock);
1979 return E_OUTOFMEMORY;
1981 This->tmp_buffer_frames = *frames;
1984 *data = This->tmp_buffer;
1985 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1986 This->fmt->nBlockAlign;
1987 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1988 frames_bytes = *frames * This->fmt->nBlockAlign;
1989 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1990 memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
1991 frames_bytes - chunk_bytes);
1992 }else
1993 *data = This->local_buffer +
1994 This->lcl_offs_frames * This->fmt->nBlockAlign;
1995 TRACE("returning %u from %u\n", This->period_frames, This->lcl_offs_frames);
1997 This->getbuf_last = *frames;
1999 if(devpos)
2000 *devpos = This->written_frames;
2001 if(qpcpos){
2002 LARGE_INTEGER stamp, freq;
2003 QueryPerformanceCounter(&stamp);
2004 QueryPerformanceFrequency(&freq);
2005 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2008 LeaveCriticalSection(&This->lock);
2010 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2013 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2014 IAudioCaptureClient *iface, UINT32 done)
2016 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2018 TRACE("(%p)->(%u)\n", This, done);
2020 EnterCriticalSection(&This->lock);
2022 if(!done){
2023 This->getbuf_last = 0;
2024 LeaveCriticalSection(&This->lock);
2025 return S_OK;
2028 if(!This->getbuf_last){
2029 LeaveCriticalSection(&This->lock);
2030 return AUDCLNT_E_OUT_OF_ORDER;
2033 if(This->getbuf_last != done){
2034 LeaveCriticalSection(&This->lock);
2035 return AUDCLNT_E_INVALID_SIZE;
2038 This->written_frames += done;
2039 This->held_frames -= done;
2040 This->lcl_offs_frames += done;
2041 This->lcl_offs_frames %= This->bufsize_frames;
2042 This->getbuf_last = 0;
2043 TRACE("lcl: %u, held: %u\n", This->lcl_offs_frames, This->held_frames);
2045 LeaveCriticalSection(&This->lock);
2047 return S_OK;
2050 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2051 IAudioCaptureClient *iface, UINT32 *frames)
2053 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2055 TRACE("(%p)->(%p)\n", This, frames);
2057 if(!frames)
2058 return E_POINTER;
2060 EnterCriticalSection(&This->lock);
2062 *frames = This->held_frames < This->period_frames ? 0 : This->period_frames;
2064 LeaveCriticalSection(&This->lock);
2066 return S_OK;
2069 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2071 AudioCaptureClient_QueryInterface,
2072 AudioCaptureClient_AddRef,
2073 AudioCaptureClient_Release,
2074 AudioCaptureClient_GetBuffer,
2075 AudioCaptureClient_ReleaseBuffer,
2076 AudioCaptureClient_GetNextPacketSize
2079 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2080 REFIID riid, void **ppv)
2082 ACImpl *This = impl_from_IAudioClock(iface);
2084 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2086 if(!ppv)
2087 return E_POINTER;
2088 *ppv = NULL;
2090 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2091 *ppv = iface;
2092 else if(IsEqualIID(riid, &IID_IAudioClock2))
2093 *ppv = &This->IAudioClock2_iface;
2094 if(*ppv){
2095 IUnknown_AddRef((IUnknown*)*ppv);
2096 return S_OK;
2099 WARN("Unknown interface %s\n", debugstr_guid(riid));
2100 return E_NOINTERFACE;
2103 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2105 ACImpl *This = impl_from_IAudioClock(iface);
2106 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
2109 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2111 ACImpl *This = impl_from_IAudioClock(iface);
2112 return IAudioClient3_Release(&This->IAudioClient3_iface);
2115 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2117 ACImpl *This = impl_from_IAudioClock(iface);
2119 TRACE("(%p)->(%p)\n", This, freq);
2121 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2122 *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
2123 else
2124 *freq = This->fmt->nSamplesPerSec;
2126 return S_OK;
2129 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2130 UINT64 *qpctime)
2132 ACImpl *This = impl_from_IAudioClock(iface);
2134 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2136 if(!pos)
2137 return E_POINTER;
2139 EnterCriticalSection(&This->lock);
2141 if(This->dataflow == eRender){
2142 *pos = This->written_frames - This->held_frames;
2143 if(*pos < This->last_pos_frames)
2144 *pos = This->last_pos_frames;
2145 }else if(This->dataflow == eCapture){
2146 *pos = This->written_frames - This->held_frames;
2149 This->last_pos_frames = *pos;
2151 TRACE("returning: 0x%s\n", wine_dbgstr_longlong(*pos));
2152 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2153 *pos *= This->fmt->nBlockAlign;
2155 LeaveCriticalSection(&This->lock);
2157 if(qpctime){
2158 LARGE_INTEGER stamp, freq;
2159 QueryPerformanceCounter(&stamp);
2160 QueryPerformanceFrequency(&freq);
2161 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2164 return S_OK;
2167 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2168 DWORD *chars)
2170 ACImpl *This = impl_from_IAudioClock(iface);
2172 TRACE("(%p)->(%p)\n", This, chars);
2174 if(!chars)
2175 return E_POINTER;
2177 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2179 return S_OK;
2182 static const IAudioClockVtbl AudioClock_Vtbl =
2184 AudioClock_QueryInterface,
2185 AudioClock_AddRef,
2186 AudioClock_Release,
2187 AudioClock_GetFrequency,
2188 AudioClock_GetPosition,
2189 AudioClock_GetCharacteristics
2192 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2193 REFIID riid, void **ppv)
2195 ACImpl *This = impl_from_IAudioClock2(iface);
2196 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2199 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2201 ACImpl *This = impl_from_IAudioClock2(iface);
2202 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
2205 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2207 ACImpl *This = impl_from_IAudioClock2(iface);
2208 return IAudioClient3_Release(&This->IAudioClient3_iface);
2211 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2212 UINT64 *pos, UINT64 *qpctime)
2214 ACImpl *This = impl_from_IAudioClock2(iface);
2216 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2218 return E_NOTIMPL;
2221 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2223 AudioClock2_QueryInterface,
2224 AudioClock2_AddRef,
2225 AudioClock2_Release,
2226 AudioClock2_GetDevicePosition
2229 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2231 AudioSessionWrapper *ret;
2233 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2234 sizeof(AudioSessionWrapper));
2235 if(!ret)
2236 return NULL;
2238 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2239 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2240 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2242 ret->ref = 1;
2244 ret->client = client;
2245 if(client){
2246 ret->session = client->session;
2247 AudioClient_AddRef(&client->IAudioClient3_iface);
2250 return ret;
2253 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2254 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2256 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2258 if(!ppv)
2259 return E_POINTER;
2260 *ppv = NULL;
2262 if(IsEqualIID(riid, &IID_IUnknown) ||
2263 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2264 IsEqualIID(riid, &IID_IAudioSessionControl2))
2265 *ppv = iface;
2266 if(*ppv){
2267 IUnknown_AddRef((IUnknown*)*ppv);
2268 return S_OK;
2271 WARN("Unknown interface %s\n", debugstr_guid(riid));
2272 return E_NOINTERFACE;
2275 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2277 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2278 ULONG ref;
2279 ref = InterlockedIncrement(&This->ref);
2280 TRACE("(%p) Refcount now %u\n", This, ref);
2281 return ref;
2284 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2286 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2287 ULONG ref;
2288 ref = InterlockedDecrement(&This->ref);
2289 TRACE("(%p) Refcount now %u\n", This, ref);
2290 if(!ref){
2291 if(This->client){
2292 EnterCriticalSection(&This->client->lock);
2293 This->client->session_wrapper = NULL;
2294 LeaveCriticalSection(&This->client->lock);
2295 AudioClient_Release(&This->client->IAudioClient3_iface);
2297 HeapFree(GetProcessHeap(), 0, This);
2299 return ref;
2302 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2303 AudioSessionState *state)
2305 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2306 ACImpl *client;
2308 TRACE("(%p)->(%p)\n", This, state);
2310 if(!state)
2311 return NULL_PTR_ERR;
2313 EnterCriticalSection(&g_sessions_lock);
2315 if(list_empty(&This->session->clients)){
2316 *state = AudioSessionStateExpired;
2317 LeaveCriticalSection(&g_sessions_lock);
2318 return S_OK;
2321 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2322 EnterCriticalSection(&client->lock);
2323 if(client->playing){
2324 *state = AudioSessionStateActive;
2325 LeaveCriticalSection(&client->lock);
2326 LeaveCriticalSection(&g_sessions_lock);
2327 return S_OK;
2329 LeaveCriticalSection(&client->lock);
2332 LeaveCriticalSection(&g_sessions_lock);
2334 *state = AudioSessionStateInactive;
2336 return S_OK;
2339 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2340 IAudioSessionControl2 *iface, WCHAR **name)
2342 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2344 FIXME("(%p)->(%p) - stub\n", This, name);
2346 return E_NOTIMPL;
2349 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2350 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2352 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2354 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2356 return E_NOTIMPL;
2359 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2360 IAudioSessionControl2 *iface, WCHAR **path)
2362 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2364 FIXME("(%p)->(%p) - stub\n", This, path);
2366 return E_NOTIMPL;
2369 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2370 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2372 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2374 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2376 return E_NOTIMPL;
2379 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2380 IAudioSessionControl2 *iface, GUID *group)
2382 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2384 FIXME("(%p)->(%p) - stub\n", This, group);
2386 return E_NOTIMPL;
2389 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2390 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2392 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2394 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2395 debugstr_guid(session));
2397 return E_NOTIMPL;
2400 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2401 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2403 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2405 FIXME("(%p)->(%p) - stub\n", This, events);
2407 return S_OK;
2410 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2411 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2413 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2415 FIXME("(%p)->(%p) - stub\n", This, events);
2417 return S_OK;
2420 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2421 IAudioSessionControl2 *iface, WCHAR **id)
2423 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2425 FIXME("(%p)->(%p) - stub\n", This, id);
2427 return E_NOTIMPL;
2430 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2431 IAudioSessionControl2 *iface, WCHAR **id)
2433 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2435 FIXME("(%p)->(%p) - stub\n", This, id);
2437 return E_NOTIMPL;
2440 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2441 IAudioSessionControl2 *iface, DWORD *pid)
2443 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2445 TRACE("(%p)->(%p)\n", This, pid);
2447 if(!pid)
2448 return E_POINTER;
2450 *pid = GetCurrentProcessId();
2452 return S_OK;
2455 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2456 IAudioSessionControl2 *iface)
2458 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2460 TRACE("(%p)\n", This);
2462 return S_FALSE;
2465 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2466 IAudioSessionControl2 *iface, BOOL optout)
2468 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2470 TRACE("(%p)->(%d)\n", This, optout);
2472 return S_OK;
2475 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2477 AudioSessionControl_QueryInterface,
2478 AudioSessionControl_AddRef,
2479 AudioSessionControl_Release,
2480 AudioSessionControl_GetState,
2481 AudioSessionControl_GetDisplayName,
2482 AudioSessionControl_SetDisplayName,
2483 AudioSessionControl_GetIconPath,
2484 AudioSessionControl_SetIconPath,
2485 AudioSessionControl_GetGroupingParam,
2486 AudioSessionControl_SetGroupingParam,
2487 AudioSessionControl_RegisterAudioSessionNotification,
2488 AudioSessionControl_UnregisterAudioSessionNotification,
2489 AudioSessionControl_GetSessionIdentifier,
2490 AudioSessionControl_GetSessionInstanceIdentifier,
2491 AudioSessionControl_GetProcessId,
2492 AudioSessionControl_IsSystemSoundsSession,
2493 AudioSessionControl_SetDuckingPreference
2496 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2497 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2499 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2501 if(!ppv)
2502 return E_POINTER;
2503 *ppv = NULL;
2505 if(IsEqualIID(riid, &IID_IUnknown) ||
2506 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2507 *ppv = iface;
2508 if(*ppv){
2509 IUnknown_AddRef((IUnknown*)*ppv);
2510 return S_OK;
2513 WARN("Unknown interface %s\n", debugstr_guid(riid));
2514 return E_NOINTERFACE;
2517 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2519 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2520 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2523 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2525 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2526 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2529 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2530 ISimpleAudioVolume *iface, float level, const GUID *context)
2532 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2533 AudioSession *session = This->session;
2535 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2537 if(level < 0.f || level > 1.f)
2538 return E_INVALIDARG;
2540 if(context)
2541 FIXME("Notifications not supported yet\n");
2543 EnterCriticalSection(&session->lock);
2545 session->master_vol = level;
2547 TRACE("OSS doesn't support setting volume\n");
2549 LeaveCriticalSection(&session->lock);
2551 return S_OK;
2554 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2555 ISimpleAudioVolume *iface, float *level)
2557 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2558 AudioSession *session = This->session;
2560 TRACE("(%p)->(%p)\n", session, level);
2562 if(!level)
2563 return NULL_PTR_ERR;
2565 *level = session->master_vol;
2567 return S_OK;
2570 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2571 BOOL mute, const GUID *context)
2573 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2574 AudioSession *session = This->session;
2576 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2578 EnterCriticalSection(&session->lock);
2580 session->mute = mute;
2582 LeaveCriticalSection(&session->lock);
2584 return S_OK;
2587 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2588 BOOL *mute)
2590 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2591 AudioSession *session = This->session;
2593 TRACE("(%p)->(%p)\n", session, mute);
2595 if(!mute)
2596 return NULL_PTR_ERR;
2598 *mute = This->session->mute;
2600 return S_OK;
2603 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2605 SimpleAudioVolume_QueryInterface,
2606 SimpleAudioVolume_AddRef,
2607 SimpleAudioVolume_Release,
2608 SimpleAudioVolume_SetMasterVolume,
2609 SimpleAudioVolume_GetMasterVolume,
2610 SimpleAudioVolume_SetMute,
2611 SimpleAudioVolume_GetMute
2614 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2615 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2617 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2619 if(!ppv)
2620 return E_POINTER;
2621 *ppv = NULL;
2623 if(IsEqualIID(riid, &IID_IUnknown) ||
2624 IsEqualIID(riid, &IID_IAudioStreamVolume))
2625 *ppv = iface;
2626 if(*ppv){
2627 IUnknown_AddRef((IUnknown*)*ppv);
2628 return S_OK;
2631 WARN("Unknown interface %s\n", debugstr_guid(riid));
2632 return E_NOINTERFACE;
2635 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2637 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2638 return IAudioClient3_AddRef(&This->IAudioClient3_iface);
2641 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2643 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2644 return IAudioClient3_Release(&This->IAudioClient3_iface);
2647 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2648 IAudioStreamVolume *iface, UINT32 *out)
2650 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2652 TRACE("(%p)->(%p)\n", This, out);
2654 if(!out)
2655 return E_POINTER;
2657 *out = This->fmt->nChannels;
2659 return S_OK;
2662 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2663 IAudioStreamVolume *iface, UINT32 index, float level)
2665 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2667 TRACE("(%p)->(%d, %f)\n", This, index, level);
2669 if(level < 0.f || level > 1.f)
2670 return E_INVALIDARG;
2672 if(index >= This->fmt->nChannels)
2673 return E_INVALIDARG;
2675 EnterCriticalSection(&This->lock);
2677 This->vols[index] = level;
2679 TRACE("OSS doesn't support setting volume\n");
2681 LeaveCriticalSection(&This->lock);
2683 return S_OK;
2686 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2687 IAudioStreamVolume *iface, UINT32 index, float *level)
2689 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2691 TRACE("(%p)->(%d, %p)\n", This, index, level);
2693 if(!level)
2694 return E_POINTER;
2696 if(index >= This->fmt->nChannels)
2697 return E_INVALIDARG;
2699 *level = This->vols[index];
2701 return S_OK;
2704 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2705 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2707 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2708 int i;
2710 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2712 if(!levels)
2713 return E_POINTER;
2715 if(count != This->fmt->nChannels)
2716 return E_INVALIDARG;
2718 EnterCriticalSection(&This->lock);
2720 for(i = 0; i < count; ++i)
2721 This->vols[i] = levels[i];
2723 TRACE("OSS doesn't support setting volume\n");
2725 LeaveCriticalSection(&This->lock);
2727 return S_OK;
2730 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2731 IAudioStreamVolume *iface, UINT32 count, float *levels)
2733 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2734 int i;
2736 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2738 if(!levels)
2739 return E_POINTER;
2741 if(count != This->fmt->nChannels)
2742 return E_INVALIDARG;
2744 EnterCriticalSection(&This->lock);
2746 for(i = 0; i < count; ++i)
2747 levels[i] = This->vols[i];
2749 LeaveCriticalSection(&This->lock);
2751 return S_OK;
2754 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2756 AudioStreamVolume_QueryInterface,
2757 AudioStreamVolume_AddRef,
2758 AudioStreamVolume_Release,
2759 AudioStreamVolume_GetChannelCount,
2760 AudioStreamVolume_SetChannelVolume,
2761 AudioStreamVolume_GetChannelVolume,
2762 AudioStreamVolume_SetAllVolumes,
2763 AudioStreamVolume_GetAllVolumes
2766 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2767 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2769 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2771 if(!ppv)
2772 return E_POINTER;
2773 *ppv = NULL;
2775 if(IsEqualIID(riid, &IID_IUnknown) ||
2776 IsEqualIID(riid, &IID_IChannelAudioVolume))
2777 *ppv = iface;
2778 if(*ppv){
2779 IUnknown_AddRef((IUnknown*)*ppv);
2780 return S_OK;
2783 WARN("Unknown interface %s\n", debugstr_guid(riid));
2784 return E_NOINTERFACE;
2787 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2789 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2790 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2793 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2795 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2796 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2799 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2800 IChannelAudioVolume *iface, UINT32 *out)
2802 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2803 AudioSession *session = This->session;
2805 TRACE("(%p)->(%p)\n", session, out);
2807 if(!out)
2808 return NULL_PTR_ERR;
2810 *out = session->channel_count;
2812 return S_OK;
2815 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2816 IChannelAudioVolume *iface, UINT32 index, float level,
2817 const GUID *context)
2819 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2820 AudioSession *session = This->session;
2822 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2823 wine_dbgstr_guid(context));
2825 if(level < 0.f || level > 1.f)
2826 return E_INVALIDARG;
2828 if(index >= session->channel_count)
2829 return E_INVALIDARG;
2831 if(context)
2832 FIXME("Notifications not supported yet\n");
2834 EnterCriticalSection(&session->lock);
2836 session->channel_vols[index] = level;
2838 TRACE("OSS doesn't support setting volume\n");
2840 LeaveCriticalSection(&session->lock);
2842 return S_OK;
2845 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2846 IChannelAudioVolume *iface, UINT32 index, float *level)
2848 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2849 AudioSession *session = This->session;
2851 TRACE("(%p)->(%d, %p)\n", session, index, level);
2853 if(!level)
2854 return NULL_PTR_ERR;
2856 if(index >= session->channel_count)
2857 return E_INVALIDARG;
2859 *level = session->channel_vols[index];
2861 return S_OK;
2864 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2865 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2866 const GUID *context)
2868 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2869 AudioSession *session = This->session;
2870 int i;
2872 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2873 wine_dbgstr_guid(context));
2875 if(!levels)
2876 return NULL_PTR_ERR;
2878 if(count != session->channel_count)
2879 return E_INVALIDARG;
2881 if(context)
2882 FIXME("Notifications not supported yet\n");
2884 EnterCriticalSection(&session->lock);
2886 for(i = 0; i < count; ++i)
2887 session->channel_vols[i] = levels[i];
2889 TRACE("OSS doesn't support setting volume\n");
2891 LeaveCriticalSection(&session->lock);
2893 return S_OK;
2896 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2897 IChannelAudioVolume *iface, UINT32 count, float *levels)
2899 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2900 AudioSession *session = This->session;
2901 int i;
2903 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2905 if(!levels)
2906 return NULL_PTR_ERR;
2908 if(count != session->channel_count)
2909 return E_INVALIDARG;
2911 for(i = 0; i < count; ++i)
2912 levels[i] = session->channel_vols[i];
2914 return S_OK;
2917 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2919 ChannelAudioVolume_QueryInterface,
2920 ChannelAudioVolume_AddRef,
2921 ChannelAudioVolume_Release,
2922 ChannelAudioVolume_GetChannelCount,
2923 ChannelAudioVolume_SetChannelVolume,
2924 ChannelAudioVolume_GetChannelVolume,
2925 ChannelAudioVolume_SetAllVolumes,
2926 ChannelAudioVolume_GetAllVolumes
2929 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2930 REFIID riid, void **ppv)
2932 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2934 if(!ppv)
2935 return E_POINTER;
2936 *ppv = NULL;
2938 if(IsEqualIID(riid, &IID_IUnknown) ||
2939 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2940 IsEqualIID(riid, &IID_IAudioSessionManager2))
2941 *ppv = iface;
2942 if(*ppv){
2943 IUnknown_AddRef((IUnknown*)*ppv);
2944 return S_OK;
2947 WARN("Unknown interface %s\n", debugstr_guid(riid));
2948 return E_NOINTERFACE;
2951 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2953 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2954 ULONG ref;
2955 ref = InterlockedIncrement(&This->ref);
2956 TRACE("(%p) Refcount now %u\n", This, ref);
2957 return ref;
2960 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2962 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2963 ULONG ref;
2964 ref = InterlockedDecrement(&This->ref);
2965 TRACE("(%p) Refcount now %u\n", This, ref);
2966 if(!ref)
2967 HeapFree(GetProcessHeap(), 0, This);
2968 return ref;
2971 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2972 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2973 IAudioSessionControl **out)
2975 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2976 AudioSession *session;
2977 AudioSessionWrapper *wrapper;
2978 HRESULT hr;
2980 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2981 flags, out);
2983 hr = get_audio_session(session_guid, This->device, 0, &session);
2984 if(FAILED(hr))
2985 return hr;
2987 wrapper = AudioSessionWrapper_Create(NULL);
2988 if(!wrapper)
2989 return E_OUTOFMEMORY;
2991 wrapper->session = session;
2993 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2995 return S_OK;
2998 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2999 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3000 ISimpleAudioVolume **out)
3002 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3003 AudioSession *session;
3004 AudioSessionWrapper *wrapper;
3005 HRESULT hr;
3007 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3008 flags, out);
3010 hr = get_audio_session(session_guid, This->device, 0, &session);
3011 if(FAILED(hr))
3012 return hr;
3014 wrapper = AudioSessionWrapper_Create(NULL);
3015 if(!wrapper)
3016 return E_OUTOFMEMORY;
3018 wrapper->session = session;
3020 *out = &wrapper->ISimpleAudioVolume_iface;
3022 return S_OK;
3025 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3026 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3028 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3029 FIXME("(%p)->(%p) - stub\n", This, out);
3030 return E_NOTIMPL;
3033 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3034 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3036 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3037 FIXME("(%p)->(%p) - stub\n", This, notification);
3038 return E_NOTIMPL;
3041 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3042 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3044 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3045 FIXME("(%p)->(%p) - stub\n", This, notification);
3046 return E_NOTIMPL;
3049 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3050 IAudioSessionManager2 *iface, const WCHAR *session_id,
3051 IAudioVolumeDuckNotification *notification)
3053 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3054 FIXME("(%p)->(%p) - stub\n", This, notification);
3055 return E_NOTIMPL;
3058 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3059 IAudioSessionManager2 *iface,
3060 IAudioVolumeDuckNotification *notification)
3062 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3063 FIXME("(%p)->(%p) - stub\n", This, notification);
3064 return E_NOTIMPL;
3067 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3069 AudioSessionManager_QueryInterface,
3070 AudioSessionManager_AddRef,
3071 AudioSessionManager_Release,
3072 AudioSessionManager_GetAudioSessionControl,
3073 AudioSessionManager_GetSimpleAudioVolume,
3074 AudioSessionManager_GetSessionEnumerator,
3075 AudioSessionManager_RegisterSessionNotification,
3076 AudioSessionManager_UnregisterSessionNotification,
3077 AudioSessionManager_RegisterDuckNotification,
3078 AudioSessionManager_UnregisterDuckNotification
3081 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3082 IAudioSessionManager2 **out)
3084 SessionMgr *This;
3086 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3087 if(!This)
3088 return E_OUTOFMEMORY;
3090 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3091 This->device = device;
3092 This->ref = 1;
3094 *out = &This->IAudioSessionManager2_iface;
3096 return S_OK;