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