ddraw: Make the OpenGL renderer the default one.
[wine/multimedia.git] / dlls / wineoss.drv / mmdevdrv.c
blob64d60fec9837202f4e162e73308e4609df1bdff2
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"
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;
123 BOOL initted, playing;
124 UINT64 written_frames, held_frames, tmp_buffer_frames, inbuf_frames;
125 UINT32 period_us, bufsize_frames;
126 UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
128 BYTE *local_buffer, *tmp_buffer;
129 int buf_state;
130 HANDLE timer;
132 CRITICAL_SECTION lock;
134 AudioSession *session;
135 AudioSessionWrapper *session_wrapper;
137 struct list entry;
140 enum BufferStates {
141 NOT_LOCKED = 0,
142 LOCKED_NORMAL, /* public buffer piece is from local_buffer */
143 LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
146 typedef struct _SessionMgr {
147 IAudioSessionManager2 IAudioSessionManager2_iface;
149 LONG ref;
151 IMMDevice *device;
152 } SessionMgr;
154 static HANDLE g_timer_q;
156 static CRITICAL_SECTION g_sessions_lock;
157 static struct list g_sessions = LIST_INIT(g_sessions);
159 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
160 static HRESULT oss_setvol(ACImpl *This, UINT32 index);
162 static const IAudioClientVtbl AudioClient_Vtbl;
163 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
164 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
165 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
166 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
167 static const IAudioClockVtbl AudioClock_Vtbl;
168 static const IAudioClock2Vtbl AudioClock2_Vtbl;
169 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
170 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
171 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
173 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
175 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
178 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
180 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
183 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
185 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
188 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
190 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
193 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
195 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
198 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
200 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
203 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
205 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
208 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
210 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
213 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
215 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
218 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
220 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
223 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
225 if(reason == DLL_PROCESS_ATTACH){
226 g_timer_q = CreateTimerQueue();
227 if(!g_timer_q)
228 return FALSE;
230 InitializeCriticalSection(&g_sessions_lock);
233 return TRUE;
236 static UINT get_default_index(EDataFlow flow, char **keys, UINT num)
238 int fd = -1, err, i;
239 oss_audioinfo ai;
241 if(flow == eRender)
242 fd = open("/dev/dsp", O_WRONLY);
243 else
244 fd = open("/dev/dsp", O_RDONLY);
246 if(fd < 0){
247 WARN("Couldn't open default device!\n");
248 return 0;
251 ai.dev = -1;
252 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
253 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
254 close(fd);
255 return 0;
258 close(fd);
260 TRACE("Default devnode: %s\n", ai.devnode);
261 for(i = 0; i < num; ++i)
262 if(!strcmp(ai.devnode, keys[i]))
263 return i;
265 WARN("Couldn't find default device! Choosing first.\n");
266 return 0;
269 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, char ***keys,
270 UINT *num, UINT *def_index)
272 int i, mixer_fd;
273 oss_sysinfo sysinfo;
274 static int print_once = 0;
276 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
278 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
279 if(mixer_fd < 0){
280 ERR("OSS /dev/mixer doesn't seem to exist\n");
281 return AUDCLNT_E_SERVICE_NOT_RUNNING;
284 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
285 close(mixer_fd);
287 if(errno == EINVAL){
288 ERR("OSS version too old, need at least OSSv4\n");
289 return AUDCLNT_E_SERVICE_NOT_RUNNING;
292 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
293 return E_FAIL;
296 if(!print_once){
297 TRACE("OSS sysinfo:\n");
298 TRACE("product: %s\n", sysinfo.product);
299 TRACE("version: %s\n", sysinfo.version);
300 TRACE("versionnum: %x\n", sysinfo.versionnum);
301 TRACE("numaudios: %d\n", sysinfo.numaudios);
302 TRACE("nummixers: %d\n", sysinfo.nummixers);
303 TRACE("numcards: %d\n", sysinfo.numcards);
304 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
305 print_once = 1;
308 if(sysinfo.numaudios <= 0){
309 WARN("No audio devices!\n");
310 close(mixer_fd);
311 return AUDCLNT_E_SERVICE_NOT_RUNNING;
314 *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
315 *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
317 *num = 0;
318 for(i = 0; i < sysinfo.numaudios; ++i){
319 oss_audioinfo ai = {0};
320 int fd;
322 ai.dev = i;
323 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
324 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
325 strerror(errno));
326 continue;
329 if(flow == eRender)
330 fd = open(ai.devnode, O_WRONLY, 0);
331 else
332 fd = open(ai.devnode, O_RDONLY, 0);
333 if(fd < 0){
334 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
335 ai.devnode, errno, strerror(errno));
336 continue;
338 close(fd);
340 if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
341 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
342 size_t len;
344 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
345 strlen(ai.devnode) + 1);
346 if(!(*keys)[*num]){
347 for(i = 0; i < *num; ++i){
348 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
349 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
351 HeapFree(GetProcessHeap(), 0, *ids);
352 HeapFree(GetProcessHeap(), 0, *keys);
353 close(mixer_fd);
354 return E_OUTOFMEMORY;
356 strcpy((*keys)[*num], ai.devnode);
358 len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
359 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
360 len * sizeof(WCHAR));
361 if(!(*ids)[*num]){
362 HeapFree(GetProcessHeap(), 0, (*keys)[*num]);
363 for(i = 0; i < *num; ++i){
364 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
365 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
367 HeapFree(GetProcessHeap(), 0, *ids);
368 HeapFree(GetProcessHeap(), 0, *keys);
369 close(mixer_fd);
370 return E_OUTOFMEMORY;
372 MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
373 (*ids)[*num], len);
375 (*num)++;
379 close(mixer_fd);
381 *def_index = get_default_index(flow, *keys, *num);
383 return S_OK;
386 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
387 EDataFlow dataflow, IAudioClient **out)
389 ACImpl *This;
391 TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
393 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
394 if(!This)
395 return E_OUTOFMEMORY;
397 if(dataflow == eRender)
398 This->fd = open(devnode, O_WRONLY, 0);
399 else if(dataflow == eCapture)
400 This->fd = open(devnode, O_RDONLY, 0);
401 else{
402 HeapFree(GetProcessHeap(), 0, This);
403 return E_INVALIDARG;
405 if(This->fd < 0){
406 ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
407 strerror(errno));
408 HeapFree(GetProcessHeap(), 0, This);
409 return AUDCLNT_E_DEVICE_INVALIDATED;
412 This->dataflow = dataflow;
414 This->ai.dev = -1;
415 if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
416 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode,
417 errno, strerror(errno));
418 close(This->fd);
419 HeapFree(GetProcessHeap(), 0, This);
420 return E_FAIL;
423 TRACE("OSS audioinfo:\n");
424 TRACE("devnode: %s\n", This->ai.devnode);
425 TRACE("name: %s\n", This->ai.name);
426 TRACE("busy: %x\n", This->ai.busy);
427 TRACE("caps: %x\n", This->ai.caps);
428 TRACE("iformats: %x\n", This->ai.iformats);
429 TRACE("oformats: %x\n", This->ai.oformats);
430 TRACE("enabled: %d\n", This->ai.enabled);
431 TRACE("min_rate: %d\n", This->ai.min_rate);
432 TRACE("max_rate: %d\n", This->ai.max_rate);
433 TRACE("min_channels: %d\n", This->ai.min_channels);
434 TRACE("max_channels: %d\n", This->ai.max_channels);
436 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
437 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
438 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
439 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
440 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
441 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
443 InitializeCriticalSection(&This->lock);
445 This->parent = dev;
446 IMMDevice_AddRef(This->parent);
448 IAudioClient_AddRef(&This->IAudioClient_iface);
450 *out = &This->IAudioClient_iface;
452 return S_OK;
455 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
456 REFIID riid, void **ppv)
458 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
460 if(!ppv)
461 return E_POINTER;
462 *ppv = NULL;
463 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
464 *ppv = iface;
465 if(*ppv){
466 IUnknown_AddRef((IUnknown*)*ppv);
467 return S_OK;
469 WARN("Unknown interface %s\n", debugstr_guid(riid));
470 return E_NOINTERFACE;
473 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
475 ACImpl *This = impl_from_IAudioClient(iface);
476 ULONG ref;
477 ref = InterlockedIncrement(&This->ref);
478 TRACE("(%p) Refcount now %u\n", This, ref);
479 return ref;
482 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
484 ACImpl *This = impl_from_IAudioClient(iface);
485 ULONG ref;
486 ref = InterlockedDecrement(&This->ref);
487 TRACE("(%p) Refcount now %u\n", This, ref);
488 if(!ref){
489 IAudioClient_Stop(iface);
490 IMMDevice_Release(This->parent);
491 DeleteCriticalSection(&This->lock);
492 close(This->fd);
493 if(This->initted){
494 EnterCriticalSection(&g_sessions_lock);
495 list_remove(&This->entry);
496 LeaveCriticalSection(&g_sessions_lock);
498 HeapFree(GetProcessHeap(), 0, This->vols);
499 HeapFree(GetProcessHeap(), 0, This->local_buffer);
500 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
501 CoTaskMemFree(This->fmt);
502 HeapFree(GetProcessHeap(), 0, This);
504 return ref;
507 static void dump_fmt(const WAVEFORMATEX *fmt)
509 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
510 switch(fmt->wFormatTag){
511 case WAVE_FORMAT_PCM:
512 TRACE("WAVE_FORMAT_PCM");
513 break;
514 case WAVE_FORMAT_IEEE_FLOAT:
515 TRACE("WAVE_FORMAT_IEEE_FLOAT");
516 break;
517 case WAVE_FORMAT_EXTENSIBLE:
518 TRACE("WAVE_FORMAT_EXTENSIBLE");
519 break;
520 default:
521 TRACE("Unknown");
522 break;
524 TRACE(")\n");
526 TRACE("nChannels: %u\n", fmt->nChannels);
527 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
528 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
529 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
530 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
531 TRACE("cbSize: %u\n", fmt->cbSize);
533 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
534 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
535 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
536 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
537 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
541 static DWORD get_channel_mask(unsigned int channels)
543 switch(channels){
544 case 0:
545 return 0;
546 case 1:
547 return SPEAKER_FRONT_CENTER;
548 case 2:
549 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
550 case 3:
551 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
552 SPEAKER_LOW_FREQUENCY;
553 case 4:
554 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
555 SPEAKER_BACK_RIGHT;
556 case 5:
557 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
558 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
559 case 6:
560 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
561 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
562 case 7:
563 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
564 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
565 SPEAKER_BACK_CENTER;
567 FIXME("Unknown speaker configuration: %u\n", channels);
568 return 0;
571 static int get_oss_format(const WAVEFORMATEX *fmt)
573 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
575 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
576 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
577 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
578 switch(fmt->wBitsPerSample){
579 case 8:
580 return AFMT_U8;
581 case 16:
582 return AFMT_S16_LE;
583 case 24:
584 return AFMT_S24_LE;
585 case 32:
586 return AFMT_S32_LE;
588 return -1;
591 #ifdef AFMT_FLOAT
592 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
593 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
594 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
595 if(fmt->wBitsPerSample != 32)
596 return -1;
598 return AFMT_FLOAT;
600 #endif
602 return -1;
605 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
607 WAVEFORMATEX *ret;
608 size_t size;
610 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
611 size = sizeof(WAVEFORMATEXTENSIBLE);
612 else
613 size = sizeof(WAVEFORMATEX);
615 ret = CoTaskMemAlloc(size);
616 if(!ret)
617 return NULL;
619 memcpy(ret, fmt, size);
621 ret->cbSize = size - sizeof(WAVEFORMATEX);
623 return ret;
626 static HRESULT setup_oss_device(ACImpl *This, const WAVEFORMATEX *fmt,
627 WAVEFORMATEX **out)
629 int tmp, oss_format;
630 double tenth;
631 HRESULT ret = S_OK;
632 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
633 WAVEFORMATEX *closest = NULL;
635 tmp = oss_format = get_oss_format(fmt);
636 if(oss_format < 0)
637 return AUDCLNT_E_UNSUPPORTED_FORMAT;
638 if(ioctl(This->fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
639 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
640 return E_FAIL;
642 if(tmp != oss_format){
643 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
644 return AUDCLNT_E_UNSUPPORTED_FORMAT;
647 closest = clone_format(fmt);
649 tmp = fmt->nSamplesPerSec;
650 if(ioctl(This->fd, SNDCTL_DSP_SPEED, &tmp) < 0){
651 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
652 CoTaskMemFree(closest);
653 return E_FAIL;
655 tenth = fmt->nSamplesPerSec * 0.1;
656 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
657 ret = S_FALSE;
658 closest->nSamplesPerSec = tmp;
661 tmp = fmt->nChannels;
662 if(ioctl(This->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
663 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
664 CoTaskMemFree(closest);
665 return E_FAIL;
667 if(tmp != fmt->nChannels){
668 ret = S_FALSE;
669 closest->nChannels = tmp;
672 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
673 DWORD mask = get_channel_mask(closest->nChannels);
675 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
677 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
678 fmtex->dwChannelMask != mask)
679 ret = S_FALSE;
682 if(ret == S_OK || !out){
683 CoTaskMemFree( closest);
684 if(out)
685 *out = NULL;
686 }else{
687 closest->nBlockAlign =
688 closest->nChannels * closest->wBitsPerSample / 8;
689 closest->nAvgBytesPerSec =
690 closest->nBlockAlign * closest->nSamplesPerSec;
691 *out = closest;
694 TRACE("returning: %08x\n", ret);
695 return ret;
698 static void session_init_vols(AudioSession *session, UINT channels)
700 if(session->channel_count < channels){
701 UINT i;
703 if(session->channel_vols)
704 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
705 session->channel_vols, sizeof(float) * channels);
706 else
707 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
708 sizeof(float) * channels);
709 if(!session->channel_vols)
710 return;
712 for(i = session->channel_count; i < channels; ++i)
713 session->channel_vols[i] = 1.f;
715 session->channel_count = channels;
719 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
720 UINT num_channels)
722 AudioSession *ret;
724 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
725 if(!ret)
726 return NULL;
728 memcpy(&ret->guid, guid, sizeof(GUID));
730 ret->device = device;
732 list_init(&ret->clients);
734 list_add_head(&g_sessions, &ret->entry);
736 InitializeCriticalSection(&ret->lock);
738 session_init_vols(ret, num_channels);
740 ret->master_vol = 1.f;
742 return ret;
745 /* if channels == 0, then this will return or create a session with
746 * matching dataflow and GUID. otherwise, channels must also match */
747 static HRESULT get_audio_session(const GUID *sessionguid,
748 IMMDevice *device, UINT channels, AudioSession **out)
750 AudioSession *session;
752 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
753 *out = create_session(&GUID_NULL, device, channels);
754 if(!*out)
755 return E_OUTOFMEMORY;
757 return S_OK;
760 *out = NULL;
761 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
762 if(session->device == device &&
763 IsEqualGUID(sessionguid, &session->guid)){
764 session_init_vols(session, channels);
765 *out = session;
766 break;
770 if(!*out){
771 *out = create_session(sessionguid, device, channels);
772 if(!*out)
773 return E_OUTOFMEMORY;
776 return S_OK;
779 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
780 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
781 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
782 const GUID *sessionguid)
784 ACImpl *This = impl_from_IAudioClient(iface);
785 int mask, i;
786 HRESULT hr;
788 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
789 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
791 if(!fmt)
792 return E_POINTER;
794 dump_fmt(fmt);
796 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
797 return AUDCLNT_E_NOT_INITIALIZED;
799 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
800 AUDCLNT_STREAMFLAGS_LOOPBACK |
801 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
802 AUDCLNT_STREAMFLAGS_NOPERSIST |
803 AUDCLNT_STREAMFLAGS_RATEADJUST |
804 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
805 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
806 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
807 TRACE("Unknown flags: %08x\n", flags);
808 return E_INVALIDARG;
811 EnterCriticalSection(&This->lock);
813 if(This->initted){
814 LeaveCriticalSection(&This->lock);
815 return AUDCLNT_E_ALREADY_INITIALIZED;
818 hr = setup_oss_device(This, fmt, NULL);
819 if(hr == S_FALSE){
820 LeaveCriticalSection(&This->lock);
821 return AUDCLNT_E_UNSUPPORTED_FORMAT;
823 if(FAILED(hr)){
824 LeaveCriticalSection(&This->lock);
825 return hr;
828 mask = 0;
829 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
830 LeaveCriticalSection(&This->lock);
831 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
832 return E_FAIL;
835 mask = (100 << 8) | 100;
836 if(ioctl(This->fd, SNDCTL_DSP_SETPLAYVOL, &mask) < 0)
837 WARN("SETPLAYVOL failed: %d (%s)\n", errno, strerror(errno));
839 This->fmt = clone_format(fmt);
840 if(!This->fmt){
841 LeaveCriticalSection(&This->lock);
842 return E_OUTOFMEMORY;
845 if(period)
846 This->period_us = period / 10;
847 else
848 This->period_us = DefaultPeriod / 10;
850 if(!duration)
851 duration = 300000; /* 0.03s */
852 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
853 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
854 This->bufsize_frames * fmt->nBlockAlign);
855 if(!This->local_buffer){
856 CoTaskMemFree(This->fmt);
857 This->fmt = NULL;
858 LeaveCriticalSection(&This->lock);
859 return E_OUTOFMEMORY;
862 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
863 if(!This->vols){
864 CoTaskMemFree(This->fmt);
865 This->fmt = NULL;
866 LeaveCriticalSection(&This->lock);
867 return E_OUTOFMEMORY;
870 for(i = 0; i < fmt->nChannels; ++i)
871 This->vols[i] = 1.f;
873 This->share = mode;
874 This->flags = flags;
876 EnterCriticalSection(&g_sessions_lock);
878 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
879 &This->session);
880 if(FAILED(hr)){
881 LeaveCriticalSection(&g_sessions_lock);
882 HeapFree(GetProcessHeap(), 0, This->vols);
883 This->vols = NULL;
884 CoTaskMemFree(This->fmt);
885 This->fmt = NULL;
886 LeaveCriticalSection(&This->lock);
887 return hr;
890 list_add_tail(&This->session->clients, &This->entry);
892 LeaveCriticalSection(&g_sessions_lock);
894 This->initted = TRUE;
896 oss_setvol(This, -1);
898 LeaveCriticalSection(&This->lock);
900 return S_OK;
903 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
904 UINT32 *frames)
906 ACImpl *This = impl_from_IAudioClient(iface);
908 TRACE("(%p)->(%p)\n", This, frames);
910 if(!frames)
911 return E_POINTER;
913 EnterCriticalSection(&This->lock);
915 if(!This->initted){
916 LeaveCriticalSection(&This->lock);
917 return AUDCLNT_E_NOT_INITIALIZED;
920 *frames = This->bufsize_frames;
922 LeaveCriticalSection(&This->lock);
924 return S_OK;
927 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
928 REFERENCE_TIME *latency)
930 ACImpl *This = impl_from_IAudioClient(iface);
932 TRACE("(%p)->(%p)\n", This, latency);
934 if(!latency)
935 return E_POINTER;
937 EnterCriticalSection(&This->lock);
939 if(!This->initted){
940 LeaveCriticalSection(&This->lock);
941 return AUDCLNT_E_NOT_INITIALIZED;
944 if(This->dataflow == eRender){
945 int delay_bytes;
946 double delay_s;
948 if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
949 LeaveCriticalSection(&This->lock);
950 WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
951 return E_FAIL;
954 delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
955 This->fmt->nBlockAlign);
957 *latency = delay_s * 10000000;
958 }else
959 *latency = 10000; /* OSS doesn't provide input latency */
961 LeaveCriticalSection(&This->lock);
963 return S_OK;
966 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
967 UINT32 *numpad)
969 ACImpl *This = impl_from_IAudioClient(iface);
970 audio_buf_info bi;
972 TRACE("(%p)->(%p)\n", This, numpad);
974 if(!numpad)
975 return E_POINTER;
977 EnterCriticalSection(&This->lock);
979 if(!This->initted){
980 LeaveCriticalSection(&This->lock);
981 return AUDCLNT_E_NOT_INITIALIZED;
984 if(This->dataflow == eRender){
985 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
986 LeaveCriticalSection(&This->lock);
987 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
988 return E_FAIL;
991 *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
992 This->fmt->nBlockAlign;
994 /* when the OSS buffer has less than one fragment of data, including
995 * no data, it often reports it as some non-zero portion of a
996 * fragment. when it has more than one fragment of data, it reports
997 * it as some multiple of that portion of the fragment size.
999 * so, we have to do some ugly workarounds to report the timing
1000 * as accurately as possible */
1001 if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
1002 *numpad = This->inbuf_frames;
1003 This->inbuf_frames = 0;
1004 }else{
1005 if(*numpad < This->inbuf_frames)
1006 This->inbuf_frames = *numpad;
1007 else
1008 *numpad = This->inbuf_frames;
1010 }else if(This->dataflow == eCapture){
1011 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1012 LeaveCriticalSection(&This->lock);
1013 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1014 return E_FAIL;
1017 if(bi.bytes <= bi.fragsize)
1018 *numpad = 0;
1019 else
1020 *numpad = bi.bytes / This->fmt->nBlockAlign;
1021 }else{
1022 LeaveCriticalSection(&This->lock);
1023 return E_UNEXPECTED;
1026 *numpad += This->held_frames;
1028 LeaveCriticalSection(&This->lock);
1030 return S_OK;
1033 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1034 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1035 WAVEFORMATEX **outpwfx)
1037 ACImpl *This = impl_from_IAudioClient(iface);
1038 HRESULT ret;
1040 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1042 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1043 return E_POINTER;
1045 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1046 return E_INVALIDARG;
1048 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1049 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1050 return E_INVALIDARG;
1052 dump_fmt(pwfx);
1054 EnterCriticalSection(&This->lock);
1056 ret = setup_oss_device(This, pwfx, outpwfx);
1058 LeaveCriticalSection(&This->lock);
1060 return ret;
1063 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1064 WAVEFORMATEX **pwfx)
1066 ACImpl *This = impl_from_IAudioClient(iface);
1067 WAVEFORMATEXTENSIBLE *fmt;
1068 int formats;
1070 TRACE("(%p)->(%p)\n", This, pwfx);
1072 if(!pwfx)
1073 return E_POINTER;
1074 *pwfx = NULL;
1076 if(This->dataflow == eRender)
1077 formats = This->ai.oformats;
1078 else if(This->dataflow == eCapture)
1079 formats = This->ai.iformats;
1080 else
1081 return E_UNEXPECTED;
1083 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1084 if(!fmt)
1085 return E_OUTOFMEMORY;
1087 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1088 if(formats & AFMT_S16_LE){
1089 fmt->Format.wBitsPerSample = 16;
1090 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1091 #ifdef AFMT_FLOAT
1092 }else if(formats & AFMT_FLOAT){
1093 fmt->Format.wBitsPerSample = 32;
1094 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1095 #endif
1096 }else if(formats & AFMT_U8){
1097 fmt->Format.wBitsPerSample = 8;
1098 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1099 }else if(formats & AFMT_S32_LE){
1100 fmt->Format.wBitsPerSample = 32;
1101 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1102 }else if(formats & AFMT_S24_LE){
1103 fmt->Format.wBitsPerSample = 24;
1104 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1105 }else{
1106 ERR("Didn't recognize any available OSS formats: %x\n", formats);
1107 CoTaskMemFree(fmt);
1108 return E_FAIL;
1111 fmt->Format.nChannels = This->ai.max_channels;
1112 fmt->Format.nSamplesPerSec = This->ai.max_rate;
1113 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1115 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1116 fmt->Format.nChannels) / 8;
1117 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1118 fmt->Format.nBlockAlign;
1120 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1121 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1123 *pwfx = (WAVEFORMATEX*)fmt;
1124 dump_fmt(*pwfx);
1126 return S_OK;
1129 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1130 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1132 ACImpl *This = impl_from_IAudioClient(iface);
1134 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1136 if(!defperiod && !minperiod)
1137 return E_POINTER;
1139 EnterCriticalSection(&This->lock);
1141 if(defperiod)
1142 *defperiod = DefaultPeriod;
1143 if(minperiod)
1144 *minperiod = MinimumPeriod;
1146 LeaveCriticalSection(&This->lock);
1148 return S_OK;
1151 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1153 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1154 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1155 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1156 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1157 This->fmt->wBitsPerSample == 8)
1158 memset(buf, 128, frames * This->fmt->nBlockAlign);
1159 else
1160 memset(buf, 0, frames * This->fmt->nBlockAlign);
1163 static void oss_write_data(ACImpl *This)
1165 ssize_t written;
1166 UINT32 written_frames;
1167 size_t to_write;
1168 BYTE *buf =
1169 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1171 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1172 to_write = This->bufsize_frames - This->lcl_offs_frames;
1173 else
1174 to_write = This->held_frames;
1176 if(This->session->mute)
1177 oss_silence_buffer(This, buf, to_write);
1179 written = write(This->fd, buf, to_write * This->fmt->nBlockAlign);
1180 if(written < 0){
1181 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1182 return;
1184 written_frames = written / This->fmt->nBlockAlign;
1186 This->lcl_offs_frames += written_frames;
1187 This->lcl_offs_frames %= This->bufsize_frames;
1188 This->held_frames -= written_frames;
1189 This->inbuf_frames += written_frames;
1191 if(written_frames < to_write){
1192 /* OSS buffer probably full */
1193 return;
1196 if(This->held_frames){
1197 /* wrapped and have some data back at the start to write */
1199 if(This->session->mute)
1200 oss_silence_buffer(This, This->local_buffer, This->held_frames);
1202 written = write(This->fd, This->local_buffer,
1203 This->held_frames * This->fmt->nBlockAlign);
1204 if(written < 0){
1205 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1206 return;
1208 written_frames = written / This->fmt->nBlockAlign;
1210 This->lcl_offs_frames += written_frames;
1211 This->lcl_offs_frames %= This->bufsize_frames;
1212 This->held_frames -= written_frames;
1213 This->inbuf_frames += written_frames;
1217 static void oss_read_data(ACImpl *This)
1219 UINT64 pos, readable;
1220 audio_buf_info bi;
1221 ssize_t nread;
1223 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1224 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1225 return;
1228 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1229 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1231 if(bi.bytes < readable)
1232 readable = bi.bytes;
1234 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1235 readable);
1236 if(nread < 0){
1237 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1238 return;
1241 This->held_frames += nread / This->fmt->nBlockAlign;
1243 if(This->held_frames > This->bufsize_frames){
1244 WARN("Overflow of unread data\n");
1245 This->lcl_offs_frames += This->held_frames;
1246 This->lcl_offs_frames %= This->bufsize_frames;
1247 This->held_frames = This->bufsize_frames;
1251 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1253 ACImpl *This = user;
1255 EnterCriticalSection(&This->lock);
1257 if(This->dataflow == eRender && This->held_frames)
1258 oss_write_data(This);
1259 else if(This->dataflow == eCapture)
1260 oss_read_data(This);
1262 if(This->event)
1263 SetEvent(This->event);
1265 LeaveCriticalSection(&This->lock);
1268 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1270 ACImpl *This = impl_from_IAudioClient(iface);
1271 int mask;
1273 TRACE("(%p)\n", This);
1275 EnterCriticalSection(&This->lock);
1277 if(!This->initted){
1278 LeaveCriticalSection(&This->lock);
1279 return AUDCLNT_E_NOT_INITIALIZED;
1282 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1283 LeaveCriticalSection(&This->lock);
1284 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1287 if(This->playing){
1288 LeaveCriticalSection(&This->lock);
1289 return AUDCLNT_E_NOT_STOPPED;
1292 if(This->dataflow == eRender)
1293 mask = PCM_ENABLE_OUTPUT;
1294 else if(This->dataflow == eCapture)
1295 mask = PCM_ENABLE_INPUT;
1296 else{
1297 LeaveCriticalSection(&This->lock);
1298 return E_UNEXPECTED;
1301 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1302 LeaveCriticalSection(&This->lock);
1303 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1304 return E_FAIL;
1307 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1308 oss_period_callback, This, 0, This->period_us / 1000,
1309 WT_EXECUTEINTIMERTHREAD))
1310 ERR("Unable to create period timer: %u\n", GetLastError());
1312 This->playing = TRUE;
1314 LeaveCriticalSection(&This->lock);
1316 return S_OK;
1319 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1321 ACImpl *This = impl_from_IAudioClient(iface);
1322 int mask;
1324 TRACE("(%p)\n", This);
1326 EnterCriticalSection(&This->lock);
1328 if(!This->initted){
1329 LeaveCriticalSection(&This->lock);
1330 return AUDCLNT_E_NOT_INITIALIZED;
1333 if(!This->playing){
1334 LeaveCriticalSection(&This->lock);
1335 return S_FALSE;
1338 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1339 DeleteTimerQueueTimer(g_timer_q, This->timer,
1340 INVALID_HANDLE_VALUE);
1341 This->timer = NULL;
1344 if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1345 LeaveCriticalSection(&This->lock);
1346 WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1347 return E_FAIL;
1350 mask = 0;
1351 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1352 LeaveCriticalSection(&This->lock);
1353 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1354 return E_FAIL;
1357 This->playing = FALSE;
1359 LeaveCriticalSection(&This->lock);
1361 return S_OK;
1364 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1366 ACImpl *This = impl_from_IAudioClient(iface);
1368 TRACE("(%p)\n", This);
1370 EnterCriticalSection(&This->lock);
1372 if(!This->initted){
1373 LeaveCriticalSection(&This->lock);
1374 return AUDCLNT_E_NOT_INITIALIZED;
1377 if(This->playing){
1378 LeaveCriticalSection(&This->lock);
1379 return AUDCLNT_E_NOT_STOPPED;
1382 if(This->buf_state != NOT_LOCKED){
1383 LeaveCriticalSection(&This->lock);
1384 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1387 This->written_frames = 0;
1388 This->inbuf_frames = 0;
1389 This->held_frames = 0;
1391 if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1392 WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1394 LeaveCriticalSection(&This->lock);
1396 return S_OK;
1399 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1400 HANDLE event)
1402 ACImpl *This = impl_from_IAudioClient(iface);
1404 TRACE("(%p)->(%p)\n", This, event);
1406 if(!event)
1407 return E_INVALIDARG;
1409 EnterCriticalSection(&This->lock);
1411 if(!This->initted){
1412 LeaveCriticalSection(&This->lock);
1413 return AUDCLNT_E_NOT_INITIALIZED;
1416 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1417 LeaveCriticalSection(&This->lock);
1418 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1421 This->event = event;
1423 LeaveCriticalSection(&This->lock);
1425 return S_OK;
1428 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1429 void **ppv)
1431 ACImpl *This = impl_from_IAudioClient(iface);
1433 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1435 if(!ppv)
1436 return E_POINTER;
1437 *ppv = NULL;
1439 EnterCriticalSection(&This->lock);
1441 if(!This->initted){
1442 LeaveCriticalSection(&This->lock);
1443 return AUDCLNT_E_NOT_INITIALIZED;
1446 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1447 if(This->dataflow != eRender){
1448 LeaveCriticalSection(&This->lock);
1449 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1451 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1452 *ppv = &This->IAudioRenderClient_iface;
1453 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1454 if(This->dataflow != eCapture){
1455 LeaveCriticalSection(&This->lock);
1456 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1458 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1459 *ppv = &This->IAudioCaptureClient_iface;
1460 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1461 IAudioClock_AddRef(&This->IAudioClock_iface);
1462 *ppv = &This->IAudioClock_iface;
1463 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1464 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1465 *ppv = &This->IAudioStreamVolume_iface;
1466 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1467 if(!This->session_wrapper){
1468 This->session_wrapper = AudioSessionWrapper_Create(This);
1469 if(!This->session_wrapper){
1470 LeaveCriticalSection(&This->lock);
1471 return E_OUTOFMEMORY;
1473 }else
1474 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1476 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1477 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1478 if(!This->session_wrapper){
1479 This->session_wrapper = AudioSessionWrapper_Create(This);
1480 if(!This->session_wrapper){
1481 LeaveCriticalSection(&This->lock);
1482 return E_OUTOFMEMORY;
1484 }else
1485 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1487 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1488 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1489 if(!This->session_wrapper){
1490 This->session_wrapper = AudioSessionWrapper_Create(This);
1491 if(!This->session_wrapper){
1492 LeaveCriticalSection(&This->lock);
1493 return E_OUTOFMEMORY;
1495 }else
1496 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1498 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1501 if(*ppv){
1502 LeaveCriticalSection(&This->lock);
1503 return S_OK;
1506 LeaveCriticalSection(&This->lock);
1508 FIXME("stub %s\n", debugstr_guid(riid));
1509 return E_NOINTERFACE;
1512 static const IAudioClientVtbl AudioClient_Vtbl =
1514 AudioClient_QueryInterface,
1515 AudioClient_AddRef,
1516 AudioClient_Release,
1517 AudioClient_Initialize,
1518 AudioClient_GetBufferSize,
1519 AudioClient_GetStreamLatency,
1520 AudioClient_GetCurrentPadding,
1521 AudioClient_IsFormatSupported,
1522 AudioClient_GetMixFormat,
1523 AudioClient_GetDevicePeriod,
1524 AudioClient_Start,
1525 AudioClient_Stop,
1526 AudioClient_Reset,
1527 AudioClient_SetEventHandle,
1528 AudioClient_GetService
1531 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1532 IAudioRenderClient *iface, REFIID riid, void **ppv)
1534 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1536 if(!ppv)
1537 return E_POINTER;
1538 *ppv = NULL;
1540 if(IsEqualIID(riid, &IID_IUnknown) ||
1541 IsEqualIID(riid, &IID_IAudioRenderClient))
1542 *ppv = iface;
1543 if(*ppv){
1544 IUnknown_AddRef((IUnknown*)*ppv);
1545 return S_OK;
1548 WARN("Unknown interface %s\n", debugstr_guid(riid));
1549 return E_NOINTERFACE;
1552 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1554 ACImpl *This = impl_from_IAudioRenderClient(iface);
1555 return AudioClient_AddRef(&This->IAudioClient_iface);
1558 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1560 ACImpl *This = impl_from_IAudioRenderClient(iface);
1561 return AudioClient_Release(&This->IAudioClient_iface);
1564 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1565 UINT32 frames, BYTE **data)
1567 ACImpl *This = impl_from_IAudioRenderClient(iface);
1568 UINT32 pad, write_pos;
1569 HRESULT hr;
1571 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1573 if(!data)
1574 return E_POINTER;
1576 EnterCriticalSection(&This->lock);
1578 if(This->buf_state != NOT_LOCKED){
1579 LeaveCriticalSection(&This->lock);
1580 return AUDCLNT_E_OUT_OF_ORDER;
1583 if(!frames){
1584 This->buf_state = LOCKED_NORMAL;
1585 LeaveCriticalSection(&This->lock);
1586 return S_OK;
1589 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1590 if(FAILED(hr)){
1591 LeaveCriticalSection(&This->lock);
1592 return hr;
1595 if(pad + frames > This->bufsize_frames){
1596 LeaveCriticalSection(&This->lock);
1597 return AUDCLNT_E_BUFFER_TOO_LARGE;
1600 write_pos =
1601 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1602 if(write_pos + frames > This->bufsize_frames){
1603 if(This->tmp_buffer_frames < frames){
1604 if(This->tmp_buffer)
1605 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1606 This->tmp_buffer, frames * This->fmt->nBlockAlign);
1607 else
1608 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1609 frames * This->fmt->nBlockAlign);
1610 if(!This->tmp_buffer){
1611 LeaveCriticalSection(&This->lock);
1612 return E_OUTOFMEMORY;
1614 This->tmp_buffer_frames = frames;
1616 *data = This->tmp_buffer;
1617 This->buf_state = LOCKED_WRAPPED;
1618 }else{
1619 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1620 This->buf_state = LOCKED_NORMAL;
1623 LeaveCriticalSection(&This->lock);
1625 return S_OK;
1628 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1630 UINT32 write_offs_frames =
1631 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1632 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1633 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1634 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1635 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1637 if(written_bytes <= chunk_bytes){
1638 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1639 }else{
1640 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1641 memcpy(This->local_buffer, buffer + chunk_bytes,
1642 written_bytes - chunk_bytes);
1646 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1647 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1649 ACImpl *This = impl_from_IAudioRenderClient(iface);
1650 BYTE *buffer;
1652 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1654 EnterCriticalSection(&This->lock);
1656 if(This->buf_state == NOT_LOCKED || !written_frames){
1657 This->buf_state = NOT_LOCKED;
1658 LeaveCriticalSection(&This->lock);
1659 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1662 if(This->buf_state == LOCKED_NORMAL)
1663 buffer = This->local_buffer + This->fmt->nBlockAlign *
1664 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1665 else
1666 buffer = This->tmp_buffer;
1668 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1669 oss_silence_buffer(This, buffer, written_frames);
1671 if(This->held_frames){
1672 if(This->buf_state == LOCKED_WRAPPED)
1673 oss_wrap_buffer(This, buffer, written_frames);
1675 This->held_frames += written_frames;
1676 }else{
1677 ssize_t w_bytes;
1678 UINT32 w_frames;
1680 if(This->session->mute)
1681 oss_silence_buffer(This, buffer, written_frames);
1683 w_bytes = write(This->fd, buffer,
1684 written_frames * This->fmt->nBlockAlign);
1685 if(w_bytes < 0){
1686 LeaveCriticalSection(&This->lock);
1687 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1688 return E_FAIL;
1690 w_frames = w_bytes / This->fmt->nBlockAlign;
1691 This->inbuf_frames += w_frames;
1693 if(w_frames < written_frames){
1694 if(This->buf_state == LOCKED_WRAPPED)
1695 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1696 written_frames - w_frames);
1698 This->held_frames = written_frames - w_frames;
1702 This->written_frames += written_frames;
1703 This->buf_state = NOT_LOCKED;
1705 LeaveCriticalSection(&This->lock);
1707 return S_OK;
1710 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1711 AudioRenderClient_QueryInterface,
1712 AudioRenderClient_AddRef,
1713 AudioRenderClient_Release,
1714 AudioRenderClient_GetBuffer,
1715 AudioRenderClient_ReleaseBuffer
1718 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1719 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1721 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1723 if(!ppv)
1724 return E_POINTER;
1725 *ppv = NULL;
1727 if(IsEqualIID(riid, &IID_IUnknown) ||
1728 IsEqualIID(riid, &IID_IAudioCaptureClient))
1729 *ppv = iface;
1730 if(*ppv){
1731 IUnknown_AddRef((IUnknown*)*ppv);
1732 return S_OK;
1735 WARN("Unknown interface %s\n", debugstr_guid(riid));
1736 return E_NOINTERFACE;
1739 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1741 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1742 return IAudioClient_AddRef(&This->IAudioClient_iface);
1745 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1747 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1748 return IAudioClient_Release(&This->IAudioClient_iface);
1751 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1752 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1753 UINT64 *qpcpos)
1755 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1756 HRESULT hr;
1758 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1759 devpos, qpcpos);
1761 if(!data || !frames || !flags)
1762 return E_POINTER;
1764 EnterCriticalSection(&This->lock);
1766 if(This->buf_state != NOT_LOCKED){
1767 LeaveCriticalSection(&This->lock);
1768 return AUDCLNT_E_OUT_OF_ORDER;
1771 hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1772 if(FAILED(hr)){
1773 LeaveCriticalSection(&This->lock);
1774 return hr;
1777 *flags = 0;
1779 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1780 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1781 if(This->tmp_buffer_frames < *frames){
1782 if(This->tmp_buffer)
1783 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1784 This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1785 else
1786 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1787 *frames * This->fmt->nBlockAlign);
1788 if(!This->tmp_buffer){
1789 LeaveCriticalSection(&This->lock);
1790 return E_OUTOFMEMORY;
1792 This->tmp_buffer_frames = *frames;
1795 *data = This->tmp_buffer;
1796 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1797 This->fmt->nBlockAlign;
1798 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1799 frames_bytes = *frames * This->fmt->nBlockAlign;
1800 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1801 memcpy(This->tmp_buffer, This->local_buffer,
1802 frames_bytes - chunk_bytes);
1803 }else
1804 *data = This->local_buffer +
1805 This->lcl_offs_frames * This->fmt->nBlockAlign;
1807 This->buf_state = LOCKED_NORMAL;
1809 if(devpos || qpcpos)
1810 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1812 LeaveCriticalSection(&This->lock);
1814 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1817 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1818 IAudioCaptureClient *iface, UINT32 done)
1820 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1822 TRACE("(%p)->(%u)\n", This, done);
1824 EnterCriticalSection(&This->lock);
1826 if(This->buf_state == NOT_LOCKED){
1827 LeaveCriticalSection(&This->lock);
1828 return AUDCLNT_E_OUT_OF_ORDER;
1831 This->held_frames -= done;
1832 This->lcl_offs_frames += done;
1833 This->lcl_offs_frames %= This->bufsize_frames;
1835 This->buf_state = NOT_LOCKED;
1837 LeaveCriticalSection(&This->lock);
1839 return S_OK;
1842 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1843 IAudioCaptureClient *iface, UINT32 *frames)
1845 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1847 TRACE("(%p)->(%p)\n", This, frames);
1849 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1852 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1854 AudioCaptureClient_QueryInterface,
1855 AudioCaptureClient_AddRef,
1856 AudioCaptureClient_Release,
1857 AudioCaptureClient_GetBuffer,
1858 AudioCaptureClient_ReleaseBuffer,
1859 AudioCaptureClient_GetNextPacketSize
1862 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1863 REFIID riid, void **ppv)
1865 ACImpl *This = impl_from_IAudioClock(iface);
1867 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1869 if(!ppv)
1870 return E_POINTER;
1871 *ppv = NULL;
1873 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1874 *ppv = iface;
1875 else if(IsEqualIID(riid, &IID_IAudioClock2))
1876 *ppv = &This->IAudioClock2_iface;
1877 if(*ppv){
1878 IUnknown_AddRef((IUnknown*)*ppv);
1879 return S_OK;
1882 WARN("Unknown interface %s\n", debugstr_guid(riid));
1883 return E_NOINTERFACE;
1886 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1888 ACImpl *This = impl_from_IAudioClock(iface);
1889 return IAudioClient_AddRef(&This->IAudioClient_iface);
1892 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1894 ACImpl *This = impl_from_IAudioClock(iface);
1895 return IAudioClient_Release(&This->IAudioClient_iface);
1898 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1900 ACImpl *This = impl_from_IAudioClock(iface);
1902 TRACE("(%p)->(%p)\n", This, freq);
1904 *freq = This->fmt->nSamplesPerSec;
1906 return S_OK;
1909 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1910 UINT64 *qpctime)
1912 ACImpl *This = impl_from_IAudioClock(iface);
1913 UINT32 pad;
1914 HRESULT hr;
1916 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1918 if(!pos)
1919 return E_POINTER;
1921 EnterCriticalSection(&This->lock);
1923 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1924 if(FAILED(hr)){
1925 LeaveCriticalSection(&This->lock);
1926 return hr;
1929 if(This->dataflow == eRender)
1930 *pos = This->written_frames - pad;
1931 else if(This->dataflow == eCapture)
1932 *pos = This->written_frames + pad;
1934 LeaveCriticalSection(&This->lock);
1936 if(qpctime){
1937 LARGE_INTEGER stamp, freq;
1938 QueryPerformanceCounter(&stamp);
1939 QueryPerformanceFrequency(&freq);
1940 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1943 return S_OK;
1946 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1947 DWORD *chars)
1949 ACImpl *This = impl_from_IAudioClock(iface);
1951 TRACE("(%p)->(%p)\n", This, chars);
1953 if(!chars)
1954 return E_POINTER;
1956 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1958 return S_OK;
1961 static const IAudioClockVtbl AudioClock_Vtbl =
1963 AudioClock_QueryInterface,
1964 AudioClock_AddRef,
1965 AudioClock_Release,
1966 AudioClock_GetFrequency,
1967 AudioClock_GetPosition,
1968 AudioClock_GetCharacteristics
1971 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1972 REFIID riid, void **ppv)
1974 ACImpl *This = impl_from_IAudioClock2(iface);
1975 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1978 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1980 ACImpl *This = impl_from_IAudioClock2(iface);
1981 return IAudioClient_AddRef(&This->IAudioClient_iface);
1984 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1986 ACImpl *This = impl_from_IAudioClock2(iface);
1987 return IAudioClient_Release(&This->IAudioClient_iface);
1990 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1991 UINT64 *pos, UINT64 *qpctime)
1993 ACImpl *This = impl_from_IAudioClock2(iface);
1995 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1997 return E_NOTIMPL;
2000 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2002 AudioClock2_QueryInterface,
2003 AudioClock2_AddRef,
2004 AudioClock2_Release,
2005 AudioClock2_GetDevicePosition
2008 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2010 AudioSessionWrapper *ret;
2012 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2013 sizeof(AudioSessionWrapper));
2014 if(!ret)
2015 return NULL;
2017 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2018 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2019 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2021 ret->ref = 1;
2023 ret->client = client;
2024 if(client){
2025 ret->session = client->session;
2026 AudioClient_AddRef(&client->IAudioClient_iface);
2029 return ret;
2032 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2033 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2035 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2037 if(!ppv)
2038 return E_POINTER;
2039 *ppv = NULL;
2041 if(IsEqualIID(riid, &IID_IUnknown) ||
2042 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2043 IsEqualIID(riid, &IID_IAudioSessionControl2))
2044 *ppv = iface;
2045 if(*ppv){
2046 IUnknown_AddRef((IUnknown*)*ppv);
2047 return S_OK;
2050 WARN("Unknown interface %s\n", debugstr_guid(riid));
2051 return E_NOINTERFACE;
2054 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2056 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2057 ULONG ref;
2058 ref = InterlockedIncrement(&This->ref);
2059 TRACE("(%p) Refcount now %u\n", This, ref);
2060 return ref;
2063 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2065 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2066 ULONG ref;
2067 ref = InterlockedDecrement(&This->ref);
2068 TRACE("(%p) Refcount now %u\n", This, ref);
2069 if(!ref){
2070 if(This->client){
2071 EnterCriticalSection(&This->client->lock);
2072 This->client->session_wrapper = NULL;
2073 LeaveCriticalSection(&This->client->lock);
2074 AudioClient_Release(&This->client->IAudioClient_iface);
2076 HeapFree(GetProcessHeap(), 0, This);
2078 return ref;
2081 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2082 AudioSessionState *state)
2084 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2085 ACImpl *client;
2087 TRACE("(%p)->(%p)\n", This, state);
2089 if(!state)
2090 return NULL_PTR_ERR;
2092 EnterCriticalSection(&g_sessions_lock);
2094 if(list_empty(&This->session->clients)){
2095 *state = AudioSessionStateExpired;
2096 LeaveCriticalSection(&g_sessions_lock);
2097 return S_OK;
2100 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2101 EnterCriticalSection(&client->lock);
2102 if(client->playing){
2103 *state = AudioSessionStateActive;
2104 LeaveCriticalSection(&client->lock);
2105 LeaveCriticalSection(&g_sessions_lock);
2106 return S_OK;
2108 LeaveCriticalSection(&client->lock);
2111 LeaveCriticalSection(&g_sessions_lock);
2113 *state = AudioSessionStateInactive;
2115 return S_OK;
2118 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2119 IAudioSessionControl2 *iface, WCHAR **name)
2121 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2123 FIXME("(%p)->(%p) - stub\n", This, name);
2125 return E_NOTIMPL;
2128 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2129 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2131 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2133 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2135 return E_NOTIMPL;
2138 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2139 IAudioSessionControl2 *iface, WCHAR **path)
2141 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2143 FIXME("(%p)->(%p) - stub\n", This, path);
2145 return E_NOTIMPL;
2148 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2149 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2151 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2153 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2155 return E_NOTIMPL;
2158 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2159 IAudioSessionControl2 *iface, GUID *group)
2161 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2163 FIXME("(%p)->(%p) - stub\n", This, group);
2165 return E_NOTIMPL;
2168 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2169 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2171 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2173 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2174 debugstr_guid(session));
2176 return E_NOTIMPL;
2179 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2180 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2182 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2184 FIXME("(%p)->(%p) - stub\n", This, events);
2186 return S_OK;
2189 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2190 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2192 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2194 FIXME("(%p)->(%p) - stub\n", This, events);
2196 return S_OK;
2199 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2200 IAudioSessionControl2 *iface, WCHAR **id)
2202 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2204 FIXME("(%p)->(%p) - stub\n", This, id);
2206 return E_NOTIMPL;
2209 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2210 IAudioSessionControl2 *iface, WCHAR **id)
2212 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2214 FIXME("(%p)->(%p) - stub\n", This, id);
2216 return E_NOTIMPL;
2219 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2220 IAudioSessionControl2 *iface, DWORD *pid)
2222 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2224 TRACE("(%p)->(%p)\n", This, pid);
2226 if(!pid)
2227 return E_POINTER;
2229 *pid = GetCurrentProcessId();
2231 return S_OK;
2234 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2235 IAudioSessionControl2 *iface)
2237 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2239 TRACE("(%p)\n", This);
2241 return S_FALSE;
2244 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2245 IAudioSessionControl2 *iface, BOOL optout)
2247 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2249 TRACE("(%p)->(%d)\n", This, optout);
2251 return S_OK;
2254 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2256 AudioSessionControl_QueryInterface,
2257 AudioSessionControl_AddRef,
2258 AudioSessionControl_Release,
2259 AudioSessionControl_GetState,
2260 AudioSessionControl_GetDisplayName,
2261 AudioSessionControl_SetDisplayName,
2262 AudioSessionControl_GetIconPath,
2263 AudioSessionControl_SetIconPath,
2264 AudioSessionControl_GetGroupingParam,
2265 AudioSessionControl_SetGroupingParam,
2266 AudioSessionControl_RegisterAudioSessionNotification,
2267 AudioSessionControl_UnregisterAudioSessionNotification,
2268 AudioSessionControl_GetSessionIdentifier,
2269 AudioSessionControl_GetSessionInstanceIdentifier,
2270 AudioSessionControl_GetProcessId,
2271 AudioSessionControl_IsSystemSoundsSession,
2272 AudioSessionControl_SetDuckingPreference
2275 /* index == -1 means set all channels, otherwise sets only the given channel */
2276 static HRESULT oss_setvol(ACImpl *This, UINT32 index)
2278 int setreq, getreq;
2279 unsigned int vol;
2280 unsigned short l;
2281 float level;
2283 if(index == (UINT32)-1){
2284 HRESULT ret = S_OK;
2285 UINT32 i;
2286 for(i = 0; i < This->fmt->nChannels; ++i){
2287 HRESULT hr;
2288 hr = oss_setvol(This, i);
2289 if(FAILED(hr))
2290 ret = hr;
2292 return ret;
2295 if(index > 1)
2296 /* OSS doesn't support volume control past the first two channels */
2297 return S_OK;
2299 if(This->dataflow == eRender){
2300 setreq = SNDCTL_DSP_SETPLAYVOL;
2301 getreq = SNDCTL_DSP_GETPLAYVOL;
2302 }else if(This->dataflow == eCapture){
2303 setreq = SNDCTL_DSP_SETRECVOL;
2304 getreq = SNDCTL_DSP_GETRECVOL;
2305 }else
2306 return E_UNEXPECTED;
2308 if(ioctl(This->fd, getreq, &vol) < 0){
2309 if(errno == EINVAL)
2310 /* device doesn't support this call */
2311 return S_OK;
2313 WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2314 return E_FAIL;
2317 level = This->session->master_vol * This->session->channel_vols[index] *
2318 This->vols[index];
2319 l = level * 100;
2320 if(index == 0)
2321 vol = l | (vol & 0xFF00);
2322 else
2323 vol = (vol & 0xFF) | (l << 8);
2325 if(ioctl(This->fd, setreq, &vol) < 0){
2326 if(errno == EINVAL)
2327 /* device doesn't support this call */
2328 return S_OK;
2330 WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2331 return E_FAIL;
2334 return S_OK;
2337 static HRESULT oss_session_setvol(AudioSession *session, UINT32 index)
2339 HRESULT ret = S_OK;
2340 ACImpl *client;
2342 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2343 HRESULT hr;
2344 hr = oss_setvol(client, index);
2345 if(FAILED(hr))
2346 ret = hr;
2349 return ret;
2352 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2353 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2355 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2357 if(!ppv)
2358 return E_POINTER;
2359 *ppv = NULL;
2361 if(IsEqualIID(riid, &IID_IUnknown) ||
2362 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2363 *ppv = iface;
2364 if(*ppv){
2365 IUnknown_AddRef((IUnknown*)*ppv);
2366 return S_OK;
2369 WARN("Unknown interface %s\n", debugstr_guid(riid));
2370 return E_NOINTERFACE;
2373 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2375 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2376 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2379 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2381 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2382 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2385 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2386 ISimpleAudioVolume *iface, float level, const GUID *context)
2388 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2389 AudioSession *session = This->session;
2390 HRESULT ret;
2392 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2394 if(level < 0.f || level > 1.f)
2395 return E_INVALIDARG;
2397 if(context)
2398 FIXME("Notifications not supported yet\n");
2400 EnterCriticalSection(&session->lock);
2402 session->master_vol = level;
2404 ret = oss_session_setvol(session, -1);
2406 LeaveCriticalSection(&session->lock);
2408 return ret;
2411 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2412 ISimpleAudioVolume *iface, float *level)
2414 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2415 AudioSession *session = This->session;
2417 TRACE("(%p)->(%p)\n", session, level);
2419 if(!level)
2420 return NULL_PTR_ERR;
2422 *level = session->master_vol;
2424 return S_OK;
2427 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2428 BOOL mute, const GUID *context)
2430 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2431 AudioSession *session = This->session;
2433 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2435 EnterCriticalSection(&session->lock);
2437 if(!mute && session->mute){
2438 ACImpl *client;
2440 session->mute = mute;
2442 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2443 EnterCriticalSection(&client->lock);
2444 if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2445 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2446 strerror(errno));
2447 oss_write_data(client);
2448 LeaveCriticalSection(&client->lock);
2450 }else
2451 session->mute = mute;
2453 LeaveCriticalSection(&session->lock);
2455 return S_OK;
2458 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2459 BOOL *mute)
2461 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2462 AudioSession *session = This->session;
2464 TRACE("(%p)->(%p)\n", session, mute);
2466 if(!mute)
2467 return NULL_PTR_ERR;
2469 *mute = This->session->mute;
2471 return S_OK;
2474 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2476 SimpleAudioVolume_QueryInterface,
2477 SimpleAudioVolume_AddRef,
2478 SimpleAudioVolume_Release,
2479 SimpleAudioVolume_SetMasterVolume,
2480 SimpleAudioVolume_GetMasterVolume,
2481 SimpleAudioVolume_SetMute,
2482 SimpleAudioVolume_GetMute
2485 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2486 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2488 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2490 if(!ppv)
2491 return E_POINTER;
2492 *ppv = NULL;
2494 if(IsEqualIID(riid, &IID_IUnknown) ||
2495 IsEqualIID(riid, &IID_IAudioStreamVolume))
2496 *ppv = iface;
2497 if(*ppv){
2498 IUnknown_AddRef((IUnknown*)*ppv);
2499 return S_OK;
2502 WARN("Unknown interface %s\n", debugstr_guid(riid));
2503 return E_NOINTERFACE;
2506 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2508 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2509 return IAudioClient_AddRef(&This->IAudioClient_iface);
2512 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2514 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2515 return IAudioClient_Release(&This->IAudioClient_iface);
2518 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2519 IAudioStreamVolume *iface, UINT32 *out)
2521 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2523 TRACE("(%p)->(%p)\n", This, out);
2525 if(!out)
2526 return E_POINTER;
2528 *out = This->fmt->nChannels;
2530 return S_OK;
2533 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2534 IAudioStreamVolume *iface, UINT32 index, float level)
2536 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2537 HRESULT ret;
2539 TRACE("(%p)->(%d, %f)\n", This, index, level);
2541 if(level < 0.f || level > 1.f)
2542 return E_INVALIDARG;
2544 if(index >= This->fmt->nChannels)
2545 return E_INVALIDARG;
2547 EnterCriticalSection(&This->lock);
2549 This->vols[index] = level;
2551 ret = oss_setvol(This, index);
2553 LeaveCriticalSection(&This->lock);
2555 return ret;
2558 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2559 IAudioStreamVolume *iface, UINT32 index, float *level)
2561 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2563 TRACE("(%p)->(%d, %p)\n", This, index, level);
2565 if(!level)
2566 return E_POINTER;
2568 if(index >= This->fmt->nChannels)
2569 return E_INVALIDARG;
2571 *level = This->vols[index];
2573 return S_OK;
2576 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2577 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2579 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2580 int i;
2581 HRESULT ret;
2583 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2585 if(!levels)
2586 return E_POINTER;
2588 if(count != This->fmt->nChannels)
2589 return E_INVALIDARG;
2591 EnterCriticalSection(&This->lock);
2593 for(i = 0; i < count; ++i)
2594 This->vols[i] = levels[i];
2596 ret = oss_setvol(This, -1);
2598 LeaveCriticalSection(&This->lock);
2600 return ret;
2603 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2604 IAudioStreamVolume *iface, UINT32 count, float *levels)
2606 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2607 int i;
2609 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2611 if(!levels)
2612 return E_POINTER;
2614 if(count != This->fmt->nChannels)
2615 return E_INVALIDARG;
2617 EnterCriticalSection(&This->lock);
2619 for(i = 0; i < count; ++i)
2620 levels[i] = This->vols[i];
2622 LeaveCriticalSection(&This->lock);
2624 return S_OK;
2627 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2629 AudioStreamVolume_QueryInterface,
2630 AudioStreamVolume_AddRef,
2631 AudioStreamVolume_Release,
2632 AudioStreamVolume_GetChannelCount,
2633 AudioStreamVolume_SetChannelVolume,
2634 AudioStreamVolume_GetChannelVolume,
2635 AudioStreamVolume_SetAllVolumes,
2636 AudioStreamVolume_GetAllVolumes
2639 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2640 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2642 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2644 if(!ppv)
2645 return E_POINTER;
2646 *ppv = NULL;
2648 if(IsEqualIID(riid, &IID_IUnknown) ||
2649 IsEqualIID(riid, &IID_IChannelAudioVolume))
2650 *ppv = iface;
2651 if(*ppv){
2652 IUnknown_AddRef((IUnknown*)*ppv);
2653 return S_OK;
2656 WARN("Unknown interface %s\n", debugstr_guid(riid));
2657 return E_NOINTERFACE;
2660 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2662 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2663 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2666 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2668 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2669 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2672 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2673 IChannelAudioVolume *iface, UINT32 *out)
2675 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2676 AudioSession *session = This->session;
2678 TRACE("(%p)->(%p)\n", session, out);
2680 if(!out)
2681 return NULL_PTR_ERR;
2683 *out = session->channel_count;
2685 return S_OK;
2688 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2689 IChannelAudioVolume *iface, UINT32 index, float level,
2690 const GUID *context)
2692 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2693 AudioSession *session = This->session;
2694 HRESULT ret;
2696 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2697 wine_dbgstr_guid(context));
2699 if(level < 0.f || level > 1.f)
2700 return E_INVALIDARG;
2702 if(index >= session->channel_count)
2703 return E_INVALIDARG;
2705 if(context)
2706 FIXME("Notifications not supported yet\n");
2708 EnterCriticalSection(&session->lock);
2710 session->channel_vols[index] = level;
2712 ret = oss_session_setvol(session, index);
2714 LeaveCriticalSection(&session->lock);
2716 return ret;
2719 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2720 IChannelAudioVolume *iface, UINT32 index, float *level)
2722 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2723 AudioSession *session = This->session;
2725 TRACE("(%p)->(%d, %p)\n", session, index, level);
2727 if(!level)
2728 return NULL_PTR_ERR;
2730 if(index >= session->channel_count)
2731 return E_INVALIDARG;
2733 *level = session->channel_vols[index];
2735 return S_OK;
2738 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2739 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2740 const GUID *context)
2742 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2743 AudioSession *session = This->session;
2744 int i;
2745 HRESULT ret;
2747 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2748 wine_dbgstr_guid(context));
2750 if(!levels)
2751 return NULL_PTR_ERR;
2753 if(count != session->channel_count)
2754 return E_INVALIDARG;
2756 if(context)
2757 FIXME("Notifications not supported yet\n");
2759 EnterCriticalSection(&session->lock);
2761 for(i = 0; i < count; ++i)
2762 session->channel_vols[i] = levels[i];
2764 ret = oss_session_setvol(session, -1);
2766 LeaveCriticalSection(&session->lock);
2768 return ret;
2771 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2772 IChannelAudioVolume *iface, UINT32 count, float *levels)
2774 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2775 AudioSession *session = This->session;
2776 int i;
2778 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2780 if(!levels)
2781 return NULL_PTR_ERR;
2783 if(count != session->channel_count)
2784 return E_INVALIDARG;
2786 for(i = 0; i < count; ++i)
2787 levels[i] = session->channel_vols[i];
2789 return S_OK;
2792 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2794 ChannelAudioVolume_QueryInterface,
2795 ChannelAudioVolume_AddRef,
2796 ChannelAudioVolume_Release,
2797 ChannelAudioVolume_GetChannelCount,
2798 ChannelAudioVolume_SetChannelVolume,
2799 ChannelAudioVolume_GetChannelVolume,
2800 ChannelAudioVolume_SetAllVolumes,
2801 ChannelAudioVolume_GetAllVolumes
2804 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2805 REFIID riid, void **ppv)
2807 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2809 if(!ppv)
2810 return E_POINTER;
2811 *ppv = NULL;
2813 if(IsEqualIID(riid, &IID_IUnknown) ||
2814 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2815 IsEqualIID(riid, &IID_IAudioSessionManager2))
2816 *ppv = iface;
2817 if(*ppv){
2818 IUnknown_AddRef((IUnknown*)*ppv);
2819 return S_OK;
2822 WARN("Unknown interface %s\n", debugstr_guid(riid));
2823 return E_NOINTERFACE;
2826 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2828 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2829 ULONG ref;
2830 ref = InterlockedIncrement(&This->ref);
2831 TRACE("(%p) Refcount now %u\n", This, ref);
2832 return ref;
2835 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2837 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2838 ULONG ref;
2839 ref = InterlockedDecrement(&This->ref);
2840 TRACE("(%p) Refcount now %u\n", This, ref);
2841 if(!ref)
2842 HeapFree(GetProcessHeap(), 0, This);
2843 return ref;
2846 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2847 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2848 IAudioSessionControl **out)
2850 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2851 AudioSession *session;
2852 AudioSessionWrapper *wrapper;
2853 HRESULT hr;
2855 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2856 flags, out);
2858 hr = get_audio_session(session_guid, This->device, 0, &session);
2859 if(FAILED(hr))
2860 return hr;
2862 wrapper = AudioSessionWrapper_Create(NULL);
2863 if(!wrapper)
2864 return E_OUTOFMEMORY;
2866 wrapper->session = session;
2868 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2870 return S_OK;
2873 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2874 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2875 ISimpleAudioVolume **out)
2877 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2878 AudioSession *session;
2879 AudioSessionWrapper *wrapper;
2880 HRESULT hr;
2882 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2883 flags, out);
2885 hr = get_audio_session(session_guid, This->device, 0, &session);
2886 if(FAILED(hr))
2887 return hr;
2889 wrapper = AudioSessionWrapper_Create(NULL);
2890 if(!wrapper)
2891 return E_OUTOFMEMORY;
2893 wrapper->session = session;
2895 *out = &wrapper->ISimpleAudioVolume_iface;
2897 return S_OK;
2900 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2901 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2903 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2904 FIXME("(%p)->(%p) - stub\n", This, out);
2905 return E_NOTIMPL;
2908 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2909 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2911 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2912 FIXME("(%p)->(%p) - stub\n", This, notification);
2913 return E_NOTIMPL;
2916 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2917 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2919 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2920 FIXME("(%p)->(%p) - stub\n", This, notification);
2921 return E_NOTIMPL;
2924 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2925 IAudioSessionManager2 *iface, const WCHAR *session_id,
2926 IAudioVolumeDuckNotification *notification)
2928 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2929 FIXME("(%p)->(%p) - stub\n", This, notification);
2930 return E_NOTIMPL;
2933 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2934 IAudioSessionManager2 *iface,
2935 IAudioVolumeDuckNotification *notification)
2937 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2938 FIXME("(%p)->(%p) - stub\n", This, notification);
2939 return E_NOTIMPL;
2942 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2944 AudioSessionManager_QueryInterface,
2945 AudioSessionManager_AddRef,
2946 AudioSessionManager_Release,
2947 AudioSessionManager_GetAudioSessionControl,
2948 AudioSessionManager_GetSimpleAudioVolume,
2949 AudioSessionManager_GetSessionEnumerator,
2950 AudioSessionManager_RegisterSessionNotification,
2951 AudioSessionManager_UnregisterSessionNotification,
2952 AudioSessionManager_RegisterDuckNotification,
2953 AudioSessionManager_UnregisterDuckNotification
2956 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2957 IAudioSessionManager2 **out)
2959 SessionMgr *This;
2961 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2962 if(!This)
2963 return E_OUTOFMEMORY;
2965 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2966 This->device = device;
2967 This->ref = 1;
2969 *out = &This->IAudioSessionManager2_iface;
2971 return S_OK;