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