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"
52 #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;
122 char devnode[OSS_DEVNODE_SIZE];
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 */
129 BYTE *local_buffer, *tmp_buffer;
133 CRITICAL_SECTION lock;
135 AudioSession *session;
136 AudioSessionWrapper *session_wrapper;
143 LOCKED_NORMAL, /* public buffer piece is from local_buffer */
144 LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
147 typedef struct _SessionMgr {
148 IAudioSessionManager2 IAudioSessionManager2_iface;
155 static HANDLE g_timer_q;
157 static CRITICAL_SECTION g_sessions_lock;
158 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
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") }
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);
167 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
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;
180 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
182 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
185 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
187 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
190 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
192 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
195 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
197 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
200 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
202 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
205 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
207 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
210 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
212 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
215 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
217 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
220 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
222 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
225 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
227 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
230 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
234 case DLL_PROCESS_ATTACH:
235 g_timer_q = CreateTimerQueue();
240 case DLL_PROCESS_DETACH:
241 DeleteCriticalSection(&g_sessions_lock);
247 /* From <dlls/mmdevapi/mmdevapi.h> */
248 enum DriverPriority {
249 Priority_Unavailable = 0,
255 int WINAPI AUDDRV_GetPriority(void)
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. */
265 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
267 TRACE("Priority_Unavailable: open failed\n");
268 return Priority_Unavailable;
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");
276 return Priority_Unavailable;
281 if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
282 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
285 if(sysinfo.versionnum & 0x80000000){
286 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
290 TRACE("Priority_Preferred: Seems like valid OSS!\n");
292 return Priority_Preferred;
295 static const char *oss_clean_devnode(const char *devnode)
297 static char ret[OSS_DEVNODE_SIZE];
299 const char *dot, *slash;
302 dot = strrchr(devnode, '.');
306 slash = strrchr(devnode, '/');
307 if(slash && dot < slash)
312 memcpy(ret, devnode, len);
318 static UINT get_default_index(EDataFlow flow, char **keys, UINT num)
325 fd = open("/dev/dsp", O_WRONLY);
327 fd = open("/dev/dsp", O_RDONLY);
330 WARN("Couldn't open default device!\n");
335 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
336 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
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]))
349 WARN("Couldn't find default device! Choosing first.\n");
353 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, char ***keys,
354 UINT *num, UINT *def_index)
358 static int print_once = 0;
360 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
362 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
364 ERR("OSS /dev/mixer doesn't seem to exist\n");
365 return AUDCLNT_E_SERVICE_NOT_RUNNING;
368 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
372 ERR("OSS version too old, need at least OSSv4\n");
373 return AUDCLNT_E_SERVICE_NOT_RUNNING;
376 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
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);
392 if(sysinfo.numaudios <= 0){
393 WARN("No audio devices!\n");
395 return AUDCLNT_E_SERVICE_NOT_RUNNING;
398 *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
399 *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
402 for(i = 0; i < sysinfo.numaudios; ++i){
403 oss_audioinfo ai = {0};
408 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
409 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
414 devnode = oss_clean_devnode(ai.devnode);
416 /* check for duplicates */
417 for(j = 0; j < *num; ++j)
418 if(!strcmp(devnode, (*keys)[j]))
424 fd = open(devnode, O_WRONLY, 0);
426 fd = open(devnode, O_RDONLY, 0);
428 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
429 devnode, errno, strerror(errno));
434 if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
435 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
438 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
439 strlen(devnode) + 1);
441 for(i = 0; i < *num; ++i){
442 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
443 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
445 HeapFree(GetProcessHeap(), 0, *ids);
446 HeapFree(GetProcessHeap(), 0, *keys);
448 return E_OUTOFMEMORY;
450 strcpy((*keys)[*num], devnode);
452 len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
453 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
454 len * sizeof(WCHAR));
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]);
461 HeapFree(GetProcessHeap(), 0, *ids);
462 HeapFree(GetProcessHeap(), 0, *keys);
464 return E_OUTOFMEMORY;
466 MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
475 *def_index = get_default_index(flow, *keys, *num);
480 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
481 EDataFlow dataflow, IAudioClient **out)
485 TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
487 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
489 return E_OUTOFMEMORY;
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);
496 HeapFree(GetProcessHeap(), 0, This);
500 ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
502 HeapFree(GetProcessHeap(), 0, This);
503 return AUDCLNT_E_DEVICE_INVALIDATED;
506 This->dataflow = dataflow;
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));
513 HeapFree(GetProcessHeap(), 0, This);
517 strcpy(This->devnode, devnode);
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);
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;
539 InitializeCriticalSection(&This->lock);
540 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
543 IMMDevice_AddRef(This->parent);
545 IAudioClient_AddRef(&This->IAudioClient_iface);
547 *out = &This->IAudioClient_iface;
552 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
553 REFIID riid, void **ppv)
555 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
560 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
563 IUnknown_AddRef((IUnknown*)*ppv);
566 WARN("Unknown interface %s\n", debugstr_guid(riid));
567 return E_NOINTERFACE;
570 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
572 ACImpl *This = impl_from_IAudioClient(iface);
574 ref = InterlockedIncrement(&This->ref);
575 TRACE("(%p) Refcount now %u\n", This, ref);
579 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
581 ACImpl *This = impl_from_IAudioClient(iface);
583 ref = InterlockedDecrement(&This->ref);
584 TRACE("(%p) Refcount now %u\n", This, ref);
586 IAudioClient_Stop(iface);
587 IMMDevice_Release(This->parent);
588 This->lock.DebugInfo->Spare[0] = 0;
589 DeleteCriticalSection(&This->lock);
592 EnterCriticalSection(&g_sessions_lock);
593 list_remove(&This->entry);
594 LeaveCriticalSection(&g_sessions_lock);
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);
605 static void dump_fmt(const WAVEFORMATEX *fmt)
607 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
608 switch(fmt->wFormatTag){
609 case WAVE_FORMAT_PCM:
610 TRACE("WAVE_FORMAT_PCM");
612 case WAVE_FORMAT_IEEE_FLOAT:
613 TRACE("WAVE_FORMAT_IEEE_FLOAT");
615 case WAVE_FORMAT_EXTENSIBLE:
616 TRACE("WAVE_FORMAT_EXTENSIBLE");
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);
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));
639 static DWORD get_channel_mask(unsigned int channels)
645 return KSAUDIO_SPEAKER_MONO;
647 return KSAUDIO_SPEAKER_STEREO;
649 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
651 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
653 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
655 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
657 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
659 return KSAUDIO_SPEAKER_7POINT1; /* not 7POINT1_SURROUND */
661 FIXME("Unknown speaker configuration: %u\n", channels);
665 static int get_oss_format(const WAVEFORMATEX *fmt)
667 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
669 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
670 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
671 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
672 switch(fmt->wBitsPerSample){
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)
699 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
704 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
705 size = sizeof(WAVEFORMATEXTENSIBLE);
707 size = sizeof(WAVEFORMATEX);
709 ret = CoTaskMemAlloc(size);
713 memcpy(ret, fmt, size);
715 ret->cbSize = size - sizeof(WAVEFORMATEX);
720 static HRESULT setup_oss_device(int fd, const WAVEFORMATEX *fmt,
721 WAVEFORMATEX **out, BOOL query)
726 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
727 WAVEFORMATEX *closest = NULL;
729 tmp = oss_format = get_oss_format(fmt);
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));
736 if(tmp != oss_format){
737 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
738 return AUDCLNT_E_UNSUPPORTED_FORMAT;
741 closest = clone_format(fmt);
743 return E_OUTOFMEMORY;
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);
751 tenth = fmt->nSamplesPerSec * 0.1;
752 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
754 closest->nSamplesPerSec = tmp;
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);
763 if(tmp != fmt->nChannels){
765 closest->nChannels = tmp;
768 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
769 DWORD mask = get_channel_mask(closest->nChannels);
771 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
773 if(query && fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
774 fmtex->dwChannelMask != 0 &&
775 fmtex->dwChannelMask != mask)
779 if(ret == S_FALSE && !out)
780 ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
782 if(ret == S_FALSE && out){
783 closest->nBlockAlign =
784 closest->nChannels * closest->wBitsPerSample / 8;
785 closest->nAvgBytesPerSec =
786 closest->nBlockAlign * closest->nSamplesPerSec;
789 CoTaskMemFree(closest);
791 TRACE("returning: %08x\n", ret);
795 static void session_init_vols(AudioSession *session, UINT channels)
797 if(session->channel_count < channels){
800 if(session->channel_vols)
801 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
802 session->channel_vols, sizeof(float) * channels);
804 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
805 sizeof(float) * channels);
806 if(!session->channel_vols)
809 for(i = session->channel_count; i < channels; ++i)
810 session->channel_vols[i] = 1.f;
812 session->channel_count = channels;
816 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
821 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
825 memcpy(&ret->guid, guid, sizeof(GUID));
827 ret->device = device;
829 list_init(&ret->clients);
831 list_add_head(&g_sessions, &ret->entry);
833 InitializeCriticalSection(&ret->lock);
834 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
836 session_init_vols(ret, num_channels);
838 ret->master_vol = 1.f;
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)
848 AudioSession *session;
850 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
851 *out = create_session(&GUID_NULL, device, channels);
853 return E_OUTOFMEMORY;
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);
869 *out = create_session(sessionguid, device, channels);
871 return E_OUTOFMEMORY;
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)
882 ACImpl *This = impl_from_IAudioClient(iface);
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));
894 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
895 return AUDCLNT_E_NOT_INITIALIZED;
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);
909 if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE && flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
910 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
911 return AUDCLNT_E_DEVICE_IN_USE;
914 EnterCriticalSection(&This->lock);
917 LeaveCriticalSection(&This->lock);
918 return AUDCLNT_E_ALREADY_INITIALIZED;
921 hr = setup_oss_device(This->fd, fmt, NULL, FALSE);
923 LeaveCriticalSection(&This->lock);
928 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
929 LeaveCriticalSection(&This->lock);
930 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
934 mask = (100 << 8) | 100;
935 if(ioctl(This->fd, SNDCTL_DSP_SETPLAYVOL, &mask) < 0)
936 WARN("SETPLAYVOL failed: %d (%s)\n", errno, strerror(errno));
938 This->fmt = clone_format(fmt);
940 LeaveCriticalSection(&This->lock);
941 return E_OUTOFMEMORY;
945 This->period_us = period / 10;
947 This->period_us = DefaultPeriod / 10;
950 duration = 300000; /* 0.03s */
951 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
952 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
953 This->bufsize_frames * fmt->nBlockAlign);
954 if(!This->local_buffer){
955 CoTaskMemFree(This->fmt);
957 LeaveCriticalSection(&This->lock);
958 return E_OUTOFMEMORY;
961 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
963 CoTaskMemFree(This->fmt);
965 LeaveCriticalSection(&This->lock);
966 return E_OUTOFMEMORY;
969 for(i = 0; i < fmt->nChannels; ++i)
975 EnterCriticalSection(&g_sessions_lock);
977 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
980 LeaveCriticalSection(&g_sessions_lock);
981 HeapFree(GetProcessHeap(), 0, This->vols);
983 CoTaskMemFree(This->fmt);
985 LeaveCriticalSection(&This->lock);
989 list_add_tail(&This->session->clients, &This->entry);
991 LeaveCriticalSection(&g_sessions_lock);
993 This->initted = TRUE;
995 LeaveCriticalSection(&This->lock);
1000 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1003 ACImpl *This = impl_from_IAudioClient(iface);
1005 TRACE("(%p)->(%p)\n", This, frames);
1010 EnterCriticalSection(&This->lock);
1013 LeaveCriticalSection(&This->lock);
1014 return AUDCLNT_E_NOT_INITIALIZED;
1017 *frames = This->bufsize_frames;
1019 LeaveCriticalSection(&This->lock);
1024 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1025 REFERENCE_TIME *latency)
1027 ACImpl *This = impl_from_IAudioClient(iface);
1029 TRACE("(%p)->(%p)\n", This, latency);
1034 EnterCriticalSection(&This->lock);
1037 LeaveCriticalSection(&This->lock);
1038 return AUDCLNT_E_NOT_INITIALIZED;
1041 if(This->dataflow == eRender){
1045 if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
1046 LeaveCriticalSection(&This->lock);
1047 WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
1051 delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
1052 This->fmt->nBlockAlign);
1054 *latency = delay_s * 10000000;
1056 *latency = 10000; /* OSS doesn't provide input latency */
1058 /* pretend we process audio in Period chunks, so max latency includes
1059 * the period time */
1060 *latency += DefaultPeriod;
1062 LeaveCriticalSection(&This->lock);
1067 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1070 ACImpl *This = impl_from_IAudioClient(iface);
1073 TRACE("(%p)->(%p)\n", This, numpad);
1078 EnterCriticalSection(&This->lock);
1081 LeaveCriticalSection(&This->lock);
1082 return AUDCLNT_E_NOT_INITIALIZED;
1085 if(This->dataflow == eRender){
1086 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1087 LeaveCriticalSection(&This->lock);
1088 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1092 *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
1093 This->fmt->nBlockAlign;
1095 /* when the OSS buffer has less than one fragment of data, including
1096 * no data, it often reports it as some non-zero portion of a
1097 * fragment. when it has more than one fragment of data, it reports
1098 * it as some multiple of that portion of the fragment size.
1100 * so, we have to do some ugly workarounds to report the timing
1101 * as accurately as possible */
1102 if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
1103 *numpad = This->inbuf_frames;
1104 This->inbuf_frames = 0;
1106 if(*numpad < This->inbuf_frames)
1107 This->inbuf_frames = *numpad;
1109 *numpad = This->inbuf_frames;
1111 }else if(This->dataflow == eCapture){
1112 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1113 LeaveCriticalSection(&This->lock);
1114 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1118 if(bi.bytes <= bi.fragsize)
1121 *numpad = bi.bytes / This->fmt->nBlockAlign;
1123 LeaveCriticalSection(&This->lock);
1124 return E_UNEXPECTED;
1127 *numpad += This->held_frames;
1129 LeaveCriticalSection(&This->lock);
1134 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1135 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1136 WAVEFORMATEX **outpwfx)
1138 ACImpl *This = impl_from_IAudioClient(iface);
1142 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1144 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1147 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1148 return E_INVALIDARG;
1150 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1151 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1152 return E_INVALIDARG;
1158 if(mode != AUDCLNT_SHAREMODE_SHARED)
1162 if(This->dataflow == eRender)
1163 fd = open(This->devnode, O_WRONLY, 0);
1164 else if(This->dataflow == eCapture)
1165 fd = open(This->devnode, O_RDONLY, 0);
1168 ERR("Unable to open device %s: %d (%s)\n", This->devnode, errno,
1170 return AUDCLNT_E_DEVICE_INVALIDATED;
1173 ret = setup_oss_device(fd, pwfx, outpwfx, TRUE);
1180 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1181 WAVEFORMATEX **pwfx)
1183 ACImpl *This = impl_from_IAudioClient(iface);
1184 WAVEFORMATEXTENSIBLE *fmt;
1187 TRACE("(%p)->(%p)\n", This, pwfx);
1193 if(This->dataflow == eRender)
1194 formats = This->ai.oformats;
1195 else if(This->dataflow == eCapture)
1196 formats = This->ai.iformats;
1198 return E_UNEXPECTED;
1200 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1202 return E_OUTOFMEMORY;
1204 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1205 if(formats & AFMT_S16_LE){
1206 fmt->Format.wBitsPerSample = 16;
1207 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1209 }else if(formats & AFMT_FLOAT){
1210 fmt->Format.wBitsPerSample = 32;
1211 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1213 }else if(formats & AFMT_U8){
1214 fmt->Format.wBitsPerSample = 8;
1215 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1216 }else if(formats & AFMT_S32_LE){
1217 fmt->Format.wBitsPerSample = 32;
1218 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1219 }else if(formats & AFMT_S24_LE){
1220 fmt->Format.wBitsPerSample = 24;
1221 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1223 ERR("Didn't recognize any available OSS formats: %x\n", formats);
1228 fmt->Format.nChannels = This->ai.max_channels;
1229 fmt->Format.nSamplesPerSec = This->ai.max_rate;
1230 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1232 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1233 fmt->Format.nChannels) / 8;
1234 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1235 fmt->Format.nBlockAlign;
1237 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1238 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1240 *pwfx = (WAVEFORMATEX*)fmt;
1246 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1247 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1249 ACImpl *This = impl_from_IAudioClient(iface);
1251 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1253 if(!defperiod && !minperiod)
1256 EnterCriticalSection(&This->lock);
1259 *defperiod = DefaultPeriod;
1261 *minperiod = MinimumPeriod;
1263 LeaveCriticalSection(&This->lock);
1268 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1270 if(This->fmt->wBitsPerSample == 8)
1271 memset(buf, 128, frames * This->fmt->nBlockAlign);
1273 memset(buf, 0, frames * This->fmt->nBlockAlign);
1276 static void oss_write_data(ACImpl *This)
1278 ssize_t written_bytes;
1279 UINT32 written_frames;
1280 size_t to_write_frames, to_write_bytes;
1283 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1285 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1286 to_write_frames = This->bufsize_frames - This->lcl_offs_frames;
1288 to_write_frames = This->held_frames;
1289 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1291 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1292 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1296 if(bi.bytes < to_write_bytes){
1297 to_write_frames = bi.bytes / This->fmt->nBlockAlign;
1298 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1301 if(This->session->mute)
1302 oss_silence_buffer(This, buf, to_write_frames);
1304 written_bytes = write(This->fd, buf, to_write_bytes);
1305 if(written_bytes < 0){
1306 /* EAGAIN is OSS buffer full, log that too */
1307 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1310 written_frames = written_bytes / This->fmt->nBlockAlign;
1312 This->lcl_offs_frames += written_frames;
1313 This->lcl_offs_frames %= This->bufsize_frames;
1314 This->held_frames -= written_frames;
1315 This->inbuf_frames += written_frames;
1317 if(written_frames < to_write_frames){
1318 /* OSS buffer probably full */
1322 bi.bytes -= written_bytes;
1323 if(This->held_frames && bi.bytes >= This->fmt->nBlockAlign){
1324 /* wrapped and have some data back at the start to write */
1326 to_write_frames = bi.bytes / This->fmt->nBlockAlign;
1327 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1329 if(This->session->mute)
1330 oss_silence_buffer(This, This->local_buffer, to_write_frames);
1332 written_bytes = write(This->fd, This->local_buffer, to_write_bytes);
1333 if(written_bytes < 0){
1334 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1337 written_frames = written_bytes / This->fmt->nBlockAlign;
1339 This->lcl_offs_frames += written_frames;
1340 This->lcl_offs_frames %= This->bufsize_frames;
1341 This->held_frames -= written_frames;
1342 This->inbuf_frames += written_frames;
1346 static void oss_read_data(ACImpl *This)
1348 UINT64 pos, readable;
1352 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1353 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1357 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1358 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1360 if(bi.bytes < readable)
1361 readable = bi.bytes;
1363 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1366 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1370 This->held_frames += nread / This->fmt->nBlockAlign;
1372 if(This->held_frames > This->bufsize_frames){
1373 WARN("Overflow of unread data\n");
1374 This->lcl_offs_frames += This->held_frames;
1375 This->lcl_offs_frames %= This->bufsize_frames;
1376 This->held_frames = This->bufsize_frames;
1380 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1382 ACImpl *This = user;
1384 EnterCriticalSection(&This->lock);
1386 if(This->dataflow == eRender && This->held_frames)
1387 oss_write_data(This);
1388 else if(This->dataflow == eCapture)
1389 oss_read_data(This);
1392 SetEvent(This->event);
1394 LeaveCriticalSection(&This->lock);
1397 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1399 ACImpl *This = impl_from_IAudioClient(iface);
1402 TRACE("(%p)\n", This);
1404 EnterCriticalSection(&This->lock);
1407 LeaveCriticalSection(&This->lock);
1408 return AUDCLNT_E_NOT_INITIALIZED;
1411 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1412 LeaveCriticalSection(&This->lock);
1413 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1417 LeaveCriticalSection(&This->lock);
1418 return AUDCLNT_E_NOT_STOPPED;
1421 if(This->dataflow == eRender)
1422 mask = PCM_ENABLE_OUTPUT;
1423 else if(This->dataflow == eCapture)
1424 mask = PCM_ENABLE_INPUT;
1426 LeaveCriticalSection(&This->lock);
1427 return E_UNEXPECTED;
1430 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1431 LeaveCriticalSection(&This->lock);
1432 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1436 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1437 oss_period_callback, This, 0, This->period_us / 1000,
1438 WT_EXECUTEINTIMERTHREAD))
1439 ERR("Unable to create period timer: %u\n", GetLastError());
1441 This->playing = TRUE;
1443 LeaveCriticalSection(&This->lock);
1448 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1450 ACImpl *This = impl_from_IAudioClient(iface);
1453 TRACE("(%p)\n", This);
1455 EnterCriticalSection(&This->lock);
1458 LeaveCriticalSection(&This->lock);
1459 return AUDCLNT_E_NOT_INITIALIZED;
1463 LeaveCriticalSection(&This->lock);
1467 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1468 DeleteTimerQueueTimer(g_timer_q, This->timer,
1469 INVALID_HANDLE_VALUE);
1473 if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1474 LeaveCriticalSection(&This->lock);
1475 WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1480 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1481 LeaveCriticalSection(&This->lock);
1482 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1486 This->playing = FALSE;
1488 LeaveCriticalSection(&This->lock);
1493 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1495 ACImpl *This = impl_from_IAudioClient(iface);
1497 TRACE("(%p)\n", This);
1499 EnterCriticalSection(&This->lock);
1502 LeaveCriticalSection(&This->lock);
1503 return AUDCLNT_E_NOT_INITIALIZED;
1507 LeaveCriticalSection(&This->lock);
1508 return AUDCLNT_E_NOT_STOPPED;
1511 if(This->buf_state != NOT_LOCKED){
1512 LeaveCriticalSection(&This->lock);
1513 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1516 This->written_frames = 0;
1517 This->inbuf_frames = 0;
1518 This->held_frames = 0;
1520 if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1521 WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1523 LeaveCriticalSection(&This->lock);
1528 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1531 ACImpl *This = impl_from_IAudioClient(iface);
1533 TRACE("(%p)->(%p)\n", This, event);
1536 return E_INVALIDARG;
1538 EnterCriticalSection(&This->lock);
1541 LeaveCriticalSection(&This->lock);
1542 return AUDCLNT_E_NOT_INITIALIZED;
1545 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1546 LeaveCriticalSection(&This->lock);
1547 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1550 This->event = event;
1552 LeaveCriticalSection(&This->lock);
1557 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1560 ACImpl *This = impl_from_IAudioClient(iface);
1562 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1568 EnterCriticalSection(&This->lock);
1571 LeaveCriticalSection(&This->lock);
1572 return AUDCLNT_E_NOT_INITIALIZED;
1575 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1576 if(This->dataflow != eRender){
1577 LeaveCriticalSection(&This->lock);
1578 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1580 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1581 *ppv = &This->IAudioRenderClient_iface;
1582 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1583 if(This->dataflow != eCapture){
1584 LeaveCriticalSection(&This->lock);
1585 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1587 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1588 *ppv = &This->IAudioCaptureClient_iface;
1589 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1590 IAudioClock_AddRef(&This->IAudioClock_iface);
1591 *ppv = &This->IAudioClock_iface;
1592 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1593 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1594 *ppv = &This->IAudioStreamVolume_iface;
1595 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1596 if(!This->session_wrapper){
1597 This->session_wrapper = AudioSessionWrapper_Create(This);
1598 if(!This->session_wrapper){
1599 LeaveCriticalSection(&This->lock);
1600 return E_OUTOFMEMORY;
1603 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1605 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1606 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1607 if(!This->session_wrapper){
1608 This->session_wrapper = AudioSessionWrapper_Create(This);
1609 if(!This->session_wrapper){
1610 LeaveCriticalSection(&This->lock);
1611 return E_OUTOFMEMORY;
1614 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1616 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1617 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1618 if(!This->session_wrapper){
1619 This->session_wrapper = AudioSessionWrapper_Create(This);
1620 if(!This->session_wrapper){
1621 LeaveCriticalSection(&This->lock);
1622 return E_OUTOFMEMORY;
1625 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1627 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1631 LeaveCriticalSection(&This->lock);
1635 LeaveCriticalSection(&This->lock);
1637 FIXME("stub %s\n", debugstr_guid(riid));
1638 return E_NOINTERFACE;
1641 static const IAudioClientVtbl AudioClient_Vtbl =
1643 AudioClient_QueryInterface,
1645 AudioClient_Release,
1646 AudioClient_Initialize,
1647 AudioClient_GetBufferSize,
1648 AudioClient_GetStreamLatency,
1649 AudioClient_GetCurrentPadding,
1650 AudioClient_IsFormatSupported,
1651 AudioClient_GetMixFormat,
1652 AudioClient_GetDevicePeriod,
1656 AudioClient_SetEventHandle,
1657 AudioClient_GetService
1660 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1661 IAudioRenderClient *iface, REFIID riid, void **ppv)
1663 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1669 if(IsEqualIID(riid, &IID_IUnknown) ||
1670 IsEqualIID(riid, &IID_IAudioRenderClient))
1673 IUnknown_AddRef((IUnknown*)*ppv);
1677 WARN("Unknown interface %s\n", debugstr_guid(riid));
1678 return E_NOINTERFACE;
1681 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1683 ACImpl *This = impl_from_IAudioRenderClient(iface);
1684 return AudioClient_AddRef(&This->IAudioClient_iface);
1687 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1689 ACImpl *This = impl_from_IAudioRenderClient(iface);
1690 return AudioClient_Release(&This->IAudioClient_iface);
1693 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1694 UINT32 frames, BYTE **data)
1696 ACImpl *This = impl_from_IAudioRenderClient(iface);
1697 UINT32 pad, write_pos;
1700 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1705 EnterCriticalSection(&This->lock);
1707 if(This->buf_state != NOT_LOCKED){
1708 LeaveCriticalSection(&This->lock);
1709 return AUDCLNT_E_OUT_OF_ORDER;
1713 This->buf_state = LOCKED_NORMAL;
1714 LeaveCriticalSection(&This->lock);
1718 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1720 LeaveCriticalSection(&This->lock);
1724 if(pad + frames > This->bufsize_frames){
1725 LeaveCriticalSection(&This->lock);
1726 return AUDCLNT_E_BUFFER_TOO_LARGE;
1730 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1731 if(write_pos + frames > This->bufsize_frames){
1732 if(This->tmp_buffer_frames < frames){
1733 if(This->tmp_buffer)
1734 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1735 This->tmp_buffer, frames * This->fmt->nBlockAlign);
1737 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1738 frames * This->fmt->nBlockAlign);
1739 if(!This->tmp_buffer){
1740 LeaveCriticalSection(&This->lock);
1741 return E_OUTOFMEMORY;
1743 This->tmp_buffer_frames = frames;
1745 *data = This->tmp_buffer;
1746 This->buf_state = LOCKED_WRAPPED;
1748 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1749 This->buf_state = LOCKED_NORMAL;
1752 LeaveCriticalSection(&This->lock);
1757 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1759 UINT32 write_offs_frames =
1760 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1761 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1762 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1763 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1764 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1766 if(written_bytes <= chunk_bytes){
1767 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1769 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1770 memcpy(This->local_buffer, buffer + chunk_bytes,
1771 written_bytes - chunk_bytes);
1775 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1776 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1778 ACImpl *This = impl_from_IAudioRenderClient(iface);
1781 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1783 EnterCriticalSection(&This->lock);
1785 if(This->buf_state == NOT_LOCKED || !written_frames){
1786 This->buf_state = NOT_LOCKED;
1787 LeaveCriticalSection(&This->lock);
1788 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1791 if(This->buf_state == LOCKED_NORMAL)
1792 buffer = This->local_buffer + This->fmt->nBlockAlign *
1793 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1795 buffer = This->tmp_buffer;
1797 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1798 oss_silence_buffer(This, buffer, written_frames);
1800 if(This->held_frames){
1801 if(This->buf_state == LOCKED_WRAPPED)
1802 oss_wrap_buffer(This, buffer, written_frames);
1804 This->held_frames += written_frames;
1809 if(This->session->mute)
1810 oss_silence_buffer(This, buffer, written_frames);
1812 w_bytes = write(This->fd, buffer,
1813 written_frames * This->fmt->nBlockAlign);
1815 if(errno != EAGAIN){
1816 This->buf_state = NOT_LOCKED;
1817 LeaveCriticalSection(&This->lock);
1818 ERR("write failed: %d (%s)\n", errno, strerror(errno));
1820 }else /* OSS buffer full */
1823 w_frames = w_bytes / This->fmt->nBlockAlign;
1824 This->inbuf_frames += w_frames;
1826 if(w_frames < written_frames){
1827 if(This->buf_state == LOCKED_WRAPPED)
1828 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1829 written_frames - w_frames);
1831 This->lcl_offs_frames += w_frames;
1832 This->held_frames = written_frames - w_frames;
1836 This->written_frames += written_frames;
1837 This->buf_state = NOT_LOCKED;
1839 LeaveCriticalSection(&This->lock);
1844 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1845 AudioRenderClient_QueryInterface,
1846 AudioRenderClient_AddRef,
1847 AudioRenderClient_Release,
1848 AudioRenderClient_GetBuffer,
1849 AudioRenderClient_ReleaseBuffer
1852 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1853 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1855 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1861 if(IsEqualIID(riid, &IID_IUnknown) ||
1862 IsEqualIID(riid, &IID_IAudioCaptureClient))
1865 IUnknown_AddRef((IUnknown*)*ppv);
1869 WARN("Unknown interface %s\n", debugstr_guid(riid));
1870 return E_NOINTERFACE;
1873 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1875 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1876 return IAudioClient_AddRef(&This->IAudioClient_iface);
1879 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1881 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1882 return IAudioClient_Release(&This->IAudioClient_iface);
1885 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1886 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1889 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1892 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1895 if(!data || !frames || !flags)
1898 EnterCriticalSection(&This->lock);
1900 if(This->buf_state != NOT_LOCKED){
1901 LeaveCriticalSection(&This->lock);
1902 return AUDCLNT_E_OUT_OF_ORDER;
1905 hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1907 LeaveCriticalSection(&This->lock);
1913 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1914 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1915 if(This->tmp_buffer_frames < *frames){
1916 if(This->tmp_buffer)
1917 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1918 This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1920 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1921 *frames * This->fmt->nBlockAlign);
1922 if(!This->tmp_buffer){
1923 LeaveCriticalSection(&This->lock);
1924 return E_OUTOFMEMORY;
1926 This->tmp_buffer_frames = *frames;
1929 *data = This->tmp_buffer;
1930 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1931 This->fmt->nBlockAlign;
1932 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1933 frames_bytes = *frames * This->fmt->nBlockAlign;
1934 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1935 memcpy(This->tmp_buffer, This->local_buffer,
1936 frames_bytes - chunk_bytes);
1938 *data = This->local_buffer +
1939 This->lcl_offs_frames * This->fmt->nBlockAlign;
1941 This->buf_state = LOCKED_NORMAL;
1943 if(devpos || qpcpos)
1944 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1946 LeaveCriticalSection(&This->lock);
1948 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1951 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1952 IAudioCaptureClient *iface, UINT32 done)
1954 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1956 TRACE("(%p)->(%u)\n", This, done);
1958 EnterCriticalSection(&This->lock);
1960 if(This->buf_state == NOT_LOCKED){
1961 LeaveCriticalSection(&This->lock);
1962 return AUDCLNT_E_OUT_OF_ORDER;
1965 This->held_frames -= done;
1966 This->lcl_offs_frames += done;
1967 This->lcl_offs_frames %= This->bufsize_frames;
1969 This->buf_state = NOT_LOCKED;
1971 LeaveCriticalSection(&This->lock);
1976 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1977 IAudioCaptureClient *iface, UINT32 *frames)
1979 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1981 TRACE("(%p)->(%p)\n", This, frames);
1983 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1986 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1988 AudioCaptureClient_QueryInterface,
1989 AudioCaptureClient_AddRef,
1990 AudioCaptureClient_Release,
1991 AudioCaptureClient_GetBuffer,
1992 AudioCaptureClient_ReleaseBuffer,
1993 AudioCaptureClient_GetNextPacketSize
1996 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1997 REFIID riid, void **ppv)
1999 ACImpl *This = impl_from_IAudioClock(iface);
2001 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2007 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2009 else if(IsEqualIID(riid, &IID_IAudioClock2))
2010 *ppv = &This->IAudioClock2_iface;
2012 IUnknown_AddRef((IUnknown*)*ppv);
2016 WARN("Unknown interface %s\n", debugstr_guid(riid));
2017 return E_NOINTERFACE;
2020 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2022 ACImpl *This = impl_from_IAudioClock(iface);
2023 return IAudioClient_AddRef(&This->IAudioClient_iface);
2026 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2028 ACImpl *This = impl_from_IAudioClock(iface);
2029 return IAudioClient_Release(&This->IAudioClient_iface);
2032 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2034 ACImpl *This = impl_from_IAudioClock(iface);
2036 TRACE("(%p)->(%p)\n", This, freq);
2038 *freq = This->fmt->nSamplesPerSec;
2043 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2046 ACImpl *This = impl_from_IAudioClock(iface);
2050 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2055 EnterCriticalSection(&This->lock);
2057 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
2059 LeaveCriticalSection(&This->lock);
2063 if(This->dataflow == eRender)
2064 *pos = This->written_frames - pad;
2065 else if(This->dataflow == eCapture)
2066 *pos = This->written_frames + pad;
2068 LeaveCriticalSection(&This->lock);
2071 LARGE_INTEGER stamp, freq;
2072 QueryPerformanceCounter(&stamp);
2073 QueryPerformanceFrequency(&freq);
2074 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2080 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2083 ACImpl *This = impl_from_IAudioClock(iface);
2085 TRACE("(%p)->(%p)\n", This, chars);
2090 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2095 static const IAudioClockVtbl AudioClock_Vtbl =
2097 AudioClock_QueryInterface,
2100 AudioClock_GetFrequency,
2101 AudioClock_GetPosition,
2102 AudioClock_GetCharacteristics
2105 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2106 REFIID riid, void **ppv)
2108 ACImpl *This = impl_from_IAudioClock2(iface);
2109 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2112 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2114 ACImpl *This = impl_from_IAudioClock2(iface);
2115 return IAudioClient_AddRef(&This->IAudioClient_iface);
2118 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2120 ACImpl *This = impl_from_IAudioClock2(iface);
2121 return IAudioClient_Release(&This->IAudioClient_iface);
2124 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2125 UINT64 *pos, UINT64 *qpctime)
2127 ACImpl *This = impl_from_IAudioClock2(iface);
2129 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2134 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2136 AudioClock2_QueryInterface,
2138 AudioClock2_Release,
2139 AudioClock2_GetDevicePosition
2142 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2144 AudioSessionWrapper *ret;
2146 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2147 sizeof(AudioSessionWrapper));
2151 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2152 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2153 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2157 ret->client = client;
2159 ret->session = client->session;
2160 AudioClient_AddRef(&client->IAudioClient_iface);
2166 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2167 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2169 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2175 if(IsEqualIID(riid, &IID_IUnknown) ||
2176 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2177 IsEqualIID(riid, &IID_IAudioSessionControl2))
2180 IUnknown_AddRef((IUnknown*)*ppv);
2184 WARN("Unknown interface %s\n", debugstr_guid(riid));
2185 return E_NOINTERFACE;
2188 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2190 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2192 ref = InterlockedIncrement(&This->ref);
2193 TRACE("(%p) Refcount now %u\n", This, ref);
2197 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2199 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2201 ref = InterlockedDecrement(&This->ref);
2202 TRACE("(%p) Refcount now %u\n", This, ref);
2205 EnterCriticalSection(&This->client->lock);
2206 This->client->session_wrapper = NULL;
2207 LeaveCriticalSection(&This->client->lock);
2208 AudioClient_Release(&This->client->IAudioClient_iface);
2210 HeapFree(GetProcessHeap(), 0, This);
2215 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2216 AudioSessionState *state)
2218 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2221 TRACE("(%p)->(%p)\n", This, state);
2224 return NULL_PTR_ERR;
2226 EnterCriticalSection(&g_sessions_lock);
2228 if(list_empty(&This->session->clients)){
2229 *state = AudioSessionStateExpired;
2230 LeaveCriticalSection(&g_sessions_lock);
2234 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2235 EnterCriticalSection(&client->lock);
2236 if(client->playing){
2237 *state = AudioSessionStateActive;
2238 LeaveCriticalSection(&client->lock);
2239 LeaveCriticalSection(&g_sessions_lock);
2242 LeaveCriticalSection(&client->lock);
2245 LeaveCriticalSection(&g_sessions_lock);
2247 *state = AudioSessionStateInactive;
2252 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2253 IAudioSessionControl2 *iface, WCHAR **name)
2255 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2257 FIXME("(%p)->(%p) - stub\n", This, name);
2262 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2263 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2265 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2267 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2272 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2273 IAudioSessionControl2 *iface, WCHAR **path)
2275 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2277 FIXME("(%p)->(%p) - stub\n", This, path);
2282 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2283 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2285 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2287 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2292 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2293 IAudioSessionControl2 *iface, GUID *group)
2295 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2297 FIXME("(%p)->(%p) - stub\n", This, group);
2302 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2303 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2305 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2307 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2308 debugstr_guid(session));
2313 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2314 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2316 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2318 FIXME("(%p)->(%p) - stub\n", This, events);
2323 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2324 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2326 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2328 FIXME("(%p)->(%p) - stub\n", This, events);
2333 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2334 IAudioSessionControl2 *iface, WCHAR **id)
2336 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2338 FIXME("(%p)->(%p) - stub\n", This, id);
2343 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2344 IAudioSessionControl2 *iface, WCHAR **id)
2346 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2348 FIXME("(%p)->(%p) - stub\n", This, id);
2353 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2354 IAudioSessionControl2 *iface, DWORD *pid)
2356 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2358 TRACE("(%p)->(%p)\n", This, pid);
2363 *pid = GetCurrentProcessId();
2368 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2369 IAudioSessionControl2 *iface)
2371 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2373 TRACE("(%p)\n", This);
2378 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2379 IAudioSessionControl2 *iface, BOOL optout)
2381 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2383 TRACE("(%p)->(%d)\n", This, optout);
2388 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2390 AudioSessionControl_QueryInterface,
2391 AudioSessionControl_AddRef,
2392 AudioSessionControl_Release,
2393 AudioSessionControl_GetState,
2394 AudioSessionControl_GetDisplayName,
2395 AudioSessionControl_SetDisplayName,
2396 AudioSessionControl_GetIconPath,
2397 AudioSessionControl_SetIconPath,
2398 AudioSessionControl_GetGroupingParam,
2399 AudioSessionControl_SetGroupingParam,
2400 AudioSessionControl_RegisterAudioSessionNotification,
2401 AudioSessionControl_UnregisterAudioSessionNotification,
2402 AudioSessionControl_GetSessionIdentifier,
2403 AudioSessionControl_GetSessionInstanceIdentifier,
2404 AudioSessionControl_GetProcessId,
2405 AudioSessionControl_IsSystemSoundsSession,
2406 AudioSessionControl_SetDuckingPreference
2409 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2410 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2412 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2418 if(IsEqualIID(riid, &IID_IUnknown) ||
2419 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2422 IUnknown_AddRef((IUnknown*)*ppv);
2426 WARN("Unknown interface %s\n", debugstr_guid(riid));
2427 return E_NOINTERFACE;
2430 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2432 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2433 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2436 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2438 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2439 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2442 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2443 ISimpleAudioVolume *iface, float level, const GUID *context)
2445 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2446 AudioSession *session = This->session;
2448 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2450 if(level < 0.f || level > 1.f)
2451 return E_INVALIDARG;
2454 FIXME("Notifications not supported yet\n");
2456 EnterCriticalSection(&session->lock);
2458 session->master_vol = level;
2460 TRACE("OSS doesn't support setting volume\n");
2462 LeaveCriticalSection(&session->lock);
2467 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2468 ISimpleAudioVolume *iface, float *level)
2470 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2471 AudioSession *session = This->session;
2473 TRACE("(%p)->(%p)\n", session, level);
2476 return NULL_PTR_ERR;
2478 *level = session->master_vol;
2483 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2484 BOOL mute, const GUID *context)
2486 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2487 AudioSession *session = This->session;
2489 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2491 EnterCriticalSection(&session->lock);
2493 if(!mute && session->mute){
2496 session->mute = mute;
2498 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2499 EnterCriticalSection(&client->lock);
2500 if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2501 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2503 oss_write_data(client);
2504 LeaveCriticalSection(&client->lock);
2507 session->mute = mute;
2509 LeaveCriticalSection(&session->lock);
2514 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2517 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2518 AudioSession *session = This->session;
2520 TRACE("(%p)->(%p)\n", session, mute);
2523 return NULL_PTR_ERR;
2525 *mute = This->session->mute;
2530 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2532 SimpleAudioVolume_QueryInterface,
2533 SimpleAudioVolume_AddRef,
2534 SimpleAudioVolume_Release,
2535 SimpleAudioVolume_SetMasterVolume,
2536 SimpleAudioVolume_GetMasterVolume,
2537 SimpleAudioVolume_SetMute,
2538 SimpleAudioVolume_GetMute
2541 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2542 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2544 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2550 if(IsEqualIID(riid, &IID_IUnknown) ||
2551 IsEqualIID(riid, &IID_IAudioStreamVolume))
2554 IUnknown_AddRef((IUnknown*)*ppv);
2558 WARN("Unknown interface %s\n", debugstr_guid(riid));
2559 return E_NOINTERFACE;
2562 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2564 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2565 return IAudioClient_AddRef(&This->IAudioClient_iface);
2568 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2570 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2571 return IAudioClient_Release(&This->IAudioClient_iface);
2574 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2575 IAudioStreamVolume *iface, UINT32 *out)
2577 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2579 TRACE("(%p)->(%p)\n", This, out);
2584 *out = This->fmt->nChannels;
2589 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2590 IAudioStreamVolume *iface, UINT32 index, float level)
2592 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2594 TRACE("(%p)->(%d, %f)\n", This, index, level);
2596 if(level < 0.f || level > 1.f)
2597 return E_INVALIDARG;
2599 if(index >= This->fmt->nChannels)
2600 return E_INVALIDARG;
2602 EnterCriticalSection(&This->lock);
2604 This->vols[index] = level;
2606 TRACE("OSS doesn't support setting volume\n");
2608 LeaveCriticalSection(&This->lock);
2613 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2614 IAudioStreamVolume *iface, UINT32 index, float *level)
2616 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2618 TRACE("(%p)->(%d, %p)\n", This, index, level);
2623 if(index >= This->fmt->nChannels)
2624 return E_INVALIDARG;
2626 *level = This->vols[index];
2631 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2632 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2634 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2637 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2642 if(count != This->fmt->nChannels)
2643 return E_INVALIDARG;
2645 EnterCriticalSection(&This->lock);
2647 for(i = 0; i < count; ++i)
2648 This->vols[i] = levels[i];
2650 TRACE("OSS doesn't support setting volume\n");
2652 LeaveCriticalSection(&This->lock);
2657 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2658 IAudioStreamVolume *iface, UINT32 count, float *levels)
2660 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2663 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2668 if(count != This->fmt->nChannels)
2669 return E_INVALIDARG;
2671 EnterCriticalSection(&This->lock);
2673 for(i = 0; i < count; ++i)
2674 levels[i] = This->vols[i];
2676 LeaveCriticalSection(&This->lock);
2681 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2683 AudioStreamVolume_QueryInterface,
2684 AudioStreamVolume_AddRef,
2685 AudioStreamVolume_Release,
2686 AudioStreamVolume_GetChannelCount,
2687 AudioStreamVolume_SetChannelVolume,
2688 AudioStreamVolume_GetChannelVolume,
2689 AudioStreamVolume_SetAllVolumes,
2690 AudioStreamVolume_GetAllVolumes
2693 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2694 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2696 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2702 if(IsEqualIID(riid, &IID_IUnknown) ||
2703 IsEqualIID(riid, &IID_IChannelAudioVolume))
2706 IUnknown_AddRef((IUnknown*)*ppv);
2710 WARN("Unknown interface %s\n", debugstr_guid(riid));
2711 return E_NOINTERFACE;
2714 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2716 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2717 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2720 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2722 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2723 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2726 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2727 IChannelAudioVolume *iface, UINT32 *out)
2729 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2730 AudioSession *session = This->session;
2732 TRACE("(%p)->(%p)\n", session, out);
2735 return NULL_PTR_ERR;
2737 *out = session->channel_count;
2742 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2743 IChannelAudioVolume *iface, UINT32 index, float level,
2744 const GUID *context)
2746 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2747 AudioSession *session = This->session;
2749 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2750 wine_dbgstr_guid(context));
2752 if(level < 0.f || level > 1.f)
2753 return E_INVALIDARG;
2755 if(index >= session->channel_count)
2756 return E_INVALIDARG;
2759 FIXME("Notifications not supported yet\n");
2761 EnterCriticalSection(&session->lock);
2763 session->channel_vols[index] = level;
2765 TRACE("OSS doesn't support setting volume\n");
2767 LeaveCriticalSection(&session->lock);
2772 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2773 IChannelAudioVolume *iface, UINT32 index, float *level)
2775 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2776 AudioSession *session = This->session;
2778 TRACE("(%p)->(%d, %p)\n", session, index, level);
2781 return NULL_PTR_ERR;
2783 if(index >= session->channel_count)
2784 return E_INVALIDARG;
2786 *level = session->channel_vols[index];
2791 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2792 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2793 const GUID *context)
2795 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2796 AudioSession *session = This->session;
2799 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2800 wine_dbgstr_guid(context));
2803 return NULL_PTR_ERR;
2805 if(count != session->channel_count)
2806 return E_INVALIDARG;
2809 FIXME("Notifications not supported yet\n");
2811 EnterCriticalSection(&session->lock);
2813 for(i = 0; i < count; ++i)
2814 session->channel_vols[i] = levels[i];
2816 TRACE("OSS doesn't support setting volume\n");
2818 LeaveCriticalSection(&session->lock);
2823 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2824 IChannelAudioVolume *iface, UINT32 count, float *levels)
2826 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2827 AudioSession *session = This->session;
2830 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2833 return NULL_PTR_ERR;
2835 if(count != session->channel_count)
2836 return E_INVALIDARG;
2838 for(i = 0; i < count; ++i)
2839 levels[i] = session->channel_vols[i];
2844 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2846 ChannelAudioVolume_QueryInterface,
2847 ChannelAudioVolume_AddRef,
2848 ChannelAudioVolume_Release,
2849 ChannelAudioVolume_GetChannelCount,
2850 ChannelAudioVolume_SetChannelVolume,
2851 ChannelAudioVolume_GetChannelVolume,
2852 ChannelAudioVolume_SetAllVolumes,
2853 ChannelAudioVolume_GetAllVolumes
2856 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2857 REFIID riid, void **ppv)
2859 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2865 if(IsEqualIID(riid, &IID_IUnknown) ||
2866 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2867 IsEqualIID(riid, &IID_IAudioSessionManager2))
2870 IUnknown_AddRef((IUnknown*)*ppv);
2874 WARN("Unknown interface %s\n", debugstr_guid(riid));
2875 return E_NOINTERFACE;
2878 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2880 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2882 ref = InterlockedIncrement(&This->ref);
2883 TRACE("(%p) Refcount now %u\n", This, ref);
2887 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2889 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2891 ref = InterlockedDecrement(&This->ref);
2892 TRACE("(%p) Refcount now %u\n", This, ref);
2894 HeapFree(GetProcessHeap(), 0, This);
2898 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2899 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2900 IAudioSessionControl **out)
2902 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2903 AudioSession *session;
2904 AudioSessionWrapper *wrapper;
2907 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2910 hr = get_audio_session(session_guid, This->device, 0, &session);
2914 wrapper = AudioSessionWrapper_Create(NULL);
2916 return E_OUTOFMEMORY;
2918 wrapper->session = session;
2920 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2925 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2926 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2927 ISimpleAudioVolume **out)
2929 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2930 AudioSession *session;
2931 AudioSessionWrapper *wrapper;
2934 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2937 hr = get_audio_session(session_guid, This->device, 0, &session);
2941 wrapper = AudioSessionWrapper_Create(NULL);
2943 return E_OUTOFMEMORY;
2945 wrapper->session = session;
2947 *out = &wrapper->ISimpleAudioVolume_iface;
2952 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2953 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2955 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2956 FIXME("(%p)->(%p) - stub\n", This, out);
2960 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2961 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2963 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2964 FIXME("(%p)->(%p) - stub\n", This, notification);
2968 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2969 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2971 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2972 FIXME("(%p)->(%p) - stub\n", This, notification);
2976 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2977 IAudioSessionManager2 *iface, const WCHAR *session_id,
2978 IAudioVolumeDuckNotification *notification)
2980 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2981 FIXME("(%p)->(%p) - stub\n", This, notification);
2985 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2986 IAudioSessionManager2 *iface,
2987 IAudioVolumeDuckNotification *notification)
2989 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2990 FIXME("(%p)->(%p) - stub\n", This, notification);
2994 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2996 AudioSessionManager_QueryInterface,
2997 AudioSessionManager_AddRef,
2998 AudioSessionManager_Release,
2999 AudioSessionManager_GetAudioSessionControl,
3000 AudioSessionManager_GetSimpleAudioVolume,
3001 AudioSessionManager_GetSessionEnumerator,
3002 AudioSessionManager_RegisterSessionNotification,
3003 AudioSessionManager_UnregisterSessionNotification,
3004 AudioSessionManager_RegisterDuckNotification,
3005 AudioSessionManager_UnregisterDuckNotification
3008 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3009 IAudioSessionManager2 **out)
3013 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3015 return E_OUTOFMEMORY;
3017 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3018 This->device = device;
3021 *out = &This->IAudioSessionManager2_iface;