d3d9: Implement IDirect3DVertexBuffer9 private data handling on top of wined3d_resource.
[wine] / dlls / wineoss.drv / mmdevdrv.c
1 /*
2  * Copyright 2011 Andrew Eikum for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #define NONAMELESSUNION
20 #define COBJMACROS
21 #include "config.h"
22
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>
36
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"
44
45 #include "ole2.h"
46 #include "mmdeviceapi.h"
47 #include "devpkey.h"
48 #include "dshow.h"
49 #include "dsound.h"
50 #include "endpointvolume.h"
51
52 #include "initguid.h"
53 #include "audiopolicy.h"
54 #include "audioclient.h"
55
56
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
62
63 WINE_DEFAULT_DEBUG_CHANNEL(oss);
64
65 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
66
67 static const REFERENCE_TIME DefaultPeriod = 200000;
68 static const REFERENCE_TIME MinimumPeriod = 100000;
69
70 struct ACImpl;
71 typedef struct ACImpl ACImpl;
72
73 typedef struct _AudioSession {
74     GUID guid;
75     struct list clients;
76
77     IMMDevice *device;
78
79     float master_vol;
80     UINT32 channel_count;
81     float *channel_vols;
82
83     CRITICAL_SECTION lock;
84
85     struct list entry;
86 } AudioSession;
87
88 typedef struct _AudioSessionWrapper {
89     IAudioSessionControl2 IAudioSessionControl2_iface;
90     IChannelAudioVolume IChannelAudioVolume_iface;
91     ISimpleAudioVolume ISimpleAudioVolume_iface;
92
93     LONG ref;
94
95     ACImpl *client;
96     AudioSession *session;
97 } AudioSessionWrapper;
98
99 struct ACImpl {
100     IAudioClient IAudioClient_iface;
101     IAudioRenderClient IAudioRenderClient_iface;
102     IAudioCaptureClient IAudioCaptureClient_iface;
103     IAudioClock IAudioClock_iface;
104     IAudioClock2 IAudioClock2_iface;
105     IAudioStreamVolume IAudioStreamVolume_iface;
106
107     LONG ref;
108
109     IMMDevice *parent;
110
111     WAVEFORMATEX *fmt;
112
113     EDataFlow dataflow;
114     DWORD flags;
115     AUDCLNT_SHAREMODE share;
116     HANDLE event;
117     float *vols;
118
119     int fd;
120     oss_audioinfo ai;
121
122     BOOL initted, playing;
123     UINT64 written_frames, held_frames, tmp_buffer_frames, inbuf_frames;
124     UINT32 period_us, bufsize_frames;
125     UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
126
127     BYTE *local_buffer, *tmp_buffer;
128     int buf_state;
129     HANDLE timer;
130
131     CRITICAL_SECTION lock;
132
133     AudioSession *session;
134     AudioSessionWrapper *session_wrapper;
135
136     struct list entry;
137 };
138
139 enum BufferStates {
140     NOT_LOCKED = 0,
141     LOCKED_NORMAL, /* public buffer piece is from local_buffer */
142     LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
143 };
144
145 typedef struct _SessionMgr {
146     IAudioSessionManager2 IAudioSessionManager2_iface;
147
148     LONG ref;
149
150     IMMDevice *device;
151 } SessionMgr;
152
153 static HANDLE g_timer_q;
154
155 static CRITICAL_SECTION g_sessions_lock;
156 static struct list g_sessions = LIST_INIT(g_sessions);
157
158 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
159 static HRESULT oss_setvol(ACImpl *This, UINT32 index);
160
161 static const IAudioClientVtbl AudioClient_Vtbl;
162 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
163 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
164 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
165 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
166 static const IAudioClockVtbl AudioClock_Vtbl;
167 static const IAudioClock2Vtbl AudioClock2_Vtbl;
168 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
169 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
170 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
171
172 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
173 {
174     return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
175 }
176
177 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
178 {
179     return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
180 }
181
182 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
183 {
184     return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
185 }
186
187 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
188 {
189     return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
190 }
191
192 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
193 {
194     return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
195 }
196
197 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
198 {
199     return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
200 }
201
202 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
203 {
204     return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
205 }
206
207 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
208 {
209     return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
210 }
211
212 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
213 {
214     return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
215 }
216
217 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
218 {
219     return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
220 }
221
222 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
223 {
224     if(reason == DLL_PROCESS_ATTACH){
225         g_timer_q = CreateTimerQueue();
226         if(!g_timer_q)
227             return FALSE;
228
229         InitializeCriticalSection(&g_sessions_lock);
230     }
231
232     return TRUE;
233 }
234
235 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
236         UINT *num, UINT *def_index)
237 {
238     int i, mixer_fd;
239     oss_sysinfo sysinfo;
240     static int print_once = 0;
241
242     TRACE("%d %p %p %p\n", flow, ids, num, def_index);
243
244     mixer_fd = open("/dev/mixer", O_RDONLY, 0);
245     if(mixer_fd < 0){
246         ERR("OSS /dev/mixer doesn't seem to exist\n");
247         return AUDCLNT_E_SERVICE_NOT_RUNNING;
248     }
249
250     if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
251         close(mixer_fd);
252
253         if(errno == EINVAL){
254             ERR("OSS version too old, need at least OSSv4\n");
255             return AUDCLNT_E_SERVICE_NOT_RUNNING;
256         }
257
258         ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
259         return E_FAIL;
260     }
261
262     if(!print_once){
263         TRACE("OSS sysinfo:\n");
264         TRACE("product: %s\n", sysinfo.product);
265         TRACE("version: %s\n", sysinfo.version);
266         TRACE("versionnum: %x\n", sysinfo.versionnum);
267         TRACE("numaudios: %d\n", sysinfo.numaudios);
268         TRACE("nummixers: %d\n", sysinfo.nummixers);
269         TRACE("numcards: %d\n", sysinfo.numcards);
270         TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
271         print_once = 1;
272     }
273
274     if(sysinfo.numaudios <= 0){
275         WARN("No audio devices!\n");
276         close(mixer_fd);
277         return AUDCLNT_E_SERVICE_NOT_RUNNING;
278     }
279
280     *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
281     *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
282
283     *num = 0;
284     *def_index = -1;
285     for(i = 0; i < sysinfo.numaudios; ++i){
286         oss_audioinfo ai = {0};
287
288         ai.dev = i;
289         if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
290             WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
291                     strerror(errno));
292             continue;
293         }
294
295         if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
296                 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
297             size_t len;
298
299             (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
300                     strlen(ai.devnode) + 1);
301             if(!(*keys)[*num]){
302                 for(i = 0; i < *num; ++i){
303                     HeapFree(GetProcessHeap(), 0, (*ids)[i]);
304                     HeapFree(GetProcessHeap(), 0, (*keys)[i]);
305                 }
306                 HeapFree(GetProcessHeap(), 0, *ids);
307                 HeapFree(GetProcessHeap(), 0, *keys);
308                 close(mixer_fd);
309                 return E_OUTOFMEMORY;
310             }
311             strcpy((*keys)[*num], ai.devnode);
312
313             len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
314             (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
315                     len * sizeof(WCHAR));
316             if(!(*ids)[*num]){
317                 HeapFree(GetProcessHeap(), 0, (*keys)[*num]);
318                 for(i = 0; i < *num; ++i){
319                     HeapFree(GetProcessHeap(), 0, (*ids)[i]);
320                     HeapFree(GetProcessHeap(), 0, (*keys)[i]);
321                 }
322                 HeapFree(GetProcessHeap(), 0, *ids);
323                 HeapFree(GetProcessHeap(), 0, *keys);
324                 close(mixer_fd);
325                 return E_OUTOFMEMORY;
326             }
327             MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
328                     (*ids)[*num], len);
329
330             if(ai.caps & PCM_CAP_DEFAULT)
331                 *def_index = *num;
332
333             (*num)++;
334         }
335     }
336
337     if(*def_index == -1)
338         *def_index = 0;
339
340     close(mixer_fd);
341
342     return S_OK;
343 }
344
345 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
346         EDataFlow dataflow, IAudioClient **out)
347 {
348     ACImpl *This;
349
350     TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
351
352     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
353     if(!This)
354         return E_OUTOFMEMORY;
355
356     if(dataflow == eRender)
357         This->fd = open(devnode, O_WRONLY, 0);
358     else if(dataflow == eCapture)
359         This->fd = open(devnode, O_RDONLY, 0);
360     else{
361         HeapFree(GetProcessHeap(), 0, This);
362         return E_INVALIDARG;
363     }
364     if(This->fd < 0){
365         ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
366                 strerror(errno));
367         HeapFree(GetProcessHeap(), 0, This);
368         return AUDCLNT_E_DEVICE_INVALIDATED;
369     }
370
371     This->dataflow = dataflow;
372
373     This->ai.dev = -1;
374     if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
375         ERR("Unable to get audio info for device %s: %d (%s)\n", devnode,
376                 errno, strerror(errno));
377         close(This->fd);
378         HeapFree(GetProcessHeap(), 0, This);
379         return E_FAIL;
380     }
381
382     TRACE("OSS audioinfo:\n");
383     TRACE("devnode: %s\n", This->ai.devnode);
384     TRACE("name: %s\n", This->ai.name);
385     TRACE("busy: %x\n", This->ai.busy);
386     TRACE("caps: %x\n", This->ai.caps);
387     TRACE("iformats: %x\n", This->ai.iformats);
388     TRACE("oformats: %x\n", This->ai.oformats);
389     TRACE("enabled: %d\n", This->ai.enabled);
390     TRACE("min_rate: %d\n", This->ai.min_rate);
391     TRACE("max_rate: %d\n", This->ai.max_rate);
392     TRACE("min_channels: %d\n", This->ai.min_channels);
393     TRACE("max_channels: %d\n", This->ai.max_channels);
394
395     This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
396     This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
397     This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
398     This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
399     This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
400     This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
401
402     InitializeCriticalSection(&This->lock);
403
404     This->parent = dev;
405     IMMDevice_AddRef(This->parent);
406
407     IAudioClient_AddRef(&This->IAudioClient_iface);
408
409     *out = &This->IAudioClient_iface;
410
411     return S_OK;
412 }
413
414 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
415         REFIID riid, void **ppv)
416 {
417     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
418
419     if(!ppv)
420         return E_POINTER;
421     *ppv = NULL;
422     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
423         *ppv = iface;
424     if(*ppv){
425         IUnknown_AddRef((IUnknown*)*ppv);
426         return S_OK;
427     }
428     WARN("Unknown interface %s\n", debugstr_guid(riid));
429     return E_NOINTERFACE;
430 }
431
432 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
433 {
434     ACImpl *This = impl_from_IAudioClient(iface);
435     ULONG ref;
436     ref = InterlockedIncrement(&This->ref);
437     TRACE("(%p) Refcount now %u\n", This, ref);
438     return ref;
439 }
440
441 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
442 {
443     ACImpl *This = impl_from_IAudioClient(iface);
444     ULONG ref;
445     ref = InterlockedDecrement(&This->ref);
446     TRACE("(%p) Refcount now %u\n", This, ref);
447     if(!ref){
448         IAudioClient_Stop(iface);
449         IMMDevice_Release(This->parent);
450         DeleteCriticalSection(&This->lock);
451         close(This->fd);
452         if(This->initted){
453             EnterCriticalSection(&g_sessions_lock);
454             list_remove(&This->entry);
455             LeaveCriticalSection(&g_sessions_lock);
456         }
457         HeapFree(GetProcessHeap(), 0, This->vols);
458         HeapFree(GetProcessHeap(), 0, This->local_buffer);
459         HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
460         CoTaskMemFree(This->fmt);
461         HeapFree(GetProcessHeap(), 0, This);
462     }
463     return ref;
464 }
465
466 static void dump_fmt(const WAVEFORMATEX *fmt)
467 {
468     TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
469     switch(fmt->wFormatTag){
470     case WAVE_FORMAT_PCM:
471         TRACE("WAVE_FORMAT_PCM");
472         break;
473     case WAVE_FORMAT_IEEE_FLOAT:
474         TRACE("WAVE_FORMAT_IEEE_FLOAT");
475         break;
476     case WAVE_FORMAT_EXTENSIBLE:
477         TRACE("WAVE_FORMAT_EXTENSIBLE");
478         break;
479     default:
480         TRACE("Unknown");
481         break;
482     }
483     TRACE(")\n");
484
485     TRACE("nChannels: %u\n", fmt->nChannels);
486     TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
487     TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
488     TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
489     TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
490     TRACE("cbSize: %u\n", fmt->cbSize);
491
492     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
493         WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
494         TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
495         TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
496         TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
497     }
498 }
499
500 static DWORD get_channel_mask(unsigned int channels)
501 {
502     switch(channels){
503     case 0:
504         return 0;
505     case 1:
506         return SPEAKER_FRONT_CENTER;
507     case 2:
508         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
509     case 3:
510         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
511             SPEAKER_LOW_FREQUENCY;
512     case 4:
513         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
514             SPEAKER_BACK_RIGHT;
515     case 5:
516         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
517             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
518     case 6:
519         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
520             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
521     case 7:
522         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
523             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
524             SPEAKER_BACK_CENTER;
525     }
526     FIXME("Unknown speaker configuration: %u\n", channels);
527     return 0;
528 }
529
530 static int get_oss_format(const WAVEFORMATEX *fmt)
531 {
532     WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
533
534     if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
535             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
536              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
537         switch(fmt->wBitsPerSample){
538         case 8:
539             return AFMT_U8;
540         case 16:
541             return AFMT_S16_LE;
542         case 24:
543             return AFMT_S24_LE;
544         case 32:
545             return AFMT_S32_LE;
546         }
547         return -1;
548     }
549
550 #ifdef AFMT_FLOAT
551     if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
552             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
553              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
554         if(fmt->wBitsPerSample != 32)
555             return -1;
556
557         return AFMT_FLOAT;
558     }
559 #endif
560
561     return -1;
562 }
563
564 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
565 {
566     WAVEFORMATEX *ret;
567     size_t size;
568
569     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
570         size = sizeof(WAVEFORMATEXTENSIBLE);
571     else
572         size = sizeof(WAVEFORMATEX);
573
574     ret = CoTaskMemAlloc(size);
575     if(!ret)
576         return NULL;
577
578     memcpy(ret, fmt, size);
579
580     ret->cbSize = size - sizeof(WAVEFORMATEX);
581
582     return ret;
583 }
584
585 static HRESULT setup_oss_device(ACImpl *This, const WAVEFORMATEX *fmt,
586         WAVEFORMATEX **out)
587 {
588     int tmp, oss_format;
589     double tenth;
590     HRESULT ret = S_OK;
591     WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
592     WAVEFORMATEX *closest = NULL;
593
594     tmp = oss_format = get_oss_format(fmt);
595     if(oss_format < 0)
596         return AUDCLNT_E_UNSUPPORTED_FORMAT;
597     if(ioctl(This->fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
598         WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
599         return E_FAIL;
600     }
601     if(tmp != oss_format){
602         TRACE("Format unsupported by this OSS version: %x\n", oss_format);
603         return AUDCLNT_E_UNSUPPORTED_FORMAT;
604     }
605
606     closest = clone_format(fmt);
607
608     tmp = fmt->nSamplesPerSec;
609     if(ioctl(This->fd, SNDCTL_DSP_SPEED, &tmp) < 0){
610         WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
611         CoTaskMemFree(closest);
612         return E_FAIL;
613     }
614     tenth = fmt->nSamplesPerSec * 0.1;
615     if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
616         ret = S_FALSE;
617         closest->nSamplesPerSec = tmp;
618     }
619
620     tmp = fmt->nChannels;
621     if(ioctl(This->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
622         WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
623         CoTaskMemFree(closest);
624         return E_FAIL;
625     }
626     if(tmp != fmt->nChannels){
627         ret = S_FALSE;
628         closest->nChannels = tmp;
629     }
630
631     if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
632         DWORD mask = get_channel_mask(closest->nChannels);
633
634         ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
635
636         if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
637                 fmtex->dwChannelMask != mask)
638             ret = S_FALSE;
639     }
640
641     if(ret == S_OK || !out){
642         CoTaskMemFree( closest);
643         if(out)
644             *out = NULL;
645     }else{
646         closest->nBlockAlign =
647             closest->nChannels * closest->wBitsPerSample / 8;
648         closest->nAvgBytesPerSec =
649             closest->nBlockAlign * closest->nSamplesPerSec;
650         *out = closest;
651     }
652
653     TRACE("returning: %08x\n", ret);
654     return ret;
655 }
656
657 static void session_init_vols(AudioSession *session, UINT channels)
658 {
659     if(session->channel_count < channels){
660         UINT i;
661
662         if(session->channel_vols)
663             session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
664                     session->channel_vols, sizeof(float) * channels);
665         else
666             session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
667                     sizeof(float) * channels);
668         if(!session->channel_vols)
669             return;
670
671         for(i = session->channel_count; i < channels; ++i)
672             session->channel_vols[i] = 1.f;
673
674         session->channel_count = channels;
675     }
676 }
677
678 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
679         UINT num_channels)
680 {
681     AudioSession *ret;
682
683     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
684     if(!ret)
685         return NULL;
686
687     memcpy(&ret->guid, guid, sizeof(GUID));
688
689     ret->device = device;
690
691     list_init(&ret->clients);
692
693     list_add_head(&g_sessions, &ret->entry);
694
695     InitializeCriticalSection(&ret->lock);
696
697     session_init_vols(ret, num_channels);
698
699     ret->master_vol = 1.f;
700
701     return ret;
702 }
703
704 /* if channels == 0, then this will return or create a session with
705  * matching dataflow and GUID. otherwise, channels must also match */
706 static HRESULT get_audio_session(const GUID *sessionguid,
707         IMMDevice *device, UINT channels, AudioSession **out)
708 {
709     AudioSession *session;
710
711     if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
712         *out = create_session(&GUID_NULL, device, channels);
713         if(!*out)
714             return E_OUTOFMEMORY;
715
716         return S_OK;
717     }
718
719     *out = NULL;
720     LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
721         if(session->device == device &&
722                 IsEqualGUID(sessionguid, &session->guid)){
723             session_init_vols(session, channels);
724             *out = session;
725             break;
726         }
727     }
728
729     if(!*out){
730         *out = create_session(sessionguid, device, channels);
731         if(!*out)
732             return E_OUTOFMEMORY;
733     }
734
735     return S_OK;
736 }
737
738 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
739         AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
740         REFERENCE_TIME period, const WAVEFORMATEX *fmt,
741         const GUID *sessionguid)
742 {
743     ACImpl *This = impl_from_IAudioClient(iface);
744     int mask, i;
745     HRESULT hr;
746
747     TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
748           wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
749
750     if(!fmt)
751         return E_POINTER;
752
753     dump_fmt(fmt);
754
755     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
756         return AUDCLNT_E_NOT_INITIALIZED;
757
758     if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
759                 AUDCLNT_STREAMFLAGS_LOOPBACK |
760                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
761                 AUDCLNT_STREAMFLAGS_NOPERSIST |
762                 AUDCLNT_STREAMFLAGS_RATEADJUST |
763                 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
764                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
765                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
766         TRACE("Unknown flags: %08x\n", flags);
767         return E_INVALIDARG;
768     }
769
770     EnterCriticalSection(&This->lock);
771
772     if(This->initted){
773         LeaveCriticalSection(&This->lock);
774         return AUDCLNT_E_ALREADY_INITIALIZED;
775     }
776
777     hr = setup_oss_device(This, fmt, NULL);
778     if(hr == S_FALSE){
779         LeaveCriticalSection(&This->lock);
780         return AUDCLNT_E_UNSUPPORTED_FORMAT;
781     }
782     if(FAILED(hr)){
783         LeaveCriticalSection(&This->lock);
784         return hr;
785     }
786
787     mask = 0;
788     if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
789         LeaveCriticalSection(&This->lock);
790         WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
791         return E_FAIL;
792     }
793
794     mask = (100 << 8) | 100;
795     if(ioctl(This->fd, SNDCTL_DSP_SETPLAYVOL, &mask) < 0)
796         WARN("SETPLAYVOL failed: %d (%s)\n", errno, strerror(errno));
797
798     This->fmt = clone_format(fmt);
799     if(!This->fmt){
800         LeaveCriticalSection(&This->lock);
801         return E_OUTOFMEMORY;
802     }
803
804     if(period)
805         This->period_us = period / 10;
806     else
807         This->period_us = DefaultPeriod / 10;
808
809     This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
810     This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
811             This->bufsize_frames * fmt->nBlockAlign);
812     if(!This->local_buffer){
813         CoTaskMemFree(This->fmt);
814         This->fmt = NULL;
815         LeaveCriticalSection(&This->lock);
816         return E_OUTOFMEMORY;
817     }
818
819     This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
820     if(!This->vols){
821         CoTaskMemFree(This->fmt);
822         This->fmt = NULL;
823         LeaveCriticalSection(&This->lock);
824         return E_OUTOFMEMORY;
825     }
826
827     for(i = 0; i < fmt->nChannels; ++i)
828         This->vols[i] = 1.f;
829
830     This->share = mode;
831     This->flags = flags;
832
833     EnterCriticalSection(&g_sessions_lock);
834
835     hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
836             &This->session);
837     if(FAILED(hr)){
838         LeaveCriticalSection(&g_sessions_lock);
839         HeapFree(GetProcessHeap(), 0, This->vols);
840         This->vols = NULL;
841         CoTaskMemFree(This->fmt);
842         This->fmt = NULL;
843         LeaveCriticalSection(&This->lock);
844         return hr;
845     }
846
847     list_add_tail(&This->session->clients, &This->entry);
848
849     LeaveCriticalSection(&g_sessions_lock);
850
851     This->initted = TRUE;
852
853     oss_setvol(This, -1);
854
855     LeaveCriticalSection(&This->lock);
856
857     return S_OK;
858 }
859
860 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
861         UINT32 *frames)
862 {
863     ACImpl *This = impl_from_IAudioClient(iface);
864
865     TRACE("(%p)->(%p)\n", This, frames);
866
867     if(!frames)
868         return E_POINTER;
869
870     EnterCriticalSection(&This->lock);
871
872     if(!This->initted){
873         LeaveCriticalSection(&This->lock);
874         return AUDCLNT_E_NOT_INITIALIZED;
875     }
876
877     *frames = This->bufsize_frames;
878
879     LeaveCriticalSection(&This->lock);
880
881     return S_OK;
882 }
883
884 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
885         REFERENCE_TIME *latency)
886 {
887     ACImpl *This = impl_from_IAudioClient(iface);
888
889     TRACE("(%p)->(%p)\n", This, latency);
890
891     if(!latency)
892         return E_POINTER;
893
894     EnterCriticalSection(&This->lock);
895
896     if(!This->initted){
897         LeaveCriticalSection(&This->lock);
898         return AUDCLNT_E_NOT_INITIALIZED;
899     }
900
901     if(This->dataflow == eRender){
902         int delay_bytes;
903         double delay_s;
904
905         if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
906             LeaveCriticalSection(&This->lock);
907             WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
908             return E_FAIL;
909         }
910
911         delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
912                 This->fmt->nBlockAlign);
913
914         *latency = delay_s * 10000000;
915     }else
916         *latency = 10000; /* OSS doesn't provide input latency */
917
918     LeaveCriticalSection(&This->lock);
919
920     return S_OK;
921 }
922
923 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
924         UINT32 *numpad)
925 {
926     ACImpl *This = impl_from_IAudioClient(iface);
927     audio_buf_info bi;
928
929     TRACE("(%p)->(%p)\n", This, numpad);
930
931     if(!numpad)
932         return E_POINTER;
933
934     EnterCriticalSection(&This->lock);
935
936     if(!This->initted){
937         LeaveCriticalSection(&This->lock);
938         return AUDCLNT_E_NOT_INITIALIZED;
939     }
940
941     if(This->dataflow == eRender){
942         if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
943             LeaveCriticalSection(&This->lock);
944             WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
945             return E_FAIL;
946         }
947
948         *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
949             This->fmt->nBlockAlign;
950
951         /* when the OSS buffer has less than one fragment of data, including
952          * no data, it often reports it as some non-zero portion of a
953          * fragment. when it has more than one fragment of data, it reports
954          * it as some multiple of that portion of the fragment size.
955          *
956          * so, we have to do some ugly workarounds to report the timing
957          * as accurately as possible */
958         if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
959             *numpad = This->inbuf_frames;
960             This->inbuf_frames = 0;
961         }else{
962             if(*numpad < This->inbuf_frames)
963                 This->inbuf_frames = *numpad;
964             else
965                 *numpad = This->inbuf_frames;
966         }
967     }else if(This->dataflow == eCapture){
968         if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
969             LeaveCriticalSection(&This->lock);
970             WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
971             return E_FAIL;
972         }
973
974         if(bi.bytes <= bi.fragsize)
975             *numpad = 0;
976         else
977             *numpad = bi.bytes / This->fmt->nBlockAlign;
978     }else{
979         LeaveCriticalSection(&This->lock);
980         return E_UNEXPECTED;
981     }
982
983     *numpad += This->held_frames;
984
985     LeaveCriticalSection(&This->lock);
986
987     return S_OK;
988 }
989
990 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
991         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
992         WAVEFORMATEX **outpwfx)
993 {
994     ACImpl *This = impl_from_IAudioClient(iface);
995     HRESULT ret;
996
997     TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
998
999     if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1000         return E_POINTER;
1001
1002     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1003         return E_INVALIDARG;
1004
1005     if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1006             pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1007         return E_INVALIDARG;
1008
1009     dump_fmt(pwfx);
1010
1011     EnterCriticalSection(&This->lock);
1012
1013     ret = setup_oss_device(This, pwfx, outpwfx);
1014
1015     LeaveCriticalSection(&This->lock);
1016
1017     return ret;
1018 }
1019
1020 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1021         WAVEFORMATEX **pwfx)
1022 {
1023     ACImpl *This = impl_from_IAudioClient(iface);
1024     WAVEFORMATEXTENSIBLE *fmt;
1025     int formats;
1026
1027     TRACE("(%p)->(%p)\n", This, pwfx);
1028
1029     if(!pwfx)
1030         return E_POINTER;
1031     *pwfx = NULL;
1032
1033     if(This->dataflow == eRender)
1034         formats = This->ai.oformats;
1035     else if(This->dataflow == eCapture)
1036         formats = This->ai.iformats;
1037     else
1038         return E_UNEXPECTED;
1039
1040     fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1041     if(!fmt)
1042         return E_OUTOFMEMORY;
1043
1044     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1045     if(formats & AFMT_S16_LE){
1046         fmt->Format.wBitsPerSample = 16;
1047         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1048 #ifdef AFMT_FLOAT
1049     }else if(formats & AFMT_FLOAT){
1050         fmt->Format.wBitsPerSample = 32;
1051         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1052 #endif
1053     }else if(formats & AFMT_U8){
1054         fmt->Format.wBitsPerSample = 8;
1055         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1056     }else if(formats & AFMT_S32_LE){
1057         fmt->Format.wBitsPerSample = 32;
1058         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1059     }else if(formats & AFMT_S24_LE){
1060         fmt->Format.wBitsPerSample = 24;
1061         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1062     }else{
1063         ERR("Didn't recognize any available OSS formats: %x\n", formats);
1064         CoTaskMemFree(fmt);
1065         return E_FAIL;
1066     }
1067
1068     fmt->Format.nChannels = This->ai.max_channels;
1069     fmt->Format.nSamplesPerSec = This->ai.max_rate;
1070     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1071
1072     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1073             fmt->Format.nChannels) / 8;
1074     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1075         fmt->Format.nBlockAlign;
1076
1077     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1078     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1079
1080     *pwfx = (WAVEFORMATEX*)fmt;
1081     dump_fmt(*pwfx);
1082
1083     return S_OK;
1084 }
1085
1086 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1087         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1088 {
1089     ACImpl *This = impl_from_IAudioClient(iface);
1090
1091     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1092
1093     if(!defperiod && !minperiod)
1094         return E_POINTER;
1095
1096     EnterCriticalSection(&This->lock);
1097
1098     if(defperiod)
1099         *defperiod = DefaultPeriod;
1100     if(minperiod)
1101         *minperiod = MinimumPeriod;
1102
1103     LeaveCriticalSection(&This->lock);
1104
1105     return S_OK;
1106 }
1107
1108 static void oss_write_data(ACImpl *This)
1109 {
1110     ssize_t written;
1111     UINT32 written_frames;
1112     size_t to_write;
1113     BYTE *buf =
1114         This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1115
1116     if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1117         to_write = This->bufsize_frames - This->lcl_offs_frames;
1118     else
1119         to_write = This->held_frames;
1120
1121     written = write(This->fd, buf, to_write * This->fmt->nBlockAlign);
1122     if(written < 0){
1123         WARN("write failed: %d (%s)\n", errno, strerror(errno));
1124         return;
1125     }
1126     written_frames = written / This->fmt->nBlockAlign;
1127
1128     This->lcl_offs_frames += written_frames;
1129     This->lcl_offs_frames %= This->bufsize_frames;
1130     This->held_frames -= written_frames;
1131     This->inbuf_frames += written_frames;
1132
1133     if(written_frames < to_write){
1134         /* OSS buffer probably full */
1135         return;
1136     }
1137
1138     if(This->held_frames){
1139         /* wrapped and have some data back at the start to write */
1140         written = write(This->fd, This->local_buffer,
1141                 This->held_frames * This->fmt->nBlockAlign);
1142         if(written < 0){
1143             WARN("write failed: %d (%s)\n", errno, strerror(errno));
1144             return;
1145         }
1146         written_frames = written / This->fmt->nBlockAlign;
1147
1148         This->lcl_offs_frames += written_frames;
1149         This->lcl_offs_frames %= This->bufsize_frames;
1150         This->held_frames -= written_frames;
1151         This->inbuf_frames += written_frames;
1152     }
1153 }
1154
1155 static void oss_read_data(ACImpl *This)
1156 {
1157     UINT64 pos, readable;
1158     audio_buf_info bi;
1159     ssize_t nread;
1160
1161     if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1162         WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1163         return;
1164     }
1165
1166     pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1167     readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1168
1169     if(bi.bytes < readable)
1170         readable = bi.bytes;
1171
1172     nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1173             readable);
1174     if(nread < 0){
1175         WARN("read failed: %d (%s)\n", errno, strerror(errno));
1176         return;
1177     }
1178
1179     This->held_frames += nread / This->fmt->nBlockAlign;
1180
1181     if(This->held_frames > This->bufsize_frames){
1182         WARN("Overflow of unread data\n");
1183         This->lcl_offs_frames += This->held_frames;
1184         This->lcl_offs_frames %= This->bufsize_frames;
1185         This->held_frames = This->bufsize_frames;
1186     }
1187 }
1188
1189 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1190 {
1191     ACImpl *This = user;
1192
1193     EnterCriticalSection(&This->lock);
1194
1195     if(This->dataflow == eRender)
1196         oss_write_data(This);
1197     else if(This->dataflow == eCapture)
1198         oss_read_data(This);
1199
1200     if(This->event)
1201         SetEvent(This->event);
1202
1203     LeaveCriticalSection(&This->lock);
1204 }
1205
1206 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1207 {
1208     ACImpl *This = impl_from_IAudioClient(iface);
1209     int mask;
1210
1211     TRACE("(%p)\n", This);
1212
1213     EnterCriticalSection(&This->lock);
1214
1215     if(!This->initted){
1216         LeaveCriticalSection(&This->lock);
1217         return AUDCLNT_E_NOT_INITIALIZED;
1218     }
1219
1220     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1221         LeaveCriticalSection(&This->lock);
1222         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1223     }
1224
1225     if(This->playing){
1226         LeaveCriticalSection(&This->lock);
1227         return AUDCLNT_E_NOT_STOPPED;
1228     }
1229
1230     if(This->dataflow == eRender)
1231         mask = PCM_ENABLE_OUTPUT;
1232     else if(This->dataflow == eCapture)
1233         mask = PCM_ENABLE_INPUT;
1234     else{
1235         LeaveCriticalSection(&This->lock);
1236         return E_UNEXPECTED;
1237     }
1238
1239     if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1240         LeaveCriticalSection(&This->lock);
1241         WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1242         return E_FAIL;
1243     }
1244
1245     if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1246                 oss_period_callback, This, 0, This->period_us / 1000,
1247                 WT_EXECUTEINTIMERTHREAD))
1248         ERR("Unable to create period timer: %u\n", GetLastError());
1249
1250     This->playing = TRUE;
1251
1252     LeaveCriticalSection(&This->lock);
1253
1254     return S_OK;
1255 }
1256
1257 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1258 {
1259     ACImpl *This = impl_from_IAudioClient(iface);
1260     int mask;
1261
1262     TRACE("(%p)\n", This);
1263
1264     EnterCriticalSection(&This->lock);
1265
1266     if(!This->initted){
1267         LeaveCriticalSection(&This->lock);
1268         return AUDCLNT_E_NOT_INITIALIZED;
1269     }
1270
1271     if(!This->playing){
1272         LeaveCriticalSection(&This->lock);
1273         return S_FALSE;
1274     }
1275
1276     if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1277         DeleteTimerQueueTimer(g_timer_q, This->timer,
1278                 INVALID_HANDLE_VALUE);
1279         This->timer = NULL;
1280     }
1281
1282     if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1283         LeaveCriticalSection(&This->lock);
1284         WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1285         return E_FAIL;
1286     }
1287
1288     mask = 0;
1289     if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1290         LeaveCriticalSection(&This->lock);
1291         WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1292         return E_FAIL;
1293     }
1294
1295     This->playing = FALSE;
1296
1297     LeaveCriticalSection(&This->lock);
1298
1299     return S_OK;
1300 }
1301
1302 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1303 {
1304     ACImpl *This = impl_from_IAudioClient(iface);
1305
1306     TRACE("(%p)\n", This);
1307
1308     EnterCriticalSection(&This->lock);
1309
1310     if(!This->initted){
1311         LeaveCriticalSection(&This->lock);
1312         return AUDCLNT_E_NOT_INITIALIZED;
1313     }
1314
1315     if(This->playing){
1316         LeaveCriticalSection(&This->lock);
1317         return AUDCLNT_E_NOT_STOPPED;
1318     }
1319
1320     This->written_frames = 0;
1321     This->inbuf_frames = 0;
1322     This->held_frames = 0;
1323
1324     if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1325         WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1326
1327     LeaveCriticalSection(&This->lock);
1328
1329     return S_OK;
1330 }
1331
1332 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1333         HANDLE event)
1334 {
1335     ACImpl *This = impl_from_IAudioClient(iface);
1336
1337     TRACE("(%p)->(%p)\n", This, event);
1338
1339     if(!event)
1340         return E_INVALIDARG;
1341
1342     EnterCriticalSection(&This->lock);
1343
1344     if(!This->initted){
1345         LeaveCriticalSection(&This->lock);
1346         return AUDCLNT_E_NOT_INITIALIZED;
1347     }
1348
1349     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1350         LeaveCriticalSection(&This->lock);
1351         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1352     }
1353
1354     This->event = event;
1355
1356     LeaveCriticalSection(&This->lock);
1357
1358     return S_OK;
1359 }
1360
1361 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1362         void **ppv)
1363 {
1364     ACImpl *This = impl_from_IAudioClient(iface);
1365
1366     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1367
1368     if(!ppv)
1369         return E_POINTER;
1370     *ppv = NULL;
1371
1372     EnterCriticalSection(&This->lock);
1373
1374     if(!This->initted){
1375         LeaveCriticalSection(&This->lock);
1376         return AUDCLNT_E_NOT_INITIALIZED;
1377     }
1378
1379     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1380         if(This->dataflow != eRender){
1381             LeaveCriticalSection(&This->lock);
1382             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1383         }
1384         *ppv = &This->IAudioRenderClient_iface;
1385     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1386         if(This->dataflow != eCapture){
1387             LeaveCriticalSection(&This->lock);
1388             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1389         }
1390         *ppv = &This->IAudioCaptureClient_iface;
1391     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1392         *ppv = &This->IAudioClock_iface;
1393     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1394         *ppv = &This->IAudioStreamVolume_iface;
1395     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1396         if(!This->session_wrapper){
1397             This->session_wrapper = AudioSessionWrapper_Create(This);
1398             if(!This->session_wrapper){
1399                 LeaveCriticalSection(&This->lock);
1400                 return E_OUTOFMEMORY;
1401             }
1402         }
1403
1404         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1405     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1406         if(!This->session_wrapper){
1407             This->session_wrapper = AudioSessionWrapper_Create(This);
1408             if(!This->session_wrapper){
1409                 LeaveCriticalSection(&This->lock);
1410                 return E_OUTOFMEMORY;
1411             }
1412         }
1413
1414         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1415     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1416         if(!This->session_wrapper){
1417             This->session_wrapper = AudioSessionWrapper_Create(This);
1418             if(!This->session_wrapper){
1419                 LeaveCriticalSection(&This->lock);
1420                 return E_OUTOFMEMORY;
1421             }
1422         }
1423
1424         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1425     }
1426
1427     if(*ppv){
1428         IUnknown_AddRef((IUnknown*)*ppv);
1429         LeaveCriticalSection(&This->lock);
1430         return S_OK;
1431     }
1432
1433     LeaveCriticalSection(&This->lock);
1434
1435     FIXME("stub %s\n", debugstr_guid(riid));
1436     return E_NOINTERFACE;
1437 }
1438
1439 static const IAudioClientVtbl AudioClient_Vtbl =
1440 {
1441     AudioClient_QueryInterface,
1442     AudioClient_AddRef,
1443     AudioClient_Release,
1444     AudioClient_Initialize,
1445     AudioClient_GetBufferSize,
1446     AudioClient_GetStreamLatency,
1447     AudioClient_GetCurrentPadding,
1448     AudioClient_IsFormatSupported,
1449     AudioClient_GetMixFormat,
1450     AudioClient_GetDevicePeriod,
1451     AudioClient_Start,
1452     AudioClient_Stop,
1453     AudioClient_Reset,
1454     AudioClient_SetEventHandle,
1455     AudioClient_GetService
1456 };
1457
1458 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1459         IAudioRenderClient *iface, REFIID riid, void **ppv)
1460 {
1461     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1462
1463     if(!ppv)
1464         return E_POINTER;
1465     *ppv = NULL;
1466
1467     if(IsEqualIID(riid, &IID_IUnknown) ||
1468             IsEqualIID(riid, &IID_IAudioRenderClient))
1469         *ppv = iface;
1470     if(*ppv){
1471         IUnknown_AddRef((IUnknown*)*ppv);
1472         return S_OK;
1473     }
1474
1475     WARN("Unknown interface %s\n", debugstr_guid(riid));
1476     return E_NOINTERFACE;
1477 }
1478
1479 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1480 {
1481     ACImpl *This = impl_from_IAudioRenderClient(iface);
1482     return AudioClient_AddRef(&This->IAudioClient_iface);
1483 }
1484
1485 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1486 {
1487     ACImpl *This = impl_from_IAudioRenderClient(iface);
1488     return AudioClient_Release(&This->IAudioClient_iface);
1489 }
1490
1491 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1492         UINT32 frames, BYTE **data)
1493 {
1494     ACImpl *This = impl_from_IAudioRenderClient(iface);
1495     UINT32 pad, write_pos;
1496     HRESULT hr;
1497
1498     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1499
1500     if(!data)
1501         return E_POINTER;
1502
1503     EnterCriticalSection(&This->lock);
1504
1505     if(This->buf_state != NOT_LOCKED){
1506         LeaveCriticalSection(&This->lock);
1507         return AUDCLNT_E_OUT_OF_ORDER;
1508     }
1509
1510     if(!frames){
1511         This->buf_state = LOCKED_NORMAL;
1512         LeaveCriticalSection(&This->lock);
1513         return S_OK;
1514     }
1515
1516     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1517     if(FAILED(hr)){
1518         LeaveCriticalSection(&This->lock);
1519         return hr;
1520     }
1521
1522     if(pad + frames > This->bufsize_frames){
1523         LeaveCriticalSection(&This->lock);
1524         return AUDCLNT_E_BUFFER_TOO_LARGE;
1525     }
1526
1527     write_pos =
1528         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1529     if(write_pos + frames > This->bufsize_frames){
1530         if(This->tmp_buffer_frames < frames){
1531             if(This->tmp_buffer)
1532                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1533                         This->tmp_buffer, frames * This->fmt->nBlockAlign);
1534             else
1535                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1536                         frames * This->fmt->nBlockAlign);
1537             if(!This->tmp_buffer){
1538                 LeaveCriticalSection(&This->lock);
1539                 return E_OUTOFMEMORY;
1540             }
1541             This->tmp_buffer_frames = frames;
1542         }
1543         *data = This->tmp_buffer;
1544         This->buf_state = LOCKED_WRAPPED;
1545     }else{
1546         *data = This->local_buffer +
1547             This->lcl_offs_frames * This->fmt->nBlockAlign;
1548         This->buf_state = LOCKED_NORMAL;
1549     }
1550
1551     LeaveCriticalSection(&This->lock);
1552
1553     return S_OK;
1554 }
1555
1556 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
1557 {
1558     UINT32 write_offs_frames =
1559         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1560     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1561     UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1562     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1563
1564     if(written_bytes < chunk_bytes){
1565         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1566     }else{
1567         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1568         memcpy(This->local_buffer, buffer + chunk_bytes,
1569                 written_bytes - chunk_bytes);
1570     }
1571 }
1572
1573 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1574         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1575 {
1576     ACImpl *This = impl_from_IAudioRenderClient(iface);
1577     BYTE *buffer;
1578     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1579
1580     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1581
1582     EnterCriticalSection(&This->lock);
1583
1584     if(This->buf_state == NOT_LOCKED || !written_frames){
1585         This->buf_state = NOT_LOCKED;
1586         LeaveCriticalSection(&This->lock);
1587         return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1588     }
1589
1590     if(This->buf_state == LOCKED_NORMAL)
1591         buffer = This->local_buffer +
1592             This->lcl_offs_frames * This->fmt->nBlockAlign;
1593     else
1594         buffer = This->tmp_buffer;
1595
1596     if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1597         WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1598         if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1599                 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1600                  IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1601                 This->fmt->wBitsPerSample == 8)
1602             memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
1603         else
1604             memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
1605     }
1606
1607     if(This->held_frames){
1608         if(This->buf_state == LOCKED_WRAPPED)
1609             oss_wrap_buffer(This, buffer, written_bytes);
1610
1611         This->held_frames += written_frames;
1612     }else{
1613         ssize_t w_bytes;
1614         UINT32 w_frames;
1615
1616         w_bytes = write(This->fd, buffer,
1617                 written_frames * This->fmt->nBlockAlign);
1618         if(w_bytes < 0){
1619             LeaveCriticalSection(&This->lock);
1620             WARN("write failed: %d (%s)\n", errno, strerror(errno));
1621             return E_FAIL;
1622         }
1623         w_frames = w_bytes / This->fmt->nBlockAlign;
1624         This->inbuf_frames += w_frames;
1625
1626         if(w_frames < written_frames){
1627             if(This->buf_state == LOCKED_WRAPPED)
1628                 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1629                         written_frames - w_frames);
1630
1631             This->held_frames = written_frames - w_frames;
1632         }
1633     }
1634
1635     This->written_frames += written_frames;
1636     This->buf_state = NOT_LOCKED;
1637
1638     LeaveCriticalSection(&This->lock);
1639
1640     return S_OK;
1641 }
1642
1643 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1644     AudioRenderClient_QueryInterface,
1645     AudioRenderClient_AddRef,
1646     AudioRenderClient_Release,
1647     AudioRenderClient_GetBuffer,
1648     AudioRenderClient_ReleaseBuffer
1649 };
1650
1651 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1652         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1653 {
1654     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1655
1656     if(!ppv)
1657         return E_POINTER;
1658     *ppv = NULL;
1659
1660     if(IsEqualIID(riid, &IID_IUnknown) ||
1661             IsEqualIID(riid, &IID_IAudioCaptureClient))
1662         *ppv = iface;
1663     if(*ppv){
1664         IUnknown_AddRef((IUnknown*)*ppv);
1665         return S_OK;
1666     }
1667
1668     WARN("Unknown interface %s\n", debugstr_guid(riid));
1669     return E_NOINTERFACE;
1670 }
1671
1672 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1673 {
1674     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1675     return IAudioClient_AddRef(&This->IAudioClient_iface);
1676 }
1677
1678 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1679 {
1680     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1681     return IAudioClient_Release(&This->IAudioClient_iface);
1682 }
1683
1684 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1685         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1686         UINT64 *qpcpos)
1687 {
1688     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1689     HRESULT hr;
1690
1691     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1692             devpos, qpcpos);
1693
1694     if(!data || !frames || !flags)
1695         return E_POINTER;
1696
1697     EnterCriticalSection(&This->lock);
1698
1699     if(This->buf_state != NOT_LOCKED){
1700         LeaveCriticalSection(&This->lock);
1701         return AUDCLNT_E_OUT_OF_ORDER;
1702     }
1703
1704     hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1705     if(FAILED(hr)){
1706         LeaveCriticalSection(&This->lock);
1707         return hr;
1708     }
1709
1710     *flags = 0;
1711
1712     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1713         UINT32 chunk_bytes, offs_bytes, frames_bytes;
1714         if(This->tmp_buffer_frames < *frames){
1715             if(This->tmp_buffer)
1716                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1717                         This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1718             else
1719                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1720                         *frames * This->fmt->nBlockAlign);
1721             if(!This->tmp_buffer){
1722                 LeaveCriticalSection(&This->lock);
1723                 return E_OUTOFMEMORY;
1724             }
1725             This->tmp_buffer_frames = *frames;
1726         }
1727
1728         *data = This->tmp_buffer;
1729         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1730             This->fmt->nBlockAlign;
1731         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1732         frames_bytes = *frames * This->fmt->nBlockAlign;
1733         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1734         memcpy(This->tmp_buffer, This->local_buffer,
1735                 frames_bytes - chunk_bytes);
1736     }else
1737         *data = This->local_buffer +
1738             This->lcl_offs_frames * This->fmt->nBlockAlign;
1739
1740     This->buf_state = LOCKED_NORMAL;
1741
1742     if(devpos || qpcpos)
1743         IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1744
1745     LeaveCriticalSection(&This->lock);
1746
1747     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1748 }
1749
1750 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1751         IAudioCaptureClient *iface, UINT32 done)
1752 {
1753     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1754
1755     TRACE("(%p)->(%u)\n", This, done);
1756
1757     EnterCriticalSection(&This->lock);
1758
1759     if(This->buf_state == NOT_LOCKED){
1760         LeaveCriticalSection(&This->lock);
1761         return AUDCLNT_E_OUT_OF_ORDER;
1762     }
1763
1764     This->held_frames -= done;
1765     This->lcl_offs_frames += done;
1766     This->lcl_offs_frames %= This->bufsize_frames;
1767
1768     This->buf_state = NOT_LOCKED;
1769
1770     LeaveCriticalSection(&This->lock);
1771
1772     return S_OK;
1773 }
1774
1775 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1776         IAudioCaptureClient *iface, UINT32 *frames)
1777 {
1778     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1779
1780     TRACE("(%p)->(%p)\n", This, frames);
1781
1782     return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1783 }
1784
1785 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1786 {
1787     AudioCaptureClient_QueryInterface,
1788     AudioCaptureClient_AddRef,
1789     AudioCaptureClient_Release,
1790     AudioCaptureClient_GetBuffer,
1791     AudioCaptureClient_ReleaseBuffer,
1792     AudioCaptureClient_GetNextPacketSize
1793 };
1794
1795 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1796         REFIID riid, void **ppv)
1797 {
1798     ACImpl *This = impl_from_IAudioClock(iface);
1799
1800     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1801
1802     if(!ppv)
1803         return E_POINTER;
1804     *ppv = NULL;
1805
1806     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1807         *ppv = iface;
1808     else if(IsEqualIID(riid, &IID_IAudioClock2))
1809         *ppv = &This->IAudioClock2_iface;
1810     if(*ppv){
1811         IUnknown_AddRef((IUnknown*)*ppv);
1812         return S_OK;
1813     }
1814
1815     WARN("Unknown interface %s\n", debugstr_guid(riid));
1816     return E_NOINTERFACE;
1817 }
1818
1819 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1820 {
1821     ACImpl *This = impl_from_IAudioClock(iface);
1822     return IAudioClient_AddRef(&This->IAudioClient_iface);
1823 }
1824
1825 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1826 {
1827     ACImpl *This = impl_from_IAudioClock(iface);
1828     return IAudioClient_Release(&This->IAudioClient_iface);
1829 }
1830
1831 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1832 {
1833     ACImpl *This = impl_from_IAudioClock(iface);
1834
1835     TRACE("(%p)->(%p)\n", This, freq);
1836
1837     *freq = This->fmt->nSamplesPerSec;
1838
1839     return S_OK;
1840 }
1841
1842 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1843         UINT64 *qpctime)
1844 {
1845     ACImpl *This = impl_from_IAudioClock(iface);
1846     UINT32 pad;
1847     HRESULT hr;
1848
1849     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1850
1851     if(!pos)
1852         return E_POINTER;
1853
1854     EnterCriticalSection(&This->lock);
1855
1856     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1857     if(FAILED(hr)){
1858         LeaveCriticalSection(&This->lock);
1859         return hr;
1860     }
1861
1862     if(This->dataflow == eRender)
1863         *pos = This->written_frames - pad;
1864     else if(This->dataflow == eCapture)
1865         *pos = This->written_frames + pad;
1866
1867     LeaveCriticalSection(&This->lock);
1868
1869     if(qpctime){
1870         LARGE_INTEGER stamp, freq;
1871         QueryPerformanceCounter(&stamp);
1872         QueryPerformanceFrequency(&freq);
1873         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1874     }
1875
1876     return S_OK;
1877 }
1878
1879 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1880         DWORD *chars)
1881 {
1882     ACImpl *This = impl_from_IAudioClock(iface);
1883
1884     TRACE("(%p)->(%p)\n", This, chars);
1885
1886     if(!chars)
1887         return E_POINTER;
1888
1889     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1890
1891     return S_OK;
1892 }
1893
1894 static const IAudioClockVtbl AudioClock_Vtbl =
1895 {
1896     AudioClock_QueryInterface,
1897     AudioClock_AddRef,
1898     AudioClock_Release,
1899     AudioClock_GetFrequency,
1900     AudioClock_GetPosition,
1901     AudioClock_GetCharacteristics
1902 };
1903
1904 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1905         REFIID riid, void **ppv)
1906 {
1907     ACImpl *This = impl_from_IAudioClock2(iface);
1908     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1909 }
1910
1911 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1912 {
1913     ACImpl *This = impl_from_IAudioClock2(iface);
1914     return IAudioClient_AddRef(&This->IAudioClient_iface);
1915 }
1916
1917 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1918 {
1919     ACImpl *This = impl_from_IAudioClock2(iface);
1920     return IAudioClient_Release(&This->IAudioClient_iface);
1921 }
1922
1923 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1924         UINT64 *pos, UINT64 *qpctime)
1925 {
1926     ACImpl *This = impl_from_IAudioClock2(iface);
1927
1928     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1929
1930     return E_NOTIMPL;
1931 }
1932
1933 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1934 {
1935     AudioClock2_QueryInterface,
1936     AudioClock2_AddRef,
1937     AudioClock2_Release,
1938     AudioClock2_GetDevicePosition
1939 };
1940
1941 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1942 {
1943     AudioSessionWrapper *ret;
1944
1945     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1946             sizeof(AudioSessionWrapper));
1947     if(!ret)
1948         return NULL;
1949
1950     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1951     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1952     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1953
1954     ret->client = client;
1955     if(client){
1956         ret->session = client->session;
1957         AudioClient_AddRef(&client->IAudioClient_iface);
1958     }
1959
1960     return ret;
1961 }
1962
1963 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1964         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1965 {
1966     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1967
1968     if(!ppv)
1969         return E_POINTER;
1970     *ppv = NULL;
1971
1972     if(IsEqualIID(riid, &IID_IUnknown) ||
1973             IsEqualIID(riid, &IID_IAudioSessionControl) ||
1974             IsEqualIID(riid, &IID_IAudioSessionControl2))
1975         *ppv = iface;
1976     if(*ppv){
1977         IUnknown_AddRef((IUnknown*)*ppv);
1978         return S_OK;
1979     }
1980
1981     WARN("Unknown interface %s\n", debugstr_guid(riid));
1982     return E_NOINTERFACE;
1983 }
1984
1985 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1986 {
1987     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1988     ULONG ref;
1989     ref = InterlockedIncrement(&This->ref);
1990     TRACE("(%p) Refcount now %u\n", This, ref);
1991     return ref;
1992 }
1993
1994 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1995 {
1996     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1997     ULONG ref;
1998     ref = InterlockedDecrement(&This->ref);
1999     TRACE("(%p) Refcount now %u\n", This, ref);
2000     if(!ref){
2001         if(This->client){
2002             EnterCriticalSection(&This->client->lock);
2003             This->client->session_wrapper = NULL;
2004             LeaveCriticalSection(&This->client->lock);
2005             AudioClient_Release(&This->client->IAudioClient_iface);
2006         }
2007         HeapFree(GetProcessHeap(), 0, This);
2008     }
2009     return ref;
2010 }
2011
2012 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2013         AudioSessionState *state)
2014 {
2015     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2016     ACImpl *client;
2017
2018     TRACE("(%p)->(%p)\n", This, state);
2019
2020     if(!state)
2021         return NULL_PTR_ERR;
2022
2023     EnterCriticalSection(&g_sessions_lock);
2024
2025     if(list_empty(&This->session->clients)){
2026         *state = AudioSessionStateExpired;
2027         LeaveCriticalSection(&g_sessions_lock);
2028         return S_OK;
2029     }
2030
2031     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2032         EnterCriticalSection(&client->lock);
2033         if(client->playing){
2034             *state = AudioSessionStateActive;
2035             LeaveCriticalSection(&client->lock);
2036             LeaveCriticalSection(&g_sessions_lock);
2037             return S_OK;
2038         }
2039         LeaveCriticalSection(&client->lock);
2040     }
2041
2042     LeaveCriticalSection(&g_sessions_lock);
2043
2044     *state = AudioSessionStateInactive;
2045
2046     return S_OK;
2047 }
2048
2049 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2050         IAudioSessionControl2 *iface, WCHAR **name)
2051 {
2052     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2053
2054     FIXME("(%p)->(%p) - stub\n", This, name);
2055
2056     return E_NOTIMPL;
2057 }
2058
2059 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2060         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2061 {
2062     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2063
2064     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2065
2066     return E_NOTIMPL;
2067 }
2068
2069 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2070         IAudioSessionControl2 *iface, WCHAR **path)
2071 {
2072     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2073
2074     FIXME("(%p)->(%p) - stub\n", This, path);
2075
2076     return E_NOTIMPL;
2077 }
2078
2079 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2080         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2081 {
2082     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2083
2084     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2085
2086     return E_NOTIMPL;
2087 }
2088
2089 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2090         IAudioSessionControl2 *iface, GUID *group)
2091 {
2092     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2093
2094     FIXME("(%p)->(%p) - stub\n", This, group);
2095
2096     return E_NOTIMPL;
2097 }
2098
2099 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2100         IAudioSessionControl2 *iface, GUID *group, const GUID *session)
2101 {
2102     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2103
2104     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2105             debugstr_guid(session));
2106
2107     return E_NOTIMPL;
2108 }
2109
2110 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2111         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2112 {
2113     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2114
2115     FIXME("(%p)->(%p) - stub\n", This, events);
2116
2117     return S_OK;
2118 }
2119
2120 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2121         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2122 {
2123     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2124
2125     FIXME("(%p)->(%p) - stub\n", This, events);
2126
2127     return S_OK;
2128 }
2129
2130 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2131         IAudioSessionControl2 *iface, WCHAR **id)
2132 {
2133     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2134
2135     FIXME("(%p)->(%p) - stub\n", This, id);
2136
2137     return E_NOTIMPL;
2138 }
2139
2140 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2141         IAudioSessionControl2 *iface, WCHAR **id)
2142 {
2143     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2144
2145     FIXME("(%p)->(%p) - stub\n", This, id);
2146
2147     return E_NOTIMPL;
2148 }
2149
2150 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2151         IAudioSessionControl2 *iface, DWORD *pid)
2152 {
2153     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2154
2155     TRACE("(%p)->(%p)\n", This, pid);
2156
2157     if(!pid)
2158         return E_POINTER;
2159
2160     *pid = GetCurrentProcessId();
2161
2162     return S_OK;
2163 }
2164
2165 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2166         IAudioSessionControl2 *iface)
2167 {
2168     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2169
2170     TRACE("(%p)\n", This);
2171
2172     return S_FALSE;
2173 }
2174
2175 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2176         IAudioSessionControl2 *iface, BOOL optout)
2177 {
2178     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2179
2180     TRACE("(%p)->(%d)\n", This, optout);
2181
2182     return S_OK;
2183 }
2184
2185 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2186 {
2187     AudioSessionControl_QueryInterface,
2188     AudioSessionControl_AddRef,
2189     AudioSessionControl_Release,
2190     AudioSessionControl_GetState,
2191     AudioSessionControl_GetDisplayName,
2192     AudioSessionControl_SetDisplayName,
2193     AudioSessionControl_GetIconPath,
2194     AudioSessionControl_SetIconPath,
2195     AudioSessionControl_GetGroupingParam,
2196     AudioSessionControl_SetGroupingParam,
2197     AudioSessionControl_RegisterAudioSessionNotification,
2198     AudioSessionControl_UnregisterAudioSessionNotification,
2199     AudioSessionControl_GetSessionIdentifier,
2200     AudioSessionControl_GetSessionInstanceIdentifier,
2201     AudioSessionControl_GetProcessId,
2202     AudioSessionControl_IsSystemSoundsSession,
2203     AudioSessionControl_SetDuckingPreference
2204 };
2205
2206 /* index == -1 means set all channels, otherwise sets only the given channel */
2207 static HRESULT oss_setvol(ACImpl *This, UINT32 index)
2208 {
2209     int setreq, getreq;
2210     unsigned int vol;
2211     unsigned short l;
2212     float level;
2213
2214     if(index == (UINT32)-1){
2215         HRESULT ret = S_OK;
2216         UINT32 i;
2217         for(i = 0; i < This->fmt->nChannels; ++i){
2218             HRESULT hr;
2219             hr = oss_setvol(This, i);
2220             if(FAILED(hr))
2221                 ret = hr;
2222         }
2223         return ret;
2224     }
2225
2226     if(index > 1)
2227         /* OSS doesn't support volume control past the first two channels */
2228         return S_OK;
2229
2230     if(This->dataflow == eRender){
2231         setreq = SNDCTL_DSP_SETPLAYVOL;
2232         getreq = SNDCTL_DSP_GETPLAYVOL;
2233     }else if(This->dataflow == eCapture){
2234         setreq = SNDCTL_DSP_SETRECVOL;
2235         getreq = SNDCTL_DSP_GETRECVOL;
2236     }else
2237         return E_UNEXPECTED;
2238
2239     if(ioctl(This->fd, getreq, &vol) < 0){
2240         if(errno == EINVAL)
2241             /* device doesn't support this call */
2242             return S_OK;
2243
2244         WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2245         return E_FAIL;
2246     }
2247
2248     level = This->session->master_vol * This->session->channel_vols[index] *
2249         This->vols[index];
2250     l = level * 100;
2251     if(index == 0)
2252         vol = l | (vol & 0xFF00);
2253     else
2254         vol = (vol & 0xFF) | (l << 8);
2255
2256     if(ioctl(This->fd, setreq, &vol) < 0){
2257         if(errno == EINVAL)
2258             /* device doesn't support this call */
2259             return S_OK;
2260
2261         WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2262         return E_FAIL;
2263     }
2264
2265     return S_OK;
2266 }
2267
2268 static HRESULT oss_session_setvol(AudioSession *session, UINT32 index)
2269 {
2270     HRESULT ret = S_OK;
2271     ACImpl *client;
2272
2273     LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2274         HRESULT hr;
2275         hr = oss_setvol(client, index);
2276         if(FAILED(hr))
2277             ret = hr;
2278     }
2279
2280     return ret;
2281 }
2282
2283 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2284         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2285 {
2286     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2287
2288     if(!ppv)
2289         return E_POINTER;
2290     *ppv = NULL;
2291
2292     if(IsEqualIID(riid, &IID_IUnknown) ||
2293             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2294         *ppv = iface;
2295     if(*ppv){
2296         IUnknown_AddRef((IUnknown*)*ppv);
2297         return S_OK;
2298     }
2299
2300     WARN("Unknown interface %s\n", debugstr_guid(riid));
2301     return E_NOINTERFACE;
2302 }
2303
2304 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2305 {
2306     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2307     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2308 }
2309
2310 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2311 {
2312     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2313     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2314 }
2315
2316 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2317         ISimpleAudioVolume *iface, float level, const GUID *context)
2318 {
2319     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2320     AudioSession *session = This->session;
2321     HRESULT ret;
2322
2323     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2324
2325     if(level < 0.f || level > 1.f)
2326         return E_INVALIDARG;
2327
2328     if(context)
2329         FIXME("Notifications not supported yet\n");
2330
2331     EnterCriticalSection(&session->lock);
2332
2333     session->master_vol = level;
2334
2335     ret = oss_session_setvol(session, -1);
2336
2337     LeaveCriticalSection(&session->lock);
2338
2339     return ret;
2340 }
2341
2342 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2343         ISimpleAudioVolume *iface, float *level)
2344 {
2345     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2346     AudioSession *session = This->session;
2347
2348     TRACE("(%p)->(%p)\n", session, level);
2349
2350     if(!level)
2351         return NULL_PTR_ERR;
2352
2353     *level = session->master_vol;
2354
2355     return S_OK;
2356 }
2357
2358 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2359         BOOL mute, const GUID *context)
2360 {
2361     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2362     AudioSession *session = This->session;
2363
2364     FIXME("(%p)->(%u, %p) - stub\n", session, mute, context);
2365
2366     return E_NOTIMPL;
2367 }
2368
2369 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2370         BOOL *mute)
2371 {
2372     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2373     AudioSession *session = This->session;
2374
2375     FIXME("(%p)->(%p) - stub\n", session, mute);
2376
2377     if(!mute)
2378         return NULL_PTR_ERR;
2379
2380     return E_NOTIMPL;
2381 }
2382
2383 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2384 {
2385     SimpleAudioVolume_QueryInterface,
2386     SimpleAudioVolume_AddRef,
2387     SimpleAudioVolume_Release,
2388     SimpleAudioVolume_SetMasterVolume,
2389     SimpleAudioVolume_GetMasterVolume,
2390     SimpleAudioVolume_SetMute,
2391     SimpleAudioVolume_GetMute
2392 };
2393
2394 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2395         IAudioStreamVolume *iface, REFIID riid, void **ppv)
2396 {
2397     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2398
2399     if(!ppv)
2400         return E_POINTER;
2401     *ppv = NULL;
2402
2403     if(IsEqualIID(riid, &IID_IUnknown) ||
2404             IsEqualIID(riid, &IID_IAudioStreamVolume))
2405         *ppv = iface;
2406     if(*ppv){
2407         IUnknown_AddRef((IUnknown*)*ppv);
2408         return S_OK;
2409     }
2410
2411     WARN("Unknown interface %s\n", debugstr_guid(riid));
2412     return E_NOINTERFACE;
2413 }
2414
2415 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2416 {
2417     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2418     return IAudioClient_AddRef(&This->IAudioClient_iface);
2419 }
2420
2421 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2422 {
2423     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2424     return IAudioClient_Release(&This->IAudioClient_iface);
2425 }
2426
2427 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2428         IAudioStreamVolume *iface, UINT32 *out)
2429 {
2430     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2431
2432     TRACE("(%p)->(%p)\n", This, out);
2433
2434     if(!out)
2435         return E_POINTER;
2436
2437     *out = This->fmt->nChannels;
2438
2439     return S_OK;
2440 }
2441
2442 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2443         IAudioStreamVolume *iface, UINT32 index, float level)
2444 {
2445     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2446     HRESULT ret;
2447
2448     TRACE("(%p)->(%d, %f)\n", This, index, level);
2449
2450     if(level < 0.f || level > 1.f)
2451         return E_INVALIDARG;
2452
2453     if(index >= This->fmt->nChannels)
2454         return E_INVALIDARG;
2455
2456     EnterCriticalSection(&This->lock);
2457
2458     This->vols[index] = level;
2459
2460     ret = oss_setvol(This, index);
2461
2462     LeaveCriticalSection(&This->lock);
2463
2464     return ret;
2465 }
2466
2467 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2468         IAudioStreamVolume *iface, UINT32 index, float *level)
2469 {
2470     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2471
2472     TRACE("(%p)->(%d, %p)\n", This, index, level);
2473
2474     if(!level)
2475         return E_POINTER;
2476
2477     if(index >= This->fmt->nChannels)
2478         return E_INVALIDARG;
2479
2480     *level = This->vols[index];
2481
2482     return S_OK;
2483 }
2484
2485 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2486         IAudioStreamVolume *iface, UINT32 count, const float *levels)
2487 {
2488     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2489     int i;
2490     HRESULT ret;
2491
2492     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2493
2494     if(!levels)
2495         return E_POINTER;
2496
2497     if(count != This->fmt->nChannels)
2498         return E_INVALIDARG;
2499
2500     EnterCriticalSection(&This->lock);
2501
2502     for(i = 0; i < count; ++i)
2503         This->vols[i] = levels[i];
2504
2505     ret = oss_setvol(This, -1);
2506
2507     LeaveCriticalSection(&This->lock);
2508
2509     return ret;
2510 }
2511
2512 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2513         IAudioStreamVolume *iface, UINT32 count, float *levels)
2514 {
2515     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2516     int i;
2517
2518     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2519
2520     if(!levels)
2521         return E_POINTER;
2522
2523     if(count != This->fmt->nChannels)
2524         return E_INVALIDARG;
2525
2526     EnterCriticalSection(&This->lock);
2527
2528     for(i = 0; i < count; ++i)
2529         levels[i] = This->vols[i];
2530
2531     LeaveCriticalSection(&This->lock);
2532
2533     return S_OK;
2534 }
2535
2536 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2537 {
2538     AudioStreamVolume_QueryInterface,
2539     AudioStreamVolume_AddRef,
2540     AudioStreamVolume_Release,
2541     AudioStreamVolume_GetChannelCount,
2542     AudioStreamVolume_SetChannelVolume,
2543     AudioStreamVolume_GetChannelVolume,
2544     AudioStreamVolume_SetAllVolumes,
2545     AudioStreamVolume_GetAllVolumes
2546 };
2547
2548 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2549         IChannelAudioVolume *iface, REFIID riid, void **ppv)
2550 {
2551     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2552
2553     if(!ppv)
2554         return E_POINTER;
2555     *ppv = NULL;
2556
2557     if(IsEqualIID(riid, &IID_IUnknown) ||
2558             IsEqualIID(riid, &IID_IChannelAudioVolume))
2559         *ppv = iface;
2560     if(*ppv){
2561         IUnknown_AddRef((IUnknown*)*ppv);
2562         return S_OK;
2563     }
2564
2565     WARN("Unknown interface %s\n", debugstr_guid(riid));
2566     return E_NOINTERFACE;
2567 }
2568
2569 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2570 {
2571     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2572     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2573 }
2574
2575 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2576 {
2577     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2578     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2579 }
2580
2581 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2582         IChannelAudioVolume *iface, UINT32 *out)
2583 {
2584     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2585     AudioSession *session = This->session;
2586
2587     TRACE("(%p)->(%p)\n", session, out);
2588
2589     if(!out)
2590         return NULL_PTR_ERR;
2591
2592     *out = session->channel_count;
2593
2594     return S_OK;
2595 }
2596
2597 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2598         IChannelAudioVolume *iface, UINT32 index, float level,
2599         const GUID *context)
2600 {
2601     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2602     AudioSession *session = This->session;
2603     HRESULT ret;
2604
2605     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2606             wine_dbgstr_guid(context));
2607
2608     if(level < 0.f || level > 1.f)
2609         return E_INVALIDARG;
2610
2611     if(index >= session->channel_count)
2612         return E_INVALIDARG;
2613
2614     if(context)
2615         FIXME("Notifications not supported yet\n");
2616
2617     EnterCriticalSection(&session->lock);
2618
2619     session->channel_vols[index] = level;
2620
2621     ret = oss_session_setvol(session, index);
2622
2623     LeaveCriticalSection(&session->lock);
2624
2625     return ret;
2626 }
2627
2628 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2629         IChannelAudioVolume *iface, UINT32 index, float *level)
2630 {
2631     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2632     AudioSession *session = This->session;
2633
2634     TRACE("(%p)->(%d, %p)\n", session, index, level);
2635
2636     if(!level)
2637         return NULL_PTR_ERR;
2638
2639     if(index >= session->channel_count)
2640         return E_INVALIDARG;
2641
2642     *level = session->channel_vols[index];
2643
2644     return S_OK;
2645 }
2646
2647 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2648         IChannelAudioVolume *iface, UINT32 count, const float *levels,
2649         const GUID *context)
2650 {
2651     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2652     AudioSession *session = This->session;
2653     int i;
2654     HRESULT ret;
2655
2656     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2657             wine_dbgstr_guid(context));
2658
2659     if(!levels)
2660         return NULL_PTR_ERR;
2661
2662     if(count != session->channel_count)
2663         return E_INVALIDARG;
2664
2665     if(context)
2666         FIXME("Notifications not supported yet\n");
2667
2668     EnterCriticalSection(&session->lock);
2669
2670     for(i = 0; i < count; ++i)
2671         session->channel_vols[i] = levels[i];
2672
2673     ret = oss_session_setvol(session, -1);
2674
2675     LeaveCriticalSection(&session->lock);
2676
2677     return ret;
2678 }
2679
2680 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2681         IChannelAudioVolume *iface, UINT32 count, float *levels)
2682 {
2683     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2684     AudioSession *session = This->session;
2685     int i;
2686
2687     TRACE("(%p)->(%d, %p)\n", session, count, levels);
2688
2689     if(!levels)
2690         return NULL_PTR_ERR;
2691
2692     if(count != session->channel_count)
2693         return E_INVALIDARG;
2694
2695     for(i = 0; i < count; ++i)
2696         levels[i] = session->channel_vols[i];
2697
2698     return S_OK;
2699 }
2700
2701 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2702 {
2703     ChannelAudioVolume_QueryInterface,
2704     ChannelAudioVolume_AddRef,
2705     ChannelAudioVolume_Release,
2706     ChannelAudioVolume_GetChannelCount,
2707     ChannelAudioVolume_SetChannelVolume,
2708     ChannelAudioVolume_GetChannelVolume,
2709     ChannelAudioVolume_SetAllVolumes,
2710     ChannelAudioVolume_GetAllVolumes
2711 };
2712
2713 HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2714         REFIID riid, void **ppv)
2715 {
2716     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2717
2718     if(!ppv)
2719         return E_POINTER;
2720     *ppv = NULL;
2721
2722     if(IsEqualIID(riid, &IID_IUnknown) ||
2723             IsEqualIID(riid, &IID_IAudioSessionManager) ||
2724             IsEqualIID(riid, &IID_IAudioSessionManager2))
2725         *ppv = iface;
2726     if(*ppv){
2727         IUnknown_AddRef((IUnknown*)*ppv);
2728         return S_OK;
2729     }
2730
2731     WARN("Unknown interface %s\n", debugstr_guid(riid));
2732     return E_NOINTERFACE;
2733 }
2734
2735 ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2736 {
2737     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2738     ULONG ref;
2739     ref = InterlockedIncrement(&This->ref);
2740     TRACE("(%p) Refcount now %u\n", This, ref);
2741     return ref;
2742 }
2743
2744 ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2745 {
2746     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2747     ULONG ref;
2748     ref = InterlockedDecrement(&This->ref);
2749     TRACE("(%p) Refcount now %u\n", This, ref);
2750     if(!ref)
2751         HeapFree(GetProcessHeap(), 0, This);
2752     return ref;
2753 }
2754
2755 HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2756         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2757         IAudioSessionControl **out)
2758 {
2759     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2760     AudioSession *session;
2761     AudioSessionWrapper *wrapper;
2762     HRESULT hr;
2763
2764     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2765             flags, out);
2766
2767     hr = get_audio_session(session_guid, This->device, 0, &session);
2768     if(FAILED(hr))
2769         return hr;
2770
2771     wrapper = AudioSessionWrapper_Create(NULL);
2772     if(!wrapper)
2773         return E_OUTOFMEMORY;
2774
2775     wrapper->session = session;
2776
2777     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2778
2779     return S_OK;
2780 }
2781
2782 HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2783         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2784         ISimpleAudioVolume **out)
2785 {
2786     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2787     AudioSession *session;
2788     AudioSessionWrapper *wrapper;
2789     HRESULT hr;
2790
2791     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2792             flags, out);
2793
2794     hr = get_audio_session(session_guid, This->device, 0, &session);
2795     if(FAILED(hr))
2796         return hr;
2797
2798     wrapper = AudioSessionWrapper_Create(NULL);
2799     if(!wrapper)
2800         return E_OUTOFMEMORY;
2801
2802     wrapper->session = session;
2803
2804     *out = &wrapper->ISimpleAudioVolume_iface;
2805
2806     return S_OK;
2807 }
2808
2809 HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2810         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2811 {
2812     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2813     FIXME("(%p)->(%p) - stub\n", This, out);
2814     return E_NOTIMPL;
2815 }
2816
2817 HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2818         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2819 {
2820     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2821     FIXME("(%p)->(%p) - stub\n", This, notification);
2822     return E_NOTIMPL;
2823 }
2824
2825 HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2826         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2827 {
2828     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2829     FIXME("(%p)->(%p) - stub\n", This, notification);
2830     return E_NOTIMPL;
2831 }
2832
2833 HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2834         IAudioSessionManager2 *iface, const WCHAR *session_id,
2835         IAudioVolumeDuckNotification *notification)
2836 {
2837     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2838     FIXME("(%p)->(%p) - stub\n", This, notification);
2839     return E_NOTIMPL;
2840 }
2841
2842 HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2843         IAudioSessionManager2 *iface,
2844         IAudioVolumeDuckNotification *notification)
2845 {
2846     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2847     FIXME("(%p)->(%p) - stub\n", This, notification);
2848     return E_NOTIMPL;
2849 }
2850
2851 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2852 {
2853     AudioSessionManager_QueryInterface,
2854     AudioSessionManager_AddRef,
2855     AudioSessionManager_Release,
2856     AudioSessionManager_GetAudioSessionControl,
2857     AudioSessionManager_GetSimpleAudioVolume,
2858     AudioSessionManager_GetSessionEnumerator,
2859     AudioSessionManager_RegisterSessionNotification,
2860     AudioSessionManager_UnregisterSessionNotification,
2861     AudioSessionManager_RegisterDuckNotification,
2862     AudioSessionManager_UnregisterDuckNotification
2863 };
2864
2865 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2866         IAudioSessionManager2 **out)
2867 {
2868     SessionMgr *This;
2869
2870     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2871     if(!This)
2872         return E_OUTOFMEMORY;
2873
2874     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2875     This->device = device;
2876     This->ref = 1;
2877
2878     *out = &This->IAudioSessionManager2_iface;
2879
2880     return S_OK;
2881 }