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