webservices: Add support for union types in the reader.
[wine.git] / dlls / wineandroid.drv / mmdevdrv.c
blob6b05c509f7aaa6e91be8cbe86cfb0d6e4aae857d
1 /*
2 * Copyright 2015 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
20 #define COBJMACROS
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/ioctl.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <math.h>
37 #include <SLES/OpenSLES.h>
38 #include <SLES/OpenSLES_Android.h>
40 #include "android.h"
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winnls.h"
45 #include "winreg.h"
46 #include "wine/debug.h"
47 #include "wine/unicode.h"
48 #include "wine/list.h"
49 #include "wine/library.h"
51 #include "ole2.h"
52 #include "mmdeviceapi.h"
53 #include "devpkey.h"
54 #include "dshow.h"
55 #include "dsound.h"
57 #include "initguid.h"
58 #include "endpointvolume.h"
59 #include "audiopolicy.h"
60 #include "audioclient.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(androidaudio);
64 #define DECL_FUNCPTR(f) static typeof(f) * p##f
65 DECL_FUNCPTR( slCreateEngine );
66 DECL_FUNCPTR( SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
67 DECL_FUNCPTR( SL_IID_ENGINE );
68 DECL_FUNCPTR( SL_IID_PLAY );
69 DECL_FUNCPTR( SL_IID_PLAYBACKRATE );
70 DECL_FUNCPTR( SL_IID_RECORD );
72 #define SLCALL_N(obj, func) (*obj)->func(obj)
73 #define SLCALL(obj, func, ...) (*obj)->func(obj, __VA_ARGS__)
75 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
77 static const REFERENCE_TIME DefaultPeriod = 100000;
78 static const REFERENCE_TIME MinimumPeriod = 50000;
80 struct ACImpl;
81 typedef struct ACImpl ACImpl;
83 typedef struct _AudioSession {
84 GUID guid;
85 struct list clients;
87 IMMDevice *device;
89 float master_vol;
90 UINT32 channel_count;
91 float *channel_vols;
92 BOOL mute;
94 CRITICAL_SECTION lock;
96 struct list entry;
97 } AudioSession;
99 typedef struct _AudioSessionWrapper {
100 IAudioSessionControl2 IAudioSessionControl2_iface;
101 IChannelAudioVolume IChannelAudioVolume_iface;
102 ISimpleAudioVolume ISimpleAudioVolume_iface;
104 LONG ref;
106 ACImpl *client;
107 AudioSession *session;
108 } AudioSessionWrapper;
110 struct ACImpl {
111 IAudioClient IAudioClient_iface;
112 IAudioRenderClient IAudioRenderClient_iface;
113 IAudioCaptureClient IAudioCaptureClient_iface;
114 IAudioClock IAudioClock_iface;
115 IAudioClock2 IAudioClock2_iface;
116 IAudioStreamVolume IAudioStreamVolume_iface;
118 LONG ref;
120 IMMDevice *parent;
121 IUnknown *pUnkFTMarshal;
123 WAVEFORMATEX *fmt;
125 EDataFlow dataflow;
126 DWORD flags;
127 AUDCLNT_SHAREMODE share;
128 HANDLE event;
129 float *vols;
131 SLObjectItf outputmix;
132 SLObjectItf player;
133 SLObjectItf recorder;
134 SLAndroidSimpleBufferQueueItf bufq;
135 SLPlayItf playitf;
136 SLRecordItf recorditf;
138 BOOL initted, playing;
139 UINT64 written_frames, last_pos_frames;
140 UINT32 period_us, period_frames, bufsize_frames, held_frames, tmp_buffer_frames, wrap_buffer_frames, in_sl_frames;
141 UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */
143 BYTE *local_buffer, *tmp_buffer, *wrap_buffer;
144 LONG32 getbuf_last; /* <0 when using tmp_buffer */
145 HANDLE timer;
147 CRITICAL_SECTION lock;
149 AudioSession *session;
150 AudioSessionWrapper *session_wrapper;
152 struct list entry;
155 typedef struct _SessionMgr {
156 IAudioSessionManager2 IAudioSessionManager2_iface;
158 LONG ref;
160 IMMDevice *device;
161 } SessionMgr;
163 static struct list g_devices = LIST_INIT(g_devices);
165 static HANDLE g_timer_q;
167 static CRITICAL_SECTION g_sessions_lock;
168 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
170 0, 0, &g_sessions_lock,
171 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
172 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
174 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
175 static struct list g_sessions = LIST_INIT(g_sessions);
177 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
179 static const IAudioClientVtbl AudioClient_Vtbl;
180 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
181 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
182 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
183 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
184 static const IAudioClockVtbl AudioClock_Vtbl;
185 static const IAudioClock2Vtbl AudioClock2_Vtbl;
186 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
187 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
188 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
190 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
192 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
195 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
197 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
200 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
202 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
205 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
207 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
210 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
212 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
215 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
217 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
220 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
222 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
225 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
227 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
230 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
232 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
235 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
237 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
240 #define LOAD_FUNCPTR(lib, func) do { \
241 if ((p##func = wine_dlsym( lib, #func, NULL, 0 )) == NULL) \
242 { ERR( "can't find symbol %s\n", #func); return FALSE; } \
243 } while(0)
245 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
247 static BOOL WINAPI load_opensles( INIT_ONCE *once, void *param, void **context )
249 void *libopensles;
250 char error[1024];
252 if (!(libopensles = wine_dlopen( "libOpenSLES.so", RTLD_GLOBAL, error, sizeof(error) )))
254 ERR( "failed to load libOpenSLES.so: %s\n", error );
255 return FALSE;
257 LOAD_FUNCPTR( libopensles, slCreateEngine );
258 LOAD_FUNCPTR( libopensles, SL_IID_ANDROIDSIMPLEBUFFERQUEUE );
259 LOAD_FUNCPTR( libopensles, SL_IID_ENGINE );
260 LOAD_FUNCPTR( libopensles, SL_IID_PLAY );
261 LOAD_FUNCPTR( libopensles, SL_IID_PLAYBACKRATE );
262 LOAD_FUNCPTR( libopensles, SL_IID_RECORD );
264 if (!(g_timer_q = CreateTimerQueue())) return FALSE;
266 return TRUE;
269 /* From <dlls/mmdevapi/mmdevapi.h> */
270 enum DriverPriority {
271 Priority_Unavailable = 0,
272 Priority_Low,
273 Priority_Neutral,
274 Priority_Preferred
277 int WINAPI AUDDRV_GetPriority(void)
279 if (!InitOnceExecuteOnce( &init_once, load_opensles, NULL, NULL ))
280 return Priority_Unavailable;
282 return Priority_Preferred;
285 static SLObjectItf sl;
286 static SLEngineItf engine;
288 HRESULT AUDDRV_Init(void)
290 SLresult sr;
291 SLEngineOption options[] = { {SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE} };
293 sr = pslCreateEngine(&sl, 1, options, 0, NULL, NULL);
294 if(sr != SL_RESULT_SUCCESS){
295 WARN("slCreateEngine failed: 0x%x\n", sr);
296 return E_FAIL;
299 sr = SLCALL(sl, Realize, SL_BOOLEAN_FALSE);
300 if(sr != SL_RESULT_SUCCESS){
301 SLCALL_N(sl, Destroy);
302 WARN("Engine Realize failed: 0x%x\n", sr);
303 return E_FAIL;
306 sr = SLCALL(sl, GetInterface, *pSL_IID_ENGINE, (void*)&engine);
307 if(sr != SL_RESULT_SUCCESS){
308 SLCALL_N(sl, Destroy);
309 WARN("GetInterface failed: 0x%x\n", sr);
310 return E_FAIL;
313 return S_OK;
316 static const GUID outGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x00}};
317 static const GUID inGuid = {0x0a047ace, 0x22b1, 0x4342, {0x98, 0xbb, 0xf8, 0x56, 0x32, 0x26, 0x61, 0x01}};
319 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids,
320 UINT *num, UINT *def_index)
322 static const WCHAR outName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','O','u','t',0};
323 static const WCHAR inName[] = {'A','n','d','r','o','i','d',' ','A','u','d','i','o',' ','I','n',0};
325 TRACE("%u %p %p %p %p\n", flow, ids, guids, num, def_index);
327 *def_index = 0;
328 *num = 1;
329 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
330 *guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
331 if(flow == eRender){
332 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(outName));
333 memcpy((*ids)[0], outName, sizeof(outName));
334 memcpy(&(*guids)[0], &outGuid, sizeof(outGuid));
335 }else{
336 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(inName));
337 memcpy((*ids)[0], inName, sizeof(inName));
338 memcpy(&(*guids)[0], &inGuid, sizeof(inGuid));
341 return S_OK;
344 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev,
345 IAudioClient **out)
347 ACImpl *This;
348 HRESULT hr;
349 EDataFlow flow;
350 SLresult sr;
352 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
354 if(!sl)
355 AUDDRV_Init();
357 if(IsEqualGUID(guid, &outGuid))
358 flow = eRender;
359 else if(IsEqualGUID(guid, &inGuid))
360 flow = eCapture;
361 else
362 return AUDCLNT_E_DEVICE_INVALIDATED;
364 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
365 if(!This)
366 return E_OUTOFMEMORY;
368 hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient_iface,
369 (IUnknown **)&This->pUnkFTMarshal);
370 if (FAILED(hr)) {
371 HeapFree(GetProcessHeap(), 0, This);
372 return hr;
375 if(flow == eRender){
376 sr = SLCALL(engine, CreateOutputMix, &This->outputmix, 0, NULL, NULL);
377 if(sr != SL_RESULT_SUCCESS){
378 WARN("CreateOutputMix failed: 0x%x\n", sr);
379 HeapFree(GetProcessHeap(), 0, This);
380 return E_FAIL;
383 sr = SLCALL(This->outputmix, Realize, SL_BOOLEAN_FALSE);
384 if(sr != SL_RESULT_SUCCESS){
385 SLCALL_N(This->outputmix, Destroy);
386 This->outputmix = NULL;
387 HeapFree(GetProcessHeap(), 0, This);
388 WARN("outputmix Realize failed: 0x%x\n", sr);
389 return E_FAIL;
393 This->dataflow = flow;
395 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
396 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
397 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
398 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
399 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
400 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
402 InitializeCriticalSection(&This->lock);
403 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
405 This->parent = dev;
406 IMMDevice_AddRef(This->parent);
408 IAudioClient_AddRef(&This->IAudioClient_iface);
410 *out = &This->IAudioClient_iface;
412 return S_OK;
415 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
416 REFIID riid, void **ppv)
418 ACImpl *This = impl_from_IAudioClient(iface);
419 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
421 if(!ppv)
422 return E_POINTER;
423 *ppv = NULL;
424 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
425 *ppv = iface;
426 else if(IsEqualIID(riid, &IID_IMarshal))
427 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
428 if(*ppv){
429 IUnknown_AddRef((IUnknown*)*ppv);
430 return S_OK;
432 WARN("Unknown interface %s\n", debugstr_guid(riid));
433 return E_NOINTERFACE;
436 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
438 ACImpl *This = impl_from_IAudioClient(iface);
439 ULONG ref;
440 ref = InterlockedIncrement(&This->ref);
441 TRACE("(%p) Refcount now %u\n", This, ref);
442 return ref;
445 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
447 ACImpl *This = impl_from_IAudioClient(iface);
448 ULONG ref;
450 ref = InterlockedDecrement(&This->ref);
451 TRACE("(%p) Refcount now %u\n", This, ref);
452 if(!ref){
453 if(This->timer){
454 HANDLE event;
455 DWORD wait;
456 event = CreateEventW(NULL, TRUE, FALSE, NULL);
457 wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
458 wait = wait && GetLastError() == ERROR_IO_PENDING;
459 if(event && wait)
460 WaitForSingleObject(event, INFINITE);
461 CloseHandle(event);
464 IAudioClient_Stop(iface);
466 IMMDevice_Release(This->parent);
467 IUnknown_Release(This->pUnkFTMarshal);
468 This->lock.DebugInfo->Spare[0] = 0;
469 DeleteCriticalSection(&This->lock);
471 if(This->recorder)
472 SLCALL_N(This->recorder, Destroy);
473 if(This->player)
474 SLCALL_N(This->player, Destroy);
475 if(This->outputmix)
476 SLCALL_N(This->outputmix, Destroy);
478 if(This->initted){
479 EnterCriticalSection(&g_sessions_lock);
480 list_remove(&This->entry);
481 LeaveCriticalSection(&g_sessions_lock);
483 HeapFree(GetProcessHeap(), 0, This->vols);
484 HeapFree(GetProcessHeap(), 0, This->local_buffer);
485 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
486 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
487 CoTaskMemFree(This->fmt);
488 HeapFree(GetProcessHeap(), 0, This);
490 return ref;
493 static void dump_fmt(const WAVEFORMATEX *fmt)
495 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
496 switch(fmt->wFormatTag){
497 case WAVE_FORMAT_PCM:
498 TRACE("WAVE_FORMAT_PCM");
499 break;
500 case WAVE_FORMAT_IEEE_FLOAT:
501 TRACE("WAVE_FORMAT_IEEE_FLOAT");
502 break;
503 case WAVE_FORMAT_EXTENSIBLE:
504 TRACE("WAVE_FORMAT_EXTENSIBLE");
505 break;
506 default:
507 TRACE("Unknown");
508 break;
510 TRACE(")\n");
512 TRACE("nChannels: %u\n", fmt->nChannels);
513 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
514 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
515 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
516 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
517 TRACE("cbSize: %u\n", fmt->cbSize);
519 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
520 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
521 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
522 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
523 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
527 static DWORD get_channel_mask(unsigned int channels)
529 switch(channels){
530 case 0:
531 return 0;
532 case 1:
533 return KSAUDIO_SPEAKER_MONO;
534 case 2:
535 return KSAUDIO_SPEAKER_STEREO;
536 case 3:
537 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
538 case 4:
539 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
540 case 5:
541 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
542 case 6:
543 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
544 case 7:
545 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
546 case 8:
547 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
549 FIXME("Unknown speaker configuration: %u\n", channels);
550 return 0;
553 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
555 WAVEFORMATEX *ret;
556 size_t size;
558 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
559 size = sizeof(WAVEFORMATEXTENSIBLE);
560 else
561 size = sizeof(WAVEFORMATEX);
563 ret = CoTaskMemAlloc(size);
564 if(!ret)
565 return NULL;
567 memcpy(ret, fmt, size);
569 ret->cbSize = size - sizeof(WAVEFORMATEX);
571 return ret;
574 static void session_init_vols(AudioSession *session, UINT channels)
576 if(session->channel_count < channels){
577 UINT i;
579 if(session->channel_vols)
580 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
581 session->channel_vols, sizeof(float) * channels);
582 else
583 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
584 sizeof(float) * channels);
585 if(!session->channel_vols)
586 return;
588 for(i = session->channel_count; i < channels; ++i)
589 session->channel_vols[i] = 1.f;
591 session->channel_count = channels;
595 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
596 UINT num_channels)
598 AudioSession *ret;
600 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
601 if(!ret)
602 return NULL;
604 memcpy(&ret->guid, guid, sizeof(GUID));
606 ret->device = device;
608 list_init(&ret->clients);
610 list_add_head(&g_sessions, &ret->entry);
612 InitializeCriticalSection(&ret->lock);
613 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
615 session_init_vols(ret, num_channels);
617 ret->master_vol = 1.f;
619 return ret;
622 /* if channels == 0, then this will return or create a session with
623 * matching dataflow and GUID. otherwise, channels must also match */
624 static HRESULT get_audio_session(const GUID *sessionguid,
625 IMMDevice *device, UINT channels, AudioSession **out)
627 AudioSession *session;
629 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
630 *out = create_session(&GUID_NULL, device, channels);
631 if(!*out)
632 return E_OUTOFMEMORY;
634 return S_OK;
637 *out = NULL;
638 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
639 if(session->device == device &&
640 IsEqualGUID(sessionguid, &session->guid)){
641 session_init_vols(session, channels);
642 *out = session;
643 break;
647 if(!*out){
648 *out = create_session(sessionguid, device, channels);
649 if(!*out)
650 return E_OUTOFMEMORY;
653 return S_OK;
656 static HRESULT waveformat_to_pcm(ACImpl *This, const WAVEFORMATEX *fmt, SLDataFormat_PCM *pcm)
658 /* only support non-float PCM */
659 if(fmt->wFormatTag != WAVE_FORMAT_PCM &&
660 !(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
661 IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)fmt)->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)))
662 return AUDCLNT_E_UNSUPPORTED_FORMAT;
664 /* TODO: does android only support 16-bit PCM? */
666 if(fmt->nSamplesPerSec < 8000 || fmt->nSamplesPerSec > 48000)
667 return AUDCLNT_E_UNSUPPORTED_FORMAT;
669 pcm->formatType = SL_DATAFORMAT_PCM;
670 pcm->numChannels = fmt->nChannels;
671 pcm->samplesPerSec = fmt->nSamplesPerSec * 1000; /* no typo, actually in milli-Hz */
672 pcm->bitsPerSample = fmt->wBitsPerSample;
673 pcm->containerSize = fmt->wBitsPerSample;
674 /* only up to stereo */
675 if(pcm->numChannels == 1)
676 pcm->channelMask = SL_SPEAKER_FRONT_LEFT;
677 else if(This->dataflow == eRender && pcm->numChannels == 2)
678 pcm->channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
679 else
680 return AUDCLNT_E_UNSUPPORTED_FORMAT;
681 pcm->endianness = SL_BYTEORDER_LITTLEENDIAN;
683 return S_OK;
686 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
687 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
688 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
689 const GUID *sessionguid)
691 ACImpl *This = impl_from_IAudioClient(iface);
692 int i;
693 HRESULT hr;
694 SLresult sr;
695 SLDataFormat_PCM pcm;
696 SLDataLocator_AndroidSimpleBufferQueue loc_bq;
698 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
699 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
701 if(!fmt)
702 return E_POINTER;
704 dump_fmt(fmt);
706 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
707 return AUDCLNT_E_NOT_INITIALIZED;
709 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
710 AUDCLNT_STREAMFLAGS_LOOPBACK |
711 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
712 AUDCLNT_STREAMFLAGS_NOPERSIST |
713 AUDCLNT_STREAMFLAGS_RATEADJUST |
714 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
715 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
716 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
717 TRACE("Unknown flags: %08x\n", flags);
718 return E_INVALIDARG;
721 if(mode == AUDCLNT_SHAREMODE_SHARED){
722 period = DefaultPeriod;
723 if( duration < 3 * period)
724 duration = 3 * period;
725 }else{
726 if(!period)
727 period = DefaultPeriod; /* not minimum */
728 if(period < MinimumPeriod || period > 5000000)
729 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
730 if(duration > 20000000) /* the smaller the period, the lower this limit */
731 return AUDCLNT_E_BUFFER_SIZE_ERROR;
732 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
733 if(duration != period)
734 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
735 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
736 return AUDCLNT_E_DEVICE_IN_USE;
737 }else{
738 if( duration < 8 * period)
739 duration = 8 * period; /* may grow above 2s */
743 EnterCriticalSection(&This->lock);
745 if(This->initted){
746 LeaveCriticalSection(&This->lock);
747 return AUDCLNT_E_ALREADY_INITIALIZED;
750 This->period_us = period / 10;
751 This->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
753 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
754 if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
755 This->bufsize_frames -= This->bufsize_frames % This->period_frames;
756 else if(This->bufsize_frames % This->period_frames != 0)
757 /* hack: round up to integer multiple */
758 This->bufsize_frames += This->period_frames - This->bufsize_frames % This->period_frames;
760 hr = waveformat_to_pcm(This, fmt, &pcm);
761 if(FAILED(hr)){
762 LeaveCriticalSection(&This->lock);
763 return hr;
766 if(This->dataflow == eRender){
767 SLDataSource source;
768 SLDataSink sink;
769 SLDataLocator_OutputMix loc_outmix;
770 SLboolean required[2];
771 SLInterfaceID iids[2];
773 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
774 loc_bq.numBuffers = This->bufsize_frames / This->period_frames;
775 source.pLocator = &loc_bq;
776 source.pFormat = &pcm;
778 loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
779 loc_outmix.outputMix = This->outputmix;
780 sink.pLocator = &loc_outmix;
781 sink.pFormat = NULL;
783 required[0] = SL_BOOLEAN_TRUE;
784 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
785 required[1] = SL_BOOLEAN_TRUE;
786 iids[1] = *pSL_IID_PLAYBACKRATE;
788 sr = SLCALL(engine, CreateAudioPlayer, &This->player, &source, &sink,
789 2, iids, required);
790 if(sr != SL_RESULT_SUCCESS){
791 WARN("CreateAudioPlayer failed: 0x%x\n", sr);
792 LeaveCriticalSection(&This->lock);
793 return E_FAIL;
796 sr = SLCALL(This->player, Realize, SL_BOOLEAN_FALSE);
797 if(sr != SL_RESULT_SUCCESS){
798 SLCALL_N(This->player, Destroy);
799 This->player = NULL;
800 WARN("Player Realize failed: 0x%x\n", sr);
801 LeaveCriticalSection(&This->lock);
802 return E_FAIL;
805 sr = SLCALL(This->player, GetInterface, *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE, &This->bufq);
806 if(sr != SL_RESULT_SUCCESS){
807 SLCALL_N(This->player, Destroy);
808 This->player = NULL;
809 WARN("Player GetInterface(BufferQueue) failed: 0x%x\n", sr);
810 LeaveCriticalSection(&This->lock);
811 return E_FAIL;
814 sr = SLCALL(This->player, GetInterface, *pSL_IID_PLAY, &This->playitf);
815 if(sr != SL_RESULT_SUCCESS){
816 SLCALL_N(This->player, Destroy);
817 This->player = NULL;
818 WARN("Player GetInterface(Play) failed: 0x%x\n", sr);
819 LeaveCriticalSection(&This->lock);
820 return E_FAIL;
822 }else{
823 SLDataSource source;
824 SLDataSink sink;
825 SLDataLocator_IODevice loc_mic;
826 SLboolean required[1];
827 SLInterfaceID iids[1];
829 loc_mic.locatorType = SL_DATALOCATOR_IODEVICE;
830 loc_mic.deviceType = SL_IODEVICE_AUDIOINPUT;
831 loc_mic.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
832 loc_mic.device = NULL;
833 source.pLocator = &loc_mic;
834 source.pFormat = NULL;
836 loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
837 loc_bq.numBuffers = This->bufsize_frames / This->period_frames;
838 sink.pLocator = &loc_bq;
839 sink.pFormat = &pcm;
841 required[0] = SL_BOOLEAN_TRUE;
842 iids[0] = *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE;
844 sr = SLCALL(engine, CreateAudioRecorder, &This->recorder, &source, &sink,
845 1, iids, required);
846 if(sr != SL_RESULT_SUCCESS){
847 WARN("CreateAudioRecorder failed: 0x%x\n", sr);
848 LeaveCriticalSection(&This->lock);
849 return E_FAIL;
852 sr = SLCALL(This->recorder, Realize, SL_BOOLEAN_FALSE);
853 if(sr != SL_RESULT_SUCCESS){
854 SLCALL_N(This->recorder, Destroy);
855 This->recorder = NULL;
856 WARN("Recorder Realize failed: 0x%x\n", sr);
857 LeaveCriticalSection(&This->lock);
858 return E_FAIL;
861 sr = SLCALL(This->recorder, GetInterface, *pSL_IID_ANDROIDSIMPLEBUFFERQUEUE, &This->bufq);
862 if(sr != SL_RESULT_SUCCESS){
863 SLCALL_N(This->recorder, Destroy);
864 This->recorder = NULL;
865 WARN("Recorder GetInterface(BufferQueue) failed: 0x%x\n", sr);
866 LeaveCriticalSection(&This->lock);
867 return E_FAIL;
870 sr = SLCALL(This->recorder, GetInterface, *pSL_IID_RECORD, &This->recorditf);
871 if(sr != SL_RESULT_SUCCESS){
872 SLCALL_N(This->recorder, Destroy);
873 This->recorder = NULL;
874 WARN("Recorder GetInterface(Record) failed: 0x%x\n", sr);
875 LeaveCriticalSection(&This->lock);
876 return E_FAIL;
880 This->fmt = clone_format(fmt);
881 if(!This->fmt){
882 if(This->player){
883 SLCALL_N(This->player, Destroy);
884 This->player = NULL;
886 if(This->recorder){
887 SLCALL_N(This->recorder, Destroy);
888 This->recorder = NULL;
890 LeaveCriticalSection(&This->lock);
891 return E_OUTOFMEMORY;
894 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
895 This->bufsize_frames * fmt->nBlockAlign);
896 if(!This->local_buffer){
897 CoTaskMemFree(This->fmt);
898 This->fmt = NULL;
899 if(This->player){
900 SLCALL_N(This->player, Destroy);
901 This->player = NULL;
903 if(This->recorder){
904 SLCALL_N(This->recorder, Destroy);
905 This->recorder = NULL;
907 LeaveCriticalSection(&This->lock);
908 return E_OUTOFMEMORY;
911 if(This->dataflow == eCapture){
912 while(This->in_sl_frames < This->bufsize_frames){
913 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
914 sr = SLCALL(This->bufq, Enqueue,
915 This->local_buffer + ((This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
916 This->period_frames * This->fmt->nBlockAlign);
917 if(sr != SL_RESULT_SUCCESS)
918 WARN("Enqueue failed: 0x%x\n", sr);
919 This->in_sl_frames += This->period_frames;
923 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
924 if(!This->vols){
925 CoTaskMemFree(This->fmt);
926 This->fmt = NULL;
927 if(This->player){
928 SLCALL_N(This->player, Destroy);
929 This->player = NULL;
931 if(This->recorder){
932 SLCALL_N(This->recorder, Destroy);
933 This->recorder = NULL;
935 LeaveCriticalSection(&This->lock);
936 return E_OUTOFMEMORY;
939 for(i = 0; i < fmt->nChannels; ++i)
940 This->vols[i] = 1.f;
942 This->share = mode;
943 This->flags = flags;
944 This->oss_bufsize_bytes = 0;
946 EnterCriticalSection(&g_sessions_lock);
948 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
949 &This->session);
950 if(FAILED(hr)){
951 LeaveCriticalSection(&g_sessions_lock);
952 HeapFree(GetProcessHeap(), 0, This->vols);
953 This->vols = NULL;
954 CoTaskMemFree(This->fmt);
955 This->fmt = NULL;
956 if(This->player){
957 SLCALL_N(This->player, Destroy);
958 This->player = NULL;
960 if(This->recorder){
961 SLCALL_N(This->recorder, Destroy);
962 This->recorder = NULL;
964 LeaveCriticalSection(&This->lock);
965 return hr;
968 list_add_tail(&This->session->clients, &This->entry);
970 LeaveCriticalSection(&g_sessions_lock);
972 This->initted = TRUE;
974 TRACE("numBuffers: %u, bufsize: %u, period: %u\n", loc_bq.numBuffers,
975 This->bufsize_frames, This->period_frames);
977 LeaveCriticalSection(&This->lock);
979 return S_OK;
982 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
983 UINT32 *frames)
985 ACImpl *This = impl_from_IAudioClient(iface);
987 TRACE("(%p)->(%p)\n", This, frames);
989 if(!frames)
990 return E_POINTER;
992 EnterCriticalSection(&This->lock);
994 if(!This->initted){
995 LeaveCriticalSection(&This->lock);
996 return AUDCLNT_E_NOT_INITIALIZED;
999 *frames = This->bufsize_frames;
1001 TRACE("buffer size: %u\n", *frames);
1003 LeaveCriticalSection(&This->lock);
1005 return S_OK;
1008 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1009 REFERENCE_TIME *latency)
1011 ACImpl *This = impl_from_IAudioClient(iface);
1013 TRACE("(%p)->(%p)\n", This, latency);
1015 if(!latency)
1016 return E_POINTER;
1018 EnterCriticalSection(&This->lock);
1020 if(!This->initted){
1021 LeaveCriticalSection(&This->lock);
1022 return AUDCLNT_E_NOT_INITIALIZED;
1025 /* pretend we process audio in Period chunks, so max latency includes
1026 * the period time. Some native machines add .6666ms in shared mode. */
1027 *latency = This->period_us * 10 + 6666;
1029 LeaveCriticalSection(&This->lock);
1031 return S_OK;
1034 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1035 UINT32 *numpad)
1037 ACImpl *This = impl_from_IAudioClient(iface);
1039 TRACE("(%p)->(%p)\n", This, numpad);
1041 if(!numpad)
1042 return E_POINTER;
1044 EnterCriticalSection(&This->lock);
1046 if(!This->initted){
1047 LeaveCriticalSection(&This->lock);
1048 return AUDCLNT_E_NOT_INITIALIZED;
1051 *numpad = This->held_frames;
1053 TRACE("padding: %u\n", *numpad);
1055 LeaveCriticalSection(&This->lock);
1057 return S_OK;
1060 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1061 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1062 WAVEFORMATEX **outpwfx)
1064 ACImpl *This = impl_from_IAudioClient(iface);
1065 SLDataFormat_PCM pcm;
1066 HRESULT hr;
1068 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1070 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1071 return E_POINTER;
1073 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1074 return E_INVALIDARG;
1076 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1077 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1078 return E_INVALIDARG;
1080 dump_fmt(pwfx);
1082 if(outpwfx){
1083 *outpwfx = NULL;
1084 if(mode != AUDCLNT_SHAREMODE_SHARED)
1085 outpwfx = NULL;
1088 hr = waveformat_to_pcm(This, pwfx, &pcm);
1089 TRACE("returning: %08x\n", hr);
1090 return hr;
1093 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1094 WAVEFORMATEX **pwfx)
1096 ACImpl *This = impl_from_IAudioClient(iface);
1097 WAVEFORMATEXTENSIBLE *fmt;
1099 TRACE("(%p)->(%p)\n", This, pwfx);
1101 if(!pwfx)
1102 return E_POINTER;
1103 *pwfx = NULL;
1105 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1106 if(!fmt)
1107 return E_OUTOFMEMORY;
1109 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1110 fmt->Format.wBitsPerSample = 16;
1111 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1112 if(This->dataflow == eRender)
1113 fmt->Format.nChannels = 2;
1114 else
1115 fmt->Format.nChannels = 1;
1116 fmt->Format.nSamplesPerSec = 48000; /* TODO: query supported? recording? */
1117 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1118 fmt->Format.nChannels) / 8;
1119 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1120 fmt->Format.nBlockAlign;
1121 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1122 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1123 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1125 *pwfx = (WAVEFORMATEX*)fmt;
1126 dump_fmt(*pwfx);
1128 return S_OK;
1131 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1132 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1134 ACImpl *This = impl_from_IAudioClient(iface);
1136 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1138 if(!defperiod && !minperiod)
1139 return E_POINTER;
1141 if(defperiod)
1142 *defperiod = DefaultPeriod;
1143 if(minperiod)
1144 *minperiod = MinimumPeriod;
1146 return S_OK;
1149 static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
1151 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1152 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1153 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1154 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1155 This->fmt->wBitsPerSample == 8)
1156 memset(buffer, 128, frames * This->fmt->nBlockAlign);
1157 else
1158 memset(buffer, 0, frames * This->fmt->nBlockAlign);
1161 static void sl_read_data(ACImpl *This)
1163 SLAndroidSimpleBufferQueueState state;
1164 SLresult sr;
1165 SLuint32 elapsed;
1167 memset(&state, 0, sizeof(state));
1169 sr = SLCALL(This->bufq, GetState, &state);
1170 if(sr != SL_RESULT_SUCCESS){
1171 WARN("GetState failed: 0x%x\n", sr);
1172 return;
1174 TRACE("got: count: %u, index: %u, held: %u, in_sl: %u\n", state.count, state.index, This->held_frames, This->in_sl_frames);
1176 elapsed = This->in_sl_frames - state.count * This->period_frames;
1177 This->held_frames += elapsed;
1178 This->in_sl_frames = state.count * This->period_frames;
1180 if(This->held_frames == This->bufsize_frames){
1181 /* overrun */
1182 TRACE("overrun??\n");
1183 This->lcl_offs_frames += This->period_frames;
1184 This->held_frames -= This->period_frames;
1187 TRACE("good range: %u, %u\n", This->lcl_offs_frames, This->lcl_offs_frames + This->held_frames);
1188 TRACE("held: %u, in_sl: %u\n", This->held_frames, This->in_sl_frames);
1189 while(This->held_frames + This->in_sl_frames < This->bufsize_frames){
1190 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->held_frames + This->in_sl_frames) % This->bufsize_frames);
1191 sr = SLCALL(This->bufq, Enqueue,
1192 This->local_buffer + ((This->lcl_offs_frames + This->held_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
1193 This->period_frames * This->fmt->nBlockAlign);
1194 if(sr != SL_RESULT_SUCCESS)
1195 WARN("Enqueue failed: 0x%x\n", sr);
1196 This->in_sl_frames += This->period_frames;
1200 static DWORD wrap_enqueue(ACImpl *This)
1202 DWORD to_enqueue = min(This->held_frames, This->period_frames);
1203 DWORD offs = (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames;
1204 BYTE *buf = This->local_buffer + offs * This->fmt->nBlockAlign;
1206 if(offs + to_enqueue > This->bufsize_frames){
1207 DWORD chunk = This->bufsize_frames - offs;
1209 if(This->wrap_buffer_frames < to_enqueue){
1210 HeapFree(GetProcessHeap(), 0, This->wrap_buffer);
1211 This->wrap_buffer = HeapAlloc(GetProcessHeap(), 0, to_enqueue * This->fmt->nBlockAlign);
1212 This->wrap_buffer_frames = to_enqueue;
1215 memcpy(This->wrap_buffer, This->local_buffer + offs * This->fmt->nBlockAlign, chunk * This->fmt->nBlockAlign);
1216 memcpy(This->wrap_buffer + chunk * This->fmt->nBlockAlign, This->local_buffer, (to_enqueue - chunk) * This->fmt->nBlockAlign);
1218 buf = This->wrap_buffer;
1221 SLCALL(This->bufq, Enqueue, buf,
1222 to_enqueue * This->fmt->nBlockAlign);
1224 return to_enqueue;
1227 static void sl_write_data(ACImpl *This)
1229 SLAndroidSimpleBufferQueueState state;
1230 SLresult sr;
1231 SLuint32 elapsed;
1233 memset(&state, 0, sizeof(state));
1235 sr = SLCALL(This->bufq, GetState, &state);
1236 if(sr != SL_RESULT_SUCCESS){
1237 WARN("GetState failed: 0x%x\n", sr);
1238 return;
1240 TRACE("got: count: %u, index: %u\n", state.count, state.index);
1242 elapsed = This->in_sl_frames - state.count * This->period_frames;
1244 if(elapsed > This->held_frames)
1245 This->held_frames = 0;
1246 else
1247 This->held_frames -= elapsed;
1249 This->lcl_offs_frames += elapsed;
1250 This->lcl_offs_frames %= This->bufsize_frames;
1252 This->in_sl_frames = state.count * This->period_frames;
1254 while(This->held_frames >= This->in_sl_frames + This->period_frames){
1255 /* have at least a period to write, so write it */
1256 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1257 This->in_sl_frames += wrap_enqueue(This);
1260 if(This->held_frames && This->in_sl_frames < This->period_frames * 3){
1261 /* write out the last bit with a partial period */
1262 TRACE("enqueueing partial period: %u frames from %u\n", This->held_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1263 This->in_sl_frames += wrap_enqueue(This);
1266 TRACE("done with enqueue, lcl_offs: %u, in_sl: %u, held: %u\n", This->lcl_offs_frames, This->in_sl_frames, This->held_frames);
1269 static void CALLBACK sl_period_callback(void *user, BOOLEAN timer)
1271 ACImpl *This = user;
1273 EnterCriticalSection(&This->lock);
1275 if(This->playing){
1276 if(This->dataflow == eRender)
1277 sl_write_data(This);
1278 else if(This->dataflow == eCapture)
1279 sl_read_data(This);
1282 LeaveCriticalSection(&This->lock);
1284 if(This->event)
1285 SetEvent(This->event);
1288 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1290 ACImpl *This = impl_from_IAudioClient(iface);
1291 SLresult sr;
1293 TRACE("(%p)\n", This);
1295 EnterCriticalSection(&This->lock);
1297 if(!This->initted){
1298 LeaveCriticalSection(&This->lock);
1299 return AUDCLNT_E_NOT_INITIALIZED;
1302 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1303 LeaveCriticalSection(&This->lock);
1304 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1307 if(This->playing){
1308 LeaveCriticalSection(&This->lock);
1309 return AUDCLNT_E_NOT_STOPPED;
1312 if(This->dataflow == eRender){
1313 sr = SLCALL(This->playitf, SetPlayState, SL_PLAYSTATE_PLAYING);
1314 if(sr != SL_RESULT_SUCCESS){
1315 WARN("SetPlayState failed: 0x%x\n", sr);
1316 LeaveCriticalSection(&This->lock);
1317 return E_FAIL;
1319 }else{
1320 sr = SLCALL(This->recorditf, SetRecordState, SL_RECORDSTATE_RECORDING);
1321 if(sr != SL_RESULT_SUCCESS){
1322 WARN("SetRecordState failed: 0x%x\n", sr);
1323 LeaveCriticalSection(&This->lock);
1324 return E_FAIL;
1328 if(!This->timer){
1329 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1330 sl_period_callback, This, 0, This->period_us / 1000,
1331 WT_EXECUTEINTIMERTHREAD))
1332 WARN("Unable to create period timer: %u\n", GetLastError());
1335 This->playing = TRUE;
1337 LeaveCriticalSection(&This->lock);
1339 return S_OK;
1342 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1344 ACImpl *This = impl_from_IAudioClient(iface);
1345 SLresult sr;
1347 TRACE("(%p)\n", This);
1349 EnterCriticalSection(&This->lock);
1351 if(!This->initted){
1352 LeaveCriticalSection(&This->lock);
1353 return AUDCLNT_E_NOT_INITIALIZED;
1356 if(!This->playing){
1357 LeaveCriticalSection(&This->lock);
1358 return S_FALSE;
1361 if(This->dataflow == eRender){
1362 sr = SLCALL(This->playitf, SetPlayState, SL_PLAYSTATE_PAUSED);
1363 if(sr != SL_RESULT_SUCCESS){
1364 WARN("SetPlayState failed: 0x%x\n", sr);
1365 LeaveCriticalSection(&This->lock);
1366 return E_FAIL;
1368 }else{
1369 sr = SLCALL(This->recorditf, SetRecordState, SL_RECORDSTATE_STOPPED);
1370 if(sr != SL_RESULT_SUCCESS){
1371 WARN("SetRecordState failed: 0x%x\n", sr);
1372 LeaveCriticalSection(&This->lock);
1373 return E_FAIL;
1377 This->playing = FALSE;
1379 LeaveCriticalSection(&This->lock);
1381 return S_OK;
1384 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1386 ACImpl *This = impl_from_IAudioClient(iface);
1387 SLresult sr;
1389 TRACE("(%p)\n", This);
1391 EnterCriticalSection(&This->lock);
1393 if(!This->initted){
1394 LeaveCriticalSection(&This->lock);
1395 return AUDCLNT_E_NOT_INITIALIZED;
1398 if(This->playing){
1399 LeaveCriticalSection(&This->lock);
1400 return AUDCLNT_E_NOT_STOPPED;
1403 if(This->getbuf_last){
1404 LeaveCriticalSection(&This->lock);
1405 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1408 sr = SLCALL_N(This->bufq, Clear);
1409 if(sr != SL_RESULT_SUCCESS){
1410 WARN("Clear failed: 0x%x\n", sr);
1411 LeaveCriticalSection(&This->lock);
1412 return E_FAIL;
1415 This->lcl_offs_frames = 0;
1416 This->in_sl_frames = 0;
1418 if(This->dataflow == eRender){
1419 This->written_frames = 0;
1420 This->last_pos_frames = 0;
1421 }else{
1422 This->written_frames += This->held_frames;
1423 while(This->in_sl_frames < This->bufsize_frames){
1424 TRACE("enqueueing: %u frames from %u\n", This->period_frames, (This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames);
1425 sr = SLCALL(This->bufq, Enqueue,
1426 This->local_buffer + ((This->lcl_offs_frames + This->in_sl_frames) % This->bufsize_frames) * This->fmt->nBlockAlign,
1427 This->period_frames * This->fmt->nBlockAlign);
1428 if(sr != SL_RESULT_SUCCESS)
1429 WARN("Enqueue failed: 0x%x\n", sr);
1430 This->in_sl_frames += This->period_frames;
1434 This->held_frames = 0;
1436 LeaveCriticalSection(&This->lock);
1438 return S_OK;
1441 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1442 HANDLE event)
1444 ACImpl *This = impl_from_IAudioClient(iface);
1446 TRACE("(%p)->(%p)\n", This, event);
1448 if(!event)
1449 return E_INVALIDARG;
1451 EnterCriticalSection(&This->lock);
1453 if(!This->initted){
1454 LeaveCriticalSection(&This->lock);
1455 return AUDCLNT_E_NOT_INITIALIZED;
1458 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1459 LeaveCriticalSection(&This->lock);
1460 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1463 if (This->event){
1464 LeaveCriticalSection(&This->lock);
1465 FIXME("called twice\n");
1466 return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1469 This->event = event;
1471 LeaveCriticalSection(&This->lock);
1473 return S_OK;
1476 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1477 void **ppv)
1479 ACImpl *This = impl_from_IAudioClient(iface);
1481 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1483 if(!ppv)
1484 return E_POINTER;
1485 *ppv = NULL;
1487 EnterCriticalSection(&This->lock);
1489 if(!This->initted){
1490 LeaveCriticalSection(&This->lock);
1491 return AUDCLNT_E_NOT_INITIALIZED;
1494 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1495 if(This->dataflow != eRender){
1496 LeaveCriticalSection(&This->lock);
1497 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1499 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1500 *ppv = &This->IAudioRenderClient_iface;
1501 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1502 if(This->dataflow != eCapture){
1503 LeaveCriticalSection(&This->lock);
1504 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1506 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1507 *ppv = &This->IAudioCaptureClient_iface;
1508 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1509 IAudioClock_AddRef(&This->IAudioClock_iface);
1510 *ppv = &This->IAudioClock_iface;
1511 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1512 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1513 *ppv = &This->IAudioStreamVolume_iface;
1514 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1515 if(!This->session_wrapper){
1516 This->session_wrapper = AudioSessionWrapper_Create(This);
1517 if(!This->session_wrapper){
1518 LeaveCriticalSection(&This->lock);
1519 return E_OUTOFMEMORY;
1521 }else
1522 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1524 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1525 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1526 if(!This->session_wrapper){
1527 This->session_wrapper = AudioSessionWrapper_Create(This);
1528 if(!This->session_wrapper){
1529 LeaveCriticalSection(&This->lock);
1530 return E_OUTOFMEMORY;
1532 }else
1533 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1535 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1536 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1537 if(!This->session_wrapper){
1538 This->session_wrapper = AudioSessionWrapper_Create(This);
1539 if(!This->session_wrapper){
1540 LeaveCriticalSection(&This->lock);
1541 return E_OUTOFMEMORY;
1543 }else
1544 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1546 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1549 if(*ppv){
1550 LeaveCriticalSection(&This->lock);
1551 return S_OK;
1554 LeaveCriticalSection(&This->lock);
1556 FIXME("stub %s\n", debugstr_guid(riid));
1557 return E_NOINTERFACE;
1560 static const IAudioClientVtbl AudioClient_Vtbl =
1562 AudioClient_QueryInterface,
1563 AudioClient_AddRef,
1564 AudioClient_Release,
1565 AudioClient_Initialize,
1566 AudioClient_GetBufferSize,
1567 AudioClient_GetStreamLatency,
1568 AudioClient_GetCurrentPadding,
1569 AudioClient_IsFormatSupported,
1570 AudioClient_GetMixFormat,
1571 AudioClient_GetDevicePeriod,
1572 AudioClient_Start,
1573 AudioClient_Stop,
1574 AudioClient_Reset,
1575 AudioClient_SetEventHandle,
1576 AudioClient_GetService
1579 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1580 IAudioRenderClient *iface, REFIID riid, void **ppv)
1582 ACImpl *This = impl_from_IAudioRenderClient(iface);
1583 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1585 if(!ppv)
1586 return E_POINTER;
1587 *ppv = NULL;
1589 if(IsEqualIID(riid, &IID_IUnknown) ||
1590 IsEqualIID(riid, &IID_IAudioRenderClient))
1591 *ppv = iface;
1592 else if(IsEqualIID(riid, &IID_IMarshal))
1593 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1594 if(*ppv){
1595 IUnknown_AddRef((IUnknown*)*ppv);
1596 return S_OK;
1599 WARN("Unknown interface %s\n", debugstr_guid(riid));
1600 return E_NOINTERFACE;
1603 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1605 ACImpl *This = impl_from_IAudioRenderClient(iface);
1606 return AudioClient_AddRef(&This->IAudioClient_iface);
1609 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1611 ACImpl *This = impl_from_IAudioRenderClient(iface);
1612 return AudioClient_Release(&This->IAudioClient_iface);
1615 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1616 UINT32 frames, BYTE **data)
1618 ACImpl *This = impl_from_IAudioRenderClient(iface);
1619 UINT32 write_pos;
1621 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1623 if(!data)
1624 return E_POINTER;
1626 *data = NULL;
1628 EnterCriticalSection(&This->lock);
1630 if(This->getbuf_last){
1631 LeaveCriticalSection(&This->lock);
1632 return AUDCLNT_E_OUT_OF_ORDER;
1635 if(!frames){
1636 LeaveCriticalSection(&This->lock);
1637 return S_OK;
1640 if(This->held_frames + frames > This->bufsize_frames){
1641 LeaveCriticalSection(&This->lock);
1642 return AUDCLNT_E_BUFFER_TOO_LARGE;
1645 write_pos =
1646 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1647 if(write_pos + frames > This->bufsize_frames){
1648 if(This->tmp_buffer_frames < frames){
1649 DWORD alloc = frames < This->period_frames ? This->period_frames : frames;
1650 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1651 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1652 alloc * This->fmt->nBlockAlign);
1653 if(!This->tmp_buffer){
1654 LeaveCriticalSection(&This->lock);
1655 return E_OUTOFMEMORY;
1657 This->tmp_buffer_frames = alloc;
1659 *data = This->tmp_buffer;
1660 This->getbuf_last = -frames;
1661 }else{
1662 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1663 This->getbuf_last = frames;
1666 silence_buffer(This, *data, frames);
1668 LeaveCriticalSection(&This->lock);
1670 return S_OK;
1673 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1675 UINT32 write_offs_frames =
1676 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1677 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1678 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1679 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1680 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1682 if(written_bytes <= chunk_bytes){
1683 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1684 }else{
1685 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1686 memcpy(This->local_buffer, buffer + chunk_bytes,
1687 written_bytes - chunk_bytes);
1691 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1692 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1694 ACImpl *This = impl_from_IAudioRenderClient(iface);
1695 BYTE *buffer;
1697 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1699 EnterCriticalSection(&This->lock);
1701 if(!written_frames){
1702 This->getbuf_last = 0;
1703 LeaveCriticalSection(&This->lock);
1704 return S_OK;
1707 if(!This->getbuf_last){
1708 LeaveCriticalSection(&This->lock);
1709 return AUDCLNT_E_OUT_OF_ORDER;
1712 if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1713 LeaveCriticalSection(&This->lock);
1714 return AUDCLNT_E_INVALID_SIZE;
1717 if(This->getbuf_last >= 0)
1718 buffer = This->local_buffer + This->fmt->nBlockAlign *
1719 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1720 else
1721 buffer = This->tmp_buffer;
1723 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1724 silence_buffer(This, buffer, written_frames);
1726 if(This->getbuf_last < 0)
1727 oss_wrap_buffer(This, buffer, written_frames);
1729 This->held_frames += written_frames;
1730 This->written_frames += written_frames;
1731 This->getbuf_last = 0;
1733 LeaveCriticalSection(&This->lock);
1735 return S_OK;
1738 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1739 AudioRenderClient_QueryInterface,
1740 AudioRenderClient_AddRef,
1741 AudioRenderClient_Release,
1742 AudioRenderClient_GetBuffer,
1743 AudioRenderClient_ReleaseBuffer
1746 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1747 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1749 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1750 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1752 if(!ppv)
1753 return E_POINTER;
1754 *ppv = NULL;
1756 if(IsEqualIID(riid, &IID_IUnknown) ||
1757 IsEqualIID(riid, &IID_IAudioCaptureClient))
1758 *ppv = iface;
1759 else if(IsEqualIID(riid, &IID_IMarshal))
1760 return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv);
1761 if(*ppv){
1762 IUnknown_AddRef((IUnknown*)*ppv);
1763 return S_OK;
1766 WARN("Unknown interface %s\n", debugstr_guid(riid));
1767 return E_NOINTERFACE;
1770 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1772 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1773 return IAudioClient_AddRef(&This->IAudioClient_iface);
1776 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1778 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1779 return IAudioClient_Release(&This->IAudioClient_iface);
1782 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1783 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1784 UINT64 *qpcpos)
1786 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1788 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1789 devpos, qpcpos);
1791 if(!data || !frames || !flags)
1792 return E_POINTER;
1794 EnterCriticalSection(&This->lock);
1796 if(This->getbuf_last){
1797 LeaveCriticalSection(&This->lock);
1798 return AUDCLNT_E_OUT_OF_ORDER;
1801 if(This->held_frames < This->period_frames){
1802 *frames = 0;
1803 LeaveCriticalSection(&This->lock);
1804 return AUDCLNT_S_BUFFER_EMPTY;
1807 *flags = 0;
1809 *frames = This->period_frames;
1811 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1812 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1813 if(This->tmp_buffer_frames < *frames){
1814 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1815 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1816 *frames * This->fmt->nBlockAlign);
1817 if(!This->tmp_buffer){
1818 LeaveCriticalSection(&This->lock);
1819 return E_OUTOFMEMORY;
1821 This->tmp_buffer_frames = *frames;
1824 *data = This->tmp_buffer;
1825 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1826 This->fmt->nBlockAlign;
1827 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1828 frames_bytes = *frames * This->fmt->nBlockAlign;
1829 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1830 memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
1831 frames_bytes - chunk_bytes);
1832 }else
1833 *data = This->local_buffer +
1834 This->lcl_offs_frames * This->fmt->nBlockAlign;
1835 TRACE("returning %u from %u\n", This->period_frames, This->lcl_offs_frames);
1837 This->getbuf_last = *frames;
1839 if(devpos)
1840 *devpos = This->written_frames;
1841 if(qpcpos){
1842 LARGE_INTEGER stamp, freq;
1843 QueryPerformanceCounter(&stamp);
1844 QueryPerformanceFrequency(&freq);
1845 *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1848 LeaveCriticalSection(&This->lock);
1850 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1853 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1854 IAudioCaptureClient *iface, UINT32 done)
1856 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1858 TRACE("(%p)->(%u)\n", This, done);
1860 EnterCriticalSection(&This->lock);
1862 if(!done){
1863 This->getbuf_last = 0;
1864 LeaveCriticalSection(&This->lock);
1865 return S_OK;
1868 if(!This->getbuf_last){
1869 LeaveCriticalSection(&This->lock);
1870 return AUDCLNT_E_OUT_OF_ORDER;
1873 if(This->getbuf_last != done){
1874 LeaveCriticalSection(&This->lock);
1875 return AUDCLNT_E_INVALID_SIZE;
1878 This->written_frames += done;
1879 This->held_frames -= done;
1880 This->lcl_offs_frames += done;
1881 This->lcl_offs_frames %= This->bufsize_frames;
1882 This->getbuf_last = 0;
1883 TRACE("lcl: %u, held: %u\n", This->lcl_offs_frames, This->held_frames);
1885 LeaveCriticalSection(&This->lock);
1887 return S_OK;
1890 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1891 IAudioCaptureClient *iface, UINT32 *frames)
1893 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1895 TRACE("(%p)->(%p)\n", This, frames);
1897 if(!frames)
1898 return E_POINTER;
1900 EnterCriticalSection(&This->lock);
1902 *frames = This->held_frames < This->period_frames ? 0 : This->period_frames;
1904 LeaveCriticalSection(&This->lock);
1906 return S_OK;
1909 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1911 AudioCaptureClient_QueryInterface,
1912 AudioCaptureClient_AddRef,
1913 AudioCaptureClient_Release,
1914 AudioCaptureClient_GetBuffer,
1915 AudioCaptureClient_ReleaseBuffer,
1916 AudioCaptureClient_GetNextPacketSize
1919 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1920 REFIID riid, void **ppv)
1922 ACImpl *This = impl_from_IAudioClock(iface);
1924 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1926 if(!ppv)
1927 return E_POINTER;
1928 *ppv = NULL;
1930 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1931 *ppv = iface;
1932 else if(IsEqualIID(riid, &IID_IAudioClock2))
1933 *ppv = &This->IAudioClock2_iface;
1934 if(*ppv){
1935 IUnknown_AddRef((IUnknown*)*ppv);
1936 return S_OK;
1939 WARN("Unknown interface %s\n", debugstr_guid(riid));
1940 return E_NOINTERFACE;
1943 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1945 ACImpl *This = impl_from_IAudioClock(iface);
1946 return IAudioClient_AddRef(&This->IAudioClient_iface);
1949 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1951 ACImpl *This = impl_from_IAudioClock(iface);
1952 return IAudioClient_Release(&This->IAudioClient_iface);
1955 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1957 ACImpl *This = impl_from_IAudioClock(iface);
1959 TRACE("(%p)->(%p)\n", This, freq);
1961 if(This->share == AUDCLNT_SHAREMODE_SHARED)
1962 *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
1963 else
1964 *freq = This->fmt->nSamplesPerSec;
1966 return S_OK;
1969 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1970 UINT64 *qpctime)
1972 ACImpl *This = impl_from_IAudioClock(iface);
1974 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1976 if(!pos)
1977 return E_POINTER;
1979 EnterCriticalSection(&This->lock);
1981 if(This->dataflow == eRender){
1982 *pos = This->written_frames - This->held_frames;
1983 if(*pos < This->last_pos_frames)
1984 *pos = This->last_pos_frames;
1985 }else if(This->dataflow == eCapture){
1986 *pos = This->written_frames - This->held_frames;
1989 This->last_pos_frames = *pos;
1991 TRACE("returning: 0x%s\n", wine_dbgstr_longlong(*pos));
1992 if(This->share == AUDCLNT_SHAREMODE_SHARED)
1993 *pos *= This->fmt->nBlockAlign;
1995 LeaveCriticalSection(&This->lock);
1997 if(qpctime){
1998 LARGE_INTEGER stamp, freq;
1999 QueryPerformanceCounter(&stamp);
2000 QueryPerformanceFrequency(&freq);
2001 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2004 return S_OK;
2007 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2008 DWORD *chars)
2010 ACImpl *This = impl_from_IAudioClock(iface);
2012 TRACE("(%p)->(%p)\n", This, chars);
2014 if(!chars)
2015 return E_POINTER;
2017 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2019 return S_OK;
2022 static const IAudioClockVtbl AudioClock_Vtbl =
2024 AudioClock_QueryInterface,
2025 AudioClock_AddRef,
2026 AudioClock_Release,
2027 AudioClock_GetFrequency,
2028 AudioClock_GetPosition,
2029 AudioClock_GetCharacteristics
2032 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2033 REFIID riid, void **ppv)
2035 ACImpl *This = impl_from_IAudioClock2(iface);
2036 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2039 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2041 ACImpl *This = impl_from_IAudioClock2(iface);
2042 return IAudioClient_AddRef(&This->IAudioClient_iface);
2045 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2047 ACImpl *This = impl_from_IAudioClock2(iface);
2048 return IAudioClient_Release(&This->IAudioClient_iface);
2051 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2052 UINT64 *pos, UINT64 *qpctime)
2054 ACImpl *This = impl_from_IAudioClock2(iface);
2056 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2058 return E_NOTIMPL;
2061 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2063 AudioClock2_QueryInterface,
2064 AudioClock2_AddRef,
2065 AudioClock2_Release,
2066 AudioClock2_GetDevicePosition
2069 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2071 AudioSessionWrapper *ret;
2073 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2074 sizeof(AudioSessionWrapper));
2075 if(!ret)
2076 return NULL;
2078 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2079 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2080 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2082 ret->ref = 1;
2084 ret->client = client;
2085 if(client){
2086 ret->session = client->session;
2087 AudioClient_AddRef(&client->IAudioClient_iface);
2090 return ret;
2093 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2094 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2096 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2098 if(!ppv)
2099 return E_POINTER;
2100 *ppv = NULL;
2102 if(IsEqualIID(riid, &IID_IUnknown) ||
2103 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2104 IsEqualIID(riid, &IID_IAudioSessionControl2))
2105 *ppv = iface;
2106 if(*ppv){
2107 IUnknown_AddRef((IUnknown*)*ppv);
2108 return S_OK;
2111 WARN("Unknown interface %s\n", debugstr_guid(riid));
2112 return E_NOINTERFACE;
2115 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2117 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2118 ULONG ref;
2119 ref = InterlockedIncrement(&This->ref);
2120 TRACE("(%p) Refcount now %u\n", This, ref);
2121 return ref;
2124 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2126 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2127 ULONG ref;
2128 ref = InterlockedDecrement(&This->ref);
2129 TRACE("(%p) Refcount now %u\n", This, ref);
2130 if(!ref){
2131 if(This->client){
2132 EnterCriticalSection(&This->client->lock);
2133 This->client->session_wrapper = NULL;
2134 LeaveCriticalSection(&This->client->lock);
2135 AudioClient_Release(&This->client->IAudioClient_iface);
2137 HeapFree(GetProcessHeap(), 0, This);
2139 return ref;
2142 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2143 AudioSessionState *state)
2145 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2146 ACImpl *client;
2148 TRACE("(%p)->(%p)\n", This, state);
2150 if(!state)
2151 return NULL_PTR_ERR;
2153 EnterCriticalSection(&g_sessions_lock);
2155 if(list_empty(&This->session->clients)){
2156 *state = AudioSessionStateExpired;
2157 LeaveCriticalSection(&g_sessions_lock);
2158 return S_OK;
2161 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2162 EnterCriticalSection(&client->lock);
2163 if(client->playing){
2164 *state = AudioSessionStateActive;
2165 LeaveCriticalSection(&client->lock);
2166 LeaveCriticalSection(&g_sessions_lock);
2167 return S_OK;
2169 LeaveCriticalSection(&client->lock);
2172 LeaveCriticalSection(&g_sessions_lock);
2174 *state = AudioSessionStateInactive;
2176 return S_OK;
2179 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2180 IAudioSessionControl2 *iface, WCHAR **name)
2182 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2184 FIXME("(%p)->(%p) - stub\n", This, name);
2186 return E_NOTIMPL;
2189 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2190 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2192 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2194 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2196 return E_NOTIMPL;
2199 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2200 IAudioSessionControl2 *iface, WCHAR **path)
2202 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2204 FIXME("(%p)->(%p) - stub\n", This, path);
2206 return E_NOTIMPL;
2209 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2210 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2212 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2214 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2216 return E_NOTIMPL;
2219 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2220 IAudioSessionControl2 *iface, GUID *group)
2222 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2224 FIXME("(%p)->(%p) - stub\n", This, group);
2226 return E_NOTIMPL;
2229 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2230 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2232 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2234 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2235 debugstr_guid(session));
2237 return E_NOTIMPL;
2240 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2241 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2243 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2245 FIXME("(%p)->(%p) - stub\n", This, events);
2247 return S_OK;
2250 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2251 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2253 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2255 FIXME("(%p)->(%p) - stub\n", This, events);
2257 return S_OK;
2260 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2261 IAudioSessionControl2 *iface, WCHAR **id)
2263 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2265 FIXME("(%p)->(%p) - stub\n", This, id);
2267 return E_NOTIMPL;
2270 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2271 IAudioSessionControl2 *iface, WCHAR **id)
2273 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2275 FIXME("(%p)->(%p) - stub\n", This, id);
2277 return E_NOTIMPL;
2280 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2281 IAudioSessionControl2 *iface, DWORD *pid)
2283 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2285 TRACE("(%p)->(%p)\n", This, pid);
2287 if(!pid)
2288 return E_POINTER;
2290 *pid = GetCurrentProcessId();
2292 return S_OK;
2295 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2296 IAudioSessionControl2 *iface)
2298 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2300 TRACE("(%p)\n", This);
2302 return S_FALSE;
2305 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2306 IAudioSessionControl2 *iface, BOOL optout)
2308 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2310 TRACE("(%p)->(%d)\n", This, optout);
2312 return S_OK;
2315 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2317 AudioSessionControl_QueryInterface,
2318 AudioSessionControl_AddRef,
2319 AudioSessionControl_Release,
2320 AudioSessionControl_GetState,
2321 AudioSessionControl_GetDisplayName,
2322 AudioSessionControl_SetDisplayName,
2323 AudioSessionControl_GetIconPath,
2324 AudioSessionControl_SetIconPath,
2325 AudioSessionControl_GetGroupingParam,
2326 AudioSessionControl_SetGroupingParam,
2327 AudioSessionControl_RegisterAudioSessionNotification,
2328 AudioSessionControl_UnregisterAudioSessionNotification,
2329 AudioSessionControl_GetSessionIdentifier,
2330 AudioSessionControl_GetSessionInstanceIdentifier,
2331 AudioSessionControl_GetProcessId,
2332 AudioSessionControl_IsSystemSoundsSession,
2333 AudioSessionControl_SetDuckingPreference
2336 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2337 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2339 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2341 if(!ppv)
2342 return E_POINTER;
2343 *ppv = NULL;
2345 if(IsEqualIID(riid, &IID_IUnknown) ||
2346 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2347 *ppv = iface;
2348 if(*ppv){
2349 IUnknown_AddRef((IUnknown*)*ppv);
2350 return S_OK;
2353 WARN("Unknown interface %s\n", debugstr_guid(riid));
2354 return E_NOINTERFACE;
2357 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2359 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2360 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2363 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2365 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2366 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2369 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2370 ISimpleAudioVolume *iface, float level, const GUID *context)
2372 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2373 AudioSession *session = This->session;
2375 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2377 if(level < 0.f || level > 1.f)
2378 return E_INVALIDARG;
2380 if(context)
2381 FIXME("Notifications not supported yet\n");
2383 EnterCriticalSection(&session->lock);
2385 session->master_vol = level;
2387 TRACE("OSS doesn't support setting volume\n");
2389 LeaveCriticalSection(&session->lock);
2391 return S_OK;
2394 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2395 ISimpleAudioVolume *iface, float *level)
2397 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2398 AudioSession *session = This->session;
2400 TRACE("(%p)->(%p)\n", session, level);
2402 if(!level)
2403 return NULL_PTR_ERR;
2405 *level = session->master_vol;
2407 return S_OK;
2410 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2411 BOOL mute, const GUID *context)
2413 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2414 AudioSession *session = This->session;
2416 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2418 EnterCriticalSection(&session->lock);
2420 session->mute = mute;
2422 LeaveCriticalSection(&session->lock);
2424 return S_OK;
2427 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2428 BOOL *mute)
2430 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2431 AudioSession *session = This->session;
2433 TRACE("(%p)->(%p)\n", session, mute);
2435 if(!mute)
2436 return NULL_PTR_ERR;
2438 *mute = This->session->mute;
2440 return S_OK;
2443 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2445 SimpleAudioVolume_QueryInterface,
2446 SimpleAudioVolume_AddRef,
2447 SimpleAudioVolume_Release,
2448 SimpleAudioVolume_SetMasterVolume,
2449 SimpleAudioVolume_GetMasterVolume,
2450 SimpleAudioVolume_SetMute,
2451 SimpleAudioVolume_GetMute
2454 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2455 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2457 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2459 if(!ppv)
2460 return E_POINTER;
2461 *ppv = NULL;
2463 if(IsEqualIID(riid, &IID_IUnknown) ||
2464 IsEqualIID(riid, &IID_IAudioStreamVolume))
2465 *ppv = iface;
2466 if(*ppv){
2467 IUnknown_AddRef((IUnknown*)*ppv);
2468 return S_OK;
2471 WARN("Unknown interface %s\n", debugstr_guid(riid));
2472 return E_NOINTERFACE;
2475 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2477 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2478 return IAudioClient_AddRef(&This->IAudioClient_iface);
2481 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2483 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2484 return IAudioClient_Release(&This->IAudioClient_iface);
2487 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2488 IAudioStreamVolume *iface, UINT32 *out)
2490 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2492 TRACE("(%p)->(%p)\n", This, out);
2494 if(!out)
2495 return E_POINTER;
2497 *out = This->fmt->nChannels;
2499 return S_OK;
2502 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2503 IAudioStreamVolume *iface, UINT32 index, float level)
2505 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2507 TRACE("(%p)->(%d, %f)\n", This, index, level);
2509 if(level < 0.f || level > 1.f)
2510 return E_INVALIDARG;
2512 if(index >= This->fmt->nChannels)
2513 return E_INVALIDARG;
2515 EnterCriticalSection(&This->lock);
2517 This->vols[index] = level;
2519 TRACE("OSS doesn't support setting volume\n");
2521 LeaveCriticalSection(&This->lock);
2523 return S_OK;
2526 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2527 IAudioStreamVolume *iface, UINT32 index, float *level)
2529 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2531 TRACE("(%p)->(%d, %p)\n", This, index, level);
2533 if(!level)
2534 return E_POINTER;
2536 if(index >= This->fmt->nChannels)
2537 return E_INVALIDARG;
2539 *level = This->vols[index];
2541 return S_OK;
2544 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2545 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2547 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2548 int i;
2550 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2552 if(!levels)
2553 return E_POINTER;
2555 if(count != This->fmt->nChannels)
2556 return E_INVALIDARG;
2558 EnterCriticalSection(&This->lock);
2560 for(i = 0; i < count; ++i)
2561 This->vols[i] = levels[i];
2563 TRACE("OSS doesn't support setting volume\n");
2565 LeaveCriticalSection(&This->lock);
2567 return S_OK;
2570 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2571 IAudioStreamVolume *iface, UINT32 count, float *levels)
2573 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2574 int i;
2576 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2578 if(!levels)
2579 return E_POINTER;
2581 if(count != This->fmt->nChannels)
2582 return E_INVALIDARG;
2584 EnterCriticalSection(&This->lock);
2586 for(i = 0; i < count; ++i)
2587 levels[i] = This->vols[i];
2589 LeaveCriticalSection(&This->lock);
2591 return S_OK;
2594 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2596 AudioStreamVolume_QueryInterface,
2597 AudioStreamVolume_AddRef,
2598 AudioStreamVolume_Release,
2599 AudioStreamVolume_GetChannelCount,
2600 AudioStreamVolume_SetChannelVolume,
2601 AudioStreamVolume_GetChannelVolume,
2602 AudioStreamVolume_SetAllVolumes,
2603 AudioStreamVolume_GetAllVolumes
2606 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2607 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2609 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2611 if(!ppv)
2612 return E_POINTER;
2613 *ppv = NULL;
2615 if(IsEqualIID(riid, &IID_IUnknown) ||
2616 IsEqualIID(riid, &IID_IChannelAudioVolume))
2617 *ppv = iface;
2618 if(*ppv){
2619 IUnknown_AddRef((IUnknown*)*ppv);
2620 return S_OK;
2623 WARN("Unknown interface %s\n", debugstr_guid(riid));
2624 return E_NOINTERFACE;
2627 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2629 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2630 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2633 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2635 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2636 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2639 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2640 IChannelAudioVolume *iface, UINT32 *out)
2642 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2643 AudioSession *session = This->session;
2645 TRACE("(%p)->(%p)\n", session, out);
2647 if(!out)
2648 return NULL_PTR_ERR;
2650 *out = session->channel_count;
2652 return S_OK;
2655 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2656 IChannelAudioVolume *iface, UINT32 index, float level,
2657 const GUID *context)
2659 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2660 AudioSession *session = This->session;
2662 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2663 wine_dbgstr_guid(context));
2665 if(level < 0.f || level > 1.f)
2666 return E_INVALIDARG;
2668 if(index >= session->channel_count)
2669 return E_INVALIDARG;
2671 if(context)
2672 FIXME("Notifications not supported yet\n");
2674 EnterCriticalSection(&session->lock);
2676 session->channel_vols[index] = level;
2678 TRACE("OSS doesn't support setting volume\n");
2680 LeaveCriticalSection(&session->lock);
2682 return S_OK;
2685 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2686 IChannelAudioVolume *iface, UINT32 index, float *level)
2688 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2689 AudioSession *session = This->session;
2691 TRACE("(%p)->(%d, %p)\n", session, index, level);
2693 if(!level)
2694 return NULL_PTR_ERR;
2696 if(index >= session->channel_count)
2697 return E_INVALIDARG;
2699 *level = session->channel_vols[index];
2701 return S_OK;
2704 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2705 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2706 const GUID *context)
2708 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2709 AudioSession *session = This->session;
2710 int i;
2712 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2713 wine_dbgstr_guid(context));
2715 if(!levels)
2716 return NULL_PTR_ERR;
2718 if(count != session->channel_count)
2719 return E_INVALIDARG;
2721 if(context)
2722 FIXME("Notifications not supported yet\n");
2724 EnterCriticalSection(&session->lock);
2726 for(i = 0; i < count; ++i)
2727 session->channel_vols[i] = levels[i];
2729 TRACE("OSS doesn't support setting volume\n");
2731 LeaveCriticalSection(&session->lock);
2733 return S_OK;
2736 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2737 IChannelAudioVolume *iface, UINT32 count, float *levels)
2739 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2740 AudioSession *session = This->session;
2741 int i;
2743 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2745 if(!levels)
2746 return NULL_PTR_ERR;
2748 if(count != session->channel_count)
2749 return E_INVALIDARG;
2751 for(i = 0; i < count; ++i)
2752 levels[i] = session->channel_vols[i];
2754 return S_OK;
2757 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2759 ChannelAudioVolume_QueryInterface,
2760 ChannelAudioVolume_AddRef,
2761 ChannelAudioVolume_Release,
2762 ChannelAudioVolume_GetChannelCount,
2763 ChannelAudioVolume_SetChannelVolume,
2764 ChannelAudioVolume_GetChannelVolume,
2765 ChannelAudioVolume_SetAllVolumes,
2766 ChannelAudioVolume_GetAllVolumes
2769 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2770 REFIID riid, void **ppv)
2772 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2774 if(!ppv)
2775 return E_POINTER;
2776 *ppv = NULL;
2778 if(IsEqualIID(riid, &IID_IUnknown) ||
2779 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2780 IsEqualIID(riid, &IID_IAudioSessionManager2))
2781 *ppv = iface;
2782 if(*ppv){
2783 IUnknown_AddRef((IUnknown*)*ppv);
2784 return S_OK;
2787 WARN("Unknown interface %s\n", debugstr_guid(riid));
2788 return E_NOINTERFACE;
2791 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2793 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2794 ULONG ref;
2795 ref = InterlockedIncrement(&This->ref);
2796 TRACE("(%p) Refcount now %u\n", This, ref);
2797 return ref;
2800 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2802 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2803 ULONG ref;
2804 ref = InterlockedDecrement(&This->ref);
2805 TRACE("(%p) Refcount now %u\n", This, ref);
2806 if(!ref)
2807 HeapFree(GetProcessHeap(), 0, This);
2808 return ref;
2811 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2812 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2813 IAudioSessionControl **out)
2815 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2816 AudioSession *session;
2817 AudioSessionWrapper *wrapper;
2818 HRESULT hr;
2820 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2821 flags, out);
2823 hr = get_audio_session(session_guid, This->device, 0, &session);
2824 if(FAILED(hr))
2825 return hr;
2827 wrapper = AudioSessionWrapper_Create(NULL);
2828 if(!wrapper)
2829 return E_OUTOFMEMORY;
2831 wrapper->session = session;
2833 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2835 return S_OK;
2838 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2839 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2840 ISimpleAudioVolume **out)
2842 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2843 AudioSession *session;
2844 AudioSessionWrapper *wrapper;
2845 HRESULT hr;
2847 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2848 flags, out);
2850 hr = get_audio_session(session_guid, This->device, 0, &session);
2851 if(FAILED(hr))
2852 return hr;
2854 wrapper = AudioSessionWrapper_Create(NULL);
2855 if(!wrapper)
2856 return E_OUTOFMEMORY;
2858 wrapper->session = session;
2860 *out = &wrapper->ISimpleAudioVolume_iface;
2862 return S_OK;
2865 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2866 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2868 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2869 FIXME("(%p)->(%p) - stub\n", This, out);
2870 return E_NOTIMPL;
2873 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2874 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2876 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2877 FIXME("(%p)->(%p) - stub\n", This, notification);
2878 return E_NOTIMPL;
2881 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2882 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2884 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2885 FIXME("(%p)->(%p) - stub\n", This, notification);
2886 return E_NOTIMPL;
2889 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2890 IAudioSessionManager2 *iface, const WCHAR *session_id,
2891 IAudioVolumeDuckNotification *notification)
2893 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2894 FIXME("(%p)->(%p) - stub\n", This, notification);
2895 return E_NOTIMPL;
2898 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2899 IAudioSessionManager2 *iface,
2900 IAudioVolumeDuckNotification *notification)
2902 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2903 FIXME("(%p)->(%p) - stub\n", This, notification);
2904 return E_NOTIMPL;
2907 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2909 AudioSessionManager_QueryInterface,
2910 AudioSessionManager_AddRef,
2911 AudioSessionManager_Release,
2912 AudioSessionManager_GetAudioSessionControl,
2913 AudioSessionManager_GetSimpleAudioVolume,
2914 AudioSessionManager_GetSessionEnumerator,
2915 AudioSessionManager_RegisterSessionNotification,
2916 AudioSessionManager_UnregisterSessionNotification,
2917 AudioSessionManager_RegisterDuckNotification,
2918 AudioSessionManager_UnregisterDuckNotification
2921 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2922 IAudioSessionManager2 **out)
2924 SessionMgr *This;
2926 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2927 if(!This)
2928 return E_OUTOFMEMORY;
2930 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2931 This->device = device;
2932 This->ref = 1;
2934 *out = &This->IAudioSessionManager2_iface;
2936 return S_OK;