2 * Copyright 2011 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
29 #include <sys/types.h>
31 #include <sys/ioctl.h>
35 #include <sys/soundcard.h>
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
46 #include "mmdeviceapi.h"
50 #include "endpointvolume.h"
53 #include "audiopolicy.h"
54 #include "audioclient.h"
57 /* Some implementations of OSS, such as FreeBSD older than 9.0, lack
58 SNDCTL_DSP_HALT which is just a synonym for the older SNDCTL_DSP_RESET. */
59 #ifndef SNDCTL_DSP_HALT
60 #define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
63 WINE_DEFAULT_DEBUG_CHANNEL(oss);
65 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
67 static const REFERENCE_TIME DefaultPeriod = 200000;
68 static const REFERENCE_TIME MinimumPeriod = 100000;
71 typedef struct ACImpl ACImpl;
73 typedef struct _AudioSession {
83 CRITICAL_SECTION lock;
88 typedef struct _AudioSessionWrapper {
89 IAudioSessionControl2 IAudioSessionControl2_iface;
90 IChannelAudioVolume IChannelAudioVolume_iface;
91 ISimpleAudioVolume ISimpleAudioVolume_iface;
96 AudioSession *session;
97 } AudioSessionWrapper;
100 IAudioClient IAudioClient_iface;
101 IAudioRenderClient IAudioRenderClient_iface;
102 IAudioCaptureClient IAudioCaptureClient_iface;
103 IAudioClock IAudioClock_iface;
104 IAudioClock2 IAudioClock2_iface;
105 IAudioStreamVolume IAudioStreamVolume_iface;
115 AUDCLNT_SHAREMODE share;
122 BOOL initted, playing;
123 UINT64 written_frames, held_frames, tmp_buffer_frames, inbuf_frames;
124 UINT32 period_us, bufsize_frames;
125 UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
127 BYTE *local_buffer, *tmp_buffer;
131 CRITICAL_SECTION lock;
133 AudioSession *session;
134 AudioSessionWrapper *session_wrapper;
141 LOCKED_NORMAL, /* public buffer piece is from local_buffer */
142 LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
145 typedef struct _SessionMgr {
146 IAudioSessionManager2 IAudioSessionManager2_iface;
153 static HANDLE g_timer_q;
155 static CRITICAL_SECTION g_sessions_lock;
156 static struct list g_sessions = LIST_INIT(g_sessions);
158 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
159 static HRESULT oss_setvol(ACImpl *This, UINT32 index);
161 static const IAudioClientVtbl AudioClient_Vtbl;
162 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
163 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
164 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
165 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
166 static const IAudioClockVtbl AudioClock_Vtbl;
167 static const IAudioClock2Vtbl AudioClock2_Vtbl;
168 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
169 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
170 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl;
172 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
174 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
177 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
179 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
182 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
184 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
187 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
189 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
192 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
194 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
197 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
199 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
202 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
204 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
207 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
209 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
212 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
214 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
217 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
219 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
222 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
224 if(reason == DLL_PROCESS_ATTACH){
225 g_timer_q = CreateTimerQueue();
229 InitializeCriticalSection(&g_sessions_lock);
235 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
236 UINT *num, UINT *def_index)
240 static int print_once = 0;
242 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
244 mixer_fd = open("/dev/mixer", O_RDONLY, 0);
246 ERR("OSS /dev/mixer doesn't seem to exist\n");
247 return AUDCLNT_E_SERVICE_NOT_RUNNING;
250 if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
254 ERR("OSS version too old, need at least OSSv4\n");
255 return AUDCLNT_E_SERVICE_NOT_RUNNING;
258 ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
263 TRACE("OSS sysinfo:\n");
264 TRACE("product: %s\n", sysinfo.product);
265 TRACE("version: %s\n", sysinfo.version);
266 TRACE("versionnum: %x\n", sysinfo.versionnum);
267 TRACE("numaudios: %d\n", sysinfo.numaudios);
268 TRACE("nummixers: %d\n", sysinfo.nummixers);
269 TRACE("numcards: %d\n", sysinfo.numcards);
270 TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
274 if(sysinfo.numaudios <= 0){
275 WARN("No audio devices!\n");
277 return AUDCLNT_E_SERVICE_NOT_RUNNING;
280 *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
281 *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
285 for(i = 0; i < sysinfo.numaudios; ++i){
286 oss_audioinfo ai = {0};
289 if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
290 WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
295 if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
296 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
299 (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
300 strlen(ai.devnode) + 1);
302 for(i = 0; i < *num; ++i){
303 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
304 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
306 HeapFree(GetProcessHeap(), 0, *ids);
307 HeapFree(GetProcessHeap(), 0, *keys);
309 return E_OUTOFMEMORY;
311 strcpy((*keys)[*num], ai.devnode);
313 len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
314 (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
315 len * sizeof(WCHAR));
317 HeapFree(GetProcessHeap(), 0, (*keys)[*num]);
318 for(i = 0; i < *num; ++i){
319 HeapFree(GetProcessHeap(), 0, (*ids)[i]);
320 HeapFree(GetProcessHeap(), 0, (*keys)[i]);
322 HeapFree(GetProcessHeap(), 0, *ids);
323 HeapFree(GetProcessHeap(), 0, *keys);
325 return E_OUTOFMEMORY;
327 MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
330 if(ai.caps & PCM_CAP_DEFAULT)
345 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
346 EDataFlow dataflow, IAudioClient **out)
350 TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
352 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
354 return E_OUTOFMEMORY;
356 if(dataflow == eRender)
357 This->fd = open(devnode, O_WRONLY, 0);
358 else if(dataflow == eCapture)
359 This->fd = open(devnode, O_RDONLY, 0);
361 HeapFree(GetProcessHeap(), 0, This);
365 ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
367 HeapFree(GetProcessHeap(), 0, This);
368 return AUDCLNT_E_DEVICE_INVALIDATED;
371 This->dataflow = dataflow;
374 if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
375 ERR("Unable to get audio info for device %s: %d (%s)\n", devnode,
376 errno, strerror(errno));
378 HeapFree(GetProcessHeap(), 0, This);
382 TRACE("OSS audioinfo:\n");
383 TRACE("devnode: %s\n", This->ai.devnode);
384 TRACE("name: %s\n", This->ai.name);
385 TRACE("busy: %x\n", This->ai.busy);
386 TRACE("caps: %x\n", This->ai.caps);
387 TRACE("iformats: %x\n", This->ai.iformats);
388 TRACE("oformats: %x\n", This->ai.oformats);
389 TRACE("enabled: %d\n", This->ai.enabled);
390 TRACE("min_rate: %d\n", This->ai.min_rate);
391 TRACE("max_rate: %d\n", This->ai.max_rate);
392 TRACE("min_channels: %d\n", This->ai.min_channels);
393 TRACE("max_channels: %d\n", This->ai.max_channels);
395 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
396 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
397 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
398 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
399 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
400 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
402 InitializeCriticalSection(&This->lock);
405 IMMDevice_AddRef(This->parent);
407 IAudioClient_AddRef(&This->IAudioClient_iface);
409 *out = &This->IAudioClient_iface;
414 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
415 REFIID riid, void **ppv)
417 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
422 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
425 IUnknown_AddRef((IUnknown*)*ppv);
428 WARN("Unknown interface %s\n", debugstr_guid(riid));
429 return E_NOINTERFACE;
432 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
434 ACImpl *This = impl_from_IAudioClient(iface);
436 ref = InterlockedIncrement(&This->ref);
437 TRACE("(%p) Refcount now %u\n", This, ref);
441 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
443 ACImpl *This = impl_from_IAudioClient(iface);
445 ref = InterlockedDecrement(&This->ref);
446 TRACE("(%p) Refcount now %u\n", This, ref);
448 IAudioClient_Stop(iface);
449 IMMDevice_Release(This->parent);
450 DeleteCriticalSection(&This->lock);
453 EnterCriticalSection(&g_sessions_lock);
454 list_remove(&This->entry);
455 LeaveCriticalSection(&g_sessions_lock);
457 HeapFree(GetProcessHeap(), 0, This->vols);
458 HeapFree(GetProcessHeap(), 0, This->local_buffer);
459 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
460 CoTaskMemFree(This->fmt);
461 HeapFree(GetProcessHeap(), 0, This);
466 static void dump_fmt(const WAVEFORMATEX *fmt)
468 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
469 switch(fmt->wFormatTag){
470 case WAVE_FORMAT_PCM:
471 TRACE("WAVE_FORMAT_PCM");
473 case WAVE_FORMAT_IEEE_FLOAT:
474 TRACE("WAVE_FORMAT_IEEE_FLOAT");
476 case WAVE_FORMAT_EXTENSIBLE:
477 TRACE("WAVE_FORMAT_EXTENSIBLE");
485 TRACE("nChannels: %u\n", fmt->nChannels);
486 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
487 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
488 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
489 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
490 TRACE("cbSize: %u\n", fmt->cbSize);
492 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
493 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
494 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
495 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
496 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
500 static DWORD get_channel_mask(unsigned int channels)
506 return SPEAKER_FRONT_CENTER;
508 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
510 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
511 SPEAKER_LOW_FREQUENCY;
513 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
516 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
517 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
519 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
520 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
522 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
523 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
526 FIXME("Unknown speaker configuration: %u\n", channels);
530 static int get_oss_format(const WAVEFORMATEX *fmt)
532 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
534 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
535 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
536 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
537 switch(fmt->wBitsPerSample){
551 if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
552 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
553 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
554 if(fmt->wBitsPerSample != 32)
564 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
569 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
570 size = sizeof(WAVEFORMATEXTENSIBLE);
572 size = sizeof(WAVEFORMATEX);
574 ret = CoTaskMemAlloc(size);
578 memcpy(ret, fmt, size);
580 ret->cbSize = size - sizeof(WAVEFORMATEX);
585 static HRESULT setup_oss_device(ACImpl *This, const WAVEFORMATEX *fmt,
591 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
592 WAVEFORMATEX *closest = NULL;
594 tmp = oss_format = get_oss_format(fmt);
596 return AUDCLNT_E_UNSUPPORTED_FORMAT;
597 if(ioctl(This->fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
598 WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
601 if(tmp != oss_format){
602 TRACE("Format unsupported by this OSS version: %x\n", oss_format);
603 return AUDCLNT_E_UNSUPPORTED_FORMAT;
606 closest = clone_format(fmt);
608 tmp = fmt->nSamplesPerSec;
609 if(ioctl(This->fd, SNDCTL_DSP_SPEED, &tmp) < 0){
610 WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
611 CoTaskMemFree(closest);
614 tenth = fmt->nSamplesPerSec * 0.1;
615 if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
617 closest->nSamplesPerSec = tmp;
620 tmp = fmt->nChannels;
621 if(ioctl(This->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
622 WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
623 CoTaskMemFree(closest);
626 if(tmp != fmt->nChannels){
628 closest->nChannels = tmp;
631 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
632 DWORD mask = get_channel_mask(closest->nChannels);
634 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
636 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
637 fmtex->dwChannelMask != mask)
641 if(ret == S_OK || !out){
642 CoTaskMemFree( closest);
646 closest->nBlockAlign =
647 closest->nChannels * closest->wBitsPerSample / 8;
648 closest->nAvgBytesPerSec =
649 closest->nBlockAlign * closest->nSamplesPerSec;
653 TRACE("returning: %08x\n", ret);
657 static void session_init_vols(AudioSession *session, UINT channels)
659 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
660 sizeof(float) * channels);
661 if(!session->channel_vols)
664 session->channel_count = channels;
666 for(; channels > 0; --channels)
667 session->channel_vols[channels - 1] = 1.f;
670 static AudioSession *create_session(const GUID *guid, EDataFlow flow,
675 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
679 memcpy(&ret->guid, guid, sizeof(GUID));
681 ret->dataflow = flow;
683 list_init(&ret->clients);
685 list_add_head(&g_sessions, &ret->entry);
687 InitializeCriticalSection(&ret->lock);
690 session_init_vols(ret, num_channels);
692 ret->master_vol = 1.f;
697 /* if channels == 0, then this will return or create a session with
698 * matching dataflow and GUID. otherwise, channels must also match */
699 static HRESULT get_audio_session(const GUID *sessionguid,
700 EDataFlow flow, UINT channels, AudioSession **out)
702 AudioSession *session;
704 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
705 *out = create_session(&GUID_NULL, flow, channels);
707 return E_OUTOFMEMORY;
713 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
714 if(IsEqualGUID(sessionguid, &session->guid) &&
715 session->dataflow == flow){
716 if(session->channel_count > 0){
717 if(channels > 0 && session->channel_count != channels)
719 }else if(channels > 0)
720 session_init_vols(session, channels);
727 *out = create_session(sessionguid, flow, channels);
729 return E_OUTOFMEMORY;
735 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
736 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
737 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
738 const GUID *sessionguid)
740 ACImpl *This = impl_from_IAudioClient(iface);
744 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
745 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
752 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
753 return AUDCLNT_E_NOT_INITIALIZED;
755 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
756 AUDCLNT_STREAMFLAGS_LOOPBACK |
757 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
758 AUDCLNT_STREAMFLAGS_NOPERSIST |
759 AUDCLNT_STREAMFLAGS_RATEADJUST |
760 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
761 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
762 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
763 TRACE("Unknown flags: %08x\n", flags);
767 EnterCriticalSection(&This->lock);
770 LeaveCriticalSection(&This->lock);
771 return AUDCLNT_E_ALREADY_INITIALIZED;
774 hr = setup_oss_device(This, fmt, NULL);
776 LeaveCriticalSection(&This->lock);
777 return AUDCLNT_E_UNSUPPORTED_FORMAT;
780 LeaveCriticalSection(&This->lock);
785 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
786 LeaveCriticalSection(&This->lock);
787 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
791 mask = (100 << 8) | 100;
792 if(ioctl(This->fd, SNDCTL_DSP_SETPLAYVOL, &mask) < 0)
793 WARN("SETPLAYVOL failed: %d (%s)\n", errno, strerror(errno));
795 This->fmt = clone_format(fmt);
797 LeaveCriticalSection(&This->lock);
798 return E_OUTOFMEMORY;
802 This->period_us = period / 10;
804 This->period_us = DefaultPeriod / 10;
806 This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
807 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
808 This->bufsize_frames * fmt->nBlockAlign);
809 if(!This->local_buffer){
810 CoTaskMemFree(This->fmt);
812 LeaveCriticalSection(&This->lock);
813 return E_OUTOFMEMORY;
816 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
818 CoTaskMemFree(This->fmt);
820 LeaveCriticalSection(&This->lock);
821 return E_OUTOFMEMORY;
824 for(i = 0; i < fmt->nChannels; ++i)
830 EnterCriticalSection(&g_sessions_lock);
832 hr = get_audio_session(sessionguid, This->dataflow, fmt->nChannels,
835 LeaveCriticalSection(&g_sessions_lock);
836 HeapFree(GetProcessHeap(), 0, This->vols);
838 CoTaskMemFree(This->fmt);
840 LeaveCriticalSection(&This->lock);
844 list_add_tail(&This->session->clients, &This->entry);
846 LeaveCriticalSection(&g_sessions_lock);
848 This->initted = TRUE;
850 oss_setvol(This, -1);
852 LeaveCriticalSection(&This->lock);
857 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
860 ACImpl *This = impl_from_IAudioClient(iface);
862 TRACE("(%p)->(%p)\n", This, frames);
867 EnterCriticalSection(&This->lock);
870 LeaveCriticalSection(&This->lock);
871 return AUDCLNT_E_NOT_INITIALIZED;
874 *frames = This->bufsize_frames;
876 LeaveCriticalSection(&This->lock);
881 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
882 REFERENCE_TIME *latency)
884 ACImpl *This = impl_from_IAudioClient(iface);
886 TRACE("(%p)->(%p)\n", This, latency);
891 EnterCriticalSection(&This->lock);
894 LeaveCriticalSection(&This->lock);
895 return AUDCLNT_E_NOT_INITIALIZED;
898 if(This->dataflow == eRender){
902 if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
903 LeaveCriticalSection(&This->lock);
904 WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
908 delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
909 This->fmt->nBlockAlign);
911 *latency = delay_s * 10000000;
913 *latency = 10000; /* OSS doesn't provide input latency */
915 LeaveCriticalSection(&This->lock);
920 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
923 ACImpl *This = impl_from_IAudioClient(iface);
926 TRACE("(%p)->(%p)\n", This, numpad);
931 EnterCriticalSection(&This->lock);
934 LeaveCriticalSection(&This->lock);
935 return AUDCLNT_E_NOT_INITIALIZED;
938 if(This->dataflow == eRender){
939 if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
940 LeaveCriticalSection(&This->lock);
941 WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
945 *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
946 This->fmt->nBlockAlign;
948 /* when the OSS buffer has less than one fragment of data, including
949 * no data, it often reports it as some non-zero portion of a
950 * fragment. when it has more than one fragment of data, it reports
951 * it as some multiple of that portion of the fragment size.
953 * so, we have to do some ugly workarounds to report the timing
954 * as accurately as possible */
955 if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
956 *numpad = This->inbuf_frames;
957 This->inbuf_frames = 0;
959 if(*numpad < This->inbuf_frames)
960 This->inbuf_frames = *numpad;
962 *numpad = This->inbuf_frames;
964 }else if(This->dataflow == eCapture){
965 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
966 LeaveCriticalSection(&This->lock);
967 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
971 if(bi.bytes <= bi.fragsize)
974 *numpad = bi.bytes / This->fmt->nBlockAlign;
976 LeaveCriticalSection(&This->lock);
980 *numpad += This->held_frames;
982 LeaveCriticalSection(&This->lock);
987 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
988 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
989 WAVEFORMATEX **outpwfx)
991 ACImpl *This = impl_from_IAudioClient(iface);
994 TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
996 if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
999 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1000 return E_INVALIDARG;
1002 if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1003 pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1004 return E_INVALIDARG;
1008 EnterCriticalSection(&This->lock);
1010 ret = setup_oss_device(This, pwfx, outpwfx);
1012 LeaveCriticalSection(&This->lock);
1017 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1018 WAVEFORMATEX **pwfx)
1020 ACImpl *This = impl_from_IAudioClient(iface);
1021 WAVEFORMATEXTENSIBLE *fmt;
1024 TRACE("(%p)->(%p)\n", This, pwfx);
1029 *pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
1031 return E_OUTOFMEMORY;
1033 fmt = (WAVEFORMATEXTENSIBLE*)*pwfx;
1035 if(This->dataflow == eRender)
1036 formats = This->ai.oformats;
1037 else if(This->dataflow == eCapture)
1038 formats = This->ai.iformats;
1040 return E_UNEXPECTED;
1042 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1043 if(formats & AFMT_S16_LE){
1044 fmt->Format.wBitsPerSample = 16;
1045 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1047 }else if(formats & AFMT_FLOAT){
1048 fmt->Format.wBitsPerSample = 32;
1049 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1051 }else if(formats & AFMT_U8){
1052 fmt->Format.wBitsPerSample = 8;
1053 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1054 }else if(formats & AFMT_S32_LE){
1055 fmt->Format.wBitsPerSample = 32;
1056 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1057 }else if(formats & AFMT_S24_LE){
1058 fmt->Format.wBitsPerSample = 24;
1059 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1061 ERR("Didn't recognize any available OSS formats: %x\n", formats);
1065 fmt->Format.nChannels = This->ai.max_channels;
1066 fmt->Format.nSamplesPerSec = This->ai.max_rate;
1067 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1069 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1070 fmt->Format.nChannels) / 8;
1071 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1072 fmt->Format.nBlockAlign;
1074 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1075 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1082 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1083 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1085 ACImpl *This = impl_from_IAudioClient(iface);
1087 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1089 if(!defperiod && !minperiod)
1092 EnterCriticalSection(&This->lock);
1095 *defperiod = DefaultPeriod;
1097 *minperiod = MinimumPeriod;
1099 LeaveCriticalSection(&This->lock);
1104 static void oss_write_data(ACImpl *This)
1107 UINT32 written_frames;
1110 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1112 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1113 to_write = This->bufsize_frames - This->lcl_offs_frames;
1115 to_write = This->held_frames;
1117 written = write(This->fd, buf, to_write * This->fmt->nBlockAlign);
1119 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1122 written_frames = written / This->fmt->nBlockAlign;
1124 This->lcl_offs_frames += written_frames;
1125 This->lcl_offs_frames %= This->bufsize_frames;
1126 This->held_frames -= written_frames;
1127 This->inbuf_frames += written_frames;
1129 if(written_frames < to_write){
1130 /* OSS buffer probably full */
1134 if(This->held_frames){
1135 /* wrapped and have some data back at the start to write */
1136 written = write(This->fd, This->local_buffer,
1137 This->held_frames * This->fmt->nBlockAlign);
1139 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1142 written_frames = written / This->fmt->nBlockAlign;
1144 This->lcl_offs_frames += written_frames;
1145 This->lcl_offs_frames %= This->bufsize_frames;
1146 This->held_frames -= written_frames;
1147 This->inbuf_frames += written_frames;
1151 static void oss_read_data(ACImpl *This)
1153 UINT64 pos, readable;
1157 if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1158 WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1162 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1163 readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1165 if(bi.bytes < readable)
1166 readable = bi.bytes;
1168 nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1171 WARN("read failed: %d (%s)\n", errno, strerror(errno));
1175 This->held_frames += nread / This->fmt->nBlockAlign;
1177 if(This->held_frames > This->bufsize_frames){
1178 WARN("Overflow of unread data\n");
1179 This->lcl_offs_frames += This->held_frames;
1180 This->lcl_offs_frames %= This->bufsize_frames;
1181 This->held_frames = This->bufsize_frames;
1185 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1187 ACImpl *This = user;
1189 EnterCriticalSection(&This->lock);
1191 if(This->dataflow == eRender)
1192 oss_write_data(This);
1193 else if(This->dataflow == eCapture)
1194 oss_read_data(This);
1197 SetEvent(This->event);
1199 LeaveCriticalSection(&This->lock);
1202 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1204 ACImpl *This = impl_from_IAudioClient(iface);
1207 TRACE("(%p)\n", This);
1209 EnterCriticalSection(&This->lock);
1212 LeaveCriticalSection(&This->lock);
1213 return AUDCLNT_E_NOT_INITIALIZED;
1216 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1217 LeaveCriticalSection(&This->lock);
1218 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1222 LeaveCriticalSection(&This->lock);
1223 return AUDCLNT_E_NOT_STOPPED;
1226 if(This->dataflow == eRender)
1227 mask = PCM_ENABLE_OUTPUT;
1228 else if(This->dataflow == eCapture)
1229 mask = PCM_ENABLE_INPUT;
1231 LeaveCriticalSection(&This->lock);
1232 return E_UNEXPECTED;
1235 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1236 LeaveCriticalSection(&This->lock);
1237 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1241 if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1242 oss_period_callback, This, 0, This->period_us / 1000,
1243 WT_EXECUTEINTIMERTHREAD))
1244 ERR("Unable to create period timer: %u\n", GetLastError());
1246 This->playing = TRUE;
1248 LeaveCriticalSection(&This->lock);
1253 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1255 ACImpl *This = impl_from_IAudioClient(iface);
1258 TRACE("(%p)\n", This);
1260 EnterCriticalSection(&This->lock);
1263 LeaveCriticalSection(&This->lock);
1264 return AUDCLNT_E_NOT_INITIALIZED;
1268 LeaveCriticalSection(&This->lock);
1272 if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1273 DeleteTimerQueueTimer(g_timer_q, This->timer,
1274 INVALID_HANDLE_VALUE);
1278 if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1279 LeaveCriticalSection(&This->lock);
1280 WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1285 if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1286 LeaveCriticalSection(&This->lock);
1287 WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1291 This->playing = FALSE;
1293 LeaveCriticalSection(&This->lock);
1298 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1300 ACImpl *This = impl_from_IAudioClient(iface);
1302 TRACE("(%p)\n", This);
1304 EnterCriticalSection(&This->lock);
1307 LeaveCriticalSection(&This->lock);
1308 return AUDCLNT_E_NOT_INITIALIZED;
1312 LeaveCriticalSection(&This->lock);
1313 return AUDCLNT_E_NOT_STOPPED;
1316 This->written_frames = 0;
1317 This->inbuf_frames = 0;
1318 This->held_frames = 0;
1320 if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1321 WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1323 LeaveCriticalSection(&This->lock);
1328 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1331 ACImpl *This = impl_from_IAudioClient(iface);
1333 TRACE("(%p)->(%p)\n", This, event);
1336 return E_INVALIDARG;
1338 EnterCriticalSection(&This->lock);
1341 LeaveCriticalSection(&This->lock);
1342 return AUDCLNT_E_NOT_INITIALIZED;
1345 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1346 LeaveCriticalSection(&This->lock);
1347 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1350 This->event = event;
1352 LeaveCriticalSection(&This->lock);
1357 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1360 ACImpl *This = impl_from_IAudioClient(iface);
1362 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1368 EnterCriticalSection(&This->lock);
1371 LeaveCriticalSection(&This->lock);
1372 return AUDCLNT_E_NOT_INITIALIZED;
1375 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1376 if(This->dataflow != eRender){
1377 LeaveCriticalSection(&This->lock);
1378 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1380 *ppv = &This->IAudioRenderClient_iface;
1381 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1382 if(This->dataflow != eCapture){
1383 LeaveCriticalSection(&This->lock);
1384 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1386 *ppv = &This->IAudioCaptureClient_iface;
1387 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1388 *ppv = &This->IAudioClock_iface;
1389 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1390 *ppv = &This->IAudioStreamVolume_iface;
1391 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1392 if(!This->session_wrapper){
1393 This->session_wrapper = AudioSessionWrapper_Create(This);
1394 if(!This->session_wrapper){
1395 LeaveCriticalSection(&This->lock);
1396 return E_OUTOFMEMORY;
1400 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1401 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1402 if(!This->session_wrapper){
1403 This->session_wrapper = AudioSessionWrapper_Create(This);
1404 if(!This->session_wrapper){
1405 LeaveCriticalSection(&This->lock);
1406 return E_OUTOFMEMORY;
1410 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1411 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1412 if(!This->session_wrapper){
1413 This->session_wrapper = AudioSessionWrapper_Create(This);
1414 if(!This->session_wrapper){
1415 LeaveCriticalSection(&This->lock);
1416 return E_OUTOFMEMORY;
1420 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1424 IUnknown_AddRef((IUnknown*)*ppv);
1425 LeaveCriticalSection(&This->lock);
1429 LeaveCriticalSection(&This->lock);
1431 FIXME("stub %s\n", debugstr_guid(riid));
1432 return E_NOINTERFACE;
1435 static const IAudioClientVtbl AudioClient_Vtbl =
1437 AudioClient_QueryInterface,
1439 AudioClient_Release,
1440 AudioClient_Initialize,
1441 AudioClient_GetBufferSize,
1442 AudioClient_GetStreamLatency,
1443 AudioClient_GetCurrentPadding,
1444 AudioClient_IsFormatSupported,
1445 AudioClient_GetMixFormat,
1446 AudioClient_GetDevicePeriod,
1450 AudioClient_SetEventHandle,
1451 AudioClient_GetService
1454 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1455 IAudioRenderClient *iface, REFIID riid, void **ppv)
1457 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1463 if(IsEqualIID(riid, &IID_IUnknown) ||
1464 IsEqualIID(riid, &IID_IAudioRenderClient))
1467 IUnknown_AddRef((IUnknown*)*ppv);
1471 WARN("Unknown interface %s\n", debugstr_guid(riid));
1472 return E_NOINTERFACE;
1475 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1477 ACImpl *This = impl_from_IAudioRenderClient(iface);
1478 return AudioClient_AddRef(&This->IAudioClient_iface);
1481 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1483 ACImpl *This = impl_from_IAudioRenderClient(iface);
1484 return AudioClient_Release(&This->IAudioClient_iface);
1487 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1488 UINT32 frames, BYTE **data)
1490 ACImpl *This = impl_from_IAudioRenderClient(iface);
1491 UINT32 pad, write_pos;
1494 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1499 EnterCriticalSection(&This->lock);
1501 if(This->buf_state != NOT_LOCKED){
1502 LeaveCriticalSection(&This->lock);
1503 return AUDCLNT_E_OUT_OF_ORDER;
1507 This->buf_state = LOCKED_NORMAL;
1508 LeaveCriticalSection(&This->lock);
1512 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1514 LeaveCriticalSection(&This->lock);
1518 if(pad + frames > This->bufsize_frames){
1519 LeaveCriticalSection(&This->lock);
1520 return AUDCLNT_E_BUFFER_TOO_LARGE;
1524 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1525 if(write_pos + frames > This->bufsize_frames){
1526 if(This->tmp_buffer_frames < frames){
1527 if(This->tmp_buffer)
1528 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1529 This->tmp_buffer, frames * This->fmt->nBlockAlign);
1531 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1532 frames * This->fmt->nBlockAlign);
1533 if(!This->tmp_buffer){
1534 LeaveCriticalSection(&This->lock);
1535 return E_OUTOFMEMORY;
1537 This->tmp_buffer_frames = frames;
1539 *data = This->tmp_buffer;
1540 This->buf_state = LOCKED_WRAPPED;
1542 *data = This->local_buffer +
1543 This->lcl_offs_frames * This->fmt->nBlockAlign;
1544 This->buf_state = LOCKED_NORMAL;
1547 LeaveCriticalSection(&This->lock);
1552 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
1554 UINT32 write_offs_frames =
1555 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1556 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1557 UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1558 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1560 if(written_bytes < chunk_bytes){
1561 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1563 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1564 memcpy(This->local_buffer, buffer + chunk_bytes,
1565 written_bytes - chunk_bytes);
1569 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1570 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1572 ACImpl *This = impl_from_IAudioRenderClient(iface);
1574 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1576 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1578 EnterCriticalSection(&This->lock);
1580 if(This->buf_state == NOT_LOCKED || !written_frames){
1581 This->buf_state = NOT_LOCKED;
1582 LeaveCriticalSection(&This->lock);
1583 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1586 if(This->buf_state == LOCKED_NORMAL)
1587 buffer = This->local_buffer +
1588 This->lcl_offs_frames * This->fmt->nBlockAlign;
1590 buffer = This->tmp_buffer;
1592 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1593 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1594 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1595 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1596 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1597 This->fmt->wBitsPerSample == 8)
1598 memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
1600 memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
1603 if(This->held_frames){
1604 if(This->buf_state == LOCKED_WRAPPED)
1605 oss_wrap_buffer(This, buffer, written_bytes);
1607 This->held_frames += written_frames;
1612 w_bytes = write(This->fd, buffer,
1613 written_frames * This->fmt->nBlockAlign);
1615 LeaveCriticalSection(&This->lock);
1616 WARN("write failed: %d (%s)\n", errno, strerror(errno));
1619 w_frames = w_bytes / This->fmt->nBlockAlign;
1620 This->inbuf_frames += w_frames;
1622 if(w_frames < written_frames){
1623 if(This->buf_state == LOCKED_WRAPPED)
1624 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1625 written_frames - w_frames);
1627 This->held_frames = written_frames - w_frames;
1631 This->written_frames += written_frames;
1632 This->buf_state = NOT_LOCKED;
1634 LeaveCriticalSection(&This->lock);
1639 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1640 AudioRenderClient_QueryInterface,
1641 AudioRenderClient_AddRef,
1642 AudioRenderClient_Release,
1643 AudioRenderClient_GetBuffer,
1644 AudioRenderClient_ReleaseBuffer
1647 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1648 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1650 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1656 if(IsEqualIID(riid, &IID_IUnknown) ||
1657 IsEqualIID(riid, &IID_IAudioCaptureClient))
1660 IUnknown_AddRef((IUnknown*)*ppv);
1664 WARN("Unknown interface %s\n", debugstr_guid(riid));
1665 return E_NOINTERFACE;
1668 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1670 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1671 return IAudioClient_AddRef(&This->IAudioClient_iface);
1674 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1676 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1677 return IAudioClient_Release(&This->IAudioClient_iface);
1680 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1681 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1684 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1687 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1690 if(!data || !frames || !flags)
1693 EnterCriticalSection(&This->lock);
1695 if(This->buf_state != NOT_LOCKED){
1696 LeaveCriticalSection(&This->lock);
1697 return AUDCLNT_E_OUT_OF_ORDER;
1700 hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1702 LeaveCriticalSection(&This->lock);
1708 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1709 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1710 if(This->tmp_buffer_frames < *frames){
1711 if(This->tmp_buffer)
1712 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1713 This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1715 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1716 *frames * This->fmt->nBlockAlign);
1717 if(!This->tmp_buffer){
1718 LeaveCriticalSection(&This->lock);
1719 return E_OUTOFMEMORY;
1721 This->tmp_buffer_frames = *frames;
1724 *data = This->tmp_buffer;
1725 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1726 This->fmt->nBlockAlign;
1727 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1728 frames_bytes = *frames * This->fmt->nBlockAlign;
1729 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1730 memcpy(This->tmp_buffer, This->local_buffer,
1731 frames_bytes - chunk_bytes);
1733 *data = This->local_buffer +
1734 This->lcl_offs_frames * This->fmt->nBlockAlign;
1736 This->buf_state = LOCKED_NORMAL;
1738 if(devpos || qpcpos)
1739 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1741 LeaveCriticalSection(&This->lock);
1743 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1746 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1747 IAudioCaptureClient *iface, UINT32 done)
1749 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1751 TRACE("(%p)->(%u)\n", This, done);
1753 EnterCriticalSection(&This->lock);
1755 if(This->buf_state == NOT_LOCKED){
1756 LeaveCriticalSection(&This->lock);
1757 return AUDCLNT_E_OUT_OF_ORDER;
1760 This->held_frames -= done;
1761 This->lcl_offs_frames += done;
1762 This->lcl_offs_frames %= This->bufsize_frames;
1764 This->buf_state = NOT_LOCKED;
1766 LeaveCriticalSection(&This->lock);
1771 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1772 IAudioCaptureClient *iface, UINT32 *frames)
1774 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1776 TRACE("(%p)->(%p)\n", This, frames);
1778 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1781 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1783 AudioCaptureClient_QueryInterface,
1784 AudioCaptureClient_AddRef,
1785 AudioCaptureClient_Release,
1786 AudioCaptureClient_GetBuffer,
1787 AudioCaptureClient_ReleaseBuffer,
1788 AudioCaptureClient_GetNextPacketSize
1791 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1792 REFIID riid, void **ppv)
1794 ACImpl *This = impl_from_IAudioClock(iface);
1796 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1802 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1804 else if(IsEqualIID(riid, &IID_IAudioClock2))
1805 *ppv = &This->IAudioClock2_iface;
1807 IUnknown_AddRef((IUnknown*)*ppv);
1811 WARN("Unknown interface %s\n", debugstr_guid(riid));
1812 return E_NOINTERFACE;
1815 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1817 ACImpl *This = impl_from_IAudioClock(iface);
1818 return IAudioClient_AddRef(&This->IAudioClient_iface);
1821 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1823 ACImpl *This = impl_from_IAudioClock(iface);
1824 return IAudioClient_Release(&This->IAudioClient_iface);
1827 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1829 ACImpl *This = impl_from_IAudioClock(iface);
1831 TRACE("(%p)->(%p)\n", This, freq);
1833 *freq = This->fmt->nSamplesPerSec;
1838 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1841 ACImpl *This = impl_from_IAudioClock(iface);
1845 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1850 EnterCriticalSection(&This->lock);
1852 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1854 LeaveCriticalSection(&This->lock);
1858 if(This->dataflow == eRender)
1859 *pos = This->written_frames - pad;
1860 else if(This->dataflow == eCapture)
1861 *pos = This->written_frames + pad;
1863 LeaveCriticalSection(&This->lock);
1866 LARGE_INTEGER stamp, freq;
1867 QueryPerformanceCounter(&stamp);
1868 QueryPerformanceFrequency(&freq);
1869 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1875 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1878 ACImpl *This = impl_from_IAudioClock(iface);
1880 TRACE("(%p)->(%p)\n", This, chars);
1885 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1890 static const IAudioClockVtbl AudioClock_Vtbl =
1892 AudioClock_QueryInterface,
1895 AudioClock_GetFrequency,
1896 AudioClock_GetPosition,
1897 AudioClock_GetCharacteristics
1900 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1901 REFIID riid, void **ppv)
1903 ACImpl *This = impl_from_IAudioClock2(iface);
1904 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1907 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1909 ACImpl *This = impl_from_IAudioClock2(iface);
1910 return IAudioClient_AddRef(&This->IAudioClient_iface);
1913 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1915 ACImpl *This = impl_from_IAudioClock2(iface);
1916 return IAudioClient_Release(&This->IAudioClient_iface);
1919 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1920 UINT64 *pos, UINT64 *qpctime)
1922 ACImpl *This = impl_from_IAudioClock2(iface);
1924 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1929 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1931 AudioClock2_QueryInterface,
1933 AudioClock2_Release,
1934 AudioClock2_GetDevicePosition
1937 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1939 AudioSessionWrapper *ret;
1941 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1942 sizeof(AudioSessionWrapper));
1946 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1947 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1948 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1950 ret->client = client;
1952 ret->session = client->session;
1953 AudioClient_AddRef(&client->IAudioClient_iface);
1959 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1960 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1962 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1968 if(IsEqualIID(riid, &IID_IUnknown) ||
1969 IsEqualIID(riid, &IID_IAudioSessionControl) ||
1970 IsEqualIID(riid, &IID_IAudioSessionControl2))
1973 IUnknown_AddRef((IUnknown*)*ppv);
1977 WARN("Unknown interface %s\n", debugstr_guid(riid));
1978 return E_NOINTERFACE;
1981 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1983 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1985 ref = InterlockedIncrement(&This->ref);
1986 TRACE("(%p) Refcount now %u\n", This, ref);
1990 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1992 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1994 ref = InterlockedDecrement(&This->ref);
1995 TRACE("(%p) Refcount now %u\n", This, ref);
1998 EnterCriticalSection(&This->client->lock);
1999 This->client->session_wrapper = NULL;
2000 LeaveCriticalSection(&This->client->lock);
2001 AudioClient_Release(&This->client->IAudioClient_iface);
2003 HeapFree(GetProcessHeap(), 0, This);
2008 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2009 AudioSessionState *state)
2011 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2014 TRACE("(%p)->(%p)\n", This, state);
2017 return NULL_PTR_ERR;
2019 EnterCriticalSection(&g_sessions_lock);
2021 if(list_empty(&This->session->clients)){
2022 *state = AudioSessionStateExpired;
2023 LeaveCriticalSection(&g_sessions_lock);
2027 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2028 EnterCriticalSection(&client->lock);
2029 if(client->playing){
2030 *state = AudioSessionStateActive;
2031 LeaveCriticalSection(&client->lock);
2032 LeaveCriticalSection(&g_sessions_lock);
2035 LeaveCriticalSection(&client->lock);
2038 LeaveCriticalSection(&g_sessions_lock);
2040 *state = AudioSessionStateInactive;
2045 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2046 IAudioSessionControl2 *iface, WCHAR **name)
2048 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2050 FIXME("(%p)->(%p) - stub\n", This, name);
2055 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2056 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2058 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2060 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2065 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2066 IAudioSessionControl2 *iface, WCHAR **path)
2068 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2070 FIXME("(%p)->(%p) - stub\n", This, path);
2075 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2076 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2078 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2080 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2085 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2086 IAudioSessionControl2 *iface, GUID *group)
2088 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2090 FIXME("(%p)->(%p) - stub\n", This, group);
2095 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2096 IAudioSessionControl2 *iface, GUID *group, const GUID *session)
2098 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2100 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2101 debugstr_guid(session));
2106 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2107 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2109 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2111 FIXME("(%p)->(%p) - stub\n", This, events);
2116 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2117 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2119 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2121 FIXME("(%p)->(%p) - stub\n", This, events);
2126 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2127 IAudioSessionControl2 *iface, WCHAR **id)
2129 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2131 FIXME("(%p)->(%p) - stub\n", This, id);
2136 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2137 IAudioSessionControl2 *iface, WCHAR **id)
2139 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2141 FIXME("(%p)->(%p) - stub\n", This, id);
2146 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2147 IAudioSessionControl2 *iface, DWORD *pid)
2149 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2151 TRACE("(%p)->(%p)\n", This, pid);
2156 *pid = GetCurrentProcessId();
2161 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2162 IAudioSessionControl2 *iface)
2164 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2166 TRACE("(%p)\n", This);
2171 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2172 IAudioSessionControl2 *iface, BOOL optout)
2174 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2176 TRACE("(%p)->(%d)\n", This, optout);
2181 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2183 AudioSessionControl_QueryInterface,
2184 AudioSessionControl_AddRef,
2185 AudioSessionControl_Release,
2186 AudioSessionControl_GetState,
2187 AudioSessionControl_GetDisplayName,
2188 AudioSessionControl_SetDisplayName,
2189 AudioSessionControl_GetIconPath,
2190 AudioSessionControl_SetIconPath,
2191 AudioSessionControl_GetGroupingParam,
2192 AudioSessionControl_SetGroupingParam,
2193 AudioSessionControl_RegisterAudioSessionNotification,
2194 AudioSessionControl_UnregisterAudioSessionNotification,
2195 AudioSessionControl_GetSessionIdentifier,
2196 AudioSessionControl_GetSessionInstanceIdentifier,
2197 AudioSessionControl_GetProcessId,
2198 AudioSessionControl_IsSystemSoundsSession,
2199 AudioSessionControl_SetDuckingPreference
2202 /* index == -1 means set all channels, otherwise sets only the given channel */
2203 static HRESULT oss_setvol(ACImpl *This, UINT32 index)
2210 if(index == (UINT32)-1){
2213 for(i = 0; i < This->fmt->nChannels; ++i){
2215 hr = oss_setvol(This, i);
2223 /* OSS doesn't support volume control past the first two channels */
2226 if(This->dataflow == eRender){
2227 setreq = SNDCTL_DSP_SETPLAYVOL;
2228 getreq = SNDCTL_DSP_GETPLAYVOL;
2229 }else if(This->dataflow == eCapture){
2230 setreq = SNDCTL_DSP_SETRECVOL;
2231 getreq = SNDCTL_DSP_GETRECVOL;
2233 return E_UNEXPECTED;
2235 if(ioctl(This->fd, getreq, &vol) < 0){
2237 /* device doesn't support this call */
2240 WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2244 level = This->session->master_vol * This->session->channel_vols[index] *
2248 vol = l | (vol & 0xFF00);
2250 vol = (vol & 0xFF) | (l << 8);
2252 if(ioctl(This->fd, setreq, &vol) < 0){
2254 /* device doesn't support this call */
2257 WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2264 static HRESULT oss_session_setvol(AudioSession *session, UINT32 index)
2269 LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2271 hr = oss_setvol(client, index);
2279 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2280 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2282 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2288 if(IsEqualIID(riid, &IID_IUnknown) ||
2289 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2292 IUnknown_AddRef((IUnknown*)*ppv);
2296 WARN("Unknown interface %s\n", debugstr_guid(riid));
2297 return E_NOINTERFACE;
2300 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2302 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2303 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2306 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2308 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2309 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2312 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2313 ISimpleAudioVolume *iface, float level, const GUID *context)
2315 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2316 AudioSession *session = This->session;
2319 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2321 if(level < 0.f || level > 1.f)
2322 return E_INVALIDARG;
2325 FIXME("Notifications not supported yet\n");
2327 EnterCriticalSection(&session->lock);
2329 session->master_vol = level;
2331 ret = oss_session_setvol(session, -1);
2333 LeaveCriticalSection(&session->lock);
2338 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2339 ISimpleAudioVolume *iface, float *level)
2341 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2342 AudioSession *session = This->session;
2344 TRACE("(%p)->(%p)\n", session, level);
2347 return NULL_PTR_ERR;
2349 *level = session->master_vol;
2354 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2355 BOOL mute, const GUID *context)
2357 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2358 AudioSession *session = This->session;
2360 FIXME("(%p)->(%u, %p) - stub\n", session, mute, context);
2365 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2368 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2369 AudioSession *session = This->session;
2371 FIXME("(%p)->(%p) - stub\n", session, mute);
2374 return NULL_PTR_ERR;
2379 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2381 SimpleAudioVolume_QueryInterface,
2382 SimpleAudioVolume_AddRef,
2383 SimpleAudioVolume_Release,
2384 SimpleAudioVolume_SetMasterVolume,
2385 SimpleAudioVolume_GetMasterVolume,
2386 SimpleAudioVolume_SetMute,
2387 SimpleAudioVolume_GetMute
2390 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2391 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2393 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2399 if(IsEqualIID(riid, &IID_IUnknown) ||
2400 IsEqualIID(riid, &IID_IAudioStreamVolume))
2403 IUnknown_AddRef((IUnknown*)*ppv);
2407 WARN("Unknown interface %s\n", debugstr_guid(riid));
2408 return E_NOINTERFACE;
2411 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2413 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2414 return IAudioClient_AddRef(&This->IAudioClient_iface);
2417 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2419 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2420 return IAudioClient_Release(&This->IAudioClient_iface);
2423 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2424 IAudioStreamVolume *iface, UINT32 *out)
2426 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2428 TRACE("(%p)->(%p)\n", This, out);
2433 *out = This->fmt->nChannels;
2438 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2439 IAudioStreamVolume *iface, UINT32 index, float level)
2441 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2444 TRACE("(%p)->(%d, %f)\n", This, index, level);
2446 if(level < 0.f || level > 1.f)
2447 return E_INVALIDARG;
2449 if(index >= This->fmt->nChannels)
2450 return E_INVALIDARG;
2452 EnterCriticalSection(&This->lock);
2454 This->vols[index] = level;
2456 ret = oss_setvol(This, index);
2458 LeaveCriticalSection(&This->lock);
2463 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2464 IAudioStreamVolume *iface, UINT32 index, float *level)
2466 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2468 TRACE("(%p)->(%d, %p)\n", This, index, level);
2473 if(index >= This->fmt->nChannels)
2474 return E_INVALIDARG;
2476 *level = This->vols[index];
2481 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2482 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2484 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2488 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2493 if(count != This->fmt->nChannels)
2494 return E_INVALIDARG;
2496 EnterCriticalSection(&This->lock);
2498 for(i = 0; i < count; ++i)
2499 This->vols[i] = levels[i];
2501 ret = oss_setvol(This, -1);
2503 LeaveCriticalSection(&This->lock);
2508 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2509 IAudioStreamVolume *iface, UINT32 count, float *levels)
2511 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2514 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2519 if(count != This->fmt->nChannels)
2520 return E_INVALIDARG;
2522 EnterCriticalSection(&This->lock);
2524 for(i = 0; i < count; ++i)
2525 levels[i] = This->vols[i];
2527 LeaveCriticalSection(&This->lock);
2532 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2534 AudioStreamVolume_QueryInterface,
2535 AudioStreamVolume_AddRef,
2536 AudioStreamVolume_Release,
2537 AudioStreamVolume_GetChannelCount,
2538 AudioStreamVolume_SetChannelVolume,
2539 AudioStreamVolume_GetChannelVolume,
2540 AudioStreamVolume_SetAllVolumes,
2541 AudioStreamVolume_GetAllVolumes
2544 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2545 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2547 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2553 if(IsEqualIID(riid, &IID_IUnknown) ||
2554 IsEqualIID(riid, &IID_IChannelAudioVolume))
2557 IUnknown_AddRef((IUnknown*)*ppv);
2561 WARN("Unknown interface %s\n", debugstr_guid(riid));
2562 return E_NOINTERFACE;
2565 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2567 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2568 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2571 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2573 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2574 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2577 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2578 IChannelAudioVolume *iface, UINT32 *out)
2580 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2581 AudioSession *session = This->session;
2583 TRACE("(%p)->(%p)\n", session, out);
2586 return NULL_PTR_ERR;
2588 *out = session->channel_count;
2593 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2594 IChannelAudioVolume *iface, UINT32 index, float level,
2595 const GUID *context)
2597 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2598 AudioSession *session = This->session;
2601 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2602 wine_dbgstr_guid(context));
2604 if(level < 0.f || level > 1.f)
2605 return E_INVALIDARG;
2607 if(index >= session->channel_count)
2608 return E_INVALIDARG;
2611 FIXME("Notifications not supported yet\n");
2613 EnterCriticalSection(&session->lock);
2615 session->channel_vols[index] = level;
2617 ret = oss_session_setvol(session, index);
2619 LeaveCriticalSection(&session->lock);
2624 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2625 IChannelAudioVolume *iface, UINT32 index, float *level)
2627 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2628 AudioSession *session = This->session;
2630 TRACE("(%p)->(%d, %p)\n", session, index, level);
2633 return NULL_PTR_ERR;
2635 if(index >= session->channel_count)
2636 return E_INVALIDARG;
2638 *level = session->channel_vols[index];
2643 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2644 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2645 const GUID *context)
2647 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2648 AudioSession *session = This->session;
2652 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2653 wine_dbgstr_guid(context));
2656 return NULL_PTR_ERR;
2658 if(count != session->channel_count)
2659 return E_INVALIDARG;
2662 FIXME("Notifications not supported yet\n");
2664 EnterCriticalSection(&session->lock);
2666 for(i = 0; i < count; ++i)
2667 session->channel_vols[i] = levels[i];
2669 ret = oss_session_setvol(session, -1);
2671 LeaveCriticalSection(&session->lock);
2676 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2677 IChannelAudioVolume *iface, UINT32 count, float *levels)
2679 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2680 AudioSession *session = This->session;
2683 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2686 return NULL_PTR_ERR;
2688 if(count != session->channel_count)
2689 return E_INVALIDARG;
2691 for(i = 0; i < count; ++i)
2692 levels[i] = session->channel_vols[i];
2697 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2699 ChannelAudioVolume_QueryInterface,
2700 ChannelAudioVolume_AddRef,
2701 ChannelAudioVolume_Release,
2702 ChannelAudioVolume_GetChannelCount,
2703 ChannelAudioVolume_SetChannelVolume,
2704 ChannelAudioVolume_GetChannelVolume,
2705 ChannelAudioVolume_SetAllVolumes,
2706 ChannelAudioVolume_GetAllVolumes
2709 HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2710 REFIID riid, void **ppv)
2712 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2718 if(IsEqualIID(riid, &IID_IUnknown) ||
2719 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2720 IsEqualIID(riid, &IID_IAudioSessionManager2))
2723 IUnknown_AddRef((IUnknown*)*ppv);
2727 WARN("Unknown interface %s\n", debugstr_guid(riid));
2728 return E_NOINTERFACE;
2731 ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2733 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2735 ref = InterlockedIncrement(&This->ref);
2736 TRACE("(%p) Refcount now %u\n", This, ref);
2740 ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2742 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2744 ref = InterlockedDecrement(&This->ref);
2745 TRACE("(%p) Refcount now %u\n", This, ref);
2747 HeapFree(GetProcessHeap(), 0, This);
2751 HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2752 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2753 IAudioSessionControl **out)
2755 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2756 AudioSession *session;
2757 AudioSessionWrapper *wrapper;
2760 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2763 hr = get_audio_session(session_guid, This->flow, 0, &session);
2767 wrapper = AudioSessionWrapper_Create(NULL);
2769 return E_OUTOFMEMORY;
2771 wrapper->session = session;
2773 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2778 HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2779 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2780 ISimpleAudioVolume **out)
2782 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2783 AudioSession *session;
2784 AudioSessionWrapper *wrapper;
2787 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2790 hr = get_audio_session(session_guid, This->flow, 0, &session);
2794 wrapper = AudioSessionWrapper_Create(NULL);
2796 return E_OUTOFMEMORY;
2798 wrapper->session = session;
2800 *out = &wrapper->ISimpleAudioVolume_iface;
2805 HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2806 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2808 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2809 FIXME("(%p)->(%p) - stub\n", This, out);
2813 HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2814 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2816 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2817 FIXME("(%p)->(%p) - stub\n", This, notification);
2821 HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2822 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2824 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2825 FIXME("(%p)->(%p) - stub\n", This, notification);
2829 HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2830 IAudioSessionManager2 *iface, const WCHAR *session_id,
2831 IAudioVolumeDuckNotification *notification)
2833 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2834 FIXME("(%p)->(%p) - stub\n", This, notification);
2838 HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2839 IAudioSessionManager2 *iface,
2840 IAudioVolumeDuckNotification *notification)
2842 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2843 FIXME("(%p)->(%p) - stub\n", This, notification);
2847 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2849 AudioSessionManager_QueryInterface,
2850 AudioSessionManager_AddRef,
2851 AudioSessionManager_Release,
2852 AudioSessionManager_GetAudioSessionControl,
2853 AudioSessionManager_GetSimpleAudioVolume,
2854 AudioSessionManager_GetSessionEnumerator,
2855 AudioSessionManager_RegisterSessionNotification,
2856 AudioSessionManager_UnregisterSessionNotification,
2857 AudioSessionManager_RegisterDuckNotification,
2858 AudioSessionManager_UnregisterDuckNotification
2861 HRESULT WINAPI AUDDRV_GetAudioSessionManager(EDataFlow dataflow,
2862 IAudioSessionManager2 **out)
2866 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2868 return E_OUTOFMEMORY;
2870 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2871 This->flow = dataflow;
2874 *out = &This->IAudioSessionManager2_iface;