winepulse: Always mute buffer.
[wine/multimedia.git] / dlls / winepulse.drv / mmdevdrv.c
blob0e2bc08538cc4aaae4ec77b4705b21c781f91d7b
1 /*
2 * Copyright 2011-2012 Maarten Lankhorst
3 * Copyright 2010-2011 Maarten Lankhorst for CodeWeavers
4 * Copyright 2011 Andrew Eikum for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
22 #define COBJMACROS
23 #define _GNU_SOURCE
25 #include "config.h"
26 #include <poll.h>
27 #include <pthread.h>
29 #include <stdarg.h>
30 #include <unistd.h>
31 #include <math.h>
32 #include <stdio.h>
33 #include <errno.h>
35 #include <pulse/pulseaudio.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winreg.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
45 #include "ole2.h"
46 #include "dshow.h"
47 #include "dsound.h"
48 #include "propsys.h"
50 #include "initguid.h"
51 #include "ks.h"
52 #include "ksmedia.h"
53 #include "mmdeviceapi.h"
54 #include "audioclient.h"
55 #include "endpointvolume.h"
56 #include "audiopolicy.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(pulse);
60 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
62 /* From <dlls/mmdevapi/mmdevapi.h> */
63 enum DriverPriority {
64 Priority_Unavailable = 0,
65 Priority_Low,
66 Priority_Neutral,
67 Priority_Preferred
70 static const REFERENCE_TIME MinimumPeriod = 30000;
71 static const REFERENCE_TIME DefaultPeriod = 100000;
73 static pa_context *pulse_ctx;
74 static pa_mainloop *pulse_ml;
76 static HANDLE pulse_thread;
77 static pthread_mutex_t pulse_lock;
78 static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
79 static struct list g_sessions = LIST_INIT(g_sessions);
81 /* Mixer format + period times */
82 static WAVEFORMATEXTENSIBLE pulse_fmt[2];
83 static REFERENCE_TIME pulse_min_period[2], pulse_def_period[2];
85 static GUID pulse_render_guid =
86 { 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } };
87 static GUID pulse_capture_guid =
88 { 0x25da76d0, 0x033c, 0x4235, { 0x90, 0x02, 0x19, 0xf4, 0x88, 0x94, 0xac, 0x6f } };
90 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
92 if (reason == DLL_PROCESS_ATTACH) {
93 pthread_mutexattr_t attr;
95 DisableThreadLibraryCalls(dll);
97 pthread_mutexattr_init(&attr);
98 pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
100 if (pthread_mutex_init(&pulse_lock, &attr) != 0)
101 pthread_mutex_init(&pulse_lock, NULL);
102 } else if (reason == DLL_PROCESS_DETACH) {
103 if (pulse_thread)
104 SetThreadPriority(pulse_thread, 0);
105 if (pulse_ctx) {
106 pa_context_disconnect(pulse_ctx);
107 pa_context_unref(pulse_ctx);
109 if (pulse_ml)
110 pa_mainloop_quit(pulse_ml, 0);
111 if (pulse_thread) {
112 WaitForSingleObject(pulse_thread, INFINITE);
113 CloseHandle(pulse_thread);
116 return TRUE;
119 typedef struct ACImpl ACImpl;
121 typedef struct _AudioSession {
122 GUID guid;
123 struct list clients;
125 IMMDevice *device;
127 float master_vol;
128 UINT32 channel_count;
129 float *channel_vols;
130 BOOL mute;
132 struct list entry;
133 } AudioSession;
135 typedef struct _AudioSessionWrapper {
136 IAudioSessionControl2 IAudioSessionControl2_iface;
137 IChannelAudioVolume IChannelAudioVolume_iface;
138 ISimpleAudioVolume ISimpleAudioVolume_iface;
140 LONG ref;
142 ACImpl *client;
143 AudioSession *session;
144 } AudioSessionWrapper;
146 typedef struct _ACPacket {
147 struct list entry;
148 UINT64 qpcpos;
149 BYTE *data;
150 UINT32 discont;
151 } ACPacket;
153 struct ACImpl {
154 IAudioClient IAudioClient_iface;
155 IAudioRenderClient IAudioRenderClient_iface;
156 IAudioCaptureClient IAudioCaptureClient_iface;
157 IAudioClock IAudioClock_iface;
158 IAudioClock2 IAudioClock2_iface;
159 IAudioStreamVolume IAudioStreamVolume_iface;
160 IUnknown *marshal;
161 IMMDevice *parent;
162 struct list entry;
163 float vol[PA_CHANNELS_MAX];
165 LONG ref;
166 EDataFlow dataflow;
167 DWORD flags;
168 AUDCLNT_SHAREMODE share;
169 HANDLE event;
171 UINT32 bufsize_frames, bufsize_bytes, locked, capture_period, pad, started, peek_ofs;
172 void *locked_ptr, *tmp_buffer;
174 pa_stream *stream;
175 pa_sample_spec ss;
176 pa_channel_map map;
178 INT64 clock_lastpos, clock_written;
180 AudioSession *session;
181 AudioSessionWrapper *session_wrapper;
182 struct list packet_free_head;
183 struct list packet_filled_head;
186 static const WCHAR defaultW[] = {'P','u','l','s','e','a','u','d','i','o',0};
188 static const IAudioClientVtbl AudioClient_Vtbl;
189 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
190 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
191 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
192 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
193 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
194 static const IAudioClockVtbl AudioClock_Vtbl;
195 static const IAudioClock2Vtbl AudioClock2_Vtbl;
196 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
198 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
200 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
202 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
205 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
207 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
210 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
212 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
215 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
217 return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
220 static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
222 return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
225 static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
227 return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
230 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
232 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
235 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
237 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
240 static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface)
242 return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface);
245 /* Following pulseaudio design here, mainloop has the lock taken whenever
246 * it is handling something for pulse, and the lock is required whenever
247 * doing any pa_* call that can affect the state in any way
249 * pa_cond_wait is used when waiting on results, because the mainloop needs
250 * the same lock taken to affect the state
252 * This is basically the same as the pa_threaded_mainloop implementation,
253 * but that cannot be used because it uses pthread_create directly
255 * pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock
256 * pa_threaded_mainloop_signal -> pthread_cond_signal
257 * pa_threaded_mainloop_wait -> pthread_cond_wait
260 static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
261 int r;
262 pthread_mutex_unlock(&pulse_lock);
263 r = poll(ufds, nfds, timeout);
264 pthread_mutex_lock(&pulse_lock);
265 return r;
268 static DWORD CALLBACK pulse_mainloop_thread(void *tmp) {
269 int ret;
270 pulse_ml = pa_mainloop_new();
271 pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL);
272 pthread_mutex_lock(&pulse_lock);
273 pthread_cond_signal(&pulse_cond);
274 pa_mainloop_run(pulse_ml, &ret);
275 pthread_mutex_unlock(&pulse_lock);
276 pa_mainloop_free(pulse_ml);
277 return ret;
280 static void pulse_contextcallback(pa_context *c, void *userdata)
282 switch (pa_context_get_state(c)) {
283 default:
284 FIXME("Unhandled state: %i\n", pa_context_get_state(c));
285 case PA_CONTEXT_CONNECTING:
286 case PA_CONTEXT_UNCONNECTED:
287 case PA_CONTEXT_AUTHORIZING:
288 case PA_CONTEXT_SETTING_NAME:
289 case PA_CONTEXT_TERMINATED:
290 TRACE("State change to %i\n", pa_context_get_state(c));
291 return;
293 case PA_CONTEXT_READY:
294 TRACE("Ready\n");
295 break;
297 case PA_CONTEXT_FAILED:
298 ERR("Context failed: %s\n", pa_strerror(pa_context_errno(c)));
299 break;
301 pthread_cond_signal(&pulse_cond);
304 static void pulse_stream_state(pa_stream *s, void *user)
306 pa_stream_state_t state = pa_stream_get_state(s);
307 TRACE("Stream state changed to %i\n", state);
308 pthread_cond_signal(&pulse_cond);
311 static const enum pa_channel_position pulse_pos_from_wfx[] = {
312 PA_CHANNEL_POSITION_FRONT_LEFT,
313 PA_CHANNEL_POSITION_FRONT_RIGHT,
314 PA_CHANNEL_POSITION_FRONT_CENTER,
315 PA_CHANNEL_POSITION_LFE,
316 PA_CHANNEL_POSITION_REAR_LEFT,
317 PA_CHANNEL_POSITION_REAR_RIGHT,
318 PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
319 PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
320 PA_CHANNEL_POSITION_REAR_CENTER,
321 PA_CHANNEL_POSITION_SIDE_LEFT,
322 PA_CHANNEL_POSITION_SIDE_RIGHT,
323 PA_CHANNEL_POSITION_TOP_CENTER,
324 PA_CHANNEL_POSITION_TOP_FRONT_LEFT,
325 PA_CHANNEL_POSITION_TOP_FRONT_CENTER,
326 PA_CHANNEL_POSITION_TOP_FRONT_RIGHT,
327 PA_CHANNEL_POSITION_TOP_REAR_LEFT,
328 PA_CHANNEL_POSITION_TOP_REAR_CENTER,
329 PA_CHANNEL_POSITION_TOP_REAR_RIGHT
332 static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
333 WAVEFORMATEX *wfx = &fmt->Format;
334 pa_stream *stream;
335 pa_channel_map map;
336 pa_sample_spec ss;
337 pa_buffer_attr attr;
338 int ret, i;
339 unsigned int length = 0;
341 pa_channel_map_init_auto(&map, 2, PA_CHANNEL_MAP_ALSA);
342 ss.rate = 48000;
343 ss.format = PA_SAMPLE_FLOAT32LE;
344 ss.channels = map.channels;
346 attr.maxlength = -1;
347 attr.tlength = -1;
348 attr.minreq = attr.fragsize = pa_frame_size(&ss);
349 attr.prebuf = 0;
351 stream = pa_stream_new(pulse_ctx, "format test stream", &ss, &map);
352 if (stream)
353 pa_stream_set_state_callback(stream, pulse_stream_state, NULL);
354 if (!stream)
355 ret = -1;
356 else if (render)
357 ret = pa_stream_connect_playback(stream, NULL, &attr,
358 PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
359 else
360 ret = pa_stream_connect_record(stream, NULL, &attr, PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS);
361 if (ret >= 0) {
362 while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 &&
363 pa_stream_get_state(stream) == PA_STREAM_CREATING)
365 if (pa_stream_get_state(stream) == PA_STREAM_READY) {
366 ss = *pa_stream_get_sample_spec(stream);
367 map = *pa_stream_get_channel_map(stream);
368 if (render)
369 length = pa_stream_get_buffer_attr(stream)->minreq;
370 else
371 length = pa_stream_get_buffer_attr(stream)->fragsize;
372 pa_stream_disconnect(stream);
373 while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 &&
374 pa_stream_get_state(stream) == PA_STREAM_READY)
378 if (stream)
379 pa_stream_unref(stream);
380 if (length)
381 pulse_def_period[!render] = pulse_min_period[!render] = pa_bytes_to_usec(10 * length, &ss);
382 else
383 pulse_min_period[!render] = MinimumPeriod;
384 if (pulse_def_period[!render] <= DefaultPeriod)
385 pulse_def_period[!render] = DefaultPeriod;
387 wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
388 wfx->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
389 wfx->nChannels = ss.channels;
390 wfx->wBitsPerSample = 8 * pa_sample_size_of_format(ss.format);
391 wfx->nSamplesPerSec = ss.rate;
392 wfx->nBlockAlign = pa_frame_size(&ss);
393 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
394 if (ss.format != PA_SAMPLE_S24_32LE)
395 fmt->Samples.wValidBitsPerSample = wfx->wBitsPerSample;
396 else
397 fmt->Samples.wValidBitsPerSample = 24;
398 if (ss.format == PA_SAMPLE_FLOAT32LE)
399 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
400 else
401 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
403 fmt->dwChannelMask = 0;
404 for (i = 0; i < map.channels; ++i)
405 switch (map.map[i]) {
406 default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map.map[i])); break;
407 case PA_CHANNEL_POSITION_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_FRONT_LEFT; break;
408 case PA_CHANNEL_POSITION_MONO:
409 case PA_CHANNEL_POSITION_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_FRONT_CENTER; break;
410 case PA_CHANNEL_POSITION_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_FRONT_RIGHT; break;
411 case PA_CHANNEL_POSITION_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_BACK_LEFT; break;
412 case PA_CHANNEL_POSITION_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_BACK_CENTER; break;
413 case PA_CHANNEL_POSITION_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_BACK_RIGHT; break;
414 case PA_CHANNEL_POSITION_LFE: fmt->dwChannelMask |= SPEAKER_LOW_FREQUENCY; break;
415 case PA_CHANNEL_POSITION_SIDE_LEFT: fmt->dwChannelMask |= SPEAKER_SIDE_LEFT; break;
416 case PA_CHANNEL_POSITION_SIDE_RIGHT: fmt->dwChannelMask |= SPEAKER_SIDE_RIGHT; break;
417 case PA_CHANNEL_POSITION_TOP_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_CENTER; break;
418 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_LEFT; break;
419 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_CENTER; break;
420 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_RIGHT; break;
421 case PA_CHANNEL_POSITION_TOP_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_LEFT; break;
422 case PA_CHANNEL_POSITION_TOP_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_BACK_CENTER; break;
423 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_RIGHT; break;
427 static HRESULT pulse_connect(void)
429 int len;
430 WCHAR path[PATH_MAX], *name;
431 char *str;
433 if (!pulse_thread)
435 if (!(pulse_thread = CreateThread(NULL, 0, pulse_mainloop_thread, NULL, 0, NULL)))
437 ERR("Failed to create mainloop thread.\n");
438 return E_FAIL;
440 SetThreadPriority(pulse_thread, THREAD_PRIORITY_TIME_CRITICAL);
441 pthread_cond_wait(&pulse_cond, &pulse_lock);
444 if (pulse_ctx && PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx)))
445 return S_OK;
446 if (pulse_ctx)
447 pa_context_unref(pulse_ctx);
449 GetModuleFileNameW(NULL, path, sizeof(path)/sizeof(*path));
450 name = strrchrW(path, '\\');
451 if (!name)
452 name = path;
453 else
454 name++;
455 len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
456 str = pa_xmalloc(len);
457 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL);
458 TRACE("Name: %s\n", str);
459 pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str);
460 pa_xfree(str);
461 if (!pulse_ctx) {
462 ERR("Failed to create context\n");
463 return E_FAIL;
466 pa_context_set_state_callback(pulse_ctx, pulse_contextcallback, NULL);
468 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx), PA_API_VERSION);
469 if (pa_context_connect(pulse_ctx, NULL, 0, NULL) < 0)
470 goto fail;
472 /* Wait for connection */
473 while (pthread_cond_wait(&pulse_cond, &pulse_lock)) {
474 pa_context_state_t state = pa_context_get_state(pulse_ctx);
476 if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
477 goto fail;
479 if (state == PA_CONTEXT_READY)
480 break;
483 TRACE("Connected to server %s with protocol version: %i.\n",
484 pa_context_get_server(pulse_ctx),
485 pa_context_get_server_protocol_version(pulse_ctx));
486 return S_OK;
488 fail:
489 pa_context_unref(pulse_ctx);
490 pulse_ctx = NULL;
491 return E_FAIL;
494 /* some poorly-behaved applications call audio functions during DllMain, so we
495 * have to do as much as possible without creating a new thread. this function
496 * sets up a synchronous connection to verify the server is running and query
497 * static data. */
498 static HRESULT pulse_test_connect(void)
500 int len, ret;
501 WCHAR path[PATH_MAX], *name;
502 char *str;
504 pulse_ml = pa_mainloop_new();
506 pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL);
508 GetModuleFileNameW(NULL, path, sizeof(path)/sizeof(*path));
509 name = strrchrW(path, '\\');
510 if (!name)
511 name = path;
512 else
513 name++;
514 len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
515 str = pa_xmalloc(len);
516 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL);
517 TRACE("Name: %s\n", str);
518 pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str);
519 pa_xfree(str);
520 if (!pulse_ctx) {
521 ERR("Failed to create context\n");
522 pa_mainloop_free(pulse_ml);
523 pulse_ml = NULL;
524 return E_FAIL;
527 pa_context_set_state_callback(pulse_ctx, pulse_contextcallback, NULL);
529 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx), PA_API_VERSION);
530 if (pa_context_connect(pulse_ctx, NULL, 0, NULL) < 0)
531 goto fail;
533 /* Wait for connection */
534 while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0) {
535 pa_context_state_t state = pa_context_get_state(pulse_ctx);
537 if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
538 goto fail;
540 if (state == PA_CONTEXT_READY)
541 break;
544 TRACE("Test-connected to server %s with protocol version: %i.\n",
545 pa_context_get_server(pulse_ctx),
546 pa_context_get_server_protocol_version(pulse_ctx));
548 pulse_probe_settings(1, &pulse_fmt[0]);
549 pulse_probe_settings(0, &pulse_fmt[1]);
551 pa_context_unref(pulse_ctx);
552 pulse_ctx = NULL;
553 pa_mainloop_free(pulse_ml);
554 pulse_ml = NULL;
556 return S_OK;
558 fail:
559 pa_context_unref(pulse_ctx);
560 pulse_ctx = NULL;
561 pa_mainloop_free(pulse_ml);
562 pulse_ml = NULL;
564 return E_FAIL;
567 static HRESULT pulse_stream_valid(ACImpl *This) {
568 if (!This->stream)
569 return AUDCLNT_E_NOT_INITIALIZED;
570 if (!This->stream || pa_stream_get_state(This->stream) != PA_STREAM_READY)
571 return AUDCLNT_E_DEVICE_INVALIDATED;
572 return S_OK;
575 static void silence_buffer(pa_sample_format_t format, BYTE *buffer, UINT32 bytes)
577 memset(buffer, format == PA_SAMPLE_U8 ? 0x80 : 0, bytes);
580 static void dump_attr(const pa_buffer_attr *attr) {
581 TRACE("maxlength: %u\n", attr->maxlength);
582 TRACE("minreq: %u\n", attr->minreq);
583 TRACE("fragsize: %u\n", attr->fragsize);
584 TRACE("tlength: %u\n", attr->tlength);
585 TRACE("prebuf: %u\n", attr->prebuf);
588 static void pulse_op_cb(pa_stream *s, int success, void *user) {
589 TRACE("Success: %i\n", success);
590 *(int*)user = success;
591 pthread_cond_signal(&pulse_cond);
594 static void pulse_attr_update(pa_stream *s, void *user) {
595 const pa_buffer_attr *attr = pa_stream_get_buffer_attr(s);
596 TRACE("New attributes or device moved:\n");
597 dump_attr(attr);
600 static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata)
602 ACImpl *This = userdata;
603 UINT32 oldpad = This->pad;
605 if (bytes < This->bufsize_bytes)
606 This->pad = This->bufsize_bytes - bytes;
607 else
608 This->pad = 0;
610 if (oldpad == This->pad)
611 return;
613 assert(oldpad > This->pad);
615 This->clock_written += oldpad - This->pad;
616 TRACE("New pad: %zu (-%zu)\n", This->pad / pa_frame_size(&This->ss), (oldpad - This->pad) / pa_frame_size(&This->ss));
618 if (This->event)
619 SetEvent(This->event);
622 static void pulse_underflow_callback(pa_stream *s, void *userdata)
624 WARN("Underflow\n");
627 /* Latency is periodically updated even when nothing is played,
628 * because of PA_STREAM_AUTO_TIMING_UPDATE so use it as timer
630 * Perfect for passing all tests :)
632 static void pulse_latency_callback(pa_stream *s, void *userdata)
634 ACImpl *This = userdata;
635 if (!This->pad && This->event)
636 SetEvent(This->event);
639 static void pulse_started_callback(pa_stream *s, void *userdata)
641 TRACE("(Re)started playing\n");
644 static void pulse_rd_loop(ACImpl *This, size_t bytes)
646 while (bytes >= This->capture_period) {
647 ACPacket *p, *next;
648 LARGE_INTEGER stamp, freq;
649 BYTE *dst, *src;
650 size_t src_len, copy, rem = This->capture_period;
651 if (!(p = (ACPacket*)list_head(&This->packet_free_head))) {
652 p = (ACPacket*)list_head(&This->packet_filled_head);
653 if (!p->discont) {
654 next = (ACPacket*)p->entry.next;
655 next->discont = 1;
656 } else
657 p = (ACPacket*)list_tail(&This->packet_filled_head);
658 assert(This->pad == This->bufsize_bytes);
659 } else {
660 assert(This->pad < This->bufsize_bytes);
661 This->pad += This->capture_period;
662 assert(This->pad <= This->bufsize_bytes);
664 QueryPerformanceCounter(&stamp);
665 QueryPerformanceFrequency(&freq);
666 p->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
667 p->discont = 0;
668 list_remove(&p->entry);
669 list_add_tail(&This->packet_filled_head, &p->entry);
671 dst = p->data;
672 while (rem) {
673 pa_stream_peek(This->stream, (const void**)&src, &src_len);
674 assert(src_len);
675 assert(This->peek_ofs < src_len);
676 src += This->peek_ofs;
677 src_len -= This->peek_ofs;
678 assert(src_len <= bytes);
680 copy = rem;
681 if (copy > src_len)
682 copy = src_len;
683 memcpy(dst, src, rem);
684 src += copy;
685 src_len -= copy;
686 dst += copy;
687 rem -= copy;
689 if (!src_len) {
690 This->peek_ofs = 0;
691 pa_stream_drop(This->stream);
692 } else
693 This->peek_ofs += copy;
695 bytes -= This->capture_period;
699 static void pulse_rd_drop(ACImpl *This, size_t bytes)
701 while (bytes >= This->capture_period) {
702 size_t src_len, copy, rem = This->capture_period;
703 while (rem) {
704 const void *src;
705 pa_stream_peek(This->stream, &src, &src_len);
706 assert(src_len);
707 assert(This->peek_ofs < src_len);
708 src_len -= This->peek_ofs;
709 assert(src_len <= bytes);
711 copy = rem;
712 if (copy > src_len)
713 copy = src_len;
715 src_len -= copy;
716 rem -= copy;
718 if (!src_len) {
719 This->peek_ofs = 0;
720 pa_stream_drop(This->stream);
721 } else
722 This->peek_ofs += copy;
723 bytes -= copy;
728 static void pulse_rd_callback(pa_stream *s, size_t bytes, void *userdata)
730 ACImpl *This = userdata;
732 TRACE("Readable total: %zu, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(s)->fragsize);
733 assert(bytes >= This->peek_ofs);
734 bytes -= This->peek_ofs;
735 if (bytes < This->capture_period)
736 return;
738 if (This->started)
739 pulse_rd_loop(This, bytes);
740 else
741 pulse_rd_drop(This, bytes);
743 if (This->event)
744 SetEvent(This->event);
747 static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
748 int ret;
749 char buffer[64];
750 static LONG number;
751 pa_buffer_attr attr;
752 if (This->stream) {
753 pa_stream_disconnect(This->stream);
754 while (pa_stream_get_state(This->stream) == PA_STREAM_READY)
755 pthread_cond_wait(&pulse_cond, &pulse_lock);
756 pa_stream_unref(This->stream);
758 ret = InterlockedIncrement(&number);
759 sprintf(buffer, "audio stream #%i", ret);
760 This->stream = pa_stream_new(pulse_ctx, buffer, &This->ss, &This->map);
762 if (!This->stream) {
763 WARN("pa_stream_new returned error %i\n", pa_context_errno(pulse_ctx));
764 return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
767 pa_stream_set_state_callback(This->stream, pulse_stream_state, This);
768 pa_stream_set_buffer_attr_callback(This->stream, pulse_attr_update, This);
769 pa_stream_set_moved_callback(This->stream, pulse_attr_update, This);
771 /* Pulseaudio will fill in correct values */
772 attr.minreq = attr.fragsize = period_bytes;
773 attr.maxlength = attr.tlength = This->bufsize_bytes;
774 attr.prebuf = pa_frame_size(&This->ss);
775 dump_attr(&attr);
776 if (This->dataflow == eRender)
777 ret = pa_stream_connect_playback(This->stream, NULL, &attr,
778 PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
779 else
780 ret = pa_stream_connect_record(This->stream, NULL, &attr,
781 PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS);
782 if (ret < 0) {
783 WARN("Returns %i\n", ret);
784 return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
786 while (pa_stream_get_state(This->stream) == PA_STREAM_CREATING)
787 pthread_cond_wait(&pulse_cond, &pulse_lock);
788 if (pa_stream_get_state(This->stream) != PA_STREAM_READY)
789 return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
791 if (This->dataflow == eRender) {
792 pa_stream_set_write_callback(This->stream, pulse_wr_callback, This);
793 pa_stream_set_underflow_callback(This->stream, pulse_underflow_callback, This);
794 pa_stream_set_started_callback(This->stream, pulse_started_callback, This);
795 } else
796 pa_stream_set_read_callback(This->stream, pulse_rd_callback, This);
797 return S_OK;
800 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **keys,
801 UINT *num, UINT *def_index)
803 WCHAR *id;
805 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
807 *num = 1;
808 *def_index = 0;
810 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(**ids));
811 *keys = NULL;
812 if (!*ids)
813 return E_OUTOFMEMORY;
815 (*ids)[0] = id = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
816 *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(**keys));
817 if (!*keys || !id) {
818 HeapFree(GetProcessHeap(), 0, id);
819 HeapFree(GetProcessHeap(), 0, *keys);
820 HeapFree(GetProcessHeap(), 0, *ids);
821 *ids = NULL;
822 *keys = NULL;
823 return E_OUTOFMEMORY;
825 memcpy(id, defaultW, sizeof(defaultW));
827 if (flow == eRender)
828 (*keys)[0] = pulse_render_guid;
829 else
830 (*keys)[0] = pulse_capture_guid;
832 return S_OK;
835 int WINAPI AUDDRV_GetPriority(void)
837 HRESULT hr;
838 pthread_mutex_lock(&pulse_lock);
839 hr = pulse_test_connect();
840 pthread_mutex_unlock(&pulse_lock);
841 return SUCCEEDED(hr) ? Priority_Low : Priority_Unavailable;
844 HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
846 ACImpl *This;
847 int i;
848 EDataFlow dataflow;
849 HRESULT hr;
851 TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
852 if (IsEqualGUID(guid, &pulse_render_guid))
853 dataflow = eRender;
854 else if (IsEqualGUID(guid, &pulse_capture_guid))
855 dataflow = eCapture;
856 else
857 return E_UNEXPECTED;
859 *out = NULL;
861 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
862 if (!This)
863 return E_OUTOFMEMORY;
865 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
866 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
867 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
868 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
869 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
870 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
871 This->dataflow = dataflow;
872 This->parent = dev;
873 for (i = 0; i < PA_CHANNELS_MAX; ++i)
874 This->vol[i] = 1.f;
876 hr = CoCreateFreeThreadedMarshaler((IUnknown*)This, &This->marshal);
877 if (hr) {
878 HeapFree(GetProcessHeap(), 0, This);
879 return hr;
881 IMMDevice_AddRef(This->parent);
883 *out = &This->IAudioClient_iface;
884 IAudioClient_AddRef(&This->IAudioClient_iface);
886 return S_OK;
889 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
890 REFIID riid, void **ppv)
892 ACImpl *This = impl_from_IAudioClient(iface);
894 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
896 if (!ppv)
897 return E_POINTER;
899 *ppv = NULL;
900 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
901 *ppv = iface;
902 if (*ppv) {
903 IUnknown_AddRef((IUnknown*)*ppv);
904 return S_OK;
907 if (IsEqualIID(riid, &IID_IMarshal))
908 return IUnknown_QueryInterface(This->marshal, riid, ppv);
910 WARN("Unknown interface %s\n", debugstr_guid(riid));
911 return E_NOINTERFACE;
914 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
916 ACImpl *This = impl_from_IAudioClient(iface);
917 ULONG ref;
918 ref = InterlockedIncrement(&This->ref);
919 TRACE("(%p) Refcount now %u\n", This, ref);
920 return ref;
923 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
925 ACImpl *This = impl_from_IAudioClient(iface);
926 ULONG ref;
927 ref = InterlockedDecrement(&This->ref);
928 TRACE("(%p) Refcount now %u\n", This, ref);
929 if (!ref) {
930 if (This->stream) {
931 pthread_mutex_lock(&pulse_lock);
932 if (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream))) {
933 pa_stream_disconnect(This->stream);
934 while (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream)))
935 pthread_cond_wait(&pulse_cond, &pulse_lock);
937 pa_stream_unref(This->stream);
938 This->stream = NULL;
939 list_remove(&This->entry);
940 pthread_mutex_unlock(&pulse_lock);
942 IUnknown_Release(This->marshal);
943 IMMDevice_Release(This->parent);
944 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
945 HeapFree(GetProcessHeap(), 0, This);
947 return ref;
950 static void dump_fmt(const WAVEFORMATEX *fmt)
952 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
953 switch(fmt->wFormatTag) {
954 case WAVE_FORMAT_PCM:
955 TRACE("WAVE_FORMAT_PCM");
956 break;
957 case WAVE_FORMAT_IEEE_FLOAT:
958 TRACE("WAVE_FORMAT_IEEE_FLOAT");
959 break;
960 case WAVE_FORMAT_EXTENSIBLE:
961 TRACE("WAVE_FORMAT_EXTENSIBLE");
962 break;
963 default:
964 TRACE("Unknown");
965 break;
967 TRACE(")\n");
969 TRACE("nChannels: %u\n", fmt->nChannels);
970 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
971 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
972 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
973 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
974 TRACE("cbSize: %u\n", fmt->cbSize);
976 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
977 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
978 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
979 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
980 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
984 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
986 WAVEFORMATEX *ret;
987 size_t size;
989 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
990 size = sizeof(WAVEFORMATEXTENSIBLE);
991 else
992 size = sizeof(WAVEFORMATEX);
994 ret = CoTaskMemAlloc(size);
995 if (!ret)
996 return NULL;
998 memcpy(ret, fmt, size);
1000 ret->cbSize = size - sizeof(WAVEFORMATEX);
1002 return ret;
1005 static DWORD get_channel_mask(unsigned int channels)
1007 switch(channels) {
1008 case 0:
1009 return 0;
1010 case 1:
1011 return KSAUDIO_SPEAKER_MONO;
1012 case 2:
1013 return KSAUDIO_SPEAKER_STEREO;
1014 case 3:
1015 return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
1016 case 4:
1017 return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
1018 case 5:
1019 return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
1020 case 6:
1021 return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
1022 case 7:
1023 return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
1024 case 8:
1025 return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
1027 FIXME("Unknown speaker configuration: %u\n", channels);
1028 return 0;
1031 static void session_init_vols(AudioSession *session, UINT channels)
1033 if (session->channel_count < channels) {
1034 UINT i;
1036 if (session->channel_vols)
1037 session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
1038 session->channel_vols, sizeof(float) * channels);
1039 else
1040 session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
1041 sizeof(float) * channels);
1042 if (!session->channel_vols)
1043 return;
1045 for(i = session->channel_count; i < channels; ++i)
1046 session->channel_vols[i] = 1.f;
1048 session->channel_count = channels;
1052 static AudioSession *create_session(const GUID *guid, IMMDevice *device,
1053 UINT num_channels)
1055 AudioSession *ret;
1057 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
1058 if (!ret)
1059 return NULL;
1061 memcpy(&ret->guid, guid, sizeof(GUID));
1063 ret->device = device;
1065 list_init(&ret->clients);
1067 list_add_head(&g_sessions, &ret->entry);
1069 session_init_vols(ret, num_channels);
1071 ret->master_vol = 1.f;
1073 return ret;
1076 /* if channels == 0, then this will return or create a session with
1077 * matching dataflow and GUID. otherwise, channels must also match */
1078 static HRESULT get_audio_session(const GUID *sessionguid,
1079 IMMDevice *device, UINT channels, AudioSession **out)
1081 AudioSession *session;
1083 if (!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)) {
1084 *out = create_session(&GUID_NULL, device, channels);
1085 if (!*out)
1086 return E_OUTOFMEMORY;
1088 return S_OK;
1091 *out = NULL;
1092 LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry) {
1093 if (session->device == device &&
1094 IsEqualGUID(sessionguid, &session->guid)) {
1095 session_init_vols(session, channels);
1096 *out = session;
1097 break;
1101 if (!*out) {
1102 *out = create_session(sessionguid, device, channels);
1103 if (!*out)
1104 return E_OUTOFMEMORY;
1107 return S_OK;
1110 static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
1112 pa_channel_map_init(&This->map);
1113 This->ss.rate = fmt->nSamplesPerSec;
1114 This->ss.format = PA_SAMPLE_INVALID;
1116 switch(fmt->wFormatTag) {
1117 case WAVE_FORMAT_IEEE_FLOAT:
1118 if (!fmt->nChannels || fmt->nChannels > 2 || fmt->wBitsPerSample != 32)
1119 break;
1120 This->ss.format = PA_SAMPLE_FLOAT32LE;
1121 pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
1122 break;
1123 case WAVE_FORMAT_PCM:
1124 if (!fmt->nChannels || fmt->nChannels > 2)
1125 break;
1126 if (fmt->wBitsPerSample == 8)
1127 This->ss.format = PA_SAMPLE_U8;
1128 else if (fmt->wBitsPerSample == 16)
1129 This->ss.format = PA_SAMPLE_S16LE;
1130 else
1131 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1132 pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
1133 break;
1134 case WAVE_FORMAT_EXTENSIBLE: {
1135 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)fmt;
1136 DWORD mask = wfe->dwChannelMask;
1137 DWORD i = 0, j;
1138 if (fmt->cbSize != (sizeof(*wfe) - sizeof(*fmt)) && fmt->cbSize != sizeof(*wfe))
1139 break;
1140 if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
1141 (!wfe->Samples.wValidBitsPerSample || wfe->Samples.wValidBitsPerSample == 32) &&
1142 fmt->wBitsPerSample == 32)
1143 This->ss.format = PA_SAMPLE_FLOAT32LE;
1144 else if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
1145 DWORD valid = wfe->Samples.wValidBitsPerSample;
1146 if (!valid)
1147 valid = fmt->wBitsPerSample;
1148 if (!valid || valid > fmt->wBitsPerSample)
1149 break;
1150 switch (fmt->wBitsPerSample) {
1151 case 8:
1152 if (valid == 8)
1153 This->ss.format = PA_SAMPLE_U8;
1154 break;
1155 case 16:
1156 if (valid == 16)
1157 This->ss.format = PA_SAMPLE_S16LE;
1158 break;
1159 case 24:
1160 if (valid == 24)
1161 This->ss.format = PA_SAMPLE_S24LE;
1162 break;
1163 case 32:
1164 if (valid == 24)
1165 This->ss.format = PA_SAMPLE_S24_32LE;
1166 else if (valid == 32)
1167 This->ss.format = PA_SAMPLE_S32LE;
1168 break;
1169 default:
1170 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1173 This->map.channels = fmt->nChannels;
1174 if (!mask || (mask & (SPEAKER_ALL|SPEAKER_RESERVED)))
1175 mask = get_channel_mask(fmt->nChannels);
1176 for (j = 0; j < sizeof(pulse_pos_from_wfx)/sizeof(*pulse_pos_from_wfx) && i < fmt->nChannels; ++j) {
1177 if (mask & (1 << j))
1178 This->map.map[i++] = pulse_pos_from_wfx[j];
1181 /* Special case for mono since pulse appears to map it differently */
1182 if (mask == SPEAKER_FRONT_CENTER)
1183 This->map.map[0] = PA_CHANNEL_POSITION_MONO;
1185 if (i < fmt->nChannels || (mask & SPEAKER_RESERVED)) {
1186 This->map.channels = 0;
1187 ERR("Invalid channel mask: %i/%i and %x(%x)\n", i, fmt->nChannels, mask, wfe->dwChannelMask);
1188 break;
1190 break;
1192 case WAVE_FORMAT_ALAW:
1193 case WAVE_FORMAT_MULAW:
1194 if (fmt->wBitsPerSample != 8) {
1195 FIXME("Unsupported bpp %u for LAW\n", fmt->wBitsPerSample);
1196 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1198 if (fmt->nChannels != 1 && fmt->nChannels != 2) {
1199 FIXME("Unsupported channels %u for LAW\n", fmt->nChannels);
1200 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1202 This->ss.format = fmt->wFormatTag == WAVE_FORMAT_MULAW ? PA_SAMPLE_ULAW : PA_SAMPLE_ALAW;
1203 pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
1204 break;
1205 default:
1206 WARN("Unhandled tag %x\n", fmt->wFormatTag);
1207 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1209 This->ss.channels = This->map.channels;
1210 if (!pa_channel_map_valid(&This->map) || This->ss.format == PA_SAMPLE_INVALID) {
1211 ERR("Invalid format! Channel spec valid: %i, format: %i\n", pa_channel_map_valid(&This->map), This->ss.format);
1212 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1214 return S_OK;
1217 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
1218 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
1219 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
1220 const GUID *sessionguid)
1222 ACImpl *This = impl_from_IAudioClient(iface);
1223 HRESULT hr = S_OK;
1224 UINT period_bytes;
1226 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
1227 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
1229 if (!fmt)
1230 return E_POINTER;
1232 if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1233 return AUDCLNT_E_NOT_INITIALIZED;
1234 if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1235 return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
1237 if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
1238 AUDCLNT_STREAMFLAGS_LOOPBACK |
1239 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
1240 AUDCLNT_STREAMFLAGS_NOPERSIST |
1241 AUDCLNT_STREAMFLAGS_RATEADJUST |
1242 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
1243 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
1244 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)) {
1245 TRACE("Unknown flags: %08x\n", flags);
1246 return E_INVALIDARG;
1249 pthread_mutex_lock(&pulse_lock);
1251 hr = pulse_connect();
1252 if (FAILED(hr)) {
1253 pthread_mutex_unlock(&pulse_lock);
1254 return hr;
1257 if (This->stream) {
1258 pthread_mutex_unlock(&pulse_lock);
1259 return AUDCLNT_E_ALREADY_INITIALIZED;
1262 hr = pulse_spec_from_waveformat(This, fmt);
1263 TRACE("Obtaining format returns %08x\n", hr);
1264 dump_fmt(fmt);
1266 if (FAILED(hr))
1267 goto exit;
1269 if (mode == AUDCLNT_SHAREMODE_SHARED) {
1270 REFERENCE_TIME def = pulse_def_period[This->dataflow == eCapture];
1271 REFERENCE_TIME min = pulse_min_period[This->dataflow == eCapture];
1273 /* Switch to low latency mode if below 2 default periods,
1274 * which is 20 ms by default, this will increase the amount
1275 * of interrupts but allows very low latency. In dsound I
1276 * managed to get a total latency of ~8ms, which is well below
1277 * default
1279 if (duration < 2 * def)
1280 period = min;
1281 else
1282 period = def;
1283 if (duration < 2 * period)
1284 duration = 2 * period;
1286 /* Uh oh, really low latency requested.. */
1287 if (duration <= 2 * period)
1288 period /= 2;
1290 period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000);
1292 if (duration < 20000000)
1293 This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
1294 else
1295 This->bufsize_frames = 2 * fmt->nSamplesPerSec;
1296 This->bufsize_bytes = This->bufsize_frames * pa_frame_size(&This->ss);
1298 This->share = mode;
1299 This->flags = flags;
1300 hr = pulse_stream_connect(This, period_bytes);
1301 if (SUCCEEDED(hr)) {
1302 UINT32 unalign;
1303 const pa_buffer_attr *attr = pa_stream_get_buffer_attr(This->stream);
1304 /* Update frames according to new size */
1305 dump_attr(attr);
1306 if (This->dataflow == eRender)
1307 This->bufsize_bytes = attr->tlength;
1308 else {
1309 This->capture_period = period_bytes = attr->fragsize;
1310 if ((unalign = This->bufsize_bytes % period_bytes))
1311 This->bufsize_bytes += period_bytes - unalign;
1313 This->bufsize_frames = This->bufsize_bytes / pa_frame_size(&This->ss);
1315 if (SUCCEEDED(hr)) {
1316 UINT32 i, capture_packets = This->capture_period ? This->bufsize_bytes / This->capture_period : 0;
1317 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_bytes + capture_packets * sizeof(ACPacket));
1318 if (!This->tmp_buffer)
1319 hr = E_OUTOFMEMORY;
1320 else {
1321 ACPacket *cur_packet = (ACPacket*)((char*)This->tmp_buffer + This->bufsize_bytes);
1322 BYTE *data = This->tmp_buffer;
1323 silence_buffer(This->ss.format, This->tmp_buffer, This->bufsize_bytes);
1324 list_init(&This->packet_free_head);
1325 list_init(&This->packet_filled_head);
1326 for (i = 0; i < capture_packets; ++i, ++cur_packet) {
1327 list_add_tail(&This->packet_free_head, &cur_packet->entry);
1328 cur_packet->data = data;
1329 data += This->capture_period;
1331 assert(!This->capture_period || This->bufsize_bytes == This->capture_period * capture_packets);
1332 assert(!capture_packets || data - This->bufsize_bytes == This->tmp_buffer);
1335 if (SUCCEEDED(hr))
1336 hr = get_audio_session(sessionguid, This->parent, fmt->nChannels, &This->session);
1337 if (SUCCEEDED(hr))
1338 list_add_tail(&This->session->clients, &This->entry);
1340 exit:
1341 if (FAILED(hr)) {
1342 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1343 This->tmp_buffer = NULL;
1344 if (This->stream) {
1345 pa_stream_disconnect(This->stream);
1346 pa_stream_unref(This->stream);
1347 This->stream = NULL;
1350 pthread_mutex_unlock(&pulse_lock);
1351 return hr;
1354 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1355 UINT32 *out)
1357 ACImpl *This = impl_from_IAudioClient(iface);
1358 HRESULT hr;
1360 TRACE("(%p)->(%p)\n", This, out);
1362 if (!out)
1363 return E_POINTER;
1365 pthread_mutex_lock(&pulse_lock);
1366 hr = pulse_stream_valid(This);
1367 if (SUCCEEDED(hr))
1368 *out = This->bufsize_frames;
1369 pthread_mutex_unlock(&pulse_lock);
1371 return hr;
1374 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1375 REFERENCE_TIME *latency)
1377 ACImpl *This = impl_from_IAudioClient(iface);
1378 const pa_buffer_attr *attr;
1379 REFERENCE_TIME lat;
1380 HRESULT hr;
1382 TRACE("(%p)->(%p)\n", This, latency);
1384 if (!latency)
1385 return E_POINTER;
1387 pthread_mutex_lock(&pulse_lock);
1388 hr = pulse_stream_valid(This);
1389 if (FAILED(hr)) {
1390 pthread_mutex_unlock(&pulse_lock);
1391 return hr;
1393 attr = pa_stream_get_buffer_attr(This->stream);
1394 if (This->dataflow == eRender)
1395 lat = attr->minreq / pa_frame_size(&This->ss);
1396 else
1397 lat = attr->fragsize / pa_frame_size(&This->ss);
1398 *latency = 10000000;
1399 *latency *= lat;
1400 *latency /= This->ss.rate;
1401 pthread_mutex_unlock(&pulse_lock);
1402 TRACE("Latency: %u ms\n", (DWORD)(*latency / 10000));
1403 return S_OK;
1406 static void ACImpl_GetRenderPad(ACImpl *This, UINT32 *out)
1408 *out = This->pad / pa_frame_size(&This->ss);
1411 static void ACImpl_GetCapturePad(ACImpl *This, UINT32 *out)
1413 ACPacket *packet = This->locked_ptr;
1414 if (!packet && !list_empty(&This->packet_filled_head)) {
1415 packet = (ACPacket*)list_head(&This->packet_filled_head);
1416 This->locked_ptr = packet;
1417 list_remove(&packet->entry);
1419 if (out)
1420 *out = This->pad / pa_frame_size(&This->ss);
1423 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1424 UINT32 *out)
1426 ACImpl *This = impl_from_IAudioClient(iface);
1427 HRESULT hr;
1429 TRACE("(%p)->(%p)\n", This, out);
1431 if (!out)
1432 return E_POINTER;
1434 pthread_mutex_lock(&pulse_lock);
1435 hr = pulse_stream_valid(This);
1436 if (FAILED(hr)) {
1437 pthread_mutex_unlock(&pulse_lock);
1438 return hr;
1441 if (This->dataflow == eRender)
1442 ACImpl_GetRenderPad(This, out);
1443 else
1444 ACImpl_GetCapturePad(This, out);
1445 pthread_mutex_unlock(&pulse_lock);
1447 TRACE("%p Pad: %u ms (%u)\n", This, MulDiv(*out, 1000, This->ss.rate), *out);
1448 return S_OK;
1451 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1452 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
1453 WAVEFORMATEX **out)
1455 ACImpl *This = impl_from_IAudioClient(iface);
1456 HRESULT hr = S_OK;
1457 WAVEFORMATEX *closest = NULL;
1458 BOOL exclusive;
1460 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
1462 if (!fmt)
1463 return E_POINTER;
1465 if (out)
1466 *out = NULL;
1468 if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
1469 exclusive = 1;
1470 out = NULL;
1471 } else if (mode == AUDCLNT_SHAREMODE_SHARED) {
1472 exclusive = 0;
1473 if (!out)
1474 return E_POINTER;
1475 } else
1476 return E_INVALIDARG;
1478 if (fmt->nChannels == 0)
1479 return AUDCLNT_E_UNSUPPORTED_FORMAT;
1481 closest = clone_format(fmt);
1482 if (!closest)
1483 return E_OUTOFMEMORY;
1485 dump_fmt(fmt);
1487 switch (fmt->wFormatTag) {
1488 case WAVE_FORMAT_EXTENSIBLE: {
1489 WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)closest;
1491 if ((fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) &&
1492 fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE)) ||
1493 fmt->nBlockAlign != fmt->wBitsPerSample / 8 * fmt->nChannels ||
1494 ext->Samples.wValidBitsPerSample > fmt->wBitsPerSample ||
1495 fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec) {
1496 hr = E_INVALIDARG;
1497 break;
1500 if (exclusive) {
1501 UINT32 mask = 0, i, channels = 0;
1503 if (!(ext->dwChannelMask & (SPEAKER_ALL | SPEAKER_RESERVED))) {
1504 for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) {
1505 if (i & ext->dwChannelMask) {
1506 mask |= i;
1507 channels++;
1511 if (channels != fmt->nChannels || (ext->dwChannelMask & ~mask)) {
1512 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1513 break;
1515 } else {
1516 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1517 break;
1521 if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
1522 if (fmt->wBitsPerSample != 32) {
1523 hr = E_INVALIDARG;
1524 break;
1527 if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample) {
1528 hr = S_FALSE;
1529 ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
1531 } else if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
1532 if (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8) {
1533 hr = E_INVALIDARG;
1534 break;
1537 if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample &&
1538 !(fmt->wBitsPerSample == 32 &&
1539 ext->Samples.wValidBitsPerSample == 24)) {
1540 hr = S_FALSE;
1541 ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
1542 break;
1544 } else {
1545 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1546 break;
1549 break;
1552 case WAVE_FORMAT_ALAW:
1553 case WAVE_FORMAT_MULAW:
1554 if (fmt->wBitsPerSample != 8) {
1555 hr = E_INVALIDARG;
1556 break;
1558 /* Fall-through */
1559 case WAVE_FORMAT_IEEE_FLOAT:
1560 if (fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT && fmt->wBitsPerSample != 32) {
1561 hr = E_INVALIDARG;
1562 break;
1564 /* Fall-through */
1565 case WAVE_FORMAT_PCM:
1566 if (fmt->wFormatTag == WAVE_FORMAT_PCM &&
1567 (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8)) {
1568 hr = E_INVALIDARG;
1569 break;
1572 if (fmt->nChannels > 2) {
1573 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1574 break;
1577 * fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
1578 * ignored, invalid values are happily accepted.
1580 break;
1581 default:
1582 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1583 break;
1586 if (exclusive && hr != S_OK) {
1587 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1588 CoTaskMemFree(closest);
1589 } else if (hr != S_FALSE)
1590 CoTaskMemFree(closest);
1591 else
1592 *out = closest;
1594 /* Winepulse does not currently support exclusive mode, if you know of an
1595 * application that uses it, I will correct this..
1597 if (hr == S_OK && exclusive)
1598 return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
1600 TRACE("returning: %08x %p\n", hr, out ? *out : NULL);
1601 return hr;
1604 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1605 WAVEFORMATEX **pwfx)
1607 ACImpl *This = impl_from_IAudioClient(iface);
1608 WAVEFORMATEXTENSIBLE *fmt = &pulse_fmt[This->dataflow == eCapture];
1610 TRACE("(%p)->(%p)\n", This, pwfx);
1612 if (!pwfx)
1613 return E_POINTER;
1615 *pwfx = clone_format(&fmt->Format);
1616 if (!*pwfx)
1617 return E_OUTOFMEMORY;
1618 dump_fmt(*pwfx);
1619 return S_OK;
1622 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1623 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1625 ACImpl *This = impl_from_IAudioClient(iface);
1627 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1629 if (!defperiod && !minperiod)
1630 return E_POINTER;
1632 if (defperiod)
1633 *defperiod = pulse_def_period[This->dataflow == eCapture];
1634 if (minperiod)
1635 *minperiod = pulse_min_period[This->dataflow == eCapture];
1637 return S_OK;
1640 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1642 ACImpl *This = impl_from_IAudioClient(iface);
1643 HRESULT hr = S_OK;
1644 int success;
1645 pa_operation *o;
1647 TRACE("(%p)\n", This);
1649 pthread_mutex_lock(&pulse_lock);
1650 hr = pulse_stream_valid(This);
1651 if (FAILED(hr)) {
1652 pthread_mutex_unlock(&pulse_lock);
1653 return hr;
1656 if ((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event) {
1657 pthread_mutex_unlock(&pulse_lock);
1658 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1661 if (This->started) {
1662 pthread_mutex_unlock(&pulse_lock);
1663 return AUDCLNT_E_NOT_STOPPED;
1666 if (pa_stream_is_corked(This->stream)) {
1667 o = pa_stream_cork(This->stream, 0, pulse_op_cb, &success);
1668 if (o) {
1669 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1670 pthread_cond_wait(&pulse_cond, &pulse_lock);
1671 pa_operation_unref(o);
1672 } else
1673 success = 0;
1674 if (!success)
1675 hr = E_FAIL;
1677 if (SUCCEEDED(hr)) {
1678 This->started = TRUE;
1679 if (This->dataflow == eRender && This->event)
1680 pa_stream_set_latency_update_callback(This->stream, pulse_latency_callback, This);
1682 pthread_mutex_unlock(&pulse_lock);
1683 return hr;
1686 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1688 ACImpl *This = impl_from_IAudioClient(iface);
1689 HRESULT hr = S_OK;
1690 pa_operation *o;
1691 int success;
1693 TRACE("(%p)\n", This);
1695 pthread_mutex_lock(&pulse_lock);
1696 hr = pulse_stream_valid(This);
1697 if (FAILED(hr)) {
1698 pthread_mutex_unlock(&pulse_lock);
1699 return hr;
1702 if (!This->started) {
1703 pthread_mutex_unlock(&pulse_lock);
1704 return S_FALSE;
1707 if (This->dataflow == eRender) {
1708 o = pa_stream_cork(This->stream, 1, pulse_op_cb, &success);
1709 if (o) {
1710 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1711 pthread_cond_wait(&pulse_cond, &pulse_lock);
1712 pa_operation_unref(o);
1713 } else
1714 success = 0;
1715 if (!success)
1716 hr = E_FAIL;
1718 if (SUCCEEDED(hr)) {
1719 This->started = FALSE;
1721 pthread_mutex_unlock(&pulse_lock);
1722 return hr;
1725 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1727 ACImpl *This = impl_from_IAudioClient(iface);
1728 HRESULT hr = S_OK;
1730 TRACE("(%p)\n", This);
1732 pthread_mutex_lock(&pulse_lock);
1733 hr = pulse_stream_valid(This);
1734 if (FAILED(hr)) {
1735 pthread_mutex_unlock(&pulse_lock);
1736 return hr;
1739 if (This->started) {
1740 pthread_mutex_unlock(&pulse_lock);
1741 return AUDCLNT_E_NOT_STOPPED;
1744 if (This->locked) {
1745 pthread_mutex_unlock(&pulse_lock);
1746 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1749 if (This->dataflow == eRender) {
1750 /* If there is still data in the render buffer it needs to be removed from the server */
1751 int success = 0;
1752 if (This->pad) {
1753 pa_operation *o = pa_stream_flush(This->stream, pulse_op_cb, &success);
1754 if (o) {
1755 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1756 pthread_cond_wait(&pulse_cond, &pulse_lock);
1757 pa_operation_unref(o);
1760 if (success || !This->pad)
1761 This->clock_lastpos = This->clock_written = This->pad = 0;
1762 } else {
1763 ACPacket *p;
1764 This->clock_written += This->pad;
1765 This->pad = 0;
1767 if ((p = This->locked_ptr)) {
1768 This->locked_ptr = NULL;
1769 list_add_tail(&This->packet_free_head, &p->entry);
1771 list_move_tail(&This->packet_free_head, &This->packet_filled_head);
1773 pthread_mutex_unlock(&pulse_lock);
1775 return hr;
1778 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1779 HANDLE event)
1781 ACImpl *This = impl_from_IAudioClient(iface);
1782 HRESULT hr;
1784 TRACE("(%p)->(%p)\n", This, event);
1786 if (!event)
1787 return E_INVALIDARG;
1789 pthread_mutex_lock(&pulse_lock);
1790 hr = pulse_stream_valid(This);
1791 if (FAILED(hr)) {
1792 pthread_mutex_unlock(&pulse_lock);
1793 return hr;
1796 if (!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1797 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1798 else if (This->event)
1799 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1800 else
1801 This->event = event;
1802 pthread_mutex_unlock(&pulse_lock);
1803 return hr;
1806 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1807 void **ppv)
1809 ACImpl *This = impl_from_IAudioClient(iface);
1810 HRESULT hr;
1812 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1814 if (!ppv)
1815 return E_POINTER;
1816 *ppv = NULL;
1818 pthread_mutex_lock(&pulse_lock);
1819 hr = pulse_stream_valid(This);
1820 pthread_mutex_unlock(&pulse_lock);
1821 if (FAILED(hr))
1822 return hr;
1824 if (IsEqualIID(riid, &IID_IAudioRenderClient)) {
1825 if (This->dataflow != eRender)
1826 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1827 *ppv = &This->IAudioRenderClient_iface;
1828 } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) {
1829 if (This->dataflow != eCapture)
1830 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1831 *ppv = &This->IAudioCaptureClient_iface;
1832 } else if (IsEqualIID(riid, &IID_IAudioClock)) {
1833 *ppv = &This->IAudioClock_iface;
1834 } else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) {
1835 *ppv = &This->IAudioStreamVolume_iface;
1836 } else if (IsEqualIID(riid, &IID_IAudioSessionControl) ||
1837 IsEqualIID(riid, &IID_IChannelAudioVolume) ||
1838 IsEqualIID(riid, &IID_ISimpleAudioVolume)) {
1839 if (!This->session_wrapper) {
1840 This->session_wrapper = AudioSessionWrapper_Create(This);
1841 if (!This->session_wrapper)
1842 return E_OUTOFMEMORY;
1844 if (IsEqualIID(riid, &IID_IAudioSessionControl))
1845 *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1846 else if (IsEqualIID(riid, &IID_IChannelAudioVolume))
1847 *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1848 else if (IsEqualIID(riid, &IID_ISimpleAudioVolume))
1849 *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1852 if (*ppv) {
1853 IUnknown_AddRef((IUnknown*)*ppv);
1854 return S_OK;
1857 FIXME("stub %s\n", debugstr_guid(riid));
1858 return E_NOINTERFACE;
1861 static const IAudioClientVtbl AudioClient_Vtbl =
1863 AudioClient_QueryInterface,
1864 AudioClient_AddRef,
1865 AudioClient_Release,
1866 AudioClient_Initialize,
1867 AudioClient_GetBufferSize,
1868 AudioClient_GetStreamLatency,
1869 AudioClient_GetCurrentPadding,
1870 AudioClient_IsFormatSupported,
1871 AudioClient_GetMixFormat,
1872 AudioClient_GetDevicePeriod,
1873 AudioClient_Start,
1874 AudioClient_Stop,
1875 AudioClient_Reset,
1876 AudioClient_SetEventHandle,
1877 AudioClient_GetService
1880 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1881 IAudioRenderClient *iface, REFIID riid, void **ppv)
1883 ACImpl *This = impl_from_IAudioRenderClient(iface);
1884 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1886 if (!ppv)
1887 return E_POINTER;
1888 *ppv = NULL;
1890 if (IsEqualIID(riid, &IID_IUnknown) ||
1891 IsEqualIID(riid, &IID_IAudioRenderClient))
1892 *ppv = iface;
1893 if (*ppv) {
1894 IUnknown_AddRef((IUnknown*)*ppv);
1895 return S_OK;
1898 if (IsEqualIID(riid, &IID_IMarshal))
1899 return IUnknown_QueryInterface(This->marshal, riid, ppv);
1901 WARN("Unknown interface %s\n", debugstr_guid(riid));
1902 return E_NOINTERFACE;
1905 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1907 ACImpl *This = impl_from_IAudioRenderClient(iface);
1908 return AudioClient_AddRef(&This->IAudioClient_iface);
1911 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1913 ACImpl *This = impl_from_IAudioRenderClient(iface);
1914 return AudioClient_Release(&This->IAudioClient_iface);
1917 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1918 UINT32 frames, BYTE **data)
1920 ACImpl *This = impl_from_IAudioRenderClient(iface);
1921 size_t avail, req, bytes = frames * pa_frame_size(&This->ss);
1922 UINT32 pad;
1923 HRESULT hr = S_OK;
1924 int ret = -1;
1926 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1928 if (!data)
1929 return E_POINTER;
1930 *data = NULL;
1932 pthread_mutex_lock(&pulse_lock);
1933 hr = pulse_stream_valid(This);
1934 if (FAILED(hr) || This->locked) {
1935 pthread_mutex_unlock(&pulse_lock);
1936 return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
1938 if (!frames) {
1939 pthread_mutex_unlock(&pulse_lock);
1940 return S_OK;
1943 ACImpl_GetRenderPad(This, &pad);
1944 avail = This->bufsize_frames - pad;
1945 if (avail < frames || bytes > This->bufsize_bytes) {
1946 pthread_mutex_unlock(&pulse_lock);
1947 WARN("Wanted to write %u, but only %zu available\n", frames, avail);
1948 return AUDCLNT_E_BUFFER_TOO_LARGE;
1951 This->locked = frames;
1952 req = bytes;
1953 ret = pa_stream_begin_write(This->stream, &This->locked_ptr, &req);
1954 if (ret < 0 || req < bytes) {
1955 FIXME("%p Not using pulse locked data: %i %zu/%u %u/%u\n", This, ret, req/pa_frame_size(&This->ss), frames, pad, This->bufsize_frames);
1956 if (ret >= 0)
1957 pa_stream_cancel_write(This->stream);
1958 *data = This->tmp_buffer;
1959 This->locked_ptr = NULL;
1960 } else
1961 *data = This->locked_ptr;
1962 pthread_mutex_unlock(&pulse_lock);
1963 return hr;
1966 static void pulse_free_noop(void *buf)
1970 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1971 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1973 ACImpl *This = impl_from_IAudioRenderClient(iface);
1974 UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
1976 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1978 pthread_mutex_lock(&pulse_lock);
1979 if (!This->locked || !written_frames) {
1980 if (This->locked_ptr)
1981 pa_stream_cancel_write(This->stream);
1982 This->locked = 0;
1983 This->locked_ptr = NULL;
1984 pthread_mutex_unlock(&pulse_lock);
1985 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1988 if (This->locked < written_frames) {
1989 pthread_mutex_unlock(&pulse_lock);
1990 return AUDCLNT_E_INVALID_SIZE;
1993 This->locked = 0;
1994 if (This->locked_ptr) {
1995 if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
1996 silence_buffer(This->ss.format, This->locked_ptr, written_bytes);
1997 pa_stream_write(This->stream, This->locked_ptr, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
1998 } else {
1999 if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
2000 silence_buffer(This->ss.format, This->tmp_buffer, written_bytes);
2001 pa_stream_write(This->stream, This->tmp_buffer, written_bytes, pulse_free_noop, 0, PA_SEEK_RELATIVE);
2004 This->pad += written_bytes;
2005 This->locked_ptr = NULL;
2006 TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
2007 assert(This->pad <= This->bufsize_bytes);
2009 pthread_mutex_unlock(&pulse_lock);
2010 return S_OK;
2013 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
2014 AudioRenderClient_QueryInterface,
2015 AudioRenderClient_AddRef,
2016 AudioRenderClient_Release,
2017 AudioRenderClient_GetBuffer,
2018 AudioRenderClient_ReleaseBuffer
2021 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
2022 IAudioCaptureClient *iface, REFIID riid, void **ppv)
2024 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2025 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2027 if (!ppv)
2028 return E_POINTER;
2029 *ppv = NULL;
2031 if (IsEqualIID(riid, &IID_IUnknown) ||
2032 IsEqualIID(riid, &IID_IAudioCaptureClient))
2033 *ppv = iface;
2034 if (*ppv) {
2035 IUnknown_AddRef((IUnknown*)*ppv);
2036 return S_OK;
2039 if (IsEqualIID(riid, &IID_IMarshal))
2040 return IUnknown_QueryInterface(This->marshal, riid, ppv);
2042 WARN("Unknown interface %s\n", debugstr_guid(riid));
2043 return E_NOINTERFACE;
2046 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
2048 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2049 return IAudioClient_AddRef(&This->IAudioClient_iface);
2052 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
2054 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2055 return IAudioClient_Release(&This->IAudioClient_iface);
2058 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
2059 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
2060 UINT64 *qpcpos)
2062 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2063 HRESULT hr;
2064 ACPacket *packet;
2066 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
2067 devpos, qpcpos);
2069 if (!data || !frames || !flags)
2070 return E_POINTER;
2072 pthread_mutex_lock(&pulse_lock);
2073 hr = pulse_stream_valid(This);
2074 if (FAILED(hr) || This->locked) {
2075 pthread_mutex_unlock(&pulse_lock);
2076 return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
2079 ACImpl_GetCapturePad(This, NULL);
2080 if ((packet = This->locked_ptr)) {
2081 *frames = This->capture_period / pa_frame_size(&This->ss);
2082 *flags = 0;
2083 if (packet->discont)
2084 *flags |= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY;
2085 if (devpos) {
2086 if (packet->discont)
2087 *devpos = (This->clock_written + This->capture_period) / pa_frame_size(&This->ss);
2088 else
2089 *devpos = This->clock_written / pa_frame_size(&This->ss);
2091 if (qpcpos)
2092 *qpcpos = packet->qpcpos;
2093 *data = packet->data;
2095 else
2096 *frames = 0;
2097 This->locked = *frames;
2098 pthread_mutex_unlock(&pulse_lock);
2099 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2102 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2103 IAudioCaptureClient *iface, UINT32 done)
2105 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2107 TRACE("(%p)->(%u)\n", This, done);
2109 pthread_mutex_lock(&pulse_lock);
2110 if (!This->locked && done) {
2111 pthread_mutex_unlock(&pulse_lock);
2112 return AUDCLNT_E_OUT_OF_ORDER;
2114 if (done && This->locked != done) {
2115 pthread_mutex_unlock(&pulse_lock);
2116 return AUDCLNT_E_INVALID_SIZE;
2118 if (done) {
2119 ACPacket *packet = This->locked_ptr;
2120 This->locked_ptr = NULL;
2121 This->pad -= This->capture_period;
2122 if (packet->discont)
2123 This->clock_written += 2 * This->capture_period;
2124 else
2125 This->clock_written += This->capture_period;
2126 list_add_tail(&This->packet_free_head, &packet->entry);
2128 This->locked = 0;
2129 pthread_mutex_unlock(&pulse_lock);
2130 return S_OK;
2133 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2134 IAudioCaptureClient *iface, UINT32 *frames)
2136 ACImpl *This = impl_from_IAudioCaptureClient(iface);
2138 TRACE("(%p)->(%p)\n", This, frames);
2139 if (!frames)
2140 return E_POINTER;
2142 pthread_mutex_lock(&pulse_lock);
2143 ACImpl_GetCapturePad(This, NULL);
2144 if (This->locked_ptr)
2145 *frames = This->capture_period / pa_frame_size(&This->ss);
2146 else
2147 *frames = 0;
2148 pthread_mutex_unlock(&pulse_lock);
2149 return S_OK;
2152 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2154 AudioCaptureClient_QueryInterface,
2155 AudioCaptureClient_AddRef,
2156 AudioCaptureClient_Release,
2157 AudioCaptureClient_GetBuffer,
2158 AudioCaptureClient_ReleaseBuffer,
2159 AudioCaptureClient_GetNextPacketSize
2162 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2163 REFIID riid, void **ppv)
2165 ACImpl *This = impl_from_IAudioClock(iface);
2167 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2169 if (!ppv)
2170 return E_POINTER;
2171 *ppv = NULL;
2173 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2174 *ppv = iface;
2175 else if (IsEqualIID(riid, &IID_IAudioClock2))
2176 *ppv = &This->IAudioClock2_iface;
2177 if (*ppv) {
2178 IUnknown_AddRef((IUnknown*)*ppv);
2179 return S_OK;
2182 if (IsEqualIID(riid, &IID_IMarshal))
2183 return IUnknown_QueryInterface(This->marshal, riid, ppv);
2185 WARN("Unknown interface %s\n", debugstr_guid(riid));
2186 return E_NOINTERFACE;
2189 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2191 ACImpl *This = impl_from_IAudioClock(iface);
2192 return IAudioClient_AddRef(&This->IAudioClient_iface);
2195 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2197 ACImpl *This = impl_from_IAudioClock(iface);
2198 return IAudioClient_Release(&This->IAudioClient_iface);
2201 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2203 ACImpl *This = impl_from_IAudioClock(iface);
2204 HRESULT hr;
2206 TRACE("(%p)->(%p)\n", This, freq);
2208 pthread_mutex_lock(&pulse_lock);
2209 hr = pulse_stream_valid(This);
2210 if (SUCCEEDED(hr))
2211 *freq = This->ss.rate * pa_frame_size(&This->ss);
2212 pthread_mutex_unlock(&pulse_lock);
2213 return hr;
2216 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2217 UINT64 *qpctime)
2219 ACImpl *This = impl_from_IAudioClock(iface);
2220 HRESULT hr;
2222 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2224 if (!pos)
2225 return E_POINTER;
2227 pthread_mutex_lock(&pulse_lock);
2228 hr = pulse_stream_valid(This);
2229 if (FAILED(hr)) {
2230 pthread_mutex_unlock(&pulse_lock);
2231 return hr;
2234 *pos = This->clock_written;
2236 /* Make time never go backwards */
2237 if (*pos < This->clock_lastpos)
2238 *pos = This->clock_lastpos;
2239 else
2240 This->clock_lastpos = *pos;
2241 pthread_mutex_unlock(&pulse_lock);
2243 TRACE("%p Position: %u\n", This, (unsigned)*pos);
2245 if (qpctime) {
2246 LARGE_INTEGER stamp, freq;
2247 QueryPerformanceCounter(&stamp);
2248 QueryPerformanceFrequency(&freq);
2249 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2252 return S_OK;
2255 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2256 DWORD *chars)
2258 ACImpl *This = impl_from_IAudioClock(iface);
2260 TRACE("(%p)->(%p)\n", This, chars);
2262 if (!chars)
2263 return E_POINTER;
2265 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2267 return S_OK;
2270 static const IAudioClockVtbl AudioClock_Vtbl =
2272 AudioClock_QueryInterface,
2273 AudioClock_AddRef,
2274 AudioClock_Release,
2275 AudioClock_GetFrequency,
2276 AudioClock_GetPosition,
2277 AudioClock_GetCharacteristics
2280 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2281 REFIID riid, void **ppv)
2283 ACImpl *This = impl_from_IAudioClock2(iface);
2284 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2287 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2289 ACImpl *This = impl_from_IAudioClock2(iface);
2290 return IAudioClient_AddRef(&This->IAudioClient_iface);
2293 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2295 ACImpl *This = impl_from_IAudioClock2(iface);
2296 return IAudioClient_Release(&This->IAudioClient_iface);
2299 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2300 UINT64 *pos, UINT64 *qpctime)
2302 ACImpl *This = impl_from_IAudioClock2(iface);
2303 HRESULT hr = AudioClock_GetPosition(&This->IAudioClock_iface, pos, qpctime);
2304 if (SUCCEEDED(hr))
2305 *pos /= pa_frame_size(&This->ss);
2306 return hr;
2309 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2311 AudioClock2_QueryInterface,
2312 AudioClock2_AddRef,
2313 AudioClock2_Release,
2314 AudioClock2_GetDevicePosition
2317 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2318 IAudioStreamVolume *iface, REFIID riid, void **ppv)
2320 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2322 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2324 if (!ppv)
2325 return E_POINTER;
2326 *ppv = NULL;
2328 if (IsEqualIID(riid, &IID_IUnknown) ||
2329 IsEqualIID(riid, &IID_IAudioStreamVolume))
2330 *ppv = iface;
2331 if (*ppv) {
2332 IUnknown_AddRef((IUnknown*)*ppv);
2333 return S_OK;
2336 if (IsEqualIID(riid, &IID_IMarshal))
2337 return IUnknown_QueryInterface(This->marshal, riid, ppv);
2339 WARN("Unknown interface %s\n", debugstr_guid(riid));
2340 return E_NOINTERFACE;
2343 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2345 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2346 return IAudioClient_AddRef(&This->IAudioClient_iface);
2349 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2351 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2352 return IAudioClient_Release(&This->IAudioClient_iface);
2355 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2356 IAudioStreamVolume *iface, UINT32 *out)
2358 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2360 TRACE("(%p)->(%p)\n", This, out);
2362 if (!out)
2363 return E_POINTER;
2365 *out = This->ss.channels;
2367 return S_OK;
2370 struct pulse_info_cb_data {
2371 UINT32 n;
2372 float *levels;
2375 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2376 IAudioStreamVolume *iface, UINT32 count, const float *levels)
2378 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2379 HRESULT hr;
2380 int i;
2382 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2384 if (!levels)
2385 return E_POINTER;
2387 if (count != This->ss.channels)
2388 return E_INVALIDARG;
2390 pthread_mutex_lock(&pulse_lock);
2391 hr = pulse_stream_valid(This);
2392 if (FAILED(hr))
2393 goto out;
2395 for (i = 0; i < count; ++i)
2396 This->vol[i] = levels[i];
2398 out:
2399 pthread_mutex_unlock(&pulse_lock);
2400 return hr;
2403 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2404 IAudioStreamVolume *iface, UINT32 count, float *levels)
2406 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2407 HRESULT hr;
2408 int i;
2410 TRACE("(%p)->(%d, %p)\n", This, count, levels);
2412 if (!levels)
2413 return E_POINTER;
2415 if (count != This->ss.channels)
2416 return E_INVALIDARG;
2418 pthread_mutex_lock(&pulse_lock);
2419 hr = pulse_stream_valid(This);
2420 if (FAILED(hr))
2421 goto out;
2423 for (i = 0; i < count; ++i)
2424 levels[i] = This->vol[i];
2426 out:
2427 pthread_mutex_unlock(&pulse_lock);
2428 return hr;
2431 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2432 IAudioStreamVolume *iface, UINT32 index, float level)
2434 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2435 HRESULT hr;
2436 float volumes[PA_CHANNELS_MAX];
2438 TRACE("(%p)->(%d, %f)\n", This, index, level);
2440 if (level < 0.f || level > 1.f)
2441 return E_INVALIDARG;
2443 if (index >= This->ss.channels)
2444 return E_INVALIDARG;
2446 hr = AudioStreamVolume_GetAllVolumes(iface, This->ss.channels, volumes);
2447 volumes[index] = level;
2448 if (SUCCEEDED(hr))
2449 hr = AudioStreamVolume_SetAllVolumes(iface, This->ss.channels, volumes);
2450 return hr;
2453 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2454 IAudioStreamVolume *iface, UINT32 index, float *level)
2456 ACImpl *This = impl_from_IAudioStreamVolume(iface);
2457 float volumes[PA_CHANNELS_MAX];
2458 HRESULT hr;
2460 TRACE("(%p)->(%d, %p)\n", This, index, level);
2462 if (!level)
2463 return E_POINTER;
2465 if (index >= This->ss.channels)
2466 return E_INVALIDARG;
2468 hr = AudioStreamVolume_GetAllVolumes(iface, This->ss.channels, volumes);
2469 if (SUCCEEDED(hr))
2470 *level = volumes[index];
2471 return hr;
2474 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2476 AudioStreamVolume_QueryInterface,
2477 AudioStreamVolume_AddRef,
2478 AudioStreamVolume_Release,
2479 AudioStreamVolume_GetChannelCount,
2480 AudioStreamVolume_SetChannelVolume,
2481 AudioStreamVolume_GetChannelVolume,
2482 AudioStreamVolume_SetAllVolumes,
2483 AudioStreamVolume_GetAllVolumes
2486 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2488 AudioSessionWrapper *ret;
2490 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2491 sizeof(AudioSessionWrapper));
2492 if (!ret)
2493 return NULL;
2495 ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2496 ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2497 ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2499 ret->ref = !client;
2501 ret->client = client;
2502 if (client) {
2503 ret->session = client->session;
2504 AudioClient_AddRef(&client->IAudioClient_iface);
2507 return ret;
2510 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2511 IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2513 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2515 if (!ppv)
2516 return E_POINTER;
2517 *ppv = NULL;
2519 if (IsEqualIID(riid, &IID_IUnknown) ||
2520 IsEqualIID(riid, &IID_IAudioSessionControl) ||
2521 IsEqualIID(riid, &IID_IAudioSessionControl2))
2522 *ppv = iface;
2523 if (*ppv) {
2524 IUnknown_AddRef((IUnknown*)*ppv);
2525 return S_OK;
2528 WARN("Unknown interface %s\n", debugstr_guid(riid));
2529 return E_NOINTERFACE;
2532 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2534 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2535 ULONG ref;
2536 ref = InterlockedIncrement(&This->ref);
2537 TRACE("(%p) Refcount now %u\n", This, ref);
2538 return ref;
2541 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2543 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2544 ULONG ref;
2545 ref = InterlockedDecrement(&This->ref);
2546 TRACE("(%p) Refcount now %u\n", This, ref);
2547 if (!ref) {
2548 if (This->client) {
2549 This->client->session_wrapper = NULL;
2550 AudioClient_Release(&This->client->IAudioClient_iface);
2552 HeapFree(GetProcessHeap(), 0, This);
2554 return ref;
2557 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2558 AudioSessionState *state)
2560 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2561 ACImpl *client;
2563 TRACE("(%p)->(%p)\n", This, state);
2565 if (!state)
2566 return NULL_PTR_ERR;
2568 pthread_mutex_lock(&pulse_lock);
2569 if (list_empty(&This->session->clients)) {
2570 *state = AudioSessionStateExpired;
2571 goto out;
2573 LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry) {
2574 if (client->started) {
2575 *state = AudioSessionStateActive;
2576 goto out;
2579 *state = AudioSessionStateInactive;
2581 out:
2582 pthread_mutex_unlock(&pulse_lock);
2583 return S_OK;
2586 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2587 IAudioSessionControl2 *iface, WCHAR **name)
2589 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2591 FIXME("(%p)->(%p) - stub\n", This, name);
2593 return E_NOTIMPL;
2596 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2597 IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2599 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2601 FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2603 return E_NOTIMPL;
2606 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2607 IAudioSessionControl2 *iface, WCHAR **path)
2609 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2611 FIXME("(%p)->(%p) - stub\n", This, path);
2613 return E_NOTIMPL;
2616 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2617 IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2619 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2621 FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2623 return E_NOTIMPL;
2626 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2627 IAudioSessionControl2 *iface, GUID *group)
2629 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2631 FIXME("(%p)->(%p) - stub\n", This, group);
2633 return E_NOTIMPL;
2636 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2637 IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2639 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2641 FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2642 debugstr_guid(session));
2644 return E_NOTIMPL;
2647 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2648 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2650 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2652 FIXME("(%p)->(%p) - stub\n", This, events);
2654 return S_OK;
2657 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2658 IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2660 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2662 FIXME("(%p)->(%p) - stub\n", This, events);
2664 return S_OK;
2667 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2668 IAudioSessionControl2 *iface, WCHAR **id)
2670 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2672 FIXME("(%p)->(%p) - stub\n", This, id);
2674 return E_NOTIMPL;
2677 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2678 IAudioSessionControl2 *iface, WCHAR **id)
2680 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2682 FIXME("(%p)->(%p) - stub\n", This, id);
2684 return E_NOTIMPL;
2687 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2688 IAudioSessionControl2 *iface, DWORD *pid)
2690 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2692 TRACE("(%p)->(%p)\n", This, pid);
2694 if (!pid)
2695 return E_POINTER;
2697 *pid = GetCurrentProcessId();
2699 return S_OK;
2702 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2703 IAudioSessionControl2 *iface)
2705 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2707 TRACE("(%p)\n", This);
2709 return S_FALSE;
2712 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2713 IAudioSessionControl2 *iface, BOOL optout)
2715 AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2717 TRACE("(%p)->(%d)\n", This, optout);
2719 return S_OK;
2722 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2724 AudioSessionControl_QueryInterface,
2725 AudioSessionControl_AddRef,
2726 AudioSessionControl_Release,
2727 AudioSessionControl_GetState,
2728 AudioSessionControl_GetDisplayName,
2729 AudioSessionControl_SetDisplayName,
2730 AudioSessionControl_GetIconPath,
2731 AudioSessionControl_SetIconPath,
2732 AudioSessionControl_GetGroupingParam,
2733 AudioSessionControl_SetGroupingParam,
2734 AudioSessionControl_RegisterAudioSessionNotification,
2735 AudioSessionControl_UnregisterAudioSessionNotification,
2736 AudioSessionControl_GetSessionIdentifier,
2737 AudioSessionControl_GetSessionInstanceIdentifier,
2738 AudioSessionControl_GetProcessId,
2739 AudioSessionControl_IsSystemSoundsSession,
2740 AudioSessionControl_SetDuckingPreference
2743 typedef struct _SessionMgr {
2744 IAudioSessionManager2 IAudioSessionManager2_iface;
2746 LONG ref;
2748 IMMDevice *device;
2749 } SessionMgr;
2751 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2752 REFIID riid, void **ppv)
2754 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2756 if (!ppv)
2757 return E_POINTER;
2758 *ppv = NULL;
2760 if (IsEqualIID(riid, &IID_IUnknown) ||
2761 IsEqualIID(riid, &IID_IAudioSessionManager) ||
2762 IsEqualIID(riid, &IID_IAudioSessionManager2))
2763 *ppv = iface;
2764 if (*ppv) {
2765 IUnknown_AddRef((IUnknown*)*ppv);
2766 return S_OK;
2769 WARN("Unknown interface %s\n", debugstr_guid(riid));
2770 return E_NOINTERFACE;
2773 static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
2775 return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
2778 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2780 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2781 ULONG ref;
2782 ref = InterlockedIncrement(&This->ref);
2783 TRACE("(%p) Refcount now %u\n", This, ref);
2784 return ref;
2787 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2789 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2790 ULONG ref;
2791 ref = InterlockedDecrement(&This->ref);
2792 TRACE("(%p) Refcount now %u\n", This, ref);
2793 if (!ref)
2794 HeapFree(GetProcessHeap(), 0, This);
2795 return ref;
2798 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2799 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2800 IAudioSessionControl **out)
2802 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2803 AudioSession *session;
2804 AudioSessionWrapper *wrapper;
2805 HRESULT hr;
2807 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2808 flags, out);
2810 hr = get_audio_session(session_guid, This->device, 0, &session);
2811 if (FAILED(hr))
2812 return hr;
2814 wrapper = AudioSessionWrapper_Create(NULL);
2815 if (!wrapper)
2816 return E_OUTOFMEMORY;
2818 wrapper->session = session;
2820 *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2822 return S_OK;
2825 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2826 IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2827 ISimpleAudioVolume **out)
2829 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2830 AudioSession *session;
2831 AudioSessionWrapper *wrapper;
2832 HRESULT hr;
2834 TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2835 flags, out);
2837 hr = get_audio_session(session_guid, This->device, 0, &session);
2838 if (FAILED(hr))
2839 return hr;
2841 wrapper = AudioSessionWrapper_Create(NULL);
2842 if (!wrapper)
2843 return E_OUTOFMEMORY;
2845 wrapper->session = session;
2847 *out = &wrapper->ISimpleAudioVolume_iface;
2849 return S_OK;
2852 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2853 IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2855 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2856 FIXME("(%p)->(%p) - stub\n", This, out);
2857 return E_NOTIMPL;
2860 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2861 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2863 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2864 FIXME("(%p)->(%p) - stub\n", This, notification);
2865 return E_NOTIMPL;
2868 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2869 IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2871 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2872 FIXME("(%p)->(%p) - stub\n", This, notification);
2873 return E_NOTIMPL;
2876 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2877 IAudioSessionManager2 *iface, const WCHAR *session_id,
2878 IAudioVolumeDuckNotification *notification)
2880 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2881 FIXME("(%p)->(%p) - stub\n", This, notification);
2882 return E_NOTIMPL;
2885 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2886 IAudioSessionManager2 *iface,
2887 IAudioVolumeDuckNotification *notification)
2889 SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2890 FIXME("(%p)->(%p) - stub\n", This, notification);
2891 return E_NOTIMPL;
2894 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2896 AudioSessionManager_QueryInterface,
2897 AudioSessionManager_AddRef,
2898 AudioSessionManager_Release,
2899 AudioSessionManager_GetAudioSessionControl,
2900 AudioSessionManager_GetSimpleAudioVolume,
2901 AudioSessionManager_GetSessionEnumerator,
2902 AudioSessionManager_RegisterSessionNotification,
2903 AudioSessionManager_UnregisterSessionNotification,
2904 AudioSessionManager_RegisterDuckNotification,
2905 AudioSessionManager_UnregisterDuckNotification
2908 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2909 ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2911 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2913 if (!ppv)
2914 return E_POINTER;
2915 *ppv = NULL;
2917 if (IsEqualIID(riid, &IID_IUnknown) ||
2918 IsEqualIID(riid, &IID_ISimpleAudioVolume))
2919 *ppv = iface;
2920 if (*ppv) {
2921 IUnknown_AddRef((IUnknown*)*ppv);
2922 return S_OK;
2925 WARN("Unknown interface %s\n", debugstr_guid(riid));
2926 return E_NOINTERFACE;
2929 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2931 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2932 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2935 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2937 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2938 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2941 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2942 ISimpleAudioVolume *iface, float level, const GUID *context)
2944 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2945 AudioSession *session = This->session;
2947 TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2949 if (level < 0.f || level > 1.f)
2950 return E_INVALIDARG;
2952 if (context)
2953 FIXME("Notifications not supported yet\n");
2955 TRACE("Pulseaudio does not support session volume control\n");
2957 pthread_mutex_lock(&pulse_lock);
2958 session->master_vol = level;
2959 pthread_mutex_unlock(&pulse_lock);
2961 return S_OK;
2964 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2965 ISimpleAudioVolume *iface, float *level)
2967 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2968 AudioSession *session = This->session;
2970 TRACE("(%p)->(%p)\n", session, level);
2972 if (!level)
2973 return NULL_PTR_ERR;
2975 *level = session->master_vol;
2977 return S_OK;
2980 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2981 BOOL mute, const GUID *context)
2983 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2984 AudioSession *session = This->session;
2986 TRACE("(%p)->(%u, %p)\n", session, mute, context);
2988 if (context)
2989 FIXME("Notifications not supported yet\n");
2991 session->mute = mute;
2993 return S_OK;
2996 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2997 BOOL *mute)
2999 AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
3000 AudioSession *session = This->session;
3002 TRACE("(%p)->(%p)\n", session, mute);
3004 if (!mute)
3005 return NULL_PTR_ERR;
3007 *mute = session->mute;
3009 return S_OK;
3012 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
3014 SimpleAudioVolume_QueryInterface,
3015 SimpleAudioVolume_AddRef,
3016 SimpleAudioVolume_Release,
3017 SimpleAudioVolume_SetMasterVolume,
3018 SimpleAudioVolume_GetMasterVolume,
3019 SimpleAudioVolume_SetMute,
3020 SimpleAudioVolume_GetMute
3023 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
3024 IChannelAudioVolume *iface, REFIID riid, void **ppv)
3026 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
3028 if (!ppv)
3029 return E_POINTER;
3030 *ppv = NULL;
3032 if (IsEqualIID(riid, &IID_IUnknown) ||
3033 IsEqualIID(riid, &IID_IChannelAudioVolume))
3034 *ppv = iface;
3035 if (*ppv) {
3036 IUnknown_AddRef((IUnknown*)*ppv);
3037 return S_OK;
3040 WARN("Unknown interface %s\n", debugstr_guid(riid));
3041 return E_NOINTERFACE;
3044 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
3046 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3047 return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
3050 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
3052 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3053 return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
3056 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
3057 IChannelAudioVolume *iface, UINT32 *out)
3059 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3060 AudioSession *session = This->session;
3062 TRACE("(%p)->(%p)\n", session, out);
3064 if (!out)
3065 return NULL_PTR_ERR;
3067 *out = session->channel_count;
3069 return S_OK;
3072 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
3073 IChannelAudioVolume *iface, UINT32 index, float level,
3074 const GUID *context)
3076 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3077 AudioSession *session = This->session;
3079 TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
3080 wine_dbgstr_guid(context));
3082 if (level < 0.f || level > 1.f)
3083 return E_INVALIDARG;
3085 if (index >= session->channel_count)
3086 return E_INVALIDARG;
3088 if (context)
3089 FIXME("Notifications not supported yet\n");
3091 TRACE("Pulseaudio does not support session volume control\n");
3093 pthread_mutex_lock(&pulse_lock);
3094 session->channel_vols[index] = level;
3095 pthread_mutex_unlock(&pulse_lock);
3097 return S_OK;
3100 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
3101 IChannelAudioVolume *iface, UINT32 index, float *level)
3103 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3104 AudioSession *session = This->session;
3106 TRACE("(%p)->(%d, %p)\n", session, index, level);
3108 if (!level)
3109 return NULL_PTR_ERR;
3111 if (index >= session->channel_count)
3112 return E_INVALIDARG;
3114 *level = session->channel_vols[index];
3116 return S_OK;
3119 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
3120 IChannelAudioVolume *iface, UINT32 count, const float *levels,
3121 const GUID *context)
3123 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3124 AudioSession *session = This->session;
3125 int i;
3127 TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
3128 wine_dbgstr_guid(context));
3130 if (!levels)
3131 return NULL_PTR_ERR;
3133 if (count != session->channel_count)
3134 return E_INVALIDARG;
3136 if (context)
3137 FIXME("Notifications not supported yet\n");
3139 TRACE("Pulseaudio does not support session volume control\n");
3141 pthread_mutex_lock(&pulse_lock);
3142 for(i = 0; i < count; ++i)
3143 session->channel_vols[i] = levels[i];
3144 pthread_mutex_unlock(&pulse_lock);
3145 return S_OK;
3148 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
3149 IChannelAudioVolume *iface, UINT32 count, float *levels)
3151 AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
3152 AudioSession *session = This->session;
3153 int i;
3155 TRACE("(%p)->(%d, %p)\n", session, count, levels);
3157 if (!levels)
3158 return NULL_PTR_ERR;
3160 if (count != session->channel_count)
3161 return E_INVALIDARG;
3163 for(i = 0; i < count; ++i)
3164 levels[i] = session->channel_vols[i];
3166 return S_OK;
3169 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
3171 ChannelAudioVolume_QueryInterface,
3172 ChannelAudioVolume_AddRef,
3173 ChannelAudioVolume_Release,
3174 ChannelAudioVolume_GetChannelCount,
3175 ChannelAudioVolume_SetChannelVolume,
3176 ChannelAudioVolume_GetChannelVolume,
3177 ChannelAudioVolume_SetAllVolumes,
3178 ChannelAudioVolume_GetAllVolumes
3181 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3182 IAudioSessionManager2 **out)
3184 SessionMgr *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3185 *out = NULL;
3186 if (!This)
3187 return E_OUTOFMEMORY;
3188 This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3189 This->device = device;
3190 This->ref = 1;
3191 *out = &This->IAudioSessionManager2_iface;
3192 return S_OK;