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 /* Following pulseaudio design here, mainloop has the lock taken whenever
171 * it is handling something for pulse, and the lock is required whenever
172 * doing any pa_* call that can affect the state in any way
174 * pa_cond_wait is used when waiting on results, because the mainloop needs
175 * the same lock taken to affect the state
177 * This is basically the same as the pa_threaded_mainloop implementation,
178 * but that cannot be used because it uses pthread_create directly
180 * pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock
181 * pa_threaded_mainloop_signal -> pthread_cond_signal
182 * pa_threaded_mainloop_wait -> pthread_cond_wait
185 static int pulse_poll_func(struct pollfd
*ufds
, unsigned long nfds
, int timeout
, void *userdata
) {
187 pthread_mutex_unlock(&pulse_lock
);
188 r
= poll(ufds
, nfds
, timeout
);
189 pthread_mutex_lock(&pulse_lock
);
193 static DWORD CALLBACK
pulse_mainloop_thread(void *tmp
) {
195 pulse_ml
= pa_mainloop_new();
196 pa_mainloop_set_poll_func(pulse_ml
, pulse_poll_func
, NULL
);
197 pthread_mutex_lock(&pulse_lock
);
198 pthread_cond_signal(&pulse_cond
);
199 pa_mainloop_run(pulse_ml
, &ret
);
200 pthread_mutex_unlock(&pulse_lock
);
201 pa_mainloop_free(pulse_ml
);
202 CloseHandle(pulse_thread
);
206 static void pulse_contextcallback(pa_context
*c
, void *userdata
);
207 static void pulse_stream_state(pa_stream
*s
, void *user
);
209 static const enum pa_channel_position pulse_pos_from_wfx
[] = {
210 PA_CHANNEL_POSITION_FRONT_LEFT
,
211 PA_CHANNEL_POSITION_FRONT_RIGHT
,
212 PA_CHANNEL_POSITION_FRONT_CENTER
,
213 PA_CHANNEL_POSITION_LFE
,
214 PA_CHANNEL_POSITION_REAR_LEFT
,
215 PA_CHANNEL_POSITION_REAR_RIGHT
,
216 PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
,
217 PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
,
218 PA_CHANNEL_POSITION_REAR_CENTER
,
219 PA_CHANNEL_POSITION_SIDE_LEFT
,
220 PA_CHANNEL_POSITION_SIDE_RIGHT
,
221 PA_CHANNEL_POSITION_TOP_CENTER
,
222 PA_CHANNEL_POSITION_TOP_FRONT_LEFT
,
223 PA_CHANNEL_POSITION_TOP_FRONT_CENTER
,
224 PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
,
225 PA_CHANNEL_POSITION_TOP_REAR_LEFT
,
226 PA_CHANNEL_POSITION_TOP_REAR_CENTER
,
227 PA_CHANNEL_POSITION_TOP_REAR_RIGHT
230 static void pulse_probe_settings(int render
, WAVEFORMATEXTENSIBLE
*fmt
) {
231 WAVEFORMATEX
*wfx
= &fmt
->Format
;
237 unsigned int length
= 0;
239 pa_channel_map_init_auto(&map
, 2, PA_CHANNEL_MAP_ALSA
);
241 ss
.format
= PA_SAMPLE_FLOAT32LE
;
242 ss
.channels
= map
.channels
;
246 attr
.minreq
= attr
.fragsize
= pa_frame_size(&ss
);
249 stream
= pa_stream_new(pulse_ctx
, "format test stream", &ss
, &map
);
251 pa_stream_set_state_callback(stream
, pulse_stream_state
, NULL
);
255 ret
= pa_stream_connect_playback(stream
, NULL
, &attr
,
256 PA_STREAM_START_CORKED
|PA_STREAM_FIX_RATE
|PA_STREAM_FIX_CHANNELS
|PA_STREAM_EARLY_REQUESTS
, NULL
, NULL
);
258 ret
= pa_stream_connect_record(stream
, NULL
, &attr
, PA_STREAM_START_CORKED
|PA_STREAM_FIX_RATE
|PA_STREAM_FIX_CHANNELS
|PA_STREAM_EARLY_REQUESTS
);
260 while (pa_stream_get_state(stream
) == PA_STREAM_CREATING
)
261 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
262 if (pa_stream_get_state(stream
) == PA_STREAM_READY
) {
263 ss
= *pa_stream_get_sample_spec(stream
);
264 map
= *pa_stream_get_channel_map(stream
);
266 length
= pa_stream_get_buffer_attr(stream
)->minreq
;
268 length
= pa_stream_get_buffer_attr(stream
)->fragsize
;
269 pa_stream_disconnect(stream
);
270 while (pa_stream_get_state(stream
) == PA_STREAM_READY
)
271 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
275 pa_stream_unref(stream
);
277 pulse_def_period
[!render
] = pulse_min_period
[!render
] = pa_bytes_to_usec(10 * length
, &ss
);
279 pulse_min_period
[!render
] = MinimumPeriod
;
280 if (pulse_def_period
[!render
] <= DefaultPeriod
)
281 pulse_def_period
[!render
] = DefaultPeriod
;
283 wfx
->wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
284 wfx
->cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
285 wfx
->nChannels
= ss
.channels
;
286 wfx
->wBitsPerSample
= 8 * pa_sample_size_of_format(ss
.format
);
287 wfx
->nSamplesPerSec
= ss
.rate
;
288 wfx
->nBlockAlign
= pa_frame_size(&ss
);
289 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
290 if (ss
.format
!= PA_SAMPLE_S24_32LE
)
291 fmt
->Samples
.wValidBitsPerSample
= wfx
->wBitsPerSample
;
293 fmt
->Samples
.wValidBitsPerSample
= 24;
294 if (ss
.format
== PA_SAMPLE_FLOAT32LE
)
295 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
297 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
299 fmt
->dwChannelMask
= 0;
300 for (i
= 0; i
< map
.channels
; ++i
)
301 switch (map
.map
[i
]) {
302 default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map
.map
[i
])); break;
303 case PA_CHANNEL_POSITION_FRONT_LEFT
: fmt
->dwChannelMask
|= SPEAKER_FRONT_LEFT
; break;
304 case PA_CHANNEL_POSITION_MONO
:
305 case PA_CHANNEL_POSITION_FRONT_CENTER
: fmt
->dwChannelMask
|= SPEAKER_FRONT_CENTER
; break;
306 case PA_CHANNEL_POSITION_FRONT_RIGHT
: fmt
->dwChannelMask
|= SPEAKER_FRONT_RIGHT
; break;
307 case PA_CHANNEL_POSITION_REAR_LEFT
: fmt
->dwChannelMask
|= SPEAKER_BACK_LEFT
; break;
308 case PA_CHANNEL_POSITION_REAR_CENTER
: fmt
->dwChannelMask
|= SPEAKER_BACK_CENTER
; break;
309 case PA_CHANNEL_POSITION_REAR_RIGHT
: fmt
->dwChannelMask
|= SPEAKER_BACK_RIGHT
; break;
310 case PA_CHANNEL_POSITION_LFE
: fmt
->dwChannelMask
|= SPEAKER_LOW_FREQUENCY
; break;
311 case PA_CHANNEL_POSITION_SIDE_LEFT
: fmt
->dwChannelMask
|= SPEAKER_SIDE_LEFT
; break;
312 case PA_CHANNEL_POSITION_SIDE_RIGHT
: fmt
->dwChannelMask
|= SPEAKER_SIDE_RIGHT
; break;
313 case PA_CHANNEL_POSITION_TOP_CENTER
: fmt
->dwChannelMask
|= SPEAKER_TOP_CENTER
; break;
314 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT
: fmt
->dwChannelMask
|= SPEAKER_TOP_FRONT_LEFT
; break;
315 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER
: fmt
->dwChannelMask
|= SPEAKER_TOP_FRONT_CENTER
; break;
316 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
: fmt
->dwChannelMask
|= SPEAKER_TOP_FRONT_RIGHT
; break;
317 case PA_CHANNEL_POSITION_TOP_REAR_LEFT
: fmt
->dwChannelMask
|= SPEAKER_TOP_BACK_LEFT
; break;
318 case PA_CHANNEL_POSITION_TOP_REAR_CENTER
: fmt
->dwChannelMask
|= SPEAKER_TOP_BACK_CENTER
; break;
319 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT
: fmt
->dwChannelMask
|= SPEAKER_TOP_BACK_RIGHT
; break;
323 static HRESULT
pulse_connect(void)
326 WCHAR path
[PATH_MAX
], *name
;
331 if (!(pulse_thread
= CreateThread(NULL
, 0, pulse_mainloop_thread
, NULL
, 0, NULL
)))
333 ERR("Failed to create mainloop thread.");
336 SetThreadPriority(pulse_thread
, THREAD_PRIORITY_TIME_CRITICAL
);
337 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
340 if (pulse_ctx
&& PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx
)))
343 pa_context_unref(pulse_ctx
);
345 GetModuleFileNameW(NULL
, path
, sizeof(path
)/sizeof(*path
));
346 name
= strrchrW(path
, '\\');
351 len
= WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
352 str
= pa_xmalloc(len
);
353 WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, str
, len
, NULL
, NULL
);
354 TRACE("Name: %s\n", str
);
355 pulse_ctx
= pa_context_new(pa_mainloop_get_api(pulse_ml
), str
);
358 ERR("Failed to create context\n");
362 pa_context_set_state_callback(pulse_ctx
, pulse_contextcallback
, NULL
);
364 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx
), PA_API_VERSION
);
365 if (pa_context_connect(pulse_ctx
, NULL
, 0, NULL
) < 0)
368 /* Wait for connection */
369 while (pthread_cond_wait(&pulse_cond
, &pulse_lock
)) {
370 pa_context_state_t state
= pa_context_get_state(pulse_ctx
);
372 if (state
== PA_CONTEXT_FAILED
|| state
== PA_CONTEXT_TERMINATED
)
375 if (state
== PA_CONTEXT_READY
)
379 TRACE("Connected to server %s with protocol version: %i.\n",
380 pa_context_get_server(pulse_ctx
),
381 pa_context_get_server_protocol_version(pulse_ctx
));
382 pulse_probe_settings(1, &pulse_fmt
[0]);
383 pulse_probe_settings(0, &pulse_fmt
[1]);
387 pa_context_unref(pulse_ctx
);
392 static void pulse_contextcallback(pa_context
*c
, void *userdata
) {
393 switch (pa_context_get_state(c
)) {
395 FIXME("Unhandled state: %i\n", pa_context_get_state(c
));
396 case PA_CONTEXT_CONNECTING
:
397 case PA_CONTEXT_UNCONNECTED
:
398 case PA_CONTEXT_AUTHORIZING
:
399 case PA_CONTEXT_SETTING_NAME
:
400 case PA_CONTEXT_TERMINATED
:
401 TRACE("State change to %i\n", pa_context_get_state(c
));
404 case PA_CONTEXT_READY
:
408 case PA_CONTEXT_FAILED
:
409 ERR("Context failed: %s\n", pa_strerror(pa_context_errno(c
)));
412 pthread_cond_signal(&pulse_cond
);
415 static HRESULT
pulse_stream_valid(ACImpl
*This
) {
417 return AUDCLNT_E_NOT_INITIALIZED
;
418 if (!This
->stream
|| pa_stream_get_state(This
->stream
) != PA_STREAM_READY
)
419 return AUDCLNT_E_DEVICE_INVALIDATED
;
423 static void dump_attr(const pa_buffer_attr
*attr
) {
424 TRACE("maxlength: %u\n", attr
->maxlength
);
425 TRACE("minreq: %u\n", attr
->minreq
);
426 TRACE("fragsize: %u\n", attr
->fragsize
);
427 TRACE("tlength: %u\n", attr
->tlength
);
428 TRACE("prebuf: %u\n", attr
->prebuf
);
431 static void pulse_op_cb(pa_stream
*s
, int success
, void *user
) {
432 TRACE("Success: %i\n", success
);
433 *(int*)user
= success
;
434 pthread_cond_signal(&pulse_cond
);
437 static void pulse_attr_update(pa_stream
*s
, void *user
) {
438 const pa_buffer_attr
*attr
= pa_stream_get_buffer_attr(s
);
439 TRACE("New attributes or device moved:\n");
443 static void pulse_wr_callback(pa_stream
*s
, size_t bytes
, void *userdata
)
445 ACImpl
*This
= userdata
;
447 UINT32 oldpad
= This
->pad
;
449 if (bytes
< This
->bufsize_bytes
)
450 This
->pad
= This
->bufsize_bytes
- bytes
;
454 assert(oldpad
>= This
->pad
);
456 if (0 && This
->pad
&& pa_stream_get_time(This
->stream
, &time
) >= 0)
457 This
->clock_pulse
= time
;
459 This
->clock_pulse
= PA_USEC_INVALID
;
461 This
->clock_written
+= oldpad
- This
->pad
;
462 TRACE("New pad: %u (-%u)\n", This
->pad
/ pa_frame_size(&This
->ss
), (oldpad
- This
->pad
) / pa_frame_size(&This
->ss
));
465 SetEvent(This
->event
);
468 static void pulse_underflow_callback(pa_stream
*s
, void *userdata
)
470 ACImpl
*This
= userdata
;
471 This
->clock_pulse
= PA_USEC_INVALID
;
475 /* Latency is periodically updated even when nothing is played,
476 * because of PA_STREAM_AUTO_TIMING_UPDATE so use it as timer
478 * Perfect for passing all tests :)
480 static void pulse_latency_callback(pa_stream
*s
, void *userdata
)
482 ACImpl
*This
= userdata
;
483 if (!This
->pad
&& This
->event
)
484 SetEvent(This
->event
);
487 static void pulse_started_callback(pa_stream
*s
, void *userdata
)
489 ACImpl
*This
= userdata
;
492 TRACE("(Re)started playing\n");
493 assert(This
->clock_pulse
== PA_USEC_INVALID
);
494 if (0 && pa_stream_get_time(This
->stream
, &time
) >= 0)
495 This
->clock_pulse
= time
;
497 SetEvent(This
->event
);
500 static void pulse_rd_loop(ACImpl
*This
, size_t bytes
)
502 while (bytes
>= This
->capture_period
) {
504 LARGE_INTEGER stamp
, freq
;
506 UINT32 src_len
, copy
, rem
= This
->capture_period
;
507 if (!(p
= (ACPacket
*)list_head(&This
->packet_free_head
))) {
508 p
= (ACPacket
*)list_head(&This
->packet_filled_head
);
510 next
= (ACPacket
*)p
->entry
.next
;
513 p
= (ACPacket
*)list_tail(&This
->packet_filled_head
);
514 assert(This
->pad
== This
->bufsize_bytes
);
516 assert(This
->pad
< This
->bufsize_bytes
);
517 This
->pad
+= This
->capture_period
;
518 assert(This
->pad
<= This
->bufsize_bytes
);
520 QueryPerformanceCounter(&stamp
);
521 QueryPerformanceFrequency(&freq
);
522 p
->qpcpos
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
524 list_remove(&p
->entry
);
525 list_add_tail(&This
->packet_filled_head
, &p
->entry
);
529 pa_stream_peek(This
->stream
, (const void**)&src
, &src_len
);
530 assert(src_len
&& src_len
<= bytes
);
531 assert(This
->peek_ofs
< src_len
);
532 src
+= This
->peek_ofs
;
533 src_len
-= This
->peek_ofs
;
538 memcpy(dst
, src
, rem
);
546 pa_stream_drop(This
->stream
);
548 This
->peek_ofs
+= copy
;
550 bytes
-= This
->capture_period
;
554 static void pulse_rd_drop(ACImpl
*This
, size_t bytes
)
556 while (bytes
>= This
->capture_period
) {
557 UINT32 src_len
, copy
, rem
= This
->capture_period
;
560 pa_stream_peek(This
->stream
, &src
, &src_len
);
561 assert(src_len
&& src_len
<= bytes
);
562 assert(This
->peek_ofs
< src_len
);
563 src_len
-= This
->peek_ofs
;
574 pa_stream_drop(This
->stream
);
576 This
->peek_ofs
+= copy
;
582 static void pulse_rd_callback(pa_stream
*s
, size_t bytes
, void *userdata
)
584 ACImpl
*This
= userdata
;
586 TRACE("Readable total: %u, fragsize: %u\n", bytes
, pa_stream_get_buffer_attr(s
)->fragsize
);
587 assert(bytes
>= This
->peek_ofs
);
588 bytes
-= This
->peek_ofs
;
589 if (bytes
< This
->capture_period
)
593 pulse_rd_loop(This
, bytes
);
595 pulse_rd_drop(This
, bytes
);
598 SetEvent(This
->event
);
601 static void pulse_stream_state(pa_stream
*s
, void *user
)
603 pa_stream_state_t state
= pa_stream_get_state(s
);
604 TRACE("Stream state changed to %i\n", state
);
605 pthread_cond_signal(&pulse_cond
);
608 static HRESULT
pulse_stream_connect(ACImpl
*This
, UINT32 period_bytes
) {
614 pa_stream_disconnect(This
->stream
);
615 while (pa_stream_get_state(This
->stream
) == PA_STREAM_READY
)
616 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
617 pa_stream_unref(This
->stream
);
619 ret
= InterlockedIncrement(&number
);
620 sprintf(buffer
, "audio stream #%i", ret
);
621 This
->stream
= pa_stream_new(pulse_ctx
, buffer
, &This
->ss
, &This
->map
);
622 pa_stream_set_state_callback(This
->stream
, pulse_stream_state
, This
);
623 pa_stream_set_buffer_attr_callback(This
->stream
, pulse_attr_update
, This
);
624 pa_stream_set_moved_callback(This
->stream
, pulse_attr_update
, This
);
626 /* Pulseaudio will fill in correct values */
627 attr
.minreq
= attr
.fragsize
= period_bytes
;
628 attr
.maxlength
= attr
.tlength
= This
->bufsize_bytes
;
629 attr
.prebuf
= pa_frame_size(&This
->ss
);
631 if (This
->dataflow
== eRender
)
632 ret
= pa_stream_connect_playback(This
->stream
, NULL
, &attr
,
633 PA_STREAM_START_CORKED
|PA_STREAM_START_UNMUTED
|PA_STREAM_AUTO_TIMING_UPDATE
|PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_EARLY_REQUESTS
, NULL
, NULL
);
635 ret
= pa_stream_connect_record(This
->stream
, NULL
, &attr
,
636 PA_STREAM_START_CORKED
|PA_STREAM_START_UNMUTED
|PA_STREAM_AUTO_TIMING_UPDATE
|PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_EARLY_REQUESTS
);
638 WARN("Returns %i\n", ret
);
639 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
641 while (pa_stream_get_state(This
->stream
) == PA_STREAM_CREATING
)
642 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
643 if (pa_stream_get_state(This
->stream
) != PA_STREAM_READY
)
644 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
646 if (This
->dataflow
== eRender
) {
647 pa_stream_set_write_callback(This
->stream
, pulse_wr_callback
, This
);
648 pa_stream_set_underflow_callback(This
->stream
, pulse_underflow_callback
, This
);
649 pa_stream_set_started_callback(This
->stream
, pulse_started_callback
, This
);
651 pa_stream_set_read_callback(This
->stream
, pulse_rd_callback
, This
);
655 HRESULT WINAPI
AUDDRV_GetEndpointIDs(EDataFlow flow
, WCHAR
***ids
, void ***keys
,
656 UINT
*num
, UINT
*def_index
)
659 TRACE("%d %p %p %p\n", flow
, ids
, num
, def_index
);
661 pthread_mutex_lock(&pulse_lock
);
662 hr
= pulse_connect();
663 pthread_mutex_unlock(&pulse_lock
);
669 *ids
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
*));
671 return E_OUTOFMEMORY
;
673 (*ids
)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW
));
675 HeapFree(GetProcessHeap(), 0, *ids
);
676 return E_OUTOFMEMORY
;
679 lstrcpyW((*ids
)[0], defaultW
);
681 *keys
= HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
687 int WINAPI
AUDDRV_GetPriority(void)
690 pthread_mutex_lock(&pulse_lock
);
691 hr
= pulse_connect();
692 pthread_mutex_unlock(&pulse_lock
);
693 return SUCCEEDED(hr
) ? 3 : 0;
696 HRESULT WINAPI
AUDDRV_GetAudioEndpoint(void *key
, IMMDevice
*dev
,
697 EDataFlow dataflow
, IAudioClient
**out
)
703 TRACE("%p %p %d %p\n", key
, dev
, dataflow
, out
);
704 if (dataflow
!= eRender
&& dataflow
!= eCapture
)
708 pthread_mutex_lock(&pulse_lock
);
709 hr
= pulse_connect();
710 pthread_mutex_unlock(&pulse_lock
);
714 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
));
716 return E_OUTOFMEMORY
;
718 This
->IAudioClient_iface
.lpVtbl
= &AudioClient_Vtbl
;
719 This
->IAudioRenderClient_iface
.lpVtbl
= &AudioRenderClient_Vtbl
;
720 This
->IAudioCaptureClient_iface
.lpVtbl
= &AudioCaptureClient_Vtbl
;
721 This
->IAudioClock_iface
.lpVtbl
= &AudioClock_Vtbl
;
722 This
->IAudioClock2_iface
.lpVtbl
= &AudioClock2_Vtbl
;
723 This
->IAudioStreamVolume_iface
.lpVtbl
= &AudioStreamVolume_Vtbl
;
724 This
->dataflow
= dataflow
;
726 This
->clock_pulse
= PA_USEC_INVALID
;
727 for (i
= 0; i
< PA_CHANNELS_MAX
; ++i
)
729 IMMDevice_AddRef(This
->parent
);
731 *out
= &This
->IAudioClient_iface
;
732 IAudioClient_AddRef(&This
->IAudioClient_iface
);
737 static HRESULT WINAPI
AudioClient_QueryInterface(IAudioClient
*iface
,
738 REFIID riid
, void **ppv
)
740 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
745 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IAudioClient
))
748 IUnknown_AddRef((IUnknown
*)*ppv
);
751 WARN("Unknown interface %s\n", debugstr_guid(riid
));
752 return E_NOINTERFACE
;
755 static ULONG WINAPI
AudioClient_AddRef(IAudioClient
*iface
)
757 ACImpl
*This
= impl_from_IAudioClient(iface
);
759 ref
= InterlockedIncrement(&This
->ref
);
760 TRACE("(%p) Refcount now %u\n", This
, ref
);
764 static ULONG WINAPI
AudioClient_Release(IAudioClient
*iface
)
766 ACImpl
*This
= impl_from_IAudioClient(iface
);
768 ref
= InterlockedDecrement(&This
->ref
);
769 TRACE("(%p) Refcount now %u\n", This
, ref
);
772 pthread_mutex_lock(&pulse_lock
);
773 if (PA_STREAM_IS_GOOD(pa_stream_get_state(This
->stream
))) {
774 pa_stream_disconnect(This
->stream
);
775 while (PA_STREAM_IS_GOOD(pa_stream_get_state(This
->stream
)))
776 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
778 pa_stream_unref(This
->stream
);
780 list_remove(&This
->entry
);
781 pthread_mutex_unlock(&pulse_lock
);
783 IMMDevice_Release(This
->parent
);
784 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
785 HeapFree(GetProcessHeap(), 0, This
);
790 static void dump_fmt(const WAVEFORMATEX
*fmt
)
792 TRACE("wFormatTag: 0x%x (", fmt
->wFormatTag
);
793 switch(fmt
->wFormatTag
) {
794 case WAVE_FORMAT_PCM
:
795 TRACE("WAVE_FORMAT_PCM");
797 case WAVE_FORMAT_IEEE_FLOAT
:
798 TRACE("WAVE_FORMAT_IEEE_FLOAT");
800 case WAVE_FORMAT_EXTENSIBLE
:
801 TRACE("WAVE_FORMAT_EXTENSIBLE");
809 TRACE("nChannels: %u\n", fmt
->nChannels
);
810 TRACE("nSamplesPerSec: %u\n", fmt
->nSamplesPerSec
);
811 TRACE("nAvgBytesPerSec: %u\n", fmt
->nAvgBytesPerSec
);
812 TRACE("nBlockAlign: %u\n", fmt
->nBlockAlign
);
813 TRACE("wBitsPerSample: %u\n", fmt
->wBitsPerSample
);
814 TRACE("cbSize: %u\n", fmt
->cbSize
);
816 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
817 WAVEFORMATEXTENSIBLE
*fmtex
= (void*)fmt
;
818 TRACE("dwChannelMask: %08x\n", fmtex
->dwChannelMask
);
819 TRACE("Samples: %04x\n", fmtex
->Samples
.wReserved
);
820 TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex
->SubFormat
));
824 static WAVEFORMATEX
*clone_format(const WAVEFORMATEX
*fmt
)
829 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
830 size
= sizeof(WAVEFORMATEXTENSIBLE
);
832 size
= sizeof(WAVEFORMATEX
);
834 ret
= CoTaskMemAlloc(size
);
838 memcpy(ret
, fmt
, size
);
840 ret
->cbSize
= size
- sizeof(WAVEFORMATEX
);
845 static DWORD
get_channel_mask(unsigned int channels
)
851 return SPEAKER_FRONT_CENTER
;
853 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
;
855 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
|
856 SPEAKER_LOW_FREQUENCY
;
858 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
861 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
862 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
;
864 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
865 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
| SPEAKER_FRONT_CENTER
;
867 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
868 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
| SPEAKER_FRONT_CENTER
|
871 return SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT
|
872 SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY
| SPEAKER_FRONT_CENTER
|
873 SPEAKER_SIDE_LEFT
| SPEAKER_SIDE_RIGHT
;
875 FIXME("Unknown speaker configuration: %u\n", channels
);
879 static HRESULT
pulse_spec_from_waveformat(ACImpl
*This
, const WAVEFORMATEX
*fmt
)
881 pa_channel_map_init(&This
->map
);
882 This
->ss
.rate
= fmt
->nSamplesPerSec
;
883 This
->ss
.format
= PA_SAMPLE_INVALID
;
884 switch(fmt
->wFormatTag
) {
885 case WAVE_FORMAT_IEEE_FLOAT
:
886 if (!fmt
->nChannels
|| fmt
->nChannels
> 2 || fmt
->wBitsPerSample
!= 32)
888 This
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
889 pa_channel_map_init_auto(&This
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
891 case WAVE_FORMAT_PCM
:
892 if (!fmt
->nChannels
|| fmt
->nChannels
> 2)
894 if (fmt
->wBitsPerSample
== 8)
895 This
->ss
.format
= PA_SAMPLE_U8
;
896 else if (fmt
->wBitsPerSample
== 16)
897 This
->ss
.format
= PA_SAMPLE_S16LE
;
898 pa_channel_map_init_auto(&This
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
900 case WAVE_FORMAT_EXTENSIBLE
: {
901 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)fmt
;
902 DWORD mask
= wfe
->dwChannelMask
;
904 if (fmt
->cbSize
!= (sizeof(*wfe
) - sizeof(*fmt
)) && fmt
->cbSize
!= sizeof(*wfe
))
906 if (IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
907 (!wfe
->Samples
.wValidBitsPerSample
|| wfe
->Samples
.wValidBitsPerSample
== 32) &&
908 fmt
->wBitsPerSample
== 32)
909 This
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
910 else if (IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
911 DWORD valid
= wfe
->Samples
.wValidBitsPerSample
;
913 valid
= fmt
->wBitsPerSample
;
914 if (!valid
|| valid
> fmt
->wBitsPerSample
)
916 switch (fmt
->wBitsPerSample
) {
919 This
->ss
.format
= PA_SAMPLE_U8
;
923 This
->ss
.format
= PA_SAMPLE_S16LE
;
927 This
->ss
.format
= PA_SAMPLE_S24LE
;
931 This
->ss
.format
= PA_SAMPLE_S24_32LE
;
932 else if (valid
== 32)
933 This
->ss
.format
= PA_SAMPLE_S32LE
;
938 This
->map
.channels
= fmt
->nChannels
;
940 mask
= get_channel_mask(fmt
->nChannels
);
941 for (j
= 0; j
< sizeof(pulse_pos_from_wfx
)/sizeof(*pulse_pos_from_wfx
) && i
< fmt
->nChannels
; ++j
) {
943 This
->map
.map
[i
++] = pulse_pos_from_wfx
[j
];
946 /* Special case for mono since pulse appears to map it differently */
947 if (mask
== SPEAKER_FRONT_CENTER
)
948 This
->map
.map
[0] = PA_CHANNEL_POSITION_MONO
;
950 if ((mask
& SPEAKER_ALL
) && i
< fmt
->nChannels
) {
951 This
->map
.map
[i
++] = PA_CHANNEL_POSITION_MONO
;
952 FIXME("Is the 'all' channel mapped correctly?\n");
955 if (i
< fmt
->nChannels
|| (mask
& SPEAKER_RESERVED
)) {
956 This
->map
.channels
= 0;
957 ERR("Invalid channel mask: %i/%i and %x\n", i
, fmt
->nChannels
, mask
);
962 default: FIXME("Unhandled tag %x\n", fmt
->wFormatTag
);
964 This
->ss
.channels
= This
->map
.channels
;
965 if (!pa_channel_map_valid(&This
->map
) || This
->ss
.format
== PA_SAMPLE_INVALID
) {
966 ERR("Invalid format! Channel spec valid: %i, format: %i\n", pa_channel_map_valid(&This
->map
), This
->ss
.format
);
968 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
973 static HRESULT WINAPI
AudioClient_Initialize(IAudioClient
*iface
,
974 AUDCLNT_SHAREMODE mode
, DWORD flags
, REFERENCE_TIME duration
,
975 REFERENCE_TIME period
, const WAVEFORMATEX
*fmt
,
976 const GUID
*sessionguid
)
978 ACImpl
*This
= impl_from_IAudioClient(iface
);
982 TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This
, mode
, flags
,
983 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(period
), fmt
, debugstr_guid(sessionguid
));
988 if (mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
989 return AUDCLNT_E_NOT_INITIALIZED
;
990 if (mode
== AUDCLNT_SHAREMODE_EXCLUSIVE
)
991 return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
993 if (flags
& ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS
|
994 AUDCLNT_STREAMFLAGS_LOOPBACK
|
995 AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
996 AUDCLNT_STREAMFLAGS_NOPERSIST
|
997 AUDCLNT_STREAMFLAGS_RATEADJUST
|
998 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED
|
999 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE
|
1000 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED
)) {
1001 TRACE("Unknown flags: %08x\n", flags
);
1002 return E_INVALIDARG
;
1005 pthread_mutex_lock(&pulse_lock
);
1007 pthread_mutex_unlock(&pulse_lock
);
1008 return AUDCLNT_E_ALREADY_INITIALIZED
;
1011 hr
= pulse_spec_from_waveformat(This
, fmt
);
1015 if (mode
== AUDCLNT_SHAREMODE_SHARED
) {
1016 period
= pulse_def_period
[This
->dataflow
== eCapture
];
1017 if (duration
< 2 * period
)
1018 duration
= 2 * period
;
1020 period_bytes
= pa_frame_size(&This
->ss
) * MulDiv(period
, This
->ss
.rate
, 10000000);
1022 if (duration
< 20000000)
1023 This
->bufsize_frames
= ceil((duration
/ 10000000.) * fmt
->nSamplesPerSec
);
1025 This
->bufsize_frames
= 2 * fmt
->nSamplesPerSec
;
1026 This
->bufsize_bytes
= This
->bufsize_frames
* pa_frame_size(&This
->ss
);
1029 This
->flags
= flags
;
1030 hr
= pulse_stream_connect(This
, period_bytes
);
1031 if (SUCCEEDED(hr
)) {
1033 const pa_buffer_attr
*attr
= pa_stream_get_buffer_attr(This
->stream
);
1034 /* Update frames according to new size */
1036 if (This
->dataflow
== eRender
)
1037 This
->bufsize_bytes
= attr
->tlength
;
1039 This
->capture_period
= period_bytes
= attr
->fragsize
;
1040 if ((unalign
= This
->bufsize_bytes
% period_bytes
))
1041 This
->bufsize_bytes
+= period_bytes
- unalign
;
1043 This
->bufsize_frames
= This
->bufsize_bytes
/ pa_frame_size(&This
->ss
);
1045 if (SUCCEEDED(hr
)) {
1046 UINT32 i
, capture_packets
= This
->capture_period
? This
->bufsize_bytes
/ This
->capture_period
: 0;
1047 This
->tmp_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->bufsize_bytes
+ capture_packets
* sizeof(ACPacket
));
1048 if (!This
->tmp_buffer
)
1051 ACPacket
*cur_packet
= (ACPacket
*)((char*)This
->tmp_buffer
+ This
->bufsize_bytes
);
1052 BYTE
*data
= This
->tmp_buffer
;
1053 memset(This
->tmp_buffer
, This
->ss
.format
== PA_SAMPLE_U8
? 0x80 : 0, This
->bufsize_bytes
);
1054 list_init(&This
->packet_free_head
);
1055 list_init(&This
->packet_filled_head
);
1056 for (i
= 0; i
< capture_packets
; ++i
, ++cur_packet
) {
1057 list_add_tail(&This
->packet_free_head
, &cur_packet
->entry
);
1058 cur_packet
->data
= data
;
1059 data
+= This
->capture_period
;
1061 assert(!This
->capture_period
|| This
->bufsize_bytes
== This
->capture_period
* capture_packets
);
1062 assert(!capture_packets
|| data
- This
->bufsize_bytes
== This
->tmp_buffer
);
1068 HeapFree(GetProcessHeap(), 0, This
->tmp_buffer
);
1069 This
->tmp_buffer
= NULL
;
1071 pa_stream_disconnect(This
->stream
);
1072 pa_stream_unref(This
->stream
);
1073 This
->stream
= NULL
;
1076 pthread_mutex_unlock(&pulse_lock
);
1080 static HRESULT WINAPI
AudioClient_GetBufferSize(IAudioClient
*iface
,
1083 ACImpl
*This
= impl_from_IAudioClient(iface
);
1086 TRACE("(%p)->(%p)\n", This
, out
);
1091 pthread_mutex_lock(&pulse_lock
);
1092 hr
= pulse_stream_valid(This
);
1094 *out
= This
->bufsize_frames
;
1095 pthread_mutex_unlock(&pulse_lock
);
1100 static HRESULT WINAPI
AudioClient_GetStreamLatency(IAudioClient
*iface
,
1101 REFERENCE_TIME
*latency
)
1103 ACImpl
*This
= impl_from_IAudioClient(iface
);
1104 const pa_buffer_attr
*attr
;
1108 TRACE("(%p)->(%p)\n", This
, latency
);
1113 pthread_mutex_lock(&pulse_lock
);
1114 hr
= pulse_stream_valid(This
);
1116 pthread_mutex_unlock(&pulse_lock
);
1119 attr
= pa_stream_get_buffer_attr(This
->stream
);
1120 if (This
->dataflow
== eRender
)
1121 lat
= attr
->minreq
/ pa_frame_size(&This
->ss
);
1123 lat
= attr
->fragsize
/ pa_frame_size(&This
->ss
);
1124 *latency
= 10000000;
1126 *latency
/= This
->ss
.rate
;
1127 pthread_mutex_unlock(&pulse_lock
);
1128 TRACE("Latency: %u ms\n", (DWORD
)(*latency
/ 10000));
1132 static void ACImpl_GetRenderPad(ACImpl
*This
, UINT32
*out
)
1134 *out
= This
->pad
/ pa_frame_size(&This
->ss
);
1137 static void ACImpl_GetCapturePad(ACImpl
*This
, UINT32
*out
)
1139 ACPacket
*packet
= This
->locked_ptr
;
1140 if (!packet
&& !list_empty(&This
->packet_filled_head
)) {
1141 packet
= (ACPacket
*)list_head(&This
->packet_filled_head
);
1142 This
->locked_ptr
= packet
;
1143 list_remove(&packet
->entry
);
1146 *out
= This
->pad
/ pa_frame_size(&This
->ss
);
1149 static HRESULT WINAPI
AudioClient_GetCurrentPadding(IAudioClient
*iface
,
1152 ACImpl
*This
= impl_from_IAudioClient(iface
);
1155 TRACE("(%p)->(%p)\n", This
, out
);
1160 pthread_mutex_lock(&pulse_lock
);
1161 hr
= pulse_stream_valid(This
);
1163 pthread_mutex_unlock(&pulse_lock
);
1167 if (This
->dataflow
== eRender
)
1168 ACImpl_GetRenderPad(This
, out
);
1170 ACImpl_GetCapturePad(This
, out
);
1171 pthread_mutex_unlock(&pulse_lock
);
1173 TRACE("%p Pad: %u ms (%u)\n", This
, MulDiv(*out
, 1000, This
->ss
.rate
), *out
);
1177 static HRESULT WINAPI
AudioClient_IsFormatSupported(IAudioClient
*iface
,
1178 AUDCLNT_SHAREMODE mode
, const WAVEFORMATEX
*fmt
,
1181 ACImpl
*This
= impl_from_IAudioClient(iface
);
1183 WAVEFORMATEX
*closest
= NULL
;
1185 TRACE("(%p)->(%x, %p, %p)\n", This
, mode
, fmt
, out
);
1187 if (!fmt
|| (mode
== AUDCLNT_SHAREMODE_SHARED
&& !out
))
1192 if (mode
!= AUDCLNT_SHAREMODE_SHARED
&& mode
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
1193 return E_INVALIDARG
;
1194 if (mode
== AUDCLNT_SHAREMODE_EXCLUSIVE
)
1195 return This
->dataflow
== eCapture
? AUDCLNT_E_UNSUPPORTED_FORMAT
: AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
1196 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
&&
1197 fmt
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
))
1198 return E_INVALIDARG
;
1202 closest
= clone_format(fmt
);
1206 if (hr
== S_OK
|| !out
) {
1207 CoTaskMemFree(closest
);
1210 } else if (closest
) {
1211 closest
->nBlockAlign
=
1212 closest
->nChannels
* closest
->wBitsPerSample
/ 8;
1213 closest
->nAvgBytesPerSec
=
1214 closest
->nBlockAlign
* closest
->nSamplesPerSec
;
1218 TRACE("returning: %08x %p\n", hr
, out
? *out
: NULL
);
1222 static HRESULT WINAPI
AudioClient_GetMixFormat(IAudioClient
*iface
,
1223 WAVEFORMATEX
**pwfx
)
1225 ACImpl
*This
= impl_from_IAudioClient(iface
);
1226 WAVEFORMATEXTENSIBLE
*fmt
= &pulse_fmt
[This
->dataflow
== eCapture
];
1228 TRACE("(%p)->(%p)\n", This
, pwfx
);
1233 *pwfx
= clone_format(&fmt
->Format
);
1235 return E_OUTOFMEMORY
;
1240 static HRESULT WINAPI
AudioClient_GetDevicePeriod(IAudioClient
*iface
,
1241 REFERENCE_TIME
*defperiod
, REFERENCE_TIME
*minperiod
)
1243 ACImpl
*This
= impl_from_IAudioClient(iface
);
1245 TRACE("(%p)->(%p, %p)\n", This
, defperiod
, minperiod
);
1247 if (!defperiod
&& !minperiod
)
1251 *defperiod
= pulse_def_period
[This
->dataflow
== eCapture
];
1253 *minperiod
= pulse_min_period
[This
->dataflow
== eCapture
];
1258 static HRESULT WINAPI
AudioClient_Start(IAudioClient
*iface
)
1260 ACImpl
*This
= impl_from_IAudioClient(iface
);
1265 TRACE("(%p)\n", This
);
1267 pthread_mutex_lock(&pulse_lock
);
1268 hr
= pulse_stream_valid(This
);
1270 pthread_mutex_unlock(&pulse_lock
);
1274 if ((This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !This
->event
) {
1275 pthread_mutex_unlock(&pulse_lock
);
1276 return AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1279 if (This
->started
) {
1280 pthread_mutex_unlock(&pulse_lock
);
1281 return AUDCLNT_E_NOT_STOPPED
;
1283 This
->clock_pulse
= PA_USEC_INVALID
;
1285 if (pa_stream_is_corked(This
->stream
)) {
1286 o
= pa_stream_cork(This
->stream
, 0, pulse_op_cb
, &success
);
1288 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1289 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
1290 pa_operation_unref(o
);
1296 if (SUCCEEDED(hr
)) {
1297 This
->started
= TRUE
;
1298 if (This
->dataflow
== eRender
&& This
->event
)
1299 pa_stream_set_latency_update_callback(This
->stream
, pulse_latency_callback
, This
);
1301 pthread_mutex_unlock(&pulse_lock
);
1305 static HRESULT WINAPI
AudioClient_Stop(IAudioClient
*iface
)
1307 ACImpl
*This
= impl_from_IAudioClient(iface
);
1312 TRACE("(%p)\n", This
);
1314 pthread_mutex_lock(&pulse_lock
);
1315 hr
= pulse_stream_valid(This
);
1317 pthread_mutex_unlock(&pulse_lock
);
1321 if (!This
->started
) {
1322 pthread_mutex_unlock(&pulse_lock
);
1326 if (This
->dataflow
== eRender
) {
1327 o
= pa_stream_cork(This
->stream
, 1, pulse_op_cb
, &success
);
1329 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1330 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
1331 pa_operation_unref(o
);
1337 if (SUCCEEDED(hr
)) {
1338 This
->started
= FALSE
;
1339 This
->clock_pulse
= PA_USEC_INVALID
;
1341 pthread_mutex_unlock(&pulse_lock
);
1345 static HRESULT WINAPI
AudioClient_Reset(IAudioClient
*iface
)
1347 ACImpl
*This
= impl_from_IAudioClient(iface
);
1350 TRACE("(%p)\n", This
);
1352 pthread_mutex_lock(&pulse_lock
);
1353 hr
= pulse_stream_valid(This
);
1355 pthread_mutex_unlock(&pulse_lock
);
1359 if (This
->started
) {
1360 pthread_mutex_unlock(&pulse_lock
);
1361 return AUDCLNT_E_NOT_STOPPED
;
1365 pthread_mutex_unlock(&pulse_lock
);
1366 return AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1369 if (This
->dataflow
== eRender
) {
1370 /* If there is still data in the render buffer it needs to be removed from the server */
1373 pa_operation
*o
= pa_stream_flush(This
->stream
, pulse_op_cb
, &success
);
1375 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1376 pthread_cond_wait(&pulse_cond
, &pulse_lock
);
1377 pa_operation_unref(o
);
1380 if (success
|| !This
->pad
)
1381 This
->clock_lastpos
= This
->clock_written
= This
->pad
= 0;
1384 This
->clock_written
+= This
->pad
;
1387 if ((p
= This
->locked_ptr
)) {
1388 This
->locked_ptr
= NULL
;
1389 list_add_tail(&This
->packet_free_head
, &p
->entry
);
1391 list_move_tail(&This
->packet_free_head
, &This
->packet_filled_head
);
1393 pthread_mutex_unlock(&pulse_lock
);
1398 static HRESULT WINAPI
AudioClient_SetEventHandle(IAudioClient
*iface
,
1401 ACImpl
*This
= impl_from_IAudioClient(iface
);
1404 TRACE("(%p)->(%p)\n", This
, event
);
1407 return E_INVALIDARG
;
1409 pthread_mutex_lock(&pulse_lock
);
1410 hr
= pulse_stream_valid(This
);
1412 pthread_mutex_unlock(&pulse_lock
);
1416 if (!(This
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
1417 hr
= AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
1418 else if (This
->event
)
1419 hr
= HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
1421 This
->event
= event
;
1422 pthread_mutex_unlock(&pulse_lock
);
1426 static HRESULT WINAPI
AudioClient_GetService(IAudioClient
*iface
, REFIID riid
,
1429 ACImpl
*This
= impl_from_IAudioClient(iface
);
1432 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppv
);
1438 pthread_mutex_lock(&pulse_lock
);
1439 hr
= pulse_stream_valid(This
);
1440 pthread_mutex_unlock(&pulse_lock
);
1444 if (IsEqualIID(riid
, &IID_IAudioRenderClient
)) {
1445 if (This
->dataflow
!= eRender
)
1446 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1447 *ppv
= &This
->IAudioRenderClient_iface
;
1448 } else if (IsEqualIID(riid
, &IID_IAudioCaptureClient
)) {
1449 if (This
->dataflow
!= eCapture
)
1450 return AUDCLNT_E_WRONG_ENDPOINT_TYPE
;
1451 *ppv
= &This
->IAudioCaptureClient_iface
;
1455 IUnknown_AddRef((IUnknown
*)*ppv
);
1459 FIXME("stub %s\n", debugstr_guid(riid
));
1460 return E_NOINTERFACE
;
1463 static const IAudioClientVtbl AudioClient_Vtbl
=
1465 AudioClient_QueryInterface
,
1467 AudioClient_Release
,
1468 AudioClient_Initialize
,
1469 AudioClient_GetBufferSize
,
1470 AudioClient_GetStreamLatency
,
1471 AudioClient_GetCurrentPadding
,
1472 AudioClient_IsFormatSupported
,
1473 AudioClient_GetMixFormat
,
1474 AudioClient_GetDevicePeriod
,
1478 AudioClient_SetEventHandle
,
1479 AudioClient_GetService
1482 static HRESULT WINAPI
AudioRenderClient_QueryInterface(
1483 IAudioRenderClient
*iface
, REFIID riid
, void **ppv
)
1485 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1491 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1492 IsEqualIID(riid
, &IID_IAudioRenderClient
))
1495 IUnknown_AddRef((IUnknown
*)*ppv
);
1499 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1500 return E_NOINTERFACE
;
1503 static ULONG WINAPI
AudioRenderClient_AddRef(IAudioRenderClient
*iface
)
1505 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1506 return AudioClient_AddRef(&This
->IAudioClient_iface
);
1509 static ULONG WINAPI
AudioRenderClient_Release(IAudioRenderClient
*iface
)
1511 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1512 return AudioClient_Release(&This
->IAudioClient_iface
);
1515 static HRESULT WINAPI
AudioRenderClient_GetBuffer(IAudioRenderClient
*iface
,
1516 UINT32 frames
, BYTE
**data
)
1518 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1519 UINT32 avail
, pad
, req
, bytes
= frames
* pa_frame_size(&This
->ss
);
1523 TRACE("(%p)->(%u, %p)\n", This
, frames
, data
);
1529 pthread_mutex_lock(&pulse_lock
);
1530 hr
= pulse_stream_valid(This
);
1531 if (FAILED(hr
) || This
->locked
) {
1532 pthread_mutex_unlock(&pulse_lock
);
1533 return FAILED(hr
) ? hr
: AUDCLNT_E_OUT_OF_ORDER
;
1536 pthread_mutex_unlock(&pulse_lock
);
1540 ACImpl_GetRenderPad(This
, &pad
);
1541 avail
= This
->bufsize_frames
- pad
;
1542 if (avail
< frames
|| bytes
> This
->bufsize_bytes
) {
1543 pthread_mutex_unlock(&pulse_lock
);
1544 WARN("Wanted to write %u, but only %u available\n", frames
, avail
);
1545 return AUDCLNT_E_BUFFER_TOO_LARGE
;
1548 This
->locked
= frames
;
1550 ret
= pa_stream_begin_write(This
->stream
, &This
->locked_ptr
, &req
);
1551 if (ret
< 0 || req
< bytes
) {
1552 FIXME("%p Not using pulse locked data: %i %u/%u %u/%u\n", This
, ret
, req
/pa_frame_size(&This
->ss
), frames
, pad
, This
->bufsize_frames
);
1554 pa_stream_cancel_write(This
->stream
);
1555 *data
= This
->tmp_buffer
;
1556 This
->locked_ptr
= NULL
;
1558 *data
= This
->locked_ptr
;
1559 pthread_mutex_unlock(&pulse_lock
);
1563 static HRESULT WINAPI
AudioRenderClient_ReleaseBuffer(
1564 IAudioRenderClient
*iface
, UINT32 written_frames
, DWORD flags
)
1566 ACImpl
*This
= impl_from_IAudioRenderClient(iface
);
1567 UINT32 written_bytes
= written_frames
* pa_frame_size(&This
->ss
);
1569 TRACE("(%p)->(%u, %x)\n", This
, written_frames
, flags
);
1571 pthread_mutex_lock(&pulse_lock
);
1572 if (!This
->locked
|| !written_frames
) {
1573 if (This
->locked_ptr
)
1574 pa_stream_cancel_write(This
->stream
);
1576 This
->locked_ptr
= NULL
;
1577 pthread_mutex_unlock(&pulse_lock
);
1578 return written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1581 if (This
->locked
< written_frames
) {
1582 pthread_mutex_unlock(&pulse_lock
);
1583 return AUDCLNT_E_INVALID_SIZE
;
1586 if (flags
& AUDCLNT_BUFFERFLAGS_SILENT
) {
1587 if (This
->ss
.format
== PA_SAMPLE_U8
)
1588 memset(This
->tmp_buffer
, 128, written_bytes
);
1590 memset(This
->tmp_buffer
, 0, written_bytes
);
1594 if (This
->locked_ptr
)
1595 pa_stream_write(This
->stream
, This
->locked_ptr
, written_bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
1597 pa_stream_write(This
->stream
, This
->tmp_buffer
, written_bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
1598 This
->pad
+= written_bytes
;
1599 This
->locked_ptr
= NULL
;
1600 TRACE("Released %u, pad %u\n", written_frames
, This
->pad
/ pa_frame_size(&This
->ss
));
1601 assert(This
->pad
<= This
->bufsize_bytes
);
1602 pthread_mutex_unlock(&pulse_lock
);
1606 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl
= {
1607 AudioRenderClient_QueryInterface
,
1608 AudioRenderClient_AddRef
,
1609 AudioRenderClient_Release
,
1610 AudioRenderClient_GetBuffer
,
1611 AudioRenderClient_ReleaseBuffer
1614 static HRESULT WINAPI
AudioCaptureClient_QueryInterface(
1615 IAudioCaptureClient
*iface
, REFIID riid
, void **ppv
)
1617 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
1623 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1624 IsEqualIID(riid
, &IID_IAudioCaptureClient
))
1627 IUnknown_AddRef((IUnknown
*)*ppv
);
1631 WARN("Unknown interface %s\n", debugstr_guid(riid
));
1632 return E_NOINTERFACE
;
1635 static ULONG WINAPI
AudioCaptureClient_AddRef(IAudioCaptureClient
*iface
)
1637 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1638 return IAudioClient_AddRef(&This
->IAudioClient_iface
);
1641 static ULONG WINAPI
AudioCaptureClient_Release(IAudioCaptureClient
*iface
)
1643 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1644 return IAudioClient_Release(&This
->IAudioClient_iface
);
1647 static HRESULT WINAPI
AudioCaptureClient_GetBuffer(IAudioCaptureClient
*iface
,
1648 BYTE
**data
, UINT32
*frames
, DWORD
*flags
, UINT64
*devpos
,
1651 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1655 TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This
, data
, frames
, flags
,
1658 if (!data
|| !frames
|| !flags
)
1661 pthread_mutex_lock(&pulse_lock
);
1662 hr
= pulse_stream_valid(This
);
1663 if (FAILED(hr
) || This
->locked
) {
1664 pthread_mutex_unlock(&pulse_lock
);
1665 return FAILED(hr
) ? hr
: AUDCLNT_E_OUT_OF_ORDER
;
1668 ACImpl_GetCapturePad(This
, NULL
);
1669 if ((packet
= This
->locked_ptr
)) {
1670 *frames
= This
->capture_period
/ pa_frame_size(&This
->ss
);
1672 if (packet
->discont
)
1673 *flags
|= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY
;
1675 if (packet
->discont
)
1676 *devpos
= (This
->clock_written
+ This
->capture_period
) / pa_frame_size(&This
->ss
);
1678 *devpos
= This
->clock_written
/ pa_frame_size(&This
->ss
);
1681 *qpcpos
= packet
->qpcpos
;
1682 *data
= packet
->data
;
1686 This
->locked
= *frames
;
1687 pthread_mutex_unlock(&pulse_lock
);
1688 return *frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
1691 static HRESULT WINAPI
AudioCaptureClient_ReleaseBuffer(
1692 IAudioCaptureClient
*iface
, UINT32 done
)
1694 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1696 TRACE("(%p)->(%u)\n", This
, done
);
1698 pthread_mutex_lock(&pulse_lock
);
1699 if (!This
->locked
&& done
) {
1700 pthread_mutex_unlock(&pulse_lock
);
1701 return AUDCLNT_E_OUT_OF_ORDER
;
1703 if (done
&& This
->locked
!= done
) {
1704 pthread_mutex_unlock(&pulse_lock
);
1705 return AUDCLNT_E_INVALID_SIZE
;
1708 ACPacket
*packet
= This
->locked_ptr
;
1709 This
->locked_ptr
= NULL
;
1710 This
->pad
-= This
->capture_period
;
1711 if (packet
->discont
)
1712 This
->clock_written
+= 2 * This
->capture_period
;
1714 This
->clock_written
+= This
->capture_period
;
1715 list_add_tail(&This
->packet_free_head
, &packet
->entry
);
1718 pthread_mutex_unlock(&pulse_lock
);
1722 static HRESULT WINAPI
AudioCaptureClient_GetNextPacketSize(
1723 IAudioCaptureClient
*iface
, UINT32
*frames
)
1725 ACImpl
*This
= impl_from_IAudioCaptureClient(iface
);
1728 TRACE("(%p)->(%p)\n", This
, frames
);
1732 pthread_mutex_lock(&pulse_lock
);
1733 ACImpl_GetCapturePad(This
, NULL
);
1734 p
= This
->locked_ptr
;
1736 *frames
= This
->capture_period
/ pa_frame_size(&This
->ss
);
1739 pthread_mutex_unlock(&pulse_lock
);
1743 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl
=
1745 AudioCaptureClient_QueryInterface
,
1746 AudioCaptureClient_AddRef
,
1747 AudioCaptureClient_Release
,
1748 AudioCaptureClient_GetBuffer
,
1749 AudioCaptureClient_ReleaseBuffer
,
1750 AudioCaptureClient_GetNextPacketSize
1753 HRESULT WINAPI
AUDDRV_GetAudioSessionManager(IMMDevice
*device
,
1754 IAudioSessionManager2
**out
)