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