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