winepulse: Add IAudioClock and IAudioClock2
[wine/multimedia.git] / dlls / winepulse.drv / mmdevdrv.c
blob3ed22886dbdf6184f6ba72f20eeb41fade2678d6
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 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
172 return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
175 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
177 return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
180 /* Following pulseaudio design here, mainloop has the lock taken whenever
181 * it is handling something for pulse, and the lock is required whenever
182 * doing any pa_* call that can affect the state in any way
184 * pa_cond_wait is used when waiting on results, because the mainloop needs
185 * the same lock taken to affect the state
187 * This is basically the same as the pa_threaded_mainloop implementation,
188 * but that cannot be used because it uses pthread_create directly
190 * pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock
191 * pa_threaded_mainloop_signal -> pthread_cond_signal
192 * pa_threaded_mainloop_wait -> pthread_cond_wait
195 static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
196 int r;
197 pthread_mutex_unlock(&pulse_lock);
198 r = poll(ufds, nfds, timeout);
199 pthread_mutex_lock(&pulse_lock);
200 return r;
203 static DWORD CALLBACK pulse_mainloop_thread(void *tmp) {
204 int ret;
205 pulse_ml = pa_mainloop_new();
206 pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL);
207 pthread_mutex_lock(&pulse_lock);
208 pthread_cond_signal(&pulse_cond);
209 pa_mainloop_run(pulse_ml, &ret);
210 pthread_mutex_unlock(&pulse_lock);
211 pa_mainloop_free(pulse_ml);
212 CloseHandle(pulse_thread);
213 return ret;
216 static void pulse_contextcallback(pa_context *c, void *userdata);
217 static void pulse_stream_state(pa_stream *s, void *user);
219 static const enum pa_channel_position pulse_pos_from_wfx[] = {
220 PA_CHANNEL_POSITION_FRONT_LEFT,
221 PA_CHANNEL_POSITION_FRONT_RIGHT,
222 PA_CHANNEL_POSITION_FRONT_CENTER,
223 PA_CHANNEL_POSITION_LFE,
224 PA_CHANNEL_POSITION_REAR_LEFT,
225 PA_CHANNEL_POSITION_REAR_RIGHT,
226 PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
227 PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
228 PA_CHANNEL_POSITION_REAR_CENTER,
229 PA_CHANNEL_POSITION_SIDE_LEFT,
230 PA_CHANNEL_POSITION_SIDE_RIGHT,
231 PA_CHANNEL_POSITION_TOP_CENTER,
232 PA_CHANNEL_POSITION_TOP_FRONT_LEFT,
233 PA_CHANNEL_POSITION_TOP_FRONT_CENTER,
234 PA_CHANNEL_POSITION_TOP_FRONT_RIGHT,
235 PA_CHANNEL_POSITION_TOP_REAR_LEFT,
236 PA_CHANNEL_POSITION_TOP_REAR_CENTER,
237 PA_CHANNEL_POSITION_TOP_REAR_RIGHT
240 static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
241 WAVEFORMATEX *wfx = &fmt->Format;
242 pa_stream *stream;
243 pa_channel_map map;
244 pa_sample_spec ss;
245 pa_buffer_attr attr;
246 int ret, i;
247 unsigned int length = 0;
249 pa_channel_map_init_auto(&map, 2, PA_CHANNEL_MAP_ALSA);
250 ss.rate = 48000;
251 ss.format = PA_SAMPLE_FLOAT32LE;
252 ss.channels = map.channels;
254 attr.maxlength = -1;
255 attr.tlength = -1;
256 attr.minreq = attr.fragsize = pa_frame_size(&ss);
257 attr.prebuf = 0;
259 stream = pa_stream_new(pulse_ctx, "format test stream", &ss, &map);
260 if (stream)
261 pa_stream_set_state_callback(stream, pulse_stream_state, NULL);
262 if (!stream)
263 ret = -1;
264 else if (render)
265 ret = pa_stream_connect_playback(stream, NULL, &attr,
266 PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
267 else
268 ret = pa_stream_connect_record(stream, NULL, &attr, PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS);
269 if (ret >= 0) {
270 while (pa_stream_get_state(stream) == PA_STREAM_CREATING)
271 pthread_cond_wait(&pulse_cond, &pulse_lock);
272 if (pa_stream_get_state(stream) == PA_STREAM_READY) {
273 ss = *pa_stream_get_sample_spec(stream);
274 map = *pa_stream_get_channel_map(stream);
275 if (render)
276 length = pa_stream_get_buffer_attr(stream)->minreq;
277 else
278 length = pa_stream_get_buffer_attr(stream)->fragsize;
279 pa_stream_disconnect(stream);
280 while (pa_stream_get_state(stream) == PA_STREAM_READY)
281 pthread_cond_wait(&pulse_cond, &pulse_lock);
284 if (stream)
285 pa_stream_unref(stream);
286 if (length)
287 pulse_def_period[!render] = pulse_min_period[!render] = pa_bytes_to_usec(10 * length, &ss);
288 else
289 pulse_min_period[!render] = MinimumPeriod;
290 if (pulse_def_period[!render] <= DefaultPeriod)
291 pulse_def_period[!render] = DefaultPeriod;
293 wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
294 wfx->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
295 wfx->nChannels = ss.channels;
296 wfx->wBitsPerSample = 8 * pa_sample_size_of_format(ss.format);
297 wfx->nSamplesPerSec = ss.rate;
298 wfx->nBlockAlign = pa_frame_size(&ss);
299 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
300 if (ss.format != PA_SAMPLE_S24_32LE)
301 fmt->Samples.wValidBitsPerSample = wfx->wBitsPerSample;
302 else
303 fmt->Samples.wValidBitsPerSample = 24;
304 if (ss.format == PA_SAMPLE_FLOAT32LE)
305 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
306 else
307 fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
309 fmt->dwChannelMask = 0;
310 for (i = 0; i < map.channels; ++i)
311 switch (map.map[i]) {
312 default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map.map[i])); break;
313 case PA_CHANNEL_POSITION_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_FRONT_LEFT; break;
314 case PA_CHANNEL_POSITION_MONO:
315 case PA_CHANNEL_POSITION_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_FRONT_CENTER; break;
316 case PA_CHANNEL_POSITION_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_FRONT_RIGHT; break;
317 case PA_CHANNEL_POSITION_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_BACK_LEFT; break;
318 case PA_CHANNEL_POSITION_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_BACK_CENTER; break;
319 case PA_CHANNEL_POSITION_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_BACK_RIGHT; break;
320 case PA_CHANNEL_POSITION_LFE: fmt->dwChannelMask |= SPEAKER_LOW_FREQUENCY; break;
321 case PA_CHANNEL_POSITION_SIDE_LEFT: fmt->dwChannelMask |= SPEAKER_SIDE_LEFT; break;
322 case PA_CHANNEL_POSITION_SIDE_RIGHT: fmt->dwChannelMask |= SPEAKER_SIDE_RIGHT; break;
323 case PA_CHANNEL_POSITION_TOP_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_CENTER; break;
324 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_LEFT; break;
325 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_CENTER; break;
326 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_RIGHT; break;
327 case PA_CHANNEL_POSITION_TOP_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_LEFT; break;
328 case PA_CHANNEL_POSITION_TOP_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_BACK_CENTER; break;
329 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_RIGHT; break;
333 static HRESULT pulse_connect(void)
335 int len;
336 WCHAR path[PATH_MAX], *name;
337 char *str;
339 if (!pulse_thread)
341 if (!(pulse_thread = CreateThread(NULL, 0, pulse_mainloop_thread, NULL, 0, NULL)))
343 ERR("Failed to create mainloop thread.");
344 return E_FAIL;
346 SetThreadPriority(pulse_thread, THREAD_PRIORITY_TIME_CRITICAL);
347 pthread_cond_wait(&pulse_cond, &pulse_lock);
350 if (pulse_ctx && PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx)))
351 return S_OK;
352 if (pulse_ctx)
353 pa_context_unref(pulse_ctx);
355 GetModuleFileNameW(NULL, path, sizeof(path)/sizeof(*path));
356 name = strrchrW(path, '\\');
357 if (!name)
358 name = path;
359 else
360 name++;
361 len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
362 str = pa_xmalloc(len);
363 WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL);
364 TRACE("Name: %s\n", str);
365 pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str);
366 pa_xfree(str);
367 if (!pulse_ctx) {
368 ERR("Failed to create context\n");
369 return E_FAIL;
372 pa_context_set_state_callback(pulse_ctx, pulse_contextcallback, NULL);
374 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx), PA_API_VERSION);
375 if (pa_context_connect(pulse_ctx, NULL, 0, NULL) < 0)
376 goto fail;
378 /* Wait for connection */
379 while (pthread_cond_wait(&pulse_cond, &pulse_lock)) {
380 pa_context_state_t state = pa_context_get_state(pulse_ctx);
382 if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
383 goto fail;
385 if (state == PA_CONTEXT_READY)
386 break;
389 TRACE("Connected to server %s with protocol version: %i.\n",
390 pa_context_get_server(pulse_ctx),
391 pa_context_get_server_protocol_version(pulse_ctx));
392 pulse_probe_settings(1, &pulse_fmt[0]);
393 pulse_probe_settings(0, &pulse_fmt[1]);
394 return S_OK;
396 fail:
397 pa_context_unref(pulse_ctx);
398 pulse_ctx = NULL;
399 return E_FAIL;
402 static void pulse_contextcallback(pa_context *c, void *userdata) {
403 switch (pa_context_get_state(c)) {
404 default:
405 FIXME("Unhandled state: %i\n", pa_context_get_state(c));
406 case PA_CONTEXT_CONNECTING:
407 case PA_CONTEXT_UNCONNECTED:
408 case PA_CONTEXT_AUTHORIZING:
409 case PA_CONTEXT_SETTING_NAME:
410 case PA_CONTEXT_TERMINATED:
411 TRACE("State change to %i\n", pa_context_get_state(c));
412 return;
414 case PA_CONTEXT_READY:
415 TRACE("Ready\n");
416 break;
418 case PA_CONTEXT_FAILED:
419 ERR("Context failed: %s\n", pa_strerror(pa_context_errno(c)));
420 break;
422 pthread_cond_signal(&pulse_cond);
425 static HRESULT pulse_stream_valid(ACImpl *This) {
426 if (!This->stream)
427 return AUDCLNT_E_NOT_INITIALIZED;
428 if (!This->stream || pa_stream_get_state(This->stream) != PA_STREAM_READY)
429 return AUDCLNT_E_DEVICE_INVALIDATED;
430 return S_OK;
433 static void dump_attr(const pa_buffer_attr *attr) {
434 TRACE("maxlength: %u\n", attr->maxlength);
435 TRACE("minreq: %u\n", attr->minreq);
436 TRACE("fragsize: %u\n", attr->fragsize);
437 TRACE("tlength: %u\n", attr->tlength);
438 TRACE("prebuf: %u\n", attr->prebuf);
441 static void pulse_op_cb(pa_stream *s, int success, void *user) {
442 TRACE("Success: %i\n", success);
443 *(int*)user = success;
444 pthread_cond_signal(&pulse_cond);
447 static void pulse_attr_update(pa_stream *s, void *user) {
448 const pa_buffer_attr *attr = pa_stream_get_buffer_attr(s);
449 TRACE("New attributes or device moved:\n");
450 dump_attr(attr);
453 static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata)
455 ACImpl *This = userdata;
456 pa_usec_t time;
457 UINT32 oldpad = This->pad;
459 if (bytes < This->bufsize_bytes)
460 This->pad = This->bufsize_bytes - bytes;
461 else
462 This->pad = 0;
464 assert(oldpad >= This->pad);
466 if (0 && This->pad && pa_stream_get_time(This->stream, &time) >= 0)
467 This->clock_pulse = time;
468 else
469 This->clock_pulse = PA_USEC_INVALID;
471 This->clock_written += oldpad - This->pad;
472 TRACE("New pad: %u (-%u)\n", This->pad / pa_frame_size(&This->ss), (oldpad - This->pad) / pa_frame_size(&This->ss));
474 if (This->event)
475 SetEvent(This->event);
478 static void pulse_underflow_callback(pa_stream *s, void *userdata)
480 ACImpl *This = userdata;
481 This->clock_pulse = PA_USEC_INVALID;
482 WARN("Underflow\n");
485 /* Latency is periodically updated even when nothing is played,
486 * because of PA_STREAM_AUTO_TIMING_UPDATE so use it as timer
488 * Perfect for passing all tests :)
490 static void pulse_latency_callback(pa_stream *s, void *userdata)
492 ACImpl *This = userdata;
493 if (!This->pad && This->event)
494 SetEvent(This->event);
497 static void pulse_started_callback(pa_stream *s, void *userdata)
499 ACImpl *This = userdata;
500 pa_usec_t time;
502 TRACE("(Re)started playing\n");
503 assert(This->clock_pulse == PA_USEC_INVALID);
504 if (0 && pa_stream_get_time(This->stream, &time) >= 0)
505 This->clock_pulse = time;
506 if (This->event)
507 SetEvent(This->event);
510 static void pulse_rd_loop(ACImpl *This, size_t bytes)
512 while (bytes >= This->capture_period) {
513 ACPacket *p, *next;
514 LARGE_INTEGER stamp, freq;
515 BYTE *dst, *src;
516 UINT32 src_len, copy, rem = This->capture_period;
517 if (!(p = (ACPacket*)list_head(&This->packet_free_head))) {
518 p = (ACPacket*)list_head(&This->packet_filled_head);
519 if (!p->discont) {
520 next = (ACPacket*)p->entry.next;
521 next->discont = 1;
522 } else
523 p = (ACPacket*)list_tail(&This->packet_filled_head);
524 assert(This->pad == This->bufsize_bytes);
525 } else {
526 assert(This->pad < This->bufsize_bytes);
527 This->pad += This->capture_period;
528 assert(This->pad <= This->bufsize_bytes);
530 QueryPerformanceCounter(&stamp);
531 QueryPerformanceFrequency(&freq);
532 p->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
533 p->discont = 0;
534 list_remove(&p->entry);
535 list_add_tail(&This->packet_filled_head, &p->entry);
537 dst = p->data;
538 while (rem) {
539 pa_stream_peek(This->stream, (const void**)&src, &src_len);
540 assert(src_len && src_len <= bytes);
541 assert(This->peek_ofs < src_len);
542 src += This->peek_ofs;
543 src_len -= This->peek_ofs;
545 copy = rem;
546 if (copy > src_len)
547 copy = src_len;
548 memcpy(dst, src, rem);
549 src += copy;
550 src_len -= copy;
551 dst += copy;
552 rem -= copy;
554 if (!src_len) {
555 This->peek_ofs = 0;
556 pa_stream_drop(This->stream);
557 } else
558 This->peek_ofs += copy;
560 bytes -= This->capture_period;
564 static void pulse_rd_drop(ACImpl *This, size_t bytes)
566 while (bytes >= This->capture_period) {
567 UINT32 src_len, copy, rem = This->capture_period;
568 while (rem) {
569 const void *src;
570 pa_stream_peek(This->stream, &src, &src_len);
571 assert(src_len && src_len <= bytes);
572 assert(This->peek_ofs < src_len);
573 src_len -= This->peek_ofs;
575 copy = rem;
576 if (copy > src_len)
577 copy = src_len;
579 src_len -= copy;
580 rem -= copy;
582 if (!src_len) {
583 This->peek_ofs = 0;
584 pa_stream_drop(This->stream);
585 } else
586 This->peek_ofs += copy;
587 bytes -= copy;
592 static void pulse_rd_callback(pa_stream *s, size_t bytes, void *userdata)
594 ACImpl *This = userdata;
596 TRACE("Readable total: %u, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(s)->fragsize);
597 assert(bytes >= This->peek_ofs);
598 bytes -= This->peek_ofs;
599 if (bytes < This->capture_period)
600 return;
602 if (This->started)
603 pulse_rd_loop(This, bytes);
604 else
605 pulse_rd_drop(This, bytes);
607 if (This->event)
608 SetEvent(This->event);
611 static void pulse_stream_state(pa_stream *s, void *user)
613 pa_stream_state_t state = pa_stream_get_state(s);
614 TRACE("Stream state changed to %i\n", state);
615 pthread_cond_signal(&pulse_cond);
618 static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
619 int ret;
620 char buffer[64];
621 static LONG number;
622 pa_buffer_attr attr;
623 if (This->stream) {
624 pa_stream_disconnect(This->stream);
625 while (pa_stream_get_state(This->stream) == PA_STREAM_READY)
626 pthread_cond_wait(&pulse_cond, &pulse_lock);
627 pa_stream_unref(This->stream);
629 ret = InterlockedIncrement(&number);
630 sprintf(buffer, "audio stream #%i", ret);
631 This->stream = pa_stream_new(pulse_ctx, buffer, &This->ss, &This->map);
632 pa_stream_set_state_callback(This->stream, pulse_stream_state, This);
633 pa_stream_set_buffer_attr_callback(This->stream, pulse_attr_update, This);
634 pa_stream_set_moved_callback(This->stream, pulse_attr_update, This);
636 /* Pulseaudio will fill in correct values */
637 attr.minreq = attr.fragsize = period_bytes;
638 attr.maxlength = attr.tlength = This->bufsize_bytes;
639 attr.prebuf = pa_frame_size(&This->ss);
640 dump_attr(&attr);
641 if (This->dataflow == eRender)
642 ret = pa_stream_connect_playback(This->stream, NULL, &attr,
643 PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
644 else
645 ret = pa_stream_connect_record(This->stream, NULL, &attr,
646 PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS);
647 if (ret < 0) {
648 WARN("Returns %i\n", ret);
649 return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
651 while (pa_stream_get_state(This->stream) == PA_STREAM_CREATING)
652 pthread_cond_wait(&pulse_cond, &pulse_lock);
653 if (pa_stream_get_state(This->stream) != PA_STREAM_READY)
654 return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
656 if (This->dataflow == eRender) {
657 pa_stream_set_write_callback(This->stream, pulse_wr_callback, This);
658 pa_stream_set_underflow_callback(This->stream, pulse_underflow_callback, This);
659 pa_stream_set_started_callback(This->stream, pulse_started_callback, This);
660 } else
661 pa_stream_set_read_callback(This->stream, pulse_rd_callback, This);
662 return S_OK;
665 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
666 UINT *num, UINT *def_index)
668 HRESULT hr = S_OK;
669 TRACE("%d %p %p %p\n", flow, ids, num, def_index);
671 pthread_mutex_lock(&pulse_lock);
672 hr = pulse_connect();
673 pthread_mutex_unlock(&pulse_lock);
674 if (FAILED(hr))
675 return hr;
676 *num = 1;
677 *def_index = 0;
679 *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
680 if (!*ids)
681 return E_OUTOFMEMORY;
683 (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
684 if (!(*ids)[0]) {
685 HeapFree(GetProcessHeap(), 0, *ids);
686 return E_OUTOFMEMORY;
689 lstrcpyW((*ids)[0], defaultW);
691 *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
692 (*keys)[0] = NULL;
694 return S_OK;
697 int WINAPI AUDDRV_GetPriority(void)
699 HRESULT hr;
700 pthread_mutex_lock(&pulse_lock);
701 hr = pulse_connect();
702 pthread_mutex_unlock(&pulse_lock);
703 return SUCCEEDED(hr) ? 3 : 0;
706 HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
707 EDataFlow dataflow, IAudioClient **out)
709 HRESULT hr;
710 ACImpl *This;
711 int i;
713 TRACE("%p %p %d %p\n", key, dev, dataflow, out);
714 if (dataflow != eRender && dataflow != eCapture)
715 return E_UNEXPECTED;
717 *out = NULL;
718 pthread_mutex_lock(&pulse_lock);
719 hr = pulse_connect();
720 pthread_mutex_unlock(&pulse_lock);
721 if (FAILED(hr))
722 return hr;
724 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
725 if (!This)
726 return E_OUTOFMEMORY;
728 This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
729 This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
730 This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
731 This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
732 This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
733 This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
734 This->dataflow = dataflow;
735 This->parent = dev;
736 This->clock_pulse = PA_USEC_INVALID;
737 for (i = 0; i < PA_CHANNELS_MAX; ++i)
738 This->vol[i] = 1.f;
739 IMMDevice_AddRef(This->parent);
741 *out = &This->IAudioClient_iface;
742 IAudioClient_AddRef(&This->IAudioClient_iface);
744 return S_OK;
747 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
748 REFIID riid, void **ppv)
750 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
752 if (!ppv)
753 return E_POINTER;
754 *ppv = NULL;
755 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
756 *ppv = iface;
757 if (*ppv) {
758 IUnknown_AddRef((IUnknown*)*ppv);
759 return S_OK;
761 WARN("Unknown interface %s\n", debugstr_guid(riid));
762 return E_NOINTERFACE;
765 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
767 ACImpl *This = impl_from_IAudioClient(iface);
768 ULONG ref;
769 ref = InterlockedIncrement(&This->ref);
770 TRACE("(%p) Refcount now %u\n", This, ref);
771 return ref;
774 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
776 ACImpl *This = impl_from_IAudioClient(iface);
777 ULONG ref;
778 ref = InterlockedDecrement(&This->ref);
779 TRACE("(%p) Refcount now %u\n", This, ref);
780 if (!ref) {
781 if (This->stream) {
782 pthread_mutex_lock(&pulse_lock);
783 if (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream))) {
784 pa_stream_disconnect(This->stream);
785 while (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream)))
786 pthread_cond_wait(&pulse_cond, &pulse_lock);
788 pa_stream_unref(This->stream);
789 This->stream = NULL;
790 list_remove(&This->entry);
791 pthread_mutex_unlock(&pulse_lock);
793 IMMDevice_Release(This->parent);
794 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
795 HeapFree(GetProcessHeap(), 0, This);
797 return ref;
800 static void dump_fmt(const WAVEFORMATEX *fmt)
802 TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
803 switch(fmt->wFormatTag) {
804 case WAVE_FORMAT_PCM:
805 TRACE("WAVE_FORMAT_PCM");
806 break;
807 case WAVE_FORMAT_IEEE_FLOAT:
808 TRACE("WAVE_FORMAT_IEEE_FLOAT");
809 break;
810 case WAVE_FORMAT_EXTENSIBLE:
811 TRACE("WAVE_FORMAT_EXTENSIBLE");
812 break;
813 default:
814 TRACE("Unknown");
815 break;
817 TRACE(")\n");
819 TRACE("nChannels: %u\n", fmt->nChannels);
820 TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
821 TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
822 TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
823 TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
824 TRACE("cbSize: %u\n", fmt->cbSize);
826 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
827 WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
828 TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
829 TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
830 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
834 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
836 WAVEFORMATEX *ret;
837 size_t size;
839 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
840 size = sizeof(WAVEFORMATEXTENSIBLE);
841 else
842 size = sizeof(WAVEFORMATEX);
844 ret = CoTaskMemAlloc(size);
845 if (!ret)
846 return NULL;
848 memcpy(ret, fmt, size);
850 ret->cbSize = size - sizeof(WAVEFORMATEX);
852 return ret;
855 static DWORD get_channel_mask(unsigned int channels)
857 switch(channels) {
858 case 0:
859 return 0;
860 case 1:
861 return SPEAKER_FRONT_CENTER;
862 case 2:
863 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
864 case 3:
865 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
866 SPEAKER_LOW_FREQUENCY;
867 case 4:
868 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
869 SPEAKER_BACK_RIGHT;
870 case 5:
871 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
872 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
873 case 6:
874 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
875 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
876 case 7:
877 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
878 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
879 SPEAKER_BACK_CENTER;
880 case 8:
881 return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
882 SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
883 SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
885 FIXME("Unknown speaker configuration: %u\n", channels);
886 return 0;
889 static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
891 pa_channel_map_init(&This->map);
892 This->ss.rate = fmt->nSamplesPerSec;
893 This->ss.format = PA_SAMPLE_INVALID;
894 switch(fmt->wFormatTag) {
895 case WAVE_FORMAT_IEEE_FLOAT:
896 if (!fmt->nChannels || fmt->nChannels > 2 || fmt->wBitsPerSample != 32)
897 break;
898 This->ss.format = PA_SAMPLE_FLOAT32LE;
899 pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
900 break;
901 case WAVE_FORMAT_PCM:
902 if (!fmt->nChannels || fmt->nChannels > 2)
903 break;
904 if (fmt->wBitsPerSample == 8)
905 This->ss.format = PA_SAMPLE_U8;
906 else if (fmt->wBitsPerSample == 16)
907 This->ss.format = PA_SAMPLE_S16LE;
908 pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
909 break;
910 case WAVE_FORMAT_EXTENSIBLE: {
911 WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)fmt;
912 DWORD mask = wfe->dwChannelMask;
913 DWORD i = 0, j;
914 if (fmt->cbSize != (sizeof(*wfe) - sizeof(*fmt)) && fmt->cbSize != sizeof(*wfe))
915 break;
916 if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) &&
917 (!wfe->Samples.wValidBitsPerSample || wfe->Samples.wValidBitsPerSample == 32) &&
918 fmt->wBitsPerSample == 32)
919 This->ss.format = PA_SAMPLE_FLOAT32LE;
920 else if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
921 DWORD valid = wfe->Samples.wValidBitsPerSample;
922 if (!valid)
923 valid = fmt->wBitsPerSample;
924 if (!valid || valid > fmt->wBitsPerSample)
925 break;
926 switch (fmt->wBitsPerSample) {
927 case 8:
928 if (valid == 8)
929 This->ss.format = PA_SAMPLE_U8;
930 break;
931 case 16:
932 if (valid == 16)
933 This->ss.format = PA_SAMPLE_S16LE;
934 break;
935 case 24:
936 if (valid == 24)
937 This->ss.format = PA_SAMPLE_S24LE;
938 break;
939 case 32:
940 if (valid == 24)
941 This->ss.format = PA_SAMPLE_S24_32LE;
942 else if (valid == 32)
943 This->ss.format = PA_SAMPLE_S32LE;
944 default:
945 break;
948 This->map.channels = fmt->nChannels;
949 if (!mask)
950 mask = get_channel_mask(fmt->nChannels);
951 for (j = 0; j < sizeof(pulse_pos_from_wfx)/sizeof(*pulse_pos_from_wfx) && i < fmt->nChannels; ++j) {
952 if (mask & (1 << j))
953 This->map.map[i++] = pulse_pos_from_wfx[j];
956 /* Special case for mono since pulse appears to map it differently */
957 if (mask == SPEAKER_FRONT_CENTER)
958 This->map.map[0] = PA_CHANNEL_POSITION_MONO;
960 if ((mask & SPEAKER_ALL) && i < fmt->nChannels) {
961 This->map.map[i++] = PA_CHANNEL_POSITION_MONO;
962 FIXME("Is the 'all' channel mapped correctly?\n");
965 if (i < fmt->nChannels || (mask & SPEAKER_RESERVED)) {
966 This->map.channels = 0;
967 ERR("Invalid channel mask: %i/%i and %x\n", i, fmt->nChannels, mask);
968 break;
970 break;
972 default: FIXME("Unhandled tag %x\n", fmt->wFormatTag);
974 This->ss.channels = This->map.channels;
975 if (!pa_channel_map_valid(&This->map) || This->ss.format == PA_SAMPLE_INVALID) {
976 ERR("Invalid format! Channel spec valid: %i, format: %i\n", pa_channel_map_valid(&This->map), This->ss.format);
977 dump_fmt(fmt);
978 return AUDCLNT_E_UNSUPPORTED_FORMAT;
980 return S_OK;
983 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
984 AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
985 REFERENCE_TIME period, const WAVEFORMATEX *fmt,
986 const GUID *sessionguid)
988 ACImpl *This = impl_from_IAudioClient(iface);
989 HRESULT hr = S_OK;
990 UINT period_bytes;
992 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
993 wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
995 if (!fmt)
996 return E_POINTER;
998 if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
999 return AUDCLNT_E_NOT_INITIALIZED;
1000 if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1001 return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
1003 if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
1004 AUDCLNT_STREAMFLAGS_LOOPBACK |
1005 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
1006 AUDCLNT_STREAMFLAGS_NOPERSIST |
1007 AUDCLNT_STREAMFLAGS_RATEADJUST |
1008 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
1009 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
1010 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)) {
1011 TRACE("Unknown flags: %08x\n", flags);
1012 return E_INVALIDARG;
1015 pthread_mutex_lock(&pulse_lock);
1016 if (This->stream) {
1017 pthread_mutex_unlock(&pulse_lock);
1018 return AUDCLNT_E_ALREADY_INITIALIZED;
1021 hr = pulse_spec_from_waveformat(This, fmt);
1022 if (FAILED(hr))
1023 goto exit;
1025 if (mode == AUDCLNT_SHAREMODE_SHARED) {
1026 period = pulse_def_period[This->dataflow == eCapture];
1027 if (duration < 2 * period)
1028 duration = 2 * period;
1030 period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000);
1032 if (duration < 20000000)
1033 This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
1034 else
1035 This->bufsize_frames = 2 * fmt->nSamplesPerSec;
1036 This->bufsize_bytes = This->bufsize_frames * pa_frame_size(&This->ss);
1038 This->share = mode;
1039 This->flags = flags;
1040 hr = pulse_stream_connect(This, period_bytes);
1041 if (SUCCEEDED(hr)) {
1042 UINT32 unalign;
1043 const pa_buffer_attr *attr = pa_stream_get_buffer_attr(This->stream);
1044 /* Update frames according to new size */
1045 dump_attr(attr);
1046 if (This->dataflow == eRender)
1047 This->bufsize_bytes = attr->tlength;
1048 else {
1049 This->capture_period = period_bytes = attr->fragsize;
1050 if ((unalign = This->bufsize_bytes % period_bytes))
1051 This->bufsize_bytes += period_bytes - unalign;
1053 This->bufsize_frames = This->bufsize_bytes / pa_frame_size(&This->ss);
1055 if (SUCCEEDED(hr)) {
1056 UINT32 i, capture_packets = This->capture_period ? This->bufsize_bytes / This->capture_period : 0;
1057 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_bytes + capture_packets * sizeof(ACPacket));
1058 if (!This->tmp_buffer)
1059 hr = E_OUTOFMEMORY;
1060 else {
1061 ACPacket *cur_packet = (ACPacket*)((char*)This->tmp_buffer + This->bufsize_bytes);
1062 BYTE *data = This->tmp_buffer;
1063 memset(This->tmp_buffer, This->ss.format == PA_SAMPLE_U8 ? 0x80 : 0, This->bufsize_bytes);
1064 list_init(&This->packet_free_head);
1065 list_init(&This->packet_filled_head);
1066 for (i = 0; i < capture_packets; ++i, ++cur_packet) {
1067 list_add_tail(&This->packet_free_head, &cur_packet->entry);
1068 cur_packet->data = data;
1069 data += This->capture_period;
1071 assert(!This->capture_period || This->bufsize_bytes == This->capture_period * capture_packets);
1072 assert(!capture_packets || data - This->bufsize_bytes == This->tmp_buffer);
1076 exit:
1077 if (FAILED(hr)) {
1078 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1079 This->tmp_buffer = NULL;
1080 if (This->stream) {
1081 pa_stream_disconnect(This->stream);
1082 pa_stream_unref(This->stream);
1083 This->stream = NULL;
1086 pthread_mutex_unlock(&pulse_lock);
1087 return hr;
1090 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
1091 UINT32 *out)
1093 ACImpl *This = impl_from_IAudioClient(iface);
1094 HRESULT hr;
1096 TRACE("(%p)->(%p)\n", This, out);
1098 if (!out)
1099 return E_POINTER;
1101 pthread_mutex_lock(&pulse_lock);
1102 hr = pulse_stream_valid(This);
1103 if (SUCCEEDED(hr))
1104 *out = This->bufsize_frames;
1105 pthread_mutex_unlock(&pulse_lock);
1107 return hr;
1110 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
1111 REFERENCE_TIME *latency)
1113 ACImpl *This = impl_from_IAudioClient(iface);
1114 const pa_buffer_attr *attr;
1115 REFERENCE_TIME lat;
1116 HRESULT hr;
1118 TRACE("(%p)->(%p)\n", This, latency);
1120 if (!latency)
1121 return E_POINTER;
1123 pthread_mutex_lock(&pulse_lock);
1124 hr = pulse_stream_valid(This);
1125 if (FAILED(hr)) {
1126 pthread_mutex_unlock(&pulse_lock);
1127 return hr;
1129 attr = pa_stream_get_buffer_attr(This->stream);
1130 if (This->dataflow == eRender)
1131 lat = attr->minreq / pa_frame_size(&This->ss);
1132 else
1133 lat = attr->fragsize / pa_frame_size(&This->ss);
1134 *latency = 10000000;
1135 *latency *= lat;
1136 *latency /= This->ss.rate;
1137 pthread_mutex_unlock(&pulse_lock);
1138 TRACE("Latency: %u ms\n", (DWORD)(*latency / 10000));
1139 return S_OK;
1142 static void ACImpl_GetRenderPad(ACImpl *This, UINT32 *out)
1144 *out = This->pad / pa_frame_size(&This->ss);
1147 static void ACImpl_GetCapturePad(ACImpl *This, UINT32 *out)
1149 ACPacket *packet = This->locked_ptr;
1150 if (!packet && !list_empty(&This->packet_filled_head)) {
1151 packet = (ACPacket*)list_head(&This->packet_filled_head);
1152 This->locked_ptr = packet;
1153 list_remove(&packet->entry);
1155 if (out)
1156 *out = This->pad / pa_frame_size(&This->ss);
1159 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
1160 UINT32 *out)
1162 ACImpl *This = impl_from_IAudioClient(iface);
1163 HRESULT hr;
1165 TRACE("(%p)->(%p)\n", This, out);
1167 if (!out)
1168 return E_POINTER;
1170 pthread_mutex_lock(&pulse_lock);
1171 hr = pulse_stream_valid(This);
1172 if (FAILED(hr)) {
1173 pthread_mutex_unlock(&pulse_lock);
1174 return hr;
1177 if (This->dataflow == eRender)
1178 ACImpl_GetRenderPad(This, out);
1179 else
1180 ACImpl_GetCapturePad(This, out);
1181 pthread_mutex_unlock(&pulse_lock);
1183 TRACE("%p Pad: %u ms (%u)\n", This, MulDiv(*out, 1000, This->ss.rate), *out);
1184 return S_OK;
1187 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1188 AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
1189 WAVEFORMATEX **out)
1191 ACImpl *This = impl_from_IAudioClient(iface);
1192 HRESULT hr = S_OK;
1193 WAVEFORMATEX *closest = NULL;
1195 TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
1197 if (!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
1198 return E_POINTER;
1200 if (out)
1201 *out = NULL;
1202 if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1203 return E_INVALIDARG;
1204 if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
1205 return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
1206 if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1207 fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1208 return E_INVALIDARG;
1210 dump_fmt(fmt);
1212 closest = clone_format(fmt);
1213 if (!closest)
1214 hr = E_OUTOFMEMORY;
1216 if (hr == S_OK || !out) {
1217 CoTaskMemFree(closest);
1218 if (out)
1219 *out = NULL;
1220 } else if (closest) {
1221 closest->nBlockAlign =
1222 closest->nChannels * closest->wBitsPerSample / 8;
1223 closest->nAvgBytesPerSec =
1224 closest->nBlockAlign * closest->nSamplesPerSec;
1225 *out = closest;
1228 TRACE("returning: %08x %p\n", hr, out ? *out : NULL);
1229 return hr;
1232 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1233 WAVEFORMATEX **pwfx)
1235 ACImpl *This = impl_from_IAudioClient(iface);
1236 WAVEFORMATEXTENSIBLE *fmt = &pulse_fmt[This->dataflow == eCapture];
1238 TRACE("(%p)->(%p)\n", This, pwfx);
1240 if (!pwfx)
1241 return E_POINTER;
1243 *pwfx = clone_format(&fmt->Format);
1244 if (!*pwfx)
1245 return E_OUTOFMEMORY;
1246 dump_fmt(*pwfx);
1247 return S_OK;
1250 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1251 REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1253 ACImpl *This = impl_from_IAudioClient(iface);
1255 TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1257 if (!defperiod && !minperiod)
1258 return E_POINTER;
1260 if (defperiod)
1261 *defperiod = pulse_def_period[This->dataflow == eCapture];
1262 if (minperiod)
1263 *minperiod = pulse_min_period[This->dataflow == eCapture];
1265 return S_OK;
1268 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1270 ACImpl *This = impl_from_IAudioClient(iface);
1271 HRESULT hr = S_OK;
1272 int success;
1273 pa_operation *o;
1275 TRACE("(%p)\n", This);
1277 pthread_mutex_lock(&pulse_lock);
1278 hr = pulse_stream_valid(This);
1279 if (FAILED(hr)) {
1280 pthread_mutex_unlock(&pulse_lock);
1281 return hr;
1284 if ((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event) {
1285 pthread_mutex_unlock(&pulse_lock);
1286 return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1289 if (This->started) {
1290 pthread_mutex_unlock(&pulse_lock);
1291 return AUDCLNT_E_NOT_STOPPED;
1293 This->clock_pulse = PA_USEC_INVALID;
1295 if (pa_stream_is_corked(This->stream)) {
1296 o = pa_stream_cork(This->stream, 0, pulse_op_cb, &success);
1297 if (o) {
1298 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1299 pthread_cond_wait(&pulse_cond, &pulse_lock);
1300 pa_operation_unref(o);
1301 } else
1302 success = 0;
1303 if (!success)
1304 hr = E_FAIL;
1306 if (SUCCEEDED(hr)) {
1307 This->started = TRUE;
1308 if (This->dataflow == eRender && This->event)
1309 pa_stream_set_latency_update_callback(This->stream, pulse_latency_callback, This);
1311 pthread_mutex_unlock(&pulse_lock);
1312 return hr;
1315 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1317 ACImpl *This = impl_from_IAudioClient(iface);
1318 HRESULT hr = S_OK;
1319 pa_operation *o;
1320 int success;
1322 TRACE("(%p)\n", This);
1324 pthread_mutex_lock(&pulse_lock);
1325 hr = pulse_stream_valid(This);
1326 if (FAILED(hr)) {
1327 pthread_mutex_unlock(&pulse_lock);
1328 return hr;
1331 if (!This->started) {
1332 pthread_mutex_unlock(&pulse_lock);
1333 return S_FALSE;
1336 if (This->dataflow == eRender) {
1337 o = pa_stream_cork(This->stream, 1, pulse_op_cb, &success);
1338 if (o) {
1339 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1340 pthread_cond_wait(&pulse_cond, &pulse_lock);
1341 pa_operation_unref(o);
1342 } else
1343 success = 0;
1344 if (!success)
1345 hr = E_FAIL;
1347 if (SUCCEEDED(hr)) {
1348 This->started = FALSE;
1349 This->clock_pulse = PA_USEC_INVALID;
1351 pthread_mutex_unlock(&pulse_lock);
1352 return hr;
1355 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1357 ACImpl *This = impl_from_IAudioClient(iface);
1358 HRESULT hr = S_OK;
1360 TRACE("(%p)\n", This);
1362 pthread_mutex_lock(&pulse_lock);
1363 hr = pulse_stream_valid(This);
1364 if (FAILED(hr)) {
1365 pthread_mutex_unlock(&pulse_lock);
1366 return hr;
1369 if (This->started) {
1370 pthread_mutex_unlock(&pulse_lock);
1371 return AUDCLNT_E_NOT_STOPPED;
1374 if (This->locked) {
1375 pthread_mutex_unlock(&pulse_lock);
1376 return AUDCLNT_E_BUFFER_OPERATION_PENDING;
1379 if (This->dataflow == eRender) {
1380 /* If there is still data in the render buffer it needs to be removed from the server */
1381 int success = 0;
1382 if (This->pad) {
1383 pa_operation *o = pa_stream_flush(This->stream, pulse_op_cb, &success);
1384 if (o) {
1385 while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
1386 pthread_cond_wait(&pulse_cond, &pulse_lock);
1387 pa_operation_unref(o);
1390 if (success || !This->pad)
1391 This->clock_lastpos = This->clock_written = This->pad = 0;
1392 } else {
1393 ACPacket *p;
1394 This->clock_written += This->pad;
1395 This->pad = 0;
1397 if ((p = This->locked_ptr)) {
1398 This->locked_ptr = NULL;
1399 list_add_tail(&This->packet_free_head, &p->entry);
1401 list_move_tail(&This->packet_free_head, &This->packet_filled_head);
1403 pthread_mutex_unlock(&pulse_lock);
1405 return hr;
1408 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1409 HANDLE event)
1411 ACImpl *This = impl_from_IAudioClient(iface);
1412 HRESULT hr;
1414 TRACE("(%p)->(%p)\n", This, event);
1416 if (!event)
1417 return E_INVALIDARG;
1419 pthread_mutex_lock(&pulse_lock);
1420 hr = pulse_stream_valid(This);
1421 if (FAILED(hr)) {
1422 pthread_mutex_unlock(&pulse_lock);
1423 return hr;
1426 if (!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
1427 hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1428 else if (This->event)
1429 hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
1430 else
1431 This->event = event;
1432 pthread_mutex_unlock(&pulse_lock);
1433 return hr;
1436 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1437 void **ppv)
1439 ACImpl *This = impl_from_IAudioClient(iface);
1440 HRESULT hr;
1442 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1444 if (!ppv)
1445 return E_POINTER;
1446 *ppv = NULL;
1448 pthread_mutex_lock(&pulse_lock);
1449 hr = pulse_stream_valid(This);
1450 pthread_mutex_unlock(&pulse_lock);
1451 if (FAILED(hr))
1452 return hr;
1454 if (IsEqualIID(riid, &IID_IAudioRenderClient)) {
1455 if (This->dataflow != eRender)
1456 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1457 *ppv = &This->IAudioRenderClient_iface;
1458 } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) {
1459 if (This->dataflow != eCapture)
1460 return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1461 *ppv = &This->IAudioCaptureClient_iface;
1462 } else if (IsEqualIID(riid, &IID_IAudioClock)) {
1463 *ppv = &This->IAudioClock_iface;
1466 if (*ppv) {
1467 IUnknown_AddRef((IUnknown*)*ppv);
1468 return S_OK;
1471 FIXME("stub %s\n", debugstr_guid(riid));
1472 return E_NOINTERFACE;
1475 static const IAudioClientVtbl AudioClient_Vtbl =
1477 AudioClient_QueryInterface,
1478 AudioClient_AddRef,
1479 AudioClient_Release,
1480 AudioClient_Initialize,
1481 AudioClient_GetBufferSize,
1482 AudioClient_GetStreamLatency,
1483 AudioClient_GetCurrentPadding,
1484 AudioClient_IsFormatSupported,
1485 AudioClient_GetMixFormat,
1486 AudioClient_GetDevicePeriod,
1487 AudioClient_Start,
1488 AudioClient_Stop,
1489 AudioClient_Reset,
1490 AudioClient_SetEventHandle,
1491 AudioClient_GetService
1494 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1495 IAudioRenderClient *iface, REFIID riid, void **ppv)
1497 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1499 if (!ppv)
1500 return E_POINTER;
1501 *ppv = NULL;
1503 if (IsEqualIID(riid, &IID_IUnknown) ||
1504 IsEqualIID(riid, &IID_IAudioRenderClient))
1505 *ppv = iface;
1506 if (*ppv) {
1507 IUnknown_AddRef((IUnknown*)*ppv);
1508 return S_OK;
1511 WARN("Unknown interface %s\n", debugstr_guid(riid));
1512 return E_NOINTERFACE;
1515 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1517 ACImpl *This = impl_from_IAudioRenderClient(iface);
1518 return AudioClient_AddRef(&This->IAudioClient_iface);
1521 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1523 ACImpl *This = impl_from_IAudioRenderClient(iface);
1524 return AudioClient_Release(&This->IAudioClient_iface);
1527 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1528 UINT32 frames, BYTE **data)
1530 ACImpl *This = impl_from_IAudioRenderClient(iface);
1531 UINT32 avail, pad, req, bytes = frames * pa_frame_size(&This->ss);
1532 HRESULT hr = S_OK;
1533 int ret = -1;
1535 TRACE("(%p)->(%u, %p)\n", This, frames, data);
1537 if (!data)
1538 return E_POINTER;
1539 *data = NULL;
1541 pthread_mutex_lock(&pulse_lock);
1542 hr = pulse_stream_valid(This);
1543 if (FAILED(hr) || This->locked) {
1544 pthread_mutex_unlock(&pulse_lock);
1545 return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
1547 if (!frames) {
1548 pthread_mutex_unlock(&pulse_lock);
1549 return S_OK;
1552 ACImpl_GetRenderPad(This, &pad);
1553 avail = This->bufsize_frames - pad;
1554 if (avail < frames || bytes > This->bufsize_bytes) {
1555 pthread_mutex_unlock(&pulse_lock);
1556 WARN("Wanted to write %u, but only %u available\n", frames, avail);
1557 return AUDCLNT_E_BUFFER_TOO_LARGE;
1560 This->locked = frames;
1561 req = bytes;
1562 ret = pa_stream_begin_write(This->stream, &This->locked_ptr, &req);
1563 if (ret < 0 || req < bytes) {
1564 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);
1565 if (ret >= 0)
1566 pa_stream_cancel_write(This->stream);
1567 *data = This->tmp_buffer;
1568 This->locked_ptr = NULL;
1569 } else
1570 *data = This->locked_ptr;
1571 pthread_mutex_unlock(&pulse_lock);
1572 return hr;
1575 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1576 IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1578 ACImpl *This = impl_from_IAudioRenderClient(iface);
1579 UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
1581 TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1583 pthread_mutex_lock(&pulse_lock);
1584 if (!This->locked || !written_frames) {
1585 if (This->locked_ptr)
1586 pa_stream_cancel_write(This->stream);
1587 This->locked = 0;
1588 This->locked_ptr = NULL;
1589 pthread_mutex_unlock(&pulse_lock);
1590 return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1593 if (This->locked < written_frames) {
1594 pthread_mutex_unlock(&pulse_lock);
1595 return AUDCLNT_E_INVALID_SIZE;
1598 if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
1599 if (This->ss.format == PA_SAMPLE_U8)
1600 memset(This->tmp_buffer, 128, written_bytes);
1601 else
1602 memset(This->tmp_buffer, 0, written_bytes);
1605 This->locked = 0;
1606 if (This->locked_ptr)
1607 pa_stream_write(This->stream, This->locked_ptr, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
1608 else
1609 pa_stream_write(This->stream, This->tmp_buffer, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
1610 This->pad += written_bytes;
1611 This->locked_ptr = NULL;
1612 TRACE("Released %u, pad %u\n", written_frames, This->pad / pa_frame_size(&This->ss));
1613 assert(This->pad <= This->bufsize_bytes);
1614 pthread_mutex_unlock(&pulse_lock);
1615 return S_OK;
1618 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1619 AudioRenderClient_QueryInterface,
1620 AudioRenderClient_AddRef,
1621 AudioRenderClient_Release,
1622 AudioRenderClient_GetBuffer,
1623 AudioRenderClient_ReleaseBuffer
1626 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1627 IAudioCaptureClient *iface, REFIID riid, void **ppv)
1629 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1631 if (!ppv)
1632 return E_POINTER;
1633 *ppv = NULL;
1635 if (IsEqualIID(riid, &IID_IUnknown) ||
1636 IsEqualIID(riid, &IID_IAudioCaptureClient))
1637 *ppv = iface;
1638 if (*ppv) {
1639 IUnknown_AddRef((IUnknown*)*ppv);
1640 return S_OK;
1643 WARN("Unknown interface %s\n", debugstr_guid(riid));
1644 return E_NOINTERFACE;
1647 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1649 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1650 return IAudioClient_AddRef(&This->IAudioClient_iface);
1653 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1655 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1656 return IAudioClient_Release(&This->IAudioClient_iface);
1659 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1660 BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1661 UINT64 *qpcpos)
1663 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1664 HRESULT hr;
1665 ACPacket *packet;
1667 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1668 devpos, qpcpos);
1670 if (!data || !frames || !flags)
1671 return E_POINTER;
1673 pthread_mutex_lock(&pulse_lock);
1674 hr = pulse_stream_valid(This);
1675 if (FAILED(hr) || This->locked) {
1676 pthread_mutex_unlock(&pulse_lock);
1677 return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
1680 ACImpl_GetCapturePad(This, NULL);
1681 if ((packet = This->locked_ptr)) {
1682 *frames = This->capture_period / pa_frame_size(&This->ss);
1683 *flags = 0;
1684 if (packet->discont)
1685 *flags |= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY;
1686 if (devpos) {
1687 if (packet->discont)
1688 *devpos = (This->clock_written + This->capture_period) / pa_frame_size(&This->ss);
1689 else
1690 *devpos = This->clock_written / pa_frame_size(&This->ss);
1692 if (qpcpos)
1693 *qpcpos = packet->qpcpos;
1694 *data = packet->data;
1696 else
1697 *frames = 0;
1698 This->locked = *frames;
1699 pthread_mutex_unlock(&pulse_lock);
1700 return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1703 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1704 IAudioCaptureClient *iface, UINT32 done)
1706 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1708 TRACE("(%p)->(%u)\n", This, done);
1710 pthread_mutex_lock(&pulse_lock);
1711 if (!This->locked && done) {
1712 pthread_mutex_unlock(&pulse_lock);
1713 return AUDCLNT_E_OUT_OF_ORDER;
1715 if (done && This->locked != done) {
1716 pthread_mutex_unlock(&pulse_lock);
1717 return AUDCLNT_E_INVALID_SIZE;
1719 if (done) {
1720 ACPacket *packet = This->locked_ptr;
1721 This->locked_ptr = NULL;
1722 This->pad -= This->capture_period;
1723 if (packet->discont)
1724 This->clock_written += 2 * This->capture_period;
1725 else
1726 This->clock_written += This->capture_period;
1727 list_add_tail(&This->packet_free_head, &packet->entry);
1729 This->locked = 0;
1730 pthread_mutex_unlock(&pulse_lock);
1731 return S_OK;
1734 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1735 IAudioCaptureClient *iface, UINT32 *frames)
1737 ACImpl *This = impl_from_IAudioCaptureClient(iface);
1738 ACPacket *p;
1740 TRACE("(%p)->(%p)\n", This, frames);
1741 if (!frames)
1742 return E_POINTER;
1744 pthread_mutex_lock(&pulse_lock);
1745 ACImpl_GetCapturePad(This, NULL);
1746 p = This->locked_ptr;
1747 if (p)
1748 *frames = This->capture_period / pa_frame_size(&This->ss);
1749 else
1750 *frames = 0;
1751 pthread_mutex_unlock(&pulse_lock);
1752 return S_OK;
1755 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1757 AudioCaptureClient_QueryInterface,
1758 AudioCaptureClient_AddRef,
1759 AudioCaptureClient_Release,
1760 AudioCaptureClient_GetBuffer,
1761 AudioCaptureClient_ReleaseBuffer,
1762 AudioCaptureClient_GetNextPacketSize
1765 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1766 REFIID riid, void **ppv)
1768 ACImpl *This = impl_from_IAudioClock(iface);
1770 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1772 if (!ppv)
1773 return E_POINTER;
1774 *ppv = NULL;
1776 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1777 *ppv = iface;
1778 else if (IsEqualIID(riid, &IID_IAudioClock2))
1779 *ppv = &This->IAudioClock2_iface;
1780 if (*ppv) {
1781 IUnknown_AddRef((IUnknown*)*ppv);
1782 return S_OK;
1785 WARN("Unknown interface %s\n", debugstr_guid(riid));
1786 return E_NOINTERFACE;
1789 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1791 ACImpl *This = impl_from_IAudioClock(iface);
1792 return IAudioClient_AddRef(&This->IAudioClient_iface);
1795 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1797 ACImpl *This = impl_from_IAudioClock(iface);
1798 return IAudioClient_Release(&This->IAudioClient_iface);
1801 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1803 ACImpl *This = impl_from_IAudioClock(iface);
1804 HRESULT hr;
1806 TRACE("(%p)->(%p)\n", This, freq);
1808 pthread_mutex_lock(&pulse_lock);
1809 hr = pulse_stream_valid(This);
1810 if (SUCCEEDED(hr))
1811 *freq = This->ss.rate * pa_frame_size(&This->ss);
1812 pthread_mutex_unlock(&pulse_lock);
1813 return hr;
1816 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1817 UINT64 *qpctime)
1819 ACImpl *This = impl_from_IAudioClock(iface);
1820 pa_usec_t time;
1821 HRESULT hr;
1823 TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1825 if (!pos)
1826 return E_POINTER;
1828 pthread_mutex_lock(&pulse_lock);
1829 hr = pulse_stream_valid(This);
1830 if (FAILED(hr)) {
1831 pthread_mutex_unlock(&pulse_lock);
1832 return hr;
1835 *pos = This->clock_written;
1836 if (This->clock_pulse != PA_USEC_INVALID && pa_stream_get_time(This->stream, &time) >= 0) {
1837 UINT32 delta = pa_usec_to_bytes(time - This->clock_pulse, &This->ss);
1838 if (delta < This->pad)
1839 *pos += delta;
1840 else
1841 *pos += This->pad;
1844 /* Make time never go backwards */
1845 if (*pos < This->clock_lastpos)
1846 *pos = This->clock_lastpos;
1847 else
1848 This->clock_lastpos = *pos;
1849 pthread_mutex_unlock(&pulse_lock);
1851 TRACE("%p Position: %u\n", This, (unsigned)*pos);
1853 if (qpctime) {
1854 LARGE_INTEGER stamp, freq;
1855 QueryPerformanceCounter(&stamp);
1856 QueryPerformanceFrequency(&freq);
1857 *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1860 return S_OK;
1863 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1864 DWORD *chars)
1866 ACImpl *This = impl_from_IAudioClock(iface);
1868 TRACE("(%p)->(%p)\n", This, chars);
1870 if (!chars)
1871 return E_POINTER;
1873 *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1875 return S_OK;
1878 static const IAudioClockVtbl AudioClock_Vtbl =
1880 AudioClock_QueryInterface,
1881 AudioClock_AddRef,
1882 AudioClock_Release,
1883 AudioClock_GetFrequency,
1884 AudioClock_GetPosition,
1885 AudioClock_GetCharacteristics
1888 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1889 REFIID riid, void **ppv)
1891 ACImpl *This = impl_from_IAudioClock2(iface);
1892 return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1895 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1897 ACImpl *This = impl_from_IAudioClock2(iface);
1898 return IAudioClient_AddRef(&This->IAudioClient_iface);
1901 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1903 ACImpl *This = impl_from_IAudioClock2(iface);
1904 return IAudioClient_Release(&This->IAudioClient_iface);
1907 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1908 UINT64 *pos, UINT64 *qpctime)
1910 ACImpl *This = impl_from_IAudioClock2(iface);
1911 HRESULT hr = AudioClock_GetPosition(&This->IAudioClock_iface, pos, qpctime);
1912 if (SUCCEEDED(hr))
1913 *pos /= pa_frame_size(&This->ss);
1914 return hr;
1917 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1919 AudioClock2_QueryInterface,
1920 AudioClock2_AddRef,
1921 AudioClock2_Release,
1922 AudioClock2_GetDevicePosition
1925 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
1926 IAudioSessionManager2 **out)
1928 *out = NULL;
1929 return E_NOTIMPL;