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 This->fmt = clone_format(fmt);
936 LeaveCriticalSection(&This->lock);
937 return E_OUTOFMEMORY;
941 This->period_us = period / 10;
943 This->period_us = DefaultPeriod / 10;
946 duration = 300000; /* 0.03s */
947 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
948 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
949 This->bufsize_frames * fmt->nBlockAlign);
950 if(!This->local_buffer){
951 CoTaskMemFree(This->fmt);
953 LeaveCriticalSection(&This->lock);
954 return E_OUTOFMEMORY;
957 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
959 CoTaskMemFree(This->fmt);
961 LeaveCriticalSection(&This->lock);
962 return E_OUTOFMEMORY;
965 for(i = 0; i < fmt->nChannels; ++i)
971 EnterCriticalSection(&g_sessions_lock);
973 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
976 LeaveCriticalSection(&g_sessions_lock);
977 HeapFree(GetProcessHeap(), 0, This->vols);
979 CoTaskMemFree(This->fmt);
981 LeaveCriticalSection(&This->lock);
985 list_add_tail(&This->session->clients, &This->entry);
987 LeaveCriticalSection(&g_sessions_lock);
989 This->initted = TRUE;
991 LeaveCriticalSection(&This->lock);
996 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
999 ACImpl *This = impl_from_IAudioClient(iface);
1001 TRACE("(%p)->(%p)\n", This, frames);
1006 EnterCriticalSection(&This->lock);
1009 LeaveCriticalSection(&This->lock);
1010 return AUDCLNT_E_NOT_INITIALIZED;
1013 *frames = This->bufsize_frames;
1015 LeaveCriticalSection(&This->lock);
1020 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1021 REFERENCE_TIME *latency)
1023 ACImpl *This = impl_from_IAudioClient(iface);
1025 TRACE("(%p)->(%p)\n", This, latency);
1030 EnterCriticalSection(&This->lock);
1033 LeaveCriticalSection(&This->lock);
1034 return AUDCLNT_E_NOT_INITIALIZED;
1037 if(This->dataflow == eRender){
1041 if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
1042 LeaveCriticalSection(&This->lock);
1043 WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
1047 delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
1048 This->fmt->nBlockAlign);
1050 *latency = delay_s * 10000000;
1052 *latency = 10000; /* OSS doesn't provide input latency */
1054 /* pretend we process audio in Period chunks, so max latency includes
1055 * the period time */
1056 *latency += DefaultPeriod;
1058 LeaveCriticalSection(&This->lock);
1063 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1066 ACImpl *This = impl_from_IAudioClient(iface);
1069 TRACE("(%p)->(%p)\n", This, numpad);
1074 EnterCriticalSection(&This->lock);
1077 LeaveCriticalSection(&This->lock);
1078 return AUDCLNT_E_NOT_INITIALIZED;
1081 if(This->dataflow == eRender){
1082 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1083 LeaveCriticalSection(&This->lock);
1084 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1088 *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
1089 This->fmt->nBlockAlign;
1091 /* when the OSS buffer has less than one fragment of data, including
1092 * no data, it often reports it as some non-zero portion of a
1093 * fragment. when it has more than one fragment of data, it reports
1094 * it as some multiple of that portion of the fragment size.
1096 * so, we have to do some ugly workarounds to report the timing
1097 * as accurately as possible */
1098 if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
1099 *numpad = This->inbuf_frames;
1100 This->inbuf_frames = 0;
1102 if(*numpad < This->inbuf_frames)
1103 This->inbuf_frames = *numpad;
1105 *numpad = This->inbuf_frames;
1107 }else if(This->dataflow == eCapture){
1108 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1109 LeaveCriticalSection(&This->lock);
1110 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1114 if(bi.bytes <= bi.fragsize)
1117 *numpad = bi.bytes / This->fmt->nBlockAlign;
1119 LeaveCriticalSection(&This->lock);
1120 return E_UNEXPECTED;
1123 *numpad += This->held_frames;
1125 LeaveCriticalSection(&This->lock);
1130 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1131 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1132 WAVEFORMATEX **outpwfx)
1134 ACImpl *This = impl_from_IAudioClient(iface);
1138 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1140 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1143 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1144 return E_INVALIDARG;
1146 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1147 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1148 return E_INVALIDARG;
1154 if(mode != AUDCLNT_SHAREMODE_SHARED)
1158 if(This->dataflow == eRender)
1159 fd = open(This->devnode, O_WRONLY, 0);
1160 else if(This->dataflow == eCapture)
1161 fd = open(This->devnode, O_RDONLY, 0);
1164 ERR("Unable to open device %s: %d (%s)\n", This->devnode, errno,
1166 return AUDCLNT_E_DEVICE_INVALIDATED;
1169 ret = setup_oss_device(fd, pwfx, outpwfx, TRUE);
1176 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1177 WAVEFORMATEX **pwfx)
1179 ACImpl *This = impl_from_IAudioClient(iface);
1180 WAVEFORMATEXTENSIBLE *fmt;
1183 TRACE("(%p)->(%p)\n", This, pwfx);
1189 if(This->dataflow == eRender)
1190 formats = This->ai.oformats;
1191 else if(This->dataflow == eCapture)
1192 formats = This->ai.iformats;
1194 return E_UNEXPECTED;
1196 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1198 return E_OUTOFMEMORY;
1200 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1201 if(formats & AFMT_S16_LE){
1202 fmt->Format.wBitsPerSample = 16;
1203 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1205 }else if(formats & AFMT_FLOAT){
1206 fmt->Format.wBitsPerSample = 32;
1207 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1209 }else if(formats & AFMT_U8){
1210 fmt->Format.wBitsPerSample = 8;
1211 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1212 }else if(formats & AFMT_S32_LE){
1213 fmt->Format.wBitsPerSample = 32;
1214 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1215 }else if(formats & AFMT_S24_LE){
1216 fmt->Format.wBitsPerSample = 24;
1217 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1219 ERR("Didn't recognize any available OSS formats: %x\n", formats);
1224 fmt->Format.nChannels = This->ai.max_channels;
1225 fmt->Format.nSamplesPerSec = This->ai.max_rate;
1226 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1228 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1229 fmt->Format.nChannels) / 8;
1230 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1231 fmt->Format.nBlockAlign;
1233 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1234 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1236 *pwfx = (WAVEFORMATEX*)fmt;
1242 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1243 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1245 ACImpl *This = impl_from_IAudioClient(iface);
1247 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1249 if(!defperiod && !minperiod)
1252 EnterCriticalSection(&This->lock);
1255 *defperiod = DefaultPeriod;
1257 *minperiod = MinimumPeriod;
1259 LeaveCriticalSection(&This->lock);
1264 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1266 if(This->fmt->wBitsPerSample == 8)
1267 memset(buf, 128, frames * This->fmt->nBlockAlign);
1269 memset(buf, 0, frames * This->fmt->nBlockAlign);
1272 static void oss_write_data(ACImpl *This)
1274 ssize_t written_bytes;
1275 UINT32 written_frames;
1276 size_t to_write_frames, to_write_bytes;
1279 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1281 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1282 to_write_frames = This->bufsize_frames - This->lcl_offs_frames;
1284 to_write_frames = This->held_frames;
1285 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1287 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1288 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1292 if(bi.bytes < to_write_bytes){
1293 to_write_frames = bi.bytes / This->fmt->nBlockAlign;
1294 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1297 if(This->session->mute)
1298 oss_silence_buffer(This, buf, to_write_frames);
1300 written_bytes = write(This->fd, buf, to_write_bytes);
1301 if(written_bytes < 0){
1302 /* EAGAIN is OSS buffer full, log that too */
1303 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1306 written_frames = written_bytes / This->fmt->nBlockAlign;
1308 This->lcl_offs_frames += written_frames;
1309 This->lcl_offs_frames %= This->bufsize_frames;
1310 This->held_frames -= written_frames;
1311 This->inbuf_frames += written_frames;
1313 if(written_frames < to_write_frames){
1314 /* OSS buffer probably full */
1318 bi.bytes -= written_bytes;
1319 if(This->held_frames && bi.bytes >= This->fmt->nBlockAlign){
1320 /* wrapped and have some data back at the start to write */
1322 to_write_frames = bi.bytes / This->fmt->nBlockAlign;
1323 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1325 if(This->session->mute)
1326 oss_silence_buffer(This, This->local_buffer, to_write_frames);
1328 written_bytes = write(This->fd, This->local_buffer, to_write_bytes);
1329 if(written_bytes < 0){
1330 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1333 written_frames = written_bytes / This->fmt->nBlockAlign;
1335 This->lcl_offs_frames += written_frames;
1336 This->lcl_offs_frames %= This->bufsize_frames;
1337 This->held_frames -= written_frames;
1338 This->inbuf_frames += written_frames;
1342 static void oss_read_data(ACImpl *This)
1344 UINT64 pos, readable;
1348 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1349 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1353 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1354 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1356 if(bi.bytes < readable)
1357 readable = bi.bytes;
1359 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1362 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1366 This->held_frames += nread / This->fmt->nBlockAlign;
1368 if(This->held_frames > This->bufsize_frames){
1369 WARN("Overflow of unread data\n");
1370 This->lcl_offs_frames += This->held_frames;
1371 This->lcl_offs_frames %= This->bufsize_frames;
1372 This->held_frames = This->bufsize_frames;
1376 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1378 ACImpl *This = user;
1380 EnterCriticalSection(&This->lock);
1382 if(This->dataflow == eRender && This->held_frames)
1383 oss_write_data(This);
1384 else if(This->dataflow == eCapture)
1385 oss_read_data(This);
1388 SetEvent(This->event);
1390 LeaveCriticalSection(&This->lock);
1393 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1395 ACImpl *This = impl_from_IAudioClient(iface);
1398 TRACE("(%p)\n", This);
1400 EnterCriticalSection(&This->lock);
1403 LeaveCriticalSection(&This->lock);
1404 return AUDCLNT_E_NOT_INITIALIZED;
1407 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1408 LeaveCriticalSection(&This->lock);
1409 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1413 LeaveCriticalSection(&This->lock);
1414 return AUDCLNT_E_NOT_STOPPED;
1417 if(This->dataflow == eRender)
1418 mask = PCM_ENABLE_OUTPUT;
1419 else if(This->dataflow == eCapture)
1420 mask = PCM_ENABLE_INPUT;
1422 LeaveCriticalSection(&This->lock);
1423 return E_UNEXPECTED;
1426 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1427 LeaveCriticalSection(&This->lock);
1428 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1432 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1433 oss_period_callback, This, 0, This->period_us / 1000,
1434 WT_EXECUTEINTIMERTHREAD))
1435 ERR("Unable to create period timer: %u\n", GetLastError());
1437 This->playing = TRUE;
1439 LeaveCriticalSection(&This->lock);
1444 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1446 ACImpl *This = impl_from_IAudioClient(iface);
1449 TRACE("(%p)\n", This);
1451 EnterCriticalSection(&This->lock);
1454 LeaveCriticalSection(&This->lock);
1455 return AUDCLNT_E_NOT_INITIALIZED;
1459 LeaveCriticalSection(&This->lock);
1463 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1464 DeleteTimerQueueTimer(g_timer_q, This->timer,
1465 INVALID_HANDLE_VALUE);
1469 if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1470 LeaveCriticalSection(&This->lock);
1471 WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1476 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1477 LeaveCriticalSection(&This->lock);
1478 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1482 This->playing = FALSE;
1484 LeaveCriticalSection(&This->lock);
1489 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1491 ACImpl *This = impl_from_IAudioClient(iface);
1493 TRACE("(%p)\n", This);
1495 EnterCriticalSection(&This->lock);
1498 LeaveCriticalSection(&This->lock);
1499 return AUDCLNT_E_NOT_INITIALIZED;
1503 LeaveCriticalSection(&This->lock);
1504 return AUDCLNT_E_NOT_STOPPED;
1507 if(This->buf_state != NOT_LOCKED){
1508 LeaveCriticalSection(&This->lock);
1509 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1512 This->written_frames = 0;
1513 This->inbuf_frames = 0;
1514 This->held_frames = 0;
1516 if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1517 WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1519 LeaveCriticalSection(&This->lock);
1524 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1527 ACImpl *This = impl_from_IAudioClient(iface);
1529 TRACE("(%p)->(%p)\n", This, event);
1532 return E_INVALIDARG;
1534 EnterCriticalSection(&This->lock);
1537 LeaveCriticalSection(&This->lock);
1538 return AUDCLNT_E_NOT_INITIALIZED;
1541 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1542 LeaveCriticalSection(&This->lock);
1543 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1546 This->event = event;
1548 LeaveCriticalSection(&This->lock);
1553 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1556 ACImpl *This = impl_from_IAudioClient(iface);
1558 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1564 EnterCriticalSection(&This->lock);
1567 LeaveCriticalSection(&This->lock);
1568 return AUDCLNT_E_NOT_INITIALIZED;
1571 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1572 if(This->dataflow != eRender){
1573 LeaveCriticalSection(&This->lock);
1574 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1576 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1577 *ppv = &This->IAudioRenderClient_iface;
1578 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1579 if(This->dataflow != eCapture){
1580 LeaveCriticalSection(&This->lock);
1581 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1583 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1584 *ppv = &This->IAudioCaptureClient_iface;
1585 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1586 IAudioClock_AddRef(&This->IAudioClock_iface);
1587 *ppv = &This->IAudioClock_iface;
1588 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1589 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1590 *ppv = &This->IAudioStreamVolume_iface;
1591 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1592 if(!This->session_wrapper){
1593 This->session_wrapper = AudioSessionWrapper_Create(This);
1594 if(!This->session_wrapper){
1595 LeaveCriticalSection(&This->lock);
1596 return E_OUTOFMEMORY;
1599 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1601 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1602 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1603 if(!This->session_wrapper){
1604 This->session_wrapper = AudioSessionWrapper_Create(This);
1605 if(!This->session_wrapper){
1606 LeaveCriticalSection(&This->lock);
1607 return E_OUTOFMEMORY;
1610 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1612 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1613 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1614 if(!This->session_wrapper){
1615 This->session_wrapper = AudioSessionWrapper_Create(This);
1616 if(!This->session_wrapper){
1617 LeaveCriticalSection(&This->lock);
1618 return E_OUTOFMEMORY;
1621 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1623 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1627 LeaveCriticalSection(&This->lock);
1631 LeaveCriticalSection(&This->lock);
1633 FIXME("stub %s\n", debugstr_guid(riid));
1634 return E_NOINTERFACE;
1637 static const IAudioClientVtbl AudioClient_Vtbl =
1639 AudioClient_QueryInterface,
1641 AudioClient_Release,
1642 AudioClient_Initialize,
1643 AudioClient_GetBufferSize,
1644 AudioClient_GetStreamLatency,
1645 AudioClient_GetCurrentPadding,
1646 AudioClient_IsFormatSupported,
1647 AudioClient_GetMixFormat,
1648 AudioClient_GetDevicePeriod,
1652 AudioClient_SetEventHandle,
1653 AudioClient_GetService
1656 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1657 IAudioRenderClient *iface, REFIID riid, void **ppv)
1659 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1665 if(IsEqualIID(riid, &IID_IUnknown) ||
1666 IsEqualIID(riid, &IID_IAudioRenderClient))
1669 IUnknown_AddRef((IUnknown*)*ppv);
1673 WARN("Unknown interface %s\n", debugstr_guid(riid));
1674 return E_NOINTERFACE;
1677 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1679 ACImpl *This = impl_from_IAudioRenderClient(iface);
1680 return AudioClient_AddRef(&This->IAudioClient_iface);
1683 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1685 ACImpl *This = impl_from_IAudioRenderClient(iface);
1686 return AudioClient_Release(&This->IAudioClient_iface);
1689 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1690 UINT32 frames, BYTE **data)
1692 ACImpl *This = impl_from_IAudioRenderClient(iface);
1693 UINT32 pad, write_pos;
1696 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1701 EnterCriticalSection(&This->lock);
1703 if(This->buf_state != NOT_LOCKED){
1704 LeaveCriticalSection(&This->lock);
1705 return AUDCLNT_E_OUT_OF_ORDER;
1709 This->buf_state = LOCKED_NORMAL;
1710 LeaveCriticalSection(&This->lock);
1714 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1716 LeaveCriticalSection(&This->lock);
1720 if(pad + frames > This->bufsize_frames){
1721 LeaveCriticalSection(&This->lock);
1722 return AUDCLNT_E_BUFFER_TOO_LARGE;
1726 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1727 if(write_pos + frames > This->bufsize_frames){
1728 if(This->tmp_buffer_frames < frames){
1729 if(This->tmp_buffer)
1730 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1731 This->tmp_buffer, frames * This->fmt->nBlockAlign);
1733 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1734 frames * This->fmt->nBlockAlign);
1735 if(!This->tmp_buffer){
1736 LeaveCriticalSection(&This->lock);
1737 return E_OUTOFMEMORY;
1739 This->tmp_buffer_frames = frames;
1741 *data = This->tmp_buffer;
1742 This->buf_state = LOCKED_WRAPPED;
1744 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1745 This->buf_state = LOCKED_NORMAL;
1748 LeaveCriticalSection(&This->lock);
1753 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1755 UINT32 write_offs_frames =
1756 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1757 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1758 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1759 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1760 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1762 if(written_bytes <= chunk_bytes){
1763 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1765 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1766 memcpy(This->local_buffer, buffer + chunk_bytes,
1767 written_bytes - chunk_bytes);
1771 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1772 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1774 ACImpl *This = impl_from_IAudioRenderClient(iface);
1777 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1779 EnterCriticalSection(&This->lock);
1781 if(This->buf_state == NOT_LOCKED || !written_frames){
1782 This->buf_state = NOT_LOCKED;
1783 LeaveCriticalSection(&This->lock);
1784 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1787 if(This->buf_state == LOCKED_NORMAL)
1788 buffer = This->local_buffer + This->fmt->nBlockAlign *
1789 ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1791 buffer = This->tmp_buffer;
1793 if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1794 oss_silence_buffer(This, buffer, written_frames);
1796 if(This->held_frames){
1797 if(This->buf_state == LOCKED_WRAPPED)
1798 oss_wrap_buffer(This, buffer, written_frames);
1800 This->held_frames += written_frames;
1805 if(This->session->mute)
1806 oss_silence_buffer(This, buffer, written_frames);
1808 w_bytes = write(This->fd, buffer,
1809 written_frames * This->fmt->nBlockAlign);
1811 if(errno != EAGAIN){
1812 This->buf_state = NOT_LOCKED;
1813 LeaveCriticalSection(&This->lock);
1814 ERR("write failed: %d (%s)\n", errno, strerror(errno));
1816 }else /* OSS buffer full */
1819 w_frames = w_bytes / This->fmt->nBlockAlign;
1820 This->inbuf_frames += w_frames;
1822 if(w_frames < written_frames){
1823 if(This->buf_state == LOCKED_WRAPPED)
1824 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1825 written_frames - w_frames);
1827 This->lcl_offs_frames += w_frames;
1828 This->held_frames = written_frames - w_frames;
1832 This->written_frames += written_frames;
1833 This->buf_state = NOT_LOCKED;
1835 LeaveCriticalSection(&This->lock);
1840 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1841 AudioRenderClient_QueryInterface,
1842 AudioRenderClient_AddRef,
1843 AudioRenderClient_Release,
1844 AudioRenderClient_GetBuffer,
1845 AudioRenderClient_ReleaseBuffer
1848 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1849 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1851 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1857 if(IsEqualIID(riid, &IID_IUnknown) ||
1858 IsEqualIID(riid, &IID_IAudioCaptureClient))
1861 IUnknown_AddRef((IUnknown*)*ppv);
1865 WARN("Unknown interface %s\n", debugstr_guid(riid));
1866 return E_NOINTERFACE;
1869 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1871 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1872 return IAudioClient_AddRef(&This->IAudioClient_iface);
1875 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1877 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1878 return IAudioClient_Release(&This->IAudioClient_iface);
1881 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1882 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1885 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1888 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1891 if(!data || !frames || !flags)
1894 EnterCriticalSection(&This->lock);
1896 if(This->buf_state != NOT_LOCKED){
1897 LeaveCriticalSection(&This->lock);
1898 return AUDCLNT_E_OUT_OF_ORDER;
1901 hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1903 LeaveCriticalSection(&This->lock);
1909 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1910 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1911 if(This->tmp_buffer_frames < *frames){
1912 if(This->tmp_buffer)
1913 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1914 This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1916 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1917 *frames * This->fmt->nBlockAlign);
1918 if(!This->tmp_buffer){
1919 LeaveCriticalSection(&This->lock);
1920 return E_OUTOFMEMORY;
1922 This->tmp_buffer_frames = *frames;
1925 *data = This->tmp_buffer;
1926 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1927 This->fmt->nBlockAlign;
1928 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1929 frames_bytes = *frames * This->fmt->nBlockAlign;
1930 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1931 memcpy(This->tmp_buffer, This->local_buffer,
1932 frames_bytes - chunk_bytes);
1934 *data = This->local_buffer +
1935 This->lcl_offs_frames * This->fmt->nBlockAlign;
1937 This->buf_state = LOCKED_NORMAL;
1939 if(devpos || qpcpos)
1940 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1942 LeaveCriticalSection(&This->lock);
1944 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1947 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1948 IAudioCaptureClient *iface, UINT32 done)
1950 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1952 TRACE("(%p)->(%u)\n", This, done);
1954 EnterCriticalSection(&This->lock);
1956 if(This->buf_state == NOT_LOCKED){
1957 LeaveCriticalSection(&This->lock);
1958 return AUDCLNT_E_OUT_OF_ORDER;
1961 This->held_frames -= done;
1962 This->lcl_offs_frames += done;
1963 This->lcl_offs_frames %= This->bufsize_frames;
1965 This->buf_state = NOT_LOCKED;
1967 LeaveCriticalSection(&This->lock);
1972 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1973 IAudioCaptureClient *iface, UINT32 *frames)
1975 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1977 TRACE("(%p)->(%p)\n", This, frames);
1979 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1982 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1984 AudioCaptureClient_QueryInterface,
1985 AudioCaptureClient_AddRef,
1986 AudioCaptureClient_Release,
1987 AudioCaptureClient_GetBuffer,
1988 AudioCaptureClient_ReleaseBuffer,
1989 AudioCaptureClient_GetNextPacketSize
1992 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1993 REFIID riid, void **ppv)
1995 ACImpl *This = impl_from_IAudioClock(iface);
1997 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2003 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2005 else if(IsEqualIID(riid, &IID_IAudioClock2))
2006 *ppv = &This->IAudioClock2_iface;
2008 IUnknown_AddRef((IUnknown*)*ppv);
2012 WARN("Unknown interface %s\n", debugstr_guid(riid));
2013 return E_NOINTERFACE;
2016 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2018 ACImpl *This = impl_from_IAudioClock(iface);
2019 return IAudioClient_AddRef(&This->IAudioClient_iface);
2022 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2024 ACImpl *This = impl_from_IAudioClock(iface);
2025 return IAudioClient_Release(&This->IAudioClient_iface);
2028 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2030 ACImpl *This = impl_from_IAudioClock(iface);
2032 TRACE("(%p)->(%p)\n", This, freq);
2034 *freq = This->fmt->nSamplesPerSec;
2039 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2042 ACImpl *This = impl_from_IAudioClock(iface);
2046 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2051 EnterCriticalSection(&This->lock);
2053 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
2055 LeaveCriticalSection(&This->lock);
2059 if(This->dataflow == eRender)
2060 *pos = This->written_frames - pad;
2061 else if(This->dataflow == eCapture)
2062 *pos = This->written_frames + pad;
2064 LeaveCriticalSection(&This->lock);
2067 LARGE_INTEGER stamp, freq;
2068 QueryPerformanceCounter(&stamp);
2069 QueryPerformanceFrequency(&freq);
2070 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2076 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2079 ACImpl *This = impl_from_IAudioClock(iface);
2081 TRACE("(%p)->(%p)\n", This, chars);
2086 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2091 static const IAudioClockVtbl AudioClock_Vtbl =
2093 AudioClock_QueryInterface,
2096 AudioClock_GetFrequency,
2097 AudioClock_GetPosition,
2098 AudioClock_GetCharacteristics
2101 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2102 REFIID riid, void **ppv)
2104 ACImpl *This = impl_from_IAudioClock2(iface);
2105 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2108 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2110 ACImpl *This = impl_from_IAudioClock2(iface);
2111 return IAudioClient_AddRef(&This->IAudioClient_iface);
2114 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2116 ACImpl *This = impl_from_IAudioClock2(iface);
2117 return IAudioClient_Release(&This->IAudioClient_iface);
2120 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2121 UINT64 *pos, UINT64 *qpctime)
2123 ACImpl *This = impl_from_IAudioClock2(iface);
2125 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2130 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2132 AudioClock2_QueryInterface,
2134 AudioClock2_Release,
2135 AudioClock2_GetDevicePosition
2138 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2140 AudioSessionWrapper *ret;
2142 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2143 sizeof(AudioSessionWrapper));
2147 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2148 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2149 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2153 ret->client = client;
2155 ret->session = client->session;
2156 AudioClient_AddRef(&client->IAudioClient_iface);
2162 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2163 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2165 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2171 if(IsEqualIID(riid, &IID_IUnknown) ||
2172 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2173 IsEqualIID(riid, &IID_IAudioSessionControl2))
2176 IUnknown_AddRef((IUnknown*)*ppv);
2180 WARN("Unknown interface %s\n", debugstr_guid(riid));
2181 return E_NOINTERFACE;
2184 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2186 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2188 ref = InterlockedIncrement(&This->ref);
2189 TRACE("(%p) Refcount now %u\n", This, ref);
2193 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2195 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2197 ref = InterlockedDecrement(&This->ref);
2198 TRACE("(%p) Refcount now %u\n", This, ref);
2201 EnterCriticalSection(&This->client->lock);
2202 This->client->session_wrapper = NULL;
2203 LeaveCriticalSection(&This->client->lock);
2204 AudioClient_Release(&This->client->IAudioClient_iface);
2206 HeapFree(GetProcessHeap(), 0, This);
2211 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2212 AudioSessionState *state)
2214 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2217 TRACE("(%p)->(%p)\n", This, state);
2220 return NULL_PTR_ERR;
2222 EnterCriticalSection(&g_sessions_lock);
2224 if(list_empty(&This->session->clients)){
2225 *state = AudioSessionStateExpired;
2226 LeaveCriticalSection(&g_sessions_lock);
2230 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2231 EnterCriticalSection(&client->lock);
2232 if(client->playing){
2233 *state = AudioSessionStateActive;
2234 LeaveCriticalSection(&client->lock);
2235 LeaveCriticalSection(&g_sessions_lock);
2238 LeaveCriticalSection(&client->lock);
2241 LeaveCriticalSection(&g_sessions_lock);
2243 *state = AudioSessionStateInactive;
2248 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2249 IAudioSessionControl2 *iface, WCHAR **name)
2251 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2253 FIXME("(%p)->(%p) - stub\n", This, name);
2258 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2259 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2261 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2263 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2268 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2269 IAudioSessionControl2 *iface, WCHAR **path)
2271 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2273 FIXME("(%p)->(%p) - stub\n", This, path);
2278 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2279 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2281 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2283 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2288 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2289 IAudioSessionControl2 *iface, GUID *group)
2291 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2293 FIXME("(%p)->(%p) - stub\n", This, group);
2298 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2299 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2301 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2303 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2304 debugstr_guid(session));
2309 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2310 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2312 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2314 FIXME("(%p)->(%p) - stub\n", This, events);
2319 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2320 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2322 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2324 FIXME("(%p)->(%p) - stub\n", This, events);
2329 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2330 IAudioSessionControl2 *iface, WCHAR **id)
2332 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2334 FIXME("(%p)->(%p) - stub\n", This, id);
2339 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2340 IAudioSessionControl2 *iface, WCHAR **id)
2342 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2344 FIXME("(%p)->(%p) - stub\n", This, id);
2349 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2350 IAudioSessionControl2 *iface, DWORD *pid)
2352 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2354 TRACE("(%p)->(%p)\n", This, pid);
2359 *pid = GetCurrentProcessId();
2364 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2365 IAudioSessionControl2 *iface)
2367 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2369 TRACE("(%p)\n", This);
2374 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2375 IAudioSessionControl2 *iface, BOOL optout)
2377 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2379 TRACE("(%p)->(%d)\n", This, optout);
2384 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2386 AudioSessionControl_QueryInterface,
2387 AudioSessionControl_AddRef,
2388 AudioSessionControl_Release,
2389 AudioSessionControl_GetState,
2390 AudioSessionControl_GetDisplayName,
2391 AudioSessionControl_SetDisplayName,
2392 AudioSessionControl_GetIconPath,
2393 AudioSessionControl_SetIconPath,
2394 AudioSessionControl_GetGroupingParam,
2395 AudioSessionControl_SetGroupingParam,
2396 AudioSessionControl_RegisterAudioSessionNotification,
2397 AudioSessionControl_UnregisterAudioSessionNotification,
2398 AudioSessionControl_GetSessionIdentifier,
2399 AudioSessionControl_GetSessionInstanceIdentifier,
2400 AudioSessionControl_GetProcessId,
2401 AudioSessionControl_IsSystemSoundsSession,
2402 AudioSessionControl_SetDuckingPreference
2405 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2406 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2408 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2414 if(IsEqualIID(riid, &IID_IUnknown) ||
2415 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2418 IUnknown_AddRef((IUnknown*)*ppv);
2422 WARN("Unknown interface %s\n", debugstr_guid(riid));
2423 return E_NOINTERFACE;
2426 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2428 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2429 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2432 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2434 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2435 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2438 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2439 ISimpleAudioVolume *iface, float level, const GUID *context)
2441 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2442 AudioSession *session = This->session;
2444 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2446 if(level < 0.f || level > 1.f)
2447 return E_INVALIDARG;
2450 FIXME("Notifications not supported yet\n");
2452 EnterCriticalSection(&session->lock);
2454 session->master_vol = level;
2456 TRACE("OSS doesn't support setting volume\n");
2458 LeaveCriticalSection(&session->lock);
2463 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2464 ISimpleAudioVolume *iface, float *level)
2466 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2467 AudioSession *session = This->session;
2469 TRACE("(%p)->(%p)\n", session, level);
2472 return NULL_PTR_ERR;
2474 *level = session->master_vol;
2479 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2480 BOOL mute, const GUID *context)
2482 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2483 AudioSession *session = This->session;
2485 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2487 EnterCriticalSection(&session->lock);
2489 if(!mute && session->mute){
2492 session->mute = mute;
2494 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2495 EnterCriticalSection(&client->lock);
2496 if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2497 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2499 oss_write_data(client);
2500 LeaveCriticalSection(&client->lock);
2503 session->mute = mute;
2505 LeaveCriticalSection(&session->lock);
2510 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2513 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2514 AudioSession *session = This->session;
2516 TRACE("(%p)->(%p)\n", session, mute);
2519 return NULL_PTR_ERR;
2521 *mute = This->session->mute;
2526 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2528 SimpleAudioVolume_QueryInterface,
2529 SimpleAudioVolume_AddRef,
2530 SimpleAudioVolume_Release,
2531 SimpleAudioVolume_SetMasterVolume,
2532 SimpleAudioVolume_GetMasterVolume,
2533 SimpleAudioVolume_SetMute,
2534 SimpleAudioVolume_GetMute
2537 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2538 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2540 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2546 if(IsEqualIID(riid, &IID_IUnknown) ||
2547 IsEqualIID(riid, &IID_IAudioStreamVolume))
2550 IUnknown_AddRef((IUnknown*)*ppv);
2554 WARN("Unknown interface %s\n", debugstr_guid(riid));
2555 return E_NOINTERFACE;
2558 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2560 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2561 return IAudioClient_AddRef(&This->IAudioClient_iface);
2564 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2566 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2567 return IAudioClient_Release(&This->IAudioClient_iface);
2570 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2571 IAudioStreamVolume *iface, UINT32 *out)
2573 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2575 TRACE("(%p)->(%p)\n", This, out);
2580 *out = This->fmt->nChannels;
2585 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2586 IAudioStreamVolume *iface, UINT32 index, float level)
2588 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2590 TRACE("(%p)->(%d, %f)\n", This, index, level);
2592 if(level < 0.f || level > 1.f)
2593 return E_INVALIDARG;
2595 if(index >= This->fmt->nChannels)
2596 return E_INVALIDARG;
2598 EnterCriticalSection(&This->lock);
2600 This->vols[index] = level;
2602 TRACE("OSS doesn't support setting volume\n");
2604 LeaveCriticalSection(&This->lock);
2609 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2610 IAudioStreamVolume *iface, UINT32 index, float *level)
2612 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2614 TRACE("(%p)->(%d, %p)\n", This, index, level);
2619 if(index >= This->fmt->nChannels)
2620 return E_INVALIDARG;
2622 *level = This->vols[index];
2627 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2628 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2630 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2633 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2638 if(count != This->fmt->nChannels)
2639 return E_INVALIDARG;
2641 EnterCriticalSection(&This->lock);
2643 for(i = 0; i < count; ++i)
2644 This->vols[i] = levels[i];
2646 TRACE("OSS doesn't support setting volume\n");
2648 LeaveCriticalSection(&This->lock);
2653 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2654 IAudioStreamVolume *iface, UINT32 count, float *levels)
2656 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2659 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2664 if(count != This->fmt->nChannels)
2665 return E_INVALIDARG;
2667 EnterCriticalSection(&This->lock);
2669 for(i = 0; i < count; ++i)
2670 levels[i] = This->vols[i];
2672 LeaveCriticalSection(&This->lock);
2677 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2679 AudioStreamVolume_QueryInterface,
2680 AudioStreamVolume_AddRef,
2681 AudioStreamVolume_Release,
2682 AudioStreamVolume_GetChannelCount,
2683 AudioStreamVolume_SetChannelVolume,
2684 AudioStreamVolume_GetChannelVolume,
2685 AudioStreamVolume_SetAllVolumes,
2686 AudioStreamVolume_GetAllVolumes
2689 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2690 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2692 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2698 if(IsEqualIID(riid, &IID_IUnknown) ||
2699 IsEqualIID(riid, &IID_IChannelAudioVolume))
2702 IUnknown_AddRef((IUnknown*)*ppv);
2706 WARN("Unknown interface %s\n", debugstr_guid(riid));
2707 return E_NOINTERFACE;
2710 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2712 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2713 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2716 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2718 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2719 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2722 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2723 IChannelAudioVolume *iface, UINT32 *out)
2725 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2726 AudioSession *session = This->session;
2728 TRACE("(%p)->(%p)\n", session, out);
2731 return NULL_PTR_ERR;
2733 *out = session->channel_count;
2738 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2739 IChannelAudioVolume *iface, UINT32 index, float level,
2740 const GUID *context)
2742 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2743 AudioSession *session = This->session;
2745 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2746 wine_dbgstr_guid(context));
2748 if(level < 0.f || level > 1.f)
2749 return E_INVALIDARG;
2751 if(index >= session->channel_count)
2752 return E_INVALIDARG;
2755 FIXME("Notifications not supported yet\n");
2757 EnterCriticalSection(&session->lock);
2759 session->channel_vols[index] = level;
2761 TRACE("OSS doesn't support setting volume\n");
2763 LeaveCriticalSection(&session->lock);
2768 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2769 IChannelAudioVolume *iface, UINT32 index, float *level)
2771 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2772 AudioSession *session = This->session;
2774 TRACE("(%p)->(%d, %p)\n", session, index, level);
2777 return NULL_PTR_ERR;
2779 if(index >= session->channel_count)
2780 return E_INVALIDARG;
2782 *level = session->channel_vols[index];
2787 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2788 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2789 const GUID *context)
2791 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2792 AudioSession *session = This->session;
2795 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2796 wine_dbgstr_guid(context));
2799 return NULL_PTR_ERR;
2801 if(count != session->channel_count)
2802 return E_INVALIDARG;
2805 FIXME("Notifications not supported yet\n");
2807 EnterCriticalSection(&session->lock);
2809 for(i = 0; i < count; ++i)
2810 session->channel_vols[i] = levels[i];
2812 TRACE("OSS doesn't support setting volume\n");
2814 LeaveCriticalSection(&session->lock);
2819 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2820 IChannelAudioVolume *iface, UINT32 count, float *levels)
2822 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2823 AudioSession *session = This->session;
2826 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2829 return NULL_PTR_ERR;
2831 if(count != session->channel_count)
2832 return E_INVALIDARG;
2834 for(i = 0; i < count; ++i)
2835 levels[i] = session->channel_vols[i];
2840 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2842 ChannelAudioVolume_QueryInterface,
2843 ChannelAudioVolume_AddRef,
2844 ChannelAudioVolume_Release,
2845 ChannelAudioVolume_GetChannelCount,
2846 ChannelAudioVolume_SetChannelVolume,
2847 ChannelAudioVolume_GetChannelVolume,
2848 ChannelAudioVolume_SetAllVolumes,
2849 ChannelAudioVolume_GetAllVolumes
2852 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2853 REFIID riid, void **ppv)
2855 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2861 if(IsEqualIID(riid, &IID_IUnknown) ||
2862 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2863 IsEqualIID(riid, &IID_IAudioSessionManager2))
2866 IUnknown_AddRef((IUnknown*)*ppv);
2870 WARN("Unknown interface %s\n", debugstr_guid(riid));
2871 return E_NOINTERFACE;
2874 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2876 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2878 ref = InterlockedIncrement(&This->ref);
2879 TRACE("(%p) Refcount now %u\n", This, ref);
2883 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2885 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2887 ref = InterlockedDecrement(&This->ref);
2888 TRACE("(%p) Refcount now %u\n", This, ref);
2890 HeapFree(GetProcessHeap(), 0, This);
2894 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2895 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2896 IAudioSessionControl **out)
2898 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2899 AudioSession *session;
2900 AudioSessionWrapper *wrapper;
2903 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2906 hr = get_audio_session(session_guid, This->device, 0, &session);
2910 wrapper = AudioSessionWrapper_Create(NULL);
2912 return E_OUTOFMEMORY;
2914 wrapper->session = session;
2916 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2921 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2922 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2923 ISimpleAudioVolume **out)
2925 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2926 AudioSession *session;
2927 AudioSessionWrapper *wrapper;
2930 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2933 hr = get_audio_session(session_guid, This->device, 0, &session);
2937 wrapper = AudioSessionWrapper_Create(NULL);
2939 return E_OUTOFMEMORY;
2941 wrapper->session = session;
2943 *out = &wrapper->ISimpleAudioVolume_iface;
2948 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2949 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2951 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2952 FIXME("(%p)->(%p) - stub\n", This, out);
2956 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2957 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2959 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2960 FIXME("(%p)->(%p) - stub\n", This, notification);
2964 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2965 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2967 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2968 FIXME("(%p)->(%p) - stub\n", This, notification);
2972 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2973 IAudioSessionManager2 *iface, const WCHAR *session_id,
2974 IAudioVolumeDuckNotification *notification)
2976 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2977 FIXME("(%p)->(%p) - stub\n", This, notification);
2981 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2982 IAudioSessionManager2 *iface,
2983 IAudioVolumeDuckNotification *notification)
2985 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2986 FIXME("(%p)->(%p) - stub\n", This, notification);
2990 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2992 AudioSessionManager_QueryInterface,
2993 AudioSessionManager_AddRef,
2994 AudioSessionManager_Release,
2995 AudioSessionManager_GetAudioSessionControl,
2996 AudioSessionManager_GetSimpleAudioVolume,
2997 AudioSessionManager_GetSessionEnumerator,
2998 AudioSessionManager_RegisterSessionNotification,
2999 AudioSessionManager_UnregisterSessionNotification,
3000 AudioSessionManager_RegisterDuckNotification,
3001 AudioSessionManager_UnregisterDuckNotification
3004 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3005 IAudioSessionManager2 **out)
3009 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3011 return E_OUTOFMEMORY;
3013 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3014 This->device = device;
3017 *out = &This->IAudioSessionManager2_iface;