2 * Copyright 2011 Andrew Eikum for CodeWeavers
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.
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.
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
19 #define NONAMELESSUNION
29 #include <sys/types.h>
31 #include <sys/ioctl.h>
35 #include <sys/soundcard.h>
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
46 #include "mmdeviceapi.h"
50 #include "endpointvolume.h"
53 #include "audiopolicy.h"
54 #include "audioclient.h"
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
63 WINE_DEFAULT_DEBUG_CHANNEL(oss);
65 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
67 static const REFERENCE_TIME DefaultPeriod = 200000;
68 static const REFERENCE_TIME MinimumPeriod = 100000;
71 typedef struct ACImpl ACImpl;
73 typedef struct _AudioSession {
84 CRITICAL_SECTION lock;
89 typedef struct _AudioSessionWrapper {
90 IAudioSessionControl2 IAudioSessionControl2_iface;
91 IChannelAudioVolume IChannelAudioVolume_iface;
92 ISimpleAudioVolume ISimpleAudioVolume_iface;
97 AudioSession *session;
98 } AudioSessionWrapper;
101 IAudioClient IAudioClient_iface;
102 IAudioRenderClient IAudioRenderClient_iface;
103 IAudioCaptureClient IAudioCaptureClient_iface;
104 IAudioClock IAudioClock_iface;
105 IAudioClock2 IAudioClock2_iface;
106 IAudioStreamVolume IAudioStreamVolume_iface;
116 AUDCLNT_SHAREMODE share;
123 BOOL initted, playing;
124 UINT64 written_frames;
125 UINT32 period_us, bufsize_frames, held_frames, tmp_buffer_frames, inbuf_frames;
126 UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
128 BYTE *local_buffer, *tmp_buffer;
132 CRITICAL_SECTION lock;
134 AudioSession *session;
135 AudioSessionWrapper *session_wrapper;
142 LOCKED_NORMAL, /* public buffer piece is from local_buffer */
143 LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
146 typedef struct _SessionMgr {
147 IAudioSessionManager2 IAudioSessionManager2_iface;
154 static HANDLE g_timer_q;
156 static CRITICAL_SECTION g_sessions_lock;
157 static struct list g_sessions = LIST_INIT(g_sessions);
159 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
160 static HRESULT oss_setvol(ACImpl *This, UINT32 index);
162 static const IAudioClientVtbl AudioClient_Vtbl;
163 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
164 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
165 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
166 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
167 static const IAudioClockVtbl AudioClock_Vtbl;
168 static const IAudioClock2Vtbl AudioClock2_Vtbl;
169 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
170 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
171 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
173 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
175 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
178 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
180 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
183 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
185 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
188 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
190 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
193 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
195 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
198 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
200 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
203 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
205 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
208 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
210 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
213 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
215 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
218 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
220 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
223 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
225 if(reason == DLL_PROCESS_ATTACH){
226 g_timer_q = CreateTimerQueue();
230 InitializeCriticalSection(&g_sessions_lock);
236 /* From <dlls/mmdevapi/mmdevapi.h> */
237 enum DriverPriority {
238 Priority_Unavailable = 0,
244 int WINAPI AUDDRV_GetPriority(void)
249 /* Attempt to determine if we are running on OSS or ALSA's OSS
250 * compatibility layer. There is no official way to do that, so just check
251 * for validity as best as possible, without rejecting valid OSS
252 * implementations. */
254 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
256 TRACE("Priority_Unavailable: open failed\n");
257 return Priority_Unavailable;
260 sysinfo.version[0] = 0xFF;
261 sysinfo.versionnum = ~0;
262 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
263 TRACE("Priority_Unavailable: ioctl failed\n");
265 return Priority_Unavailable;
270 if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
271 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
274 if(sysinfo.versionnum & 0x80000000){
275 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
279 TRACE("Priority_Preferred: Seems like valid OSS!\n");
281 return Priority_Preferred;
284 static UINT get_default_index(EDataFlow flow, char **keys, UINT num)
290 fd = open("/dev/dsp", O_WRONLY);
292 fd = open("/dev/dsp", O_RDONLY);
295 WARN("Couldn't open default device!\n");
300 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
301 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
308 TRACE("Default devnode: %s\n", ai.devnode);
309 for(i = 0; i < num; ++i)
310 if(!strcmp(ai.devnode, keys[i]))
313 WARN("Couldn't find default device! Choosing first.\n");
317 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, char ***keys,
318 UINT *num, UINT *def_index)
322 static int print_once = 0;
324 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
326 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
328 ERR("OSS /dev/mixer doesn't seem to exist\n");
329 return AUDCLNT_E_SERVICE_NOT_RUNNING;
332 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
336 ERR("OSS version too old, need at least OSSv4\n");
337 return AUDCLNT_E_SERVICE_NOT_RUNNING;
340 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
345 TRACE("OSS sysinfo:\n");
346 TRACE("product: %s\n", sysinfo.product);
347 TRACE("version: %s\n", sysinfo.version);
348 TRACE("versionnum: %x\n", sysinfo.versionnum);
349 TRACE("numaudios: %d\n", sysinfo.numaudios);
350 TRACE("nummixers: %d\n", sysinfo.nummixers);
351 TRACE("numcards: %d\n", sysinfo.numcards);
352 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
356 if(sysinfo.numaudios <= 0){
357 WARN("No audio devices!\n");
359 return AUDCLNT_E_SERVICE_NOT_RUNNING;
362 *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
363 *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
366 for(i = 0; i < sysinfo.numaudios; ++i){
367 oss_audioinfo ai = {0};
371 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
372 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
378 fd = open(ai.devnode, O_WRONLY, 0);
380 fd = open(ai.devnode, O_RDONLY, 0);
382 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
383 ai.devnode, errno, strerror(errno));
388 if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
389 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
392 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
393 strlen(ai.devnode) + 1);
395 for(i = 0; i < *num; ++i){
396 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
397 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
399 HeapFree(GetProcessHeap(), 0, *ids);
400 HeapFree(GetProcessHeap(), 0, *keys);
402 return E_OUTOFMEMORY;
404 strcpy((*keys)[*num], ai.devnode);
406 len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
407 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
408 len * sizeof(WCHAR));
410 HeapFree(GetProcessHeap(), 0, (*keys)[*num]);
411 for(i = 0; i < *num; ++i){
412 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
413 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
415 HeapFree(GetProcessHeap(), 0, *ids);
416 HeapFree(GetProcessHeap(), 0, *keys);
418 return E_OUTOFMEMORY;
420 MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
429 *def_index = get_default_index(flow, *keys, *num);
434 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
435 EDataFlow dataflow, IAudioClient **out)
439 TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
441 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
443 return E_OUTOFMEMORY;
445 if(dataflow == eRender)
446 This->fd = open(devnode, O_WRONLY, 0);
447 else if(dataflow == eCapture)
448 This->fd = open(devnode, O_RDONLY, 0);
450 HeapFree(GetProcessHeap(), 0, This);
454 ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
456 HeapFree(GetProcessHeap(), 0, This);
457 return AUDCLNT_E_DEVICE_INVALIDATED;
460 This->dataflow = dataflow;
463 if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
464 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode,
465 errno, strerror(errno));
467 HeapFree(GetProcessHeap(), 0, This);
471 TRACE("OSS audioinfo:\n");
472 TRACE("devnode: %s\n", This->ai.devnode);
473 TRACE("name: %s\n", This->ai.name);
474 TRACE("busy: %x\n", This->ai.busy);
475 TRACE("caps: %x\n", This->ai.caps);
476 TRACE("iformats: %x\n", This->ai.iformats);
477 TRACE("oformats: %x\n", This->ai.oformats);
478 TRACE("enabled: %d\n", This->ai.enabled);
479 TRACE("min_rate: %d\n", This->ai.min_rate);
480 TRACE("max_rate: %d\n", This->ai.max_rate);
481 TRACE("min_channels: %d\n", This->ai.min_channels);
482 TRACE("max_channels: %d\n", This->ai.max_channels);
484 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
485 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
486 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
487 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
488 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
489 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
491 InitializeCriticalSection(&This->lock);
494 IMMDevice_AddRef(This->parent);
496 IAudioClient_AddRef(&This->IAudioClient_iface);
498 *out = &This->IAudioClient_iface;
503 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
504 REFIID riid, void **ppv)
506 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
511 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
514 IUnknown_AddRef((IUnknown*)*ppv);
517 WARN("Unknown interface %s\n", debugstr_guid(riid));
518 return E_NOINTERFACE;
521 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
523 ACImpl *This = impl_from_IAudioClient(iface);
525 ref = InterlockedIncrement(&This->ref);
526 TRACE("(%p) Refcount now %u\n", This, ref);
530 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
532 ACImpl *This = impl_from_IAudioClient(iface);
534 ref = InterlockedDecrement(&This->ref);
535 TRACE("(%p) Refcount now %u\n", This, ref);
537 IAudioClient_Stop(iface);
538 IMMDevice_Release(This->parent);
539 DeleteCriticalSection(&This->lock);
542 EnterCriticalSection(&g_sessions_lock);
543 list_remove(&This->entry);
544 LeaveCriticalSection(&g_sessions_lock);
546 HeapFree(GetProcessHeap(), 0, This->vols);
547 HeapFree(GetProcessHeap(), 0, This->local_buffer);
548 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
549 CoTaskMemFree(This->fmt);
550 HeapFree(GetProcessHeap(), 0, This);
555 static void dump_fmt(const WAVEFORMATEX *fmt)
557 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
558 switch(fmt->wFormatTag){
559 case WAVE_FORMAT_PCM:
560 TRACE("WAVE_FORMAT_PCM");
562 case WAVE_FORMAT_IEEE_FLOAT:
563 TRACE("WAVE_FORMAT_IEEE_FLOAT");
565 case WAVE_FORMAT_EXTENSIBLE:
566 TRACE("WAVE_FORMAT_EXTENSIBLE");
574 TRACE("nChannels: %u\n", fmt->nChannels);
575 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
576 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
577 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
578 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
579 TRACE("cbSize: %u\n", fmt->cbSize);
581 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
582 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
583 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
584 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
585 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
589 static DWORD get_channel_mask(unsigned int channels)
595 return KSAUDIO_SPEAKER_MONO;
597 return KSAUDIO_SPEAKER_STEREO;
599 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
601 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
603 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
605 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
607 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
609 return KSAUDIO_SPEAKER_7POINT1; /* not 7POINT1_SURROUND */
611 FIXME("Unknown speaker configuration: %u\n", channels);
615 static int get_oss_format(const WAVEFORMATEX *fmt)
617 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
619 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
620 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
621 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
622 switch(fmt->wBitsPerSample){
636 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
637 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
638 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
639 if(fmt->wBitsPerSample != 32)
649 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
654 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
655 size = sizeof(WAVEFORMATEXTENSIBLE);
657 size = sizeof(WAVEFORMATEX);
659 ret = CoTaskMemAlloc(size);
663 memcpy(ret, fmt, size);
665 ret->cbSize = size - sizeof(WAVEFORMATEX);
670 static HRESULT setup_oss_device(ACImpl *This, const WAVEFORMATEX *fmt,
676 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
677 WAVEFORMATEX *closest = NULL;
682 tmp = oss_format = get_oss_format(fmt);
684 return AUDCLNT_E_UNSUPPORTED_FORMAT;
685 if(ioctl(This->fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
686 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
689 if(tmp != oss_format){
690 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
691 return AUDCLNT_E_UNSUPPORTED_FORMAT;
694 closest = clone_format(fmt);
696 return E_OUTOFMEMORY;
698 tmp = fmt->nSamplesPerSec;
699 if(ioctl(This->fd, SNDCTL_DSP_SPEED, &tmp) < 0){
700 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
701 CoTaskMemFree(closest);
704 tenth = fmt->nSamplesPerSec * 0.1;
705 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
707 closest->nSamplesPerSec = tmp;
710 tmp = fmt->nChannels;
711 if(ioctl(This->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
712 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
713 CoTaskMemFree(closest);
716 if(tmp != fmt->nChannels){
718 closest->nChannels = tmp;
721 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
722 DWORD mask = get_channel_mask(closest->nChannels);
724 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
726 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
727 fmtex->dwChannelMask != mask)
731 if(ret == S_FALSE && out){
732 closest->nBlockAlign =
733 closest->nChannels * closest->wBitsPerSample / 8;
734 closest->nAvgBytesPerSec =
735 closest->nBlockAlign * closest->nSamplesPerSec;
738 CoTaskMemFree(closest);
740 TRACE("returning: %08x\n", ret);
744 static void session_init_vols(AudioSession *session, UINT channels)
746 if(session->channel_count < channels){
749 if(session->channel_vols)
750 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
751 session->channel_vols, sizeof(float) * channels);
753 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
754 sizeof(float) * channels);
755 if(!session->channel_vols)
758 for(i = session->channel_count; i < channels; ++i)
759 session->channel_vols[i] = 1.f;
761 session->channel_count = channels;
765 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
770 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
774 memcpy(&ret->guid, guid, sizeof(GUID));
776 ret->device = device;
778 list_init(&ret->clients);
780 list_add_head(&g_sessions, &ret->entry);
782 InitializeCriticalSection(&ret->lock);
784 session_init_vols(ret, num_channels);
786 ret->master_vol = 1.f;
791 /* if channels == 0, then this will return or create a session with
792 * matching dataflow and GUID. otherwise, channels must also match */
793 static HRESULT get_audio_session(const GUID *sessionguid,
794 IMMDevice *device, UINT channels, AudioSession **out)
796 AudioSession *session;
798 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
799 *out = create_session(&GUID_NULL, device, channels);
801 return E_OUTOFMEMORY;
807 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
808 if(session->device == device &&
809 IsEqualGUID(sessionguid, &session->guid)){
810 session_init_vols(session, channels);
817 *out = create_session(sessionguid, device, channels);
819 return E_OUTOFMEMORY;
825 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
826 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
827 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
828 const GUID *sessionguid)
830 ACImpl *This = impl_from_IAudioClient(iface);
834 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
835 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
842 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
843 return AUDCLNT_E_NOT_INITIALIZED;
845 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
846 AUDCLNT_STREAMFLAGS_LOOPBACK |
847 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
848 AUDCLNT_STREAMFLAGS_NOPERSIST |
849 AUDCLNT_STREAMFLAGS_RATEADJUST |
850 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
851 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
852 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
853 TRACE("Unknown flags: %08x\n", flags);
857 EnterCriticalSection(&This->lock);
860 LeaveCriticalSection(&This->lock);
861 return AUDCLNT_E_ALREADY_INITIALIZED;
864 hr = setup_oss_device(This, fmt, NULL);
866 LeaveCriticalSection(&This->lock);
867 return AUDCLNT_E_UNSUPPORTED_FORMAT;
870 LeaveCriticalSection(&This->lock);
875 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
876 LeaveCriticalSection(&This->lock);
877 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
881 mask = (100 << 8) | 100;
882 if(ioctl(This->fd, SNDCTL_DSP_SETPLAYVOL, &mask) < 0)
883 WARN("SETPLAYVOL failed: %d (%s)\n", errno, strerror(errno));
885 This->fmt = clone_format(fmt);
887 LeaveCriticalSection(&This->lock);
888 return E_OUTOFMEMORY;
892 This->period_us = period / 10;
894 This->period_us = DefaultPeriod / 10;
897 duration = 300000; /* 0.03s */
898 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
899 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
900 This->bufsize_frames * fmt->nBlockAlign);
901 if(!This->local_buffer){
902 CoTaskMemFree(This->fmt);
904 LeaveCriticalSection(&This->lock);
905 return E_OUTOFMEMORY;
908 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
910 CoTaskMemFree(This->fmt);
912 LeaveCriticalSection(&This->lock);
913 return E_OUTOFMEMORY;
916 for(i = 0; i < fmt->nChannels; ++i)
922 EnterCriticalSection(&g_sessions_lock);
924 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
927 LeaveCriticalSection(&g_sessions_lock);
928 HeapFree(GetProcessHeap(), 0, This->vols);
930 CoTaskMemFree(This->fmt);
932 LeaveCriticalSection(&This->lock);
936 list_add_tail(&This->session->clients, &This->entry);
938 LeaveCriticalSection(&g_sessions_lock);
940 This->initted = TRUE;
942 oss_setvol(This, -1);
944 LeaveCriticalSection(&This->lock);
949 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
952 ACImpl *This = impl_from_IAudioClient(iface);
954 TRACE("(%p)->(%p)\n", This, frames);
959 EnterCriticalSection(&This->lock);
962 LeaveCriticalSection(&This->lock);
963 return AUDCLNT_E_NOT_INITIALIZED;
966 *frames = This->bufsize_frames;
968 LeaveCriticalSection(&This->lock);
973 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
974 REFERENCE_TIME *latency)
976 ACImpl *This = impl_from_IAudioClient(iface);
978 TRACE("(%p)->(%p)\n", This, latency);
983 EnterCriticalSection(&This->lock);
986 LeaveCriticalSection(&This->lock);
987 return AUDCLNT_E_NOT_INITIALIZED;
990 if(This->dataflow == eRender){
994 if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
995 LeaveCriticalSection(&This->lock);
996 WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
1000 delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
1001 This->fmt->nBlockAlign);
1003 *latency = delay_s * 10000000;
1005 *latency = 10000; /* OSS doesn't provide input latency */
1007 LeaveCriticalSection(&This->lock);
1012 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1015 ACImpl *This = impl_from_IAudioClient(iface);
1018 TRACE("(%p)->(%p)\n", This, numpad);
1023 EnterCriticalSection(&This->lock);
1026 LeaveCriticalSection(&This->lock);
1027 return AUDCLNT_E_NOT_INITIALIZED;
1030 if(This->dataflow == eRender){
1031 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1032 LeaveCriticalSection(&This->lock);
1033 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1037 *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
1038 This->fmt->nBlockAlign;
1040 /* when the OSS buffer has less than one fragment of data, including
1041 * no data, it often reports it as some non-zero portion of a
1042 * fragment. when it has more than one fragment of data, it reports
1043 * it as some multiple of that portion of the fragment size.
1045 * so, we have to do some ugly workarounds to report the timing
1046 * as accurately as possible */
1047 if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
1048 *numpad = This->inbuf_frames;
1049 This->inbuf_frames = 0;
1051 if(*numpad < This->inbuf_frames)
1052 This->inbuf_frames = *numpad;
1054 *numpad = This->inbuf_frames;
1056 }else if(This->dataflow == eCapture){
1057 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1058 LeaveCriticalSection(&This->lock);
1059 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1063 if(bi.bytes <= bi.fragsize)
1066 *numpad = bi.bytes / This->fmt->nBlockAlign;
1068 LeaveCriticalSection(&This->lock);
1069 return E_UNEXPECTED;
1072 *numpad += This->held_frames;
1074 LeaveCriticalSection(&This->lock);
1079 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1080 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1081 WAVEFORMATEX **outpwfx)
1083 ACImpl *This = impl_from_IAudioClient(iface);
1086 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1088 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1091 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1092 return E_INVALIDARG;
1094 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1095 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1096 return E_INVALIDARG;
1100 EnterCriticalSection(&This->lock);
1102 ret = setup_oss_device(This, pwfx, outpwfx);
1104 LeaveCriticalSection(&This->lock);
1109 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1110 WAVEFORMATEX **pwfx)
1112 ACImpl *This = impl_from_IAudioClient(iface);
1113 WAVEFORMATEXTENSIBLE *fmt;
1116 TRACE("(%p)->(%p)\n", This, pwfx);
1122 if(This->dataflow == eRender)
1123 formats = This->ai.oformats;
1124 else if(This->dataflow == eCapture)
1125 formats = This->ai.iformats;
1127 return E_UNEXPECTED;
1129 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1131 return E_OUTOFMEMORY;
1133 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1134 if(formats & AFMT_S16_LE){
1135 fmt->Format.wBitsPerSample = 16;
1136 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1138 }else if(formats & AFMT_FLOAT){
1139 fmt->Format.wBitsPerSample = 32;
1140 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1142 }else if(formats & AFMT_U8){
1143 fmt->Format.wBitsPerSample = 8;
1144 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1145 }else if(formats & AFMT_S32_LE){
1146 fmt->Format.wBitsPerSample = 32;
1147 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1148 }else if(formats & AFMT_S24_LE){
1149 fmt->Format.wBitsPerSample = 24;
1150 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1152 ERR("Didn't recognize any available OSS formats: %x\n", formats);
1157 fmt->Format.nChannels = This->ai.max_channels;
1158 fmt->Format.nSamplesPerSec = This->ai.max_rate;
1159 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1161 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1162 fmt->Format.nChannels) / 8;
1163 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1164 fmt->Format.nBlockAlign;
1166 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1167 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1169 *pwfx = (WAVEFORMATEX*)fmt;
1175 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1176 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1178 ACImpl *This = impl_from_IAudioClient(iface);
1180 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1182 if(!defperiod && !minperiod)
1185 EnterCriticalSection(&This->lock);
1188 *defperiod = DefaultPeriod;
1190 *minperiod = MinimumPeriod;
1192 LeaveCriticalSection(&This->lock);
1197 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1199 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1200 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1201 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1202 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1203 This->fmt->wBitsPerSample == 8)
1204 memset(buf, 128, frames * This->fmt->nBlockAlign);
1206 memset(buf, 0, frames * This->fmt->nBlockAlign);
1209 static void oss_write_data(ACImpl *This)
1212 UINT32 written_frames;
1215 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1217 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1218 to_write = This->bufsize_frames - This->lcl_offs_frames;
1220 to_write = This->held_frames;
1222 if(This->session->mute)
1223 oss_silence_buffer(This, buf, to_write);
1225 written = write(This->fd, buf, to_write * This->fmt->nBlockAlign);
1227 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1230 written_frames = written / This->fmt->nBlockAlign;
1232 This->lcl_offs_frames += written_frames;
1233 This->lcl_offs_frames %= This->bufsize_frames;
1234 This->held_frames -= written_frames;
1235 This->inbuf_frames += written_frames;
1237 if(written_frames < to_write){
1238 /* OSS buffer probably full */
1242 if(This->held_frames){
1243 /* wrapped and have some data back at the start to write */
1245 if(This->session->mute)
1246 oss_silence_buffer(This, This->local_buffer, This->held_frames);
1248 written = write(This->fd, This->local_buffer,
1249 This->held_frames * This->fmt->nBlockAlign);
1251 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1254 written_frames = written / This->fmt->nBlockAlign;
1256 This->lcl_offs_frames += written_frames;
1257 This->lcl_offs_frames %= This->bufsize_frames;
1258 This->held_frames -= written_frames;
1259 This->inbuf_frames += written_frames;
1263 static void oss_read_data(ACImpl *This)
1265 UINT64 pos, readable;
1269 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1270 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1274 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1275 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1277 if(bi.bytes < readable)
1278 readable = bi.bytes;
1280 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1283 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1287 This->held_frames += nread / This->fmt->nBlockAlign;
1289 if(This->held_frames > This->bufsize_frames){
1290 WARN("Overflow of unread data\n");
1291 This->lcl_offs_frames += This->held_frames;
1292 This->lcl_offs_frames %= This->bufsize_frames;
1293 This->held_frames = This->bufsize_frames;
1297 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1299 ACImpl *This = user;
1301 EnterCriticalSection(&This->lock);
1303 if(This->dataflow == eRender && This->held_frames)
1304 oss_write_data(This);
1305 else if(This->dataflow == eCapture)
1306 oss_read_data(This);
1309 SetEvent(This->event);
1311 LeaveCriticalSection(&This->lock);
1314 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1316 ACImpl *This = impl_from_IAudioClient(iface);
1319 TRACE("(%p)\n", This);
1321 EnterCriticalSection(&This->lock);
1324 LeaveCriticalSection(&This->lock);
1325 return AUDCLNT_E_NOT_INITIALIZED;
1328 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1329 LeaveCriticalSection(&This->lock);
1330 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1334 LeaveCriticalSection(&This->lock);
1335 return AUDCLNT_E_NOT_STOPPED;
1338 if(This->dataflow == eRender)
1339 mask = PCM_ENABLE_OUTPUT;
1340 else if(This->dataflow == eCapture)
1341 mask = PCM_ENABLE_INPUT;
1343 LeaveCriticalSection(&This->lock);
1344 return E_UNEXPECTED;
1347 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1348 LeaveCriticalSection(&This->lock);
1349 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1353 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1354 oss_period_callback, This, 0, This->period_us / 1000,
1355 WT_EXECUTEINTIMERTHREAD))
1356 ERR("Unable to create period timer: %u\n", GetLastError());
1358 This->playing = TRUE;
1360 LeaveCriticalSection(&This->lock);
1365 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1367 ACImpl *This = impl_from_IAudioClient(iface);
1370 TRACE("(%p)\n", This);
1372 EnterCriticalSection(&This->lock);
1375 LeaveCriticalSection(&This->lock);
1376 return AUDCLNT_E_NOT_INITIALIZED;
1380 LeaveCriticalSection(&This->lock);
1384 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1385 DeleteTimerQueueTimer(g_timer_q, This->timer,
1386 INVALID_HANDLE_VALUE);
1390 if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1391 LeaveCriticalSection(&This->lock);
1392 WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1397 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1398 LeaveCriticalSection(&This->lock);
1399 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1403 This->playing = FALSE;
1405 LeaveCriticalSection(&This->lock);
1410 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1412 ACImpl *This = impl_from_IAudioClient(iface);
1414 TRACE("(%p)\n", This);
1416 EnterCriticalSection(&This->lock);
1419 LeaveCriticalSection(&This->lock);
1420 return AUDCLNT_E_NOT_INITIALIZED;
1424 LeaveCriticalSection(&This->lock);
1425 return AUDCLNT_E_NOT_STOPPED;
1428 if(This->buf_state != NOT_LOCKED){
1429 LeaveCriticalSection(&This->lock);
1430 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1433 This->written_frames = 0;
1434 This->inbuf_frames = 0;
1435 This->held_frames = 0;
1437 if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1438 WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1440 LeaveCriticalSection(&This->lock);
1445 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1448 ACImpl *This = impl_from_IAudioClient(iface);
1450 TRACE("(%p)->(%p)\n", This, event);
1453 return E_INVALIDARG;
1455 EnterCriticalSection(&This->lock);
1458 LeaveCriticalSection(&This->lock);
1459 return AUDCLNT_E_NOT_INITIALIZED;
1462 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1463 LeaveCriticalSection(&This->lock);
1464 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1467 This->event = event;
1469 LeaveCriticalSection(&This->lock);
1474 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1477 ACImpl *This = impl_from_IAudioClient(iface);
1479 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1485 EnterCriticalSection(&This->lock);
1488 LeaveCriticalSection(&This->lock);
1489 return AUDCLNT_E_NOT_INITIALIZED;
1492 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1493 if(This->dataflow != eRender){
1494 LeaveCriticalSection(&This->lock);
1495 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1497 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1498 *ppv = &This->IAudioRenderClient_iface;
1499 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1500 if(This->dataflow != eCapture){
1501 LeaveCriticalSection(&This->lock);
1502 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1504 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1505 *ppv = &This->IAudioCaptureClient_iface;
1506 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1507 IAudioClock_AddRef(&This->IAudioClock_iface);
1508 *ppv = &This->IAudioClock_iface;
1509 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1510 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1511 *ppv = &This->IAudioStreamVolume_iface;
1512 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1513 if(!This->session_wrapper){
1514 This->session_wrapper = AudioSessionWrapper_Create(This);
1515 if(!This->session_wrapper){
1516 LeaveCriticalSection(&This->lock);
1517 return E_OUTOFMEMORY;
1520 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1522 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1523 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1524 if(!This->session_wrapper){
1525 This->session_wrapper = AudioSessionWrapper_Create(This);
1526 if(!This->session_wrapper){
1527 LeaveCriticalSection(&This->lock);
1528 return E_OUTOFMEMORY;
1531 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1533 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1534 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1535 if(!This->session_wrapper){
1536 This->session_wrapper = AudioSessionWrapper_Create(This);
1537 if(!This->session_wrapper){
1538 LeaveCriticalSection(&This->lock);
1539 return E_OUTOFMEMORY;
1542 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1544 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1548 LeaveCriticalSection(&This->lock);
1552 LeaveCriticalSection(&This->lock);
1554 FIXME("stub %s\n", debugstr_guid(riid));
1555 return E_NOINTERFACE;
1558 static const IAudioClientVtbl AudioClient_Vtbl =
1560 AudioClient_QueryInterface,
1562 AudioClient_Release,
1563 AudioClient_Initialize,
1564 AudioClient_GetBufferSize,
1565 AudioClient_GetStreamLatency,
1566 AudioClient_GetCurrentPadding,
1567 AudioClient_IsFormatSupported,
1568 AudioClient_GetMixFormat,
1569 AudioClient_GetDevicePeriod,
1573 AudioClient_SetEventHandle,
1574 AudioClient_GetService
1577 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1578 IAudioRenderClient *iface, REFIID riid, void **ppv)
1580 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1586 if(IsEqualIID(riid, &IID_IUnknown) ||
1587 IsEqualIID(riid, &IID_IAudioRenderClient))
1590 IUnknown_AddRef((IUnknown*)*ppv);
1594 WARN("Unknown interface %s\n", debugstr_guid(riid));
1595 return E_NOINTERFACE;
1598 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1600 ACImpl *This = impl_from_IAudioRenderClient(iface);
1601 return AudioClient_AddRef(&This->IAudioClient_iface);
1604 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1606 ACImpl *This = impl_from_IAudioRenderClient(iface);
1607 return AudioClient_Release(&This->IAudioClient_iface);
1610 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1611 UINT32 frames, BYTE **data)
1613 ACImpl *This = impl_from_IAudioRenderClient(iface);
1614 UINT32 pad, write_pos;
1617 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1622 EnterCriticalSection(&This->lock);
1624 if(This->buf_state != NOT_LOCKED){
1625 LeaveCriticalSection(&This->lock);
1626 return AUDCLNT_E_OUT_OF_ORDER;
1630 This->buf_state = LOCKED_NORMAL;
1631 LeaveCriticalSection(&This->lock);
1635 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1637 LeaveCriticalSection(&This->lock);
1641 if(pad + frames > This->bufsize_frames){
1642 LeaveCriticalSection(&This->lock);
1643 return AUDCLNT_E_BUFFER_TOO_LARGE;
1647 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1648 if(write_pos + frames > This->bufsize_frames){
1649 if(This->tmp_buffer_frames < frames){
1650 if(This->tmp_buffer)
1651 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1652 This->tmp_buffer, frames * This->fmt->nBlockAlign);
1654 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1655 frames * This->fmt->nBlockAlign);
1656 if(!This->tmp_buffer){
1657 LeaveCriticalSection(&This->lock);
1658 return E_OUTOFMEMORY;
1660 This->tmp_buffer_frames = frames;
1662 *data = This->tmp_buffer;
1663 This->buf_state = LOCKED_WRAPPED;
1665 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1666 This->buf_state = LOCKED_NORMAL;
1669 LeaveCriticalSection(&This->lock);
1674 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1676 UINT32 write_offs_frames =
1677 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1678 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1679 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1680 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1681 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1683 if(written_bytes <= chunk_bytes){
1684 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1686 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1687 memcpy(This->local_buffer, buffer + chunk_bytes,
1688 written_bytes - chunk_bytes);
1692 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1693 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1695 ACImpl *This = impl_from_IAudioRenderClient(iface);
1698 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1700 EnterCriticalSection(&This->lock);
1702 if(This->buf_state == NOT_LOCKED || !written_frames){
1703 This->buf_state = NOT_LOCKED;
1704 LeaveCriticalSection(&This->lock);
1705 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1708 if(This->buf_state == LOCKED_NORMAL)
1709 buffer = This->local_buffer + This->fmt->nBlockAlign *
1710 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1712 buffer = This->tmp_buffer;
1714 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1715 oss_silence_buffer(This, buffer, written_frames);
1717 if(This->held_frames){
1718 if(This->buf_state == LOCKED_WRAPPED)
1719 oss_wrap_buffer(This, buffer, written_frames);
1721 This->held_frames += written_frames;
1726 if(This->session->mute)
1727 oss_silence_buffer(This, buffer, written_frames);
1729 w_bytes = write(This->fd, buffer,
1730 written_frames * This->fmt->nBlockAlign);
1732 LeaveCriticalSection(&This->lock);
1733 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1736 w_frames = w_bytes / This->fmt->nBlockAlign;
1737 This->inbuf_frames += w_frames;
1739 if(w_frames < written_frames){
1740 if(This->buf_state == LOCKED_WRAPPED)
1741 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1742 written_frames - w_frames);
1744 This->held_frames = written_frames - w_frames;
1748 This->written_frames += written_frames;
1749 This->buf_state = NOT_LOCKED;
1751 LeaveCriticalSection(&This->lock);
1756 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1757 AudioRenderClient_QueryInterface,
1758 AudioRenderClient_AddRef,
1759 AudioRenderClient_Release,
1760 AudioRenderClient_GetBuffer,
1761 AudioRenderClient_ReleaseBuffer
1764 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1765 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1767 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1773 if(IsEqualIID(riid, &IID_IUnknown) ||
1774 IsEqualIID(riid, &IID_IAudioCaptureClient))
1777 IUnknown_AddRef((IUnknown*)*ppv);
1781 WARN("Unknown interface %s\n", debugstr_guid(riid));
1782 return E_NOINTERFACE;
1785 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1787 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1788 return IAudioClient_AddRef(&This->IAudioClient_iface);
1791 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1793 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1794 return IAudioClient_Release(&This->IAudioClient_iface);
1797 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1798 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1801 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1804 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1807 if(!data || !frames || !flags)
1810 EnterCriticalSection(&This->lock);
1812 if(This->buf_state != NOT_LOCKED){
1813 LeaveCriticalSection(&This->lock);
1814 return AUDCLNT_E_OUT_OF_ORDER;
1817 hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1819 LeaveCriticalSection(&This->lock);
1825 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1826 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1827 if(This->tmp_buffer_frames < *frames){
1828 if(This->tmp_buffer)
1829 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1830 This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1832 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1833 *frames * This->fmt->nBlockAlign);
1834 if(!This->tmp_buffer){
1835 LeaveCriticalSection(&This->lock);
1836 return E_OUTOFMEMORY;
1838 This->tmp_buffer_frames = *frames;
1841 *data = This->tmp_buffer;
1842 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1843 This->fmt->nBlockAlign;
1844 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1845 frames_bytes = *frames * This->fmt->nBlockAlign;
1846 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1847 memcpy(This->tmp_buffer, This->local_buffer,
1848 frames_bytes - chunk_bytes);
1850 *data = This->local_buffer +
1851 This->lcl_offs_frames * This->fmt->nBlockAlign;
1853 This->buf_state = LOCKED_NORMAL;
1855 if(devpos || qpcpos)
1856 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1858 LeaveCriticalSection(&This->lock);
1860 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1863 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1864 IAudioCaptureClient *iface, UINT32 done)
1866 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1868 TRACE("(%p)->(%u)\n", This, done);
1870 EnterCriticalSection(&This->lock);
1872 if(This->buf_state == NOT_LOCKED){
1873 LeaveCriticalSection(&This->lock);
1874 return AUDCLNT_E_OUT_OF_ORDER;
1877 This->held_frames -= done;
1878 This->lcl_offs_frames += done;
1879 This->lcl_offs_frames %= This->bufsize_frames;
1881 This->buf_state = NOT_LOCKED;
1883 LeaveCriticalSection(&This->lock);
1888 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1889 IAudioCaptureClient *iface, UINT32 *frames)
1891 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1893 TRACE("(%p)->(%p)\n", This, frames);
1895 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1898 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1900 AudioCaptureClient_QueryInterface,
1901 AudioCaptureClient_AddRef,
1902 AudioCaptureClient_Release,
1903 AudioCaptureClient_GetBuffer,
1904 AudioCaptureClient_ReleaseBuffer,
1905 AudioCaptureClient_GetNextPacketSize
1908 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1909 REFIID riid, void **ppv)
1911 ACImpl *This = impl_from_IAudioClock(iface);
1913 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1919 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1921 else if(IsEqualIID(riid, &IID_IAudioClock2))
1922 *ppv = &This->IAudioClock2_iface;
1924 IUnknown_AddRef((IUnknown*)*ppv);
1928 WARN("Unknown interface %s\n", debugstr_guid(riid));
1929 return E_NOINTERFACE;
1932 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1934 ACImpl *This = impl_from_IAudioClock(iface);
1935 return IAudioClient_AddRef(&This->IAudioClient_iface);
1938 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1940 ACImpl *This = impl_from_IAudioClock(iface);
1941 return IAudioClient_Release(&This->IAudioClient_iface);
1944 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1946 ACImpl *This = impl_from_IAudioClock(iface);
1948 TRACE("(%p)->(%p)\n", This, freq);
1950 *freq = This->fmt->nSamplesPerSec;
1955 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1958 ACImpl *This = impl_from_IAudioClock(iface);
1962 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1967 EnterCriticalSection(&This->lock);
1969 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1971 LeaveCriticalSection(&This->lock);
1975 if(This->dataflow == eRender)
1976 *pos = This->written_frames - pad;
1977 else if(This->dataflow == eCapture)
1978 *pos = This->written_frames + pad;
1980 LeaveCriticalSection(&This->lock);
1983 LARGE_INTEGER stamp, freq;
1984 QueryPerformanceCounter(&stamp);
1985 QueryPerformanceFrequency(&freq);
1986 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1992 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1995 ACImpl *This = impl_from_IAudioClock(iface);
1997 TRACE("(%p)->(%p)\n", This, chars);
2002 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2007 static const IAudioClockVtbl AudioClock_Vtbl =
2009 AudioClock_QueryInterface,
2012 AudioClock_GetFrequency,
2013 AudioClock_GetPosition,
2014 AudioClock_GetCharacteristics
2017 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2018 REFIID riid, void **ppv)
2020 ACImpl *This = impl_from_IAudioClock2(iface);
2021 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2024 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2026 ACImpl *This = impl_from_IAudioClock2(iface);
2027 return IAudioClient_AddRef(&This->IAudioClient_iface);
2030 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2032 ACImpl *This = impl_from_IAudioClock2(iface);
2033 return IAudioClient_Release(&This->IAudioClient_iface);
2036 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2037 UINT64 *pos, UINT64 *qpctime)
2039 ACImpl *This = impl_from_IAudioClock2(iface);
2041 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2046 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2048 AudioClock2_QueryInterface,
2050 AudioClock2_Release,
2051 AudioClock2_GetDevicePosition
2054 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2056 AudioSessionWrapper *ret;
2058 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2059 sizeof(AudioSessionWrapper));
2063 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2064 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2065 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2069 ret->client = client;
2071 ret->session = client->session;
2072 AudioClient_AddRef(&client->IAudioClient_iface);
2078 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2079 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2081 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2087 if(IsEqualIID(riid, &IID_IUnknown) ||
2088 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2089 IsEqualIID(riid, &IID_IAudioSessionControl2))
2092 IUnknown_AddRef((IUnknown*)*ppv);
2096 WARN("Unknown interface %s\n", debugstr_guid(riid));
2097 return E_NOINTERFACE;
2100 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2102 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2104 ref = InterlockedIncrement(&This->ref);
2105 TRACE("(%p) Refcount now %u\n", This, ref);
2109 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2111 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2113 ref = InterlockedDecrement(&This->ref);
2114 TRACE("(%p) Refcount now %u\n", This, ref);
2117 EnterCriticalSection(&This->client->lock);
2118 This->client->session_wrapper = NULL;
2119 LeaveCriticalSection(&This->client->lock);
2120 AudioClient_Release(&This->client->IAudioClient_iface);
2122 HeapFree(GetProcessHeap(), 0, This);
2127 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2128 AudioSessionState *state)
2130 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2133 TRACE("(%p)->(%p)\n", This, state);
2136 return NULL_PTR_ERR;
2138 EnterCriticalSection(&g_sessions_lock);
2140 if(list_empty(&This->session->clients)){
2141 *state = AudioSessionStateExpired;
2142 LeaveCriticalSection(&g_sessions_lock);
2146 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2147 EnterCriticalSection(&client->lock);
2148 if(client->playing){
2149 *state = AudioSessionStateActive;
2150 LeaveCriticalSection(&client->lock);
2151 LeaveCriticalSection(&g_sessions_lock);
2154 LeaveCriticalSection(&client->lock);
2157 LeaveCriticalSection(&g_sessions_lock);
2159 *state = AudioSessionStateInactive;
2164 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2165 IAudioSessionControl2 *iface, WCHAR **name)
2167 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2169 FIXME("(%p)->(%p) - stub\n", This, name);
2174 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2175 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2177 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2179 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2184 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2185 IAudioSessionControl2 *iface, WCHAR **path)
2187 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2189 FIXME("(%p)->(%p) - stub\n", This, path);
2194 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2195 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2197 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2199 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2204 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2205 IAudioSessionControl2 *iface, GUID *group)
2207 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2209 FIXME("(%p)->(%p) - stub\n", This, group);
2214 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2215 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2217 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2219 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2220 debugstr_guid(session));
2225 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2226 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2228 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2230 FIXME("(%p)->(%p) - stub\n", This, events);
2235 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2236 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2238 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2240 FIXME("(%p)->(%p) - stub\n", This, events);
2245 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2246 IAudioSessionControl2 *iface, WCHAR **id)
2248 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2250 FIXME("(%p)->(%p) - stub\n", This, id);
2255 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2256 IAudioSessionControl2 *iface, WCHAR **id)
2258 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2260 FIXME("(%p)->(%p) - stub\n", This, id);
2265 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2266 IAudioSessionControl2 *iface, DWORD *pid)
2268 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2270 TRACE("(%p)->(%p)\n", This, pid);
2275 *pid = GetCurrentProcessId();
2280 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2281 IAudioSessionControl2 *iface)
2283 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2285 TRACE("(%p)\n", This);
2290 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2291 IAudioSessionControl2 *iface, BOOL optout)
2293 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2295 TRACE("(%p)->(%d)\n", This, optout);
2300 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2302 AudioSessionControl_QueryInterface,
2303 AudioSessionControl_AddRef,
2304 AudioSessionControl_Release,
2305 AudioSessionControl_GetState,
2306 AudioSessionControl_GetDisplayName,
2307 AudioSessionControl_SetDisplayName,
2308 AudioSessionControl_GetIconPath,
2309 AudioSessionControl_SetIconPath,
2310 AudioSessionControl_GetGroupingParam,
2311 AudioSessionControl_SetGroupingParam,
2312 AudioSessionControl_RegisterAudioSessionNotification,
2313 AudioSessionControl_UnregisterAudioSessionNotification,
2314 AudioSessionControl_GetSessionIdentifier,
2315 AudioSessionControl_GetSessionInstanceIdentifier,
2316 AudioSessionControl_GetProcessId,
2317 AudioSessionControl_IsSystemSoundsSession,
2318 AudioSessionControl_SetDuckingPreference
2321 /* index == -1 means set all channels, otherwise sets only the given channel */
2322 static HRESULT oss_setvol(ACImpl *This, UINT32 index)
2329 if(index == (UINT32)-1){
2332 for(i = 0; i < This->fmt->nChannels; ++i){
2334 hr = oss_setvol(This, i);
2342 /* OSS doesn't support volume control past the first two channels */
2345 if(This->dataflow == eRender){
2346 setreq = SNDCTL_DSP_SETPLAYVOL;
2347 getreq = SNDCTL_DSP_GETPLAYVOL;
2348 }else if(This->dataflow == eCapture){
2349 setreq = SNDCTL_DSP_SETRECVOL;
2350 getreq = SNDCTL_DSP_GETRECVOL;
2352 return E_UNEXPECTED;
2354 if(ioctl(This->fd, getreq, &vol) < 0){
2356 /* device doesn't support this call */
2359 WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2363 level = This->session->master_vol * This->session->channel_vols[index] *
2367 vol = l | (vol & 0xFF00);
2369 vol = (vol & 0xFF) | (l << 8);
2371 if(ioctl(This->fd, setreq, &vol) < 0){
2373 /* device doesn't support this call */
2376 WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2383 static HRESULT oss_session_setvol(AudioSession *session, UINT32 index)
2388 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2390 hr = oss_setvol(client, index);
2398 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2399 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2401 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2407 if(IsEqualIID(riid, &IID_IUnknown) ||
2408 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2411 IUnknown_AddRef((IUnknown*)*ppv);
2415 WARN("Unknown interface %s\n", debugstr_guid(riid));
2416 return E_NOINTERFACE;
2419 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2421 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2422 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2425 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2427 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2428 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2431 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2432 ISimpleAudioVolume *iface, float level, const GUID *context)
2434 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2435 AudioSession *session = This->session;
2438 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2440 if(level < 0.f || level > 1.f)
2441 return E_INVALIDARG;
2444 FIXME("Notifications not supported yet\n");
2446 EnterCriticalSection(&session->lock);
2448 session->master_vol = level;
2450 ret = oss_session_setvol(session, -1);
2452 LeaveCriticalSection(&session->lock);
2457 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2458 ISimpleAudioVolume *iface, float *level)
2460 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2461 AudioSession *session = This->session;
2463 TRACE("(%p)->(%p)\n", session, level);
2466 return NULL_PTR_ERR;
2468 *level = session->master_vol;
2473 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2474 BOOL mute, const GUID *context)
2476 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2477 AudioSession *session = This->session;
2479 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2481 EnterCriticalSection(&session->lock);
2483 if(!mute && session->mute){
2486 session->mute = mute;
2488 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2489 EnterCriticalSection(&client->lock);
2490 if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2491 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2493 oss_write_data(client);
2494 LeaveCriticalSection(&client->lock);
2497 session->mute = mute;
2499 LeaveCriticalSection(&session->lock);
2504 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2507 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2508 AudioSession *session = This->session;
2510 TRACE("(%p)->(%p)\n", session, mute);
2513 return NULL_PTR_ERR;
2515 *mute = This->session->mute;
2520 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2522 SimpleAudioVolume_QueryInterface,
2523 SimpleAudioVolume_AddRef,
2524 SimpleAudioVolume_Release,
2525 SimpleAudioVolume_SetMasterVolume,
2526 SimpleAudioVolume_GetMasterVolume,
2527 SimpleAudioVolume_SetMute,
2528 SimpleAudioVolume_GetMute
2531 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2532 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2534 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2540 if(IsEqualIID(riid, &IID_IUnknown) ||
2541 IsEqualIID(riid, &IID_IAudioStreamVolume))
2544 IUnknown_AddRef((IUnknown*)*ppv);
2548 WARN("Unknown interface %s\n", debugstr_guid(riid));
2549 return E_NOINTERFACE;
2552 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2554 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2555 return IAudioClient_AddRef(&This->IAudioClient_iface);
2558 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2560 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2561 return IAudioClient_Release(&This->IAudioClient_iface);
2564 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2565 IAudioStreamVolume *iface, UINT32 *out)
2567 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2569 TRACE("(%p)->(%p)\n", This, out);
2574 *out = This->fmt->nChannels;
2579 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2580 IAudioStreamVolume *iface, UINT32 index, float level)
2582 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2585 TRACE("(%p)->(%d, %f)\n", This, index, level);
2587 if(level < 0.f || level > 1.f)
2588 return E_INVALIDARG;
2590 if(index >= This->fmt->nChannels)
2591 return E_INVALIDARG;
2593 EnterCriticalSection(&This->lock);
2595 This->vols[index] = level;
2597 ret = oss_setvol(This, index);
2599 LeaveCriticalSection(&This->lock);
2604 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2605 IAudioStreamVolume *iface, UINT32 index, float *level)
2607 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2609 TRACE("(%p)->(%d, %p)\n", This, index, level);
2614 if(index >= This->fmt->nChannels)
2615 return E_INVALIDARG;
2617 *level = This->vols[index];
2622 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2623 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2625 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2629 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2634 if(count != This->fmt->nChannels)
2635 return E_INVALIDARG;
2637 EnterCriticalSection(&This->lock);
2639 for(i = 0; i < count; ++i)
2640 This->vols[i] = levels[i];
2642 ret = oss_setvol(This, -1);
2644 LeaveCriticalSection(&This->lock);
2649 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2650 IAudioStreamVolume *iface, UINT32 count, float *levels)
2652 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2655 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2660 if(count != This->fmt->nChannels)
2661 return E_INVALIDARG;
2663 EnterCriticalSection(&This->lock);
2665 for(i = 0; i < count; ++i)
2666 levels[i] = This->vols[i];
2668 LeaveCriticalSection(&This->lock);
2673 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2675 AudioStreamVolume_QueryInterface,
2676 AudioStreamVolume_AddRef,
2677 AudioStreamVolume_Release,
2678 AudioStreamVolume_GetChannelCount,
2679 AudioStreamVolume_SetChannelVolume,
2680 AudioStreamVolume_GetChannelVolume,
2681 AudioStreamVolume_SetAllVolumes,
2682 AudioStreamVolume_GetAllVolumes
2685 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2686 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2688 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2694 if(IsEqualIID(riid, &IID_IUnknown) ||
2695 IsEqualIID(riid, &IID_IChannelAudioVolume))
2698 IUnknown_AddRef((IUnknown*)*ppv);
2702 WARN("Unknown interface %s\n", debugstr_guid(riid));
2703 return E_NOINTERFACE;
2706 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2708 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2709 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2712 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2714 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2715 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2718 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2719 IChannelAudioVolume *iface, UINT32 *out)
2721 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2722 AudioSession *session = This->session;
2724 TRACE("(%p)->(%p)\n", session, out);
2727 return NULL_PTR_ERR;
2729 *out = session->channel_count;
2734 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2735 IChannelAudioVolume *iface, UINT32 index, float level,
2736 const GUID *context)
2738 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2739 AudioSession *session = This->session;
2742 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2743 wine_dbgstr_guid(context));
2745 if(level < 0.f || level > 1.f)
2746 return E_INVALIDARG;
2748 if(index >= session->channel_count)
2749 return E_INVALIDARG;
2752 FIXME("Notifications not supported yet\n");
2754 EnterCriticalSection(&session->lock);
2756 session->channel_vols[index] = level;
2758 ret = oss_session_setvol(session, index);
2760 LeaveCriticalSection(&session->lock);
2765 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2766 IChannelAudioVolume *iface, UINT32 index, float *level)
2768 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2769 AudioSession *session = This->session;
2771 TRACE("(%p)->(%d, %p)\n", session, index, level);
2774 return NULL_PTR_ERR;
2776 if(index >= session->channel_count)
2777 return E_INVALIDARG;
2779 *level = session->channel_vols[index];
2784 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2785 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2786 const GUID *context)
2788 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2789 AudioSession *session = This->session;
2793 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2794 wine_dbgstr_guid(context));
2797 return NULL_PTR_ERR;
2799 if(count != session->channel_count)
2800 return E_INVALIDARG;
2803 FIXME("Notifications not supported yet\n");
2805 EnterCriticalSection(&session->lock);
2807 for(i = 0; i < count; ++i)
2808 session->channel_vols[i] = levels[i];
2810 ret = oss_session_setvol(session, -1);
2812 LeaveCriticalSection(&session->lock);
2817 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2818 IChannelAudioVolume *iface, UINT32 count, float *levels)
2820 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2821 AudioSession *session = This->session;
2824 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2827 return NULL_PTR_ERR;
2829 if(count != session->channel_count)
2830 return E_INVALIDARG;
2832 for(i = 0; i < count; ++i)
2833 levels[i] = session->channel_vols[i];
2838 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2840 ChannelAudioVolume_QueryInterface,
2841 ChannelAudioVolume_AddRef,
2842 ChannelAudioVolume_Release,
2843 ChannelAudioVolume_GetChannelCount,
2844 ChannelAudioVolume_SetChannelVolume,
2845 ChannelAudioVolume_GetChannelVolume,
2846 ChannelAudioVolume_SetAllVolumes,
2847 ChannelAudioVolume_GetAllVolumes
2850 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2851 REFIID riid, void **ppv)
2853 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2859 if(IsEqualIID(riid, &IID_IUnknown) ||
2860 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2861 IsEqualIID(riid, &IID_IAudioSessionManager2))
2864 IUnknown_AddRef((IUnknown*)*ppv);
2868 WARN("Unknown interface %s\n", debugstr_guid(riid));
2869 return E_NOINTERFACE;
2872 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2874 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2876 ref = InterlockedIncrement(&This->ref);
2877 TRACE("(%p) Refcount now %u\n", This, ref);
2881 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2883 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2885 ref = InterlockedDecrement(&This->ref);
2886 TRACE("(%p) Refcount now %u\n", This, ref);
2888 HeapFree(GetProcessHeap(), 0, This);
2892 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2893 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2894 IAudioSessionControl **out)
2896 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2897 AudioSession *session;
2898 AudioSessionWrapper *wrapper;
2901 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2904 hr = get_audio_session(session_guid, This->device, 0, &session);
2908 wrapper = AudioSessionWrapper_Create(NULL);
2910 return E_OUTOFMEMORY;
2912 wrapper->session = session;
2914 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2919 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2920 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2921 ISimpleAudioVolume **out)
2923 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2924 AudioSession *session;
2925 AudioSessionWrapper *wrapper;
2928 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2931 hr = get_audio_session(session_guid, This->device, 0, &session);
2935 wrapper = AudioSessionWrapper_Create(NULL);
2937 return E_OUTOFMEMORY;
2939 wrapper->session = session;
2941 *out = &wrapper->ISimpleAudioVolume_iface;
2946 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2947 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2949 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2950 FIXME("(%p)->(%p) - stub\n", This, out);
2954 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2955 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2957 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2958 FIXME("(%p)->(%p) - stub\n", This, notification);
2962 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2963 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2965 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2966 FIXME("(%p)->(%p) - stub\n", This, notification);
2970 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2971 IAudioSessionManager2 *iface, const WCHAR *session_id,
2972 IAudioVolumeDuckNotification *notification)
2974 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2975 FIXME("(%p)->(%p) - stub\n", This, notification);
2979 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2980 IAudioSessionManager2 *iface,
2981 IAudioVolumeDuckNotification *notification)
2983 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2984 FIXME("(%p)->(%p) - stub\n", This, notification);
2988 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2990 AudioSessionManager_QueryInterface,
2991 AudioSessionManager_AddRef,
2992 AudioSessionManager_Release,
2993 AudioSessionManager_GetAudioSessionControl,
2994 AudioSessionManager_GetSimpleAudioVolume,
2995 AudioSessionManager_GetSessionEnumerator,
2996 AudioSessionManager_RegisterSessionNotification,
2997 AudioSessionManager_UnregisterSessionNotification,
2998 AudioSessionManager_RegisterDuckNotification,
2999 AudioSessionManager_UnregisterDuckNotification
3002 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3003 IAudioSessionManager2 **out)
3007 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3009 return E_OUTOFMEMORY;
3011 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3012 This->device = device;
3015 *out = &This->IAudioSessionManager2_iface;