winepulse: Add IAudioRenderClient and IAudioCaptureClient
[wine/multimedia.git] / dlls / winepulse.drv / mmdevdrv.c
blob01cfd25febe5d5a7ca1b2b65cecc1160116d54b0
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
20 * Pulseaudio driver support.. hell froze over
23 #define NONAMELESSUNION
24 #define COBJMACROS
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>
34 #include <pulse/pulseaudio.h>
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winnls.h"
39 #include "winreg.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42 #include "wine/list.h"
44 #include "ole2.h"
45 #include "dshow.h"
46 #include "dsound.h"
47 #include "propsys.h"
49 #include "initguid.h"
50 #include "ks.h"
51 #include "ksmedia.h"
52 #include "mmdeviceapi.h"
53 #include "audioclient.h"
54 #include "endpointvolume.h"
55 #include "audiopolicy.h"
57 #include "wine/list.h"
59 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
61 WINE_DEFAULT_DEBUG_CHANNEL(pulse);
63 static const REFERENCE_TIME MinimumPeriod = 30000;
64 static const REFERENCE_TIME DefaultPeriod = 100000;
66 static pa_context *pulse_ctx;
67 static pa_mainloop *pulse_ml;
69 static HANDLE pulse_thread;
70 static pthread_mutex_t pulse_lock = PTHREAD_MUTEX_INITIALIZER;
71 static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
73 /* Mixer format + period times */
74 static WAVEFORMATEXTENSIBLE pulse_fmt[2];
75 static REFERENCE_TIME pulse_min_period[2], pulse_def_period[2];
77 static DWORD pulse_stream_volume;
79 const WCHAR pulse_keyW[] = {'S','o','f','t','w','a','r','e','\\',
80 'W','i','n','e','\\','P','u','l','s','e',0};
81 const WCHAR pulse_streamW[] = { 'S','t','r','e','a','m','V','o','l',0 };
83 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
85 if (reason == DLL_PROCESS_ATTACH) {
86 HKEY key;
87 if (RegOpenKeyW(HKEY_CURRENT_USER, pulse_keyW, &key) == ERROR_SUCCESS) {
88 DWORD size = sizeof(pulse_stream_volume);
89 RegQueryValueExW(key, pulse_streamW, 0, NULL,
90 (BYTE*)&pulse_stream_volume, &size);
91 RegCloseKey(key);
93 DisableThreadLibraryCalls(dll);
94 } else if (reason == DLL_PROCESS_DETACH) {
95 if (pulse_ctx) {
96 pa_context_disconnect(pulse_ctx);
97 pa_context_unref(pulse_ctx);
99 if (pulse_ml)
100 pa_mainloop_quit(pulse_ml, 0);
101 CloseHandle(pulse_thread);
103 return TRUE;
106 typedef struct ACImpl ACImpl;
108 typedef struct _ACPacket {
109 struct list entry;
110 UINT64 qpcpos;
111 BYTE *data;
112 UINT32 discont;
113 } ACPacket;
115 struct ACImpl {
116 IAudioClient IAudioClient_iface;
117 IAudioRenderClient IAudioRenderClient_iface;
118 IAudioCaptureClient IAudioCaptureClient_iface;
119 IAudioClock IAudioClock_iface;
120 IAudioClock2 IAudioClock2_iface;
121 IAudioStreamVolume IAudioStreamVolume_iface;
122 IMMDevice *parent;
123 struct list entry;
124 float vol[PA_CHANNELS_MAX];
126 LONG ref;
127 EDataFlow dataflow;
128 DWORD flags;
129 AUDCLNT_SHAREMODE share;
130 HANDLE event;
132 UINT32 bufsize_frames, bufsize_bytes, locked, capture_period, pad, started, peek_ofs;
133 void *locked_ptr, *tmp_buffer;
135 pa_stream *stream;
136 pa_sample_spec ss;
137 pa_channel_map map;
139 INT64 clock_lastpos, clock_written;
140 pa_usec_t clock_pulse;
142 struct list packet_free_head;
143 struct list packet_filled_head;
146 static const WCHAR defaultW[] = {'P','u','l','s','e','a','u','d','i','o',0};
148 static const IAudioClientVtbl AudioClient_Vtbl;
149 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
150 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
151 static const IAudioClockVtbl AudioClock_Vtbl;
152 static const IAudioClock2Vtbl AudioClock2_Vtbl;
153 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
155 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
157 return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
160 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
162 return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
165 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
167 return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
170 /* Following pulseaudio design here, mainloop has the lock taken whenever
171 * it is handling something for pulse, and the lock is required whenever
172 * doing any pa_* call that can affect the state in any way
174 * pa_cond_wait is used when waiting on results, because the mainloop needs
175 * the same lock taken to affect the state
177 * This is basically the same as the pa_threaded_mainloop implementation,
178 * but that cannot be used because it uses pthread_create directly
180 * pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock
181 * pa_threaded_mainloop_signal -> pthread_cond_signal
182 * pa_threaded_mainloop_wait -> pthread_cond_wait
185 static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
186 int r;
187 pthread_mutex_unlock(&pulse_lock);
188 r = poll(ufds, nfds, timeout);
189 pthread_mutex_lock(&pulse_lock);
190 return r;
193 static DWORD CALLBACK pulse_mainloop_thread(void *tmp) {
194 int ret;
195 pulse_ml = pa_mainloop_new();
196 pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL);
197 pthread_mutex_lock(&pulse_lock);
198 pthread_cond_signal(&pulse_cond);
199 pa_mainloop_run(pulse_ml, &ret);
200 pthread_mutex_unlock(&pulse_lock);
201 pa_mainloop_free(pulse_ml);
202 CloseHandle(pulse_thread);
203 return ret;
206 static void pulse_contextcallback(pa_context *c, void *userdata);
207 static void pulse_stream_state(pa_stream *s, void *user);
209 static const enum pa_channel_position pulse_pos_from_wfx[] = {
210 PA_CHANNEL_POSITION_FRONT_LEFT,
211 PA_CHANNEL_POSITION_FRONT_RIGHT,
212 PA_CHANNEL_POSITION_FRONT_CENTER,
213 PA_CHANNEL_POSITION_LFE,
214 PA_CHANNEL_POSITION_REAR_LEFT,
215 PA_CHANNEL_POSITION_REAR_RIGHT,
216 PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
217 PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
218 PA_CHANNEL_POSITION_REAR_CENTER,
219 PA_CHANNEL_POSITION_SIDE_LEFT,
220 PA_CHANNEL_POSITION_SIDE_RIGHT,
221 PA_CHANNEL_POSITION_TOP_CENTER,
222 PA_CHANNEL_POSITION_TOP_FRONT_LEFT,
223 PA_CHANNEL_POSITION_TOP_FRONT_CENTER,
224 PA_CHANNEL_POSITION_TOP_FRONT_RIGHT,
225 PA_CHANNEL_POSITION_TOP_REAR_LEFT,
226 PA_CHANNEL_POSITION_TOP_REAR_CENTER,
227 PA_CHANNEL_POSITION_TOP_REAR_RIGHT
230 static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
231 WAVEFORMATEX *wfx = &fmt->Format;
232 pa_stream *stream;
233 pa_channel_map map;
234 pa_sample_spec ss;
235 pa_buffer_attr attr;
236 int ret, i;
237 unsigned int length = 0;
239 pa_channel_map_init_auto(&map, 2, PA_CHANNEL_MAP_ALSA);
240 ss.rate = 48000;
241 ss.format = PA_SAMPLE_FLOAT32LE;
242 ss.channels = map.channels;
244 attr.maxlength = -1;
245 attr.tlength = -1;
246 attr.minreq = attr.fragsize = pa_frame_size(&ss);
247 attr.prebuf = 0;
249 stream = pa_stream_new(pulse_ctx, "format test stream", &ss, &map);
250 if (stream)
251 pa_stream_set_state_callback(stream, pulse_stream_state, NULL);
252 if (!stream)
253 ret = -1;
254 else if (render)
255 ret = pa_stream_connect_playback(stream, NULL, &attr,
256 PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
257 else
258 ret = pa_stream_connect_record(stream, NULL, &attr, PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS);
259 if (ret >= 0) {
260 while (pa_stream_get_state(stream) == PA_STREAM_CREATING)
261 pthread_cond_wait(&pulse_cond, &pulse_lock);
262 if (pa_stream_get_state(stream) == PA_STREAM_READY) {
263 ss = *pa_stream_get_sample_spec(stream);
264 map = *pa_stream_get_channel_map(stream);
265 if (render)
266 length = pa_stream_get_buffer_attr(stream)->minreq;
267 else
268 length = pa_stream_get_buffer_attr(stream)->fragsize;
269 pa_stream_disconnect(stream);
270 while (pa_stream_get_state(stream) == PA_STREAM_READY)
271 pthread_cond_wait(&pulse_cond, &pulse_lock);
274 if (stream)
275 pa_stream_unref(stream);
276 if (length)
277 pulse_def_period[!render] = pulse_min_period[!render] = pa_bytes_to_usec(10 * length, &ss);
278 else
279 pulse_min_period[!render] = MinimumPeriod;
280 if (pulse_def_period[!render] <= DefaultPeriod)
281 pulse_def_period[!render] = DefaultPeriod;
283 wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
284 wfx->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
285 wfx->nChannels = ss.channels;
286 wfx->wBitsPerSample = 8 * pa_sample_size_of_format(ss.format);
287 wfx->nSamplesPerSec = ss.rate;
288 wfx->nBlockAlign = pa_frame_size(&ss);
289 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
290 if (ss.format != PA_SAMPLE_S24_32LE)
291 fmt->Samples.wValidBitsPerSample = wfx->wBitsPerSample;
292 else
293 fmt->Samples.wValidBitsPerSample = 24;
294 if (ss.format == PA_SAMPLE_FLOAT32LE)
295 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
296 else
297 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
299 fmt->dwChannelMask = 0;
300 for (i = 0; i < map.channels; ++i)
301 switch (map.map[i]) {
302 default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map.map[i])); break;
303 case PA_CHANNEL_POSITION_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_FRONT_LEFT; break;
304 case PA_CHANNEL_POSITION_MONO:
305 case PA_CHANNEL_POSITION_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_FRONT_CENTER; break;
306 case PA_CHANNEL_POSITION_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_FRONT_RIGHT; break;
307 case PA_CHANNEL_POSITION_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_BACK_LEFT; break;
308 case PA_CHANNEL_POSITION_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_BACK_CENTER; break;
309 case PA_CHANNEL_POSITION_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_BACK_RIGHT; break;
310 case PA_CHANNEL_POSITION_LFE: fmt->dwChannelMask |= SPEAKER_LOW_FREQUENCY; break;
311 case PA_CHANNEL_POSITION_SIDE_LEFT: fmt->dwChannelMask |= SPEAKER_SIDE_LEFT; break;
312 case PA_CHANNEL_POSITION_SIDE_RIGHT: fmt->dwChannelMask |= SPEAKER_SIDE_RIGHT; break;
313 case PA_CHANNEL_POSITION_TOP_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_CENTER; break;
314 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_LEFT; break;
315 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_CENTER; break;
316 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_RIGHT; break;
317 case PA_CHANNEL_POSITION_TOP_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_LEFT; break;
318 case PA_CHANNEL_POSITION_TOP_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_BACK_CENTER; break;
319 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_RIGHT; break;
323 static HRESULT pulse_connect(void)
325 int len;
326 WCHAR path[PATH_MAX], *name;
327 char *str;
329 if (!pulse_thread)
331 if (!(pulse_thread = CreateThread(NULL, 0, pulse_mainloop_thread, NULL, 0, NULL)))
333 ERR("Failed to create mainloop thread.");
334 return E_FAIL;
336 SetThreadPriority(pulse_thread, THREAD_PRIORITY_TIME_CRITICAL);
337 pthread_cond_wait(&pulse_cond, &pulse_lock);
340 if (pulse_ctx && PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx)))
341 return S_OK;
342 if (pulse_ctx)
343 pa_context_unref(pulse_ctx);
345 GetModuleFileNameW(NULL, path, sizeof(path)/sizeof(*path));
346 name = strrchrW(path, '\\');
347 if (!name)
348 name = path;
349 else
350 name++;
351 len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
352 str = pa_xmalloc(len);
353 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL);
354 TRACE("Name: %s\n", str);
355 pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str);
356 pa_xfree(str);
357 if (!pulse_ctx) {
358 ERR("Failed to create context\n");
359 return E_FAIL;
362 pa_context_set_state_callback(pulse_ctx, pulse_contextcallback, NULL);
364 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx), PA_API_VERSION);
365 if (pa_context_connect(pulse_ctx, NULL, 0, NULL) < 0)
366 goto fail;
368 /* Wait for connection */
369 while (pthread_cond_wait(&pulse_cond, &pulse_lock)) {
370 pa_context_state_t state = pa_context_get_state(pulse_ctx);
372 if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
373 goto fail;
375 if (state == PA_CONTEXT_READY)
376 break;
379 TRACE("Connected to server %s with protocol version: %i.\n",
380 pa_context_get_server(pulse_ctx),
381 pa_context_get_server_protocol_version(pulse_ctx));
382 pulse_probe_settings(1, &pulse_fmt[0]);
383 pulse_probe_settings(0, &pulse_fmt[1]);
384 return S_OK;
386 fail:
387 pa_context_unref(pulse_ctx);
388 pulse_ctx = NULL;
389 return E_FAIL;
392 static void pulse_contextcallback(pa_context *c, void *userdata) {
393 switch (pa_context_get_state(c)) {
394 default:
395 FIXME("Unhandled state: %i\n", pa_context_get_state(c));
396 case PA_CONTEXT_CONNECTING:
397 case PA_CONTEXT_UNCONNECTED:
398 case PA_CONTEXT_AUTHORIZING:
399 case PA_CONTEXT_SETTING_NAME:
400 case PA_CONTEXT_TERMINATED:
401 TRACE("State change to %i\n", pa_context_get_state(c));
402 return;
404 case PA_CONTEXT_READY:
405 TRACE("Ready\n");
406 break;
408 case PA_CONTEXT_FAILED:
409 ERR("Context failed: %s\n", pa_strerror(pa_context_errno(c)));
410 break;
412 pthread_cond_signal(&pulse_cond);
415 static HRESULT pulse_stream_valid(ACImpl *This) {
416 if (!This->stream)
417 return AUDCLNT_E_NOT_INITIALIZED;
418 if (!This->stream || pa_stream_get_state(This->stream) != PA_STREAM_READY)
419 return AUDCLNT_E_DEVICE_INVALIDATED;
420 return S_OK;
423 static void dump_attr(const pa_buffer_attr *attr) {
424 TRACE("maxlength: %u\n", attr->maxlength);
425 TRACE("minreq: %u\n", attr->minreq);
426 TRACE("fragsize: %u\n", attr->fragsize);
427 TRACE("tlength: %u\n", attr->tlength);
428 TRACE("prebuf: %u\n", attr->prebuf);
431 static void pulse_op_cb(pa_stream *s, int success, void *user) {
432 TRACE("Success: %i\n", success);
433 *(int*)user = success;
434 pthread_cond_signal(&pulse_cond);
437 static void pulse_attr_update(pa_stream *s, void *user) {
438 const pa_buffer_attr *attr = pa_stream_get_buffer_attr(s);
439 TRACE("New attributes or device moved:\n");
440 dump_attr(attr);
443 static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata)
445 ACImpl *This = userdata;
446 pa_usec_t time;
447 UINT32 oldpad = This->pad;
449 if (bytes < This->bufsize_bytes)
450 This->pad = This->bufsize_bytes - bytes;
451 else
452 This->pad = 0;
454 assert(oldpad >= This->pad);
456 if (0 && This->pad && pa_stream_get_time(This->stream, &time) >= 0)
457 This->clock_pulse = time;
458 else
459 This->clock_pulse = PA_USEC_INVALID;
461 This->clock_written += oldpad - This->pad;
462 TRACE("New pad: %u (-%u)\n", This->pad / pa_frame_size(&This->ss), (oldpad - This->pad) / pa_frame_size(&This->ss));
464 if (This->event)
465 SetEvent(This->event);
468 static void pulse_underflow_callback(pa_stream *s, void *userdata)
470 ACImpl *This = userdata;
471 This->clock_pulse = PA_USEC_INVALID;
472 WARN("Underflow\n");
475 /* Latency is periodically updated even when nothing is played,
476 * because of PA_STREAM_AUTO_TIMING_UPDATE so use it as timer
478 * Perfect for passing all tests :)
480 static void pulse_latency_callback(pa_stream *s, void *userdata)
482 ACImpl *This = userdata;
483 if (!This->pad && This->event)
484 SetEvent(This->event);
487 static void pulse_started_callback(pa_stream *s, void *userdata)
489 ACImpl *This = userdata;
490 pa_usec_t time;
492 TRACE("(Re)started playing\n");
493 assert(This->clock_pulse == PA_USEC_INVALID);
494 if (0 && pa_stream_get_time(This->stream, &time) >= 0)
495 This->clock_pulse = time;
496 if (This->event)
497 SetEvent(This->event);
500 static void pulse_rd_loop(ACImpl *This, size_t bytes)
502 while (bytes >= This->capture_period) {
503 ACPacket *p, *next;
504 LARGE_INTEGER stamp, freq;
505 BYTE *dst, *src;
506 UINT32 src_len, copy, rem = This->capture_period;
507 if (!(p = (ACPacket*)list_head(&This->packet_free_head))) {
508 p = (ACPacket*)list_head(&This->packet_filled_head);
509 if (!p->discont) {
510 next = (ACPacket*)p->entry.next;
511 next->discont = 1;
512 } else
513 p = (ACPacket*)list_tail(&This->packet_filled_head);
514 assert(This->pad == This->bufsize_bytes);
515 } else {
516 assert(This->pad < This->bufsize_bytes);
517 This->pad += This->capture_period;
518 assert(This->pad <= This->bufsize_bytes);
520 QueryPerformanceCounter(&stamp);
521 QueryPerformanceFrequency(&freq);
522 p->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
523 p->discont = 0;
524 list_remove(&p->entry);
525 list_add_tail(&This->packet_filled_head, &p->entry);
527 dst = p->data;
528 while (rem) {
529 pa_stream_peek(This->stream, (const void**)&src, &src_len);
530 assert(src_len && src_len <= bytes);
531 assert(This->peek_ofs < src_len);
532 src += This->peek_ofs;
533 src_len -= This->peek_ofs;
535 copy = rem;
536 if (copy > src_len)
537 copy = src_len;
538 memcpy(dst, src, rem);
539 src += copy;
540 src_len -= copy;
541 dst += copy;
542 rem -= copy;
544 if (!src_len) {
545 This->peek_ofs = 0;
546 pa_stream_drop(This->stream);
547 } else
548 This->peek_ofs += copy;
550 bytes -= This->capture_period;
554 static void pulse_rd_drop(ACImpl *This, size_t bytes)
556 while (bytes >= This->capture_period) {
557 UINT32 src_len, copy, rem = This->capture_period;
558 while (rem) {
559 const void *src;
560 pa_stream_peek(This->stream, &src, &src_len);
561 assert(src_len && src_len <= bytes);
562 assert(This->peek_ofs < src_len);
563 src_len -= This->peek_ofs;
565 copy = rem;
566 if (copy > src_len)
567 copy = src_len;
569 src_len -= copy;
570 rem -= copy;
572 if (!src_len) {
573 This->peek_ofs = 0;
574 pa_stream_drop(This->stream);
575 } else
576 This->peek_ofs += copy;
577 bytes -= copy;
582 static void pulse_rd_callback(pa_stream *s, size_t bytes, void *userdata)
584 ACImpl *This = userdata;
586 TRACE("Readable total: %u, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(s)->fragsize);
587 assert(bytes >= This->peek_ofs);
588 bytes -= This->peek_ofs;
589 if (bytes < This->capture_period)
590 return;
592 if (This->started)
593 pulse_rd_loop(This, bytes);
594 else
595 pulse_rd_drop(This, bytes);
597 if (This->event)
598 SetEvent(This->event);
601 static void pulse_stream_state(pa_stream *s, void *user)
603 pa_stream_state_t state = pa_stream_get_state(s);
604 TRACE("Stream state changed to %i\n", state);
605 pthread_cond_signal(&pulse_cond);
608 static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
609 int ret;
610 char buffer[64];
611 static LONG number;
612 pa_buffer_attr attr;
613 if (This->stream) {
614 pa_stream_disconnect(This->stream);
615 while (pa_stream_get_state(This->stream) == PA_STREAM_READY)
616 pthread_cond_wait(&pulse_cond, &pulse_lock);
617 pa_stream_unref(This->stream);
619 ret = InterlockedIncrement(&number);
620 sprintf(buffer, "audio stream #%i", ret);
621 This->stream = pa_stream_new(pulse_ctx, buffer, &This->ss, &This->map);
622 pa_stream_set_state_callback(This->stream, pulse_stream_state, This);
623 pa_stream_set_buffer_attr_callback(This->stream, pulse_attr_update, This);
624 pa_stream_set_moved_callback(This->stream, pulse_attr_update, This);
626 /* Pulseaudio will fill in correct values */
627 attr.minreq = attr.fragsize = period_bytes;
628 attr.maxlength = attr.tlength = This->bufsize_bytes;
629 attr.prebuf = pa_frame_size(&This->ss);
630 dump_attr(&attr);
631 if (This->dataflow == eRender)
632 ret = pa_stream_connect_playback(This->stream, NULL, &attr,
633 PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
634 else
635 ret = pa_stream_connect_record(This->stream, NULL, &attr,
636 PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS);
637 if (ret < 0) {
638 WARN("Returns %i\n", ret);
639 return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
641 while (pa_stream_get_state(This->stream) == PA_STREAM_CREATING)
642 pthread_cond_wait(&pulse_cond, &pulse_lock);
643 if (pa_stream_get_state(This->stream) != PA_STREAM_READY)
644 return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
646 if (This->dataflow == eRender) {
647 pa_stream_set_write_callback(This->stream, pulse_wr_callback, This);
648 pa_stream_set_underflow_callback(This->stream, pulse_underflow_callback, This);
649 pa_stream_set_started_callback(This->stream, pulse_started_callback, This);
650 } else
651 pa_stream_set_read_callback(This->stream, pulse_rd_callback, This);
652 return S_OK;
655 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
656 UINT *num, UINT *def_index)
658 HRESULT hr = S_OK;
659 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
661 pthread_mutex_lock(&pulse_lock);
662 hr = pulse_connect();
663 pthread_mutex_unlock(&pulse_lock);
664 if (FAILED(hr))
665 return hr;
666 *num = 1;
667 *def_index = 0;
669 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
670 if (!*ids)
671 return E_OUTOFMEMORY;
673 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
674 if (!(*ids)[0]) {
675 HeapFree(GetProcessHeap(), 0, *ids);
676 return E_OUTOFMEMORY;
679 lstrcpyW((*ids)[0], defaultW);
681 *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
682 (*keys)[0] = NULL;
684 return S_OK;
687 int WINAPI AUDDRV_GetPriority(void)
689 HRESULT hr;
690 pthread_mutex_lock(&pulse_lock);
691 hr = pulse_connect();
692 pthread_mutex_unlock(&pulse_lock);
693 return SUCCEEDED(hr) ? 3 : 0;
696 HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
697 EDataFlow dataflow, IAudioClient **out)
699 HRESULT hr;
700 ACImpl *This;
701 int i;
703 TRACE("%p %p %d %p\n", key, dev, dataflow, out);
704 if (dataflow != eRender && dataflow != eCapture)
705 return E_UNEXPECTED;
707 *out = NULL;
708 pthread_mutex_lock(&pulse_lock);
709 hr = pulse_connect();
710 pthread_mutex_unlock(&pulse_lock);
711 if (FAILED(hr))
712 return hr;
714 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
715 if (!This)
716 return E_OUTOFMEMORY;
718 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
719 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
720 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
721 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
722 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
723 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
724 This->dataflow = dataflow;
725 This->parent = dev;
726 This->clock_pulse = PA_USEC_INVALID;
727 for (i = 0; i < PA_CHANNELS_MAX; ++i)
728 This->vol[i] = 1.f;
729 IMMDevice_AddRef(This->parent);
731 *out = &This->IAudioClient_iface;
732 IAudioClient_AddRef(&This->IAudioClient_iface);
734 return S_OK;
737 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
738 REFIID riid, void **ppv)
740 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
742 if (!ppv)
743 return E_POINTER;
744 *ppv = NULL;
745 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
746 *ppv = iface;
747 if (*ppv) {
748 IUnknown_AddRef((IUnknown*)*ppv);
749 return S_OK;
751 WARN("Unknown interface %s\n", debugstr_guid(riid));
752 return E_NOINTERFACE;
755 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
757 ACImpl *This = impl_from_IAudioClient(iface);
758 ULONG ref;
759 ref = InterlockedIncrement(&This->ref);
760 TRACE("(%p) Refcount now %u\n", This, ref);
761 return ref;
764 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
766 ACImpl *This = impl_from_IAudioClient(iface);
767 ULONG ref;
768 ref = InterlockedDecrement(&This->ref);
769 TRACE("(%p) Refcount now %u\n", This, ref);
770 if (!ref) {
771 if (This->stream) {
772 pthread_mutex_lock(&pulse_lock);
773 if (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream))) {
774 pa_stream_disconnect(This->stream);
775 while (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream)))
776 pthread_cond_wait(&pulse_cond, &pulse_lock);
778 pa_stream_unref(This->stream);
779 This->stream = NULL;
780 list_remove(&This->entry);
781 pthread_mutex_unlock(&pulse_lock);
783 IMMDevice_Release(This->parent);
784 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
785 HeapFree(GetProcessHeap(), 0, This);
787 return ref;
790 static void dump_fmt(const WAVEFORMATEX *fmt)
792 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
793 switch(fmt->wFormatTag) {
794 case WAVE_FORMAT_PCM:
795 TRACE("WAVE_FORMAT_PCM");
796 break;
797 case WAVE_FORMAT_IEEE_FLOAT:
798 TRACE("WAVE_FORMAT_IEEE_FLOAT");
799 break;
800 case WAVE_FORMAT_EXTENSIBLE:
801 TRACE("WAVE_FORMAT_EXTENSIBLE");
802 break;
803 default:
804 TRACE("Unknown");
805 break;
807 TRACE(")\n");
809 TRACE("nChannels: %u\n", fmt->nChannels);
810 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
811 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
812 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
813 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
814 TRACE("cbSize: %u\n", fmt->cbSize);
816 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
817 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
818 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
819 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
820 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
824 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
826 WAVEFORMATEX *ret;
827 size_t size;
829 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
830 size = sizeof(WAVEFORMATEXTENSIBLE);
831 else
832 size = sizeof(WAVEFORMATEX);
834 ret = CoTaskMemAlloc(size);
835 if (!ret)
836 return NULL;
838 memcpy(ret, fmt, size);
840 ret->cbSize = size - sizeof(WAVEFORMATEX);
842 return ret;
845 static DWORD get_channel_mask(unsigned int channels)
847 switch(channels) {
848 case 0:
849 return 0;
850 case 1:
851 return SPEAKER_FRONT_CENTER;
852 case 2:
853 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
854 case 3:
855 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
856 SPEAKER_LOW_FREQUENCY;
857 case 4:
858 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
859 SPEAKER_BACK_RIGHT;
860 case 5:
861 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
862 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
863 case 6:
864 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
865 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
866 case 7:
867 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
868 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
869 SPEAKER_BACK_CENTER;
870 case 8:
871 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
872 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
873 SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
875 FIXME("Unknown speaker configuration: %u\n", channels);
876 return 0;
879 static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
881 pa_channel_map_init(&This->map);
882 This->ss.rate = fmt->nSamplesPerSec;
883 This->ss.format = PA_SAMPLE_INVALID;
884 switch(fmt->wFormatTag) {
885 case WAVE_FORMAT_IEEE_FLOAT:
886 if (!fmt->nChannels || fmt->nChannels > 2 || fmt->wBitsPerSample != 32)
887 break;
888 This->ss.format = PA_SAMPLE_FLOAT32LE;
889 pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
890 break;
891 case WAVE_FORMAT_PCM:
892 if (!fmt->nChannels || fmt->nChannels > 2)
893 break;
894 if (fmt->wBitsPerSample == 8)
895 This->ss.format = PA_SAMPLE_U8;
896 else if (fmt->wBitsPerSample == 16)
897 This->ss.format = PA_SAMPLE_S16LE;
898 pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
899 break;
900 case WAVE_FORMAT_EXTENSIBLE: {
901 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)fmt;
902 DWORD mask = wfe->dwChannelMask;
903 DWORD i = 0, j;
904 if (fmt->cbSize != (sizeof(*wfe) - sizeof(*fmt)) && fmt->cbSize != sizeof(*wfe))
905 break;
906 if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
907 (!wfe->Samples.wValidBitsPerSample || wfe->Samples.wValidBitsPerSample == 32) &&
908 fmt->wBitsPerSample == 32)
909 This->ss.format = PA_SAMPLE_FLOAT32LE;
910 else if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
911 DWORD valid = wfe->Samples.wValidBitsPerSample;
912 if (!valid)
913 valid = fmt->wBitsPerSample;
914 if (!valid || valid > fmt->wBitsPerSample)
915 break;
916 switch (fmt->wBitsPerSample) {
917 case 8:
918 if (valid == 8)
919 This->ss.format = PA_SAMPLE_U8;
920 break;
921 case 16:
922 if (valid == 16)
923 This->ss.format = PA_SAMPLE_S16LE;
924 break;
925 case 24:
926 if (valid == 24)
927 This->ss.format = PA_SAMPLE_S24LE;
928 break;
929 case 32:
930 if (valid == 24)
931 This->ss.format = PA_SAMPLE_S24_32LE;
932 else if (valid == 32)
933 This->ss.format = PA_SAMPLE_S32LE;
934 default:
935 break;
938 This->map.channels = fmt->nChannels;
939 if (!mask)
940 mask = get_channel_mask(fmt->nChannels);
941 for (j = 0; j < sizeof(pulse_pos_from_wfx)/sizeof(*pulse_pos_from_wfx) && i < fmt->nChannels; ++j) {
942 if (mask & (1 << j))
943 This->map.map[i++] = pulse_pos_from_wfx[j];
946 /* Special case for mono since pulse appears to map it differently */
947 if (mask == SPEAKER_FRONT_CENTER)
948 This->map.map[0] = PA_CHANNEL_POSITION_MONO;
950 if ((mask & SPEAKER_ALL) && i < fmt->nChannels) {
951 This->map.map[i++] = PA_CHANNEL_POSITION_MONO;
952 FIXME("Is the 'all' channel mapped correctly?\n");
955 if (i < fmt->nChannels || (mask & SPEAKER_RESERVED)) {
956 This->map.channels = 0;
957 ERR("Invalid channel mask: %i/%i and %x\n", i, fmt->nChannels, mask);
958 break;
960 break;
962 default: FIXME("Unhandled tag %x\n", fmt->wFormatTag);
964 This->ss.channels = This->map.channels;
965 if (!pa_channel_map_valid(&This->map) || This->ss.format == PA_SAMPLE_INVALID) {
966 ERR("Invalid format! Channel spec valid: %i, format: %i\n", pa_channel_map_valid(&This->map), This->ss.format);
967 dump_fmt(fmt);
968 return AUDCLNT_E_UNSUPPORTED_FORMAT;
970 return S_OK;
973 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
974 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
975 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
976 const GUID *sessionguid)
978 ACImpl *This = impl_from_IAudioClient(iface);
979 HRESULT hr = S_OK;
980 UINT period_bytes;
982 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
983 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
985 if (!fmt)
986 return E_POINTER;
988 if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
989 return AUDCLNT_E_NOT_INITIALIZED;
990 if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
991 return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
993 if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
994 AUDCLNT_STREAMFLAGS_LOOPBACK |
995 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
996 AUDCLNT_STREAMFLAGS_NOPERSIST |
997 AUDCLNT_STREAMFLAGS_RATEADJUST |
998 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
999 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
1000 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)) {
1001 TRACE("Unknown flags: %08x\n", flags);
1002 return E_INVALIDARG;
1005 pthread_mutex_lock(&pulse_lock);
1006 if (This->stream) {
1007 pthread_mutex_unlock(&pulse_lock);
1008 return AUDCLNT_E_ALREADY_INITIALIZED;
1011 hr = pulse_spec_from_waveformat(This, fmt);
1012 if (FAILED(hr))
1013 goto exit;
1015 if (mode == AUDCLNT_SHAREMODE_SHARED) {
1016 period = pulse_def_period[This->dataflow == eCapture];
1017 if (duration < 2 * period)
1018 duration = 2 * period;
1020 period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000);
1022 if (duration < 20000000)
1023 This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
1024 else
1025 This->bufsize_frames = 2 * fmt->nSamplesPerSec;
1026 This->bufsize_bytes = This->bufsize_frames * pa_frame_size(&This->ss);
1028 This->share = mode;
1029 This->flags = flags;
1030 hr = pulse_stream_connect(This, period_bytes);
1031 if (SUCCEEDED(hr)) {
1032 UINT32 unalign;
1033 const pa_buffer_attr *attr = pa_stream_get_buffer_attr(This->stream);
1034 /* Update frames according to new size */
1035 dump_attr(attr);
1036 if (This->dataflow == eRender)
1037 This->bufsize_bytes = attr->tlength;
1038 else {
1039 This->capture_period = period_bytes = attr->fragsize;
1040 if ((unalign = This->bufsize_bytes % period_bytes))
1041 This->bufsize_bytes += period_bytes - unalign;
1043 This->bufsize_frames = This->bufsize_bytes / pa_frame_size(&This->ss);
1045 if (SUCCEEDED(hr)) {
1046 UINT32 i, capture_packets = This->capture_period ? This->bufsize_bytes / This->capture_period : 0;
1047 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_bytes + capture_packets * sizeof(ACPacket));
1048 if (!This->tmp_buffer)
1049 hr = E_OUTOFMEMORY;
1050 else {
1051 ACPacket *cur_packet = (ACPacket*)((char*)This->tmp_buffer + This->bufsize_bytes);
1052 BYTE *data = This->tmp_buffer;
1053 memset(This->tmp_buffer, This->ss.format == PA_SAMPLE_U8 ? 0x80 : 0, This->bufsize_bytes);
1054 list_init(&This->packet_free_head);
1055 list_init(&This->packet_filled_head);
1056 for (i = 0; i < capture_packets; ++i, ++cur_packet) {
1057 list_add_tail(&This->packet_free_head, &cur_packet->entry);
1058 cur_packet->data = data;
1059 data += This->capture_period;
1061 assert(!This->capture_period || This->bufsize_bytes == This->capture_period * capture_packets);
1062 assert(!capture_packets || data - This->bufsize_bytes == This->tmp_buffer);
1066 exit:
1067 if (FAILED(hr)) {
1068 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1069 This->tmp_buffer = NULL;
1070 if (This->stream) {
1071 pa_stream_disconnect(This->stream);
1072 pa_stream_unref(This->stream);
1073 This->stream = NULL;
1076 pthread_mutex_unlock(&pulse_lock);
1077 return hr;
1080 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1081 UINT32 *out)
1083 ACImpl *This = impl_from_IAudioClient(iface);
1084 HRESULT hr;
1086 TRACE("(%p)->(%p)\n", This, out);
1088 if (!out)
1089 return E_POINTER;
1091 pthread_mutex_lock(&pulse_lock);
1092 hr = pulse_stream_valid(This);
1093 if (SUCCEEDED(hr))
1094 *out = This->bufsize_frames;
1095 pthread_mutex_unlock(&pulse_lock);
1097 return hr;
1100 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1101 REFERENCE_TIME *latency)
1103 ACImpl *This = impl_from_IAudioClient(iface);
1104 const pa_buffer_attr *attr;
1105 REFERENCE_TIME lat;
1106 HRESULT hr;
1108 TRACE("(%p)->(%p)\n", This, latency);
1110 if (!latency)
1111 return E_POINTER;
1113 pthread_mutex_lock(&pulse_lock);
1114 hr = pulse_stream_valid(This);
1115 if (FAILED(hr)) {
1116 pthread_mutex_unlock(&pulse_lock);
1117 return hr;
1119 attr = pa_stream_get_buffer_attr(This->stream);
1120 if (This->dataflow == eRender)
1121 lat = attr->minreq / pa_frame_size(&This->ss);
1122 else
1123 lat = attr->fragsize / pa_frame_size(&This->ss);
1124 *latency = 10000000;
1125 *latency *= lat;
1126 *latency /= This->ss.rate;
1127 pthread_mutex_unlock(&pulse_lock);
1128 TRACE("Latency: %u ms\n", (DWORD)(*latency / 10000));
1129 return S_OK;
1132 static void ACImpl_GetRenderPad(ACImpl *This, UINT32 *out)
1134 *out = This->pad / pa_frame_size(&This->ss);
1137 static void ACImpl_GetCapturePad(ACImpl *This, UINT32 *out)
1139 ACPacket *packet = This->locked_ptr;
1140 if (!packet && !list_empty(&This->packet_filled_head)) {
1141 packet = (ACPacket*)list_head(&This->packet_filled_head);
1142 This->locked_ptr = packet;
1143 list_remove(&packet->entry);
1145 if (out)
1146 *out = This->pad / pa_frame_size(&This->ss);
1149 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1150 UINT32 *out)
1152 ACImpl *This = impl_from_IAudioClient(iface);
1153 HRESULT hr;
1155 TRACE("(%p)->(%p)\n", This, out);
1157 if (!out)
1158 return E_POINTER;
1160 pthread_mutex_lock(&pulse_lock);
1161 hr = pulse_stream_valid(This);
1162 if (FAILED(hr)) {
1163 pthread_mutex_unlock(&pulse_lock);
1164 return hr;
1167 if (This->dataflow == eRender)
1168 ACImpl_GetRenderPad(This, out);
1169 else
1170 ACImpl_GetCapturePad(This, out);
1171 pthread_mutex_unlock(&pulse_lock);
1173 TRACE("%p Pad: %u ms (%u)\n", This, MulDiv(*out, 1000, This->ss.rate), *out);
1174 return S_OK;
1177 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1178 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
1179 WAVEFORMATEX **out)
1181 ACImpl *This = impl_from_IAudioClient(iface);
1182 HRESULT hr = S_OK;
1183 WAVEFORMATEX *closest = NULL;
1185 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
1187 if (!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
1188 return E_POINTER;
1190 if (out)
1191 *out = NULL;
1192 if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1193 return E_INVALIDARG;
1194 if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1195 return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
1196 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1197 fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1198 return E_INVALIDARG;
1200 dump_fmt(fmt);
1202 closest = clone_format(fmt);
1203 if (!closest)
1204 hr = E_OUTOFMEMORY;
1206 if (hr == S_OK || !out) {
1207 CoTaskMemFree(closest);
1208 if (out)
1209 *out = NULL;
1210 } else if (closest) {
1211 closest->nBlockAlign =
1212 closest->nChannels * closest->wBitsPerSample / 8;
1213 closest->nAvgBytesPerSec =
1214 closest->nBlockAlign * closest->nSamplesPerSec;
1215 *out = closest;
1218 TRACE("returning: %08x %p\n", hr, out ? *out : NULL);
1219 return hr;
1222 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1223 WAVEFORMATEX **pwfx)
1225 ACImpl *This = impl_from_IAudioClient(iface);
1226 WAVEFORMATEXTENSIBLE *fmt = &pulse_fmt[This->dataflow == eCapture];
1228 TRACE("(%p)->(%p)\n", This, pwfx);
1230 if (!pwfx)
1231 return E_POINTER;
1233 *pwfx = clone_format(&fmt->Format);
1234 if (!*pwfx)
1235 return E_OUTOFMEMORY;
1236 dump_fmt(*pwfx);
1237 return S_OK;
1240 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1241 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1243 ACImpl *This = impl_from_IAudioClient(iface);
1245 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1247 if (!defperiod && !minperiod)
1248 return E_POINTER;
1250 if (defperiod)
1251 *defperiod = pulse_def_period[This->dataflow == eCapture];
1252 if (minperiod)
1253 *minperiod = pulse_min_period[This->dataflow == eCapture];
1255 return S_OK;
1258 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1260 ACImpl *This = impl_from_IAudioClient(iface);
1261 HRESULT hr = S_OK;
1262 int success;
1263 pa_operation *o;
1265 TRACE("(%p)\n", This);
1267 pthread_mutex_lock(&pulse_lock);
1268 hr = pulse_stream_valid(This);
1269 if (FAILED(hr)) {
1270 pthread_mutex_unlock(&pulse_lock);
1271 return hr;
1274 if ((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event) {
1275 pthread_mutex_unlock(&pulse_lock);
1276 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1279 if (This->started) {
1280 pthread_mutex_unlock(&pulse_lock);
1281 return AUDCLNT_E_NOT_STOPPED;
1283 This->clock_pulse = PA_USEC_INVALID;
1285 if (pa_stream_is_corked(This->stream)) {
1286 o = pa_stream_cork(This->stream, 0, pulse_op_cb, &success);
1287 if (o) {
1288 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1289 pthread_cond_wait(&pulse_cond, &pulse_lock);
1290 pa_operation_unref(o);
1291 } else
1292 success = 0;
1293 if (!success)
1294 hr = E_FAIL;
1296 if (SUCCEEDED(hr)) {
1297 This->started = TRUE;
1298 if (This->dataflow == eRender && This->event)
1299 pa_stream_set_latency_update_callback(This->stream, pulse_latency_callback, This);
1301 pthread_mutex_unlock(&pulse_lock);
1302 return hr;
1305 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1307 ACImpl *This = impl_from_IAudioClient(iface);
1308 HRESULT hr = S_OK;
1309 pa_operation *o;
1310 int success;
1312 TRACE("(%p)\n", This);
1314 pthread_mutex_lock(&pulse_lock);
1315 hr = pulse_stream_valid(This);
1316 if (FAILED(hr)) {
1317 pthread_mutex_unlock(&pulse_lock);
1318 return hr;
1321 if (!This->started) {
1322 pthread_mutex_unlock(&pulse_lock);
1323 return S_FALSE;
1326 if (This->dataflow == eRender) {
1327 o = pa_stream_cork(This->stream, 1, pulse_op_cb, &success);
1328 if (o) {
1329 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1330 pthread_cond_wait(&pulse_cond, &pulse_lock);
1331 pa_operation_unref(o);
1332 } else
1333 success = 0;
1334 if (!success)
1335 hr = E_FAIL;
1337 if (SUCCEEDED(hr)) {
1338 This->started = FALSE;
1339 This->clock_pulse = PA_USEC_INVALID;
1341 pthread_mutex_unlock(&pulse_lock);
1342 return hr;
1345 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1347 ACImpl *This = impl_from_IAudioClient(iface);
1348 HRESULT hr = S_OK;
1350 TRACE("(%p)\n", This);
1352 pthread_mutex_lock(&pulse_lock);
1353 hr = pulse_stream_valid(This);
1354 if (FAILED(hr)) {
1355 pthread_mutex_unlock(&pulse_lock);
1356 return hr;
1359 if (This->started) {
1360 pthread_mutex_unlock(&pulse_lock);
1361 return AUDCLNT_E_NOT_STOPPED;
1364 if (This->locked) {
1365 pthread_mutex_unlock(&pulse_lock);
1366 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1369 if (This->dataflow == eRender) {
1370 /* If there is still data in the render buffer it needs to be removed from the server */
1371 int success = 0;
1372 if (This->pad) {
1373 pa_operation *o = pa_stream_flush(This->stream, pulse_op_cb, &success);
1374 if (o) {
1375 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1376 pthread_cond_wait(&pulse_cond, &pulse_lock);
1377 pa_operation_unref(o);
1380 if (success || !This->pad)
1381 This->clock_lastpos = This->clock_written = This->pad = 0;
1382 } else {
1383 ACPacket *p;
1384 This->clock_written += This->pad;
1385 This->pad = 0;
1387 if ((p = This->locked_ptr)) {
1388 This->locked_ptr = NULL;
1389 list_add_tail(&This->packet_free_head, &p->entry);
1391 list_move_tail(&This->packet_free_head, &This->packet_filled_head);
1393 pthread_mutex_unlock(&pulse_lock);
1395 return hr;
1398 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1399 HANDLE event)
1401 ACImpl *This = impl_from_IAudioClient(iface);
1402 HRESULT hr;
1404 TRACE("(%p)->(%p)\n", This, event);
1406 if (!event)
1407 return E_INVALIDARG;
1409 pthread_mutex_lock(&pulse_lock);
1410 hr = pulse_stream_valid(This);
1411 if (FAILED(hr)) {
1412 pthread_mutex_unlock(&pulse_lock);
1413 return hr;
1416 if (!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1417 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1418 else if (This->event)
1419 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1420 else
1421 This->event = event;
1422 pthread_mutex_unlock(&pulse_lock);
1423 return hr;
1426 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1427 void **ppv)
1429 ACImpl *This = impl_from_IAudioClient(iface);
1430 HRESULT hr;
1432 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1434 if (!ppv)
1435 return E_POINTER;
1436 *ppv = NULL;
1438 pthread_mutex_lock(&pulse_lock);
1439 hr = pulse_stream_valid(This);
1440 pthread_mutex_unlock(&pulse_lock);
1441 if (FAILED(hr))
1442 return hr;
1444 if (IsEqualIID(riid, &IID_IAudioRenderClient)) {
1445 if (This->dataflow != eRender)
1446 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1447 *ppv = &This->IAudioRenderClient_iface;
1448 } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) {
1449 if (This->dataflow != eCapture)
1450 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1451 *ppv = &This->IAudioCaptureClient_iface;
1454 if (*ppv) {
1455 IUnknown_AddRef((IUnknown*)*ppv);
1456 return S_OK;
1459 FIXME("stub %s\n", debugstr_guid(riid));
1460 return E_NOINTERFACE;
1463 static const IAudioClientVtbl AudioClient_Vtbl =
1465 AudioClient_QueryInterface,
1466 AudioClient_AddRef,
1467 AudioClient_Release,
1468 AudioClient_Initialize,
1469 AudioClient_GetBufferSize,
1470 AudioClient_GetStreamLatency,
1471 AudioClient_GetCurrentPadding,
1472 AudioClient_IsFormatSupported,
1473 AudioClient_GetMixFormat,
1474 AudioClient_GetDevicePeriod,
1475 AudioClient_Start,
1476 AudioClient_Stop,
1477 AudioClient_Reset,
1478 AudioClient_SetEventHandle,
1479 AudioClient_GetService
1482 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1483 IAudioRenderClient *iface, REFIID riid, void **ppv)
1485 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1487 if (!ppv)
1488 return E_POINTER;
1489 *ppv = NULL;
1491 if (IsEqualIID(riid, &IID_IUnknown) ||
1492 IsEqualIID(riid, &IID_IAudioRenderClient))
1493 *ppv = iface;
1494 if (*ppv) {
1495 IUnknown_AddRef((IUnknown*)*ppv);
1496 return S_OK;
1499 WARN("Unknown interface %s\n", debugstr_guid(riid));
1500 return E_NOINTERFACE;
1503 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1505 ACImpl *This = impl_from_IAudioRenderClient(iface);
1506 return AudioClient_AddRef(&This->IAudioClient_iface);
1509 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1511 ACImpl *This = impl_from_IAudioRenderClient(iface);
1512 return AudioClient_Release(&This->IAudioClient_iface);
1515 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1516 UINT32 frames, BYTE **data)
1518 ACImpl *This = impl_from_IAudioRenderClient(iface);
1519 UINT32 avail, pad, req, bytes = frames * pa_frame_size(&This->ss);
1520 HRESULT hr = S_OK;
1521 int ret = -1;
1523 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1525 if (!data)
1526 return E_POINTER;
1527 *data = NULL;
1529 pthread_mutex_lock(&pulse_lock);
1530 hr = pulse_stream_valid(This);
1531 if (FAILED(hr) || This->locked) {
1532 pthread_mutex_unlock(&pulse_lock);
1533 return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
1535 if (!frames) {
1536 pthread_mutex_unlock(&pulse_lock);
1537 return S_OK;
1540 ACImpl_GetRenderPad(This, &pad);
1541 avail = This->bufsize_frames - pad;
1542 if (avail < frames || bytes > This->bufsize_bytes) {
1543 pthread_mutex_unlock(&pulse_lock);
1544 WARN("Wanted to write %u, but only %u available\n", frames, avail);
1545 return AUDCLNT_E_BUFFER_TOO_LARGE;
1548 This->locked = frames;
1549 req = bytes;
1550 ret = pa_stream_begin_write(This->stream, &This->locked_ptr, &req);
1551 if (ret < 0 || req < bytes) {
1552 FIXME("%p Not using pulse locked data: %i %u/%u %u/%u\n", This, ret, req/pa_frame_size(&This->ss), frames, pad, This->bufsize_frames);
1553 if (ret >= 0)
1554 pa_stream_cancel_write(This->stream);
1555 *data = This->tmp_buffer;
1556 This->locked_ptr = NULL;
1557 } else
1558 *data = This->locked_ptr;
1559 pthread_mutex_unlock(&pulse_lock);
1560 return hr;
1563 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1564 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1566 ACImpl *This = impl_from_IAudioRenderClient(iface);
1567 UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
1569 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1571 pthread_mutex_lock(&pulse_lock);
1572 if (!This->locked || !written_frames) {
1573 if (This->locked_ptr)
1574 pa_stream_cancel_write(This->stream);
1575 This->locked = 0;
1576 This->locked_ptr = NULL;
1577 pthread_mutex_unlock(&pulse_lock);
1578 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1581 if (This->locked < written_frames) {
1582 pthread_mutex_unlock(&pulse_lock);
1583 return AUDCLNT_E_INVALID_SIZE;
1586 if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
1587 if (This->ss.format == PA_SAMPLE_U8)
1588 memset(This->tmp_buffer, 128, written_bytes);
1589 else
1590 memset(This->tmp_buffer, 0, written_bytes);
1593 This->locked = 0;
1594 if (This->locked_ptr)
1595 pa_stream_write(This->stream, This->locked_ptr, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
1596 else
1597 pa_stream_write(This->stream, This->tmp_buffer, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
1598 This->pad += written_bytes;
1599 This->locked_ptr = NULL;
1600 TRACE("Released %u, pad %u\n", written_frames, This->pad / pa_frame_size(&This->ss));
1601 assert(This->pad <= This->bufsize_bytes);
1602 pthread_mutex_unlock(&pulse_lock);
1603 return S_OK;
1606 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1607 AudioRenderClient_QueryInterface,
1608 AudioRenderClient_AddRef,
1609 AudioRenderClient_Release,
1610 AudioRenderClient_GetBuffer,
1611 AudioRenderClient_ReleaseBuffer
1614 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1615 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1617 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1619 if (!ppv)
1620 return E_POINTER;
1621 *ppv = NULL;
1623 if (IsEqualIID(riid, &IID_IUnknown) ||
1624 IsEqualIID(riid, &IID_IAudioCaptureClient))
1625 *ppv = iface;
1626 if (*ppv) {
1627 IUnknown_AddRef((IUnknown*)*ppv);
1628 return S_OK;
1631 WARN("Unknown interface %s\n", debugstr_guid(riid));
1632 return E_NOINTERFACE;
1635 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1637 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1638 return IAudioClient_AddRef(&This->IAudioClient_iface);
1641 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1643 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1644 return IAudioClient_Release(&This->IAudioClient_iface);
1647 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1648 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1649 UINT64 *qpcpos)
1651 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1652 HRESULT hr;
1653 ACPacket *packet;
1655 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1656 devpos, qpcpos);
1658 if (!data || !frames || !flags)
1659 return E_POINTER;
1661 pthread_mutex_lock(&pulse_lock);
1662 hr = pulse_stream_valid(This);
1663 if (FAILED(hr) || This->locked) {
1664 pthread_mutex_unlock(&pulse_lock);
1665 return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
1668 ACImpl_GetCapturePad(This, NULL);
1669 if ((packet = This->locked_ptr)) {
1670 *frames = This->capture_period / pa_frame_size(&This->ss);
1671 *flags = 0;
1672 if (packet->discont)
1673 *flags |= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY;
1674 if (devpos) {
1675 if (packet->discont)
1676 *devpos = (This->clock_written + This->capture_period) / pa_frame_size(&This->ss);
1677 else
1678 *devpos = This->clock_written / pa_frame_size(&This->ss);
1680 if (qpcpos)
1681 *qpcpos = packet->qpcpos;
1682 *data = packet->data;
1684 else
1685 *frames = 0;
1686 This->locked = *frames;
1687 pthread_mutex_unlock(&pulse_lock);
1688 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1691 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1692 IAudioCaptureClient *iface, UINT32 done)
1694 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1696 TRACE("(%p)->(%u)\n", This, done);
1698 pthread_mutex_lock(&pulse_lock);
1699 if (!This->locked && done) {
1700 pthread_mutex_unlock(&pulse_lock);
1701 return AUDCLNT_E_OUT_OF_ORDER;
1703 if (done && This->locked != done) {
1704 pthread_mutex_unlock(&pulse_lock);
1705 return AUDCLNT_E_INVALID_SIZE;
1707 if (done) {
1708 ACPacket *packet = This->locked_ptr;
1709 This->locked_ptr = NULL;
1710 This->pad -= This->capture_period;
1711 if (packet->discont)
1712 This->clock_written += 2 * This->capture_period;
1713 else
1714 This->clock_written += This->capture_period;
1715 list_add_tail(&This->packet_free_head, &packet->entry);
1717 This->locked = 0;
1718 pthread_mutex_unlock(&pulse_lock);
1719 return S_OK;
1722 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1723 IAudioCaptureClient *iface, UINT32 *frames)
1725 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1726 ACPacket *p;
1728 TRACE("(%p)->(%p)\n", This, frames);
1729 if (!frames)
1730 return E_POINTER;
1732 pthread_mutex_lock(&pulse_lock);
1733 ACImpl_GetCapturePad(This, NULL);
1734 p = This->locked_ptr;
1735 if (p)
1736 *frames = This->capture_period / pa_frame_size(&This->ss);
1737 else
1738 *frames = 0;
1739 pthread_mutex_unlock(&pulse_lock);
1740 return S_OK;
1743 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1745 AudioCaptureClient_QueryInterface,
1746 AudioCaptureClient_AddRef,
1747 AudioCaptureClient_Release,
1748 AudioCaptureClient_GetBuffer,
1749 AudioCaptureClient_ReleaseBuffer,
1750 AudioCaptureClient_GetNextPacketSize
1753 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
1754 IAudioSessionManager2 **out)
1756 *out = NULL;
1757 return E_NOTIMPL;