kernel32: Remove a no longer needed todo_wine.
[wine.git] / dlls / wineoss.drv / mmdevdrv.c
blob8bfb768c471d49691d36cf3ebaf3a723d28a5265
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"
51 #include "initguid.h"
52 #include "endpointvolume.h"
53 #include "audiopolicy.h"
54 #include "audioclient.h"
57 /* Some implementations of OSS, such as FreeBSD older than 9.0, lack
58 SNDCTL_DSP_HALT which is just a synonym for the older SNDCTL_DSP_RESET. */
59 #ifndef SNDCTL_DSP_HALT
60 #define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
61 #endif
63 WINE_DEFAULT_DEBUG_CHANNEL(oss);
65 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
67 static const REFERENCE_TIME DefaultPeriod = 200000;
68 static const REFERENCE_TIME MinimumPeriod = 100000;
70 struct ACImpl;
71 typedef struct ACImpl ACImpl;
73 typedef struct _AudioSession {
74 GUID guid;
75 struct list clients;
77 IMMDevice *device;
79 float master_vol;
80 UINT32 channel_count;
81 float *channel_vols;
82 BOOL mute;
84 CRITICAL_SECTION lock;
86 struct list entry;
87 } AudioSession;
89 typedef struct _AudioSessionWrapper {
90 IAudioSessionControl2 IAudioSessionControl2_iface;
91 IChannelAudioVolume IChannelAudioVolume_iface;
92 ISimpleAudioVolume ISimpleAudioVolume_iface;
94 LONG ref;
96 ACImpl *client;
97 AudioSession *session;
98 } AudioSessionWrapper;
100 struct ACImpl {
101 IAudioClient IAudioClient_iface;
102 IAudioRenderClient IAudioRenderClient_iface;
103 IAudioCaptureClient IAudioCaptureClient_iface;
104 IAudioClock IAudioClock_iface;
105 IAudioClock2 IAudioClock2_iface;
106 IAudioStreamVolume IAudioStreamVolume_iface;
108 LONG ref;
110 IMMDevice *parent;
112 WAVEFORMATEX *fmt;
114 EDataFlow dataflow;
115 DWORD flags;
116 AUDCLNT_SHAREMODE share;
117 HANDLE event;
118 float *vols;
120 int fd;
121 oss_audioinfo ai;
122 char devnode[OSS_DEVNODE_SIZE];
124 BOOL initted, playing;
125 UINT64 written_frames;
126 UINT32 period_us, bufsize_frames, held_frames, tmp_buffer_frames, inbuf_frames;
127 UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
129 BYTE *local_buffer, *tmp_buffer;
130 int buf_state;
131 long getbuf_last; /* <0 when using tmp_buffer */
132 HANDLE timer;
134 CRITICAL_SECTION lock;
136 AudioSession *session;
137 AudioSessionWrapper *session_wrapper;
139 struct list entry;
142 enum BufferStates {
143 NOT_LOCKED = 0,
144 LOCKED_NORMAL, /* public buffer piece is from local_buffer */
145 LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
148 typedef struct _SessionMgr {
149 IAudioSessionManager2 IAudioSessionManager2_iface;
151 LONG ref;
153 IMMDevice *device;
154 } SessionMgr;
156 static HANDLE g_timer_q;
158 static CRITICAL_SECTION g_sessions_lock;
159 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
161 0, 0, &g_sessions_lock,
162 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
163 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
165 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
166 static struct list g_sessions = LIST_INIT(g_sessions);
168 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
170 static const IAudioClientVtbl AudioClient_Vtbl;
171 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
172 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
173 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
174 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
175 static const IAudioClockVtbl AudioClock_Vtbl;
176 static const IAudioClock2Vtbl AudioClock2_Vtbl;
177 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
178 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
179 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
181 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
183 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
186 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
188 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
191 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
193 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
196 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
198 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
201 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
203 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
206 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
208 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
211 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
213 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
216 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
218 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
221 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
223 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
226 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
228 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
231 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
233 switch (reason)
235 case DLL_PROCESS_ATTACH:
236 g_timer_q = CreateTimerQueue();
237 if(!g_timer_q)
238 return FALSE;
239 break;
241 case DLL_PROCESS_DETACH:
242 DeleteCriticalSection(&g_sessions_lock);
243 break;
245 return TRUE;
248 /* From <dlls/mmdevapi/mmdevapi.h> */
249 enum DriverPriority {
250 Priority_Unavailable = 0,
251 Priority_Low,
252 Priority_Neutral,
253 Priority_Preferred
256 int WINAPI AUDDRV_GetPriority(void)
258 int mixer_fd;
259 oss_sysinfo sysinfo;
261 /* Attempt to determine if we are running on OSS or ALSA's OSS
262 * compatibility layer. There is no official way to do that, so just check
263 * for validity as best as possible, without rejecting valid OSS
264 * implementations. */
266 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
267 if(mixer_fd < 0){
268 TRACE("Priority_Unavailable: open failed\n");
269 return Priority_Unavailable;
272 sysinfo.version[0] = 0xFF;
273 sysinfo.versionnum = ~0;
274 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
275 TRACE("Priority_Unavailable: ioctl failed\n");
276 close(mixer_fd);
277 return Priority_Unavailable;
280 close(mixer_fd);
282 if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
283 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
284 return Priority_Low;
286 if(sysinfo.versionnum & 0x80000000){
287 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
288 return Priority_Low;
291 TRACE("Priority_Preferred: Seems like valid OSS!\n");
293 return Priority_Preferred;
296 static const char *oss_clean_devnode(const char *devnode)
298 static char ret[OSS_DEVNODE_SIZE];
300 const char *dot, *slash;
301 size_t len;
303 dot = strrchr(devnode, '.');
304 if(!dot)
305 return devnode;
307 slash = strrchr(devnode, '/');
308 if(slash && dot < slash)
309 return devnode;
311 len = dot - devnode;
313 memcpy(ret, devnode, len);
314 ret[len] = '\0';
316 return ret;
319 static UINT get_default_index(EDataFlow flow, char **keys, UINT num)
321 int fd = -1, err, i;
322 oss_audioinfo ai;
323 const char *devnode;
325 if(flow == eRender)
326 fd = open("/dev/dsp", O_WRONLY);
327 else
328 fd = open("/dev/dsp", O_RDONLY);
330 if(fd < 0){
331 WARN("Couldn't open default device!\n");
332 return 0;
335 ai.dev = -1;
336 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
337 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
338 close(fd);
339 return 0;
342 close(fd);
344 TRACE("Default devnode: %s\n", ai.devnode);
345 devnode = oss_clean_devnode(ai.devnode);
346 for(i = 0; i < num; ++i)
347 if(!strcmp(devnode, keys[i]))
348 return i;
350 WARN("Couldn't find default device! Choosing first.\n");
351 return 0;
354 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, char ***keys,
355 UINT *num, UINT *def_index)
357 int i, j, mixer_fd;
358 oss_sysinfo sysinfo;
359 static int print_once = 0;
361 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
363 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
364 if(mixer_fd < 0){
365 ERR("OSS /dev/mixer doesn't seem to exist\n");
366 return AUDCLNT_E_SERVICE_NOT_RUNNING;
369 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
370 close(mixer_fd);
372 if(errno == EINVAL){
373 ERR("OSS version too old, need at least OSSv4\n");
374 return AUDCLNT_E_SERVICE_NOT_RUNNING;
377 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
378 return E_FAIL;
381 if(!print_once){
382 TRACE("OSS sysinfo:\n");
383 TRACE("product: %s\n", sysinfo.product);
384 TRACE("version: %s\n", sysinfo.version);
385 TRACE("versionnum: %x\n", sysinfo.versionnum);
386 TRACE("numaudios: %d\n", sysinfo.numaudios);
387 TRACE("nummixers: %d\n", sysinfo.nummixers);
388 TRACE("numcards: %d\n", sysinfo.numcards);
389 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
390 print_once = 1;
393 if(sysinfo.numaudios <= 0){
394 WARN("No audio devices!\n");
395 close(mixer_fd);
396 return AUDCLNT_E_SERVICE_NOT_RUNNING;
399 *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
400 *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
402 *num = 0;
403 for(i = 0; i < sysinfo.numaudios; ++i){
404 oss_audioinfo ai = {0};
405 const char *devnode;
406 int fd;
408 ai.dev = i;
409 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
410 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
411 strerror(errno));
412 continue;
415 devnode = oss_clean_devnode(ai.devnode);
417 /* check for duplicates */
418 for(j = 0; j < *num; ++j)
419 if(!strcmp(devnode, (*keys)[j]))
420 break;
421 if(j != *num)
422 continue;
424 if(flow == eRender)
425 fd = open(devnode, O_WRONLY, 0);
426 else
427 fd = open(devnode, O_RDONLY, 0);
428 if(fd < 0){
429 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
430 devnode, errno, strerror(errno));
431 continue;
433 close(fd);
435 if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
436 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
437 size_t len;
439 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
440 strlen(devnode) + 1);
441 if(!(*keys)[*num]){
442 for(i = 0; i < *num; ++i){
443 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
444 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
446 HeapFree(GetProcessHeap(), 0, *ids);
447 HeapFree(GetProcessHeap(), 0, *keys);
448 close(mixer_fd);
449 return E_OUTOFMEMORY;
451 strcpy((*keys)[*num], devnode);
453 len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
454 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
455 len * sizeof(WCHAR));
456 if(!(*ids)[*num]){
457 HeapFree(GetProcessHeap(), 0, (*keys)[*num]);
458 for(i = 0; i < *num; ++i){
459 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
460 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
462 HeapFree(GetProcessHeap(), 0, *ids);
463 HeapFree(GetProcessHeap(), 0, *keys);
464 close(mixer_fd);
465 return E_OUTOFMEMORY;
467 MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
468 (*ids)[*num], len);
470 (*num)++;
474 close(mixer_fd);
476 *def_index = get_default_index(flow, *keys, *num);
478 return S_OK;
481 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
482 EDataFlow dataflow, IAudioClient **out)
484 ACImpl *This;
486 TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
488 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
489 if(!This)
490 return E_OUTOFMEMORY;
492 if(dataflow == eRender)
493 This->fd = open(devnode, O_WRONLY, 0);
494 else if(dataflow == eCapture)
495 This->fd = open(devnode, O_RDONLY, 0);
496 else{
497 HeapFree(GetProcessHeap(), 0, This);
498 return E_INVALIDARG;
500 if(This->fd < 0){
501 ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
502 strerror(errno));
503 HeapFree(GetProcessHeap(), 0, This);
504 return AUDCLNT_E_DEVICE_INVALIDATED;
507 This->dataflow = dataflow;
509 This->ai.dev = -1;
510 if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
511 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode,
512 errno, strerror(errno));
513 close(This->fd);
514 HeapFree(GetProcessHeap(), 0, This);
515 return E_FAIL;
518 strcpy(This->devnode, devnode);
520 TRACE("OSS audioinfo:\n");
521 TRACE("devnode: %s\n", This->ai.devnode);
522 TRACE("name: %s\n", This->ai.name);
523 TRACE("busy: %x\n", This->ai.busy);
524 TRACE("caps: %x\n", This->ai.caps);
525 TRACE("iformats: %x\n", This->ai.iformats);
526 TRACE("oformats: %x\n", This->ai.oformats);
527 TRACE("enabled: %d\n", This->ai.enabled);
528 TRACE("min_rate: %d\n", This->ai.min_rate);
529 TRACE("max_rate: %d\n", This->ai.max_rate);
530 TRACE("min_channels: %d\n", This->ai.min_channels);
531 TRACE("max_channels: %d\n", This->ai.max_channels);
533 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
534 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
535 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
536 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
537 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
538 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
540 InitializeCriticalSection(&This->lock);
541 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
543 This->parent = dev;
544 IMMDevice_AddRef(This->parent);
546 IAudioClient_AddRef(&This->IAudioClient_iface);
548 *out = &This->IAudioClient_iface;
550 return S_OK;
553 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
554 REFIID riid, void **ppv)
556 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
558 if(!ppv)
559 return E_POINTER;
560 *ppv = NULL;
561 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
562 *ppv = iface;
563 if(*ppv){
564 IUnknown_AddRef((IUnknown*)*ppv);
565 return S_OK;
567 WARN("Unknown interface %s\n", debugstr_guid(riid));
568 return E_NOINTERFACE;
571 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
573 ACImpl *This = impl_from_IAudioClient(iface);
574 ULONG ref;
575 ref = InterlockedIncrement(&This->ref);
576 TRACE("(%p) Refcount now %u\n", This, ref);
577 return ref;
580 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
582 ACImpl *This = impl_from_IAudioClient(iface);
583 ULONG ref;
584 ref = InterlockedDecrement(&This->ref);
585 TRACE("(%p) Refcount now %u\n", This, ref);
586 if(!ref){
587 IAudioClient_Stop(iface);
588 IMMDevice_Release(This->parent);
589 This->lock.DebugInfo->Spare[0] = 0;
590 DeleteCriticalSection(&This->lock);
591 close(This->fd);
592 if(This->initted){
593 EnterCriticalSection(&g_sessions_lock);
594 list_remove(&This->entry);
595 LeaveCriticalSection(&g_sessions_lock);
597 HeapFree(GetProcessHeap(), 0, This->vols);
598 HeapFree(GetProcessHeap(), 0, This->local_buffer);
599 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
600 CoTaskMemFree(This->fmt);
601 HeapFree(GetProcessHeap(), 0, This);
603 return ref;
606 static void dump_fmt(const WAVEFORMATEX *fmt)
608 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
609 switch(fmt->wFormatTag){
610 case WAVE_FORMAT_PCM:
611 TRACE("WAVE_FORMAT_PCM");
612 break;
613 case WAVE_FORMAT_IEEE_FLOAT:
614 TRACE("WAVE_FORMAT_IEEE_FLOAT");
615 break;
616 case WAVE_FORMAT_EXTENSIBLE:
617 TRACE("WAVE_FORMAT_EXTENSIBLE");
618 break;
619 default:
620 TRACE("Unknown");
621 break;
623 TRACE(")\n");
625 TRACE("nChannels: %u\n", fmt->nChannels);
626 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
627 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
628 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
629 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
630 TRACE("cbSize: %u\n", fmt->cbSize);
632 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
633 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
634 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
635 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
636 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
640 static DWORD get_channel_mask(unsigned int channels)
642 switch(channels){
643 case 0:
644 return 0;
645 case 1:
646 return KSAUDIO_SPEAKER_MONO;
647 case 2:
648 return KSAUDIO_SPEAKER_STEREO;
649 case 3:
650 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
651 case 4:
652 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
653 case 5:
654 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
655 case 6:
656 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
657 case 7:
658 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
659 case 8:
660 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
662 FIXME("Unknown speaker configuration: %u\n", channels);
663 return 0;
666 static int get_oss_format(const WAVEFORMATEX *fmt)
668 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
670 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
671 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
672 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
673 switch(fmt->wBitsPerSample){
674 case 8:
675 return AFMT_U8;
676 case 16:
677 return AFMT_S16_LE;
678 case 24:
679 return AFMT_S24_LE;
680 case 32:
681 return AFMT_S32_LE;
683 return -1;
686 #ifdef AFMT_FLOAT
687 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
688 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
689 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
690 if(fmt->wBitsPerSample != 32)
691 return -1;
693 return AFMT_FLOAT;
695 #endif
697 return -1;
700 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
702 WAVEFORMATEX *ret;
703 size_t size;
705 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
706 size = sizeof(WAVEFORMATEXTENSIBLE);
707 else
708 size = sizeof(WAVEFORMATEX);
710 ret = CoTaskMemAlloc(size);
711 if(!ret)
712 return NULL;
714 memcpy(ret, fmt, size);
716 ret->cbSize = size - sizeof(WAVEFORMATEX);
718 return ret;
721 static HRESULT setup_oss_device(int fd, const WAVEFORMATEX *fmt,
722 WAVEFORMATEX **out, BOOL query)
724 int tmp, oss_format;
725 double tenth;
726 HRESULT ret = S_OK;
727 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
728 WAVEFORMATEX *closest = NULL;
730 tmp = oss_format = get_oss_format(fmt);
731 if(oss_format < 0)
732 return AUDCLNT_E_UNSUPPORTED_FORMAT;
733 if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
734 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
735 return E_FAIL;
737 if(tmp != oss_format){
738 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
739 return AUDCLNT_E_UNSUPPORTED_FORMAT;
742 closest = clone_format(fmt);
743 if(!closest)
744 return E_OUTOFMEMORY;
746 tmp = fmt->nSamplesPerSec;
747 if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
748 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
749 CoTaskMemFree(closest);
750 return E_FAIL;
752 tenth = fmt->nSamplesPerSec * 0.1;
753 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
754 ret = S_FALSE;
755 closest->nSamplesPerSec = tmp;
758 tmp = fmt->nChannels;
759 if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
760 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
761 CoTaskMemFree(closest);
762 return E_FAIL;
764 if(tmp != fmt->nChannels){
765 ret = S_FALSE;
766 closest->nChannels = tmp;
769 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
770 DWORD mask = get_channel_mask(closest->nChannels);
772 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
774 if(query && fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
775 fmtex->dwChannelMask != 0 &&
776 fmtex->dwChannelMask != mask)
777 ret = S_FALSE;
780 if(ret == S_FALSE && !out)
781 ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
783 if(ret == S_FALSE && out){
784 closest->nBlockAlign =
785 closest->nChannels * closest->wBitsPerSample / 8;
786 closest->nAvgBytesPerSec =
787 closest->nBlockAlign * closest->nSamplesPerSec;
788 *out = closest;
789 } else
790 CoTaskMemFree(closest);
792 TRACE("returning: %08x\n", ret);
793 return ret;
796 static void session_init_vols(AudioSession *session, UINT channels)
798 if(session->channel_count < channels){
799 UINT i;
801 if(session->channel_vols)
802 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
803 session->channel_vols, sizeof(float) * channels);
804 else
805 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
806 sizeof(float) * channels);
807 if(!session->channel_vols)
808 return;
810 for(i = session->channel_count; i < channels; ++i)
811 session->channel_vols[i] = 1.f;
813 session->channel_count = channels;
817 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
818 UINT num_channels)
820 AudioSession *ret;
822 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
823 if(!ret)
824 return NULL;
826 memcpy(&ret->guid, guid, sizeof(GUID));
828 ret->device = device;
830 list_init(&ret->clients);
832 list_add_head(&g_sessions, &ret->entry);
834 InitializeCriticalSection(&ret->lock);
835 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
837 session_init_vols(ret, num_channels);
839 ret->master_vol = 1.f;
841 return ret;
844 /* if channels == 0, then this will return or create a session with
845 * matching dataflow and GUID. otherwise, channels must also match */
846 static HRESULT get_audio_session(const GUID *sessionguid,
847 IMMDevice *device, UINT channels, AudioSession **out)
849 AudioSession *session;
851 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
852 *out = create_session(&GUID_NULL, device, channels);
853 if(!*out)
854 return E_OUTOFMEMORY;
856 return S_OK;
859 *out = NULL;
860 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
861 if(session->device == device &&
862 IsEqualGUID(sessionguid, &session->guid)){
863 session_init_vols(session, channels);
864 *out = session;
865 break;
869 if(!*out){
870 *out = create_session(sessionguid, device, channels);
871 if(!*out)
872 return E_OUTOFMEMORY;
875 return S_OK;
878 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
879 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
880 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
881 const GUID *sessionguid)
883 ACImpl *This = impl_from_IAudioClient(iface);
884 int mask, i;
885 HRESULT hr;
887 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
888 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
890 if(!fmt)
891 return E_POINTER;
893 dump_fmt(fmt);
895 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
896 return AUDCLNT_E_NOT_INITIALIZED;
898 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
899 AUDCLNT_STREAMFLAGS_LOOPBACK |
900 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
901 AUDCLNT_STREAMFLAGS_NOPERSIST |
902 AUDCLNT_STREAMFLAGS_RATEADJUST |
903 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
904 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
905 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
906 TRACE("Unknown flags: %08x\n", flags);
907 return E_INVALIDARG;
910 if(mode == AUDCLNT_SHAREMODE_SHARED){
911 period = DefaultPeriod;
912 if( duration < 3 * period)
913 duration = 3 * period;
914 }else{
915 if(!period)
916 period = DefaultPeriod; /* not minimum */
917 if(period < MinimumPeriod || period > 5000000)
918 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
919 if(duration > 20000000) /* the smaller the period, the lower this limit */
920 return AUDCLNT_E_BUFFER_SIZE_ERROR;
921 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
922 if(duration != period)
923 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
924 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
925 return AUDCLNT_E_DEVICE_IN_USE;
926 }else{
927 if( duration < 8 * period)
928 duration = 8 * period; /* may grow above 2s */
932 EnterCriticalSection(&This->lock);
934 if(This->initted){
935 LeaveCriticalSection(&This->lock);
936 return AUDCLNT_E_ALREADY_INITIALIZED;
939 hr = setup_oss_device(This->fd, fmt, NULL, FALSE);
940 if(FAILED(hr)){
941 LeaveCriticalSection(&This->lock);
942 return hr;
945 mask = 0;
946 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
947 LeaveCriticalSection(&This->lock);
948 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
949 return E_FAIL;
952 This->fmt = clone_format(fmt);
953 if(!This->fmt){
954 LeaveCriticalSection(&This->lock);
955 return E_OUTOFMEMORY;
958 This->period_us = period / 10;
960 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
961 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
962 This->bufsize_frames * fmt->nBlockAlign);
963 if(!This->local_buffer){
964 CoTaskMemFree(This->fmt);
965 This->fmt = NULL;
966 LeaveCriticalSection(&This->lock);
967 return E_OUTOFMEMORY;
970 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
971 if(!This->vols){
972 CoTaskMemFree(This->fmt);
973 This->fmt = NULL;
974 LeaveCriticalSection(&This->lock);
975 return E_OUTOFMEMORY;
978 for(i = 0; i < fmt->nChannels; ++i)
979 This->vols[i] = 1.f;
981 This->share = mode;
982 This->flags = flags;
984 EnterCriticalSection(&g_sessions_lock);
986 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
987 &This->session);
988 if(FAILED(hr)){
989 LeaveCriticalSection(&g_sessions_lock);
990 HeapFree(GetProcessHeap(), 0, This->vols);
991 This->vols = NULL;
992 CoTaskMemFree(This->fmt);
993 This->fmt = NULL;
994 LeaveCriticalSection(&This->lock);
995 return hr;
998 list_add_tail(&This->session->clients, &This->entry);
1000 LeaveCriticalSection(&g_sessions_lock);
1002 This->initted = TRUE;
1004 LeaveCriticalSection(&This->lock);
1006 return S_OK;
1009 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1010 UINT32 *frames)
1012 ACImpl *This = impl_from_IAudioClient(iface);
1014 TRACE("(%p)->(%p)\n", This, frames);
1016 if(!frames)
1017 return E_POINTER;
1019 EnterCriticalSection(&This->lock);
1021 if(!This->initted){
1022 LeaveCriticalSection(&This->lock);
1023 return AUDCLNT_E_NOT_INITIALIZED;
1026 *frames = This->bufsize_frames;
1028 LeaveCriticalSection(&This->lock);
1030 return S_OK;
1033 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1034 REFERENCE_TIME *latency)
1036 ACImpl *This = impl_from_IAudioClient(iface);
1038 TRACE("(%p)->(%p)\n", This, latency);
1040 if(!latency)
1041 return E_POINTER;
1043 EnterCriticalSection(&This->lock);
1045 if(!This->initted){
1046 LeaveCriticalSection(&This->lock);
1047 return AUDCLNT_E_NOT_INITIALIZED;
1050 /* pretend we process audio in Period chunks, so max latency includes
1051 * the period time. Some native machines add .6666ms in shared mode. */
1052 *latency = This->period_us * 10 + 6666;
1054 LeaveCriticalSection(&This->lock);
1056 return S_OK;
1059 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1060 UINT32 *numpad)
1062 ACImpl *This = impl_from_IAudioClient(iface);
1063 audio_buf_info bi;
1065 TRACE("(%p)->(%p)\n", This, numpad);
1067 if(!numpad)
1068 return E_POINTER;
1070 EnterCriticalSection(&This->lock);
1072 if(!This->initted){
1073 LeaveCriticalSection(&This->lock);
1074 return AUDCLNT_E_NOT_INITIALIZED;
1077 if(This->dataflow == eRender){
1078 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1079 LeaveCriticalSection(&This->lock);
1080 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1081 return E_FAIL;
1084 *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
1085 This->fmt->nBlockAlign;
1087 /* when the OSS buffer has less than one fragment of data, including
1088 * no data, it often reports it as some non-zero portion of a
1089 * fragment. when it has more than one fragment of data, it reports
1090 * it as some multiple of that portion of the fragment size.
1092 * so, we have to do some ugly workarounds to report the timing
1093 * as accurately as possible */
1094 if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
1095 *numpad = This->inbuf_frames;
1096 This->inbuf_frames = 0;
1097 }else{
1098 if(*numpad < This->inbuf_frames)
1099 This->inbuf_frames = *numpad;
1100 else
1101 *numpad = This->inbuf_frames;
1103 }else if(This->dataflow == eCapture){
1104 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1105 LeaveCriticalSection(&This->lock);
1106 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1107 return E_FAIL;
1110 if(bi.bytes <= bi.fragsize)
1111 *numpad = 0;
1112 else
1113 *numpad = bi.bytes / This->fmt->nBlockAlign;
1114 }else{
1115 LeaveCriticalSection(&This->lock);
1116 return E_UNEXPECTED;
1119 *numpad += This->held_frames;
1121 LeaveCriticalSection(&This->lock);
1123 return S_OK;
1126 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1127 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1128 WAVEFORMATEX **outpwfx)
1130 ACImpl *This = impl_from_IAudioClient(iface);
1131 int fd = -1;
1132 HRESULT ret;
1134 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1136 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1137 return E_POINTER;
1139 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1140 return E_INVALIDARG;
1142 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1143 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1144 return E_INVALIDARG;
1146 dump_fmt(pwfx);
1148 if(outpwfx){
1149 *outpwfx = NULL;
1150 if(mode != AUDCLNT_SHAREMODE_SHARED)
1151 outpwfx = NULL;
1154 if(This->dataflow == eRender)
1155 fd = open(This->devnode, O_WRONLY, 0);
1156 else if(This->dataflow == eCapture)
1157 fd = open(This->devnode, O_RDONLY, 0);
1159 if(fd < 0){
1160 ERR("Unable to open device %s: %d (%s)\n", This->devnode, errno,
1161 strerror(errno));
1162 return AUDCLNT_E_DEVICE_INVALIDATED;
1165 ret = setup_oss_device(fd, pwfx, outpwfx, TRUE);
1167 close(fd);
1169 return ret;
1172 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1173 WAVEFORMATEX **pwfx)
1175 ACImpl *This = impl_from_IAudioClient(iface);
1176 WAVEFORMATEXTENSIBLE *fmt;
1177 int formats;
1179 TRACE("(%p)->(%p)\n", This, pwfx);
1181 if(!pwfx)
1182 return E_POINTER;
1183 *pwfx = NULL;
1185 if(This->dataflow == eRender)
1186 formats = This->ai.oformats;
1187 else if(This->dataflow == eCapture)
1188 formats = This->ai.iformats;
1189 else
1190 return E_UNEXPECTED;
1192 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1193 if(!fmt)
1194 return E_OUTOFMEMORY;
1196 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1197 if(formats & AFMT_S16_LE){
1198 fmt->Format.wBitsPerSample = 16;
1199 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1200 #ifdef AFMT_FLOAT
1201 }else if(formats & AFMT_FLOAT){
1202 fmt->Format.wBitsPerSample = 32;
1203 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1204 #endif
1205 }else if(formats & AFMT_U8){
1206 fmt->Format.wBitsPerSample = 8;
1207 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1208 }else if(formats & AFMT_S32_LE){
1209 fmt->Format.wBitsPerSample = 32;
1210 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1211 }else if(formats & AFMT_S24_LE){
1212 fmt->Format.wBitsPerSample = 24;
1213 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1214 }else{
1215 ERR("Didn't recognize any available OSS formats: %x\n", formats);
1216 CoTaskMemFree(fmt);
1217 return E_FAIL;
1220 fmt->Format.nChannels = This->ai.max_channels;
1221 fmt->Format.nSamplesPerSec = This->ai.max_rate;
1222 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1224 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1225 fmt->Format.nChannels) / 8;
1226 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1227 fmt->Format.nBlockAlign;
1229 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1230 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1232 *pwfx = (WAVEFORMATEX*)fmt;
1233 dump_fmt(*pwfx);
1235 return S_OK;
1238 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1239 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1241 ACImpl *This = impl_from_IAudioClient(iface);
1243 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1245 if(!defperiod && !minperiod)
1246 return E_POINTER;
1248 if(defperiod)
1249 *defperiod = DefaultPeriod;
1250 if(minperiod)
1251 *minperiod = MinimumPeriod;
1253 return S_OK;
1256 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1258 if(This->fmt->wBitsPerSample == 8)
1259 memset(buf, 128, frames * This->fmt->nBlockAlign);
1260 else
1261 memset(buf, 0, frames * This->fmt->nBlockAlign);
1264 static void oss_write_data(ACImpl *This)
1266 ssize_t written_bytes;
1267 UINT32 written_frames;
1268 size_t to_write_frames, to_write_bytes;
1269 audio_buf_info bi;
1270 BYTE *buf =
1271 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1273 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1274 to_write_frames = This->bufsize_frames - This->lcl_offs_frames;
1275 else
1276 to_write_frames = This->held_frames;
1277 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1279 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1280 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1281 return;
1284 if(bi.bytes < to_write_bytes){
1285 to_write_frames = bi.bytes / This->fmt->nBlockAlign;
1286 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1289 if(This->session->mute)
1290 oss_silence_buffer(This, buf, to_write_frames);
1292 written_bytes = write(This->fd, buf, to_write_bytes);
1293 if(written_bytes < 0){
1294 /* EAGAIN is OSS buffer full, log that too */
1295 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1296 return;
1298 written_frames = written_bytes / This->fmt->nBlockAlign;
1300 This->lcl_offs_frames += written_frames;
1301 This->lcl_offs_frames %= This->bufsize_frames;
1302 This->held_frames -= written_frames;
1303 This->inbuf_frames += written_frames;
1305 if(written_frames < to_write_frames){
1306 /* OSS buffer probably full */
1307 return;
1310 bi.bytes -= written_bytes;
1311 if(This->held_frames && bi.bytes >= This->fmt->nBlockAlign){
1312 /* wrapped and have some data back at the start to write */
1314 to_write_frames = bi.bytes / This->fmt->nBlockAlign;
1315 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1317 if(This->session->mute)
1318 oss_silence_buffer(This, This->local_buffer, to_write_frames);
1320 written_bytes = write(This->fd, This->local_buffer, to_write_bytes);
1321 if(written_bytes < 0){
1322 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1323 return;
1325 written_frames = written_bytes / This->fmt->nBlockAlign;
1327 This->lcl_offs_frames += written_frames;
1328 This->lcl_offs_frames %= This->bufsize_frames;
1329 This->held_frames -= written_frames;
1330 This->inbuf_frames += written_frames;
1334 static void oss_read_data(ACImpl *This)
1336 UINT64 pos, readable;
1337 audio_buf_info bi;
1338 ssize_t nread;
1340 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1341 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1342 return;
1345 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1346 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1348 if(bi.bytes < readable)
1349 readable = bi.bytes;
1351 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1352 readable);
1353 if(nread < 0){
1354 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1355 return;
1358 This->held_frames += nread / This->fmt->nBlockAlign;
1360 if(This->held_frames > This->bufsize_frames){
1361 WARN("Overflow of unread data\n");
1362 This->lcl_offs_frames += This->held_frames;
1363 This->lcl_offs_frames %= This->bufsize_frames;
1364 This->held_frames = This->bufsize_frames;
1368 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1370 ACImpl *This = user;
1372 EnterCriticalSection(&This->lock);
1374 if(This->dataflow == eRender && This->held_frames)
1375 oss_write_data(This);
1376 else if(This->dataflow == eCapture)
1377 oss_read_data(This);
1379 if(This->event)
1380 SetEvent(This->event);
1382 LeaveCriticalSection(&This->lock);
1385 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1387 ACImpl *This = impl_from_IAudioClient(iface);
1388 int mask;
1390 TRACE("(%p)\n", This);
1392 EnterCriticalSection(&This->lock);
1394 if(!This->initted){
1395 LeaveCriticalSection(&This->lock);
1396 return AUDCLNT_E_NOT_INITIALIZED;
1399 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1400 LeaveCriticalSection(&This->lock);
1401 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1404 if(This->playing){
1405 LeaveCriticalSection(&This->lock);
1406 return AUDCLNT_E_NOT_STOPPED;
1409 if(This->dataflow == eRender)
1410 mask = PCM_ENABLE_OUTPUT;
1411 else if(This->dataflow == eCapture)
1412 mask = PCM_ENABLE_INPUT;
1413 else{
1414 LeaveCriticalSection(&This->lock);
1415 return E_UNEXPECTED;
1418 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1419 LeaveCriticalSection(&This->lock);
1420 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1421 return E_FAIL;
1424 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1425 oss_period_callback, This, 0, This->period_us / 1000,
1426 WT_EXECUTEINTIMERTHREAD))
1427 ERR("Unable to create period timer: %u\n", GetLastError());
1429 This->playing = TRUE;
1431 LeaveCriticalSection(&This->lock);
1433 return S_OK;
1436 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1438 ACImpl *This = impl_from_IAudioClient(iface);
1439 int mask;
1441 TRACE("(%p)\n", This);
1443 EnterCriticalSection(&This->lock);
1445 if(!This->initted){
1446 LeaveCriticalSection(&This->lock);
1447 return AUDCLNT_E_NOT_INITIALIZED;
1450 if(!This->playing){
1451 LeaveCriticalSection(&This->lock);
1452 return S_FALSE;
1455 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1456 DeleteTimerQueueTimer(g_timer_q, This->timer,
1457 INVALID_HANDLE_VALUE);
1458 This->timer = NULL;
1461 if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1462 LeaveCriticalSection(&This->lock);
1463 WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1464 return E_FAIL;
1467 mask = 0;
1468 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1469 LeaveCriticalSection(&This->lock);
1470 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1471 return E_FAIL;
1474 This->playing = FALSE;
1476 LeaveCriticalSection(&This->lock);
1478 return S_OK;
1481 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1483 ACImpl *This = impl_from_IAudioClient(iface);
1485 TRACE("(%p)\n", This);
1487 EnterCriticalSection(&This->lock);
1489 if(!This->initted){
1490 LeaveCriticalSection(&This->lock);
1491 return AUDCLNT_E_NOT_INITIALIZED;
1494 if(This->playing){
1495 LeaveCriticalSection(&This->lock);
1496 return AUDCLNT_E_NOT_STOPPED;
1499 if(This->buf_state != NOT_LOCKED || This->getbuf_last){
1500 LeaveCriticalSection(&This->lock);
1501 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1504 if(This->dataflow == eRender){
1505 This->written_frames = 0;
1506 }else{
1507 This->written_frames += This->held_frames;
1509 This->lcl_offs_frames = 0;
1510 This->inbuf_frames = 0;
1511 This->held_frames = 0;
1513 if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1514 WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1516 LeaveCriticalSection(&This->lock);
1518 return S_OK;
1521 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1522 HANDLE event)
1524 ACImpl *This = impl_from_IAudioClient(iface);
1526 TRACE("(%p)->(%p)\n", This, event);
1528 if(!event)
1529 return E_INVALIDARG;
1531 EnterCriticalSection(&This->lock);
1533 if(!This->initted){
1534 LeaveCriticalSection(&This->lock);
1535 return AUDCLNT_E_NOT_INITIALIZED;
1538 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1539 LeaveCriticalSection(&This->lock);
1540 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1543 This->event = event;
1545 LeaveCriticalSection(&This->lock);
1547 return S_OK;
1550 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1551 void **ppv)
1553 ACImpl *This = impl_from_IAudioClient(iface);
1555 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1557 if(!ppv)
1558 return E_POINTER;
1559 *ppv = NULL;
1561 EnterCriticalSection(&This->lock);
1563 if(!This->initted){
1564 LeaveCriticalSection(&This->lock);
1565 return AUDCLNT_E_NOT_INITIALIZED;
1568 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1569 if(This->dataflow != eRender){
1570 LeaveCriticalSection(&This->lock);
1571 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1573 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1574 *ppv = &This->IAudioRenderClient_iface;
1575 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1576 if(This->dataflow != eCapture){
1577 LeaveCriticalSection(&This->lock);
1578 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1580 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1581 *ppv = &This->IAudioCaptureClient_iface;
1582 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1583 IAudioClock_AddRef(&This->IAudioClock_iface);
1584 *ppv = &This->IAudioClock_iface;
1585 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1586 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1587 *ppv = &This->IAudioStreamVolume_iface;
1588 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1589 if(!This->session_wrapper){
1590 This->session_wrapper = AudioSessionWrapper_Create(This);
1591 if(!This->session_wrapper){
1592 LeaveCriticalSection(&This->lock);
1593 return E_OUTOFMEMORY;
1595 }else
1596 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1598 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1599 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1600 if(!This->session_wrapper){
1601 This->session_wrapper = AudioSessionWrapper_Create(This);
1602 if(!This->session_wrapper){
1603 LeaveCriticalSection(&This->lock);
1604 return E_OUTOFMEMORY;
1606 }else
1607 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1609 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1610 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1611 if(!This->session_wrapper){
1612 This->session_wrapper = AudioSessionWrapper_Create(This);
1613 if(!This->session_wrapper){
1614 LeaveCriticalSection(&This->lock);
1615 return E_OUTOFMEMORY;
1617 }else
1618 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1620 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1623 if(*ppv){
1624 LeaveCriticalSection(&This->lock);
1625 return S_OK;
1628 LeaveCriticalSection(&This->lock);
1630 FIXME("stub %s\n", debugstr_guid(riid));
1631 return E_NOINTERFACE;
1634 static const IAudioClientVtbl AudioClient_Vtbl =
1636 AudioClient_QueryInterface,
1637 AudioClient_AddRef,
1638 AudioClient_Release,
1639 AudioClient_Initialize,
1640 AudioClient_GetBufferSize,
1641 AudioClient_GetStreamLatency,
1642 AudioClient_GetCurrentPadding,
1643 AudioClient_IsFormatSupported,
1644 AudioClient_GetMixFormat,
1645 AudioClient_GetDevicePeriod,
1646 AudioClient_Start,
1647 AudioClient_Stop,
1648 AudioClient_Reset,
1649 AudioClient_SetEventHandle,
1650 AudioClient_GetService
1653 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1654 IAudioRenderClient *iface, REFIID riid, void **ppv)
1656 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1658 if(!ppv)
1659 return E_POINTER;
1660 *ppv = NULL;
1662 if(IsEqualIID(riid, &IID_IUnknown) ||
1663 IsEqualIID(riid, &IID_IAudioRenderClient))
1664 *ppv = iface;
1665 if(*ppv){
1666 IUnknown_AddRef((IUnknown*)*ppv);
1667 return S_OK;
1670 WARN("Unknown interface %s\n", debugstr_guid(riid));
1671 return E_NOINTERFACE;
1674 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1676 ACImpl *This = impl_from_IAudioRenderClient(iface);
1677 return AudioClient_AddRef(&This->IAudioClient_iface);
1680 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1682 ACImpl *This = impl_from_IAudioRenderClient(iface);
1683 return AudioClient_Release(&This->IAudioClient_iface);
1686 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1687 UINT32 frames, BYTE **data)
1689 ACImpl *This = impl_from_IAudioRenderClient(iface);
1690 UINT32 pad, write_pos;
1691 HRESULT hr;
1693 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1695 if(!data)
1696 return E_POINTER;
1698 *data = NULL;
1700 EnterCriticalSection(&This->lock);
1702 if(This->getbuf_last){
1703 LeaveCriticalSection(&This->lock);
1704 return AUDCLNT_E_OUT_OF_ORDER;
1707 if(!frames){
1708 LeaveCriticalSection(&This->lock);
1709 return S_OK;
1712 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1713 if(FAILED(hr)){
1714 LeaveCriticalSection(&This->lock);
1715 return hr;
1718 if(pad + frames > This->bufsize_frames){
1719 LeaveCriticalSection(&This->lock);
1720 return AUDCLNT_E_BUFFER_TOO_LARGE;
1723 write_pos =
1724 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1725 if(write_pos + frames > This->bufsize_frames){
1726 if(This->tmp_buffer_frames < frames){
1727 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1728 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1729 frames * This->fmt->nBlockAlign);
1730 if(!This->tmp_buffer){
1731 LeaveCriticalSection(&This->lock);
1732 return E_OUTOFMEMORY;
1734 This->tmp_buffer_frames = frames;
1736 *data = This->tmp_buffer;
1737 This->getbuf_last = -frames;
1738 }else{
1739 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1740 This->getbuf_last = frames;
1743 LeaveCriticalSection(&This->lock);
1745 return S_OK;
1748 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1750 UINT32 write_offs_frames =
1751 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1752 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1753 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1754 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1755 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1757 if(written_bytes <= chunk_bytes){
1758 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1759 }else{
1760 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1761 memcpy(This->local_buffer, buffer + chunk_bytes,
1762 written_bytes - chunk_bytes);
1766 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1767 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1769 ACImpl *This = impl_from_IAudioRenderClient(iface);
1770 BYTE *buffer;
1772 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1774 EnterCriticalSection(&This->lock);
1776 if(!written_frames){
1777 This->getbuf_last = 0;
1778 LeaveCriticalSection(&This->lock);
1779 return S_OK;
1782 if(!This->getbuf_last){
1783 LeaveCriticalSection(&This->lock);
1784 return AUDCLNT_E_OUT_OF_ORDER;
1787 if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1788 LeaveCriticalSection(&This->lock);
1789 return AUDCLNT_E_INVALID_SIZE;
1792 if(This->getbuf_last >= 0)
1793 buffer = This->local_buffer + This->fmt->nBlockAlign *
1794 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1795 else
1796 buffer = This->tmp_buffer;
1798 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1799 oss_silence_buffer(This, buffer, written_frames);
1801 if(This->held_frames){
1802 if(This->getbuf_last < 0)
1803 oss_wrap_buffer(This, buffer, written_frames);
1805 This->held_frames += written_frames;
1806 }else{
1807 ssize_t w_bytes;
1808 UINT32 w_frames;
1810 if(This->session->mute)
1811 oss_silence_buffer(This, buffer, written_frames);
1813 w_bytes = write(This->fd, buffer,
1814 written_frames * This->fmt->nBlockAlign);
1815 if(w_bytes < 0){
1816 if(errno != EAGAIN){
1817 This->getbuf_last = 0;
1818 LeaveCriticalSection(&This->lock);
1819 ERR("write failed: %d (%s)\n", errno, strerror(errno));
1820 return E_FAIL;
1821 }else /* OSS buffer full */
1822 w_bytes = 0;
1824 w_frames = w_bytes / This->fmt->nBlockAlign;
1825 This->inbuf_frames += w_frames;
1827 if(w_frames < written_frames){
1828 if(This->getbuf_last < 0)
1829 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1830 written_frames - w_frames);
1831 else
1832 This->lcl_offs_frames += w_frames;
1833 This->held_frames = written_frames - w_frames;
1837 This->written_frames += written_frames;
1838 This->getbuf_last = 0;
1840 LeaveCriticalSection(&This->lock);
1842 return S_OK;
1845 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1846 AudioRenderClient_QueryInterface,
1847 AudioRenderClient_AddRef,
1848 AudioRenderClient_Release,
1849 AudioRenderClient_GetBuffer,
1850 AudioRenderClient_ReleaseBuffer
1853 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1854 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1856 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1858 if(!ppv)
1859 return E_POINTER;
1860 *ppv = NULL;
1862 if(IsEqualIID(riid, &IID_IUnknown) ||
1863 IsEqualIID(riid, &IID_IAudioCaptureClient))
1864 *ppv = iface;
1865 if(*ppv){
1866 IUnknown_AddRef((IUnknown*)*ppv);
1867 return S_OK;
1870 WARN("Unknown interface %s\n", debugstr_guid(riid));
1871 return E_NOINTERFACE;
1874 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1876 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1877 return IAudioClient_AddRef(&This->IAudioClient_iface);
1880 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1882 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1883 return IAudioClient_Release(&This->IAudioClient_iface);
1886 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1887 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1888 UINT64 *qpcpos)
1890 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1891 HRESULT hr;
1893 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1894 devpos, qpcpos);
1896 if(!data || !frames || !flags)
1897 return E_POINTER;
1899 EnterCriticalSection(&This->lock);
1901 if(This->buf_state != NOT_LOCKED){
1902 LeaveCriticalSection(&This->lock);
1903 return AUDCLNT_E_OUT_OF_ORDER;
1906 hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1907 if(FAILED(hr)){
1908 LeaveCriticalSection(&This->lock);
1909 return hr;
1912 *flags = 0;
1914 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1915 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1916 if(This->tmp_buffer_frames < *frames){
1917 if(This->tmp_buffer)
1918 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1919 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1920 *frames * This->fmt->nBlockAlign);
1921 if(!This->tmp_buffer){
1922 LeaveCriticalSection(&This->lock);
1923 return E_OUTOFMEMORY;
1925 This->tmp_buffer_frames = *frames;
1928 *data = This->tmp_buffer;
1929 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1930 This->fmt->nBlockAlign;
1931 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1932 frames_bytes = *frames * This->fmt->nBlockAlign;
1933 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1934 memcpy(This->tmp_buffer, This->local_buffer,
1935 frames_bytes - chunk_bytes);
1936 }else
1937 *data = This->local_buffer +
1938 This->lcl_offs_frames * This->fmt->nBlockAlign;
1940 This->buf_state = LOCKED_NORMAL;
1942 if(devpos || qpcpos)
1943 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1945 LeaveCriticalSection(&This->lock);
1947 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1950 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1951 IAudioCaptureClient *iface, UINT32 done)
1953 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1955 TRACE("(%p)->(%u)\n", This, done);
1957 EnterCriticalSection(&This->lock);
1959 if(This->buf_state == NOT_LOCKED){
1960 LeaveCriticalSection(&This->lock);
1961 return AUDCLNT_E_OUT_OF_ORDER;
1964 This->held_frames -= done;
1965 This->lcl_offs_frames += done;
1966 This->lcl_offs_frames %= This->bufsize_frames;
1968 This->buf_state = NOT_LOCKED;
1970 LeaveCriticalSection(&This->lock);
1972 return S_OK;
1975 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1976 IAudioCaptureClient *iface, UINT32 *frames)
1978 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1980 TRACE("(%p)->(%p)\n", This, frames);
1982 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1985 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1987 AudioCaptureClient_QueryInterface,
1988 AudioCaptureClient_AddRef,
1989 AudioCaptureClient_Release,
1990 AudioCaptureClient_GetBuffer,
1991 AudioCaptureClient_ReleaseBuffer,
1992 AudioCaptureClient_GetNextPacketSize
1995 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1996 REFIID riid, void **ppv)
1998 ACImpl *This = impl_from_IAudioClock(iface);
2000 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2002 if(!ppv)
2003 return E_POINTER;
2004 *ppv = NULL;
2006 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2007 *ppv = iface;
2008 else if(IsEqualIID(riid, &IID_IAudioClock2))
2009 *ppv = &This->IAudioClock2_iface;
2010 if(*ppv){
2011 IUnknown_AddRef((IUnknown*)*ppv);
2012 return S_OK;
2015 WARN("Unknown interface %s\n", debugstr_guid(riid));
2016 return E_NOINTERFACE;
2019 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2021 ACImpl *This = impl_from_IAudioClock(iface);
2022 return IAudioClient_AddRef(&This->IAudioClient_iface);
2025 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2027 ACImpl *This = impl_from_IAudioClock(iface);
2028 return IAudioClient_Release(&This->IAudioClient_iface);
2031 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2033 ACImpl *This = impl_from_IAudioClock(iface);
2035 TRACE("(%p)->(%p)\n", This, freq);
2037 *freq = This->fmt->nSamplesPerSec;
2039 return S_OK;
2042 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2043 UINT64 *qpctime)
2045 ACImpl *This = impl_from_IAudioClock(iface);
2046 UINT32 pad;
2047 HRESULT hr;
2049 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2051 if(!pos)
2052 return E_POINTER;
2054 EnterCriticalSection(&This->lock);
2056 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
2057 if(FAILED(hr)){
2058 LeaveCriticalSection(&This->lock);
2059 return hr;
2062 if(This->dataflow == eRender)
2063 *pos = This->written_frames - pad;
2064 else if(This->dataflow == eCapture)
2065 *pos = This->written_frames + pad;
2067 LeaveCriticalSection(&This->lock);
2069 if(qpctime){
2070 LARGE_INTEGER stamp, freq;
2071 QueryPerformanceCounter(&stamp);
2072 QueryPerformanceFrequency(&freq);
2073 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2076 return S_OK;
2079 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2080 DWORD *chars)
2082 ACImpl *This = impl_from_IAudioClock(iface);
2084 TRACE("(%p)->(%p)\n", This, chars);
2086 if(!chars)
2087 return E_POINTER;
2089 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2091 return S_OK;
2094 static const IAudioClockVtbl AudioClock_Vtbl =
2096 AudioClock_QueryInterface,
2097 AudioClock_AddRef,
2098 AudioClock_Release,
2099 AudioClock_GetFrequency,
2100 AudioClock_GetPosition,
2101 AudioClock_GetCharacteristics
2104 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2105 REFIID riid, void **ppv)
2107 ACImpl *This = impl_from_IAudioClock2(iface);
2108 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2111 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2113 ACImpl *This = impl_from_IAudioClock2(iface);
2114 return IAudioClient_AddRef(&This->IAudioClient_iface);
2117 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2119 ACImpl *This = impl_from_IAudioClock2(iface);
2120 return IAudioClient_Release(&This->IAudioClient_iface);
2123 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2124 UINT64 *pos, UINT64 *qpctime)
2126 ACImpl *This = impl_from_IAudioClock2(iface);
2128 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2130 return E_NOTIMPL;
2133 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2135 AudioClock2_QueryInterface,
2136 AudioClock2_AddRef,
2137 AudioClock2_Release,
2138 AudioClock2_GetDevicePosition
2141 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2143 AudioSessionWrapper *ret;
2145 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2146 sizeof(AudioSessionWrapper));
2147 if(!ret)
2148 return NULL;
2150 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2151 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2152 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2154 ret->ref = 1;
2156 ret->client = client;
2157 if(client){
2158 ret->session = client->session;
2159 AudioClient_AddRef(&client->IAudioClient_iface);
2162 return ret;
2165 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2166 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2168 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2170 if(!ppv)
2171 return E_POINTER;
2172 *ppv = NULL;
2174 if(IsEqualIID(riid, &IID_IUnknown) ||
2175 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2176 IsEqualIID(riid, &IID_IAudioSessionControl2))
2177 *ppv = iface;
2178 if(*ppv){
2179 IUnknown_AddRef((IUnknown*)*ppv);
2180 return S_OK;
2183 WARN("Unknown interface %s\n", debugstr_guid(riid));
2184 return E_NOINTERFACE;
2187 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2189 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2190 ULONG ref;
2191 ref = InterlockedIncrement(&This->ref);
2192 TRACE("(%p) Refcount now %u\n", This, ref);
2193 return ref;
2196 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2198 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2199 ULONG ref;
2200 ref = InterlockedDecrement(&This->ref);
2201 TRACE("(%p) Refcount now %u\n", This, ref);
2202 if(!ref){
2203 if(This->client){
2204 EnterCriticalSection(&This->client->lock);
2205 This->client->session_wrapper = NULL;
2206 LeaveCriticalSection(&This->client->lock);
2207 AudioClient_Release(&This->client->IAudioClient_iface);
2209 HeapFree(GetProcessHeap(), 0, This);
2211 return ref;
2214 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2215 AudioSessionState *state)
2217 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2218 ACImpl *client;
2220 TRACE("(%p)->(%p)\n", This, state);
2222 if(!state)
2223 return NULL_PTR_ERR;
2225 EnterCriticalSection(&g_sessions_lock);
2227 if(list_empty(&This->session->clients)){
2228 *state = AudioSessionStateExpired;
2229 LeaveCriticalSection(&g_sessions_lock);
2230 return S_OK;
2233 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2234 EnterCriticalSection(&client->lock);
2235 if(client->playing){
2236 *state = AudioSessionStateActive;
2237 LeaveCriticalSection(&client->lock);
2238 LeaveCriticalSection(&g_sessions_lock);
2239 return S_OK;
2241 LeaveCriticalSection(&client->lock);
2244 LeaveCriticalSection(&g_sessions_lock);
2246 *state = AudioSessionStateInactive;
2248 return S_OK;
2251 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2252 IAudioSessionControl2 *iface, WCHAR **name)
2254 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2256 FIXME("(%p)->(%p) - stub\n", This, name);
2258 return E_NOTIMPL;
2261 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2262 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2264 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2266 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2268 return E_NOTIMPL;
2271 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2272 IAudioSessionControl2 *iface, WCHAR **path)
2274 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2276 FIXME("(%p)->(%p) - stub\n", This, path);
2278 return E_NOTIMPL;
2281 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2282 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2284 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2286 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2288 return E_NOTIMPL;
2291 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2292 IAudioSessionControl2 *iface, GUID *group)
2294 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2296 FIXME("(%p)->(%p) - stub\n", This, group);
2298 return E_NOTIMPL;
2301 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2302 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2304 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2306 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2307 debugstr_guid(session));
2309 return E_NOTIMPL;
2312 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2313 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2315 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2317 FIXME("(%p)->(%p) - stub\n", This, events);
2319 return S_OK;
2322 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2323 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2325 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2327 FIXME("(%p)->(%p) - stub\n", This, events);
2329 return S_OK;
2332 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2333 IAudioSessionControl2 *iface, WCHAR **id)
2335 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2337 FIXME("(%p)->(%p) - stub\n", This, id);
2339 return E_NOTIMPL;
2342 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2343 IAudioSessionControl2 *iface, WCHAR **id)
2345 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2347 FIXME("(%p)->(%p) - stub\n", This, id);
2349 return E_NOTIMPL;
2352 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2353 IAudioSessionControl2 *iface, DWORD *pid)
2355 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2357 TRACE("(%p)->(%p)\n", This, pid);
2359 if(!pid)
2360 return E_POINTER;
2362 *pid = GetCurrentProcessId();
2364 return S_OK;
2367 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2368 IAudioSessionControl2 *iface)
2370 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2372 TRACE("(%p)\n", This);
2374 return S_FALSE;
2377 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2378 IAudioSessionControl2 *iface, BOOL optout)
2380 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2382 TRACE("(%p)->(%d)\n", This, optout);
2384 return S_OK;
2387 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2389 AudioSessionControl_QueryInterface,
2390 AudioSessionControl_AddRef,
2391 AudioSessionControl_Release,
2392 AudioSessionControl_GetState,
2393 AudioSessionControl_GetDisplayName,
2394 AudioSessionControl_SetDisplayName,
2395 AudioSessionControl_GetIconPath,
2396 AudioSessionControl_SetIconPath,
2397 AudioSessionControl_GetGroupingParam,
2398 AudioSessionControl_SetGroupingParam,
2399 AudioSessionControl_RegisterAudioSessionNotification,
2400 AudioSessionControl_UnregisterAudioSessionNotification,
2401 AudioSessionControl_GetSessionIdentifier,
2402 AudioSessionControl_GetSessionInstanceIdentifier,
2403 AudioSessionControl_GetProcessId,
2404 AudioSessionControl_IsSystemSoundsSession,
2405 AudioSessionControl_SetDuckingPreference
2408 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2409 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2411 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2413 if(!ppv)
2414 return E_POINTER;
2415 *ppv = NULL;
2417 if(IsEqualIID(riid, &IID_IUnknown) ||
2418 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2419 *ppv = iface;
2420 if(*ppv){
2421 IUnknown_AddRef((IUnknown*)*ppv);
2422 return S_OK;
2425 WARN("Unknown interface %s\n", debugstr_guid(riid));
2426 return E_NOINTERFACE;
2429 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2431 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2432 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2435 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2437 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2438 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2441 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2442 ISimpleAudioVolume *iface, float level, const GUID *context)
2444 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2445 AudioSession *session = This->session;
2447 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2449 if(level < 0.f || level > 1.f)
2450 return E_INVALIDARG;
2452 if(context)
2453 FIXME("Notifications not supported yet\n");
2455 EnterCriticalSection(&session->lock);
2457 session->master_vol = level;
2459 TRACE("OSS doesn't support setting volume\n");
2461 LeaveCriticalSection(&session->lock);
2463 return S_OK;
2466 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2467 ISimpleAudioVolume *iface, float *level)
2469 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2470 AudioSession *session = This->session;
2472 TRACE("(%p)->(%p)\n", session, level);
2474 if(!level)
2475 return NULL_PTR_ERR;
2477 *level = session->master_vol;
2479 return S_OK;
2482 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2483 BOOL mute, const GUID *context)
2485 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2486 AudioSession *session = This->session;
2488 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2490 EnterCriticalSection(&session->lock);
2492 if(!mute && session->mute){
2493 ACImpl *client;
2495 session->mute = mute;
2497 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2498 EnterCriticalSection(&client->lock);
2499 if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2500 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2501 strerror(errno));
2502 oss_write_data(client);
2503 LeaveCriticalSection(&client->lock);
2505 }else
2506 session->mute = mute;
2508 LeaveCriticalSection(&session->lock);
2510 return S_OK;
2513 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2514 BOOL *mute)
2516 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2517 AudioSession *session = This->session;
2519 TRACE("(%p)->(%p)\n", session, mute);
2521 if(!mute)
2522 return NULL_PTR_ERR;
2524 *mute = This->session->mute;
2526 return S_OK;
2529 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2531 SimpleAudioVolume_QueryInterface,
2532 SimpleAudioVolume_AddRef,
2533 SimpleAudioVolume_Release,
2534 SimpleAudioVolume_SetMasterVolume,
2535 SimpleAudioVolume_GetMasterVolume,
2536 SimpleAudioVolume_SetMute,
2537 SimpleAudioVolume_GetMute
2540 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2541 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2543 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2545 if(!ppv)
2546 return E_POINTER;
2547 *ppv = NULL;
2549 if(IsEqualIID(riid, &IID_IUnknown) ||
2550 IsEqualIID(riid, &IID_IAudioStreamVolume))
2551 *ppv = iface;
2552 if(*ppv){
2553 IUnknown_AddRef((IUnknown*)*ppv);
2554 return S_OK;
2557 WARN("Unknown interface %s\n", debugstr_guid(riid));
2558 return E_NOINTERFACE;
2561 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2563 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2564 return IAudioClient_AddRef(&This->IAudioClient_iface);
2567 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2569 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2570 return IAudioClient_Release(&This->IAudioClient_iface);
2573 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2574 IAudioStreamVolume *iface, UINT32 *out)
2576 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2578 TRACE("(%p)->(%p)\n", This, out);
2580 if(!out)
2581 return E_POINTER;
2583 *out = This->fmt->nChannels;
2585 return S_OK;
2588 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2589 IAudioStreamVolume *iface, UINT32 index, float level)
2591 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2593 TRACE("(%p)->(%d, %f)\n", This, index, level);
2595 if(level < 0.f || level > 1.f)
2596 return E_INVALIDARG;
2598 if(index >= This->fmt->nChannels)
2599 return E_INVALIDARG;
2601 EnterCriticalSection(&This->lock);
2603 This->vols[index] = level;
2605 TRACE("OSS doesn't support setting volume\n");
2607 LeaveCriticalSection(&This->lock);
2609 return S_OK;
2612 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2613 IAudioStreamVolume *iface, UINT32 index, float *level)
2615 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2617 TRACE("(%p)->(%d, %p)\n", This, index, level);
2619 if(!level)
2620 return E_POINTER;
2622 if(index >= This->fmt->nChannels)
2623 return E_INVALIDARG;
2625 *level = This->vols[index];
2627 return S_OK;
2630 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2631 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2633 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2634 int i;
2636 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2638 if(!levels)
2639 return E_POINTER;
2641 if(count != This->fmt->nChannels)
2642 return E_INVALIDARG;
2644 EnterCriticalSection(&This->lock);
2646 for(i = 0; i < count; ++i)
2647 This->vols[i] = levels[i];
2649 TRACE("OSS doesn't support setting volume\n");
2651 LeaveCriticalSection(&This->lock);
2653 return S_OK;
2656 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2657 IAudioStreamVolume *iface, UINT32 count, float *levels)
2659 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2660 int i;
2662 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2664 if(!levels)
2665 return E_POINTER;
2667 if(count != This->fmt->nChannels)
2668 return E_INVALIDARG;
2670 EnterCriticalSection(&This->lock);
2672 for(i = 0; i < count; ++i)
2673 levels[i] = This->vols[i];
2675 LeaveCriticalSection(&This->lock);
2677 return S_OK;
2680 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2682 AudioStreamVolume_QueryInterface,
2683 AudioStreamVolume_AddRef,
2684 AudioStreamVolume_Release,
2685 AudioStreamVolume_GetChannelCount,
2686 AudioStreamVolume_SetChannelVolume,
2687 AudioStreamVolume_GetChannelVolume,
2688 AudioStreamVolume_SetAllVolumes,
2689 AudioStreamVolume_GetAllVolumes
2692 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2693 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2695 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2697 if(!ppv)
2698 return E_POINTER;
2699 *ppv = NULL;
2701 if(IsEqualIID(riid, &IID_IUnknown) ||
2702 IsEqualIID(riid, &IID_IChannelAudioVolume))
2703 *ppv = iface;
2704 if(*ppv){
2705 IUnknown_AddRef((IUnknown*)*ppv);
2706 return S_OK;
2709 WARN("Unknown interface %s\n", debugstr_guid(riid));
2710 return E_NOINTERFACE;
2713 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2715 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2716 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2719 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2721 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2722 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2725 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2726 IChannelAudioVolume *iface, UINT32 *out)
2728 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2729 AudioSession *session = This->session;
2731 TRACE("(%p)->(%p)\n", session, out);
2733 if(!out)
2734 return NULL_PTR_ERR;
2736 *out = session->channel_count;
2738 return S_OK;
2741 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2742 IChannelAudioVolume *iface, UINT32 index, float level,
2743 const GUID *context)
2745 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2746 AudioSession *session = This->session;
2748 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2749 wine_dbgstr_guid(context));
2751 if(level < 0.f || level > 1.f)
2752 return E_INVALIDARG;
2754 if(index >= session->channel_count)
2755 return E_INVALIDARG;
2757 if(context)
2758 FIXME("Notifications not supported yet\n");
2760 EnterCriticalSection(&session->lock);
2762 session->channel_vols[index] = level;
2764 TRACE("OSS doesn't support setting volume\n");
2766 LeaveCriticalSection(&session->lock);
2768 return S_OK;
2771 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2772 IChannelAudioVolume *iface, UINT32 index, float *level)
2774 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2775 AudioSession *session = This->session;
2777 TRACE("(%p)->(%d, %p)\n", session, index, level);
2779 if(!level)
2780 return NULL_PTR_ERR;
2782 if(index >= session->channel_count)
2783 return E_INVALIDARG;
2785 *level = session->channel_vols[index];
2787 return S_OK;
2790 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2791 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2792 const GUID *context)
2794 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2795 AudioSession *session = This->session;
2796 int i;
2798 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2799 wine_dbgstr_guid(context));
2801 if(!levels)
2802 return NULL_PTR_ERR;
2804 if(count != session->channel_count)
2805 return E_INVALIDARG;
2807 if(context)
2808 FIXME("Notifications not supported yet\n");
2810 EnterCriticalSection(&session->lock);
2812 for(i = 0; i < count; ++i)
2813 session->channel_vols[i] = levels[i];
2815 TRACE("OSS doesn't support setting volume\n");
2817 LeaveCriticalSection(&session->lock);
2819 return S_OK;
2822 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2823 IChannelAudioVolume *iface, UINT32 count, float *levels)
2825 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2826 AudioSession *session = This->session;
2827 int i;
2829 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2831 if(!levels)
2832 return NULL_PTR_ERR;
2834 if(count != session->channel_count)
2835 return E_INVALIDARG;
2837 for(i = 0; i < count; ++i)
2838 levels[i] = session->channel_vols[i];
2840 return S_OK;
2843 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2845 ChannelAudioVolume_QueryInterface,
2846 ChannelAudioVolume_AddRef,
2847 ChannelAudioVolume_Release,
2848 ChannelAudioVolume_GetChannelCount,
2849 ChannelAudioVolume_SetChannelVolume,
2850 ChannelAudioVolume_GetChannelVolume,
2851 ChannelAudioVolume_SetAllVolumes,
2852 ChannelAudioVolume_GetAllVolumes
2855 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2856 REFIID riid, void **ppv)
2858 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2860 if(!ppv)
2861 return E_POINTER;
2862 *ppv = NULL;
2864 if(IsEqualIID(riid, &IID_IUnknown) ||
2865 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2866 IsEqualIID(riid, &IID_IAudioSessionManager2))
2867 *ppv = iface;
2868 if(*ppv){
2869 IUnknown_AddRef((IUnknown*)*ppv);
2870 return S_OK;
2873 WARN("Unknown interface %s\n", debugstr_guid(riid));
2874 return E_NOINTERFACE;
2877 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2879 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2880 ULONG ref;
2881 ref = InterlockedIncrement(&This->ref);
2882 TRACE("(%p) Refcount now %u\n", This, ref);
2883 return ref;
2886 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2888 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2889 ULONG ref;
2890 ref = InterlockedDecrement(&This->ref);
2891 TRACE("(%p) Refcount now %u\n", This, ref);
2892 if(!ref)
2893 HeapFree(GetProcessHeap(), 0, This);
2894 return ref;
2897 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2898 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2899 IAudioSessionControl **out)
2901 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2902 AudioSession *session;
2903 AudioSessionWrapper *wrapper;
2904 HRESULT hr;
2906 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2907 flags, out);
2909 hr = get_audio_session(session_guid, This->device, 0, &session);
2910 if(FAILED(hr))
2911 return hr;
2913 wrapper = AudioSessionWrapper_Create(NULL);
2914 if(!wrapper)
2915 return E_OUTOFMEMORY;
2917 wrapper->session = session;
2919 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2921 return S_OK;
2924 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2925 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2926 ISimpleAudioVolume **out)
2928 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2929 AudioSession *session;
2930 AudioSessionWrapper *wrapper;
2931 HRESULT hr;
2933 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2934 flags, out);
2936 hr = get_audio_session(session_guid, This->device, 0, &session);
2937 if(FAILED(hr))
2938 return hr;
2940 wrapper = AudioSessionWrapper_Create(NULL);
2941 if(!wrapper)
2942 return E_OUTOFMEMORY;
2944 wrapper->session = session;
2946 *out = &wrapper->ISimpleAudioVolume_iface;
2948 return S_OK;
2951 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2952 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2954 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2955 FIXME("(%p)->(%p) - stub\n", This, out);
2956 return E_NOTIMPL;
2959 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2960 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2962 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2963 FIXME("(%p)->(%p) - stub\n", This, notification);
2964 return E_NOTIMPL;
2967 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2968 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2970 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2971 FIXME("(%p)->(%p) - stub\n", This, notification);
2972 return E_NOTIMPL;
2975 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2976 IAudioSessionManager2 *iface, const WCHAR *session_id,
2977 IAudioVolumeDuckNotification *notification)
2979 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2980 FIXME("(%p)->(%p) - stub\n", This, notification);
2981 return E_NOTIMPL;
2984 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2985 IAudioSessionManager2 *iface,
2986 IAudioVolumeDuckNotification *notification)
2988 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2989 FIXME("(%p)->(%p) - stub\n", This, notification);
2990 return E_NOTIMPL;
2993 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2995 AudioSessionManager_QueryInterface,
2996 AudioSessionManager_AddRef,
2997 AudioSessionManager_Release,
2998 AudioSessionManager_GetAudioSessionControl,
2999 AudioSessionManager_GetSimpleAudioVolume,
3000 AudioSessionManager_GetSessionEnumerator,
3001 AudioSessionManager_RegisterSessionNotification,
3002 AudioSessionManager_UnregisterSessionNotification,
3003 AudioSessionManager_RegisterDuckNotification,
3004 AudioSessionManager_UnregisterDuckNotification
3007 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3008 IAudioSessionManager2 **out)
3010 SessionMgr *This;
3012 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3013 if(!This)
3014 return E_OUTOFMEMORY;
3016 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3017 This->device = device;
3018 This->ref = 1;
3020 *out = &This->IAudioSessionManager2_iface;
3022 return S_OK;