Release 1.5.29.
[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(AUDCLNT_SHAREMODE mode, int fd,
841         const WAVEFORMATEX *fmt, WAVEFORMATEX **out)
842 {
843     int tmp, oss_format;
844     double tenth;
845     HRESULT ret = S_OK;
846     WAVEFORMATEX *closest = NULL;
847
848     tmp = oss_format = get_oss_format(fmt);
849     if(oss_format < 0)
850         return AUDCLNT_E_UNSUPPORTED_FORMAT;
851     if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
852         WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
853         return E_FAIL;
854     }
855     if(tmp != oss_format){
856         TRACE("Format unsupported by this OSS version: %x\n", oss_format);
857         return AUDCLNT_E_UNSUPPORTED_FORMAT;
858     }
859
860     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
861             (fmt->nAvgBytesPerSec == 0 ||
862              fmt->nBlockAlign == 0 ||
863              ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample > fmt->wBitsPerSample))
864         return E_INVALIDARG;
865
866     if(fmt->nChannels == 0)
867         return AUDCLNT_E_UNSUPPORTED_FORMAT;
868
869     closest = clone_format(fmt);
870     if(!closest)
871         return E_OUTOFMEMORY;
872
873     tmp = fmt->nSamplesPerSec;
874     if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
875         WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
876         CoTaskMemFree(closest);
877         return E_FAIL;
878     }
879     tenth = fmt->nSamplesPerSec * 0.1;
880     if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
881         ret = S_FALSE;
882         closest->nSamplesPerSec = tmp;
883     }
884
885     tmp = fmt->nChannels;
886     if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
887         WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
888         CoTaskMemFree(closest);
889         return E_FAIL;
890     }
891     if(tmp != fmt->nChannels){
892         ret = S_FALSE;
893         closest->nChannels = tmp;
894     }
895
896     if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
897         ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = get_channel_mask(closest->nChannels);
898
899     if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
900             fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec ||
901             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
902              ((WAVEFORMATEXTENSIBLE*)fmt)->Samples.wValidBitsPerSample < fmt->wBitsPerSample))
903         ret = S_FALSE;
904
905     if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
906             fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
907         if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 ||
908                 ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED)
909             ret = S_FALSE;
910     }
911
912     if(ret == S_FALSE && !out)
913         ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
914
915     if(ret == S_FALSE && out){
916         closest->nBlockAlign =
917             closest->nChannels * closest->wBitsPerSample / 8;
918         closest->nAvgBytesPerSec =
919             closest->nBlockAlign * closest->nSamplesPerSec;
920         if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
921             ((WAVEFORMATEXTENSIBLE*)closest)->Samples.wValidBitsPerSample = closest->wBitsPerSample;
922         *out = closest;
923     } else
924         CoTaskMemFree(closest);
925
926     TRACE("returning: %08x\n", ret);
927     return ret;
928 }
929
930 static void session_init_vols(AudioSession *session, UINT channels)
931 {
932     if(session->channel_count < channels){
933         UINT i;
934
935         if(session->channel_vols)
936             session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
937                     session->channel_vols, sizeof(float) * channels);
938         else
939             session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
940                     sizeof(float) * channels);
941         if(!session->channel_vols)
942             return;
943
944         for(i = session->channel_count; i < channels; ++i)
945             session->channel_vols[i] = 1.f;
946
947         session->channel_count = channels;
948     }
949 }
950
951 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
952         UINT num_channels)
953 {
954     AudioSession *ret;
955
956     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
957     if(!ret)
958         return NULL;
959
960     memcpy(&ret->guid, guid, sizeof(GUID));
961
962     ret->device = device;
963
964     list_init(&ret->clients);
965
966     list_add_head(&g_sessions, &ret->entry);
967
968     InitializeCriticalSection(&ret->lock);
969     ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
970
971     session_init_vols(ret, num_channels);
972
973     ret->master_vol = 1.f;
974
975     return ret;
976 }
977
978 /* if channels == 0, then this will return or create a session with
979  * matching dataflow and GUID. otherwise, channels must also match */
980 static HRESULT get_audio_session(const GUID *sessionguid,
981         IMMDevice *device, UINT channels, AudioSession **out)
982 {
983     AudioSession *session;
984
985     if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
986         *out = create_session(&GUID_NULL, device, channels);
987         if(!*out)
988             return E_OUTOFMEMORY;
989
990         return S_OK;
991     }
992
993     *out = NULL;
994     LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
995         if(session->device == device &&
996                 IsEqualGUID(sessionguid, &session->guid)){
997             session_init_vols(session, channels);
998             *out = session;
999             break;
1000         }
1001     }
1002
1003     if(!*out){
1004         *out = create_session(sessionguid, device, channels);
1005         if(!*out)
1006             return E_OUTOFMEMORY;
1007     }
1008
1009     return S_OK;
1010 }
1011
1012 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
1013         AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
1014         REFERENCE_TIME period, const WAVEFORMATEX *fmt,
1015         const GUID *sessionguid)
1016 {
1017     ACImpl *This = impl_from_IAudioClient(iface);
1018     int i;
1019     HRESULT hr;
1020
1021     TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
1022           wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
1023
1024     if(!fmt)
1025         return E_POINTER;
1026
1027     dump_fmt(fmt);
1028
1029     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1030         return AUDCLNT_E_NOT_INITIALIZED;
1031
1032     if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
1033                 AUDCLNT_STREAMFLAGS_LOOPBACK |
1034                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
1035                 AUDCLNT_STREAMFLAGS_NOPERSIST |
1036                 AUDCLNT_STREAMFLAGS_RATEADJUST |
1037                 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
1038                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
1039                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
1040         TRACE("Unknown flags: %08x\n", flags);
1041         return E_INVALIDARG;
1042     }
1043
1044     if(mode == AUDCLNT_SHAREMODE_SHARED){
1045         period = DefaultPeriod;
1046         if( duration < 3 * period)
1047             duration = 3 * period;
1048     }else{
1049         if(!period)
1050             period = DefaultPeriod; /* not minimum */
1051         if(period < MinimumPeriod || period > 5000000)
1052             return AUDCLNT_E_INVALID_DEVICE_PERIOD;
1053         if(duration > 20000000) /* the smaller the period, the lower this limit */
1054             return AUDCLNT_E_BUFFER_SIZE_ERROR;
1055         if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
1056             if(duration != period)
1057                 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
1058             FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
1059             return AUDCLNT_E_DEVICE_IN_USE;
1060         }else{
1061             if( duration < 8 * period)
1062                 duration = 8 * period; /* may grow above 2s */
1063         }
1064     }
1065
1066     EnterCriticalSection(&This->lock);
1067
1068     if(This->initted){
1069         LeaveCriticalSection(&This->lock);
1070         return AUDCLNT_E_ALREADY_INITIALIZED;
1071     }
1072
1073     hr = setup_oss_device(mode, This->fd, fmt, NULL);
1074     if(FAILED(hr)){
1075         LeaveCriticalSection(&This->lock);
1076         return hr;
1077     }
1078
1079     This->fmt = clone_format(fmt);
1080     if(!This->fmt){
1081         LeaveCriticalSection(&This->lock);
1082         return E_OUTOFMEMORY;
1083     }
1084
1085     This->period_us = period / 10;
1086     This->period_frames = MulDiv(fmt->nSamplesPerSec, period, 10000000);
1087
1088     This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
1089     This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
1090             This->bufsize_frames * fmt->nBlockAlign);
1091     if(!This->local_buffer){
1092         CoTaskMemFree(This->fmt);
1093         This->fmt = NULL;
1094         LeaveCriticalSection(&This->lock);
1095         return E_OUTOFMEMORY;
1096     }
1097
1098     This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
1099     if(!This->vols){
1100         CoTaskMemFree(This->fmt);
1101         This->fmt = NULL;
1102         LeaveCriticalSection(&This->lock);
1103         return E_OUTOFMEMORY;
1104     }
1105
1106     for(i = 0; i < fmt->nChannels; ++i)
1107         This->vols[i] = 1.f;
1108
1109     This->share = mode;
1110     This->flags = flags;
1111     This->oss_bufsize_bytes = 0;
1112
1113     EnterCriticalSection(&g_sessions_lock);
1114
1115     hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
1116             &This->session);
1117     if(FAILED(hr)){
1118         LeaveCriticalSection(&g_sessions_lock);
1119         HeapFree(GetProcessHeap(), 0, This->vols);
1120         This->vols = NULL;
1121         CoTaskMemFree(This->fmt);
1122         This->fmt = NULL;
1123         LeaveCriticalSection(&This->lock);
1124         return hr;
1125     }
1126
1127     list_add_tail(&This->session->clients, &This->entry);
1128
1129     LeaveCriticalSection(&g_sessions_lock);
1130
1131     This->initted = TRUE;
1132
1133     LeaveCriticalSection(&This->lock);
1134
1135     return S_OK;
1136 }
1137
1138 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1139         UINT32 *frames)
1140 {
1141     ACImpl *This = impl_from_IAudioClient(iface);
1142
1143     TRACE("(%p)->(%p)\n", This, frames);
1144
1145     if(!frames)
1146         return E_POINTER;
1147
1148     EnterCriticalSection(&This->lock);
1149
1150     if(!This->initted){
1151         LeaveCriticalSection(&This->lock);
1152         return AUDCLNT_E_NOT_INITIALIZED;
1153     }
1154
1155     *frames = This->bufsize_frames;
1156
1157     TRACE("buffer size: %u\n", *frames);
1158
1159     LeaveCriticalSection(&This->lock);
1160
1161     return S_OK;
1162 }
1163
1164 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1165         REFERENCE_TIME *latency)
1166 {
1167     ACImpl *This = impl_from_IAudioClient(iface);
1168
1169     TRACE("(%p)->(%p)\n", This, latency);
1170
1171     if(!latency)
1172         return E_POINTER;
1173
1174     EnterCriticalSection(&This->lock);
1175
1176     if(!This->initted){
1177         LeaveCriticalSection(&This->lock);
1178         return AUDCLNT_E_NOT_INITIALIZED;
1179     }
1180
1181     /* pretend we process audio in Period chunks, so max latency includes
1182      * the period time.  Some native machines add .6666ms in shared mode. */
1183     *latency = This->period_us * 10 + 6666;
1184
1185     LeaveCriticalSection(&This->lock);
1186
1187     return S_OK;
1188 }
1189
1190 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1191         UINT32 *numpad)
1192 {
1193     ACImpl *This = impl_from_IAudioClient(iface);
1194
1195     TRACE("(%p)->(%p)\n", This, numpad);
1196
1197     if(!numpad)
1198         return E_POINTER;
1199
1200     EnterCriticalSection(&This->lock);
1201
1202     if(!This->initted){
1203         LeaveCriticalSection(&This->lock);
1204         return AUDCLNT_E_NOT_INITIALIZED;
1205     }
1206
1207     *numpad = This->held_frames;
1208
1209     TRACE("padding: %u\n", *numpad);
1210
1211     LeaveCriticalSection(&This->lock);
1212
1213     return S_OK;
1214 }
1215
1216 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1217         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1218         WAVEFORMATEX **outpwfx)
1219 {
1220     ACImpl *This = impl_from_IAudioClient(iface);
1221     int fd = -1;
1222     HRESULT ret;
1223
1224     TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1225
1226     if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1227         return E_POINTER;
1228
1229     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1230         return E_INVALIDARG;
1231
1232     if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1233             pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1234         return E_INVALIDARG;
1235
1236     dump_fmt(pwfx);
1237
1238     if(outpwfx){
1239         *outpwfx = NULL;
1240         if(mode != AUDCLNT_SHAREMODE_SHARED)
1241             outpwfx = NULL;
1242     }
1243
1244     if(This->dataflow == eRender)
1245         fd = open(This->devnode, O_WRONLY | O_NONBLOCK, 0);
1246     else if(This->dataflow == eCapture)
1247         fd = open(This->devnode, O_RDONLY | O_NONBLOCK, 0);
1248
1249     if(fd < 0){
1250         WARN("Unable to open device %s: %d (%s)\n", This->devnode, errno,
1251                 strerror(errno));
1252         return AUDCLNT_E_DEVICE_INVALIDATED;
1253     }
1254
1255     ret = setup_oss_device(mode, fd, pwfx, outpwfx);
1256
1257     close(fd);
1258
1259     return ret;
1260 }
1261
1262 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1263         WAVEFORMATEX **pwfx)
1264 {
1265     ACImpl *This = impl_from_IAudioClient(iface);
1266     WAVEFORMATEXTENSIBLE *fmt;
1267     int formats;
1268
1269     TRACE("(%p)->(%p)\n", This, pwfx);
1270
1271     if(!pwfx)
1272         return E_POINTER;
1273     *pwfx = NULL;
1274
1275     if(This->dataflow == eRender)
1276         formats = This->ai.oformats;
1277     else if(This->dataflow == eCapture)
1278         formats = This->ai.iformats;
1279     else
1280         return E_UNEXPECTED;
1281
1282     fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1283     if(!fmt)
1284         return E_OUTOFMEMORY;
1285
1286     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1287     if(formats & AFMT_S16_LE){
1288         fmt->Format.wBitsPerSample = 16;
1289         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1290 #ifdef AFMT_FLOAT
1291     }else if(formats & AFMT_FLOAT){
1292         fmt->Format.wBitsPerSample = 32;
1293         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1294 #endif
1295     }else if(formats & AFMT_U8){
1296         fmt->Format.wBitsPerSample = 8;
1297         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1298     }else if(formats & AFMT_S32_LE){
1299         fmt->Format.wBitsPerSample = 32;
1300         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1301     }else if(formats & AFMT_S24_LE){
1302         fmt->Format.wBitsPerSample = 24;
1303         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1304     }else{
1305         WARN("Didn't recognize any available OSS formats: %x\n", formats);
1306         CoTaskMemFree(fmt);
1307         return E_FAIL;
1308     }
1309
1310     /* some OSS drivers are buggy, so set reasonable defaults if
1311      * the reported values seem wacky */
1312     fmt->Format.nChannels = max(This->ai.max_channels, This->ai.min_channels);
1313     if(fmt->Format.nChannels == 0 || fmt->Format.nChannels > 8)
1314         fmt->Format.nChannels = 2;
1315
1316     if(This->ai.max_rate == 0)
1317         fmt->Format.nSamplesPerSec = 44100;
1318     else
1319         fmt->Format.nSamplesPerSec = min(This->ai.max_rate, 44100);
1320     if(fmt->Format.nSamplesPerSec < This->ai.min_rate)
1321         fmt->Format.nSamplesPerSec = This->ai.min_rate;
1322
1323     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1324
1325     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1326             fmt->Format.nChannels) / 8;
1327     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1328         fmt->Format.nBlockAlign;
1329
1330     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1331     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1332
1333     *pwfx = (WAVEFORMATEX*)fmt;
1334     dump_fmt(*pwfx);
1335
1336     return S_OK;
1337 }
1338
1339 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1340         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1341 {
1342     ACImpl *This = impl_from_IAudioClient(iface);
1343
1344     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1345
1346     if(!defperiod && !minperiod)
1347         return E_POINTER;
1348
1349     if(defperiod)
1350         *defperiod = DefaultPeriod;
1351     if(minperiod)
1352         *minperiod = MinimumPeriod;
1353
1354     return S_OK;
1355 }
1356
1357 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1358 {
1359     if(This->fmt->wBitsPerSample == 8)
1360         memset(buf, 128, frames * This->fmt->nBlockAlign);
1361     else
1362         memset(buf, 0, frames * This->fmt->nBlockAlign);
1363 }
1364
1365 static void oss_write_data(ACImpl *This)
1366 {
1367     ssize_t written_bytes;
1368     UINT32 written_frames, in_oss_frames, write_limit, max_period;
1369     size_t to_write_frames, to_write_bytes;
1370     audio_buf_info bi;
1371     BYTE *buf =
1372         This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1373
1374     if(This->held_frames == 0)
1375         return;
1376
1377     if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1378         to_write_frames = This->bufsize_frames - This->lcl_offs_frames;
1379     else
1380         to_write_frames = This->held_frames;
1381
1382     if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1383         WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1384         return;
1385     }
1386
1387     max_period = max(bi.fragsize / This->fmt->nBlockAlign, This->period_frames);
1388
1389     if(bi.bytes > This->oss_bufsize_bytes){
1390         TRACE("New buffer size (%u) is larger than old buffer size (%u)\n",
1391                 bi.bytes, This->oss_bufsize_bytes);
1392         This->oss_bufsize_bytes = bi.bytes;
1393         in_oss_frames = 0;
1394     }else if(This->oss_bufsize_bytes - bi.bytes <= bi.fragsize)
1395         in_oss_frames = 0;
1396     else
1397         in_oss_frames = (This->oss_bufsize_bytes - bi.bytes) / This->fmt->nBlockAlign;
1398
1399     write_limit = 0;
1400     while(write_limit + in_oss_frames < max_period * 3)
1401         write_limit += max_period;
1402     if(write_limit == 0)
1403         return;
1404
1405     to_write_frames = min(to_write_frames, write_limit);
1406     to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1407
1408     if(This->session->mute)
1409         oss_silence_buffer(This, buf, to_write_frames);
1410
1411     written_bytes = write(This->fd, buf, to_write_bytes);
1412     if(written_bytes < 0){
1413         /* EAGAIN is OSS buffer full, log that too */
1414         WARN("write failed: %d (%s)\n", errno, strerror(errno));
1415         return;
1416     }
1417     written_frames = written_bytes / This->fmt->nBlockAlign;
1418
1419     This->lcl_offs_frames += written_frames;
1420     This->lcl_offs_frames %= This->bufsize_frames;
1421     This->held_frames -= written_frames;
1422
1423     if(written_frames < to_write_frames){
1424         /* OSS buffer probably full */
1425         return;
1426     }
1427
1428     if(This->held_frames && written_frames < write_limit){
1429         /* wrapped and have some data back at the start to write */
1430
1431         to_write_frames = min(write_limit - written_frames, This->held_frames);
1432         to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1433
1434         if(This->session->mute)
1435             oss_silence_buffer(This, This->local_buffer, to_write_frames);
1436
1437         written_bytes = write(This->fd, This->local_buffer, to_write_bytes);
1438         if(written_bytes < 0){
1439             WARN("write failed: %d (%s)\n", errno, strerror(errno));
1440             return;
1441         }
1442         written_frames = written_bytes / This->fmt->nBlockAlign;
1443
1444         This->lcl_offs_frames += written_frames;
1445         This->lcl_offs_frames %= This->bufsize_frames;
1446         This->held_frames -= written_frames;
1447     }
1448 }
1449
1450 static void oss_read_data(ACImpl *This)
1451 {
1452     UINT64 pos, readable;
1453     audio_buf_info bi;
1454     ssize_t nread;
1455
1456     if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1457         WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1458         return;
1459     }
1460
1461     pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1462     readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1463
1464     if(bi.bytes < readable)
1465         readable = bi.bytes;
1466
1467     nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1468             readable);
1469     if(nread < 0){
1470         WARN("read failed: %d (%s)\n", errno, strerror(errno));
1471         return;
1472     }
1473
1474     This->held_frames += nread / This->fmt->nBlockAlign;
1475
1476     if(This->held_frames > This->bufsize_frames){
1477         WARN("Overflow of unread data\n");
1478         This->lcl_offs_frames += This->held_frames;
1479         This->lcl_offs_frames %= This->bufsize_frames;
1480         This->held_frames = This->bufsize_frames;
1481     }
1482 }
1483
1484 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1485 {
1486     ACImpl *This = user;
1487
1488     EnterCriticalSection(&This->lock);
1489
1490     if(This->playing){
1491         if(This->dataflow == eRender && This->held_frames)
1492             oss_write_data(This);
1493         else if(This->dataflow == eCapture)
1494             oss_read_data(This);
1495     }
1496
1497     LeaveCriticalSection(&This->lock);
1498
1499     if(This->event)
1500         SetEvent(This->event);
1501 }
1502
1503 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1504 {
1505     ACImpl *This = impl_from_IAudioClient(iface);
1506
1507     TRACE("(%p)\n", This);
1508
1509     EnterCriticalSection(&This->lock);
1510
1511     if(!This->initted){
1512         LeaveCriticalSection(&This->lock);
1513         return AUDCLNT_E_NOT_INITIALIZED;
1514     }
1515
1516     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1517         LeaveCriticalSection(&This->lock);
1518         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1519     }
1520
1521     if(This->playing){
1522         LeaveCriticalSection(&This->lock);
1523         return AUDCLNT_E_NOT_STOPPED;
1524     }
1525
1526     if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1527                 oss_period_callback, This, 0, This->period_us / 1000,
1528                 WT_EXECUTEINTIMERTHREAD))
1529         ERR("Unable to create period timer: %u\n", GetLastError());
1530
1531     This->playing = TRUE;
1532
1533     LeaveCriticalSection(&This->lock);
1534
1535     return S_OK;
1536 }
1537
1538 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1539 {
1540     ACImpl *This = impl_from_IAudioClient(iface);
1541     HANDLE event;
1542     DWORD wait;
1543
1544     TRACE("(%p)\n", This);
1545
1546     EnterCriticalSection(&This->lock);
1547
1548     if(!This->initted){
1549         LeaveCriticalSection(&This->lock);
1550         return AUDCLNT_E_NOT_INITIALIZED;
1551     }
1552
1553     if(!This->playing){
1554         LeaveCriticalSection(&This->lock);
1555         return S_FALSE;
1556     }
1557
1558     event = CreateEventW(NULL, TRUE, FALSE, NULL);
1559     wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
1560     if(wait)
1561         WARN("DeleteTimerQueueTimer error %u\n", GetLastError());
1562     wait = wait && GetLastError() == ERROR_IO_PENDING;
1563
1564     This->playing = FALSE;
1565
1566     LeaveCriticalSection(&This->lock);
1567
1568     if(event && wait)
1569         WaitForSingleObject(event, INFINITE);
1570     CloseHandle(event);
1571
1572     return S_OK;
1573 }
1574
1575 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1576 {
1577     ACImpl *This = impl_from_IAudioClient(iface);
1578
1579     TRACE("(%p)\n", This);
1580
1581     EnterCriticalSection(&This->lock);
1582
1583     if(!This->initted){
1584         LeaveCriticalSection(&This->lock);
1585         return AUDCLNT_E_NOT_INITIALIZED;
1586     }
1587
1588     if(This->playing){
1589         LeaveCriticalSection(&This->lock);
1590         return AUDCLNT_E_NOT_STOPPED;
1591     }
1592
1593     if(This->getbuf_last){
1594         LeaveCriticalSection(&This->lock);
1595         return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1596     }
1597
1598     if(This->dataflow == eRender){
1599         This->written_frames = 0;
1600         This->last_pos_frames = 0;
1601     }else{
1602         This->written_frames += This->held_frames;
1603     }
1604     This->held_frames = 0;
1605     This->lcl_offs_frames = 0;
1606
1607     LeaveCriticalSection(&This->lock);
1608
1609     return S_OK;
1610 }
1611
1612 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1613         HANDLE event)
1614 {
1615     ACImpl *This = impl_from_IAudioClient(iface);
1616
1617     TRACE("(%p)->(%p)\n", This, event);
1618
1619     if(!event)
1620         return E_INVALIDARG;
1621
1622     EnterCriticalSection(&This->lock);
1623
1624     if(!This->initted){
1625         LeaveCriticalSection(&This->lock);
1626         return AUDCLNT_E_NOT_INITIALIZED;
1627     }
1628
1629     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1630         LeaveCriticalSection(&This->lock);
1631         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1632     }
1633
1634     if (This->event){
1635         LeaveCriticalSection(&This->lock);
1636         FIXME("called twice\n");
1637         return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1638     }
1639
1640     This->event = event;
1641
1642     LeaveCriticalSection(&This->lock);
1643
1644     return S_OK;
1645 }
1646
1647 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1648         void **ppv)
1649 {
1650     ACImpl *This = impl_from_IAudioClient(iface);
1651
1652     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1653
1654     if(!ppv)
1655         return E_POINTER;
1656     *ppv = NULL;
1657
1658     EnterCriticalSection(&This->lock);
1659
1660     if(!This->initted){
1661         LeaveCriticalSection(&This->lock);
1662         return AUDCLNT_E_NOT_INITIALIZED;
1663     }
1664
1665     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1666         if(This->dataflow != eRender){
1667             LeaveCriticalSection(&This->lock);
1668             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1669         }
1670         IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1671         *ppv = &This->IAudioRenderClient_iface;
1672     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1673         if(This->dataflow != eCapture){
1674             LeaveCriticalSection(&This->lock);
1675             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1676         }
1677         IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1678         *ppv = &This->IAudioCaptureClient_iface;
1679     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1680         IAudioClock_AddRef(&This->IAudioClock_iface);
1681         *ppv = &This->IAudioClock_iface;
1682     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1683         IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1684         *ppv = &This->IAudioStreamVolume_iface;
1685     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1686         if(!This->session_wrapper){
1687             This->session_wrapper = AudioSessionWrapper_Create(This);
1688             if(!This->session_wrapper){
1689                 LeaveCriticalSection(&This->lock);
1690                 return E_OUTOFMEMORY;
1691             }
1692         }else
1693             IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1694
1695         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1696     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1697         if(!This->session_wrapper){
1698             This->session_wrapper = AudioSessionWrapper_Create(This);
1699             if(!This->session_wrapper){
1700                 LeaveCriticalSection(&This->lock);
1701                 return E_OUTOFMEMORY;
1702             }
1703         }else
1704             IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1705
1706         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1707     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1708         if(!This->session_wrapper){
1709             This->session_wrapper = AudioSessionWrapper_Create(This);
1710             if(!This->session_wrapper){
1711                 LeaveCriticalSection(&This->lock);
1712                 return E_OUTOFMEMORY;
1713             }
1714         }else
1715             ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1716
1717         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1718     }
1719
1720     if(*ppv){
1721         LeaveCriticalSection(&This->lock);
1722         return S_OK;
1723     }
1724
1725     LeaveCriticalSection(&This->lock);
1726
1727     FIXME("stub %s\n", debugstr_guid(riid));
1728     return E_NOINTERFACE;
1729 }
1730
1731 static const IAudioClientVtbl AudioClient_Vtbl =
1732 {
1733     AudioClient_QueryInterface,
1734     AudioClient_AddRef,
1735     AudioClient_Release,
1736     AudioClient_Initialize,
1737     AudioClient_GetBufferSize,
1738     AudioClient_GetStreamLatency,
1739     AudioClient_GetCurrentPadding,
1740     AudioClient_IsFormatSupported,
1741     AudioClient_GetMixFormat,
1742     AudioClient_GetDevicePeriod,
1743     AudioClient_Start,
1744     AudioClient_Stop,
1745     AudioClient_Reset,
1746     AudioClient_SetEventHandle,
1747     AudioClient_GetService
1748 };
1749
1750 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1751         IAudioRenderClient *iface, REFIID riid, void **ppv)
1752 {
1753     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1754
1755     if(!ppv)
1756         return E_POINTER;
1757     *ppv = NULL;
1758
1759     if(IsEqualIID(riid, &IID_IUnknown) ||
1760             IsEqualIID(riid, &IID_IAudioRenderClient))
1761         *ppv = iface;
1762     if(*ppv){
1763         IUnknown_AddRef((IUnknown*)*ppv);
1764         return S_OK;
1765     }
1766
1767     WARN("Unknown interface %s\n", debugstr_guid(riid));
1768     return E_NOINTERFACE;
1769 }
1770
1771 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1772 {
1773     ACImpl *This = impl_from_IAudioRenderClient(iface);
1774     return AudioClient_AddRef(&This->IAudioClient_iface);
1775 }
1776
1777 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1778 {
1779     ACImpl *This = impl_from_IAudioRenderClient(iface);
1780     return AudioClient_Release(&This->IAudioClient_iface);
1781 }
1782
1783 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1784         UINT32 frames, BYTE **data)
1785 {
1786     ACImpl *This = impl_from_IAudioRenderClient(iface);
1787     UINT32 write_pos;
1788
1789     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1790
1791     if(!data)
1792         return E_POINTER;
1793
1794     *data = NULL;
1795
1796     EnterCriticalSection(&This->lock);
1797
1798     if(This->getbuf_last){
1799         LeaveCriticalSection(&This->lock);
1800         return AUDCLNT_E_OUT_OF_ORDER;
1801     }
1802
1803     if(!frames){
1804         LeaveCriticalSection(&This->lock);
1805         return S_OK;
1806     }
1807
1808     if(This->held_frames + frames > This->bufsize_frames){
1809         LeaveCriticalSection(&This->lock);
1810         return AUDCLNT_E_BUFFER_TOO_LARGE;
1811     }
1812
1813     write_pos =
1814         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1815     if(write_pos + frames > This->bufsize_frames){
1816         if(This->tmp_buffer_frames < frames){
1817             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1818             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1819                     frames * This->fmt->nBlockAlign);
1820             if(!This->tmp_buffer){
1821                 LeaveCriticalSection(&This->lock);
1822                 return E_OUTOFMEMORY;
1823             }
1824             This->tmp_buffer_frames = frames;
1825         }
1826         *data = This->tmp_buffer;
1827         This->getbuf_last = -frames;
1828     }else{
1829         *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1830         This->getbuf_last = frames;
1831     }
1832
1833     LeaveCriticalSection(&This->lock);
1834
1835     return S_OK;
1836 }
1837
1838 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1839 {
1840     UINT32 write_offs_frames =
1841         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1842     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1843     UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1844     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1845     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1846
1847     if(written_bytes <= chunk_bytes){
1848         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1849     }else{
1850         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1851         memcpy(This->local_buffer, buffer + chunk_bytes,
1852                 written_bytes - chunk_bytes);
1853     }
1854 }
1855
1856 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1857         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1858 {
1859     ACImpl *This = impl_from_IAudioRenderClient(iface);
1860     BYTE *buffer;
1861
1862     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1863
1864     EnterCriticalSection(&This->lock);
1865
1866     if(!written_frames){
1867         This->getbuf_last = 0;
1868         LeaveCriticalSection(&This->lock);
1869         return S_OK;
1870     }
1871
1872     if(!This->getbuf_last){
1873         LeaveCriticalSection(&This->lock);
1874         return AUDCLNT_E_OUT_OF_ORDER;
1875     }
1876
1877     if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1878         LeaveCriticalSection(&This->lock);
1879         return AUDCLNT_E_INVALID_SIZE;
1880     }
1881
1882     if(This->getbuf_last >= 0)
1883         buffer = This->local_buffer + This->fmt->nBlockAlign *
1884           ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1885     else
1886         buffer = This->tmp_buffer;
1887
1888     if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1889         oss_silence_buffer(This, buffer, written_frames);
1890
1891     if(This->getbuf_last < 0)
1892         oss_wrap_buffer(This, buffer, written_frames);
1893
1894     This->held_frames += written_frames;
1895     This->written_frames += written_frames;
1896     This->getbuf_last = 0;
1897
1898     LeaveCriticalSection(&This->lock);
1899
1900     return S_OK;
1901 }
1902
1903 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1904     AudioRenderClient_QueryInterface,
1905     AudioRenderClient_AddRef,
1906     AudioRenderClient_Release,
1907     AudioRenderClient_GetBuffer,
1908     AudioRenderClient_ReleaseBuffer
1909 };
1910
1911 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1912         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1913 {
1914     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1915
1916     if(!ppv)
1917         return E_POINTER;
1918     *ppv = NULL;
1919
1920     if(IsEqualIID(riid, &IID_IUnknown) ||
1921             IsEqualIID(riid, &IID_IAudioCaptureClient))
1922         *ppv = iface;
1923     if(*ppv){
1924         IUnknown_AddRef((IUnknown*)*ppv);
1925         return S_OK;
1926     }
1927
1928     WARN("Unknown interface %s\n", debugstr_guid(riid));
1929     return E_NOINTERFACE;
1930 }
1931
1932 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1933 {
1934     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1935     return IAudioClient_AddRef(&This->IAudioClient_iface);
1936 }
1937
1938 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1939 {
1940     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1941     return IAudioClient_Release(&This->IAudioClient_iface);
1942 }
1943
1944 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1945         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1946         UINT64 *qpcpos)
1947 {
1948     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1949
1950     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1951             devpos, qpcpos);
1952
1953     if(!data || !frames || !flags)
1954         return E_POINTER;
1955
1956     EnterCriticalSection(&This->lock);
1957
1958     if(This->getbuf_last){
1959         LeaveCriticalSection(&This->lock);
1960         return AUDCLNT_E_OUT_OF_ORDER;
1961     }
1962
1963     if(This->held_frames < This->period_frames){
1964         *frames = 0;
1965         LeaveCriticalSection(&This->lock);
1966         return AUDCLNT_S_BUFFER_EMPTY;
1967     }
1968
1969     *flags = 0;
1970
1971     *frames = This->period_frames;
1972
1973     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1974         UINT32 chunk_bytes, offs_bytes, frames_bytes;
1975         if(This->tmp_buffer_frames < *frames){
1976             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1977             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1978                     *frames * This->fmt->nBlockAlign);
1979             if(!This->tmp_buffer){
1980                 LeaveCriticalSection(&This->lock);
1981                 return E_OUTOFMEMORY;
1982             }
1983             This->tmp_buffer_frames = *frames;
1984         }
1985
1986         *data = This->tmp_buffer;
1987         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1988             This->fmt->nBlockAlign;
1989         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1990         frames_bytes = *frames * This->fmt->nBlockAlign;
1991         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1992         memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
1993                 frames_bytes - chunk_bytes);
1994     }else
1995         *data = This->local_buffer +
1996             This->lcl_offs_frames * This->fmt->nBlockAlign;
1997
1998     This->getbuf_last = *frames;
1999
2000     if(devpos)
2001        *devpos = This->written_frames;
2002     if(qpcpos){
2003         LARGE_INTEGER stamp, freq;
2004         QueryPerformanceCounter(&stamp);
2005         QueryPerformanceFrequency(&freq);
2006         *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2007     }
2008
2009     LeaveCriticalSection(&This->lock);
2010
2011     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2012 }
2013
2014 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2015         IAudioCaptureClient *iface, UINT32 done)
2016 {
2017     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2018
2019     TRACE("(%p)->(%u)\n", This, done);
2020
2021     EnterCriticalSection(&This->lock);
2022
2023     if(!done){
2024         This->getbuf_last = 0;
2025         LeaveCriticalSection(&This->lock);
2026         return S_OK;
2027     }
2028
2029     if(!This->getbuf_last){
2030         LeaveCriticalSection(&This->lock);
2031         return AUDCLNT_E_OUT_OF_ORDER;
2032     }
2033
2034     if(This->getbuf_last != done){
2035         LeaveCriticalSection(&This->lock);
2036         return AUDCLNT_E_INVALID_SIZE;
2037     }
2038
2039     This->written_frames += done;
2040     This->held_frames -= done;
2041     This->lcl_offs_frames += done;
2042     This->lcl_offs_frames %= This->bufsize_frames;
2043     This->getbuf_last = 0;
2044
2045     LeaveCriticalSection(&This->lock);
2046
2047     return S_OK;
2048 }
2049
2050 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2051         IAudioCaptureClient *iface, UINT32 *frames)
2052 {
2053     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2054
2055     TRACE("(%p)->(%p)\n", This, frames);
2056
2057     if(!frames)
2058         return E_POINTER;
2059
2060     EnterCriticalSection(&This->lock);
2061
2062     *frames = This->held_frames < This->period_frames ? 0 : This->period_frames;
2063
2064     LeaveCriticalSection(&This->lock);
2065
2066     return S_OK;
2067 }
2068
2069 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2070 {
2071     AudioCaptureClient_QueryInterface,
2072     AudioCaptureClient_AddRef,
2073     AudioCaptureClient_Release,
2074     AudioCaptureClient_GetBuffer,
2075     AudioCaptureClient_ReleaseBuffer,
2076     AudioCaptureClient_GetNextPacketSize
2077 };
2078
2079 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2080         REFIID riid, void **ppv)
2081 {
2082     ACImpl *This = impl_from_IAudioClock(iface);
2083
2084     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2085
2086     if(!ppv)
2087         return E_POINTER;
2088     *ppv = NULL;
2089
2090     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2091         *ppv = iface;
2092     else if(IsEqualIID(riid, &IID_IAudioClock2))
2093         *ppv = &This->IAudioClock2_iface;
2094     if(*ppv){
2095         IUnknown_AddRef((IUnknown*)*ppv);
2096         return S_OK;
2097     }
2098
2099     WARN("Unknown interface %s\n", debugstr_guid(riid));
2100     return E_NOINTERFACE;
2101 }
2102
2103 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2104 {
2105     ACImpl *This = impl_from_IAudioClock(iface);
2106     return IAudioClient_AddRef(&This->IAudioClient_iface);
2107 }
2108
2109 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2110 {
2111     ACImpl *This = impl_from_IAudioClock(iface);
2112     return IAudioClient_Release(&This->IAudioClient_iface);
2113 }
2114
2115 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2116 {
2117     ACImpl *This = impl_from_IAudioClock(iface);
2118
2119     TRACE("(%p)->(%p)\n", This, freq);
2120
2121     *freq = This->fmt->nSamplesPerSec;
2122
2123     return S_OK;
2124 }
2125
2126 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2127         UINT64 *qpctime)
2128 {
2129     ACImpl *This = impl_from_IAudioClock(iface);
2130     int delay;
2131
2132     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2133
2134     if(!pos)
2135         return E_POINTER;
2136
2137     EnterCriticalSection(&This->lock);
2138
2139     if(This->dataflow == eRender){
2140         if(!This->playing || !This->held_frames ||
2141                 ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay) < 0)
2142             delay = 0;
2143         else
2144             delay /= This->fmt->nBlockAlign;
2145         if(This->held_frames + delay >= This->written_frames)
2146             *pos = This->last_pos_frames;
2147         else{
2148             *pos = This->written_frames - This->held_frames - delay;
2149             if(*pos < This->last_pos_frames)
2150                 *pos = This->last_pos_frames;
2151         }
2152     }else if(This->dataflow == eCapture){
2153         audio_buf_info bi;
2154         UINT32 held;
2155
2156         if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
2157             TRACE("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
2158             held = 0;
2159         }else{
2160             if(bi.bytes <= bi.fragsize)
2161                 held = 0;
2162             else
2163                 held = bi.bytes / This->fmt->nBlockAlign;
2164         }
2165
2166         *pos = This->written_frames + held;
2167     }
2168
2169     This->last_pos_frames = *pos;
2170
2171     LeaveCriticalSection(&This->lock);
2172
2173     if(qpctime){
2174         LARGE_INTEGER stamp, freq;
2175         QueryPerformanceCounter(&stamp);
2176         QueryPerformanceFrequency(&freq);
2177         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2178     }
2179
2180     return S_OK;
2181 }
2182
2183 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2184         DWORD *chars)
2185 {
2186     ACImpl *This = impl_from_IAudioClock(iface);
2187
2188     TRACE("(%p)->(%p)\n", This, chars);
2189
2190     if(!chars)
2191         return E_POINTER;
2192
2193     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2194
2195     return S_OK;
2196 }
2197
2198 static const IAudioClockVtbl AudioClock_Vtbl =
2199 {
2200     AudioClock_QueryInterface,
2201     AudioClock_AddRef,
2202     AudioClock_Release,
2203     AudioClock_GetFrequency,
2204     AudioClock_GetPosition,
2205     AudioClock_GetCharacteristics
2206 };
2207
2208 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2209         REFIID riid, void **ppv)
2210 {
2211     ACImpl *This = impl_from_IAudioClock2(iface);
2212     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2213 }
2214
2215 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2216 {
2217     ACImpl *This = impl_from_IAudioClock2(iface);
2218     return IAudioClient_AddRef(&This->IAudioClient_iface);
2219 }
2220
2221 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2222 {
2223     ACImpl *This = impl_from_IAudioClock2(iface);
2224     return IAudioClient_Release(&This->IAudioClient_iface);
2225 }
2226
2227 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2228         UINT64 *pos, UINT64 *qpctime)
2229 {
2230     ACImpl *This = impl_from_IAudioClock2(iface);
2231
2232     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2233
2234     return E_NOTIMPL;
2235 }
2236
2237 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2238 {
2239     AudioClock2_QueryInterface,
2240     AudioClock2_AddRef,
2241     AudioClock2_Release,
2242     AudioClock2_GetDevicePosition
2243 };
2244
2245 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2246 {
2247     AudioSessionWrapper *ret;
2248
2249     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2250             sizeof(AudioSessionWrapper));
2251     if(!ret)
2252         return NULL;
2253
2254     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2255     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2256     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2257
2258     ret->ref = 1;
2259
2260     ret->client = client;
2261     if(client){
2262         ret->session = client->session;
2263         AudioClient_AddRef(&client->IAudioClient_iface);
2264     }
2265
2266     return ret;
2267 }
2268
2269 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2270         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2271 {
2272     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2273
2274     if(!ppv)
2275         return E_POINTER;
2276     *ppv = NULL;
2277
2278     if(IsEqualIID(riid, &IID_IUnknown) ||
2279             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2280             IsEqualIID(riid, &IID_IAudioSessionControl2))
2281         *ppv = iface;
2282     if(*ppv){
2283         IUnknown_AddRef((IUnknown*)*ppv);
2284         return S_OK;
2285     }
2286
2287     WARN("Unknown interface %s\n", debugstr_guid(riid));
2288     return E_NOINTERFACE;
2289 }
2290
2291 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2292 {
2293     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2294     ULONG ref;
2295     ref = InterlockedIncrement(&This->ref);
2296     TRACE("(%p) Refcount now %u\n", This, ref);
2297     return ref;
2298 }
2299
2300 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2301 {
2302     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2303     ULONG ref;
2304     ref = InterlockedDecrement(&This->ref);
2305     TRACE("(%p) Refcount now %u\n", This, ref);
2306     if(!ref){
2307         if(This->client){
2308             EnterCriticalSection(&This->client->lock);
2309             This->client->session_wrapper = NULL;
2310             LeaveCriticalSection(&This->client->lock);
2311             AudioClient_Release(&This->client->IAudioClient_iface);
2312         }
2313         HeapFree(GetProcessHeap(), 0, This);
2314     }
2315     return ref;
2316 }
2317
2318 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2319         AudioSessionState *state)
2320 {
2321     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2322     ACImpl *client;
2323
2324     TRACE("(%p)->(%p)\n", This, state);
2325
2326     if(!state)
2327         return NULL_PTR_ERR;
2328
2329     EnterCriticalSection(&g_sessions_lock);
2330
2331     if(list_empty(&This->session->clients)){
2332         *state = AudioSessionStateExpired;
2333         LeaveCriticalSection(&g_sessions_lock);
2334         return S_OK;
2335     }
2336
2337     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2338         EnterCriticalSection(&client->lock);
2339         if(client->playing){
2340             *state = AudioSessionStateActive;
2341             LeaveCriticalSection(&client->lock);
2342             LeaveCriticalSection(&g_sessions_lock);
2343             return S_OK;
2344         }
2345         LeaveCriticalSection(&client->lock);
2346     }
2347
2348     LeaveCriticalSection(&g_sessions_lock);
2349
2350     *state = AudioSessionStateInactive;
2351
2352     return S_OK;
2353 }
2354
2355 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2356         IAudioSessionControl2 *iface, WCHAR **name)
2357 {
2358     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2359
2360     FIXME("(%p)->(%p) - stub\n", This, name);
2361
2362     return E_NOTIMPL;
2363 }
2364
2365 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2366         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2367 {
2368     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2369
2370     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2371
2372     return E_NOTIMPL;
2373 }
2374
2375 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2376         IAudioSessionControl2 *iface, WCHAR **path)
2377 {
2378     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2379
2380     FIXME("(%p)->(%p) - stub\n", This, path);
2381
2382     return E_NOTIMPL;
2383 }
2384
2385 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2386         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2387 {
2388     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2389
2390     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2391
2392     return E_NOTIMPL;
2393 }
2394
2395 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2396         IAudioSessionControl2 *iface, GUID *group)
2397 {
2398     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2399
2400     FIXME("(%p)->(%p) - stub\n", This, group);
2401
2402     return E_NOTIMPL;
2403 }
2404
2405 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2406         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2407 {
2408     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2409
2410     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2411             debugstr_guid(session));
2412
2413     return E_NOTIMPL;
2414 }
2415
2416 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2417         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2418 {
2419     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2420
2421     FIXME("(%p)->(%p) - stub\n", This, events);
2422
2423     return S_OK;
2424 }
2425
2426 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2427         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2428 {
2429     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2430
2431     FIXME("(%p)->(%p) - stub\n", This, events);
2432
2433     return S_OK;
2434 }
2435
2436 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2437         IAudioSessionControl2 *iface, WCHAR **id)
2438 {
2439     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2440
2441     FIXME("(%p)->(%p) - stub\n", This, id);
2442
2443     return E_NOTIMPL;
2444 }
2445
2446 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2447         IAudioSessionControl2 *iface, WCHAR **id)
2448 {
2449     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2450
2451     FIXME("(%p)->(%p) - stub\n", This, id);
2452
2453     return E_NOTIMPL;
2454 }
2455
2456 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2457         IAudioSessionControl2 *iface, DWORD *pid)
2458 {
2459     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2460
2461     TRACE("(%p)->(%p)\n", This, pid);
2462
2463     if(!pid)
2464         return E_POINTER;
2465
2466     *pid = GetCurrentProcessId();
2467
2468     return S_OK;
2469 }
2470
2471 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2472         IAudioSessionControl2 *iface)
2473 {
2474     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2475
2476     TRACE("(%p)\n", This);
2477
2478     return S_FALSE;
2479 }
2480
2481 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2482         IAudioSessionControl2 *iface, BOOL optout)
2483 {
2484     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2485
2486     TRACE("(%p)->(%d)\n", This, optout);
2487
2488     return S_OK;
2489 }
2490
2491 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2492 {
2493     AudioSessionControl_QueryInterface,
2494     AudioSessionControl_AddRef,
2495     AudioSessionControl_Release,
2496     AudioSessionControl_GetState,
2497     AudioSessionControl_GetDisplayName,
2498     AudioSessionControl_SetDisplayName,
2499     AudioSessionControl_GetIconPath,
2500     AudioSessionControl_SetIconPath,
2501     AudioSessionControl_GetGroupingParam,
2502     AudioSessionControl_SetGroupingParam,
2503     AudioSessionControl_RegisterAudioSessionNotification,
2504     AudioSessionControl_UnregisterAudioSessionNotification,
2505     AudioSessionControl_GetSessionIdentifier,
2506     AudioSessionControl_GetSessionInstanceIdentifier,
2507     AudioSessionControl_GetProcessId,
2508     AudioSessionControl_IsSystemSoundsSession,
2509     AudioSessionControl_SetDuckingPreference
2510 };
2511
2512 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2513         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2514 {
2515     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2516
2517     if(!ppv)
2518         return E_POINTER;
2519     *ppv = NULL;
2520
2521     if(IsEqualIID(riid, &IID_IUnknown) ||
2522             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2523         *ppv = iface;
2524     if(*ppv){
2525         IUnknown_AddRef((IUnknown*)*ppv);
2526         return S_OK;
2527     }
2528
2529     WARN("Unknown interface %s\n", debugstr_guid(riid));
2530     return E_NOINTERFACE;
2531 }
2532
2533 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2534 {
2535     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2536     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2537 }
2538
2539 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2540 {
2541     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2542     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2543 }
2544
2545 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2546         ISimpleAudioVolume *iface, float level, const GUID *context)
2547 {
2548     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2549     AudioSession *session = This->session;
2550
2551     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2552
2553     if(level < 0.f || level > 1.f)
2554         return E_INVALIDARG;
2555
2556     if(context)
2557         FIXME("Notifications not supported yet\n");
2558
2559     EnterCriticalSection(&session->lock);
2560
2561     session->master_vol = level;
2562
2563     TRACE("OSS doesn't support setting volume\n");
2564
2565     LeaveCriticalSection(&session->lock);
2566
2567     return S_OK;
2568 }
2569
2570 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2571         ISimpleAudioVolume *iface, float *level)
2572 {
2573     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2574     AudioSession *session = This->session;
2575
2576     TRACE("(%p)->(%p)\n", session, level);
2577
2578     if(!level)
2579         return NULL_PTR_ERR;
2580
2581     *level = session->master_vol;
2582
2583     return S_OK;
2584 }
2585
2586 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2587         BOOL mute, const GUID *context)
2588 {
2589     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2590     AudioSession *session = This->session;
2591
2592     TRACE("(%p)->(%u, %p)\n", session, mute, context);
2593
2594     EnterCriticalSection(&session->lock);
2595
2596     session->mute = mute;
2597
2598     LeaveCriticalSection(&session->lock);
2599
2600     return S_OK;
2601 }
2602
2603 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2604         BOOL *mute)
2605 {
2606     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2607     AudioSession *session = This->session;
2608
2609     TRACE("(%p)->(%p)\n", session, mute);
2610
2611     if(!mute)
2612         return NULL_PTR_ERR;
2613
2614     *mute = This->session->mute;
2615
2616     return S_OK;
2617 }
2618
2619 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2620 {
2621     SimpleAudioVolume_QueryInterface,
2622     SimpleAudioVolume_AddRef,
2623     SimpleAudioVolume_Release,
2624     SimpleAudioVolume_SetMasterVolume,
2625     SimpleAudioVolume_GetMasterVolume,
2626     SimpleAudioVolume_SetMute,
2627     SimpleAudioVolume_GetMute
2628 };
2629
2630 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2631         IAudioStreamVolume *iface, REFIID riid, void **ppv)
2632 {
2633     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2634
2635     if(!ppv)
2636         return E_POINTER;
2637     *ppv = NULL;
2638
2639     if(IsEqualIID(riid, &IID_IUnknown) ||
2640             IsEqualIID(riid, &IID_IAudioStreamVolume))
2641         *ppv = iface;
2642     if(*ppv){
2643         IUnknown_AddRef((IUnknown*)*ppv);
2644         return S_OK;
2645     }
2646
2647     WARN("Unknown interface %s\n", debugstr_guid(riid));
2648     return E_NOINTERFACE;
2649 }
2650
2651 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2652 {
2653     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2654     return IAudioClient_AddRef(&This->IAudioClient_iface);
2655 }
2656
2657 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2658 {
2659     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2660     return IAudioClient_Release(&This->IAudioClient_iface);
2661 }
2662
2663 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2664         IAudioStreamVolume *iface, UINT32 *out)
2665 {
2666     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2667
2668     TRACE("(%p)->(%p)\n", This, out);
2669
2670     if(!out)
2671         return E_POINTER;
2672
2673     *out = This->fmt->nChannels;
2674
2675     return S_OK;
2676 }
2677
2678 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2679         IAudioStreamVolume *iface, UINT32 index, float level)
2680 {
2681     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2682
2683     TRACE("(%p)->(%d, %f)\n", This, index, level);
2684
2685     if(level < 0.f || level > 1.f)
2686         return E_INVALIDARG;
2687
2688     if(index >= This->fmt->nChannels)
2689         return E_INVALIDARG;
2690
2691     EnterCriticalSection(&This->lock);
2692
2693     This->vols[index] = level;
2694
2695     TRACE("OSS doesn't support setting volume\n");
2696
2697     LeaveCriticalSection(&This->lock);
2698
2699     return S_OK;
2700 }
2701
2702 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2703         IAudioStreamVolume *iface, UINT32 index, float *level)
2704 {
2705     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2706
2707     TRACE("(%p)->(%d, %p)\n", This, index, level);
2708
2709     if(!level)
2710         return E_POINTER;
2711
2712     if(index >= This->fmt->nChannels)
2713         return E_INVALIDARG;
2714
2715     *level = This->vols[index];
2716
2717     return S_OK;
2718 }
2719
2720 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2721         IAudioStreamVolume *iface, UINT32 count, const float *levels)
2722 {
2723     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2724     int i;
2725
2726     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2727
2728     if(!levels)
2729         return E_POINTER;
2730
2731     if(count != This->fmt->nChannels)
2732         return E_INVALIDARG;
2733
2734     EnterCriticalSection(&This->lock);
2735
2736     for(i = 0; i < count; ++i)
2737         This->vols[i] = levels[i];
2738
2739     TRACE("OSS doesn't support setting volume\n");
2740
2741     LeaveCriticalSection(&This->lock);
2742
2743     return S_OK;
2744 }
2745
2746 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2747         IAudioStreamVolume *iface, UINT32 count, float *levels)
2748 {
2749     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2750     int i;
2751
2752     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2753
2754     if(!levels)
2755         return E_POINTER;
2756
2757     if(count != This->fmt->nChannels)
2758         return E_INVALIDARG;
2759
2760     EnterCriticalSection(&This->lock);
2761
2762     for(i = 0; i < count; ++i)
2763         levels[i] = This->vols[i];
2764
2765     LeaveCriticalSection(&This->lock);
2766
2767     return S_OK;
2768 }
2769
2770 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2771 {
2772     AudioStreamVolume_QueryInterface,
2773     AudioStreamVolume_AddRef,
2774     AudioStreamVolume_Release,
2775     AudioStreamVolume_GetChannelCount,
2776     AudioStreamVolume_SetChannelVolume,
2777     AudioStreamVolume_GetChannelVolume,
2778     AudioStreamVolume_SetAllVolumes,
2779     AudioStreamVolume_GetAllVolumes
2780 };
2781
2782 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2783         IChannelAudioVolume *iface, REFIID riid, void **ppv)
2784 {
2785     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2786
2787     if(!ppv)
2788         return E_POINTER;
2789     *ppv = NULL;
2790
2791     if(IsEqualIID(riid, &IID_IUnknown) ||
2792             IsEqualIID(riid, &IID_IChannelAudioVolume))
2793         *ppv = iface;
2794     if(*ppv){
2795         IUnknown_AddRef((IUnknown*)*ppv);
2796         return S_OK;
2797     }
2798
2799     WARN("Unknown interface %s\n", debugstr_guid(riid));
2800     return E_NOINTERFACE;
2801 }
2802
2803 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2804 {
2805     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2806     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2807 }
2808
2809 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2810 {
2811     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2812     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2813 }
2814
2815 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2816         IChannelAudioVolume *iface, UINT32 *out)
2817 {
2818     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2819     AudioSession *session = This->session;
2820
2821     TRACE("(%p)->(%p)\n", session, out);
2822
2823     if(!out)
2824         return NULL_PTR_ERR;
2825
2826     *out = session->channel_count;
2827
2828     return S_OK;
2829 }
2830
2831 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2832         IChannelAudioVolume *iface, UINT32 index, float level,
2833         const GUID *context)
2834 {
2835     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2836     AudioSession *session = This->session;
2837
2838     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2839             wine_dbgstr_guid(context));
2840
2841     if(level < 0.f || level > 1.f)
2842         return E_INVALIDARG;
2843
2844     if(index >= session->channel_count)
2845         return E_INVALIDARG;
2846
2847     if(context)
2848         FIXME("Notifications not supported yet\n");
2849
2850     EnterCriticalSection(&session->lock);
2851
2852     session->channel_vols[index] = level;
2853
2854     TRACE("OSS doesn't support setting volume\n");
2855
2856     LeaveCriticalSection(&session->lock);
2857
2858     return S_OK;
2859 }
2860
2861 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2862         IChannelAudioVolume *iface, UINT32 index, float *level)
2863 {
2864     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2865     AudioSession *session = This->session;
2866
2867     TRACE("(%p)->(%d, %p)\n", session, index, level);
2868
2869     if(!level)
2870         return NULL_PTR_ERR;
2871
2872     if(index >= session->channel_count)
2873         return E_INVALIDARG;
2874
2875     *level = session->channel_vols[index];
2876
2877     return S_OK;
2878 }
2879
2880 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2881         IChannelAudioVolume *iface, UINT32 count, const float *levels,
2882         const GUID *context)
2883 {
2884     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2885     AudioSession *session = This->session;
2886     int i;
2887
2888     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2889             wine_dbgstr_guid(context));
2890
2891     if(!levels)
2892         return NULL_PTR_ERR;
2893
2894     if(count != session->channel_count)
2895         return E_INVALIDARG;
2896
2897     if(context)
2898         FIXME("Notifications not supported yet\n");
2899
2900     EnterCriticalSection(&session->lock);
2901
2902     for(i = 0; i < count; ++i)
2903         session->channel_vols[i] = levels[i];
2904
2905     TRACE("OSS doesn't support setting volume\n");
2906
2907     LeaveCriticalSection(&session->lock);
2908
2909     return S_OK;
2910 }
2911
2912 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2913         IChannelAudioVolume *iface, UINT32 count, float *levels)
2914 {
2915     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2916     AudioSession *session = This->session;
2917     int i;
2918
2919     TRACE("(%p)->(%d, %p)\n", session, count, levels);
2920
2921     if(!levels)
2922         return NULL_PTR_ERR;
2923
2924     if(count != session->channel_count)
2925         return E_INVALIDARG;
2926
2927     for(i = 0; i < count; ++i)
2928         levels[i] = session->channel_vols[i];
2929
2930     return S_OK;
2931 }
2932
2933 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2934 {
2935     ChannelAudioVolume_QueryInterface,
2936     ChannelAudioVolume_AddRef,
2937     ChannelAudioVolume_Release,
2938     ChannelAudioVolume_GetChannelCount,
2939     ChannelAudioVolume_SetChannelVolume,
2940     ChannelAudioVolume_GetChannelVolume,
2941     ChannelAudioVolume_SetAllVolumes,
2942     ChannelAudioVolume_GetAllVolumes
2943 };
2944
2945 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2946         REFIID riid, void **ppv)
2947 {
2948     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2949
2950     if(!ppv)
2951         return E_POINTER;
2952     *ppv = NULL;
2953
2954     if(IsEqualIID(riid, &IID_IUnknown) ||
2955             IsEqualIID(riid, &IID_IAudioSessionManager) ||
2956             IsEqualIID(riid, &IID_IAudioSessionManager2))
2957         *ppv = iface;
2958     if(*ppv){
2959         IUnknown_AddRef((IUnknown*)*ppv);
2960         return S_OK;
2961     }
2962
2963     WARN("Unknown interface %s\n", debugstr_guid(riid));
2964     return E_NOINTERFACE;
2965 }
2966
2967 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2968 {
2969     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2970     ULONG ref;
2971     ref = InterlockedIncrement(&This->ref);
2972     TRACE("(%p) Refcount now %u\n", This, ref);
2973     return ref;
2974 }
2975
2976 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2977 {
2978     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2979     ULONG ref;
2980     ref = InterlockedDecrement(&This->ref);
2981     TRACE("(%p) Refcount now %u\n", This, ref);
2982     if(!ref)
2983         HeapFree(GetProcessHeap(), 0, This);
2984     return ref;
2985 }
2986
2987 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2988         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2989         IAudioSessionControl **out)
2990 {
2991     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2992     AudioSession *session;
2993     AudioSessionWrapper *wrapper;
2994     HRESULT hr;
2995
2996     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2997             flags, out);
2998
2999     hr = get_audio_session(session_guid, This->device, 0, &session);
3000     if(FAILED(hr))
3001         return hr;
3002
3003     wrapper = AudioSessionWrapper_Create(NULL);
3004     if(!wrapper)
3005         return E_OUTOFMEMORY;
3006
3007     wrapper->session = session;
3008
3009     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
3010
3011     return S_OK;
3012 }
3013
3014 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3015         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3016         ISimpleAudioVolume **out)
3017 {
3018     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3019     AudioSession *session;
3020     AudioSessionWrapper *wrapper;
3021     HRESULT hr;
3022
3023     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3024             flags, out);
3025
3026     hr = get_audio_session(session_guid, This->device, 0, &session);
3027     if(FAILED(hr))
3028         return hr;
3029
3030     wrapper = AudioSessionWrapper_Create(NULL);
3031     if(!wrapper)
3032         return E_OUTOFMEMORY;
3033
3034     wrapper->session = session;
3035
3036     *out = &wrapper->ISimpleAudioVolume_iface;
3037
3038     return S_OK;
3039 }
3040
3041 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3042         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3043 {
3044     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3045     FIXME("(%p)->(%p) - stub\n", This, out);
3046     return E_NOTIMPL;
3047 }
3048
3049 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3050         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3051 {
3052     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3053     FIXME("(%p)->(%p) - stub\n", This, notification);
3054     return E_NOTIMPL;
3055 }
3056
3057 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3058         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3059 {
3060     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3061     FIXME("(%p)->(%p) - stub\n", This, notification);
3062     return E_NOTIMPL;
3063 }
3064
3065 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3066         IAudioSessionManager2 *iface, const WCHAR *session_id,
3067         IAudioVolumeDuckNotification *notification)
3068 {
3069     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3070     FIXME("(%p)->(%p) - stub\n", This, notification);
3071     return E_NOTIMPL;
3072 }
3073
3074 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3075         IAudioSessionManager2 *iface,
3076         IAudioVolumeDuckNotification *notification)
3077 {
3078     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3079     FIXME("(%p)->(%p) - stub\n", This, notification);
3080     return E_NOTIMPL;
3081 }
3082
3083 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3084 {
3085     AudioSessionManager_QueryInterface,
3086     AudioSessionManager_AddRef,
3087     AudioSessionManager_Release,
3088     AudioSessionManager_GetAudioSessionControl,
3089     AudioSessionManager_GetSimpleAudioVolume,
3090     AudioSessionManager_GetSessionEnumerator,
3091     AudioSessionManager_RegisterSessionNotification,
3092     AudioSessionManager_UnregisterSessionNotification,
3093     AudioSessionManager_RegisterDuckNotification,
3094     AudioSessionManager_UnregisterDuckNotification
3095 };
3096
3097 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3098         IAudioSessionManager2 **out)
3099 {
3100     SessionMgr *This;
3101
3102     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3103     if(!This)
3104         return E_OUTOFMEMORY;
3105
3106     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3107     This->device = device;
3108     This->ref = 1;
3109
3110     *out = &This->IAudioSessionManager2_iface;
3111
3112     return S_OK;
3113 }