libwine: Remove __wine_main_arg* from the public header.
[wine/zf.git] / dlls / wineandroid.drv / mmdevdrv.c
blobb4d85642561276918ecdb998783a66399ce2f043
1 /*
2 * Copyright 2015 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
20 #define COBJMACROS
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/ioctl.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <math.h>
37 #include <SLES/OpenSLES.h>
38 #include <SLES/OpenSLES_Android.h>
40 #include "android.h"
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winnls.h"
45 #include "winreg.h"
46 #include "wine/debug.h"
47 #include "wine/unicode.h"
48 #include "wine/list.h"
50 #include "ole2.h"
51 #include "mmdeviceapi.h"
52 #include "devpkey.h"
53 #include "dshow.h"
54 #include "dsound.h"
56 #include "initguid.h"
57 #include "endpointvolume.h"
58 #include "audiopolicy.h"
59 #include "audioclient.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(androidaudio);
63 #define DECL_FUNCPTR(f) static typeof(f) * p##f
64 DECL_FUNCPTR( slCreateEngine );
65 DECL_FUNCPTR( SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
66 DECL_FUNCPTR( SL_IID_ENGINE );
67 DECL_FUNCPTR( SL_IID_PLAY );
68 DECL_FUNCPTR( SL_IID_PLAYBACKRATE );
69 DECL_FUNCPTR( SL_IID_RECORD );
71 #define SLCALL_N(obj, func) (*obj)->func(obj)
72 #define SLCALL(obj, func, ...) (*obj)->func(obj, __VA_ARGS__)
74 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
76 static const REFERENCE_TIME DefaultPeriod = 100000;
77 static const REFERENCE_TIME MinimumPeriod = 50000;
79 struct ACImpl;
80 typedef struct ACImpl ACImpl;
82 typedef struct _AudioSession {
83 GUID guid;
84 struct list clients;
86 IMMDevice *device;
88 float master_vol;
89 UINT32 channel_count;
90 float *channel_vols;
91 BOOL mute;
93 CRITICAL_SECTION lock;
95 struct list entry;
96 } AudioSession;
98 typedef struct _AudioSessionWrapper {
99 IAudioSessionControl2 IAudioSessionControl2_iface;
100 IChannelAudioVolume IChannelAudioVolume_iface;
101 ISimpleAudioVolume ISimpleAudioVolume_iface;
103 LONG ref;
105 ACImpl *client;
106 AudioSession *session;
107 } AudioSessionWrapper;
109 struct ACImpl {
110 IAudioClient IAudioClient_iface;
111 IAudioRenderClient IAudioRenderClient_iface;
112 IAudioCaptureClient IAudioCaptureClient_iface;
113 IAudioClock IAudioClock_iface;
114 IAudioClock2 IAudioClock2_iface;
115 IAudioStreamVolume IAudioStreamVolume_iface;
117 LONG ref;
119 IMMDevice *parent;
120 IUnknown *pUnkFTMarshal;
122 WAVEFORMATEX *fmt;
124 EDataFlow dataflow;
125 DWORD flags;
126 AUDCLNT_SHAREMODE share;
127 HANDLE event;
128 float *vols;
130 SLObjectItf player;
131 SLObjectItf recorder;
132 SLAndroidSimpleBufferQueueItf bufq;
133 SLPlayItf playitf;
134 SLRecordItf recorditf;
136 BOOL initted, playing;
137 UINT64 written_frames, last_pos_frames;
138 UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames, wrap_buffer_frames, in_sl_frames;
139 UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
141 BYTE *local_buffer, *tmp_buffer, *wrap_buffer;
142 LONG32 getbuf_last; /* <0 when using tmp_buffer */
143 HANDLE timer;
145 CRITICAL_SECTION lock;
147 AudioSession *session;
148 AudioSessionWrapper *session_wrapper;
150 struct list entry;
153 typedef struct _SessionMgr {
154 IAudioSessionManager2 IAudioSessionManager2_iface;
156 LONG ref;
158 IMMDevice *device;
159 } SessionMgr;
161 static struct list g_devices = LIST_INIT(g_devices);
163 static HANDLE g_timer_q;
165 static CRITICAL_SECTION g_sessions_lock;
166 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
168 0, 0, &g_sessions_lock,
169 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
170 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
172 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
173 static struct list g_sessions = LIST_INIT(g_sessions);
175 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
177 static const IAudioClientVtbl AudioClient_Vtbl;
178 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
179 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
180 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
181 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
182 static const IAudioClockVtbl AudioClock_Vtbl;
183 static const IAudioClock2Vtbl AudioClock2_Vtbl;
184 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
185 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
186 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
188 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
190 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
193 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
195 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
198 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
200 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
203 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
205 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
208 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
210 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
213 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
215 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
218 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
220 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
223 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
225 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
228 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
230 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
233 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
235 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
238 #define LOAD_FUNCPTR(lib, func) do { \
239 if ((p##func = dlsym( lib, #func )) == NULL) \
240 { ERR( "can't find symbol %s\n", #func); return FALSE; } \
241 } while(0)
243 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
245 static BOOL WINAPI load_opensles( INIT_ONCE *once, void *param, void **context )
247 void *libopensles;
249 if (!(libopensles = dlopen( "libOpenSLES.so", RTLD_GLOBAL )))
251 ERR( "failed to load libOpenSLES.so: %s\n", dlerror() );
252 return FALSE;
254 LOAD_FUNCPTR( libopensles, slCreateEngine );
255 LOAD_FUNCPTR( libopensles, SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
256 LOAD_FUNCPTR( libopensles, SL_IID_ENGINE );
257 LOAD_FUNCPTR( libopensles, SL_IID_PLAY );
258 LOAD_FUNCPTR( libopensles, SL_IID_PLAYBACKRATE );
259 LOAD_FUNCPTR( libopensles, SL_IID_RECORD );
261 if (!(g_timer_q = CreateTimerQueue())) return FALSE;
263 return TRUE;
266 /* From <dlls/mmdevapi/mmdevapi.h> */
267 enum DriverPriority {
268 Priority_Unavailable = 0,
269 Priority_Low,
270 Priority_Neutral,
271 Priority_Preferred
274 int WINAPI AUDDRV_GetPriority(void)
276 if (!InitOnceExecuteOnce( &init_once, load_opensles, NULL, NULL ))
277 return Priority_Unavailable;
279 return Priority_Preferred;
282 static SLObjectItf sl;
283 static SLEngineItf engine;
284 static SLObjectItf outputmix;
286 HRESULT AUDDRV_Init(void)
288 static const SLEngineOption options[] = { {SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE} };
289 SLresult sr;
291 sr = pslCreateEngine(&sl, 1, options, 0, NULL, NULL);
292 if(sr != SL_RESULT_SUCCESS){
293 WARN("slCreateEngine failed: 0x%x\n", sr);
294 return E_FAIL;
297 sr = SLCALL(sl, Realize, SL_BOOLEAN_FALSE);
298 if(sr != SL_RESULT_SUCCESS){
299 SLCALL_N(sl, Destroy);
300 WARN("Engine Realize failed: 0x%x\n", sr);
301 return E_FAIL;
304 sr = SLCALL(sl, GetInterface, *pSL_IID_ENGINE, (void*)&engine);
305 if(sr != SL_RESULT_SUCCESS){
306 SLCALL_N(sl, Destroy);
307 WARN("GetInterface failed: 0x%x\n", sr);
308 return E_FAIL;
311 sr = SLCALL(engine, CreateOutputMix, &outputmix, 0, NULL, NULL);
312 if(sr != SL_RESULT_SUCCESS){
313 SLCALL_N(sl, Destroy);
314 WARN("CreateOutputMix failed: 0x%x\n", sr);
315 return E_FAIL;
318 sr = SLCALL(outputmix, Realize, SL_BOOLEAN_FALSE);
319 if(sr != SL_RESULT_SUCCESS){
320 SLCALL_N(outputmix, Destroy);
321 SLCALL_N(sl, Destroy);
322 WARN("outputmix Realize failed: 0x%x\n", sr);
323 return E_FAIL;
326 return S_OK;
329 static const GUID outGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x00}};
330 static const GUID inGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x01}};
332 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids,
333 UINT *num, UINT *def_index)
335 static const WCHAR outName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','O','u','t',0};
336 static const WCHAR inName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','I','n',0};
338 TRACE("%u %p %p %p %p\n", flow, ids, guids, num, def_index);
340 *def_index = 0;
341 *num = 1;
342 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
343 *guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
344 if(flow == eRender){
345 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(outName));
346 memcpy((*ids)[0], outName, sizeof(outName));
347 memcpy(&(*guids)[0], &outGuid, sizeof(outGuid));
348 }else{
349 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(inName));
350 memcpy((*ids)[0], inName, sizeof(inName));
351 memcpy(&(*guids)[0], &inGuid, sizeof(inGuid));
354 return S_OK;
357 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
358 IAudioClient **out)
360 ACImpl *This;
361 HRESULT hr;
362 EDataFlow flow;
364 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
366 if(!sl)
367 AUDDRV_Init();
369 if(IsEqualGUID(guid, &outGuid))
370 flow = eRender;
371 else if(IsEqualGUID(guid, &inGuid))
372 flow = eCapture;
373 else
374 return AUDCLNT_E_DEVICE_INVALIDATED;
376 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
377 if(!This)
378 return E_OUTOFMEMORY;
380 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient_iface, &This->pUnkFTMarshal);
381 if (FAILED(hr)) {
382 HeapFree(GetProcessHeap(), 0, This);
383 return hr;
386 This->dataflow = flow;
388 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
389 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
390 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
391 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
392 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
393 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
395 InitializeCriticalSection(&This->lock);
396 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
398 This->parent = dev;
399 IMMDevice_AddRef(This->parent);
401 IAudioClient_AddRef(&This->IAudioClient_iface);
403 *out = &This->IAudioClient_iface;
405 return S_OK;
408 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
409 REFIID riid, void **ppv)
411 ACImpl *This = impl_from_IAudioClient(iface);
412 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
414 if(!ppv)
415 return E_POINTER;
416 *ppv = NULL;
417 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
418 *ppv = iface;
419 else if(IsEqualIID(riid, &IID_IMarshal))
420 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
421 if(*ppv){
422 IUnknown_AddRef((IUnknown*)*ppv);
423 return S_OK;
425 WARN("Unknown interface %s\n", debugstr_guid(riid));
426 return E_NOINTERFACE;
429 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
431 ACImpl *This = impl_from_IAudioClient(iface);
432 ULONG ref;
433 ref = InterlockedIncrement(&This->ref);
434 TRACE("(%p) Refcount now %u\n", This, ref);
435 return ref;
438 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
440 ACImpl *This = impl_from_IAudioClient(iface);
441 ULONG ref;
443 ref = InterlockedDecrement(&This->ref);
444 TRACE("(%p) Refcount now %u\n", This, ref);
445 if(!ref){
446 if(This->timer){
447 HANDLE event;
448 DWORD wait;
449 event = CreateEventW(NULL, TRUE, FALSE, NULL);
450 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
451 wait = wait && GetLastError() == ERROR_IO_PENDING;
452 if(event && wait)
453 WaitForSingleObject(event, INFINITE);
454 CloseHandle(event);
457 IAudioClient_Stop(iface);
459 IMMDevice_Release(This->parent);
460 IUnknown_Release(This->pUnkFTMarshal);
461 This->lock.DebugInfo->Spare[0] = 0;
462 DeleteCriticalSection(&This->lock);
464 if(This->recorder)
465 SLCALL_N(This->recorder, Destroy);
466 if(This->player)
467 SLCALL_N(This->player, Destroy);
469 if(This->initted){
470 EnterCriticalSection(&g_sessions_lock);
471 list_remove(&This->entry);
472 LeaveCriticalSection(&g_sessions_lock);
474 HeapFree(GetProcessHeap(), 0, This->vols);
475 HeapFree(GetProcessHeap(), 0, This->local_buffer);
476 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
477 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
478 CoTaskMemFree(This->fmt);
479 HeapFree(GetProcessHeap(), 0, This);
481 return ref;
484 static void dump_fmt(const WAVEFORMATEX *fmt)
486 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
487 switch(fmt->wFormatTag){
488 case WAVE_FORMAT_PCM:
489 TRACE("WAVE_FORMAT_PCM");
490 break;
491 case WAVE_FORMAT_IEEE_FLOAT:
492 TRACE("WAVE_FORMAT_IEEE_FLOAT");
493 break;
494 case WAVE_FORMAT_EXTENSIBLE:
495 TRACE("WAVE_FORMAT_EXTENSIBLE");
496 break;
497 default:
498 TRACE("Unknown");
499 break;
501 TRACE(")\n");
503 TRACE("nChannels: %u\n", fmt->nChannels);
504 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
505 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
506 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
507 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
508 TRACE("cbSize: %u\n", fmt->cbSize);
510 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
511 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
512 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
513 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
514 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
518 static DWORD get_channel_mask(unsigned int channels)
520 switch(channels){
521 case 0:
522 return 0;
523 case 1:
524 return KSAUDIO_SPEAKER_MONO;
525 case 2:
526 return KSAUDIO_SPEAKER_STEREO;
527 case 3:
528 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
529 case 4:
530 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
531 case 5:
532 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
533 case 6:
534 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
535 case 7:
536 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
537 case 8:
538 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
540 FIXME("Unknown speaker configuration: %u\n", channels);
541 return 0;
544 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
546 WAVEFORMATEX *ret;
547 size_t size;
549 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
550 size = sizeof(WAVEFORMATEXTENSIBLE);
551 else
552 size = sizeof(WAVEFORMATEX);
554 ret = CoTaskMemAlloc(size);
555 if(!ret)
556 return NULL;
558 memcpy(ret, fmt, size);
560 ret->cbSize = size - sizeof(WAVEFORMATEX);
562 return ret;
565 static void session_init_vols(AudioSession *session, UINT channels)
567 if(session->channel_count < channels){
568 UINT i;
570 if(session->channel_vols)
571 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
572 session->channel_vols, sizeof(float) * channels);
573 else
574 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
575 sizeof(float) * channels);
576 if(!session->channel_vols)
577 return;
579 for(i = session->channel_count; i < channels; ++i)
580 session->channel_vols[i] = 1.f;
582 session->channel_count = channels;
586 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
587 UINT num_channels)
589 AudioSession *ret;
591 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
592 if(!ret)
593 return NULL;
595 memcpy(&ret->guid, guid, sizeof(GUID));
597 ret->device = device;
599 list_init(&ret->clients);
601 list_add_head(&g_sessions, &ret->entry);
603 InitializeCriticalSection(&ret->lock);
604 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
606 session_init_vols(ret, num_channels);
608 ret->master_vol = 1.f;
610 return ret;
613 /* if channels == 0, then this will return or create a session with
614 * matching dataflow and GUID. otherwise, channels must also match */
615 static HRESULT get_audio_session(const GUID *sessionguid,
616 IMMDevice *device, UINT channels, AudioSession **out)
618 AudioSession *session;
620 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
621 *out = create_session(&GUID_NULL, device, channels);
622 if(!*out)
623 return E_OUTOFMEMORY;
625 return S_OK;
628 *out = NULL;
629 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
630 if(session->device == device &&
631 IsEqualGUID(sessionguid, &session->guid)){
632 session_init_vols(session, channels);
633 *out = session;
634 break;
638 if(!*out){
639 *out = create_session(sessionguid, device, channels);
640 if(!*out)
641 return E_OUTOFMEMORY;
644 return S_OK;
647 static HRESULT waveformat_to_pcm(ACImpl *This, const WAVEFORMATEX *fmt, SLAndroidDataFormat_PCM_EX *pcm)
649 if(fmt->nSamplesPerSec < 8000 || fmt->nSamplesPerSec > 48000)
650 return AUDCLNT_E_UNSUPPORTED_FORMAT;
652 pcm->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
654 pcm->sampleRate = fmt->nSamplesPerSec * 1000; /* sampleRate is in milli-Hz */
655 pcm->bitsPerSample = fmt->wBitsPerSample;
656 pcm->containerSize = fmt->wBitsPerSample;
658 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
659 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
660 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
661 if(pcm->bitsPerSample == 8)
662 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
663 else if(pcm->bitsPerSample == 16)
664 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
665 else
666 return AUDCLNT_E_UNSUPPORTED_FORMAT;
667 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
668 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
669 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
670 if(pcm->bitsPerSample == 32)
671 pcm->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
672 else
673 return AUDCLNT_E_UNSUPPORTED_FORMAT;
674 }else
675 return AUDCLNT_E_UNSUPPORTED_FORMAT;
677 /* only up to stereo */
678 pcm->numChannels = fmt->nChannels;
679 if(pcm->numChannels == 1)
680 pcm->channelMask = SL_SPEAKER_FRONT_CENTER;
681 else if(This->dataflow == eRender && pcm->numChannels == 2)
682 pcm->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
683 else
684 return AUDCLNT_E_UNSUPPORTED_FORMAT;
686 pcm->endianness = SL_BYTEORDER_LITTLEENDIAN;
688 return S_OK;
691 static HRESULT try_open_render_device(SLAndroidDataFormat_PCM_EX *pcm, unsigned int num_buffers, SLObjectItf *out)
693 SLresult sr;
694 SLDataSource source;
695 SLDataSink sink;
696 SLDataLocator_OutputMix loc_outmix;
697 SLboolean required[2];
698 SLInterfaceID iids[2];
699 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
700 SLObjectItf player;
702 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
703 loc_bq.numBuffers = num_buffers;
704 source.pLocator = &loc_bq;
705 source.pFormat = pcm;
707 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
708 loc_outmix.outputMix = outputmix;
709 sink.pLocator = &loc_outmix;
710 sink.pFormat = NULL;
712 required[0] = SL_BOOLEAN_TRUE;
713 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
714 required[1] = SL_BOOLEAN_TRUE;
715 iids[1] = *pSL_IID_PLAYBACKRATE;
717 sr = SLCALL(engine, CreateAudioPlayer, &player, &source, &sink,
718 2, iids, required);
719 if(sr != SL_RESULT_SUCCESS){
720 WARN("CreateAudioPlayer failed: 0x%x\n", sr);
721 return E_FAIL;
724 sr = SLCALL(player, Realize, SL_BOOLEAN_FALSE);
725 if(sr != SL_RESULT_SUCCESS){
726 SLCALL_N(player, Destroy);
727 WARN("Player Realize failed: 0x%x\n", sr);
728 return E_FAIL;
731 if(out)
732 *out = player;
733 else
734 SLCALL_N(player, Destroy);
736 return S_OK;
739 static HRESULT try_open_capture_device(SLAndroidDataFormat_PCM_EX *pcm, unsigned int num_buffers, SLObjectItf *out)
741 SLresult sr;
742 SLDataSource source;
743 SLDataSink sink;
744 SLDataLocator_IODevice loc_mic;
745 SLboolean required[1];
746 SLInterfaceID iids[1];
747 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
748 SLObjectItf recorder;
750 loc_mic.locatorType = SL_DATALOCATOR_IODEVICE;
751 loc_mic.deviceType = SL_IODEVICE_AUDIOINPUT;
752 loc_mic.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
753 loc_mic.device = NULL;
754 source.pLocator = &loc_mic;
755 source.pFormat = NULL;
757 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
758 loc_bq.numBuffers = num_buffers;
759 sink.pLocator = &loc_bq;
760 sink.pFormat = pcm;
762 required[0] = SL_BOOLEAN_TRUE;
763 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
765 sr = SLCALL(engine, CreateAudioRecorder, &recorder, &source, &sink,
766 1, iids, required);
767 if(sr != SL_RESULT_SUCCESS){
768 WARN("CreateAudioRecorder failed: 0x%x\n", sr);
769 return E_FAIL;
772 sr = SLCALL(recorder, Realize, SL_BOOLEAN_FALSE);
773 if(sr != SL_RESULT_SUCCESS){
774 SLCALL_N(recorder, Destroy);
775 WARN("Recorder Realize failed: 0x%x\n", sr);
776 return E_FAIL;
779 if(out)
780 *out = recorder;
781 else
782 SLCALL_N(recorder, Destroy);
784 return S_OK;
787 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
788 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
789 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
790 const GUID *sessionguid)
792 ACImpl *This = impl_from_IAudioClient(iface);
793 int i, num_buffers;
794 HRESULT hr;
795 SLresult sr;
796 SLAndroidDataFormat_PCM_EX pcm;
798 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
799 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
801 if(!fmt)
802 return E_POINTER;
804 dump_fmt(fmt);
806 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
807 return E_INVALIDARG;
809 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
810 AUDCLNT_STREAMFLAGS_LOOPBACK |
811 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
812 AUDCLNT_STREAMFLAGS_NOPERSIST |
813 AUDCLNT_STREAMFLAGS_RATEADJUST |
814 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
815 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
816 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
817 TRACE("Unknown flags: %08x\n", flags);
818 return E_INVALIDARG;
821 if(mode == AUDCLNT_SHAREMODE_SHARED){
822 period = DefaultPeriod;
823 if( duration < 3 * period)
824 duration = 3 * period;
825 }else{
826 if(!period)
827 period = DefaultPeriod; /* not minimum */
828 if(period < MinimumPeriod || period > 5000000)
829 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
830 if(duration > 20000000) /* the smaller the period, the lower this limit */
831 return AUDCLNT_E_BUFFER_SIZE_ERROR;
832 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
833 if(duration != period)
834 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
835 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
836 return AUDCLNT_E_DEVICE_IN_USE;
837 }else{
838 if( duration < 8 * period)
839 duration = 8 * period; /* may grow above 2s */
843 EnterCriticalSection(&This->lock);
845 if(This->initted){
846 LeaveCriticalSection(&This->lock);
847 return AUDCLNT_E_ALREADY_INITIALIZED;
850 This->period_us = period / 10;
851 This->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
853 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
854 if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
855 This->bufsize_frames -= This->bufsize_frames % This->period_frames;
856 else if(This->bufsize_frames % This->period_frames != 0)
857 /* hack: round up to integer multiple */
858 This->bufsize_frames += This->period_frames - This->bufsize_frames % This->period_frames;
860 hr = waveformat_to_pcm(This, fmt, &pcm);
861 if(FAILED(hr)){
862 LeaveCriticalSection(&This->lock);
863 return hr;
866 num_buffers = This->bufsize_frames / This->period_frames;
868 if(This->dataflow == eRender){
869 hr = try_open_render_device(&pcm, num_buffers, &This->player);
870 if(FAILED(hr)){
871 LeaveCriticalSection(&This->lock);
872 return hr;
875 sr = SLCALL(This->player, GetInterface, *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE, &This->bufq);
876 if(sr != SL_RESULT_SUCCESS){
877 SLCALL_N(This->player, Destroy);
878 This->player = NULL;
879 WARN("Player GetInterface(BufferQueue) failed: 0x%x\n", sr);
880 LeaveCriticalSection(&This->lock);
881 return E_FAIL;
884 sr = SLCALL(This->player, GetInterface, *pSL_IID_PLAY, &This->playitf);
885 if(sr != SL_RESULT_SUCCESS){
886 SLCALL_N(This->player, Destroy);
887 This->player = NULL;
888 WARN("Player GetInterface(Play) failed: 0x%x\n", sr);
889 LeaveCriticalSection(&This->lock);
890 return E_FAIL;
892 }else{
893 hr = try_open_capture_device(&pcm, num_buffers, &This->recorder);
894 if(FAILED(hr)){
895 LeaveCriticalSection(&This->lock);
896 return hr;
899 sr = SLCALL(This->recorder, GetInterface, *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE, &This->bufq);
900 if(sr != SL_RESULT_SUCCESS){
901 SLCALL_N(This->recorder, Destroy);
902 This->recorder = NULL;
903 WARN("Recorder GetInterface(BufferQueue) failed: 0x%x\n", sr);
904 LeaveCriticalSection(&This->lock);
905 return E_FAIL;
908 sr = SLCALL(This->recorder, GetInterface, *pSL_IID_RECORD, &This->recorditf);
909 if(sr != SL_RESULT_SUCCESS){
910 SLCALL_N(This->recorder, Destroy);
911 This->recorder = NULL;
912 WARN("Recorder GetInterface(Record) failed: 0x%x\n", sr);
913 LeaveCriticalSection(&This->lock);
914 return E_FAIL;
918 This->fmt = clone_format(fmt);
919 if(!This->fmt){
920 if(This->player){
921 SLCALL_N(This->player, Destroy);
922 This->player = NULL;
924 if(This->recorder){
925 SLCALL_N(This->recorder, Destroy);
926 This->recorder = NULL;
928 LeaveCriticalSection(&This->lock);
929 return E_OUTOFMEMORY;
932 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
933 This->bufsize_frames * fmt->nBlockAlign);
934 if(!This->local_buffer){
935 CoTaskMemFree(This->fmt);
936 This->fmt = NULL;
937 if(This->player){
938 SLCALL_N(This->player, Destroy);
939 This->player = NULL;
941 if(This->recorder){
942 SLCALL_N(This->recorder, Destroy);
943 This->recorder = NULL;
945 LeaveCriticalSection(&This->lock);
946 return E_OUTOFMEMORY;
949 if(This->dataflow == eCapture){
950 while(This->in_sl_frames < This->bufsize_frames){
951 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
952 sr = SLCALL(This->bufq, Enqueue,
953 This->local_buffer + ((This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
954 This->period_frames * This->fmt->nBlockAlign);
955 if(sr != SL_RESULT_SUCCESS)
956 WARN("Enqueue failed: 0x%x\n", sr);
957 This->in_sl_frames += This->period_frames;
961 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
962 if(!This->vols){
963 CoTaskMemFree(This->fmt);
964 This->fmt = NULL;
965 if(This->player){
966 SLCALL_N(This->player, Destroy);
967 This->player = NULL;
969 if(This->recorder){
970 SLCALL_N(This->recorder, Destroy);
971 This->recorder = NULL;
973 LeaveCriticalSection(&This->lock);
974 return E_OUTOFMEMORY;
977 for(i = 0; i < fmt->nChannels; ++i)
978 This->vols[i] = 1.f;
980 This->share = mode;
981 This->flags = flags;
982 This->oss_bufsize_bytes = 0;
984 EnterCriticalSection(&g_sessions_lock);
986 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
987 &This->session);
988 if(FAILED(hr)){
989 LeaveCriticalSection(&g_sessions_lock);
990 HeapFree(GetProcessHeap(), 0, This->vols);
991 This->vols = NULL;
992 CoTaskMemFree(This->fmt);
993 This->fmt = NULL;
994 if(This->player){
995 SLCALL_N(This->player, Destroy);
996 This->player = NULL;
998 if(This->recorder){
999 SLCALL_N(This->recorder, Destroy);
1000 This->recorder = NULL;
1002 LeaveCriticalSection(&This->lock);
1003 return hr;
1006 list_add_tail(&This->session->clients, &This->entry);
1008 LeaveCriticalSection(&g_sessions_lock);
1010 This->initted = TRUE;
1012 TRACE("numBuffers: %u, bufsize: %u, period: %u\n", num_buffers,
1013 This->bufsize_frames, This->period_frames);
1015 LeaveCriticalSection(&This->lock);
1017 return S_OK;
1020 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1021 UINT32 *frames)
1023 ACImpl *This = impl_from_IAudioClient(iface);
1025 TRACE("(%p)->(%p)\n", This, frames);
1027 if(!frames)
1028 return E_POINTER;
1030 EnterCriticalSection(&This->lock);
1032 if(!This->initted){
1033 LeaveCriticalSection(&This->lock);
1034 return AUDCLNT_E_NOT_INITIALIZED;
1037 *frames = This->bufsize_frames;
1039 TRACE("buffer size: %u\n", *frames);
1041 LeaveCriticalSection(&This->lock);
1043 return S_OK;
1046 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1047 REFERENCE_TIME *latency)
1049 ACImpl *This = impl_from_IAudioClient(iface);
1051 TRACE("(%p)->(%p)\n", This, latency);
1053 if(!latency)
1054 return E_POINTER;
1056 EnterCriticalSection(&This->lock);
1058 if(!This->initted){
1059 LeaveCriticalSection(&This->lock);
1060 return AUDCLNT_E_NOT_INITIALIZED;
1063 /* pretend we process audio in Period chunks, so max latency includes
1064 * the period time. Some native machines add .6666ms in shared mode. */
1065 *latency = This->period_us * 10 + 6666;
1067 LeaveCriticalSection(&This->lock);
1069 return S_OK;
1072 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1073 UINT32 *numpad)
1075 ACImpl *This = impl_from_IAudioClient(iface);
1077 TRACE("(%p)->(%p)\n", This, numpad);
1079 if(!numpad)
1080 return E_POINTER;
1082 EnterCriticalSection(&This->lock);
1084 if(!This->initted){
1085 LeaveCriticalSection(&This->lock);
1086 return AUDCLNT_E_NOT_INITIALIZED;
1089 *numpad = This->held_frames;
1091 TRACE("padding: %u\n", *numpad);
1093 LeaveCriticalSection(&This->lock);
1095 return S_OK;
1098 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1099 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1100 WAVEFORMATEX **outpwfx)
1102 ACImpl *This = impl_from_IAudioClient(iface);
1103 SLAndroidDataFormat_PCM_EX pcm;
1104 HRESULT hr;
1106 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1108 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1109 return E_POINTER;
1111 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1112 return E_INVALIDARG;
1114 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1115 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1116 return E_INVALIDARG;
1118 dump_fmt(pwfx);
1120 if(outpwfx)
1121 *outpwfx = NULL;
1123 hr = waveformat_to_pcm(This, pwfx, &pcm);
1124 if(SUCCEEDED(hr)){
1125 if(This->dataflow == eRender){
1126 hr = try_open_render_device(&pcm, 10, NULL);
1127 }else{
1128 hr = try_open_capture_device(&pcm, 10, NULL);
1132 if(FAILED(hr)){
1133 if(outpwfx){
1134 hr = IAudioClient_GetMixFormat(iface, outpwfx);
1135 if(FAILED(hr))
1136 return hr;
1137 return S_FALSE;
1140 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1143 TRACE("returning: %08x\n", hr);
1145 return hr;
1148 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1149 WAVEFORMATEX **pwfx)
1151 ACImpl *This = impl_from_IAudioClient(iface);
1152 WAVEFORMATEXTENSIBLE *fmt;
1154 TRACE("(%p)->(%p)\n", This, pwfx);
1156 if(!pwfx)
1157 return E_POINTER;
1158 *pwfx = NULL;
1160 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1161 if(!fmt)
1162 return E_OUTOFMEMORY;
1164 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1165 fmt->Format.wBitsPerSample = 16;
1166 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1167 if(This->dataflow == eRender)
1168 fmt->Format.nChannels = 2;
1169 else
1170 fmt->Format.nChannels = 1;
1171 fmt->Format.nSamplesPerSec = 48000; /* TODO: query supported? recording? */
1172 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1173 fmt->Format.nChannels) / 8;
1174 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1175 fmt->Format.nBlockAlign;
1176 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1177 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1178 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1180 *pwfx = (WAVEFORMATEX*)fmt;
1181 dump_fmt(*pwfx);
1183 return S_OK;
1186 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1187 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1189 ACImpl *This = impl_from_IAudioClient(iface);
1191 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1193 if(!defperiod && !minperiod)
1194 return E_POINTER;
1196 if(defperiod)
1197 *defperiod = DefaultPeriod;
1198 if(minperiod)
1199 *minperiod = MinimumPeriod;
1201 return S_OK;
1204 static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
1206 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1207 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1208 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1209 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1210 This->fmt->wBitsPerSample == 8)
1211 memset(buffer, 128, frames * This->fmt->nBlockAlign);
1212 else
1213 memset(buffer, 0, frames * This->fmt->nBlockAlign);
1216 static void sl_read_data(ACImpl *This)
1218 SLAndroidSimpleBufferQueueState state;
1219 SLresult sr;
1220 SLuint32 elapsed;
1222 memset(&state, 0, sizeof(state));
1224 sr = SLCALL(This->bufq, GetState, &state);
1225 if(sr != SL_RESULT_SUCCESS){
1226 WARN("GetState failed: 0x%x\n", sr);
1227 return;
1229 TRACE("got: count: %u, index: %u, held: %u, in_sl: %u\n", state.count, state.index, This->held_frames, This->in_sl_frames);
1231 elapsed = This->in_sl_frames - state.count * This->period_frames;
1232 This->held_frames += elapsed;
1233 This->in_sl_frames = state.count * This->period_frames;
1235 if(This->held_frames == This->bufsize_frames){
1236 /* overrun */
1237 TRACE("overrun??\n");
1238 This->lcl_offs_frames += This->period_frames;
1239 This->held_frames -= This->period_frames;
1242 TRACE("good range: %u, %u\n", This->lcl_offs_frames, This->lcl_offs_frames + This->held_frames);
1243 TRACE("held: %u, in_sl: %u\n", This->held_frames, This->in_sl_frames);
1244 while(This->held_frames + This->in_sl_frames < This->bufsize_frames){
1245 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->held_frames + This->in_sl_frames) % This->bufsize_frames);
1246 sr = SLCALL(This->bufq, Enqueue,
1247 This->local_buffer + ((This->lcl_offs_frames + This->held_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
1248 This->period_frames * This->fmt->nBlockAlign);
1249 if(sr != SL_RESULT_SUCCESS)
1250 WARN("Enqueue failed: 0x%x\n", sr);
1251 This->in_sl_frames += This->period_frames;
1255 static DWORD wrap_enqueue(ACImpl *This)
1257 DWORD to_enqueue = min(This->held_frames, This->period_frames);
1258 DWORD offs = (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames;
1259 BYTE *buf = This->local_buffer + offs * This->fmt->nBlockAlign;
1261 if(offs + to_enqueue > This->bufsize_frames){
1262 DWORD chunk = This->bufsize_frames - offs;
1264 if(This->wrap_buffer_frames < to_enqueue){
1265 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
1266 This->wrap_buffer = HeapAlloc(GetProcessHeap(), 0, to_enqueue * This->fmt->nBlockAlign);
1267 This->wrap_buffer_frames = to_enqueue;
1270 memcpy(This->wrap_buffer, This->local_buffer + offs * This->fmt->nBlockAlign, chunk * This->fmt->nBlockAlign);
1271 memcpy(This->wrap_buffer + chunk * This->fmt->nBlockAlign, This->local_buffer, (to_enqueue - chunk) * This->fmt->nBlockAlign);
1273 buf = This->wrap_buffer;
1276 SLCALL(This->bufq, Enqueue, buf,
1277 to_enqueue * This->fmt->nBlockAlign);
1279 return to_enqueue;
1282 static void sl_write_data(ACImpl *This)
1284 SLAndroidSimpleBufferQueueState state;
1285 SLresult sr;
1286 SLuint32 elapsed;
1288 memset(&state, 0, sizeof(state));
1290 sr = SLCALL(This->bufq, GetState, &state);
1291 if(sr != SL_RESULT_SUCCESS){
1292 WARN("GetState failed: 0x%x\n", sr);
1293 return;
1295 TRACE("got: count: %u, index: %u\n", state.count, state.index);
1297 elapsed = This->in_sl_frames - state.count * This->period_frames;
1299 if(elapsed > This->held_frames)
1300 This->held_frames = 0;
1301 else
1302 This->held_frames -= elapsed;
1304 This->lcl_offs_frames += elapsed;
1305 This->lcl_offs_frames %= This->bufsize_frames;
1307 This->in_sl_frames = state.count * This->period_frames;
1309 while(This->held_frames >= This->in_sl_frames + This->period_frames){
1310 /* have at least a period to write, so write it */
1311 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1312 This->in_sl_frames += wrap_enqueue(This);
1315 if(This->held_frames && This->in_sl_frames < This->period_frames * 3){
1316 /* write out the last bit with a partial period */
1317 TRACE("enqueueing partial period: %u frames from %u\n", This->held_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1318 This->in_sl_frames += wrap_enqueue(This);
1321 TRACE("done with enqueue, lcl_offs: %u, in_sl: %u, held: %u\n", This->lcl_offs_frames, This->in_sl_frames, This->held_frames);
1324 static void CALLBACK sl_period_callback(void *user, BOOLEAN timer)
1326 ACImpl *This = user;
1328 EnterCriticalSection(&This->lock);
1330 if(This->playing){
1331 if(This->dataflow == eRender)
1332 sl_write_data(This);
1333 else if(This->dataflow == eCapture)
1334 sl_read_data(This);
1337 LeaveCriticalSection(&This->lock);
1339 if(This->event)
1340 SetEvent(This->event);
1343 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1345 ACImpl *This = impl_from_IAudioClient(iface);
1346 SLresult sr;
1348 TRACE("(%p)\n", This);
1350 EnterCriticalSection(&This->lock);
1352 if(!This->initted){
1353 LeaveCriticalSection(&This->lock);
1354 return AUDCLNT_E_NOT_INITIALIZED;
1357 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1358 LeaveCriticalSection(&This->lock);
1359 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1362 if(This->playing){
1363 LeaveCriticalSection(&This->lock);
1364 return AUDCLNT_E_NOT_STOPPED;
1367 if(This->dataflow == eRender){
1368 sr = SLCALL(This->playitf, SetPlayState, SL_PLAYSTATE_PLAYING);
1369 if(sr != SL_RESULT_SUCCESS){
1370 WARN("SetPlayState failed: 0x%x\n", sr);
1371 LeaveCriticalSection(&This->lock);
1372 return E_FAIL;
1374 }else{
1375 sr = SLCALL(This->recorditf, SetRecordState, SL_RECORDSTATE_RECORDING);
1376 if(sr != SL_RESULT_SUCCESS){
1377 WARN("SetRecordState failed: 0x%x\n", sr);
1378 LeaveCriticalSection(&This->lock);
1379 return E_FAIL;
1383 if(!This->timer){
1384 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1385 sl_period_callback, This, 0, This->period_us / 1000,
1386 WT_EXECUTEINTIMERTHREAD))
1387 WARN("Unable to create period timer: %u\n", GetLastError());
1390 This->playing = TRUE;
1392 LeaveCriticalSection(&This->lock);
1394 return S_OK;
1397 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1399 ACImpl *This = impl_from_IAudioClient(iface);
1400 SLresult sr;
1402 TRACE("(%p)\n", This);
1404 EnterCriticalSection(&This->lock);
1406 if(!This->initted){
1407 LeaveCriticalSection(&This->lock);
1408 return AUDCLNT_E_NOT_INITIALIZED;
1411 if(!This->playing){
1412 LeaveCriticalSection(&This->lock);
1413 return S_FALSE;
1416 if(This->dataflow == eRender){
1417 sr = SLCALL(This->playitf, SetPlayState, SL_PLAYSTATE_PAUSED);
1418 if(sr != SL_RESULT_SUCCESS){
1419 WARN("SetPlayState failed: 0x%x\n", sr);
1420 LeaveCriticalSection(&This->lock);
1421 return E_FAIL;
1423 }else{
1424 sr = SLCALL(This->recorditf, SetRecordState, SL_RECORDSTATE_STOPPED);
1425 if(sr != SL_RESULT_SUCCESS){
1426 WARN("SetRecordState failed: 0x%x\n", sr);
1427 LeaveCriticalSection(&This->lock);
1428 return E_FAIL;
1432 This->playing = FALSE;
1434 LeaveCriticalSection(&This->lock);
1436 return S_OK;
1439 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1441 ACImpl *This = impl_from_IAudioClient(iface);
1442 SLresult sr;
1444 TRACE("(%p)\n", This);
1446 EnterCriticalSection(&This->lock);
1448 if(!This->initted){
1449 LeaveCriticalSection(&This->lock);
1450 return AUDCLNT_E_NOT_INITIALIZED;
1453 if(This->playing){
1454 LeaveCriticalSection(&This->lock);
1455 return AUDCLNT_E_NOT_STOPPED;
1458 if(This->getbuf_last){
1459 LeaveCriticalSection(&This->lock);
1460 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1463 sr = SLCALL_N(This->bufq, Clear);
1464 if(sr != SL_RESULT_SUCCESS){
1465 WARN("Clear failed: 0x%x\n", sr);
1466 LeaveCriticalSection(&This->lock);
1467 return E_FAIL;
1470 This->lcl_offs_frames = 0;
1471 This->in_sl_frames = 0;
1473 if(This->dataflow == eRender){
1474 This->written_frames = 0;
1475 This->last_pos_frames = 0;
1476 }else{
1477 This->written_frames += This->held_frames;
1478 while(This->in_sl_frames < This->bufsize_frames){
1479 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1480 sr = SLCALL(This->bufq, Enqueue,
1481 This->local_buffer + ((This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
1482 This->period_frames * This->fmt->nBlockAlign);
1483 if(sr != SL_RESULT_SUCCESS)
1484 WARN("Enqueue failed: 0x%x\n", sr);
1485 This->in_sl_frames += This->period_frames;
1489 This->held_frames = 0;
1491 LeaveCriticalSection(&This->lock);
1493 return S_OK;
1496 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1497 HANDLE event)
1499 ACImpl *This = impl_from_IAudioClient(iface);
1501 TRACE("(%p)->(%p)\n", This, event);
1503 if(!event)
1504 return E_INVALIDARG;
1506 EnterCriticalSection(&This->lock);
1508 if(!This->initted){
1509 LeaveCriticalSection(&This->lock);
1510 return AUDCLNT_E_NOT_INITIALIZED;
1513 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1514 LeaveCriticalSection(&This->lock);
1515 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1518 if (This->event){
1519 LeaveCriticalSection(&This->lock);
1520 FIXME("called twice\n");
1521 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1524 This->event = event;
1526 LeaveCriticalSection(&This->lock);
1528 return S_OK;
1531 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1532 void **ppv)
1534 ACImpl *This = impl_from_IAudioClient(iface);
1536 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1538 if(!ppv)
1539 return E_POINTER;
1540 *ppv = NULL;
1542 EnterCriticalSection(&This->lock);
1544 if(!This->initted){
1545 LeaveCriticalSection(&This->lock);
1546 return AUDCLNT_E_NOT_INITIALIZED;
1549 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1550 if(This->dataflow != eRender){
1551 LeaveCriticalSection(&This->lock);
1552 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1554 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1555 *ppv = &This->IAudioRenderClient_iface;
1556 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1557 if(This->dataflow != eCapture){
1558 LeaveCriticalSection(&This->lock);
1559 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1561 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1562 *ppv = &This->IAudioCaptureClient_iface;
1563 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1564 IAudioClock_AddRef(&This->IAudioClock_iface);
1565 *ppv = &This->IAudioClock_iface;
1566 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1567 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1568 *ppv = &This->IAudioStreamVolume_iface;
1569 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1570 if(!This->session_wrapper){
1571 This->session_wrapper = AudioSessionWrapper_Create(This);
1572 if(!This->session_wrapper){
1573 LeaveCriticalSection(&This->lock);
1574 return E_OUTOFMEMORY;
1576 }else
1577 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1579 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1580 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1581 if(!This->session_wrapper){
1582 This->session_wrapper = AudioSessionWrapper_Create(This);
1583 if(!This->session_wrapper){
1584 LeaveCriticalSection(&This->lock);
1585 return E_OUTOFMEMORY;
1587 }else
1588 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1590 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1591 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1592 if(!This->session_wrapper){
1593 This->session_wrapper = AudioSessionWrapper_Create(This);
1594 if(!This->session_wrapper){
1595 LeaveCriticalSection(&This->lock);
1596 return E_OUTOFMEMORY;
1598 }else
1599 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1601 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1604 if(*ppv){
1605 LeaveCriticalSection(&This->lock);
1606 return S_OK;
1609 LeaveCriticalSection(&This->lock);
1611 FIXME("stub %s\n", debugstr_guid(riid));
1612 return E_NOINTERFACE;
1615 static const IAudioClientVtbl AudioClient_Vtbl =
1617 AudioClient_QueryInterface,
1618 AudioClient_AddRef,
1619 AudioClient_Release,
1620 AudioClient_Initialize,
1621 AudioClient_GetBufferSize,
1622 AudioClient_GetStreamLatency,
1623 AudioClient_GetCurrentPadding,
1624 AudioClient_IsFormatSupported,
1625 AudioClient_GetMixFormat,
1626 AudioClient_GetDevicePeriod,
1627 AudioClient_Start,
1628 AudioClient_Stop,
1629 AudioClient_Reset,
1630 AudioClient_SetEventHandle,
1631 AudioClient_GetService
1634 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1635 IAudioRenderClient *iface, REFIID riid, void **ppv)
1637 ACImpl *This = impl_from_IAudioRenderClient(iface);
1638 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1640 if(!ppv)
1641 return E_POINTER;
1642 *ppv = NULL;
1644 if(IsEqualIID(riid, &IID_IUnknown) ||
1645 IsEqualIID(riid, &IID_IAudioRenderClient))
1646 *ppv = iface;
1647 else if(IsEqualIID(riid, &IID_IMarshal))
1648 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1649 if(*ppv){
1650 IUnknown_AddRef((IUnknown*)*ppv);
1651 return S_OK;
1654 WARN("Unknown interface %s\n", debugstr_guid(riid));
1655 return E_NOINTERFACE;
1658 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1660 ACImpl *This = impl_from_IAudioRenderClient(iface);
1661 return AudioClient_AddRef(&This->IAudioClient_iface);
1664 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1666 ACImpl *This = impl_from_IAudioRenderClient(iface);
1667 return AudioClient_Release(&This->IAudioClient_iface);
1670 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1671 UINT32 frames, BYTE **data)
1673 ACImpl *This = impl_from_IAudioRenderClient(iface);
1674 UINT32 write_pos;
1676 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1678 if(!data)
1679 return E_POINTER;
1681 *data = NULL;
1683 EnterCriticalSection(&This->lock);
1685 if(This->getbuf_last){
1686 LeaveCriticalSection(&This->lock);
1687 return AUDCLNT_E_OUT_OF_ORDER;
1690 if(!frames){
1691 LeaveCriticalSection(&This->lock);
1692 return S_OK;
1695 if(This->held_frames + frames > This->bufsize_frames){
1696 LeaveCriticalSection(&This->lock);
1697 return AUDCLNT_E_BUFFER_TOO_LARGE;
1700 write_pos =
1701 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1702 if(write_pos + frames > This->bufsize_frames){
1703 if(This->tmp_buffer_frames < frames){
1704 DWORD alloc = frames < This->period_frames ? This->period_frames : frames;
1705 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1706 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1707 alloc * This->fmt->nBlockAlign);
1708 if(!This->tmp_buffer){
1709 LeaveCriticalSection(&This->lock);
1710 return E_OUTOFMEMORY;
1712 This->tmp_buffer_frames = alloc;
1714 *data = This->tmp_buffer;
1715 This->getbuf_last = -frames;
1716 }else{
1717 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1718 This->getbuf_last = frames;
1721 silence_buffer(This, *data, frames);
1723 LeaveCriticalSection(&This->lock);
1725 return S_OK;
1728 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1730 UINT32 write_offs_frames =
1731 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1732 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1733 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1734 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1735 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1737 if(written_bytes <= chunk_bytes){
1738 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1739 }else{
1740 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1741 memcpy(This->local_buffer, buffer + chunk_bytes,
1742 written_bytes - chunk_bytes);
1746 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1747 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1749 ACImpl *This = impl_from_IAudioRenderClient(iface);
1750 BYTE *buffer;
1752 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1754 EnterCriticalSection(&This->lock);
1756 if(!written_frames){
1757 This->getbuf_last = 0;
1758 LeaveCriticalSection(&This->lock);
1759 return S_OK;
1762 if(!This->getbuf_last){
1763 LeaveCriticalSection(&This->lock);
1764 return AUDCLNT_E_OUT_OF_ORDER;
1767 if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1768 LeaveCriticalSection(&This->lock);
1769 return AUDCLNT_E_INVALID_SIZE;
1772 if(This->getbuf_last >= 0)
1773 buffer = This->local_buffer + This->fmt->nBlockAlign *
1774 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1775 else
1776 buffer = This->tmp_buffer;
1778 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1779 silence_buffer(This, buffer, written_frames);
1781 if(This->getbuf_last < 0)
1782 oss_wrap_buffer(This, buffer, written_frames);
1784 This->held_frames += written_frames;
1785 This->written_frames += written_frames;
1786 This->getbuf_last = 0;
1788 LeaveCriticalSection(&This->lock);
1790 return S_OK;
1793 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1794 AudioRenderClient_QueryInterface,
1795 AudioRenderClient_AddRef,
1796 AudioRenderClient_Release,
1797 AudioRenderClient_GetBuffer,
1798 AudioRenderClient_ReleaseBuffer
1801 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1802 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1804 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1805 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1807 if(!ppv)
1808 return E_POINTER;
1809 *ppv = NULL;
1811 if(IsEqualIID(riid, &IID_IUnknown) ||
1812 IsEqualIID(riid, &IID_IAudioCaptureClient))
1813 *ppv = iface;
1814 else if(IsEqualIID(riid, &IID_IMarshal))
1815 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1816 if(*ppv){
1817 IUnknown_AddRef((IUnknown*)*ppv);
1818 return S_OK;
1821 WARN("Unknown interface %s\n", debugstr_guid(riid));
1822 return E_NOINTERFACE;
1825 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1827 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1828 return IAudioClient_AddRef(&This->IAudioClient_iface);
1831 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1833 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1834 return IAudioClient_Release(&This->IAudioClient_iface);
1837 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1838 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1839 UINT64 *qpcpos)
1841 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1843 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1844 devpos, qpcpos);
1846 if(!data)
1847 return E_POINTER;
1849 *data = NULL;
1851 if(!frames || !flags)
1852 return E_POINTER;
1854 EnterCriticalSection(&This->lock);
1856 if(This->getbuf_last){
1857 LeaveCriticalSection(&This->lock);
1858 return AUDCLNT_E_OUT_OF_ORDER;
1861 if(This->held_frames < This->period_frames){
1862 *frames = 0;
1863 LeaveCriticalSection(&This->lock);
1864 return AUDCLNT_S_BUFFER_EMPTY;
1867 *flags = 0;
1869 *frames = This->period_frames;
1871 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1872 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1873 if(This->tmp_buffer_frames < *frames){
1874 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1875 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1876 *frames * This->fmt->nBlockAlign);
1877 if(!This->tmp_buffer){
1878 LeaveCriticalSection(&This->lock);
1879 return E_OUTOFMEMORY;
1881 This->tmp_buffer_frames = *frames;
1884 *data = This->tmp_buffer;
1885 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1886 This->fmt->nBlockAlign;
1887 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1888 frames_bytes = *frames * This->fmt->nBlockAlign;
1889 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1890 memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
1891 frames_bytes - chunk_bytes);
1892 }else
1893 *data = This->local_buffer +
1894 This->lcl_offs_frames * This->fmt->nBlockAlign;
1895 TRACE("returning %u from %u\n", This->period_frames, This->lcl_offs_frames);
1897 This->getbuf_last = *frames;
1899 if(devpos)
1900 *devpos = This->written_frames;
1901 if(qpcpos){
1902 LARGE_INTEGER stamp, freq;
1903 QueryPerformanceCounter(&stamp);
1904 QueryPerformanceFrequency(&freq);
1905 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1908 LeaveCriticalSection(&This->lock);
1910 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1913 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1914 IAudioCaptureClient *iface, UINT32 done)
1916 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1918 TRACE("(%p)->(%u)\n", This, done);
1920 EnterCriticalSection(&This->lock);
1922 if(!done){
1923 This->getbuf_last = 0;
1924 LeaveCriticalSection(&This->lock);
1925 return S_OK;
1928 if(!This->getbuf_last){
1929 LeaveCriticalSection(&This->lock);
1930 return AUDCLNT_E_OUT_OF_ORDER;
1933 if(This->getbuf_last != done){
1934 LeaveCriticalSection(&This->lock);
1935 return AUDCLNT_E_INVALID_SIZE;
1938 This->written_frames += done;
1939 This->held_frames -= done;
1940 This->lcl_offs_frames += done;
1941 This->lcl_offs_frames %= This->bufsize_frames;
1942 This->getbuf_last = 0;
1943 TRACE("lcl: %u, held: %u\n", This->lcl_offs_frames, This->held_frames);
1945 LeaveCriticalSection(&This->lock);
1947 return S_OK;
1950 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1951 IAudioCaptureClient *iface, UINT32 *frames)
1953 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1955 TRACE("(%p)->(%p)\n", This, frames);
1957 if(!frames)
1958 return E_POINTER;
1960 EnterCriticalSection(&This->lock);
1962 *frames = This->held_frames < This->period_frames ? 0 : This->period_frames;
1964 LeaveCriticalSection(&This->lock);
1966 return S_OK;
1969 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1971 AudioCaptureClient_QueryInterface,
1972 AudioCaptureClient_AddRef,
1973 AudioCaptureClient_Release,
1974 AudioCaptureClient_GetBuffer,
1975 AudioCaptureClient_ReleaseBuffer,
1976 AudioCaptureClient_GetNextPacketSize
1979 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1980 REFIID riid, void **ppv)
1982 ACImpl *This = impl_from_IAudioClock(iface);
1984 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1986 if(!ppv)
1987 return E_POINTER;
1988 *ppv = NULL;
1990 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1991 *ppv = iface;
1992 else if(IsEqualIID(riid, &IID_IAudioClock2))
1993 *ppv = &This->IAudioClock2_iface;
1994 if(*ppv){
1995 IUnknown_AddRef((IUnknown*)*ppv);
1996 return S_OK;
1999 WARN("Unknown interface %s\n", debugstr_guid(riid));
2000 return E_NOINTERFACE;
2003 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2005 ACImpl *This = impl_from_IAudioClock(iface);
2006 return IAudioClient_AddRef(&This->IAudioClient_iface);
2009 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2011 ACImpl *This = impl_from_IAudioClock(iface);
2012 return IAudioClient_Release(&This->IAudioClient_iface);
2015 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2017 ACImpl *This = impl_from_IAudioClock(iface);
2019 TRACE("(%p)->(%p)\n", This, freq);
2021 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2022 *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
2023 else
2024 *freq = This->fmt->nSamplesPerSec;
2026 return S_OK;
2029 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2030 UINT64 *qpctime)
2032 ACImpl *This = impl_from_IAudioClock(iface);
2034 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2036 if(!pos)
2037 return E_POINTER;
2039 EnterCriticalSection(&This->lock);
2041 if(This->dataflow == eRender){
2042 *pos = This->written_frames - This->held_frames;
2043 if(*pos < This->last_pos_frames)
2044 *pos = This->last_pos_frames;
2045 }else if(This->dataflow == eCapture){
2046 *pos = This->written_frames - This->held_frames;
2049 This->last_pos_frames = *pos;
2051 TRACE("returning: 0x%s\n", wine_dbgstr_longlong(*pos));
2052 if(This->share == AUDCLNT_SHAREMODE_SHARED)
2053 *pos *= This->fmt->nBlockAlign;
2055 LeaveCriticalSection(&This->lock);
2057 if(qpctime){
2058 LARGE_INTEGER stamp, freq;
2059 QueryPerformanceCounter(&stamp);
2060 QueryPerformanceFrequency(&freq);
2061 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2064 return S_OK;
2067 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2068 DWORD *chars)
2070 ACImpl *This = impl_from_IAudioClock(iface);
2072 TRACE("(%p)->(%p)\n", This, chars);
2074 if(!chars)
2075 return E_POINTER;
2077 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2079 return S_OK;
2082 static const IAudioClockVtbl AudioClock_Vtbl =
2084 AudioClock_QueryInterface,
2085 AudioClock_AddRef,
2086 AudioClock_Release,
2087 AudioClock_GetFrequency,
2088 AudioClock_GetPosition,
2089 AudioClock_GetCharacteristics
2092 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2093 REFIID riid, void **ppv)
2095 ACImpl *This = impl_from_IAudioClock2(iface);
2096 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2099 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2101 ACImpl *This = impl_from_IAudioClock2(iface);
2102 return IAudioClient_AddRef(&This->IAudioClient_iface);
2105 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2107 ACImpl *This = impl_from_IAudioClock2(iface);
2108 return IAudioClient_Release(&This->IAudioClient_iface);
2111 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2112 UINT64 *pos, UINT64 *qpctime)
2114 ACImpl *This = impl_from_IAudioClock2(iface);
2116 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2118 return E_NOTIMPL;
2121 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2123 AudioClock2_QueryInterface,
2124 AudioClock2_AddRef,
2125 AudioClock2_Release,
2126 AudioClock2_GetDevicePosition
2129 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2131 AudioSessionWrapper *ret;
2133 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2134 sizeof(AudioSessionWrapper));
2135 if(!ret)
2136 return NULL;
2138 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2139 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2140 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2142 ret->ref = 1;
2144 ret->client = client;
2145 if(client){
2146 ret->session = client->session;
2147 AudioClient_AddRef(&client->IAudioClient_iface);
2150 return ret;
2153 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2154 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2156 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2158 if(!ppv)
2159 return E_POINTER;
2160 *ppv = NULL;
2162 if(IsEqualIID(riid, &IID_IUnknown) ||
2163 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2164 IsEqualIID(riid, &IID_IAudioSessionControl2))
2165 *ppv = iface;
2166 if(*ppv){
2167 IUnknown_AddRef((IUnknown*)*ppv);
2168 return S_OK;
2171 WARN("Unknown interface %s\n", debugstr_guid(riid));
2172 return E_NOINTERFACE;
2175 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2177 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2178 ULONG ref;
2179 ref = InterlockedIncrement(&This->ref);
2180 TRACE("(%p) Refcount now %u\n", This, ref);
2181 return ref;
2184 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2186 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2187 ULONG ref;
2188 ref = InterlockedDecrement(&This->ref);
2189 TRACE("(%p) Refcount now %u\n", This, ref);
2190 if(!ref){
2191 if(This->client){
2192 EnterCriticalSection(&This->client->lock);
2193 This->client->session_wrapper = NULL;
2194 LeaveCriticalSection(&This->client->lock);
2195 AudioClient_Release(&This->client->IAudioClient_iface);
2197 HeapFree(GetProcessHeap(), 0, This);
2199 return ref;
2202 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2203 AudioSessionState *state)
2205 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2206 ACImpl *client;
2208 TRACE("(%p)->(%p)\n", This, state);
2210 if(!state)
2211 return NULL_PTR_ERR;
2213 EnterCriticalSection(&g_sessions_lock);
2215 if(list_empty(&This->session->clients)){
2216 *state = AudioSessionStateExpired;
2217 LeaveCriticalSection(&g_sessions_lock);
2218 return S_OK;
2221 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2222 EnterCriticalSection(&client->lock);
2223 if(client->playing){
2224 *state = AudioSessionStateActive;
2225 LeaveCriticalSection(&client->lock);
2226 LeaveCriticalSection(&g_sessions_lock);
2227 return S_OK;
2229 LeaveCriticalSection(&client->lock);
2232 LeaveCriticalSection(&g_sessions_lock);
2234 *state = AudioSessionStateInactive;
2236 return S_OK;
2239 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2240 IAudioSessionControl2 *iface, WCHAR **name)
2242 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2244 FIXME("(%p)->(%p) - stub\n", This, name);
2246 return E_NOTIMPL;
2249 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2250 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2252 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2254 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2256 return E_NOTIMPL;
2259 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2260 IAudioSessionControl2 *iface, WCHAR **path)
2262 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2264 FIXME("(%p)->(%p) - stub\n", This, path);
2266 return E_NOTIMPL;
2269 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2270 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2272 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2274 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2276 return E_NOTIMPL;
2279 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2280 IAudioSessionControl2 *iface, GUID *group)
2282 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2284 FIXME("(%p)->(%p) - stub\n", This, group);
2286 return E_NOTIMPL;
2289 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2290 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2292 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2294 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2295 debugstr_guid(session));
2297 return E_NOTIMPL;
2300 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2301 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2303 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2305 FIXME("(%p)->(%p) - stub\n", This, events);
2307 return S_OK;
2310 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2311 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2313 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2315 FIXME("(%p)->(%p) - stub\n", This, events);
2317 return S_OK;
2320 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2321 IAudioSessionControl2 *iface, WCHAR **id)
2323 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2325 FIXME("(%p)->(%p) - stub\n", This, id);
2327 return E_NOTIMPL;
2330 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2331 IAudioSessionControl2 *iface, WCHAR **id)
2333 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2335 FIXME("(%p)->(%p) - stub\n", This, id);
2337 return E_NOTIMPL;
2340 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2341 IAudioSessionControl2 *iface, DWORD *pid)
2343 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2345 TRACE("(%p)->(%p)\n", This, pid);
2347 if(!pid)
2348 return E_POINTER;
2350 *pid = GetCurrentProcessId();
2352 return S_OK;
2355 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2356 IAudioSessionControl2 *iface)
2358 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2360 TRACE("(%p)\n", This);
2362 return S_FALSE;
2365 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2366 IAudioSessionControl2 *iface, BOOL optout)
2368 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2370 TRACE("(%p)->(%d)\n", This, optout);
2372 return S_OK;
2375 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2377 AudioSessionControl_QueryInterface,
2378 AudioSessionControl_AddRef,
2379 AudioSessionControl_Release,
2380 AudioSessionControl_GetState,
2381 AudioSessionControl_GetDisplayName,
2382 AudioSessionControl_SetDisplayName,
2383 AudioSessionControl_GetIconPath,
2384 AudioSessionControl_SetIconPath,
2385 AudioSessionControl_GetGroupingParam,
2386 AudioSessionControl_SetGroupingParam,
2387 AudioSessionControl_RegisterAudioSessionNotification,
2388 AudioSessionControl_UnregisterAudioSessionNotification,
2389 AudioSessionControl_GetSessionIdentifier,
2390 AudioSessionControl_GetSessionInstanceIdentifier,
2391 AudioSessionControl_GetProcessId,
2392 AudioSessionControl_IsSystemSoundsSession,
2393 AudioSessionControl_SetDuckingPreference
2396 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2397 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2399 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2401 if(!ppv)
2402 return E_POINTER;
2403 *ppv = NULL;
2405 if(IsEqualIID(riid, &IID_IUnknown) ||
2406 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2407 *ppv = iface;
2408 if(*ppv){
2409 IUnknown_AddRef((IUnknown*)*ppv);
2410 return S_OK;
2413 WARN("Unknown interface %s\n", debugstr_guid(riid));
2414 return E_NOINTERFACE;
2417 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2419 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2420 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2423 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2425 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2426 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2429 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2430 ISimpleAudioVolume *iface, float level, const GUID *context)
2432 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2433 AudioSession *session = This->session;
2435 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2437 if(level < 0.f || level > 1.f)
2438 return E_INVALIDARG;
2440 if(context)
2441 FIXME("Notifications not supported yet\n");
2443 EnterCriticalSection(&session->lock);
2445 session->master_vol = level;
2447 TRACE("OSS doesn't support setting volume\n");
2449 LeaveCriticalSection(&session->lock);
2451 return S_OK;
2454 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2455 ISimpleAudioVolume *iface, float *level)
2457 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2458 AudioSession *session = This->session;
2460 TRACE("(%p)->(%p)\n", session, level);
2462 if(!level)
2463 return NULL_PTR_ERR;
2465 *level = session->master_vol;
2467 return S_OK;
2470 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2471 BOOL mute, const GUID *context)
2473 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2474 AudioSession *session = This->session;
2476 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2478 EnterCriticalSection(&session->lock);
2480 session->mute = mute;
2482 LeaveCriticalSection(&session->lock);
2484 return S_OK;
2487 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2488 BOOL *mute)
2490 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2491 AudioSession *session = This->session;
2493 TRACE("(%p)->(%p)\n", session, mute);
2495 if(!mute)
2496 return NULL_PTR_ERR;
2498 *mute = This->session->mute;
2500 return S_OK;
2503 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2505 SimpleAudioVolume_QueryInterface,
2506 SimpleAudioVolume_AddRef,
2507 SimpleAudioVolume_Release,
2508 SimpleAudioVolume_SetMasterVolume,
2509 SimpleAudioVolume_GetMasterVolume,
2510 SimpleAudioVolume_SetMute,
2511 SimpleAudioVolume_GetMute
2514 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2515 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2517 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2519 if(!ppv)
2520 return E_POINTER;
2521 *ppv = NULL;
2523 if(IsEqualIID(riid, &IID_IUnknown) ||
2524 IsEqualIID(riid, &IID_IAudioStreamVolume))
2525 *ppv = iface;
2526 if(*ppv){
2527 IUnknown_AddRef((IUnknown*)*ppv);
2528 return S_OK;
2531 WARN("Unknown interface %s\n", debugstr_guid(riid));
2532 return E_NOINTERFACE;
2535 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2537 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2538 return IAudioClient_AddRef(&This->IAudioClient_iface);
2541 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2543 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2544 return IAudioClient_Release(&This->IAudioClient_iface);
2547 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2548 IAudioStreamVolume *iface, UINT32 *out)
2550 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2552 TRACE("(%p)->(%p)\n", This, out);
2554 if(!out)
2555 return E_POINTER;
2557 *out = This->fmt->nChannels;
2559 return S_OK;
2562 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2563 IAudioStreamVolume *iface, UINT32 index, float level)
2565 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2567 TRACE("(%p)->(%d, %f)\n", This, index, level);
2569 if(level < 0.f || level > 1.f)
2570 return E_INVALIDARG;
2572 if(index >= This->fmt->nChannels)
2573 return E_INVALIDARG;
2575 EnterCriticalSection(&This->lock);
2577 This->vols[index] = level;
2579 TRACE("OSS doesn't support setting volume\n");
2581 LeaveCriticalSection(&This->lock);
2583 return S_OK;
2586 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2587 IAudioStreamVolume *iface, UINT32 index, float *level)
2589 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2591 TRACE("(%p)->(%d, %p)\n", This, index, level);
2593 if(!level)
2594 return E_POINTER;
2596 if(index >= This->fmt->nChannels)
2597 return E_INVALIDARG;
2599 *level = This->vols[index];
2601 return S_OK;
2604 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2605 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2607 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2608 int i;
2610 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2612 if(!levels)
2613 return E_POINTER;
2615 if(count != This->fmt->nChannels)
2616 return E_INVALIDARG;
2618 EnterCriticalSection(&This->lock);
2620 for(i = 0; i < count; ++i)
2621 This->vols[i] = levels[i];
2623 TRACE("OSS doesn't support setting volume\n");
2625 LeaveCriticalSection(&This->lock);
2627 return S_OK;
2630 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2631 IAudioStreamVolume *iface, UINT32 count, float *levels)
2633 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2634 int i;
2636 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2638 if(!levels)
2639 return E_POINTER;
2641 if(count != This->fmt->nChannels)
2642 return E_INVALIDARG;
2644 EnterCriticalSection(&This->lock);
2646 for(i = 0; i < count; ++i)
2647 levels[i] = This->vols[i];
2649 LeaveCriticalSection(&This->lock);
2651 return S_OK;
2654 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2656 AudioStreamVolume_QueryInterface,
2657 AudioStreamVolume_AddRef,
2658 AudioStreamVolume_Release,
2659 AudioStreamVolume_GetChannelCount,
2660 AudioStreamVolume_SetChannelVolume,
2661 AudioStreamVolume_GetChannelVolume,
2662 AudioStreamVolume_SetAllVolumes,
2663 AudioStreamVolume_GetAllVolumes
2666 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2667 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2669 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2671 if(!ppv)
2672 return E_POINTER;
2673 *ppv = NULL;
2675 if(IsEqualIID(riid, &IID_IUnknown) ||
2676 IsEqualIID(riid, &IID_IChannelAudioVolume))
2677 *ppv = iface;
2678 if(*ppv){
2679 IUnknown_AddRef((IUnknown*)*ppv);
2680 return S_OK;
2683 WARN("Unknown interface %s\n", debugstr_guid(riid));
2684 return E_NOINTERFACE;
2687 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2689 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2690 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2693 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2695 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2696 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2699 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2700 IChannelAudioVolume *iface, UINT32 *out)
2702 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2703 AudioSession *session = This->session;
2705 TRACE("(%p)->(%p)\n", session, out);
2707 if(!out)
2708 return NULL_PTR_ERR;
2710 *out = session->channel_count;
2712 return S_OK;
2715 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2716 IChannelAudioVolume *iface, UINT32 index, float level,
2717 const GUID *context)
2719 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2720 AudioSession *session = This->session;
2722 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2723 wine_dbgstr_guid(context));
2725 if(level < 0.f || level > 1.f)
2726 return E_INVALIDARG;
2728 if(index >= session->channel_count)
2729 return E_INVALIDARG;
2731 if(context)
2732 FIXME("Notifications not supported yet\n");
2734 EnterCriticalSection(&session->lock);
2736 session->channel_vols[index] = level;
2738 TRACE("OSS doesn't support setting volume\n");
2740 LeaveCriticalSection(&session->lock);
2742 return S_OK;
2745 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2746 IChannelAudioVolume *iface, UINT32 index, float *level)
2748 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2749 AudioSession *session = This->session;
2751 TRACE("(%p)->(%d, %p)\n", session, index, level);
2753 if(!level)
2754 return NULL_PTR_ERR;
2756 if(index >= session->channel_count)
2757 return E_INVALIDARG;
2759 *level = session->channel_vols[index];
2761 return S_OK;
2764 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2765 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2766 const GUID *context)
2768 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2769 AudioSession *session = This->session;
2770 int i;
2772 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2773 wine_dbgstr_guid(context));
2775 if(!levels)
2776 return NULL_PTR_ERR;
2778 if(count != session->channel_count)
2779 return E_INVALIDARG;
2781 if(context)
2782 FIXME("Notifications not supported yet\n");
2784 EnterCriticalSection(&session->lock);
2786 for(i = 0; i < count; ++i)
2787 session->channel_vols[i] = levels[i];
2789 TRACE("OSS doesn't support setting volume\n");
2791 LeaveCriticalSection(&session->lock);
2793 return S_OK;
2796 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2797 IChannelAudioVolume *iface, UINT32 count, float *levels)
2799 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2800 AudioSession *session = This->session;
2801 int i;
2803 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2805 if(!levels)
2806 return NULL_PTR_ERR;
2808 if(count != session->channel_count)
2809 return E_INVALIDARG;
2811 for(i = 0; i < count; ++i)
2812 levels[i] = session->channel_vols[i];
2814 return S_OK;
2817 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2819 ChannelAudioVolume_QueryInterface,
2820 ChannelAudioVolume_AddRef,
2821 ChannelAudioVolume_Release,
2822 ChannelAudioVolume_GetChannelCount,
2823 ChannelAudioVolume_SetChannelVolume,
2824 ChannelAudioVolume_GetChannelVolume,
2825 ChannelAudioVolume_SetAllVolumes,
2826 ChannelAudioVolume_GetAllVolumes
2829 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2830 REFIID riid, void **ppv)
2832 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2834 if(!ppv)
2835 return E_POINTER;
2836 *ppv = NULL;
2838 if(IsEqualIID(riid, &IID_IUnknown) ||
2839 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2840 IsEqualIID(riid, &IID_IAudioSessionManager2))
2841 *ppv = iface;
2842 if(*ppv){
2843 IUnknown_AddRef((IUnknown*)*ppv);
2844 return S_OK;
2847 WARN("Unknown interface %s\n", debugstr_guid(riid));
2848 return E_NOINTERFACE;
2851 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2853 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2854 ULONG ref;
2855 ref = InterlockedIncrement(&This->ref);
2856 TRACE("(%p) Refcount now %u\n", This, ref);
2857 return ref;
2860 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2862 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2863 ULONG ref;
2864 ref = InterlockedDecrement(&This->ref);
2865 TRACE("(%p) Refcount now %u\n", This, ref);
2866 if(!ref)
2867 HeapFree(GetProcessHeap(), 0, This);
2868 return ref;
2871 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2872 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2873 IAudioSessionControl **out)
2875 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2876 AudioSession *session;
2877 AudioSessionWrapper *wrapper;
2878 HRESULT hr;
2880 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2881 flags, out);
2883 hr = get_audio_session(session_guid, This->device, 0, &session);
2884 if(FAILED(hr))
2885 return hr;
2887 wrapper = AudioSessionWrapper_Create(NULL);
2888 if(!wrapper)
2889 return E_OUTOFMEMORY;
2891 wrapper->session = session;
2893 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2895 return S_OK;
2898 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2899 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2900 ISimpleAudioVolume **out)
2902 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2903 AudioSession *session;
2904 AudioSessionWrapper *wrapper;
2905 HRESULT hr;
2907 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2908 flags, out);
2910 hr = get_audio_session(session_guid, This->device, 0, &session);
2911 if(FAILED(hr))
2912 return hr;
2914 wrapper = AudioSessionWrapper_Create(NULL);
2915 if(!wrapper)
2916 return E_OUTOFMEMORY;
2918 wrapper->session = session;
2920 *out = &wrapper->ISimpleAudioVolume_iface;
2922 return S_OK;
2925 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2926 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2928 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2929 FIXME("(%p)->(%p) - stub\n", This, out);
2930 return E_NOTIMPL;
2933 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2934 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2936 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2937 FIXME("(%p)->(%p) - stub\n", This, notification);
2938 return E_NOTIMPL;
2941 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2942 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2944 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2945 FIXME("(%p)->(%p) - stub\n", This, notification);
2946 return E_NOTIMPL;
2949 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2950 IAudioSessionManager2 *iface, const WCHAR *session_id,
2951 IAudioVolumeDuckNotification *notification)
2953 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2954 FIXME("(%p)->(%p) - stub\n", This, notification);
2955 return E_NOTIMPL;
2958 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2959 IAudioSessionManager2 *iface,
2960 IAudioVolumeDuckNotification *notification)
2962 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2963 FIXME("(%p)->(%p) - stub\n", This, notification);
2964 return E_NOTIMPL;
2967 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2969 AudioSessionManager_QueryInterface,
2970 AudioSessionManager_AddRef,
2971 AudioSessionManager_Release,
2972 AudioSessionManager_GetAudioSessionControl,
2973 AudioSessionManager_GetSimpleAudioVolume,
2974 AudioSessionManager_GetSessionEnumerator,
2975 AudioSessionManager_RegisterSessionNotification,
2976 AudioSessionManager_UnregisterSessionNotification,
2977 AudioSessionManager_RegisterDuckNotification,
2978 AudioSessionManager_UnregisterDuckNotification
2981 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2982 IAudioSessionManager2 **out)
2984 SessionMgr *This;
2986 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2987 if(!This)
2988 return E_OUTOFMEMORY;
2990 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2991 This->device = device;
2992 This->ref = 1;
2994 *out = &This->IAudioSessionManager2_iface;
2996 return S_OK;