wineoss: Get rid of %ll printf formats.
[wine/multimedia.git] / dlls / wineoss.drv / mmdevdrv.c
blobff21cd69cc78cb939b5556fd81c4a7d1fe0fe143
1 /*
2 * Copyright 2011 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
20 #define COBJMACROS
21 #include "config.h"
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/ioctl.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <math.h>
35 #include <sys/soundcard.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winreg.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
45 #include "ole2.h"
46 #include "mmdeviceapi.h"
47 #include "devpkey.h"
48 #include "dshow.h"
49 #include "dsound.h"
50 #include "endpointvolume.h"
52 #include "initguid.h"
53 #include "audiopolicy.h"
54 #include "audioclient.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(oss);
58 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
60 static const REFERENCE_TIME DefaultPeriod = 200000;
61 static const REFERENCE_TIME MinimumPeriod = 100000;
63 struct ACImpl;
64 typedef struct ACImpl ACImpl;
66 typedef struct _AudioSession {
67 GUID guid;
68 struct list clients;
70 EDataFlow dataflow;
72 struct list entry;
73 } AudioSession;
75 typedef struct _AudioSessionWrapper {
76 IAudioSessionControl2 IAudioSessionControl2_iface;
78 LONG ref;
80 ACImpl *client;
81 AudioSession *session;
82 } AudioSessionWrapper;
84 struct ACImpl {
85 IAudioClient IAudioClient_iface;
86 IAudioRenderClient IAudioRenderClient_iface;
87 IAudioCaptureClient IAudioCaptureClient_iface;
88 ISimpleAudioVolume ISimpleAudioVolume_iface;
89 IAudioClock IAudioClock_iface;
90 IAudioClock2 IAudioClock2_iface;
92 LONG ref;
94 IMMDevice *parent;
96 WAVEFORMATEX *fmt;
98 EDataFlow dataflow;
99 DWORD flags;
100 AUDCLNT_SHAREMODE share;
101 HANDLE event;
103 int fd;
104 oss_audioinfo ai;
106 BOOL initted, playing;
107 UINT64 written_frames, held_frames, tmp_buffer_frames, inbuf_frames;
108 UINT32 period_us, bufsize_frames;
109 UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
111 BYTE *local_buffer, *tmp_buffer;
112 int buf_state;
113 HANDLE timer;
115 CRITICAL_SECTION lock;
117 AudioSession *session;
118 AudioSessionWrapper *session_wrapper;
120 struct list entry;
123 enum BufferStates {
124 NOT_LOCKED = 0,
125 LOCKED_NORMAL, /* public buffer piece is from local_buffer */
126 LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
129 static HANDLE g_timer_q;
131 static CRITICAL_SECTION g_sessions_lock;
132 static struct list g_sessions = LIST_INIT(g_sessions);
134 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
136 static const IAudioClientVtbl AudioClient_Vtbl;
137 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
138 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
139 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
140 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
141 static const IAudioClockVtbl AudioClock_Vtbl;
142 static const IAudioClock2Vtbl AudioClock2_Vtbl;
144 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
146 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
149 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
151 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
154 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
156 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
159 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
161 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
164 static inline ACImpl *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
166 return CONTAINING_RECORD(iface, ACImpl, ISimpleAudioVolume_iface);
169 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
171 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
174 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
176 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
179 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
181 if(reason == DLL_PROCESS_ATTACH){
182 g_timer_q = CreateTimerQueue();
183 if(!g_timer_q)
184 return FALSE;
186 InitializeCriticalSection(&g_sessions_lock);
189 return TRUE;
192 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
193 UINT *num, UINT *def_index)
195 int i, mixer_fd;
196 oss_sysinfo sysinfo;
197 static int print_once = 0;
199 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
201 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
202 if(mixer_fd < 0){
203 ERR("OSS /dev/mixer doesn't seem to exist\n");
204 return AUDCLNT_E_SERVICE_NOT_RUNNING;
207 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
208 close(mixer_fd);
210 if(errno == EINVAL){
211 ERR("OSS version too old, need at least OSSv4\n");
212 return AUDCLNT_E_SERVICE_NOT_RUNNING;
215 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
216 return E_FAIL;
219 if(!print_once){
220 TRACE("OSS sysinfo:\n");
221 TRACE("product: %s\n", sysinfo.product);
222 TRACE("version: %s\n", sysinfo.version);
223 TRACE("versionnum: %x\n", sysinfo.versionnum);
224 TRACE("numaudios: %d\n", sysinfo.numaudios);
225 TRACE("nummixers: %d\n", sysinfo.nummixers);
226 TRACE("numcards: %d\n", sysinfo.numcards);
227 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
228 print_once = 1;
231 if(sysinfo.numaudios <= 0){
232 WARN("No audio devices!\n");
233 close(mixer_fd);
234 return AUDCLNT_E_SERVICE_NOT_RUNNING;
237 *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
238 *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
240 *num = 0;
241 *def_index = -1;
242 for(i = 0; i < sysinfo.numaudios; ++i){
243 oss_audioinfo ai = {0};
245 ai.dev = i;
246 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
247 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
248 strerror(errno));
249 continue;
252 if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
253 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
254 size_t len;
256 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
257 strlen(ai.devnode) + 1);
258 if(!(*keys)[*num]){
259 for(i = 0; i < *num; ++i){
260 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
261 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
263 HeapFree(GetProcessHeap(), 0, *ids);
264 HeapFree(GetProcessHeap(), 0, *keys);
265 close(mixer_fd);
266 return E_OUTOFMEMORY;
268 strcpy((*keys)[*num], ai.devnode);
270 len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
271 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
272 len * sizeof(WCHAR));
273 if(!(*ids)[*num]){
274 HeapFree(GetProcessHeap(), 0, (*keys)[*num]);
275 for(i = 0; i < *num; ++i){
276 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
277 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
279 HeapFree(GetProcessHeap(), 0, *ids);
280 HeapFree(GetProcessHeap(), 0, *keys);
281 close(mixer_fd);
282 return E_OUTOFMEMORY;
284 MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
285 (*ids)[*num], len);
287 if(ai.caps & PCM_CAP_DEFAULT)
288 *def_index = *num;
290 (*num)++;
294 if(*def_index == -1)
295 *def_index = 0;
297 close(mixer_fd);
299 return S_OK;
302 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
303 EDataFlow dataflow, IAudioClient **out)
305 ACImpl *This;
307 TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
309 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
310 if(!This)
311 return E_OUTOFMEMORY;
313 if(dataflow == eRender)
314 This->fd = open(devnode, O_WRONLY, 0);
315 else if(dataflow == eCapture)
316 This->fd = open(devnode, O_RDONLY, 0);
317 else{
318 HeapFree(GetProcessHeap(), 0, This);
319 return E_INVALIDARG;
321 if(This->fd < 0){
322 ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
323 strerror(errno));
324 HeapFree(GetProcessHeap(), 0, This);
325 return AUDCLNT_E_DEVICE_INVALIDATED;
328 This->dataflow = dataflow;
330 This->ai.dev = -1;
331 if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
332 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode,
333 errno, strerror(errno));
334 close(This->fd);
335 HeapFree(GetProcessHeap(), 0, This);
336 return E_FAIL;
339 TRACE("OSS audioinfo:\n");
340 TRACE("devnode: %s\n", This->ai.devnode);
341 TRACE("name: %s\n", This->ai.name);
342 TRACE("busy: %x\n", This->ai.busy);
343 TRACE("caps: %x\n", This->ai.caps);
344 TRACE("iformats: %x\n", This->ai.iformats);
345 TRACE("oformats: %x\n", This->ai.oformats);
346 TRACE("enabled: %d\n", This->ai.enabled);
347 TRACE("min_rate: %d\n", This->ai.min_rate);
348 TRACE("max_rate: %d\n", This->ai.max_rate);
349 TRACE("min_channels: %d\n", This->ai.min_channels);
350 TRACE("max_channels: %d\n", This->ai.max_channels);
352 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
353 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
354 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
355 This->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
356 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
357 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
359 InitializeCriticalSection(&This->lock);
361 This->parent = dev;
362 IMMDevice_AddRef(This->parent);
364 IAudioClient_AddRef(&This->IAudioClient_iface);
366 *out = &This->IAudioClient_iface;
368 return S_OK;
371 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
372 REFIID riid, void **ppv)
374 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
376 if(!ppv)
377 return E_POINTER;
378 *ppv = NULL;
379 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
380 *ppv = iface;
381 if(*ppv){
382 IUnknown_AddRef((IUnknown*)*ppv);
383 return S_OK;
385 WARN("Unknown interface %s\n", debugstr_guid(riid));
386 return E_NOINTERFACE;
389 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
391 ACImpl *This = impl_from_IAudioClient(iface);
392 ULONG ref;
393 ref = InterlockedIncrement(&This->ref);
394 TRACE("(%p) Refcount now %u\n", This, ref);
395 return ref;
398 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
400 ACImpl *This = impl_from_IAudioClient(iface);
401 ULONG ref;
402 ref = InterlockedDecrement(&This->ref);
403 TRACE("(%p) Refcount now %u\n", This, ref);
404 if(!ref){
405 IAudioClient_Stop(iface);
406 IMMDevice_Release(This->parent);
407 DeleteCriticalSection(&This->lock);
408 close(This->fd);
409 if(This->initted){
410 EnterCriticalSection(&g_sessions_lock);
411 list_remove(&This->entry);
412 if(list_empty(&This->session->clients)){
413 list_remove(&This->session->entry);
414 HeapFree(GetProcessHeap(), 0, This->session);
416 LeaveCriticalSection(&g_sessions_lock);
418 HeapFree(GetProcessHeap(), 0, This->local_buffer);
419 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
420 CoTaskMemFree(This->fmt);
421 HeapFree(GetProcessHeap(), 0, This);
423 return ref;
426 static void dump_fmt(const WAVEFORMATEX *fmt)
428 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
429 switch(fmt->wFormatTag){
430 case WAVE_FORMAT_PCM:
431 TRACE("WAVE_FORMAT_PCM");
432 break;
433 case WAVE_FORMAT_IEEE_FLOAT:
434 TRACE("WAVE_FORMAT_IEEE_FLOAT");
435 break;
436 case WAVE_FORMAT_EXTENSIBLE:
437 TRACE("WAVE_FORMAT_EXTENSIBLE");
438 break;
439 default:
440 TRACE("Unknown");
441 break;
443 TRACE(")\n");
445 TRACE("nChannels: %u\n", fmt->nChannels);
446 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
447 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
448 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
449 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
450 TRACE("cbSize: %u\n", fmt->cbSize);
452 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
453 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
454 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
455 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
456 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
460 static DWORD get_channel_mask(unsigned int channels)
462 switch(channels){
463 case 0:
464 return 0;
465 case 1:
466 return SPEAKER_FRONT_CENTER;
467 case 2:
468 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
469 case 3:
470 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
471 SPEAKER_LOW_FREQUENCY;
472 case 4:
473 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
474 SPEAKER_BACK_RIGHT;
475 case 5:
476 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
477 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
478 case 6:
479 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
480 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
481 case 7:
482 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
483 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
484 SPEAKER_BACK_CENTER;
486 FIXME("Unknown speaker configuration: %u\n", channels);
487 return 0;
490 static int get_oss_format(const WAVEFORMATEX *fmt)
492 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
494 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
495 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
496 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
497 switch(fmt->wBitsPerSample){
498 case 8:
499 return AFMT_U8;
500 case 16:
501 return AFMT_S16_LE;
502 case 24:
503 return AFMT_S24_PACKED;
504 case 32:
505 return AFMT_S32_LE;
507 return -1;
510 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
511 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
512 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
513 if(fmt->wBitsPerSample != 32)
514 return -1;
516 return AFMT_FLOAT;
519 return -1;
522 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
524 WAVEFORMATEX *ret;
525 size_t size;
527 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
528 size = sizeof(WAVEFORMATEXTENSIBLE);
529 else
530 size = sizeof(WAVEFORMATEX);
532 ret = CoTaskMemAlloc(size);
533 if(!ret)
534 return NULL;
536 memcpy(ret, fmt, size);
538 ret->cbSize = size - sizeof(WAVEFORMATEX);
540 return ret;
543 static HRESULT setup_oss_device(ACImpl *This, const WAVEFORMATEX *fmt,
544 WAVEFORMATEX **out)
546 int tmp, oss_format;
547 double tenth;
548 HRESULT ret = S_OK;
549 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
550 WAVEFORMATEX *closest = NULL;
552 tmp = oss_format = get_oss_format(fmt);
553 if(oss_format < 0)
554 return AUDCLNT_E_UNSUPPORTED_FORMAT;
555 if(ioctl(This->fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
556 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
557 return E_FAIL;
559 if(tmp != oss_format){
560 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
561 return AUDCLNT_E_UNSUPPORTED_FORMAT;
564 closest = clone_format(fmt);
566 tmp = fmt->nSamplesPerSec;
567 if(ioctl(This->fd, SNDCTL_DSP_SPEED, &tmp) < 0){
568 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
569 CoTaskMemFree(closest);
570 return E_FAIL;
572 tenth = fmt->nSamplesPerSec * 0.1;
573 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
574 ret = S_FALSE;
575 closest->nSamplesPerSec = tmp;
578 tmp = fmt->nChannels;
579 if(ioctl(This->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
580 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
581 CoTaskMemFree(closest);
582 return E_FAIL;
584 if(tmp != fmt->nChannels){
585 ret = S_FALSE;
586 closest->nChannels = tmp;
589 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
590 DWORD mask = get_channel_mask(closest->nChannels);
592 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
594 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
595 fmtex->dwChannelMask != mask)
596 ret = S_FALSE;
599 if(ret == S_OK || !out){
600 CoTaskMemFree( closest);
601 if(out)
602 *out = NULL;
603 }else{
604 closest->nBlockAlign =
605 closest->nChannels * closest->wBitsPerSample / 8;
606 closest->nAvgBytesPerSec =
607 closest->nBlockAlign * closest->nSamplesPerSec;
608 *out = closest;
611 TRACE("returning: %08x\n", ret);
612 return ret;
615 static AudioSession *create_session(const GUID *guid, EDataFlow flow)
617 AudioSession *ret;
619 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
620 if(!ret)
621 return NULL;
623 memcpy(&ret->guid, guid, sizeof(GUID));
625 ret->dataflow = flow;
627 list_init(&ret->clients);
629 list_add_head(&g_sessions, &ret->entry);
631 return ret;
634 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
635 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
636 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
637 const GUID *sessionguid)
639 ACImpl *This = impl_from_IAudioClient(iface);
640 int mask;
641 HRESULT hr;
643 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
644 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
646 if(!fmt)
647 return E_POINTER;
649 dump_fmt(fmt);
651 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
652 return AUDCLNT_E_NOT_INITIALIZED;
654 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
655 AUDCLNT_STREAMFLAGS_LOOPBACK |
656 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
657 AUDCLNT_STREAMFLAGS_NOPERSIST |
658 AUDCLNT_STREAMFLAGS_RATEADJUST |
659 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
660 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
661 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
662 TRACE("Unknown flags: %08x\n", flags);
663 return E_INVALIDARG;
666 EnterCriticalSection(&This->lock);
668 if(This->initted){
669 LeaveCriticalSection(&This->lock);
670 return AUDCLNT_E_ALREADY_INITIALIZED;
673 hr = setup_oss_device(This, fmt, NULL);
674 if(hr == S_FALSE){
675 LeaveCriticalSection(&This->lock);
676 return AUDCLNT_E_UNSUPPORTED_FORMAT;
678 if(FAILED(hr)){
679 LeaveCriticalSection(&This->lock);
680 return hr;
683 mask = 0;
684 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
685 LeaveCriticalSection(&This->lock);
686 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
687 return E_FAIL;
690 mask = (100 << 8) | 100;
691 if(ioctl(This->fd, SNDCTL_DSP_SETPLAYVOL, &mask) < 0)
692 WARN("SETPLAYVOL failed: %d (%s)\n", errno, strerror(errno));
694 This->fmt = clone_format(fmt);
695 if(!This->fmt){
696 LeaveCriticalSection(&This->lock);
697 return E_OUTOFMEMORY;
700 if(period)
701 This->period_us = period / 10;
702 else
703 This->period_us = DefaultPeriod / 10;
705 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
706 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
707 This->bufsize_frames * fmt->nBlockAlign);
708 if(!This->local_buffer){
709 CoTaskMemFree(This->fmt);
710 This->fmt = NULL;
711 LeaveCriticalSection(&This->lock);
712 return E_OUTOFMEMORY;
715 This->share = mode;
716 This->flags = flags;
718 EnterCriticalSection(&g_sessions_lock);
720 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
721 This->session = create_session(&GUID_NULL, This->dataflow);
722 if(!This->session){
723 CoTaskMemFree(This->fmt);
724 This->fmt = NULL;
725 LeaveCriticalSection(&g_sessions_lock);
726 return E_OUTOFMEMORY;
728 }else{
729 AudioSession *session;
731 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry)
732 if(IsEqualGUID(sessionguid, &session->guid) &&
733 This->dataflow == session->dataflow)
734 This->session = session;
736 if(!This->session){
737 This->session = create_session(sessionguid, This->dataflow);
738 if(!This->session){
739 CoTaskMemFree(This->fmt);
740 This->fmt = NULL;
741 LeaveCriticalSection(&g_sessions_lock);
742 return E_OUTOFMEMORY;
747 list_add_tail(&This->session->clients, &This->entry);
749 LeaveCriticalSection(&g_sessions_lock);
751 This->initted = TRUE;
753 LeaveCriticalSection(&This->lock);
755 return S_OK;
758 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
759 UINT32 *frames)
761 ACImpl *This = impl_from_IAudioClient(iface);
763 TRACE("(%p)->(%p)\n", This, frames);
765 if(!frames)
766 return E_POINTER;
768 EnterCriticalSection(&This->lock);
770 if(!This->initted){
771 LeaveCriticalSection(&This->lock);
772 return AUDCLNT_E_NOT_INITIALIZED;
775 *frames = This->bufsize_frames;
777 LeaveCriticalSection(&This->lock);
779 return S_OK;
782 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
783 REFERENCE_TIME *latency)
785 ACImpl *This = impl_from_IAudioClient(iface);
787 TRACE("(%p)->(%p)\n", This, latency);
789 if(!latency)
790 return E_POINTER;
792 EnterCriticalSection(&This->lock);
794 if(!This->initted){
795 LeaveCriticalSection(&This->lock);
796 return AUDCLNT_E_NOT_INITIALIZED;
799 if(This->dataflow == eRender){
800 int delay_bytes;
801 double delay_s;
803 if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
804 LeaveCriticalSection(&This->lock);
805 WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
806 return E_FAIL;
809 delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
810 This->fmt->nBlockAlign);
812 *latency = delay_s * 10000000;
813 }else
814 *latency = 10000; /* OSS doesn't provide input latency */
816 LeaveCriticalSection(&This->lock);
818 return S_OK;
821 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
822 UINT32 *numpad)
824 ACImpl *This = impl_from_IAudioClient(iface);
825 audio_buf_info bi;
827 TRACE("(%p)->(%p)\n", This, numpad);
829 if(!numpad)
830 return E_POINTER;
832 EnterCriticalSection(&This->lock);
834 if(!This->initted){
835 LeaveCriticalSection(&This->lock);
836 return AUDCLNT_E_NOT_INITIALIZED;
839 if(This->dataflow == eRender){
840 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
841 LeaveCriticalSection(&This->lock);
842 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
843 return E_FAIL;
846 *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
847 This->fmt->nBlockAlign;
849 /* when the OSS buffer has less than one fragment of data, including
850 * no data, it often reports it as some non-zero portion of a
851 * fragment. when it has more than one fragment of data, it reports
852 * it as some multiple of that portion of the fragment size.
854 * so, we have to do some ugly workarounds to report the timing
855 * as accurately as possible */
856 if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
857 *numpad = This->inbuf_frames;
858 This->inbuf_frames = 0;
859 }else{
860 if(*numpad < This->inbuf_frames)
861 This->inbuf_frames = *numpad;
862 else
863 *numpad = This->inbuf_frames;
865 }else if(This->dataflow == eCapture){
866 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
867 LeaveCriticalSection(&This->lock);
868 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
869 return E_FAIL;
872 if(bi.bytes <= bi.fragsize)
873 *numpad = 0;
874 else
875 *numpad = bi.bytes / This->fmt->nBlockAlign;
876 }else{
877 LeaveCriticalSection(&This->lock);
878 return E_UNEXPECTED;
881 *numpad += This->held_frames;
883 LeaveCriticalSection(&This->lock);
885 return S_OK;
888 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
889 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
890 WAVEFORMATEX **outpwfx)
892 ACImpl *This = impl_from_IAudioClient(iface);
893 HRESULT ret;
895 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
897 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
898 return E_POINTER;
900 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
901 return E_INVALIDARG;
903 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
904 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
905 return E_INVALIDARG;
907 dump_fmt(pwfx);
909 EnterCriticalSection(&This->lock);
911 ret = setup_oss_device(This, pwfx, outpwfx);
913 LeaveCriticalSection(&This->lock);
915 return ret;
918 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
919 WAVEFORMATEX **pwfx)
921 ACImpl *This = impl_from_IAudioClient(iface);
922 WAVEFORMATEXTENSIBLE *fmt;
923 int formats;
925 TRACE("(%p)->(%p)\n", This, pwfx);
927 if(!pwfx)
928 return E_POINTER;
930 *pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
931 if(!*pwfx)
932 return E_OUTOFMEMORY;
934 fmt = (WAVEFORMATEXTENSIBLE*)*pwfx;
936 if(This->dataflow == eRender)
937 formats = This->ai.oformats;
938 else if(This->dataflow == eCapture)
939 formats = This->ai.iformats;
940 else
941 return E_UNEXPECTED;
943 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
944 if(formats & AFMT_S16_LE){
945 fmt->Format.wBitsPerSample = 16;
946 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
947 }else if(formats & AFMT_FLOAT){
948 fmt->Format.wBitsPerSample = 32;
949 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
950 }else if(formats & AFMT_U8){
951 fmt->Format.wBitsPerSample = 8;
952 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
953 }else if(formats & AFMT_S32_LE){
954 fmt->Format.wBitsPerSample = 32;
955 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
956 }else if(formats & AFMT_S24_PACKED){
957 fmt->Format.wBitsPerSample = 24;
958 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
959 }else{
960 ERR("Didn't recognize any available OSS formats: %x\n", formats);
961 return E_FAIL;
964 fmt->Format.nChannels = This->ai.max_channels;
965 fmt->Format.nSamplesPerSec = This->ai.max_rate;
966 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
968 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
969 fmt->Format.nChannels) / 8;
970 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
971 fmt->Format.nBlockAlign;
973 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
974 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
976 dump_fmt(*pwfx);
978 return S_OK;
981 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
982 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
984 ACImpl *This = impl_from_IAudioClient(iface);
986 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
988 if(!defperiod && !minperiod)
989 return E_POINTER;
991 EnterCriticalSection(&This->lock);
993 if(defperiod)
994 *defperiod = DefaultPeriod;
995 if(minperiod)
996 *minperiod = MinimumPeriod;
998 LeaveCriticalSection(&This->lock);
1000 return S_OK;
1003 static void oss_write_data(ACImpl *This)
1005 ssize_t written;
1006 UINT32 written_frames;
1007 size_t to_write;
1008 BYTE *buf =
1009 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1011 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1012 to_write = This->bufsize_frames - This->lcl_offs_frames;
1013 else
1014 to_write = This->held_frames;
1016 written = write(This->fd, buf, to_write * This->fmt->nBlockAlign);
1017 if(written < 0){
1018 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1019 return;
1021 written_frames = written / This->fmt->nBlockAlign;
1023 This->lcl_offs_frames += written_frames;
1024 This->lcl_offs_frames %= This->bufsize_frames;
1025 This->held_frames -= written_frames;
1026 This->inbuf_frames += written_frames;
1028 if(written_frames < to_write){
1029 /* OSS buffer probably full */
1030 return;
1033 if(This->held_frames){
1034 /* wrapped and have some data back at the start to write */
1035 written = write(This->fd, This->local_buffer,
1036 This->held_frames * This->fmt->nBlockAlign);
1037 if(written < 0){
1038 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1039 return;
1041 written_frames = written / This->fmt->nBlockAlign;
1043 This->lcl_offs_frames += written_frames;
1044 This->lcl_offs_frames %= This->bufsize_frames;
1045 This->held_frames -= written_frames;
1046 This->inbuf_frames += written_frames;
1050 static void oss_read_data(ACImpl *This)
1052 UINT64 pos, readable;
1053 audio_buf_info bi;
1054 ssize_t nread;
1056 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1057 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1058 return;
1061 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1062 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1064 if(bi.bytes < readable)
1065 readable = bi.bytes;
1067 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1068 readable);
1069 if(nread < 0){
1070 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1071 return;
1074 This->held_frames += nread / This->fmt->nBlockAlign;
1076 if(This->held_frames > This->bufsize_frames){
1077 WARN("Overflow of unread data\n");
1078 This->lcl_offs_frames += This->held_frames;
1079 This->lcl_offs_frames %= This->bufsize_frames;
1080 This->held_frames = This->bufsize_frames;
1084 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1086 ACImpl *This = user;
1088 EnterCriticalSection(&This->lock);
1090 if(This->dataflow == eRender)
1091 oss_write_data(This);
1092 else if(This->dataflow == eCapture)
1093 oss_read_data(This);
1095 if(This->event)
1096 SetEvent(This->event);
1098 LeaveCriticalSection(&This->lock);
1101 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1103 ACImpl *This = impl_from_IAudioClient(iface);
1104 int mask;
1106 TRACE("(%p)\n", This);
1108 EnterCriticalSection(&This->lock);
1110 if(!This->initted){
1111 LeaveCriticalSection(&This->lock);
1112 return AUDCLNT_E_NOT_INITIALIZED;
1115 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1116 LeaveCriticalSection(&This->lock);
1117 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1120 if(This->playing){
1121 LeaveCriticalSection(&This->lock);
1122 return AUDCLNT_E_NOT_STOPPED;
1125 if(This->dataflow == eRender)
1126 mask = PCM_ENABLE_OUTPUT;
1127 else if(This->dataflow == eCapture)
1128 mask = PCM_ENABLE_INPUT;
1129 else{
1130 LeaveCriticalSection(&This->lock);
1131 return E_UNEXPECTED;
1134 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1135 LeaveCriticalSection(&This->lock);
1136 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1137 return E_FAIL;
1140 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1141 oss_period_callback, This, 0, This->period_us / 1000,
1142 WT_EXECUTEINTIMERTHREAD))
1143 ERR("Unable to create period timer: %u\n", GetLastError());
1145 This->playing = TRUE;
1147 LeaveCriticalSection(&This->lock);
1149 return S_OK;
1152 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1154 ACImpl *This = impl_from_IAudioClient(iface);
1155 int mask;
1157 TRACE("(%p)\n", This);
1159 EnterCriticalSection(&This->lock);
1161 if(!This->initted){
1162 LeaveCriticalSection(&This->lock);
1163 return AUDCLNT_E_NOT_INITIALIZED;
1166 if(!This->playing){
1167 LeaveCriticalSection(&This->lock);
1168 return S_FALSE;
1171 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1172 DeleteTimerQueueTimer(g_timer_q, This->timer,
1173 INVALID_HANDLE_VALUE);
1174 This->timer = NULL;
1177 if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1178 LeaveCriticalSection(&This->lock);
1179 WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1180 return E_FAIL;
1183 mask = 0;
1184 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1185 LeaveCriticalSection(&This->lock);
1186 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1187 return E_FAIL;
1190 This->playing = FALSE;
1192 LeaveCriticalSection(&This->lock);
1194 return S_OK;
1197 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1199 ACImpl *This = impl_from_IAudioClient(iface);
1201 TRACE("(%p)\n", This);
1203 EnterCriticalSection(&This->lock);
1205 if(!This->initted){
1206 LeaveCriticalSection(&This->lock);
1207 return AUDCLNT_E_NOT_INITIALIZED;
1210 if(This->playing){
1211 LeaveCriticalSection(&This->lock);
1212 return AUDCLNT_E_NOT_STOPPED;
1215 This->written_frames = 0;
1216 This->inbuf_frames = 0;
1217 This->held_frames = 0;
1219 if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1220 WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1222 LeaveCriticalSection(&This->lock);
1224 return S_OK;
1227 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1228 HANDLE event)
1230 ACImpl *This = impl_from_IAudioClient(iface);
1232 TRACE("(%p)->(%p)\n", This, event);
1234 if(!event)
1235 return E_INVALIDARG;
1237 EnterCriticalSection(&This->lock);
1239 if(!This->initted){
1240 LeaveCriticalSection(&This->lock);
1241 return AUDCLNT_E_NOT_INITIALIZED;
1244 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1245 LeaveCriticalSection(&This->lock);
1246 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1249 This->event = event;
1251 LeaveCriticalSection(&This->lock);
1253 return S_OK;
1256 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1257 void **ppv)
1259 ACImpl *This = impl_from_IAudioClient(iface);
1261 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1263 if(!ppv)
1264 return E_POINTER;
1265 *ppv = NULL;
1267 EnterCriticalSection(&This->lock);
1269 if(!This->initted){
1270 LeaveCriticalSection(&This->lock);
1271 return AUDCLNT_E_NOT_INITIALIZED;
1274 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1275 if(This->dataflow != eRender){
1276 LeaveCriticalSection(&This->lock);
1277 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1279 *ppv = &This->IAudioRenderClient_iface;
1280 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1281 if(This->dataflow != eCapture){
1282 LeaveCriticalSection(&This->lock);
1283 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1285 *ppv = &This->IAudioCaptureClient_iface;
1286 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1287 if(!This->session_wrapper){
1288 This->session_wrapper = AudioSessionWrapper_Create(This);
1289 if(!This->session_wrapper){
1290 LeaveCriticalSection(&This->lock);
1291 return E_OUTOFMEMORY;
1295 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1296 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1297 *ppv = &This->ISimpleAudioVolume_iface;
1298 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1299 *ppv = &This->IAudioClock_iface;
1302 if(*ppv){
1303 IUnknown_AddRef((IUnknown*)*ppv);
1304 LeaveCriticalSection(&This->lock);
1305 return S_OK;
1308 LeaveCriticalSection(&This->lock);
1310 FIXME("stub %s\n", debugstr_guid(riid));
1311 return E_NOINTERFACE;
1314 static const IAudioClientVtbl AudioClient_Vtbl =
1316 AudioClient_QueryInterface,
1317 AudioClient_AddRef,
1318 AudioClient_Release,
1319 AudioClient_Initialize,
1320 AudioClient_GetBufferSize,
1321 AudioClient_GetStreamLatency,
1322 AudioClient_GetCurrentPadding,
1323 AudioClient_IsFormatSupported,
1324 AudioClient_GetMixFormat,
1325 AudioClient_GetDevicePeriod,
1326 AudioClient_Start,
1327 AudioClient_Stop,
1328 AudioClient_Reset,
1329 AudioClient_SetEventHandle,
1330 AudioClient_GetService
1333 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1334 IAudioRenderClient *iface, REFIID riid, void **ppv)
1336 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1338 if(!ppv)
1339 return E_POINTER;
1340 *ppv = NULL;
1342 if(IsEqualIID(riid, &IID_IUnknown) ||
1343 IsEqualIID(riid, &IID_IAudioRenderClient))
1344 *ppv = iface;
1345 if(*ppv){
1346 IUnknown_AddRef((IUnknown*)*ppv);
1347 return S_OK;
1350 WARN("Unknown interface %s\n", debugstr_guid(riid));
1351 return E_NOINTERFACE;
1354 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1356 ACImpl *This = impl_from_IAudioRenderClient(iface);
1357 return AudioClient_AddRef(&This->IAudioClient_iface);
1360 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1362 ACImpl *This = impl_from_IAudioRenderClient(iface);
1363 return AudioClient_Release(&This->IAudioClient_iface);
1366 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1367 UINT32 frames, BYTE **data)
1369 ACImpl *This = impl_from_IAudioRenderClient(iface);
1370 UINT32 pad, write_pos;
1371 HRESULT hr;
1373 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1375 if(!data)
1376 return E_POINTER;
1378 EnterCriticalSection(&This->lock);
1380 if(This->buf_state != NOT_LOCKED){
1381 LeaveCriticalSection(&This->lock);
1382 return AUDCLNT_E_OUT_OF_ORDER;
1385 if(!frames){
1386 This->buf_state = LOCKED_NORMAL;
1387 LeaveCriticalSection(&This->lock);
1388 return S_OK;
1391 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1392 if(FAILED(hr)){
1393 LeaveCriticalSection(&This->lock);
1394 return hr;
1397 if(pad + frames > This->bufsize_frames){
1398 LeaveCriticalSection(&This->lock);
1399 return AUDCLNT_E_BUFFER_TOO_LARGE;
1402 write_pos =
1403 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1404 if(write_pos + frames > This->bufsize_frames){
1405 if(This->tmp_buffer_frames < frames){
1406 if(This->tmp_buffer)
1407 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1408 This->tmp_buffer, frames * This->fmt->nBlockAlign);
1409 else
1410 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1411 frames * This->fmt->nBlockAlign);
1412 if(!This->tmp_buffer){
1413 LeaveCriticalSection(&This->lock);
1414 return E_OUTOFMEMORY;
1416 This->tmp_buffer_frames = frames;
1418 *data = This->tmp_buffer;
1419 This->buf_state = LOCKED_WRAPPED;
1420 }else{
1421 *data = This->local_buffer +
1422 This->lcl_offs_frames * This->fmt->nBlockAlign;
1423 This->buf_state = LOCKED_NORMAL;
1426 LeaveCriticalSection(&This->lock);
1428 return S_OK;
1431 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
1433 UINT32 write_offs_frames =
1434 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1435 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1436 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1437 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1439 if(written_bytes < chunk_bytes){
1440 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1441 }else{
1442 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1443 memcpy(This->local_buffer, buffer + chunk_bytes,
1444 written_bytes - chunk_bytes);
1448 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1449 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1451 ACImpl *This = impl_from_IAudioRenderClient(iface);
1452 BYTE *buffer;
1453 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1455 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1457 EnterCriticalSection(&This->lock);
1459 if(This->buf_state == NOT_LOCKED || !written_frames){
1460 This->buf_state = NOT_LOCKED;
1461 LeaveCriticalSection(&This->lock);
1462 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1465 if(This->buf_state == LOCKED_NORMAL)
1466 buffer = This->local_buffer +
1467 This->lcl_offs_frames * This->fmt->nBlockAlign;
1468 else
1469 buffer = This->tmp_buffer;
1471 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1472 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1473 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1474 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1475 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1476 This->fmt->wBitsPerSample == 8)
1477 memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
1478 else
1479 memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
1482 if(This->held_frames){
1483 if(This->buf_state == LOCKED_WRAPPED)
1484 oss_wrap_buffer(This, buffer, written_bytes);
1486 This->held_frames += written_frames;
1487 }else{
1488 ssize_t w_bytes;
1489 UINT32 w_frames;
1491 w_bytes = write(This->fd, buffer,
1492 written_frames * This->fmt->nBlockAlign);
1493 if(w_bytes < 0){
1494 LeaveCriticalSection(&This->lock);
1495 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1496 return E_FAIL;
1498 w_frames = w_bytes / This->fmt->nBlockAlign;
1499 This->inbuf_frames += w_frames;
1501 if(w_frames < written_frames){
1502 if(This->buf_state == LOCKED_WRAPPED)
1503 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1504 written_frames - w_frames);
1506 This->held_frames = written_frames - w_frames;
1510 This->written_frames += written_frames;
1511 This->buf_state = NOT_LOCKED;
1513 LeaveCriticalSection(&This->lock);
1515 return S_OK;
1518 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1519 AudioRenderClient_QueryInterface,
1520 AudioRenderClient_AddRef,
1521 AudioRenderClient_Release,
1522 AudioRenderClient_GetBuffer,
1523 AudioRenderClient_ReleaseBuffer
1526 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1527 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1529 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1531 if(!ppv)
1532 return E_POINTER;
1533 *ppv = NULL;
1535 if(IsEqualIID(riid, &IID_IUnknown) ||
1536 IsEqualIID(riid, &IID_IAudioCaptureClient))
1537 *ppv = iface;
1538 if(*ppv){
1539 IUnknown_AddRef((IUnknown*)*ppv);
1540 return S_OK;
1543 WARN("Unknown interface %s\n", debugstr_guid(riid));
1544 return E_NOINTERFACE;
1547 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1549 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1550 return IAudioClient_AddRef(&This->IAudioClient_iface);
1553 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1555 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1556 return IAudioClient_Release(&This->IAudioClient_iface);
1559 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1560 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1561 UINT64 *qpcpos)
1563 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1564 HRESULT hr;
1566 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1567 devpos, qpcpos);
1569 if(!data || !frames || !flags)
1570 return E_POINTER;
1572 EnterCriticalSection(&This->lock);
1574 if(This->buf_state != NOT_LOCKED){
1575 LeaveCriticalSection(&This->lock);
1576 return AUDCLNT_E_OUT_OF_ORDER;
1579 hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1580 if(FAILED(hr)){
1581 LeaveCriticalSection(&This->lock);
1582 return hr;
1585 *flags = 0;
1587 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1588 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1589 if(This->tmp_buffer_frames < *frames){
1590 if(This->tmp_buffer)
1591 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1592 This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1593 else
1594 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1595 *frames * This->fmt->nBlockAlign);
1596 if(!This->tmp_buffer){
1597 LeaveCriticalSection(&This->lock);
1598 return E_OUTOFMEMORY;
1600 This->tmp_buffer_frames = *frames;
1603 *data = This->tmp_buffer;
1604 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1605 This->fmt->nBlockAlign;
1606 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1607 frames_bytes = *frames * This->fmt->nBlockAlign;
1608 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1609 memcpy(This->tmp_buffer, This->local_buffer,
1610 frames_bytes - chunk_bytes);
1611 }else
1612 *data = This->local_buffer +
1613 This->lcl_offs_frames * This->fmt->nBlockAlign;
1615 This->buf_state = LOCKED_NORMAL;
1617 if(devpos || qpcpos)
1618 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1620 LeaveCriticalSection(&This->lock);
1622 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1625 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1626 IAudioCaptureClient *iface, UINT32 done)
1628 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1630 TRACE("(%p)->(%u)\n", This, done);
1632 EnterCriticalSection(&This->lock);
1634 if(This->buf_state == NOT_LOCKED){
1635 LeaveCriticalSection(&This->lock);
1636 return AUDCLNT_E_OUT_OF_ORDER;
1639 This->held_frames -= done;
1640 This->lcl_offs_frames += done;
1641 This->lcl_offs_frames %= This->bufsize_frames;
1643 This->buf_state = NOT_LOCKED;
1645 LeaveCriticalSection(&This->lock);
1647 return S_OK;
1650 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1651 IAudioCaptureClient *iface, UINT32 *frames)
1653 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1655 TRACE("(%p)->(%p)\n", This, frames);
1657 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1660 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1662 AudioCaptureClient_QueryInterface,
1663 AudioCaptureClient_AddRef,
1664 AudioCaptureClient_Release,
1665 AudioCaptureClient_GetBuffer,
1666 AudioCaptureClient_ReleaseBuffer,
1667 AudioCaptureClient_GetNextPacketSize
1670 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1672 AudioSessionWrapper *ret;
1674 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1675 sizeof(AudioSessionWrapper));
1676 if(!ret)
1677 return NULL;
1679 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1681 ret->client = client;
1682 ret->session = client->session;
1683 AudioClient_AddRef(&client->IAudioClient_iface);
1685 return ret;
1688 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1689 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1691 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1693 if(!ppv)
1694 return E_POINTER;
1695 *ppv = NULL;
1697 if(IsEqualIID(riid, &IID_IUnknown) ||
1698 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1699 IsEqualIID(riid, &IID_IAudioSessionControl2))
1700 *ppv = iface;
1701 if(*ppv){
1702 IUnknown_AddRef((IUnknown*)*ppv);
1703 return S_OK;
1706 WARN("Unknown interface %s\n", debugstr_guid(riid));
1707 return E_NOINTERFACE;
1710 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1712 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1713 ULONG ref;
1714 ref = InterlockedIncrement(&This->ref);
1715 TRACE("(%p) Refcount now %u\n", This, ref);
1716 return ref;
1719 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1721 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1722 ULONG ref;
1723 ref = InterlockedDecrement(&This->ref);
1724 TRACE("(%p) Refcount now %u\n", This, ref);
1725 if(!ref){
1726 EnterCriticalSection(&This->client->lock);
1727 This->client->session_wrapper = NULL;
1728 LeaveCriticalSection(&This->client->lock);
1729 AudioClient_Release(&This->client->IAudioClient_iface);
1730 HeapFree(GetProcessHeap(), 0, This);
1732 return ref;
1735 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1736 AudioSessionState *state)
1738 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1739 ACImpl *client;
1741 TRACE("(%p)->(%p)\n", This, state);
1743 if(!state)
1744 return NULL_PTR_ERR;
1746 EnterCriticalSection(&g_sessions_lock);
1748 if(list_empty(&This->session->clients)){
1749 *state = AudioSessionStateExpired;
1750 LeaveCriticalSection(&g_sessions_lock);
1751 return S_OK;
1754 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1755 EnterCriticalSection(&client->lock);
1756 if(client->playing){
1757 *state = AudioSessionStateActive;
1758 LeaveCriticalSection(&client->lock);
1759 LeaveCriticalSection(&g_sessions_lock);
1760 return S_OK;
1762 LeaveCriticalSection(&client->lock);
1765 LeaveCriticalSection(&g_sessions_lock);
1767 *state = AudioSessionStateInactive;
1769 return S_OK;
1772 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1773 IAudioSessionControl2 *iface, WCHAR **name)
1775 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1777 FIXME("(%p)->(%p) - stub\n", This, name);
1779 return E_NOTIMPL;
1782 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1783 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1785 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1787 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1789 return E_NOTIMPL;
1792 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1793 IAudioSessionControl2 *iface, WCHAR **path)
1795 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1797 FIXME("(%p)->(%p) - stub\n", This, path);
1799 return E_NOTIMPL;
1802 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1803 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1805 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1807 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1809 return E_NOTIMPL;
1812 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1813 IAudioSessionControl2 *iface, GUID *group)
1815 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1817 FIXME("(%p)->(%p) - stub\n", This, group);
1819 return E_NOTIMPL;
1822 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1823 IAudioSessionControl2 *iface, GUID *group, const GUID *session)
1825 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1827 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1828 debugstr_guid(session));
1830 return E_NOTIMPL;
1833 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1834 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1836 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1838 FIXME("(%p)->(%p) - stub\n", This, events);
1840 return S_OK;
1843 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1844 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1846 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1848 FIXME("(%p)->(%p) - stub\n", This, events);
1850 return S_OK;
1853 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1854 IAudioSessionControl2 *iface, WCHAR **id)
1856 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1858 FIXME("(%p)->(%p) - stub\n", This, id);
1860 return E_NOTIMPL;
1863 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1864 IAudioSessionControl2 *iface, WCHAR **id)
1866 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1868 FIXME("(%p)->(%p) - stub\n", This, id);
1870 return E_NOTIMPL;
1873 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1874 IAudioSessionControl2 *iface, DWORD *pid)
1876 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1878 TRACE("(%p)->(%p)\n", This, pid);
1880 if(!pid)
1881 return E_POINTER;
1883 *pid = GetCurrentProcessId();
1885 return S_OK;
1888 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1889 IAudioSessionControl2 *iface)
1891 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1893 TRACE("(%p)\n", This);
1895 return S_FALSE;
1898 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1899 IAudioSessionControl2 *iface, BOOL optout)
1901 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1903 TRACE("(%p)->(%d)\n", This, optout);
1905 return S_OK;
1908 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1910 AudioSessionControl_QueryInterface,
1911 AudioSessionControl_AddRef,
1912 AudioSessionControl_Release,
1913 AudioSessionControl_GetState,
1914 AudioSessionControl_GetDisplayName,
1915 AudioSessionControl_SetDisplayName,
1916 AudioSessionControl_GetIconPath,
1917 AudioSessionControl_SetIconPath,
1918 AudioSessionControl_GetGroupingParam,
1919 AudioSessionControl_SetGroupingParam,
1920 AudioSessionControl_RegisterAudioSessionNotification,
1921 AudioSessionControl_UnregisterAudioSessionNotification,
1922 AudioSessionControl_GetSessionIdentifier,
1923 AudioSessionControl_GetSessionInstanceIdentifier,
1924 AudioSessionControl_GetProcessId,
1925 AudioSessionControl_IsSystemSoundsSession,
1926 AudioSessionControl_SetDuckingPreference
1929 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1930 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1932 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1934 if(!ppv)
1935 return E_POINTER;
1936 *ppv = NULL;
1938 if(IsEqualIID(riid, &IID_IUnknown) ||
1939 IsEqualIID(riid, &IID_ISimpleAudioVolume))
1940 *ppv = iface;
1941 if(*ppv){
1942 IUnknown_AddRef((IUnknown*)*ppv);
1943 return S_OK;
1946 WARN("Unknown interface %s\n", debugstr_guid(riid));
1947 return E_NOINTERFACE;
1950 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1952 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1953 return IAudioClient_AddRef(&This->IAudioClient_iface);
1956 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1958 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1959 return IAudioClient_Release(&This->IAudioClient_iface);
1962 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1963 ISimpleAudioVolume *iface, float level, const GUID *context)
1965 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1967 FIXME("(%p)->(%f, %p) - stub\n", This, level, context);
1969 return E_NOTIMPL;
1972 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1973 ISimpleAudioVolume *iface, float *level)
1975 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1977 FIXME("(%p)->(%p) - stub\n", This, level);
1979 return E_NOTIMPL;
1982 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1983 BOOL mute, const GUID *context)
1985 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1987 FIXME("(%p)->(%u, %p) - stub\n", This, mute, context);
1989 return E_NOTIMPL;
1992 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1993 BOOL *mute)
1995 ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1997 FIXME("(%p)->(%p) - stub\n", This, mute);
1999 return E_NOTIMPL;
2002 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2004 SimpleAudioVolume_QueryInterface,
2005 SimpleAudioVolume_AddRef,
2006 SimpleAudioVolume_Release,
2007 SimpleAudioVolume_SetMasterVolume,
2008 SimpleAudioVolume_GetMasterVolume,
2009 SimpleAudioVolume_SetMute,
2010 SimpleAudioVolume_GetMute
2013 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2014 REFIID riid, void **ppv)
2016 ACImpl *This = impl_from_IAudioClock(iface);
2018 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2020 if(!ppv)
2021 return E_POINTER;
2022 *ppv = NULL;
2024 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2025 *ppv = iface;
2026 else if(IsEqualIID(riid, &IID_IAudioClock2))
2027 *ppv = &This->IAudioClock2_iface;
2028 if(*ppv){
2029 IUnknown_AddRef((IUnknown*)*ppv);
2030 return S_OK;
2033 WARN("Unknown interface %s\n", debugstr_guid(riid));
2034 return E_NOINTERFACE;
2037 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2039 ACImpl *This = impl_from_IAudioClock(iface);
2040 return IAudioClient_AddRef(&This->IAudioClient_iface);
2043 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2045 ACImpl *This = impl_from_IAudioClock(iface);
2046 return IAudioClient_Release(&This->IAudioClient_iface);
2049 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2051 ACImpl *This = impl_from_IAudioClock(iface);
2053 TRACE("(%p)->(%p)\n", This, freq);
2055 *freq = This->fmt->nSamplesPerSec;
2057 return S_OK;
2060 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2061 UINT64 *qpctime)
2063 ACImpl *This = impl_from_IAudioClock(iface);
2064 UINT32 pad;
2065 HRESULT hr;
2067 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2069 if(!pos)
2070 return E_POINTER;
2072 EnterCriticalSection(&This->lock);
2074 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
2075 if(FAILED(hr)){
2076 LeaveCriticalSection(&This->lock);
2077 return hr;
2080 if(This->dataflow == eRender)
2081 *pos = This->written_frames - pad;
2082 else if(This->dataflow == eCapture)
2083 *pos = This->written_frames + pad;
2085 LeaveCriticalSection(&This->lock);
2087 if(qpctime){
2088 LARGE_INTEGER stamp, freq;
2089 QueryPerformanceCounter(&stamp);
2090 QueryPerformanceFrequency(&freq);
2091 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2094 return S_OK;
2097 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2098 DWORD *chars)
2100 ACImpl *This = impl_from_IAudioClock(iface);
2102 TRACE("(%p)->(%p)\n", This, chars);
2104 if(!chars)
2105 return E_POINTER;
2107 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2109 return S_OK;
2112 static const IAudioClockVtbl AudioClock_Vtbl =
2114 AudioClock_QueryInterface,
2115 AudioClock_AddRef,
2116 AudioClock_Release,
2117 AudioClock_GetFrequency,
2118 AudioClock_GetPosition,
2119 AudioClock_GetCharacteristics
2122 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2123 REFIID riid, void **ppv)
2125 ACImpl *This = impl_from_IAudioClock2(iface);
2126 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2129 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2131 ACImpl *This = impl_from_IAudioClock2(iface);
2132 return IAudioClient_AddRef(&This->IAudioClient_iface);
2135 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2137 ACImpl *This = impl_from_IAudioClock2(iface);
2138 return IAudioClient_Release(&This->IAudioClient_iface);
2141 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2142 UINT64 *pos, UINT64 *qpctime)
2144 ACImpl *This = impl_from_IAudioClock2(iface);
2146 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2148 return E_NOTIMPL;
2151 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2153 AudioClock2_QueryInterface,
2154 AudioClock2_AddRef,
2155 AudioClock2_Release,
2156 AudioClock2_GetDevicePosition