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;
131 long getbuf_last; /* <0 when using tmp_buffer */
134 CRITICAL_SECTION lock;
136 AudioSession *session;
137 AudioSessionWrapper *session_wrapper;
144 LOCKED_NORMAL, /* public buffer piece is from local_buffer */
145 LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
148 typedef struct _SessionMgr {
149 IAudioSessionManager2 IAudioSessionManager2_iface;
156 static HANDLE g_timer_q;
158 static CRITICAL_SECTION g_sessions_lock;
159 static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
161 0, 0, &g_sessions_lock,
162 { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList },
163 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") }
165 static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 };
166 static struct list g_sessions = LIST_INIT(g_sessions);
168 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
170 static const IAudioClientVtbl AudioClient_Vtbl;
171 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
172 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
173 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
174 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
175 static const IAudioClockVtbl AudioClock_Vtbl;
176 static const IAudioClock2Vtbl AudioClock2_Vtbl;
177 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
178 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
179 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
181 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
183 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
186 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
188 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
191 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
193 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
196 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
198 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
201 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
203 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
206 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
208 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
211 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
213 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
216 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
218 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
221 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
223 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
226 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
228 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
231 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
235 case DLL_PROCESS_ATTACH:
236 g_timer_q = CreateTimerQueue();
241 case DLL_PROCESS_DETACH:
242 DeleteCriticalSection(&g_sessions_lock);
248 /* From <dlls/mmdevapi/mmdevapi.h> */
249 enum DriverPriority {
250 Priority_Unavailable = 0,
256 int WINAPI AUDDRV_GetPriority(void)
261 /* Attempt to determine if we are running on OSS or ALSA's OSS
262 * compatibility layer. There is no official way to do that, so just check
263 * for validity as best as possible, without rejecting valid OSS
264 * implementations. */
266 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
268 TRACE("Priority_Unavailable: open failed\n");
269 return Priority_Unavailable;
272 sysinfo.version[0] = 0xFF;
273 sysinfo.versionnum = ~0;
274 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
275 TRACE("Priority_Unavailable: ioctl failed\n");
277 return Priority_Unavailable;
282 if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){
283 TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]);
286 if(sysinfo.versionnum & 0x80000000){
287 TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum);
291 TRACE("Priority_Preferred: Seems like valid OSS!\n");
293 return Priority_Preferred;
296 static const char *oss_clean_devnode(const char *devnode)
298 static char ret[OSS_DEVNODE_SIZE];
300 const char *dot, *slash;
303 dot = strrchr(devnode, '.');
307 slash = strrchr(devnode, '/');
308 if(slash && dot < slash)
313 memcpy(ret, devnode, len);
319 static UINT get_default_index(EDataFlow flow, char **keys, UINT num)
326 fd = open("/dev/dsp", O_WRONLY);
328 fd = open("/dev/dsp", O_RDONLY);
331 WARN("Couldn't open default device!\n");
336 if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){
337 WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno));
344 TRACE("Default devnode: %s\n", ai.devnode);
345 devnode = oss_clean_devnode(ai.devnode);
346 for(i = 0; i < num; ++i)
347 if(!strcmp(devnode, keys[i]))
350 WARN("Couldn't find default device! Choosing first.\n");
354 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, char ***keys,
355 UINT *num, UINT *def_index)
359 static int print_once = 0;
361 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
363 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
365 ERR("OSS /dev/mixer doesn't seem to exist\n");
366 return AUDCLNT_E_SERVICE_NOT_RUNNING;
369 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
373 ERR("OSS version too old, need at least OSSv4\n");
374 return AUDCLNT_E_SERVICE_NOT_RUNNING;
377 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
382 TRACE("OSS sysinfo:\n");
383 TRACE("product: %s\n", sysinfo.product);
384 TRACE("version: %s\n", sysinfo.version);
385 TRACE("versionnum: %x\n", sysinfo.versionnum);
386 TRACE("numaudios: %d\n", sysinfo.numaudios);
387 TRACE("nummixers: %d\n", sysinfo.nummixers);
388 TRACE("numcards: %d\n", sysinfo.numcards);
389 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
393 if(sysinfo.numaudios <= 0){
394 WARN("No audio devices!\n");
396 return AUDCLNT_E_SERVICE_NOT_RUNNING;
399 *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
400 *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
403 for(i = 0; i < sysinfo.numaudios; ++i){
404 oss_audioinfo ai = {0};
409 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
410 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
415 devnode = oss_clean_devnode(ai.devnode);
417 /* check for duplicates */
418 for(j = 0; j < *num; ++j)
419 if(!strcmp(devnode, (*keys)[j]))
425 fd = open(devnode, O_WRONLY, 0);
427 fd = open(devnode, O_RDONLY, 0);
429 WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n",
430 devnode, errno, strerror(errno));
435 if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
436 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
439 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
440 strlen(devnode) + 1);
442 for(i = 0; i < *num; ++i){
443 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
444 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
446 HeapFree(GetProcessHeap(), 0, *ids);
447 HeapFree(GetProcessHeap(), 0, *keys);
449 return E_OUTOFMEMORY;
451 strcpy((*keys)[*num], devnode);
453 len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
454 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
455 len * sizeof(WCHAR));
457 HeapFree(GetProcessHeap(), 0, (*keys)[*num]);
458 for(i = 0; i < *num; ++i){
459 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
460 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
462 HeapFree(GetProcessHeap(), 0, *ids);
463 HeapFree(GetProcessHeap(), 0, *keys);
465 return E_OUTOFMEMORY;
467 MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
476 *def_index = get_default_index(flow, *keys, *num);
481 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
482 EDataFlow dataflow, IAudioClient **out)
486 TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
488 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
490 return E_OUTOFMEMORY;
492 if(dataflow == eRender)
493 This->fd = open(devnode, O_WRONLY, 0);
494 else if(dataflow == eCapture)
495 This->fd = open(devnode, O_RDONLY, 0);
497 HeapFree(GetProcessHeap(), 0, This);
501 ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
503 HeapFree(GetProcessHeap(), 0, This);
504 return AUDCLNT_E_DEVICE_INVALIDATED;
507 This->dataflow = dataflow;
510 if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
511 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode,
512 errno, strerror(errno));
514 HeapFree(GetProcessHeap(), 0, This);
518 strcpy(This->devnode, devnode);
520 TRACE("OSS audioinfo:\n");
521 TRACE("devnode: %s\n", This->ai.devnode);
522 TRACE("name: %s\n", This->ai.name);
523 TRACE("busy: %x\n", This->ai.busy);
524 TRACE("caps: %x\n", This->ai.caps);
525 TRACE("iformats: %x\n", This->ai.iformats);
526 TRACE("oformats: %x\n", This->ai.oformats);
527 TRACE("enabled: %d\n", This->ai.enabled);
528 TRACE("min_rate: %d\n", This->ai.min_rate);
529 TRACE("max_rate: %d\n", This->ai.max_rate);
530 TRACE("min_channels: %d\n", This->ai.min_channels);
531 TRACE("max_channels: %d\n", This->ai.max_channels);
533 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
534 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
535 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
536 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
537 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
538 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
540 InitializeCriticalSection(&This->lock);
541 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ACImpl.lock");
544 IMMDevice_AddRef(This->parent);
546 IAudioClient_AddRef(&This->IAudioClient_iface);
548 *out = &This->IAudioClient_iface;
553 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
554 REFIID riid, void **ppv)
556 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
561 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
564 IUnknown_AddRef((IUnknown*)*ppv);
567 WARN("Unknown interface %s\n", debugstr_guid(riid));
568 return E_NOINTERFACE;
571 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
573 ACImpl *This = impl_from_IAudioClient(iface);
575 ref = InterlockedIncrement(&This->ref);
576 TRACE("(%p) Refcount now %u\n", This, ref);
580 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
582 ACImpl *This = impl_from_IAudioClient(iface);
584 ref = InterlockedDecrement(&This->ref);
585 TRACE("(%p) Refcount now %u\n", This, ref);
587 IAudioClient_Stop(iface);
588 IMMDevice_Release(This->parent);
589 This->lock.DebugInfo->Spare[0] = 0;
590 DeleteCriticalSection(&This->lock);
593 EnterCriticalSection(&g_sessions_lock);
594 list_remove(&This->entry);
595 LeaveCriticalSection(&g_sessions_lock);
597 HeapFree(GetProcessHeap(), 0, This->vols);
598 HeapFree(GetProcessHeap(), 0, This->local_buffer);
599 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
600 CoTaskMemFree(This->fmt);
601 HeapFree(GetProcessHeap(), 0, This);
606 static void dump_fmt(const WAVEFORMATEX *fmt)
608 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
609 switch(fmt->wFormatTag){
610 case WAVE_FORMAT_PCM:
611 TRACE("WAVE_FORMAT_PCM");
613 case WAVE_FORMAT_IEEE_FLOAT:
614 TRACE("WAVE_FORMAT_IEEE_FLOAT");
616 case WAVE_FORMAT_EXTENSIBLE:
617 TRACE("WAVE_FORMAT_EXTENSIBLE");
625 TRACE("nChannels: %u\n", fmt->nChannels);
626 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
627 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
628 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
629 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
630 TRACE("cbSize: %u\n", fmt->cbSize);
632 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
633 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
634 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
635 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
636 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
640 static DWORD get_channel_mask(unsigned int channels)
646 return KSAUDIO_SPEAKER_MONO;
648 return KSAUDIO_SPEAKER_STEREO;
650 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
652 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
654 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
656 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
658 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
660 return KSAUDIO_SPEAKER_7POINT1; /* not 7POINT1_SURROUND */
662 FIXME("Unknown speaker configuration: %u\n", channels);
666 static int get_oss_format(const WAVEFORMATEX *fmt)
668 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
670 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
671 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
672 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
673 switch(fmt->wBitsPerSample){
687 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
688 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
689 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
690 if(fmt->wBitsPerSample != 32)
700 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
705 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
706 size = sizeof(WAVEFORMATEXTENSIBLE);
708 size = sizeof(WAVEFORMATEX);
710 ret = CoTaskMemAlloc(size);
714 memcpy(ret, fmt, size);
716 ret->cbSize = size - sizeof(WAVEFORMATEX);
721 static HRESULT setup_oss_device(int fd, const WAVEFORMATEX *fmt,
722 WAVEFORMATEX **out, BOOL query)
727 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
728 WAVEFORMATEX *closest = NULL;
730 tmp = oss_format = get_oss_format(fmt);
732 return AUDCLNT_E_UNSUPPORTED_FORMAT;
733 if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
734 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
737 if(tmp != oss_format){
738 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
739 return AUDCLNT_E_UNSUPPORTED_FORMAT;
742 closest = clone_format(fmt);
744 return E_OUTOFMEMORY;
746 tmp = fmt->nSamplesPerSec;
747 if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){
748 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
749 CoTaskMemFree(closest);
752 tenth = fmt->nSamplesPerSec * 0.1;
753 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
755 closest->nSamplesPerSec = tmp;
758 tmp = fmt->nChannels;
759 if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
760 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
761 CoTaskMemFree(closest);
764 if(tmp != fmt->nChannels){
766 closest->nChannels = tmp;
769 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
770 DWORD mask = get_channel_mask(closest->nChannels);
772 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
774 if(query && fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
775 fmtex->dwChannelMask != 0 &&
776 fmtex->dwChannelMask != mask)
780 if(ret == S_FALSE && !out)
781 ret = AUDCLNT_E_UNSUPPORTED_FORMAT;
783 if(ret == S_FALSE && out){
784 closest->nBlockAlign =
785 closest->nChannels * closest->wBitsPerSample / 8;
786 closest->nAvgBytesPerSec =
787 closest->nBlockAlign * closest->nSamplesPerSec;
790 CoTaskMemFree(closest);
792 TRACE("returning: %08x\n", ret);
796 static void session_init_vols(AudioSession *session, UINT channels)
798 if(session->channel_count < channels){
801 if(session->channel_vols)
802 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
803 session->channel_vols, sizeof(float) * channels);
805 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
806 sizeof(float) * channels);
807 if(!session->channel_vols)
810 for(i = session->channel_count; i < channels; ++i)
811 session->channel_vols[i] = 1.f;
813 session->channel_count = channels;
817 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
822 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
826 memcpy(&ret->guid, guid, sizeof(GUID));
828 ret->device = device;
830 list_init(&ret->clients);
832 list_add_head(&g_sessions, &ret->entry);
834 InitializeCriticalSection(&ret->lock);
835 ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
837 session_init_vols(ret, num_channels);
839 ret->master_vol = 1.f;
844 /* if channels == 0, then this will return or create a session with
845 * matching dataflow and GUID. otherwise, channels must also match */
846 static HRESULT get_audio_session(const GUID *sessionguid,
847 IMMDevice *device, UINT channels, AudioSession **out)
849 AudioSession *session;
851 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
852 *out = create_session(&GUID_NULL, device, channels);
854 return E_OUTOFMEMORY;
860 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
861 if(session->device == device &&
862 IsEqualGUID(sessionguid, &session->guid)){
863 session_init_vols(session, channels);
870 *out = create_session(sessionguid, device, channels);
872 return E_OUTOFMEMORY;
878 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
879 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
880 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
881 const GUID *sessionguid)
883 ACImpl *This = impl_from_IAudioClient(iface);
887 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
888 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
895 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
896 return AUDCLNT_E_NOT_INITIALIZED;
898 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
899 AUDCLNT_STREAMFLAGS_LOOPBACK |
900 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
901 AUDCLNT_STREAMFLAGS_NOPERSIST |
902 AUDCLNT_STREAMFLAGS_RATEADJUST |
903 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
904 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
905 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
906 TRACE("Unknown flags: %08x\n", flags);
910 if(mode == AUDCLNT_SHAREMODE_SHARED){
911 period = DefaultPeriod;
912 if( duration < 3 * period)
913 duration = 3 * period;
916 period = DefaultPeriod; /* not minimum */
917 if(period < MinimumPeriod || period > 5000000)
918 return AUDCLNT_E_INVALID_DEVICE_PERIOD;
919 if(duration > 20000000) /* the smaller the period, the lower this limit */
920 return AUDCLNT_E_BUFFER_SIZE_ERROR;
921 if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){
922 if(duration != period)
923 return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL;
924 FIXME("EXCLUSIVE mode with EVENTCALLBACK\n");
925 return AUDCLNT_E_DEVICE_IN_USE;
927 if( duration < 8 * period)
928 duration = 8 * period; /* may grow above 2s */
932 EnterCriticalSection(&This->lock);
935 LeaveCriticalSection(&This->lock);
936 return AUDCLNT_E_ALREADY_INITIALIZED;
939 hr = setup_oss_device(This->fd, fmt, NULL, FALSE);
941 LeaveCriticalSection(&This->lock);
946 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
947 LeaveCriticalSection(&This->lock);
948 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
952 This->fmt = clone_format(fmt);
954 LeaveCriticalSection(&This->lock);
955 return E_OUTOFMEMORY;
958 This->period_us = period / 10;
960 This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
961 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
962 This->bufsize_frames * fmt->nBlockAlign);
963 if(!This->local_buffer){
964 CoTaskMemFree(This->fmt);
966 LeaveCriticalSection(&This->lock);
967 return E_OUTOFMEMORY;
970 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
972 CoTaskMemFree(This->fmt);
974 LeaveCriticalSection(&This->lock);
975 return E_OUTOFMEMORY;
978 for(i = 0; i < fmt->nChannels; ++i)
984 EnterCriticalSection(&g_sessions_lock);
986 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
989 LeaveCriticalSection(&g_sessions_lock);
990 HeapFree(GetProcessHeap(), 0, This->vols);
992 CoTaskMemFree(This->fmt);
994 LeaveCriticalSection(&This->lock);
998 list_add_tail(&This->session->clients, &This->entry);
1000 LeaveCriticalSection(&g_sessions_lock);
1002 This->initted = TRUE;
1004 LeaveCriticalSection(&This->lock);
1009 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1012 ACImpl *This = impl_from_IAudioClient(iface);
1014 TRACE("(%p)->(%p)\n", This, frames);
1019 EnterCriticalSection(&This->lock);
1022 LeaveCriticalSection(&This->lock);
1023 return AUDCLNT_E_NOT_INITIALIZED;
1026 *frames = This->bufsize_frames;
1028 LeaveCriticalSection(&This->lock);
1033 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1034 REFERENCE_TIME *latency)
1036 ACImpl *This = impl_from_IAudioClient(iface);
1038 TRACE("(%p)->(%p)\n", This, latency);
1043 EnterCriticalSection(&This->lock);
1046 LeaveCriticalSection(&This->lock);
1047 return AUDCLNT_E_NOT_INITIALIZED;
1050 /* pretend we process audio in Period chunks, so max latency includes
1051 * the period time. Some native machines add .6666ms in shared mode. */
1052 *latency = This->period_us * 10 + 6666;
1054 LeaveCriticalSection(&This->lock);
1059 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1062 ACImpl *This = impl_from_IAudioClient(iface);
1065 TRACE("(%p)->(%p)\n", This, numpad);
1070 EnterCriticalSection(&This->lock);
1073 LeaveCriticalSection(&This->lock);
1074 return AUDCLNT_E_NOT_INITIALIZED;
1077 if(This->dataflow == eRender){
1078 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1079 LeaveCriticalSection(&This->lock);
1080 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1084 *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
1085 This->fmt->nBlockAlign;
1087 /* when the OSS buffer has less than one fragment of data, including
1088 * no data, it often reports it as some non-zero portion of a
1089 * fragment. when it has more than one fragment of data, it reports
1090 * it as some multiple of that portion of the fragment size.
1092 * so, we have to do some ugly workarounds to report the timing
1093 * as accurately as possible */
1094 if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
1095 *numpad = This->inbuf_frames;
1096 This->inbuf_frames = 0;
1098 if(*numpad < This->inbuf_frames)
1099 This->inbuf_frames = *numpad;
1101 *numpad = This->inbuf_frames;
1103 }else if(This->dataflow == eCapture){
1104 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1105 LeaveCriticalSection(&This->lock);
1106 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1110 if(bi.bytes <= bi.fragsize)
1113 *numpad = bi.bytes / This->fmt->nBlockAlign;
1115 LeaveCriticalSection(&This->lock);
1116 return E_UNEXPECTED;
1119 *numpad += This->held_frames;
1121 LeaveCriticalSection(&This->lock);
1126 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1127 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1128 WAVEFORMATEX **outpwfx)
1130 ACImpl *This = impl_from_IAudioClient(iface);
1134 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1136 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1139 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1140 return E_INVALIDARG;
1142 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1143 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1144 return E_INVALIDARG;
1150 if(mode != AUDCLNT_SHAREMODE_SHARED)
1154 if(This->dataflow == eRender)
1155 fd = open(This->devnode, O_WRONLY, 0);
1156 else if(This->dataflow == eCapture)
1157 fd = open(This->devnode, O_RDONLY, 0);
1160 ERR("Unable to open device %s: %d (%s)\n", This->devnode, errno,
1162 return AUDCLNT_E_DEVICE_INVALIDATED;
1165 ret = setup_oss_device(fd, pwfx, outpwfx, TRUE);
1172 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1173 WAVEFORMATEX **pwfx)
1175 ACImpl *This = impl_from_IAudioClient(iface);
1176 WAVEFORMATEXTENSIBLE *fmt;
1179 TRACE("(%p)->(%p)\n", This, pwfx);
1185 if(This->dataflow == eRender)
1186 formats = This->ai.oformats;
1187 else if(This->dataflow == eCapture)
1188 formats = This->ai.iformats;
1190 return E_UNEXPECTED;
1192 fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1194 return E_OUTOFMEMORY;
1196 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1197 if(formats & AFMT_S16_LE){
1198 fmt->Format.wBitsPerSample = 16;
1199 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1201 }else if(formats & AFMT_FLOAT){
1202 fmt->Format.wBitsPerSample = 32;
1203 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1205 }else if(formats & AFMT_U8){
1206 fmt->Format.wBitsPerSample = 8;
1207 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1208 }else if(formats & AFMT_S32_LE){
1209 fmt->Format.wBitsPerSample = 32;
1210 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1211 }else if(formats & AFMT_S24_LE){
1212 fmt->Format.wBitsPerSample = 24;
1213 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1215 ERR("Didn't recognize any available OSS formats: %x\n", formats);
1220 fmt->Format.nChannels = This->ai.max_channels;
1221 fmt->Format.nSamplesPerSec = This->ai.max_rate;
1222 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1224 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1225 fmt->Format.nChannels) / 8;
1226 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1227 fmt->Format.nBlockAlign;
1229 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1230 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1232 *pwfx = (WAVEFORMATEX*)fmt;
1238 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1239 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1241 ACImpl *This = impl_from_IAudioClient(iface);
1243 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1245 if(!defperiod && !minperiod)
1249 *defperiod = DefaultPeriod;
1251 *minperiod = MinimumPeriod;
1256 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1258 if(This->fmt->wBitsPerSample == 8)
1259 memset(buf, 128, frames * This->fmt->nBlockAlign);
1261 memset(buf, 0, frames * This->fmt->nBlockAlign);
1264 static void oss_write_data(ACImpl *This)
1266 ssize_t written_bytes;
1267 UINT32 written_frames;
1268 size_t to_write_frames, to_write_bytes;
1271 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1273 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1274 to_write_frames = This->bufsize_frames - This->lcl_offs_frames;
1276 to_write_frames = This->held_frames;
1277 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1279 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
1280 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
1284 if(bi.bytes < to_write_bytes){
1285 to_write_frames = bi.bytes / This->fmt->nBlockAlign;
1286 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1289 if(This->session->mute)
1290 oss_silence_buffer(This, buf, to_write_frames);
1292 written_bytes = write(This->fd, buf, to_write_bytes);
1293 if(written_bytes < 0){
1294 /* EAGAIN is OSS buffer full, log that too */
1295 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1298 written_frames = written_bytes / This->fmt->nBlockAlign;
1300 This->lcl_offs_frames += written_frames;
1301 This->lcl_offs_frames %= This->bufsize_frames;
1302 This->held_frames -= written_frames;
1303 This->inbuf_frames += written_frames;
1305 if(written_frames < to_write_frames){
1306 /* OSS buffer probably full */
1310 bi.bytes -= written_bytes;
1311 if(This->held_frames && bi.bytes >= This->fmt->nBlockAlign){
1312 /* wrapped and have some data back at the start to write */
1314 to_write_frames = bi.bytes / This->fmt->nBlockAlign;
1315 to_write_bytes = to_write_frames * This->fmt->nBlockAlign;
1317 if(This->session->mute)
1318 oss_silence_buffer(This, This->local_buffer, to_write_frames);
1320 written_bytes = write(This->fd, This->local_buffer, to_write_bytes);
1321 if(written_bytes < 0){
1322 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1325 written_frames = written_bytes / This->fmt->nBlockAlign;
1327 This->lcl_offs_frames += written_frames;
1328 This->lcl_offs_frames %= This->bufsize_frames;
1329 This->held_frames -= written_frames;
1330 This->inbuf_frames += written_frames;
1334 static void oss_read_data(ACImpl *This)
1336 UINT64 pos, readable;
1340 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1341 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1345 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1346 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1348 if(bi.bytes < readable)
1349 readable = bi.bytes;
1351 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1354 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1358 This->held_frames += nread / This->fmt->nBlockAlign;
1360 if(This->held_frames > This->bufsize_frames){
1361 WARN("Overflow of unread data\n");
1362 This->lcl_offs_frames += This->held_frames;
1363 This->lcl_offs_frames %= This->bufsize_frames;
1364 This->held_frames = This->bufsize_frames;
1368 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1370 ACImpl *This = user;
1372 EnterCriticalSection(&This->lock);
1374 if(This->dataflow == eRender && This->held_frames)
1375 oss_write_data(This);
1376 else if(This->dataflow == eCapture)
1377 oss_read_data(This);
1380 SetEvent(This->event);
1382 LeaveCriticalSection(&This->lock);
1385 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1387 ACImpl *This = impl_from_IAudioClient(iface);
1390 TRACE("(%p)\n", This);
1392 EnterCriticalSection(&This->lock);
1395 LeaveCriticalSection(&This->lock);
1396 return AUDCLNT_E_NOT_INITIALIZED;
1399 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1400 LeaveCriticalSection(&This->lock);
1401 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1405 LeaveCriticalSection(&This->lock);
1406 return AUDCLNT_E_NOT_STOPPED;
1409 if(This->dataflow == eRender)
1410 mask = PCM_ENABLE_OUTPUT;
1411 else if(This->dataflow == eCapture)
1412 mask = PCM_ENABLE_INPUT;
1414 LeaveCriticalSection(&This->lock);
1415 return E_UNEXPECTED;
1418 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1419 LeaveCriticalSection(&This->lock);
1420 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1424 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1425 oss_period_callback, This, 0, This->period_us / 1000,
1426 WT_EXECUTEINTIMERTHREAD))
1427 ERR("Unable to create period timer: %u\n", GetLastError());
1429 This->playing = TRUE;
1431 LeaveCriticalSection(&This->lock);
1436 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1438 ACImpl *This = impl_from_IAudioClient(iface);
1441 TRACE("(%p)\n", This);
1443 EnterCriticalSection(&This->lock);
1446 LeaveCriticalSection(&This->lock);
1447 return AUDCLNT_E_NOT_INITIALIZED;
1451 LeaveCriticalSection(&This->lock);
1455 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1456 DeleteTimerQueueTimer(g_timer_q, This->timer,
1457 INVALID_HANDLE_VALUE);
1461 if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1462 LeaveCriticalSection(&This->lock);
1463 WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1468 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1469 LeaveCriticalSection(&This->lock);
1470 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1474 This->playing = FALSE;
1476 LeaveCriticalSection(&This->lock);
1481 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1483 ACImpl *This = impl_from_IAudioClient(iface);
1485 TRACE("(%p)\n", This);
1487 EnterCriticalSection(&This->lock);
1490 LeaveCriticalSection(&This->lock);
1491 return AUDCLNT_E_NOT_INITIALIZED;
1495 LeaveCriticalSection(&This->lock);
1496 return AUDCLNT_E_NOT_STOPPED;
1499 if(This->buf_state != NOT_LOCKED || This->getbuf_last){
1500 LeaveCriticalSection(&This->lock);
1501 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1504 This->written_frames = 0;
1505 This->inbuf_frames = 0;
1506 This->held_frames = 0;
1508 if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1509 WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1511 LeaveCriticalSection(&This->lock);
1516 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1519 ACImpl *This = impl_from_IAudioClient(iface);
1521 TRACE("(%p)->(%p)\n", This, event);
1524 return E_INVALIDARG;
1526 EnterCriticalSection(&This->lock);
1529 LeaveCriticalSection(&This->lock);
1530 return AUDCLNT_E_NOT_INITIALIZED;
1533 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1534 LeaveCriticalSection(&This->lock);
1535 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1538 This->event = event;
1540 LeaveCriticalSection(&This->lock);
1545 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1548 ACImpl *This = impl_from_IAudioClient(iface);
1550 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1556 EnterCriticalSection(&This->lock);
1559 LeaveCriticalSection(&This->lock);
1560 return AUDCLNT_E_NOT_INITIALIZED;
1563 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1564 if(This->dataflow != eRender){
1565 LeaveCriticalSection(&This->lock);
1566 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1568 IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1569 *ppv = &This->IAudioRenderClient_iface;
1570 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1571 if(This->dataflow != eCapture){
1572 LeaveCriticalSection(&This->lock);
1573 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1575 IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1576 *ppv = &This->IAudioCaptureClient_iface;
1577 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1578 IAudioClock_AddRef(&This->IAudioClock_iface);
1579 *ppv = &This->IAudioClock_iface;
1580 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1581 IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1582 *ppv = &This->IAudioStreamVolume_iface;
1583 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1584 if(!This->session_wrapper){
1585 This->session_wrapper = AudioSessionWrapper_Create(This);
1586 if(!This->session_wrapper){
1587 LeaveCriticalSection(&This->lock);
1588 return E_OUTOFMEMORY;
1591 IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1593 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1594 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1595 if(!This->session_wrapper){
1596 This->session_wrapper = AudioSessionWrapper_Create(This);
1597 if(!This->session_wrapper){
1598 LeaveCriticalSection(&This->lock);
1599 return E_OUTOFMEMORY;
1602 IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1604 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1605 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1606 if(!This->session_wrapper){
1607 This->session_wrapper = AudioSessionWrapper_Create(This);
1608 if(!This->session_wrapper){
1609 LeaveCriticalSection(&This->lock);
1610 return E_OUTOFMEMORY;
1613 ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1615 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1619 LeaveCriticalSection(&This->lock);
1623 LeaveCriticalSection(&This->lock);
1625 FIXME("stub %s\n", debugstr_guid(riid));
1626 return E_NOINTERFACE;
1629 static const IAudioClientVtbl AudioClient_Vtbl =
1631 AudioClient_QueryInterface,
1633 AudioClient_Release,
1634 AudioClient_Initialize,
1635 AudioClient_GetBufferSize,
1636 AudioClient_GetStreamLatency,
1637 AudioClient_GetCurrentPadding,
1638 AudioClient_IsFormatSupported,
1639 AudioClient_GetMixFormat,
1640 AudioClient_GetDevicePeriod,
1644 AudioClient_SetEventHandle,
1645 AudioClient_GetService
1648 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1649 IAudioRenderClient *iface, REFIID riid, void **ppv)
1651 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1657 if(IsEqualIID(riid, &IID_IUnknown) ||
1658 IsEqualIID(riid, &IID_IAudioRenderClient))
1661 IUnknown_AddRef((IUnknown*)*ppv);
1665 WARN("Unknown interface %s\n", debugstr_guid(riid));
1666 return E_NOINTERFACE;
1669 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1671 ACImpl *This = impl_from_IAudioRenderClient(iface);
1672 return AudioClient_AddRef(&This->IAudioClient_iface);
1675 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1677 ACImpl *This = impl_from_IAudioRenderClient(iface);
1678 return AudioClient_Release(&This->IAudioClient_iface);
1681 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1682 UINT32 frames, BYTE **data)
1684 ACImpl *This = impl_from_IAudioRenderClient(iface);
1685 UINT32 pad, write_pos;
1688 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1695 EnterCriticalSection(&This->lock);
1697 if(This->getbuf_last){
1698 LeaveCriticalSection(&This->lock);
1699 return AUDCLNT_E_OUT_OF_ORDER;
1703 LeaveCriticalSection(&This->lock);
1707 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1709 LeaveCriticalSection(&This->lock);
1713 if(pad + frames > This->bufsize_frames){
1714 LeaveCriticalSection(&This->lock);
1715 return AUDCLNT_E_BUFFER_TOO_LARGE;
1719 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1720 if(write_pos + frames > This->bufsize_frames){
1721 if(This->tmp_buffer_frames < frames){
1722 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1723 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1724 frames * This->fmt->nBlockAlign);
1725 if(!This->tmp_buffer){
1726 LeaveCriticalSection(&This->lock);
1727 return E_OUTOFMEMORY;
1729 This->tmp_buffer_frames = frames;
1731 *data = This->tmp_buffer;
1732 This->getbuf_last = -frames;
1734 *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1735 This->getbuf_last = frames;
1738 LeaveCriticalSection(&This->lock);
1743 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1745 UINT32 write_offs_frames =
1746 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1747 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1748 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1749 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1750 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1752 if(written_bytes <= chunk_bytes){
1753 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1755 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1756 memcpy(This->local_buffer, buffer + chunk_bytes,
1757 written_bytes - chunk_bytes);
1761 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1762 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1764 ACImpl *This = impl_from_IAudioRenderClient(iface);
1767 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1769 EnterCriticalSection(&This->lock);
1771 if(!written_frames){
1772 This->getbuf_last = 0;
1773 LeaveCriticalSection(&This->lock);
1777 if(!This->getbuf_last){
1778 LeaveCriticalSection(&This->lock);
1779 return AUDCLNT_E_OUT_OF_ORDER;
1782 if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1783 LeaveCriticalSection(&This->lock);
1784 return AUDCLNT_E_INVALID_SIZE;
1787 if(This->getbuf_last >= 0)
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->getbuf_last < 0)
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->getbuf_last = 0;
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->getbuf_last < 0)
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->getbuf_last = 0;
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 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1914 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1915 *frames * This->fmt->nBlockAlign);
1916 if(!This->tmp_buffer){
1917 LeaveCriticalSection(&This->lock);
1918 return E_OUTOFMEMORY;
1920 This->tmp_buffer_frames = *frames;
1923 *data = This->tmp_buffer;
1924 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1925 This->fmt->nBlockAlign;
1926 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1927 frames_bytes = *frames * This->fmt->nBlockAlign;
1928 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1929 memcpy(This->tmp_buffer, This->local_buffer,
1930 frames_bytes - chunk_bytes);
1932 *data = This->local_buffer +
1933 This->lcl_offs_frames * This->fmt->nBlockAlign;
1935 This->buf_state = LOCKED_NORMAL;
1937 if(devpos || qpcpos)
1938 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1940 LeaveCriticalSection(&This->lock);
1942 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1945 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1946 IAudioCaptureClient *iface, UINT32 done)
1948 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1950 TRACE("(%p)->(%u)\n", This, done);
1952 EnterCriticalSection(&This->lock);
1954 if(This->buf_state == NOT_LOCKED){
1955 LeaveCriticalSection(&This->lock);
1956 return AUDCLNT_E_OUT_OF_ORDER;
1959 This->held_frames -= done;
1960 This->lcl_offs_frames += done;
1961 This->lcl_offs_frames %= This->bufsize_frames;
1963 This->buf_state = NOT_LOCKED;
1965 LeaveCriticalSection(&This->lock);
1970 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1971 IAudioCaptureClient *iface, UINT32 *frames)
1973 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1975 TRACE("(%p)->(%p)\n", This, frames);
1977 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1980 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1982 AudioCaptureClient_QueryInterface,
1983 AudioCaptureClient_AddRef,
1984 AudioCaptureClient_Release,
1985 AudioCaptureClient_GetBuffer,
1986 AudioCaptureClient_ReleaseBuffer,
1987 AudioCaptureClient_GetNextPacketSize
1990 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1991 REFIID riid, void **ppv)
1993 ACImpl *This = impl_from_IAudioClock(iface);
1995 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2001 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2003 else if(IsEqualIID(riid, &IID_IAudioClock2))
2004 *ppv = &This->IAudioClock2_iface;
2006 IUnknown_AddRef((IUnknown*)*ppv);
2010 WARN("Unknown interface %s\n", debugstr_guid(riid));
2011 return E_NOINTERFACE;
2014 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2016 ACImpl *This = impl_from_IAudioClock(iface);
2017 return IAudioClient_AddRef(&This->IAudioClient_iface);
2020 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2022 ACImpl *This = impl_from_IAudioClock(iface);
2023 return IAudioClient_Release(&This->IAudioClient_iface);
2026 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2028 ACImpl *This = impl_from_IAudioClock(iface);
2030 TRACE("(%p)->(%p)\n", This, freq);
2032 *freq = This->fmt->nSamplesPerSec;
2037 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2040 ACImpl *This = impl_from_IAudioClock(iface);
2044 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2049 EnterCriticalSection(&This->lock);
2051 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
2053 LeaveCriticalSection(&This->lock);
2057 if(This->dataflow == eRender)
2058 *pos = This->written_frames - pad;
2059 else if(This->dataflow == eCapture)
2060 *pos = This->written_frames + pad;
2062 LeaveCriticalSection(&This->lock);
2065 LARGE_INTEGER stamp, freq;
2066 QueryPerformanceCounter(&stamp);
2067 QueryPerformanceFrequency(&freq);
2068 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2074 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2077 ACImpl *This = impl_from_IAudioClock(iface);
2079 TRACE("(%p)->(%p)\n", This, chars);
2084 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2089 static const IAudioClockVtbl AudioClock_Vtbl =
2091 AudioClock_QueryInterface,
2094 AudioClock_GetFrequency,
2095 AudioClock_GetPosition,
2096 AudioClock_GetCharacteristics
2099 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2100 REFIID riid, void **ppv)
2102 ACImpl *This = impl_from_IAudioClock2(iface);
2103 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2106 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2108 ACImpl *This = impl_from_IAudioClock2(iface);
2109 return IAudioClient_AddRef(&This->IAudioClient_iface);
2112 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2114 ACImpl *This = impl_from_IAudioClock2(iface);
2115 return IAudioClient_Release(&This->IAudioClient_iface);
2118 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2119 UINT64 *pos, UINT64 *qpctime)
2121 ACImpl *This = impl_from_IAudioClock2(iface);
2123 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2128 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2130 AudioClock2_QueryInterface,
2132 AudioClock2_Release,
2133 AudioClock2_GetDevicePosition
2136 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2138 AudioSessionWrapper *ret;
2140 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2141 sizeof(AudioSessionWrapper));
2145 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2146 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2147 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2151 ret->client = client;
2153 ret->session = client->session;
2154 AudioClient_AddRef(&client->IAudioClient_iface);
2160 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2161 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2163 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2169 if(IsEqualIID(riid, &IID_IUnknown) ||
2170 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2171 IsEqualIID(riid, &IID_IAudioSessionControl2))
2174 IUnknown_AddRef((IUnknown*)*ppv);
2178 WARN("Unknown interface %s\n", debugstr_guid(riid));
2179 return E_NOINTERFACE;
2182 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2184 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2186 ref = InterlockedIncrement(&This->ref);
2187 TRACE("(%p) Refcount now %u\n", This, ref);
2191 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2193 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2195 ref = InterlockedDecrement(&This->ref);
2196 TRACE("(%p) Refcount now %u\n", This, ref);
2199 EnterCriticalSection(&This->client->lock);
2200 This->client->session_wrapper = NULL;
2201 LeaveCriticalSection(&This->client->lock);
2202 AudioClient_Release(&This->client->IAudioClient_iface);
2204 HeapFree(GetProcessHeap(), 0, This);
2209 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2210 AudioSessionState *state)
2212 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2215 TRACE("(%p)->(%p)\n", This, state);
2218 return NULL_PTR_ERR;
2220 EnterCriticalSection(&g_sessions_lock);
2222 if(list_empty(&This->session->clients)){
2223 *state = AudioSessionStateExpired;
2224 LeaveCriticalSection(&g_sessions_lock);
2228 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2229 EnterCriticalSection(&client->lock);
2230 if(client->playing){
2231 *state = AudioSessionStateActive;
2232 LeaveCriticalSection(&client->lock);
2233 LeaveCriticalSection(&g_sessions_lock);
2236 LeaveCriticalSection(&client->lock);
2239 LeaveCriticalSection(&g_sessions_lock);
2241 *state = AudioSessionStateInactive;
2246 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2247 IAudioSessionControl2 *iface, WCHAR **name)
2249 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2251 FIXME("(%p)->(%p) - stub\n", This, name);
2256 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2257 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2259 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2261 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2266 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2267 IAudioSessionControl2 *iface, WCHAR **path)
2269 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2271 FIXME("(%p)->(%p) - stub\n", This, path);
2276 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2277 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2279 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2281 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2286 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2287 IAudioSessionControl2 *iface, GUID *group)
2289 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2291 FIXME("(%p)->(%p) - stub\n", This, group);
2296 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2297 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2299 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2301 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2302 debugstr_guid(session));
2307 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2308 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2310 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2312 FIXME("(%p)->(%p) - stub\n", This, events);
2317 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2318 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2320 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2322 FIXME("(%p)->(%p) - stub\n", This, events);
2327 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2328 IAudioSessionControl2 *iface, WCHAR **id)
2330 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2332 FIXME("(%p)->(%p) - stub\n", This, id);
2337 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2338 IAudioSessionControl2 *iface, WCHAR **id)
2340 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2342 FIXME("(%p)->(%p) - stub\n", This, id);
2347 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2348 IAudioSessionControl2 *iface, DWORD *pid)
2350 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2352 TRACE("(%p)->(%p)\n", This, pid);
2357 *pid = GetCurrentProcessId();
2362 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2363 IAudioSessionControl2 *iface)
2365 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2367 TRACE("(%p)\n", This);
2372 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2373 IAudioSessionControl2 *iface, BOOL optout)
2375 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2377 TRACE("(%p)->(%d)\n", This, optout);
2382 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2384 AudioSessionControl_QueryInterface,
2385 AudioSessionControl_AddRef,
2386 AudioSessionControl_Release,
2387 AudioSessionControl_GetState,
2388 AudioSessionControl_GetDisplayName,
2389 AudioSessionControl_SetDisplayName,
2390 AudioSessionControl_GetIconPath,
2391 AudioSessionControl_SetIconPath,
2392 AudioSessionControl_GetGroupingParam,
2393 AudioSessionControl_SetGroupingParam,
2394 AudioSessionControl_RegisterAudioSessionNotification,
2395 AudioSessionControl_UnregisterAudioSessionNotification,
2396 AudioSessionControl_GetSessionIdentifier,
2397 AudioSessionControl_GetSessionInstanceIdentifier,
2398 AudioSessionControl_GetProcessId,
2399 AudioSessionControl_IsSystemSoundsSession,
2400 AudioSessionControl_SetDuckingPreference
2403 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2404 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2406 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2412 if(IsEqualIID(riid, &IID_IUnknown) ||
2413 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2416 IUnknown_AddRef((IUnknown*)*ppv);
2420 WARN("Unknown interface %s\n", debugstr_guid(riid));
2421 return E_NOINTERFACE;
2424 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2426 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2427 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2430 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2432 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2433 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2436 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2437 ISimpleAudioVolume *iface, float level, const GUID *context)
2439 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2440 AudioSession *session = This->session;
2442 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2444 if(level < 0.f || level > 1.f)
2445 return E_INVALIDARG;
2448 FIXME("Notifications not supported yet\n");
2450 EnterCriticalSection(&session->lock);
2452 session->master_vol = level;
2454 TRACE("OSS doesn't support setting volume\n");
2456 LeaveCriticalSection(&session->lock);
2461 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2462 ISimpleAudioVolume *iface, float *level)
2464 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2465 AudioSession *session = This->session;
2467 TRACE("(%p)->(%p)\n", session, level);
2470 return NULL_PTR_ERR;
2472 *level = session->master_vol;
2477 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2478 BOOL mute, const GUID *context)
2480 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2481 AudioSession *session = This->session;
2483 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2485 EnterCriticalSection(&session->lock);
2487 if(!mute && session->mute){
2490 session->mute = mute;
2492 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2493 EnterCriticalSection(&client->lock);
2494 if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2495 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2497 oss_write_data(client);
2498 LeaveCriticalSection(&client->lock);
2501 session->mute = mute;
2503 LeaveCriticalSection(&session->lock);
2508 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2511 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2512 AudioSession *session = This->session;
2514 TRACE("(%p)->(%p)\n", session, mute);
2517 return NULL_PTR_ERR;
2519 *mute = This->session->mute;
2524 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2526 SimpleAudioVolume_QueryInterface,
2527 SimpleAudioVolume_AddRef,
2528 SimpleAudioVolume_Release,
2529 SimpleAudioVolume_SetMasterVolume,
2530 SimpleAudioVolume_GetMasterVolume,
2531 SimpleAudioVolume_SetMute,
2532 SimpleAudioVolume_GetMute
2535 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2536 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2538 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2544 if(IsEqualIID(riid, &IID_IUnknown) ||
2545 IsEqualIID(riid, &IID_IAudioStreamVolume))
2548 IUnknown_AddRef((IUnknown*)*ppv);
2552 WARN("Unknown interface %s\n", debugstr_guid(riid));
2553 return E_NOINTERFACE;
2556 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2558 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2559 return IAudioClient_AddRef(&This->IAudioClient_iface);
2562 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2564 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2565 return IAudioClient_Release(&This->IAudioClient_iface);
2568 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2569 IAudioStreamVolume *iface, UINT32 *out)
2571 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2573 TRACE("(%p)->(%p)\n", This, out);
2578 *out = This->fmt->nChannels;
2583 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2584 IAudioStreamVolume *iface, UINT32 index, float level)
2586 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2588 TRACE("(%p)->(%d, %f)\n", This, index, level);
2590 if(level < 0.f || level > 1.f)
2591 return E_INVALIDARG;
2593 if(index >= This->fmt->nChannels)
2594 return E_INVALIDARG;
2596 EnterCriticalSection(&This->lock);
2598 This->vols[index] = level;
2600 TRACE("OSS doesn't support setting volume\n");
2602 LeaveCriticalSection(&This->lock);
2607 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2608 IAudioStreamVolume *iface, UINT32 index, float *level)
2610 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2612 TRACE("(%p)->(%d, %p)\n", This, index, level);
2617 if(index >= This->fmt->nChannels)
2618 return E_INVALIDARG;
2620 *level = This->vols[index];
2625 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2626 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2628 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2631 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2636 if(count != This->fmt->nChannels)
2637 return E_INVALIDARG;
2639 EnterCriticalSection(&This->lock);
2641 for(i = 0; i < count; ++i)
2642 This->vols[i] = levels[i];
2644 TRACE("OSS doesn't support setting volume\n");
2646 LeaveCriticalSection(&This->lock);
2651 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2652 IAudioStreamVolume *iface, UINT32 count, float *levels)
2654 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2657 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2662 if(count != This->fmt->nChannels)
2663 return E_INVALIDARG;
2665 EnterCriticalSection(&This->lock);
2667 for(i = 0; i < count; ++i)
2668 levels[i] = This->vols[i];
2670 LeaveCriticalSection(&This->lock);
2675 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2677 AudioStreamVolume_QueryInterface,
2678 AudioStreamVolume_AddRef,
2679 AudioStreamVolume_Release,
2680 AudioStreamVolume_GetChannelCount,
2681 AudioStreamVolume_SetChannelVolume,
2682 AudioStreamVolume_GetChannelVolume,
2683 AudioStreamVolume_SetAllVolumes,
2684 AudioStreamVolume_GetAllVolumes
2687 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2688 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2690 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2696 if(IsEqualIID(riid, &IID_IUnknown) ||
2697 IsEqualIID(riid, &IID_IChannelAudioVolume))
2700 IUnknown_AddRef((IUnknown*)*ppv);
2704 WARN("Unknown interface %s\n", debugstr_guid(riid));
2705 return E_NOINTERFACE;
2708 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2710 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2711 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2714 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2716 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2717 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2720 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2721 IChannelAudioVolume *iface, UINT32 *out)
2723 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2724 AudioSession *session = This->session;
2726 TRACE("(%p)->(%p)\n", session, out);
2729 return NULL_PTR_ERR;
2731 *out = session->channel_count;
2736 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2737 IChannelAudioVolume *iface, UINT32 index, float level,
2738 const GUID *context)
2740 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2741 AudioSession *session = This->session;
2743 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2744 wine_dbgstr_guid(context));
2746 if(level < 0.f || level > 1.f)
2747 return E_INVALIDARG;
2749 if(index >= session->channel_count)
2750 return E_INVALIDARG;
2753 FIXME("Notifications not supported yet\n");
2755 EnterCriticalSection(&session->lock);
2757 session->channel_vols[index] = level;
2759 TRACE("OSS doesn't support setting volume\n");
2761 LeaveCriticalSection(&session->lock);
2766 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2767 IChannelAudioVolume *iface, UINT32 index, float *level)
2769 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2770 AudioSession *session = This->session;
2772 TRACE("(%p)->(%d, %p)\n", session, index, level);
2775 return NULL_PTR_ERR;
2777 if(index >= session->channel_count)
2778 return E_INVALIDARG;
2780 *level = session->channel_vols[index];
2785 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2786 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2787 const GUID *context)
2789 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2790 AudioSession *session = This->session;
2793 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2794 wine_dbgstr_guid(context));
2797 return NULL_PTR_ERR;
2799 if(count != session->channel_count)
2800 return E_INVALIDARG;
2803 FIXME("Notifications not supported yet\n");
2805 EnterCriticalSection(&session->lock);
2807 for(i = 0; i < count; ++i)
2808 session->channel_vols[i] = levels[i];
2810 TRACE("OSS doesn't support setting volume\n");
2812 LeaveCriticalSection(&session->lock);
2817 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2818 IChannelAudioVolume *iface, UINT32 count, float *levels)
2820 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2821 AudioSession *session = This->session;
2824 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2827 return NULL_PTR_ERR;
2829 if(count != session->channel_count)
2830 return E_INVALIDARG;
2832 for(i = 0; i < count; ++i)
2833 levels[i] = session->channel_vols[i];
2838 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2840 ChannelAudioVolume_QueryInterface,
2841 ChannelAudioVolume_AddRef,
2842 ChannelAudioVolume_Release,
2843 ChannelAudioVolume_GetChannelCount,
2844 ChannelAudioVolume_SetChannelVolume,
2845 ChannelAudioVolume_GetChannelVolume,
2846 ChannelAudioVolume_SetAllVolumes,
2847 ChannelAudioVolume_GetAllVolumes
2850 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2851 REFIID riid, void **ppv)
2853 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2859 if(IsEqualIID(riid, &IID_IUnknown) ||
2860 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2861 IsEqualIID(riid, &IID_IAudioSessionManager2))
2864 IUnknown_AddRef((IUnknown*)*ppv);
2868 WARN("Unknown interface %s\n", debugstr_guid(riid));
2869 return E_NOINTERFACE;
2872 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2874 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2876 ref = InterlockedIncrement(&This->ref);
2877 TRACE("(%p) Refcount now %u\n", This, ref);
2881 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2883 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2885 ref = InterlockedDecrement(&This->ref);
2886 TRACE("(%p) Refcount now %u\n", This, ref);
2888 HeapFree(GetProcessHeap(), 0, This);
2892 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2893 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2894 IAudioSessionControl **out)
2896 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2897 AudioSession *session;
2898 AudioSessionWrapper *wrapper;
2901 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2904 hr = get_audio_session(session_guid, This->device, 0, &session);
2908 wrapper = AudioSessionWrapper_Create(NULL);
2910 return E_OUTOFMEMORY;
2912 wrapper->session = session;
2914 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2919 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2920 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2921 ISimpleAudioVolume **out)
2923 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2924 AudioSession *session;
2925 AudioSessionWrapper *wrapper;
2928 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2931 hr = get_audio_session(session_guid, This->device, 0, &session);
2935 wrapper = AudioSessionWrapper_Create(NULL);
2937 return E_OUTOFMEMORY;
2939 wrapper->session = session;
2941 *out = &wrapper->ISimpleAudioVolume_iface;
2946 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2947 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2949 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2950 FIXME("(%p)->(%p) - stub\n", This, out);
2954 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2955 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2957 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2958 FIXME("(%p)->(%p) - stub\n", This, notification);
2962 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2963 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2965 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2966 FIXME("(%p)->(%p) - stub\n", This, notification);
2970 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2971 IAudioSessionManager2 *iface, const WCHAR *session_id,
2972 IAudioVolumeDuckNotification *notification)
2974 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2975 FIXME("(%p)->(%p) - stub\n", This, notification);
2979 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2980 IAudioSessionManager2 *iface,
2981 IAudioVolumeDuckNotification *notification)
2983 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2984 FIXME("(%p)->(%p) - stub\n", This, notification);
2988 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2990 AudioSessionManager_QueryInterface,
2991 AudioSessionManager_AddRef,
2992 AudioSessionManager_Release,
2993 AudioSessionManager_GetAudioSessionControl,
2994 AudioSessionManager_GetSimpleAudioVolume,
2995 AudioSessionManager_GetSessionEnumerator,
2996 AudioSessionManager_RegisterSessionNotification,
2997 AudioSessionManager_UnregisterSessionNotification,
2998 AudioSessionManager_RegisterDuckNotification,
2999 AudioSessionManager_UnregisterDuckNotification
3002 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3003 IAudioSessionManager2 **out)
3007 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3009 return E_OUTOFMEMORY;
3011 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3012 This->device = device;
3015 *out = &This->IAudioSessionManager2_iface;