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
34 #include <pulse/pulseaudio.h>
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42 #include "wine/list.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
) {
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
);
93 DisableThreadLibraryCalls(dll
);
94 } else if (reason
== DLL_PROCESS_DETACH
) {
96 pa_context_disconnect(pulse_ctx
);
97 pa_context_unref(pulse_ctx
);
100 pa_mainloop_quit(pulse_ml
, 0);
101 CloseHandle(pulse_thread
);
106 typedef struct ACImpl ACImpl
;
108 typedef struct _ACPacket
{
116 IAudioClient IAudioClient_iface
;
117 IAudioRenderClient IAudioRenderClient_iface
;
118 IAudioCaptureClient IAudioCaptureClient_iface
;
119 IAudioClock IAudioClock_iface
;
120 IAudioClock2 IAudioClock2_iface
;
121 IAudioStreamVolume IAudioStreamVolume_iface
;
124 float vol
[PA_CHANNELS_MAX
];
129 AUDCLNT_SHAREMODE share
;
132 UINT32 bufsize_frames
, bufsize_bytes
, locked
, capture_period
, pad
, started
, peek_ofs
;
133 void *locked_ptr
, *tmp_buffer
;
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
) {
197 pthread_mutex_unlock(&pulse_lock
);
198 r
= poll(ufds
, nfds
, timeout
);
199 pthread_mutex_lock(&pulse_lock
);
203 static DWORD CALLBACK
pulse_mainloop_thread(void *tmp
) {
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
);
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
;
247 unsigned int length
= 0;
249 pa_channel_map_init_auto(&map
, 2, PA_CHANNEL_MAP_ALSA
);
251 ss
.format
= PA_SAMPLE_FLOAT32LE
;
252 ss
.channels
= map
.channels
;
256 attr
.minreq
= attr
.fragsize
= pa_frame_size(&ss
);
259 stream
= pa_stream_new(pulse_ctx
, "format test stream", &ss
, &map
);
261 pa_stream_set_state_callback(stream
, pulse_stream_state
, NULL
);
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
);
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
);
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
);
276 length
= pa_stream_get_buffer_attr(stream
)->minreq
;
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
);
285 pa_stream_unref(stream
);
287 pulse_def_period
[!render
] = pulse_min_period
[!render
] = pa_bytes_to_usec(10 * length
, &ss
);
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
;
303 fmt
->Samples
.wValidBitsPerSample
= 24;
304 if (ss
.format
== PA_SAMPLE_FLOAT32LE
)
305 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
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)
336 WCHAR path
[PATH_MAX
], *name
;
341 if (!(pulse_thread
= CreateThread(NULL
, 0, pulse_mainloop_thread
, NULL
, 0, NULL
)))
343 ERR("Failed to create mainloop thread.");
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
)))
353 pa_context_unref(pulse_ctx
);
355 GetModuleFileNameW(NULL
, path
, sizeof(path
)/sizeof(*path
));
356 name
= strrchrW(path
, '\\');
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
);
368 ERR("Failed to create context\n");
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)
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
)
385 if (state
== PA_CONTEXT_READY
)
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]);
397 pa_context_unref(pulse_ctx
);
402 static void pulse_contextcallback(pa_context
*c
, void *userdata
) {
403 switch (pa_context_get_state(c
)) {
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
));
414 case PA_CONTEXT_READY
:
418 case PA_CONTEXT_FAILED
:
419 ERR("Context failed: %s\n", pa_strerror(pa_context_errno(c
)));
422 pthread_cond_signal(&pulse_cond
);
425 static HRESULT
pulse_stream_valid(ACImpl
*This
) {
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
;
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");
453 static void pulse_wr_callback(pa_stream
*s
, size_t bytes
, void *userdata
)
455 ACImpl
*This
= userdata
;
457 UINT32 oldpad
= This
->pad
;
459 if (bytes
< This
->bufsize_bytes
)
460 This
->pad
= This
->bufsize_bytes
- bytes
;
464 assert(oldpad
>= This
->pad
);
466 if (0 && This
->pad
&& pa_stream_get_time(This
->stream
, &time
) >= 0)
467 This
->clock_pulse
= time
;
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
));
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
;
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
;
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
;
507 SetEvent(This
->event
);
510 static void pulse_rd_loop(ACImpl
*This
, size_t bytes
)
512 while (bytes
>= This
->capture_period
) {
514 LARGE_INTEGER stamp
, freq
;
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
);
520 next
= (ACPacket
*)p
->entry
.next
;
523 p
= (ACPacket
*)list_tail(&This
->packet_filled_head
);
524 assert(This
->pad
== This
->bufsize_bytes
);
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
;
534 list_remove(&p
->entry
);
535 list_add_tail(&This
->packet_filled_head
, &p
->entry
);
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
;
548 memcpy(dst
, src
, rem
);
556 pa_stream_drop(This
->stream
);
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
;
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
;
584 pa_stream_drop(This
->stream
);
586 This
->peek_ofs
+= 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
)
603 pulse_rd_loop(This
, bytes
);
605 pulse_rd_drop(This
, bytes
);
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
) {
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
);
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
);
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
);
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
);
661 pa_stream_set_read_callback(This
->stream
, pulse_rd_callback
, This
);
665 HRESULT WINAPI
AUDDRV_GetEndpointIDs(EDataFlow flow
, WCHAR
***ids
, void ***keys
,
666 UINT
*num
, UINT
*def_index
)
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
);
679 *ids
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
*));
681 return E_OUTOFMEMORY
;
683 (*ids
)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW
));
685 HeapFree(GetProcessHeap(), 0, *ids
);
686 return E_OUTOFMEMORY
;
689 lstrcpyW((*ids
)[0], defaultW
);
691 *keys
= HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
697 int WINAPI
AUDDRV_GetPriority(void)
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
)
713 TRACE("%p %p %d %p\n", key
, dev
, dataflow
, out
);
714 if (dataflow
!= eRender
&& dataflow
!= eCapture
)
718 pthread_mutex_lock(&pulse_lock
);
719 hr
= pulse_connect();
720 pthread_mutex_unlock(&pulse_lock
);
724 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*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
;
736 This
->clock_pulse
= PA_USEC_INVALID
;
737 for (i
= 0; i
< PA_CHANNELS_MAX
; ++i
)
739 IMMDevice_AddRef(This
->parent
);
741 *out
= &This
->IAudioClient_iface
;
742 IAudioClient_AddRef(&This
->IAudioClient_iface
);
747 static HRESULT WINAPI
AudioClient_QueryInterface(IAudioClient
*iface
,
748 REFIID riid
, void **ppv
)
750 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
755 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClient
))
758 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
769 ref
= InterlockedIncrement(&This
->ref
);
770 TRACE("(%p) Refcount now %u\n", This
, ref
);
774 static ULONG WINAPI
AudioClient_Release(IAudioClient
*iface
)
776 ACImpl
*This
= impl_from_IAudioClient(iface
);
778 ref
= InterlockedDecrement(&This
->ref
);
779 TRACE("(%p) Refcount now %u\n", This
, ref
);
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
);
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
);
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");
807 case WAVE_FORMAT_IEEE_FLOAT
:
808 TRACE("WAVE_FORMAT_IEEE_FLOAT");
810 case WAVE_FORMAT_EXTENSIBLE
:
811 TRACE("WAVE_FORMAT_EXTENSIBLE");
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
)
839 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
840 size
= sizeof(WAVEFORMATEXTENSIBLE
);
842 size
= sizeof(WAVEFORMATEX
);
844 ret
= CoTaskMemAlloc(size
);
848 memcpy(ret
, fmt
, size
);
850 ret
->cbSize
= size
- sizeof(WAVEFORMATEX
);
855 static DWORD
get_channel_mask(unsigned int channels
)
861 return SPEAKER_FRONT_CENTER
;
863 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
;
865 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
|
866 SPEAKER_LOW_FREQUENCY
;
868 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
871 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
872 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
;
874 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
875 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
| SPEAKER_FRONT_CENTER
;
877 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
878 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
| SPEAKER_FRONT_CENTER
|
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
);
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)
898 This
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
899 pa_channel_map_init_auto(&This
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
901 case WAVE_FORMAT_PCM
:
902 if (!fmt
->nChannels
|| fmt
->nChannels
> 2)
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
);
910 case WAVE_FORMAT_EXTENSIBLE
: {
911 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)fmt
;
912 DWORD mask
= wfe
->dwChannelMask
;
914 if (fmt
->cbSize
!= (sizeof(*wfe
) - sizeof(*fmt
)) && fmt
->cbSize
!= sizeof(*wfe
))
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
;
923 valid
= fmt
->wBitsPerSample
;
924 if (!valid
|| valid
> fmt
->wBitsPerSample
)
926 switch (fmt
->wBitsPerSample
) {
929 This
->ss
.format
= PA_SAMPLE_U8
;
933 This
->ss
.format
= PA_SAMPLE_S16LE
;
937 This
->ss
.format
= PA_SAMPLE_S24LE
;
941 This
->ss
.format
= PA_SAMPLE_S24_32LE
;
942 else if (valid
== 32)
943 This
->ss
.format
= PA_SAMPLE_S32LE
;
948 This
->map
.channels
= fmt
->nChannels
;
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
) {
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
);
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
);
978 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
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
);
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
));
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
);
1017 pthread_mutex_unlock(&pulse_lock
);
1018 return AUDCLNT_E_ALREADY_INITIALIZED
;
1021 hr
= pulse_spec_from_waveformat(This
, fmt
);
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
);
1035 This
->bufsize_frames
= 2 * fmt
->nSamplesPerSec
;
1036 This
->bufsize_bytes
= This
->bufsize_frames
* pa_frame_size(&This
->ss
);
1039 This
->flags
= flags
;
1040 hr
= pulse_stream_connect(This
, period_bytes
);
1041 if (SUCCEEDED(hr
)) {
1043 const pa_buffer_attr
*attr
= pa_stream_get_buffer_attr(This
->stream
);
1044 /* Update frames according to new size */
1046 if (This
->dataflow
== eRender
)
1047 This
->bufsize_bytes
= attr
->tlength
;
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
)
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
);
1078 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
1079 This
->tmp_buffer
= NULL
;
1081 pa_stream_disconnect(This
->stream
);
1082 pa_stream_unref(This
->stream
);
1083 This
->stream
= NULL
;
1086 pthread_mutex_unlock(&pulse_lock
);
1090 static HRESULT WINAPI
AudioClient_GetBufferSize(IAudioClient
*iface
,
1093 ACImpl
*This
= impl_from_IAudioClient(iface
);
1096 TRACE("(%p)->(%p)\n", This
, out
);
1101 pthread_mutex_lock(&pulse_lock
);
1102 hr
= pulse_stream_valid(This
);
1104 *out
= This
->bufsize_frames
;
1105 pthread_mutex_unlock(&pulse_lock
);
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
;
1118 TRACE("(%p)->(%p)\n", This
, latency
);
1123 pthread_mutex_lock(&pulse_lock
);
1124 hr
= pulse_stream_valid(This
);
1126 pthread_mutex_unlock(&pulse_lock
);
1129 attr
= pa_stream_get_buffer_attr(This
->stream
);
1130 if (This
->dataflow
== eRender
)
1131 lat
= attr
->minreq
/ pa_frame_size(&This
->ss
);
1133 lat
= attr
->fragsize
/ pa_frame_size(&This
->ss
);
1134 *latency
= 10000000;
1136 *latency
/= This
->ss
.rate
;
1137 pthread_mutex_unlock(&pulse_lock
);
1138 TRACE("Latency: %u ms\n", (DWORD
)(*latency
/ 10000));
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
);
1156 *out
= This
->pad
/ pa_frame_size(&This
->ss
);
1159 static HRESULT WINAPI
AudioClient_GetCurrentPadding(IAudioClient
*iface
,
1162 ACImpl
*This
= impl_from_IAudioClient(iface
);
1165 TRACE("(%p)->(%p)\n", This
, out
);
1170 pthread_mutex_lock(&pulse_lock
);
1171 hr
= pulse_stream_valid(This
);
1173 pthread_mutex_unlock(&pulse_lock
);
1177 if (This
->dataflow
== eRender
)
1178 ACImpl_GetRenderPad(This
, out
);
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
);
1187 static HRESULT WINAPI
AudioClient_IsFormatSupported(IAudioClient
*iface
,
1188 AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*fmt
,
1191 ACImpl
*This
= impl_from_IAudioClient(iface
);
1193 WAVEFORMATEX
*closest
= NULL
;
1195 TRACE("(%p)->(%x, %p, %p)\n", This
, mode
, fmt
, out
);
1197 if (!fmt
|| (mode
== AUDCLNT_SHAREMODE_SHARED
&& !out
))
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
;
1212 closest
= clone_format(fmt
);
1216 if (hr
== S_OK
|| !out
) {
1217 CoTaskMemFree(closest
);
1220 } else if (closest
) {
1221 closest
->nBlockAlign
=
1222 closest
->nChannels
* closest
->wBitsPerSample
/ 8;
1223 closest
->nAvgBytesPerSec
=
1224 closest
->nBlockAlign
* closest
->nSamplesPerSec
;
1228 TRACE("returning: %08x %p\n", hr
, out
? *out
: NULL
);
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
);
1243 *pwfx
= clone_format(&fmt
->Format
);
1245 return E_OUTOFMEMORY
;
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
)
1261 *defperiod
= pulse_def_period
[This
->dataflow
== eCapture
];
1263 *minperiod
= pulse_min_period
[This
->dataflow
== eCapture
];
1268 static HRESULT WINAPI
AudioClient_Start(IAudioClient
*iface
)
1270 ACImpl
*This
= impl_from_IAudioClient(iface
);
1275 TRACE("(%p)\n", This
);
1277 pthread_mutex_lock(&pulse_lock
);
1278 hr
= pulse_stream_valid(This
);
1280 pthread_mutex_unlock(&pulse_lock
);
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
);
1298 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1299 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
1300 pa_operation_unref(o
);
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
);
1315 static HRESULT WINAPI
AudioClient_Stop(IAudioClient
*iface
)
1317 ACImpl
*This
= impl_from_IAudioClient(iface
);
1322 TRACE("(%p)\n", This
);
1324 pthread_mutex_lock(&pulse_lock
);
1325 hr
= pulse_stream_valid(This
);
1327 pthread_mutex_unlock(&pulse_lock
);
1331 if (!This
->started
) {
1332 pthread_mutex_unlock(&pulse_lock
);
1336 if (This
->dataflow
== eRender
) {
1337 o
= pa_stream_cork(This
->stream
, 1, pulse_op_cb
, &success
);
1339 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1340 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
1341 pa_operation_unref(o
);
1347 if (SUCCEEDED(hr
)) {
1348 This
->started
= FALSE
;
1349 This
->clock_pulse
= PA_USEC_INVALID
;
1351 pthread_mutex_unlock(&pulse_lock
);
1355 static HRESULT WINAPI
AudioClient_Reset(IAudioClient
*iface
)
1357 ACImpl
*This
= impl_from_IAudioClient(iface
);
1360 TRACE("(%p)\n", This
);
1362 pthread_mutex_lock(&pulse_lock
);
1363 hr
= pulse_stream_valid(This
);
1365 pthread_mutex_unlock(&pulse_lock
);
1369 if (This
->started
) {
1370 pthread_mutex_unlock(&pulse_lock
);
1371 return AUDCLNT_E_NOT_STOPPED
;
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 */
1383 pa_operation
*o
= pa_stream_flush(This
->stream
, pulse_op_cb
, &success
);
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;
1394 This
->clock_written
+= This
->pad
;
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
);
1408 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient
*iface
,
1411 ACImpl
*This
= impl_from_IAudioClient(iface
);
1414 TRACE("(%p)->(%p)\n", This
, event
);
1417 return E_INVALIDARG
;
1419 pthread_mutex_lock(&pulse_lock
);
1420 hr
= pulse_stream_valid(This
);
1422 pthread_mutex_unlock(&pulse_lock
);
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
);
1431 This
->event
= event
;
1432 pthread_mutex_unlock(&pulse_lock
);
1436 static HRESULT WINAPI
AudioClient_GetService(IAudioClient
*iface
, REFIID riid
,
1439 ACImpl
*This
= impl_from_IAudioClient(iface
);
1442 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1448 pthread_mutex_lock(&pulse_lock
);
1449 hr
= pulse_stream_valid(This
);
1450 pthread_mutex_unlock(&pulse_lock
);
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
;
1467 IUnknown_AddRef((IUnknown
*)*ppv
);
1471 FIXME("stub %s\n", debugstr_guid(riid
));
1472 return E_NOINTERFACE
;
1475 static const IAudioClientVtbl AudioClient_Vtbl
=
1477 AudioClient_QueryInterface
,
1479 AudioClient_Release
,
1480 AudioClient_Initialize
,
1481 AudioClient_GetBufferSize
,
1482 AudioClient_GetStreamLatency
,
1483 AudioClient_GetCurrentPadding
,
1484 AudioClient_IsFormatSupported
,
1485 AudioClient_GetMixFormat
,
1486 AudioClient_GetDevicePeriod
,
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
);
1503 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1504 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1507 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
1535 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
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
;
1548 pthread_mutex_unlock(&pulse_lock
);
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
;
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
);
1566 pa_stream_cancel_write(This
->stream
);
1567 *data
= This
->tmp_buffer
;
1568 This
->locked_ptr
= NULL
;
1570 *data
= This
->locked_ptr
;
1571 pthread_mutex_unlock(&pulse_lock
);
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
);
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
);
1602 memset(This
->tmp_buffer
, 0, written_bytes
);
1606 if (This
->locked_ptr
)
1607 pa_stream_write(This
->stream
, This
->locked_ptr
, written_bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
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
);
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
);
1635 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1636 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1639 IUnknown_AddRef((IUnknown
*)*ppv
);
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
,
1663 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1667 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
1670 if (!data
|| !frames
|| !flags
)
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
);
1684 if (packet
->discont
)
1685 *flags
|= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY
;
1687 if (packet
->discont
)
1688 *devpos
= (This
->clock_written
+ This
->capture_period
) / pa_frame_size(&This
->ss
);
1690 *devpos
= This
->clock_written
/ pa_frame_size(&This
->ss
);
1693 *qpcpos
= packet
->qpcpos
;
1694 *data
= packet
->data
;
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
;
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
;
1726 This
->clock_written
+= This
->capture_period
;
1727 list_add_tail(&This
->packet_free_head
, &packet
->entry
);
1730 pthread_mutex_unlock(&pulse_lock
);
1734 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
1735 IAudioCaptureClient
*iface
, UINT32
*frames
)
1737 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1740 TRACE("(%p)->(%p)\n", This
, frames
);
1744 pthread_mutex_lock(&pulse_lock
);
1745 ACImpl_GetCapturePad(This
, NULL
);
1746 p
= This
->locked_ptr
;
1748 *frames
= This
->capture_period
/ pa_frame_size(&This
->ss
);
1751 pthread_mutex_unlock(&pulse_lock
);
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
);
1776 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClock
))
1778 else if (IsEqualIID(riid
, &IID_IAudioClock2
))
1779 *ppv
= &This
->IAudioClock2_iface
;
1781 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
1806 TRACE("(%p)->(%p)\n", This
, freq
);
1808 pthread_mutex_lock(&pulse_lock
);
1809 hr
= pulse_stream_valid(This
);
1811 *freq
= This
->ss
.rate
* pa_frame_size(&This
->ss
);
1812 pthread_mutex_unlock(&pulse_lock
);
1816 static HRESULT WINAPI
AudioClock_GetPosition(IAudioClock
*iface
, UINT64
*pos
,
1819 ACImpl
*This
= impl_from_IAudioClock(iface
);
1823 TRACE("(%p)->(%p, %p)\n", This
, pos
, qpctime
);
1828 pthread_mutex_lock(&pulse_lock
);
1829 hr
= pulse_stream_valid(This
);
1831 pthread_mutex_unlock(&pulse_lock
);
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
)
1844 /* Make time never go backwards */
1845 if (*pos
< This
->clock_lastpos
)
1846 *pos
= This
->clock_lastpos
;
1848 This
->clock_lastpos
= *pos
;
1849 pthread_mutex_unlock(&pulse_lock
);
1851 TRACE("%p Position: %u\n", This
, (unsigned)*pos
);
1854 LARGE_INTEGER stamp
, freq
;
1855 QueryPerformanceCounter(&stamp
);
1856 QueryPerformanceFrequency(&freq
);
1857 *qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1863 static HRESULT WINAPI
AudioClock_GetCharacteristics(IAudioClock
*iface
,
1866 ACImpl
*This
= impl_from_IAudioClock(iface
);
1868 TRACE("(%p)->(%p)\n", This
, chars
);
1873 *chars
= AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ
;
1878 static const IAudioClockVtbl AudioClock_Vtbl
=
1880 AudioClock_QueryInterface
,
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
);
1913 *pos
/= pa_frame_size(&This
->ss
);
1917 static const IAudioClock2Vtbl AudioClock2_Vtbl
=
1919 AudioClock2_QueryInterface
,
1921 AudioClock2_Release
,
1922 AudioClock2_GetDevicePosition
1925 HRESULT WINAPI
AUDDRV_GetAudioSessionManager(IMMDevice
*device
,
1926 IAudioSessionManager2
**out
)