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