2 * Copyright 2010 Maarten Lankhorst for CodeWeavers
3 * Copyright 2011 Andrew Eikum for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define NONAMELESSUNION
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33 #include "wine/list.h"
36 #include "mmdeviceapi.h"
40 #include "endpointvolume.h"
43 #include "audioclient.h"
44 #include "audiopolicy.h"
47 #include <alsa/asoundlib.h>
49 WINE_DEFAULT_DEBUG_CHANNEL(alsa);
51 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
53 static const REFERENCE_TIME DefaultPeriod = 200000;
54 static const REFERENCE_TIME MinimumPeriod = 100000;
57 typedef struct ACImpl ACImpl;
59 typedef struct _AudioSession {
69 CRITICAL_SECTION lock;
74 typedef struct _AudioSessionWrapper {
75 IAudioSessionControl2 IAudioSessionControl2_iface;
76 IChannelAudioVolume IChannelAudioVolume_iface;
77 ISimpleAudioVolume ISimpleAudioVolume_iface;
82 AudioSession *session;
83 } AudioSessionWrapper;
86 IAudioClient IAudioClient_iface;
87 IAudioRenderClient IAudioRenderClient_iface;
88 IAudioCaptureClient IAudioCaptureClient_iface;
89 IAudioClock IAudioClock_iface;
90 IAudioClock2 IAudioClock2_iface;
91 IAudioStreamVolume IAudioStreamVolume_iface;
95 snd_pcm_t *pcm_handle;
96 snd_pcm_uframes_t period_alsa, bufsize_alsa;
97 snd_pcm_hw_params_t *hw_params; /* does not hold state between calls */
104 AUDCLNT_SHAREMODE share;
108 BOOL initted, started;
109 UINT64 written_frames, held_frames, tmp_buffer_frames;
110 UINT32 bufsize_frames, period_us;
111 UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
114 BYTE *local_buffer, *tmp_buffer;
117 CRITICAL_SECTION lock;
119 AudioSession *session;
120 AudioSessionWrapper *session_wrapper;
127 LOCKED_NORMAL, /* public buffer piece is from local_buffer */
128 LOCKED_WRAPPED /* public buffer piece is wrapped around, in tmp_buffer */
131 static HANDLE g_timer_q;
133 static CRITICAL_SECTION g_sessions_lock;
134 static struct list g_sessions = LIST_INIT(g_sessions);
136 static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0};
138 static const IAudioClientVtbl AudioClient_Vtbl;
139 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
140 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
141 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
142 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
143 static const IAudioClockVtbl AudioClock_Vtbl;
144 static const IAudioClock2Vtbl AudioClock2_Vtbl;
145 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
146 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
148 int wine_snd_pcm_recover(snd_pcm_t *pcm, int err, int silent);
149 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
151 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
153 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
156 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
158 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
161 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
163 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
166 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
168 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
171 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
173 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
176 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
178 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
181 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
183 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
186 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
188 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
191 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
193 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
196 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
198 if(reason == DLL_PROCESS_ATTACH){
199 g_timer_q = CreateTimerQueue();
203 InitializeCriticalSection(&g_sessions_lock);
209 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
210 UINT *num, UINT *def_index)
212 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
217 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
219 return E_OUTOFMEMORY;
221 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
223 HeapFree(GetProcessHeap(), 0, *ids);
224 return E_OUTOFMEMORY;
227 lstrcpyW((*ids)[0], defaultW);
229 *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
235 HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
236 EDataFlow dataflow, IAudioClient **out)
240 snd_pcm_stream_t stream;
242 TRACE("%p %p %d %p\n", key, dev, dataflow, out);
244 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
246 return E_OUTOFMEMORY;
248 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
249 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
250 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
251 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
252 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
253 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
255 if(dataflow == eRender)
256 stream = SND_PCM_STREAM_PLAYBACK;
257 else if(dataflow == eCapture)
258 stream = SND_PCM_STREAM_CAPTURE;
260 HeapFree(GetProcessHeap(), 0, This);
264 This->dataflow = dataflow;
265 if((err = snd_pcm_open(&This->pcm_handle, "default", stream,
266 SND_PCM_NONBLOCK)) < 0){
267 HeapFree(GetProcessHeap(), 0, This);
268 WARN("Unable to open PCM \"default\": %d (%s)\n", err,
273 This->hw_params = HeapAlloc(GetProcessHeap(), 0,
274 snd_pcm_hw_params_sizeof());
275 if(!This->hw_params){
276 HeapFree(GetProcessHeap(), 0, This);
277 snd_pcm_close(This->pcm_handle);
278 return E_OUTOFMEMORY;
281 InitializeCriticalSection(&This->lock);
284 IMMDevice_AddRef(This->parent);
286 *out = &This->IAudioClient_iface;
287 IAudioClient_AddRef(&This->IAudioClient_iface);
292 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
293 REFIID riid, void **ppv)
295 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
300 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
303 IUnknown_AddRef((IUnknown*)*ppv);
306 WARN("Unknown interface %s\n", debugstr_guid(riid));
307 return E_NOINTERFACE;
310 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
312 ACImpl *This = impl_from_IAudioClient(iface);
314 ref = InterlockedIncrement(&This->ref);
315 TRACE("(%p) Refcount now %u\n", This, ref);
319 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
321 ACImpl *This = impl_from_IAudioClient(iface);
323 ref = InterlockedDecrement(&This->ref);
324 TRACE("(%p) Refcount now %u\n", This, ref);
326 IAudioClient_Stop(iface);
327 IMMDevice_Release(This->parent);
328 DeleteCriticalSection(&This->lock);
329 snd_pcm_drop(This->pcm_handle);
330 snd_pcm_close(This->pcm_handle);
332 EnterCriticalSection(&g_sessions_lock);
333 list_remove(&This->entry);
334 if(list_empty(&This->session->clients)){
335 list_remove(&This->session->entry);
336 DeleteCriticalSection(&This->session->lock);
337 HeapFree(GetProcessHeap(), 0, This->session->channel_vols);
338 HeapFree(GetProcessHeap(), 0, This->session);
340 LeaveCriticalSection(&g_sessions_lock);
342 HeapFree(GetProcessHeap(), 0, This->vols);
343 HeapFree(GetProcessHeap(), 0, This->local_buffer);
344 HeapFree(GetProcessHeap(), 0, This->hw_params);
345 CoTaskMemFree(This->fmt);
346 HeapFree(GetProcessHeap(), 0, This);
351 static void dump_fmt(const WAVEFORMATEX *fmt)
353 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
354 switch(fmt->wFormatTag){
355 case WAVE_FORMAT_PCM:
356 TRACE("WAVE_FORMAT_PCM");
358 case WAVE_FORMAT_IEEE_FLOAT:
359 TRACE("WAVE_FORMAT_IEEE_FLOAT");
361 case WAVE_FORMAT_EXTENSIBLE:
362 TRACE("WAVE_FORMAT_EXTENSIBLE");
370 TRACE("nChannels: %u\n", fmt->nChannels);
371 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
372 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
373 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
374 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
375 TRACE("cbSize: %u\n", fmt->cbSize);
377 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
378 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
379 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
380 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
381 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
385 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
390 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
391 size = sizeof(WAVEFORMATEXTENSIBLE);
393 size = sizeof(WAVEFORMATEX);
395 ret = CoTaskMemAlloc(size);
399 memcpy(ret, fmt, size);
401 ret->cbSize = size - sizeof(WAVEFORMATEX);
406 static AudioSession *create_session(const GUID *guid, EDataFlow flow,
411 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
415 memcpy(&ret->guid, guid, sizeof(GUID));
417 ret->dataflow = flow;
419 list_init(&ret->clients);
421 list_add_head(&g_sessions, &ret->entry);
423 InitializeCriticalSection(&ret->lock);
425 ret->channel_count = num_channels;
426 ret->channel_vols = HeapAlloc(GetProcessHeap(), 0,
427 sizeof(float) * num_channels);
428 if(!ret->channel_vols){
429 HeapFree(GetProcessHeap(), 0, ret);
433 for(; num_channels > 0; --num_channels)
434 ret->channel_vols[num_channels - 1] = 1.f;
436 ret->master_vol = 1.f;
441 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
442 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
443 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
444 const GUID *sessionguid)
446 ACImpl *This = impl_from_IAudioClient(iface);
447 snd_pcm_sw_params_t *sw_params = NULL;
448 snd_pcm_format_t format;
449 snd_pcm_uframes_t boundary;
450 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
451 unsigned int time_us, rate;
455 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
456 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
461 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
462 return AUDCLNT_E_NOT_INITIALIZED;
464 if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
465 AUDCLNT_STREAMFLAGS_LOOPBACK |
466 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
467 AUDCLNT_STREAMFLAGS_NOPERSIST |
468 AUDCLNT_STREAMFLAGS_RATEADJUST |
469 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
470 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
471 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
472 TRACE("Unknown flags: %08x\n", flags);
476 EnterCriticalSection(&This->lock);
479 LeaveCriticalSection(&This->lock);
480 return AUDCLNT_E_ALREADY_INITIALIZED;
485 if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
486 WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
491 if((err = snd_pcm_hw_params_set_access(This->pcm_handle, This->hw_params,
492 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
493 WARN("Unable to set access: %d (%s)\n", err, snd_strerror(err));
498 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
499 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
500 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
501 if(fmt->wBitsPerSample == 8)
502 format = SND_PCM_FORMAT_U8;
503 else if(fmt->wBitsPerSample == 16)
504 format = SND_PCM_FORMAT_S16_LE;
505 else if(fmt->wBitsPerSample == 24)
506 format = SND_PCM_FORMAT_S24_3LE;
507 else if(fmt->wBitsPerSample == 32)
508 format = SND_PCM_FORMAT_S32_LE;
510 WARN("Unsupported bit depth: %u\n", fmt->wBitsPerSample);
511 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
514 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
515 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
516 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
517 if(fmt->wBitsPerSample == 32)
518 format = SND_PCM_FORMAT_FLOAT_LE;
519 else if(fmt->wBitsPerSample == 64)
520 format = SND_PCM_FORMAT_FLOAT64_LE;
522 WARN("Unsupported float size: %u\n", fmt->wBitsPerSample);
523 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
527 WARN("Unknown wave format: %04x\n", fmt->wFormatTag);
528 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
532 if((err = snd_pcm_hw_params_set_format(This->pcm_handle, This->hw_params,
534 WARN("Unable to set ALSA format to %u: %d (%s)\n", format, err,
540 rate = fmt->nSamplesPerSec;
541 if((err = snd_pcm_hw_params_set_rate_near(This->pcm_handle, This->hw_params,
543 WARN("Unable to set rate to %u: %d (%s)\n", rate, err,
549 if((err = snd_pcm_hw_params_set_channels(This->pcm_handle, This->hw_params,
550 fmt->nChannels)) < 0){
551 WARN("Unable to set channels to %u: %d (%s)\n", fmt->nChannels, err,
557 time_us = MinimumPeriod / 10;
558 if((err = snd_pcm_hw_params_set_period_time_near(This->pcm_handle,
559 This->hw_params, &time_us, NULL)) < 0){
560 WARN("Unable to set max period time to %u: %d (%s)\n", time_us,
561 err, snd_strerror(err));
566 if((err = snd_pcm_hw_params(This->pcm_handle, This->hw_params)) < 0){
567 WARN("Unable to set hw params: %d (%s)\n", err, snd_strerror(err));
572 sw_params = HeapAlloc(GetProcessHeap(), 0, snd_pcm_sw_params_sizeof());
578 if((err = snd_pcm_sw_params_current(This->pcm_handle, sw_params)) < 0){
579 WARN("Unable to get sw_params: %d (%s)\n", err, snd_strerror(err));
584 This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
585 This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
586 This->bufsize_frames * fmt->nBlockAlign);
587 if(!This->local_buffer){
591 if (fmt->wBitsPerSample == 8)
592 memset(This->local_buffer, 128, This->bufsize_frames * fmt->nBlockAlign);
594 memset(This->local_buffer, 0, This->bufsize_frames * fmt->nBlockAlign);
596 if((err = snd_pcm_sw_params_get_boundary(sw_params, &boundary)) < 0){
597 WARN("Unable to get boundary: %d (%s)\n", err, snd_strerror(err));
602 if((err = snd_pcm_sw_params_set_start_threshold(This->pcm_handle,
603 sw_params, boundary)) < 0){
604 WARN("Unable to set start threshold to %lx: %d (%s)\n", boundary, err,
610 if((err = snd_pcm_sw_params_set_stop_threshold(This->pcm_handle,
611 sw_params, boundary)) < 0){
612 WARN("Unable to set stop threshold to %lx: %d (%s)\n", boundary, err,
618 if((err = snd_pcm_sw_params_set_avail_min(This->pcm_handle,
620 WARN("Unable to set avail min to 0: %d (%s)\n", err, snd_strerror(err));
625 if((err = snd_pcm_sw_params(This->pcm_handle, sw_params)) < 0){
626 WARN("Unable to set sw params: %d (%s)\n", err, snd_strerror(err));
631 if((err = snd_pcm_prepare(This->pcm_handle)) < 0){
632 WARN("Unable to prepare device: %d (%s)\n", err, snd_strerror(err));
637 if((err = snd_pcm_hw_params_get_buffer_size(This->hw_params,
638 &This->bufsize_alsa)) < 0){
639 WARN("Unable to get buffer size: %d (%s)\n", err, snd_strerror(err));
644 if((err = snd_pcm_hw_params_get_period_size(This->hw_params,
645 &This->period_alsa, NULL)) < 0){
646 WARN("Unable to get period size: %d (%s)\n", err, snd_strerror(err));
651 if((err = snd_pcm_hw_params_get_period_time(This->hw_params,
652 &This->period_us, NULL)) < 0){
653 WARN("Unable to get period time: %d (%s)\n", err, snd_strerror(err));
658 This->fmt = clone_format(fmt);
664 This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
670 for(i = 0; i < fmt->nChannels; ++i)
676 EnterCriticalSection(&g_sessions_lock);
678 if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
679 This->session = create_session(&GUID_NULL, This->dataflow,
682 LeaveCriticalSection(&g_sessions_lock);
687 AudioSession *session;
689 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){
690 if(IsEqualGUID(sessionguid, &session->guid) &&
691 This->dataflow == session->dataflow){
692 if(session->channel_count != fmt->nChannels){
693 LeaveCriticalSection(&g_sessions_lock);
697 This->session = session;
702 This->session = create_session(sessionguid, This->dataflow,
705 LeaveCriticalSection(&g_sessions_lock);
712 list_add_tail(&This->session->clients, &This->entry);
714 LeaveCriticalSection(&g_sessions_lock);
716 This->initted = TRUE;
719 HeapFree(GetProcessHeap(), 0, sw_params);
721 if(This->local_buffer){
722 HeapFree(GetProcessHeap(), 0, This->local_buffer);
723 This->local_buffer = NULL;
726 HeapFree(GetProcessHeap(), 0, This->fmt);
730 HeapFree(GetProcessHeap(), 0, This->vols);
735 LeaveCriticalSection(&This->lock);
740 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
743 ACImpl *This = impl_from_IAudioClient(iface);
745 TRACE("(%p)->(%p)\n", This, out);
750 EnterCriticalSection(&This->lock);
753 LeaveCriticalSection(&This->lock);
754 return AUDCLNT_E_NOT_INITIALIZED;
757 *out = This->bufsize_frames;
759 LeaveCriticalSection(&This->lock);
764 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
765 REFERENCE_TIME *latency)
767 ACImpl *This = impl_from_IAudioClient(iface);
769 TRACE("(%p)->(%p)\n", This, latency);
774 EnterCriticalSection(&This->lock);
777 LeaveCriticalSection(&This->lock);
778 return AUDCLNT_E_NOT_INITIALIZED;
781 LeaveCriticalSection(&This->lock);
788 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
791 ACImpl *This = impl_from_IAudioClient(iface);
793 TRACE("(%p)->(%p)\n", This, out);
798 EnterCriticalSection(&This->lock);
801 LeaveCriticalSection(&This->lock);
802 return AUDCLNT_E_NOT_INITIALIZED;
805 if(This->dataflow == eRender){
806 snd_pcm_sframes_t avail_frames;
808 avail_frames = snd_pcm_avail_update(This->pcm_handle);
810 if(This->bufsize_alsa < avail_frames){
811 WARN("Xrun detected\n");
812 *out = This->held_frames;
814 *out = This->bufsize_alsa - avail_frames + This->held_frames;
815 }else if(This->dataflow == eCapture){
816 *out = This->held_frames;
818 LeaveCriticalSection(&This->lock);
822 LeaveCriticalSection(&This->lock);
827 static DWORD get_channel_mask(unsigned int channels)
833 return SPEAKER_FRONT_CENTER;
835 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
837 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
838 SPEAKER_LOW_FREQUENCY;
840 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
843 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
844 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
846 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
847 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
849 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
850 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
853 FIXME("Unknown speaker configuration: %u\n", channels);
857 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
858 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
861 ACImpl *This = impl_from_IAudioClient(iface);
862 snd_pcm_format_mask_t *formats = NULL;
864 WAVEFORMATEX *closest = NULL;
865 const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
866 unsigned int max = 0, min = 0;
869 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
871 if(!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
874 if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
877 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
878 fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
883 EnterCriticalSection(&This->lock);
885 if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
890 formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
891 snd_pcm_format_mask_sizeof());
897 snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
899 if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
900 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
901 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
902 switch(fmt->wBitsPerSample){
904 if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
905 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
910 if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
911 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
916 if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
917 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
922 if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
923 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
928 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
931 }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
932 (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
933 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
934 switch(fmt->wBitsPerSample){
936 if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
937 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
942 if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT64_LE)){
943 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
948 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
952 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
956 closest = clone_format(fmt);
962 if((err = snd_pcm_hw_params_get_rate_min(This->hw_params, &min, NULL)) < 0){
964 WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
968 if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max, NULL)) < 0){
970 WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
974 if(fmt->nSamplesPerSec < min || fmt->nSamplesPerSec > max ||
975 (fmt->nSamplesPerSec != 48000 &&
976 fmt->nSamplesPerSec != 44100 &&
977 fmt->nSamplesPerSec != 22050 &&
978 fmt->nSamplesPerSec != 11025 &&
979 fmt->nSamplesPerSec != 8000)){
980 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
984 if((err = snd_pcm_hw_params_get_channels_min(This->hw_params, &min)) < 0){
986 WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
990 if((err = snd_pcm_hw_params_get_channels_max(This->hw_params, &max)) < 0){
992 WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
997 if(fmt->nChannels > max){
999 closest->nChannels = max;
1000 }else if(fmt->nChannels < min){
1002 closest->nChannels = min;
1005 if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1006 DWORD mask = get_channel_mask(closest->nChannels);
1008 ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
1010 if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1011 fmtex->dwChannelMask != mask)
1016 LeaveCriticalSection(&This->lock);
1017 HeapFree(GetProcessHeap(), 0, formats);
1019 if(hr == S_OK || !out){
1020 CoTaskMemFree(closest);
1024 closest->nBlockAlign =
1025 closest->nChannels * closest->wBitsPerSample / 8;
1026 closest->nAvgBytesPerSec =
1027 closest->nBlockAlign * closest->nSamplesPerSec;
1031 TRACE("returning: %08x\n", hr);
1035 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1036 WAVEFORMATEX **pwfx)
1038 ACImpl *This = impl_from_IAudioClient(iface);
1039 WAVEFORMATEXTENSIBLE *fmt;
1040 snd_pcm_format_mask_t *formats;
1041 unsigned int max_rate, max_channels;
1045 TRACE("(%p)->(%p)\n", This, pwfx);
1050 *pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
1052 return E_OUTOFMEMORY;
1054 fmt = (WAVEFORMATEXTENSIBLE*)*pwfx;
1056 formats = HeapAlloc(GetProcessHeap(), 0, snd_pcm_format_mask_sizeof());
1058 HeapFree(GetProcessHeap(), 0, *pwfx);
1059 return E_OUTOFMEMORY;
1062 EnterCriticalSection(&This->lock);
1064 if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
1065 WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
1070 snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
1072 fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1073 if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
1074 fmt->Format.wBitsPerSample = 32;
1075 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1076 }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
1077 fmt->Format.wBitsPerSample = 16;
1078 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1079 }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
1080 fmt->Format.wBitsPerSample = 8;
1081 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1082 }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
1083 fmt->Format.wBitsPerSample = 32;
1084 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1085 }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
1086 fmt->Format.wBitsPerSample = 24;
1087 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1089 ERR("Didn't recognize any available ALSA formats\n");
1094 if((err = snd_pcm_hw_params_get_channels_max(This->hw_params,
1095 &max_channels)) < 0){
1096 WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
1101 if(max_channels > 2){
1102 FIXME("Don't know what to do with %u channels, pretending there's "
1103 "only 2 channels\n", max_channels);
1104 fmt->Format.nChannels = 2;
1106 fmt->Format.nChannels = max_channels;
1108 fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1110 if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max_rate,
1112 WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
1117 if(max_rate >= 48000)
1118 fmt->Format.nSamplesPerSec = 48000;
1119 else if(max_rate >= 44100)
1120 fmt->Format.nSamplesPerSec = 44100;
1121 else if(max_rate >= 22050)
1122 fmt->Format.nSamplesPerSec = 22050;
1123 else if(max_rate >= 11025)
1124 fmt->Format.nSamplesPerSec = 11025;
1125 else if(max_rate >= 8000)
1126 fmt->Format.nSamplesPerSec = 8000;
1128 ERR("Unknown max rate: %u\n", max_rate);
1133 fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1134 fmt->Format.nChannels) / 8;
1135 fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1136 fmt->Format.nBlockAlign;
1138 fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1139 fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1141 dump_fmt((WAVEFORMATEX*)fmt);
1144 LeaveCriticalSection(&This->lock);
1146 HeapFree(GetProcessHeap(), 0, *pwfx);
1147 HeapFree(GetProcessHeap(), 0, formats);
1152 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1153 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1155 ACImpl *This = impl_from_IAudioClient(iface);
1157 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1159 if(!defperiod && !minperiod)
1163 *defperiod = DefaultPeriod;
1165 *minperiod = MinimumPeriod;
1170 static snd_pcm_sframes_t alsa_write_best_effort(snd_pcm_t *handle, BYTE *buf,
1171 snd_pcm_uframes_t frames)
1173 snd_pcm_sframes_t written;
1175 written = snd_pcm_writei(handle, buf, frames);
1179 if(written == -EAGAIN)
1183 WARN("writei failed, recovering: %ld (%s)\n", written,
1184 snd_strerror(written));
1186 ret = wine_snd_pcm_recover(handle, written, 0);
1188 WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret));
1192 written = snd_pcm_writei(handle, buf, frames);
1198 static void alsa_write_data(ACImpl *This)
1200 snd_pcm_sframes_t written;
1201 snd_pcm_uframes_t to_write;
1203 This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1205 if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1206 to_write = This->bufsize_frames - This->lcl_offs_frames;
1208 to_write = This->held_frames;
1210 written = alsa_write_best_effort(This->pcm_handle, buf, to_write);
1212 WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
1216 This->lcl_offs_frames += written;
1217 This->lcl_offs_frames %= This->bufsize_frames;
1218 This->held_frames -= written;
1220 if(written < to_write){
1221 /* ALSA buffer probably full */
1225 if(This->held_frames){
1226 /* wrapped and have some data back at the start to write */
1227 written = alsa_write_best_effort(This->pcm_handle, This->local_buffer,
1230 WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
1234 This->lcl_offs_frames += written;
1235 This->lcl_offs_frames %= This->bufsize_frames;
1236 This->held_frames -= written;
1240 static void alsa_read_data(ACImpl *This)
1242 snd_pcm_sframes_t pos, readable, nread;
1244 pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1245 readable = This->bufsize_frames - pos;
1247 nread = snd_pcm_readi(This->pcm_handle,
1248 This->local_buffer + pos * This->fmt->nBlockAlign, readable);
1252 WARN("read failed, recovering: %ld (%s)\n", nread, snd_strerror(nread));
1254 ret = wine_snd_pcm_recover(This->pcm_handle, nread, 0);
1256 WARN("Recover failed: %d (%s)\n", ret, snd_strerror(ret));
1260 nread = snd_pcm_readi(This->pcm_handle,
1261 This->local_buffer + pos * This->fmt->nBlockAlign, readable);
1263 WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread));
1268 This->held_frames += nread;
1270 if(This->held_frames > This->bufsize_frames){
1271 WARN("Overflow of unread data\n");
1272 This->lcl_offs_frames += This->held_frames;
1273 This->lcl_offs_frames %= This->bufsize_frames;
1274 This->held_frames = This->bufsize_frames;
1278 static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
1280 ACImpl *This = user;
1282 EnterCriticalSection(&This->lock);
1284 if(This->dataflow == eRender && This->held_frames)
1285 alsa_write_data(This);
1286 else if(This->dataflow == eCapture)
1287 alsa_read_data(This);
1290 SetEvent(This->event);
1292 LeaveCriticalSection(&This->lock);
1295 static HRESULT alsa_consider_start(ACImpl *This)
1297 snd_pcm_sframes_t avail;
1300 avail = snd_pcm_avail_update(This->pcm_handle);
1302 WARN("Unable to get avail_update: %ld (%s)\n", avail,
1303 snd_strerror(avail));
1307 if(This->period_alsa < This->bufsize_alsa - avail){
1308 if((err = snd_pcm_start(This->pcm_handle)) < 0){
1309 WARN("Start failed: %d (%s), state: %d\n", err, snd_strerror(err),
1310 snd_pcm_state(This->pcm_handle));
1320 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1322 ACImpl *This = impl_from_IAudioClient(iface);
1326 TRACE("(%p)\n", This);
1328 EnterCriticalSection(&This->lock);
1331 LeaveCriticalSection(&This->lock);
1332 return AUDCLNT_E_NOT_INITIALIZED;
1335 if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1336 LeaveCriticalSection(&This->lock);
1337 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1341 LeaveCriticalSection(&This->lock);
1342 return AUDCLNT_E_NOT_STOPPED;
1345 hr = alsa_consider_start(This);
1347 LeaveCriticalSection(&This->lock);
1351 period_ms = This->period_us / 1000;
1355 if(This->dataflow == eCapture){
1356 /* dump any data that might be leftover in the ALSA capture buffer */
1357 snd_pcm_readi(This->pcm_handle, This->local_buffer,
1358 This->bufsize_frames);
1361 if(!CreateTimerQueueTimer(&This->timer, g_timer_q, alsa_push_buffer_data,
1362 This, 0, period_ms, WT_EXECUTEINTIMERTHREAD)){
1363 LeaveCriticalSection(&This->lock);
1364 WARN("Unable to create timer: %u\n", GetLastError());
1368 This->started = TRUE;
1370 LeaveCriticalSection(&This->lock);
1375 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1377 ACImpl *This = impl_from_IAudioClient(iface);
1380 TRACE("(%p)\n", This);
1382 EnterCriticalSection(&This->lock);
1385 LeaveCriticalSection(&This->lock);
1386 return AUDCLNT_E_NOT_INITIALIZED;
1390 LeaveCriticalSection(&This->lock);
1394 DeleteTimerQueueTimer(g_timer_q, This->timer, INVALID_HANDLE_VALUE);
1396 if((err = snd_pcm_drop(This->pcm_handle)) < 0){
1397 LeaveCriticalSection(&This->lock);
1398 WARN("Drop failed: %d (%s)\n", err, snd_strerror(err));
1402 if((err = snd_pcm_prepare(This->pcm_handle)) < 0){
1403 LeaveCriticalSection(&This->lock);
1404 WARN("Prepare failed: %d (%s)\n", err, snd_strerror(err));
1408 This->started = FALSE;
1410 LeaveCriticalSection(&This->lock);
1415 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1417 ACImpl *This = impl_from_IAudioClient(iface);
1419 TRACE("(%p)\n", This);
1421 EnterCriticalSection(&This->lock);
1424 LeaveCriticalSection(&This->lock);
1425 return AUDCLNT_E_NOT_INITIALIZED;
1429 LeaveCriticalSection(&This->lock);
1430 return AUDCLNT_E_NOT_STOPPED;
1433 This->held_frames = 0;
1434 This->written_frames = 0;
1435 This->lcl_offs_frames = 0;
1437 LeaveCriticalSection(&This->lock);
1442 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1445 ACImpl *This = impl_from_IAudioClient(iface);
1447 TRACE("(%p)->(%p)\n", This, event);
1450 return E_INVALIDARG;
1452 EnterCriticalSection(&This->lock);
1455 LeaveCriticalSection(&This->lock);
1456 return AUDCLNT_E_NOT_INITIALIZED;
1459 if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1460 LeaveCriticalSection(&This->lock);
1461 return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1464 This->event = event;
1466 LeaveCriticalSection(&This->lock);
1471 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1474 ACImpl *This = impl_from_IAudioClient(iface);
1476 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1482 EnterCriticalSection(&This->lock);
1485 LeaveCriticalSection(&This->lock);
1486 return AUDCLNT_E_NOT_INITIALIZED;
1489 if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1490 if(This->dataflow != eRender){
1491 LeaveCriticalSection(&This->lock);
1492 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1494 *ppv = &This->IAudioRenderClient_iface;
1495 }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1496 if(This->dataflow != eCapture){
1497 LeaveCriticalSection(&This->lock);
1498 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1500 *ppv = &This->IAudioCaptureClient_iface;
1501 }else if(IsEqualIID(riid, &IID_IAudioClock)){
1502 *ppv = &This->IAudioClock_iface;
1503 }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1504 *ppv = &This->IAudioStreamVolume_iface;
1505 }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1506 if(!This->session_wrapper){
1507 This->session_wrapper = AudioSessionWrapper_Create(This);
1508 if(!This->session_wrapper){
1509 LeaveCriticalSection(&This->lock);
1510 return E_OUTOFMEMORY;
1514 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1515 }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1516 if(!This->session_wrapper){
1517 This->session_wrapper = AudioSessionWrapper_Create(This);
1518 if(!This->session_wrapper){
1519 LeaveCriticalSection(&This->lock);
1520 return E_OUTOFMEMORY;
1524 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1525 }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1526 if(!This->session_wrapper){
1527 This->session_wrapper = AudioSessionWrapper_Create(This);
1528 if(!This->session_wrapper){
1529 LeaveCriticalSection(&This->lock);
1530 return E_OUTOFMEMORY;
1534 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1538 IUnknown_AddRef((IUnknown*)*ppv);
1539 LeaveCriticalSection(&This->lock);
1543 LeaveCriticalSection(&This->lock);
1545 FIXME("stub %s\n", debugstr_guid(riid));
1546 return E_NOINTERFACE;
1549 static const IAudioClientVtbl AudioClient_Vtbl =
1551 AudioClient_QueryInterface,
1553 AudioClient_Release,
1554 AudioClient_Initialize,
1555 AudioClient_GetBufferSize,
1556 AudioClient_GetStreamLatency,
1557 AudioClient_GetCurrentPadding,
1558 AudioClient_IsFormatSupported,
1559 AudioClient_GetMixFormat,
1560 AudioClient_GetDevicePeriod,
1564 AudioClient_SetEventHandle,
1565 AudioClient_GetService
1568 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1569 IAudioRenderClient *iface, REFIID riid, void **ppv)
1571 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1577 if(IsEqualIID(riid, &IID_IUnknown) ||
1578 IsEqualIID(riid, &IID_IAudioRenderClient))
1581 IUnknown_AddRef((IUnknown*)*ppv);
1585 WARN("Unknown interface %s\n", debugstr_guid(riid));
1586 return E_NOINTERFACE;
1589 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1591 ACImpl *This = impl_from_IAudioRenderClient(iface);
1592 return AudioClient_AddRef(&This->IAudioClient_iface);
1595 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1597 ACImpl *This = impl_from_IAudioRenderClient(iface);
1598 return AudioClient_Release(&This->IAudioClient_iface);
1601 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1602 UINT32 frames, BYTE **data)
1604 ACImpl *This = impl_from_IAudioRenderClient(iface);
1609 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1614 EnterCriticalSection(&This->lock);
1616 if(This->buf_state != NOT_LOCKED){
1617 LeaveCriticalSection(&This->lock);
1618 return AUDCLNT_E_OUT_OF_ORDER;
1622 This->buf_state = LOCKED_NORMAL;
1623 LeaveCriticalSection(&This->lock);
1627 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1629 LeaveCriticalSection(&This->lock);
1633 if(pad + frames > This->bufsize_frames){
1634 LeaveCriticalSection(&This->lock);
1635 return AUDCLNT_E_BUFFER_TOO_LARGE;
1639 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1640 if(write_pos + frames > This->bufsize_frames){
1641 if(This->tmp_buffer_frames < frames){
1642 if(This->tmp_buffer)
1643 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1644 This->tmp_buffer, frames * This->fmt->nBlockAlign);
1646 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1647 frames * This->fmt->nBlockAlign);
1648 if(!This->tmp_buffer){
1649 LeaveCriticalSection(&This->lock);
1650 return E_OUTOFMEMORY;
1652 This->tmp_buffer_frames = frames;
1654 *data = This->tmp_buffer;
1655 This->buf_state = LOCKED_WRAPPED;
1657 *data = This->local_buffer +
1658 This->lcl_offs_frames * This->fmt->nBlockAlign;
1659 This->buf_state = LOCKED_NORMAL;
1662 LeaveCriticalSection(&This->lock);
1667 static void alsa_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
1669 snd_pcm_uframes_t write_offs_frames =
1670 (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1671 UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1672 snd_pcm_uframes_t chunk_frames = This->bufsize_frames - write_offs_frames;
1673 UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1675 if(written_bytes < chunk_bytes){
1676 memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1678 memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1679 memcpy(This->local_buffer, buffer + chunk_bytes,
1680 written_bytes - chunk_bytes);
1684 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1685 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1687 ACImpl *This = impl_from_IAudioRenderClient(iface);
1688 UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1692 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1694 EnterCriticalSection(&This->lock);
1696 if(This->buf_state == NOT_LOCKED || !written_frames){
1697 This->buf_state = NOT_LOCKED;
1698 LeaveCriticalSection(&This->lock);
1699 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1702 if(This->buf_state == LOCKED_NORMAL)
1703 buffer = This->local_buffer +
1704 This->lcl_offs_frames * This->fmt->nBlockAlign;
1706 buffer = This->tmp_buffer;
1708 if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1709 WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1710 if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1711 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1712 IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1713 This->fmt->wBitsPerSample == 8)
1714 memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
1716 memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
1719 if(This->held_frames){
1720 if(This->buf_state == LOCKED_WRAPPED)
1721 alsa_wrap_buffer(This, buffer, written_bytes);
1723 This->held_frames += written_frames;
1725 snd_pcm_sframes_t written;
1727 written = alsa_write_best_effort(This->pcm_handle, buffer,
1730 LeaveCriticalSection(&This->lock);
1731 WARN("write failed: %ld (%s)\n", written, snd_strerror(written));
1735 if(written < written_frames){
1736 if(This->buf_state == LOCKED_WRAPPED)
1737 alsa_wrap_buffer(This,
1738 This->tmp_buffer + written * This->fmt->nBlockAlign,
1739 written_frames - written);
1741 This->held_frames = written_frames - written;
1746 snd_pcm_state(This->pcm_handle) == SND_PCM_STATE_PREPARED){
1747 hr = alsa_consider_start(This);
1749 LeaveCriticalSection(&This->lock);
1754 This->written_frames += written_frames;
1755 This->buf_state = NOT_LOCKED;
1757 LeaveCriticalSection(&This->lock);
1762 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1763 AudioRenderClient_QueryInterface,
1764 AudioRenderClient_AddRef,
1765 AudioRenderClient_Release,
1766 AudioRenderClient_GetBuffer,
1767 AudioRenderClient_ReleaseBuffer
1770 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1771 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1773 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1779 if(IsEqualIID(riid, &IID_IUnknown) ||
1780 IsEqualIID(riid, &IID_IAudioCaptureClient))
1783 IUnknown_AddRef((IUnknown*)*ppv);
1787 WARN("Unknown interface %s\n", debugstr_guid(riid));
1788 return E_NOINTERFACE;
1791 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1793 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1794 return IAudioClient_AddRef(&This->IAudioClient_iface);
1797 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1799 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1800 return IAudioClient_Release(&This->IAudioClient_iface);
1803 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1804 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1807 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1810 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1813 if(!data || !frames || !flags)
1816 EnterCriticalSection(&This->lock);
1818 if(This->buf_state != NOT_LOCKED){
1819 LeaveCriticalSection(&This->lock);
1820 return AUDCLNT_E_OUT_OF_ORDER;
1823 hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1825 LeaveCriticalSection(&This->lock);
1831 if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1832 UINT32 chunk_bytes, offs_bytes, frames_bytes;
1833 if(This->tmp_buffer_frames < *frames){
1834 if(This->tmp_buffer)
1835 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1836 This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1838 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1839 *frames * This->fmt->nBlockAlign);
1840 if(!This->tmp_buffer){
1841 LeaveCriticalSection(&This->lock);
1842 return E_OUTOFMEMORY;
1844 This->tmp_buffer_frames = *frames;
1847 *data = This->tmp_buffer;
1848 chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1849 This->fmt->nBlockAlign;
1850 offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1851 frames_bytes = *frames * This->fmt->nBlockAlign;
1852 memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1853 memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
1854 frames_bytes - chunk_bytes);
1856 *data = This->local_buffer +
1857 This->lcl_offs_frames * This->fmt->nBlockAlign;
1859 This->buf_state = LOCKED_NORMAL;
1861 if(devpos || qpcpos)
1862 IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1864 LeaveCriticalSection(&This->lock);
1866 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1869 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1870 IAudioCaptureClient *iface, UINT32 done)
1872 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1874 TRACE("(%p)->(%u)\n", This, done);
1876 EnterCriticalSection(&This->lock);
1878 if(This->buf_state == NOT_LOCKED){
1879 LeaveCriticalSection(&This->lock);
1880 return AUDCLNT_E_OUT_OF_ORDER;
1883 This->held_frames -= done;
1884 This->lcl_offs_frames += done;
1885 This->lcl_offs_frames %= This->bufsize_frames;
1887 This->buf_state = NOT_LOCKED;
1889 LeaveCriticalSection(&This->lock);
1894 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1895 IAudioCaptureClient *iface, UINT32 *frames)
1897 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1899 TRACE("(%p)->(%p)\n", This, frames);
1901 return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1904 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1906 AudioCaptureClient_QueryInterface,
1907 AudioCaptureClient_AddRef,
1908 AudioCaptureClient_Release,
1909 AudioCaptureClient_GetBuffer,
1910 AudioCaptureClient_ReleaseBuffer,
1911 AudioCaptureClient_GetNextPacketSize
1914 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1915 REFIID riid, void **ppv)
1917 ACImpl *This = impl_from_IAudioClock(iface);
1919 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1925 if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1927 else if(IsEqualIID(riid, &IID_IAudioClock2))
1928 *ppv = &This->IAudioClock2_iface;
1930 IUnknown_AddRef((IUnknown*)*ppv);
1934 WARN("Unknown interface %s\n", debugstr_guid(riid));
1935 return E_NOINTERFACE;
1938 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1940 ACImpl *This = impl_from_IAudioClock(iface);
1941 return IAudioClient_AddRef(&This->IAudioClient_iface);
1944 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1946 ACImpl *This = impl_from_IAudioClock(iface);
1947 return IAudioClient_Release(&This->IAudioClient_iface);
1950 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1952 ACImpl *This = impl_from_IAudioClock(iface);
1954 TRACE("(%p)->(%p)\n", This, freq);
1956 *freq = This->fmt->nSamplesPerSec;
1961 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1964 ACImpl *This = impl_from_IAudioClock(iface);
1968 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1973 EnterCriticalSection(&This->lock);
1975 hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1977 LeaveCriticalSection(&This->lock);
1981 if(This->dataflow == eRender)
1982 *pos = This->written_frames - pad;
1983 else if(This->dataflow == eCapture)
1984 *pos = This->written_frames + pad;
1986 LeaveCriticalSection(&This->lock);
1989 LARGE_INTEGER stamp, freq;
1990 QueryPerformanceCounter(&stamp);
1991 QueryPerformanceFrequency(&freq);
1992 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1998 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2001 ACImpl *This = impl_from_IAudioClock(iface);
2003 TRACE("(%p)->(%p)\n", This, chars);
2008 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2013 static const IAudioClockVtbl AudioClock_Vtbl =
2015 AudioClock_QueryInterface,
2018 AudioClock_GetFrequency,
2019 AudioClock_GetPosition,
2020 AudioClock_GetCharacteristics
2023 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2024 REFIID riid, void **ppv)
2026 ACImpl *This = impl_from_IAudioClock2(iface);
2027 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2030 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2032 ACImpl *This = impl_from_IAudioClock2(iface);
2033 return IAudioClient_AddRef(&This->IAudioClient_iface);
2036 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2038 ACImpl *This = impl_from_IAudioClock2(iface);
2039 return IAudioClient_Release(&This->IAudioClient_iface);
2042 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2043 UINT64 *pos, UINT64 *qpctime)
2045 ACImpl *This = impl_from_IAudioClock2(iface);
2047 FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2052 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2054 AudioClock2_QueryInterface,
2056 AudioClock2_Release,
2057 AudioClock2_GetDevicePosition
2060 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2062 AudioSessionWrapper *ret;
2064 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2065 sizeof(AudioSessionWrapper));
2069 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2070 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2071 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2073 ret->client = client;
2074 ret->session = client->session;
2075 AudioClient_AddRef(&client->IAudioClient_iface);
2080 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2081 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2083 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2089 if(IsEqualIID(riid, &IID_IUnknown) ||
2090 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2091 IsEqualIID(riid, &IID_IAudioSessionControl2))
2094 IUnknown_AddRef((IUnknown*)*ppv);
2098 WARN("Unknown interface %s\n", debugstr_guid(riid));
2099 return E_NOINTERFACE;
2102 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2104 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2106 ref = InterlockedIncrement(&This->ref);
2107 TRACE("(%p) Refcount now %u\n", This, ref);
2111 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2113 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2115 ref = InterlockedDecrement(&This->ref);
2116 TRACE("(%p) Refcount now %u\n", This, ref);
2118 EnterCriticalSection(&This->client->lock);
2119 This->client->session_wrapper = NULL;
2120 LeaveCriticalSection(&This->client->lock);
2121 AudioClient_Release(&This->client->IAudioClient_iface);
2122 HeapFree(GetProcessHeap(), 0, This);
2127 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2128 AudioSessionState *state)
2130 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2133 TRACE("(%p)->(%p)\n", This, state);
2136 return NULL_PTR_ERR;
2138 EnterCriticalSection(&g_sessions_lock);
2140 if(list_empty(&This->session->clients)){
2141 *state = AudioSessionStateExpired;
2142 LeaveCriticalSection(&g_sessions_lock);
2146 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2147 EnterCriticalSection(&client->lock);
2148 if(client->started){
2149 *state = AudioSessionStateActive;
2150 LeaveCriticalSection(&client->lock);
2151 LeaveCriticalSection(&g_sessions_lock);
2154 LeaveCriticalSection(&client->lock);
2157 LeaveCriticalSection(&g_sessions_lock);
2159 *state = AudioSessionStateInactive;
2164 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2165 IAudioSessionControl2 *iface, WCHAR **name)
2167 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2169 FIXME("(%p)->(%p) - stub\n", This, name);
2174 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2175 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2177 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2179 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2184 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2185 IAudioSessionControl2 *iface, WCHAR **path)
2187 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2189 FIXME("(%p)->(%p) - stub\n", This, path);
2194 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2195 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2197 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2199 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2204 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2205 IAudioSessionControl2 *iface, GUID *group)
2207 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2209 FIXME("(%p)->(%p) - stub\n", This, group);
2214 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2215 IAudioSessionControl2 *iface, GUID *group, const GUID *session)
2217 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2219 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2220 debugstr_guid(session));
2225 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2226 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2228 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2230 FIXME("(%p)->(%p) - stub\n", This, events);
2235 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2236 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2238 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2240 FIXME("(%p)->(%p) - stub\n", This, events);
2245 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2246 IAudioSessionControl2 *iface, WCHAR **id)
2248 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2250 FIXME("(%p)->(%p) - stub\n", This, id);
2255 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2256 IAudioSessionControl2 *iface, WCHAR **id)
2258 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2260 FIXME("(%p)->(%p) - stub\n", This, id);
2265 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2266 IAudioSessionControl2 *iface, DWORD *pid)
2268 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2270 TRACE("(%p)->(%p)\n", This, pid);
2275 *pid = GetCurrentProcessId();
2280 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2281 IAudioSessionControl2 *iface)
2283 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2285 TRACE("(%p)\n", This);
2290 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2291 IAudioSessionControl2 *iface, BOOL optout)
2293 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2295 TRACE("(%p)->(%d)\n", This, optout);
2300 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2302 AudioSessionControl_QueryInterface,
2303 AudioSessionControl_AddRef,
2304 AudioSessionControl_Release,
2305 AudioSessionControl_GetState,
2306 AudioSessionControl_GetDisplayName,
2307 AudioSessionControl_SetDisplayName,
2308 AudioSessionControl_GetIconPath,
2309 AudioSessionControl_SetIconPath,
2310 AudioSessionControl_GetGroupingParam,
2311 AudioSessionControl_SetGroupingParam,
2312 AudioSessionControl_RegisterAudioSessionNotification,
2313 AudioSessionControl_UnregisterAudioSessionNotification,
2314 AudioSessionControl_GetSessionIdentifier,
2315 AudioSessionControl_GetSessionInstanceIdentifier,
2316 AudioSessionControl_GetProcessId,
2317 AudioSessionControl_IsSystemSoundsSession,
2318 AudioSessionControl_SetDuckingPreference
2321 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2322 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2324 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2330 if(IsEqualIID(riid, &IID_IUnknown) ||
2331 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2334 IUnknown_AddRef((IUnknown*)*ppv);
2338 WARN("Unknown interface %s\n", debugstr_guid(riid));
2339 return E_NOINTERFACE;
2342 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2344 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2345 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2348 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2350 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2351 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2354 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2355 ISimpleAudioVolume *iface, float level, const GUID *context)
2357 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2358 AudioSession *session = This->session;
2360 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2362 if(level < 0.f || level > 1.f)
2363 return E_INVALIDARG;
2366 FIXME("Notifications not supported yet\n");
2368 TRACE("ALSA does not support volume control\n");
2370 EnterCriticalSection(&session->lock);
2372 session->master_vol = level;
2374 LeaveCriticalSection(&session->lock);
2379 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2380 ISimpleAudioVolume *iface, float *level)
2382 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2383 AudioSession *session = This->session;
2385 TRACE("(%p)->(%p)\n", session, level);
2388 return NULL_PTR_ERR;
2390 *level = session->master_vol;
2395 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2396 BOOL mute, const GUID *context)
2398 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2399 AudioSession *session = This->session;
2401 FIXME("(%p)->(%u, %p) - stub\n", session, mute, context);
2406 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2409 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2410 AudioSession *session = This->session;
2412 FIXME("(%p)->(%p) - stub\n", session, mute);
2415 return NULL_PTR_ERR;
2420 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
2422 SimpleAudioVolume_QueryInterface,
2423 SimpleAudioVolume_AddRef,
2424 SimpleAudioVolume_Release,
2425 SimpleAudioVolume_SetMasterVolume,
2426 SimpleAudioVolume_GetMasterVolume,
2427 SimpleAudioVolume_SetMute,
2428 SimpleAudioVolume_GetMute
2431 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2432 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2434 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2440 if(IsEqualIID(riid, &IID_IUnknown) ||
2441 IsEqualIID(riid, &IID_IAudioStreamVolume))
2444 IUnknown_AddRef((IUnknown*)*ppv);
2448 WARN("Unknown interface %s\n", debugstr_guid(riid));
2449 return E_NOINTERFACE;
2452 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2454 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2455 return IAudioClient_AddRef(&This->IAudioClient_iface);
2458 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2460 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2461 return IAudioClient_Release(&This->IAudioClient_iface);
2464 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2465 IAudioStreamVolume *iface, UINT32 *out)
2467 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2469 TRACE("(%p)->(%p)\n", This, out);
2474 *out = This->fmt->nChannels;
2479 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2480 IAudioStreamVolume *iface, UINT32 index, float level)
2482 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2484 TRACE("(%p)->(%d, %f)\n", This, index, level);
2486 if(level < 0.f || level > 1.f)
2487 return E_INVALIDARG;
2489 if(index >= This->fmt->nChannels)
2490 return E_INVALIDARG;
2492 TRACE("ALSA does not support volume control\n");
2494 EnterCriticalSection(&This->lock);
2496 This->vols[index] = level;
2498 LeaveCriticalSection(&This->lock);
2503 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2504 IAudioStreamVolume *iface, UINT32 index, float *level)
2506 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2508 TRACE("(%p)->(%d, %p)\n", This, index, level);
2513 if(index >= This->fmt->nChannels)
2514 return E_INVALIDARG;
2516 *level = This->vols[index];
2521 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2522 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2524 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2527 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2532 if(count != This->fmt->nChannels)
2533 return E_INVALIDARG;
2535 TRACE("ALSA does not support volume control\n");
2537 EnterCriticalSection(&This->lock);
2539 for(i = 0; i < count; ++i)
2540 This->vols[i] = levels[i];
2542 LeaveCriticalSection(&This->lock);
2547 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2548 IAudioStreamVolume *iface, UINT32 count, float *levels)
2550 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2553 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2558 if(count != This->fmt->nChannels)
2559 return E_INVALIDARG;
2561 EnterCriticalSection(&This->lock);
2563 for(i = 0; i < count; ++i)
2564 levels[i] = This->vols[i];
2566 LeaveCriticalSection(&This->lock);
2571 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2573 AudioStreamVolume_QueryInterface,
2574 AudioStreamVolume_AddRef,
2575 AudioStreamVolume_Release,
2576 AudioStreamVolume_GetChannelCount,
2577 AudioStreamVolume_SetChannelVolume,
2578 AudioStreamVolume_GetChannelVolume,
2579 AudioStreamVolume_SetAllVolumes,
2580 AudioStreamVolume_GetAllVolumes
2583 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2584 IChannelAudioVolume *iface, REFIID riid, void **ppv)
2586 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2592 if(IsEqualIID(riid, &IID_IUnknown) ||
2593 IsEqualIID(riid, &IID_IChannelAudioVolume))
2596 IUnknown_AddRef((IUnknown*)*ppv);
2600 WARN("Unknown interface %s\n", debugstr_guid(riid));
2601 return E_NOINTERFACE;
2604 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2606 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2607 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2610 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2612 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2613 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2616 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2617 IChannelAudioVolume *iface, UINT32 *out)
2619 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2620 AudioSession *session = This->session;
2622 TRACE("(%p)->(%p)\n", session, out);
2625 return NULL_PTR_ERR;
2627 *out = session->channel_count;
2632 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2633 IChannelAudioVolume *iface, UINT32 index, float level,
2634 const GUID *context)
2636 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2637 AudioSession *session = This->session;
2639 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2640 wine_dbgstr_guid(context));
2642 if(level < 0.f || level > 1.f)
2643 return E_INVALIDARG;
2645 if(index >= session->channel_count)
2646 return E_INVALIDARG;
2649 FIXME("Notifications not supported yet\n");
2651 TRACE("ALSA does not support volume control\n");
2653 EnterCriticalSection(&session->lock);
2655 session->channel_vols[index] = level;
2657 LeaveCriticalSection(&session->lock);
2662 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2663 IChannelAudioVolume *iface, UINT32 index, float *level)
2665 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2666 AudioSession *session = This->session;
2668 TRACE("(%p)->(%d, %p)\n", session, index, level);
2671 return NULL_PTR_ERR;
2673 if(index >= session->channel_count)
2674 return E_INVALIDARG;
2676 *level = session->channel_vols[index];
2681 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2682 IChannelAudioVolume *iface, UINT32 count, const float *levels,
2683 const GUID *context)
2685 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2686 AudioSession *session = This->session;
2689 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2690 wine_dbgstr_guid(context));
2693 return NULL_PTR_ERR;
2695 if(count != session->channel_count)
2696 return E_INVALIDARG;
2699 FIXME("Notifications not supported yet\n");
2701 TRACE("ALSA does not support volume control\n");
2703 EnterCriticalSection(&session->lock);
2705 for(i = 0; i < count; ++i)
2706 session->channel_vols[i] = levels[i];
2708 LeaveCriticalSection(&session->lock);
2713 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2714 IChannelAudioVolume *iface, UINT32 count, float *levels)
2716 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2717 AudioSession *session = This->session;
2720 TRACE("(%p)->(%d, %p)\n", session, count, levels);
2723 return NULL_PTR_ERR;
2725 if(count != session->channel_count)
2726 return E_INVALIDARG;
2728 for(i = 0; i < count; ++i)
2729 levels[i] = session->channel_vols[i];
2734 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2736 ChannelAudioVolume_QueryInterface,
2737 ChannelAudioVolume_AddRef,
2738 ChannelAudioVolume_Release,
2739 ChannelAudioVolume_GetChannelCount,
2740 ChannelAudioVolume_SetChannelVolume,
2741 ChannelAudioVolume_GetChannelVolume,
2742 ChannelAudioVolume_SetAllVolumes,
2743 ChannelAudioVolume_GetAllVolumes