2 * Copyright 2011-2012 Maarten Lankhorst
3 * Copyright 2010-2011 Maarten Lankhorst for CodeWeavers
4 * Copyright 2011 Andrew Eikum for CodeWeavers
5 * Copyright 2022 Huw Davies
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include <pulse/pulseaudio.h>
34 #define WIN32_NO_STATUS
37 #include "mmdeviceapi.h"
39 #include "audioclient.h"
41 #include "wine/debug.h"
42 #include "wine/list.h"
43 #include "wine/unixlib.h"
45 #include "../mmdevapi/unixlib.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(pulse
);
51 enum phys_device_bus_type
{
52 phys_device_bus_invalid
= -1,
67 AUDCLNT_SHAREMODE share
;
69 float vol
[PA_CHANNELS_MAX
];
71 REFERENCE_TIME def_period
;
75 SIZE_T bufsize_frames
, real_bufsize_bytes
, period_bytes
;
76 SIZE_T peek_ofs
, read_offs_bytes
, lcl_offs_bytes
, pa_offs_bytes
;
77 SIZE_T tmp_buffer_bytes
, held_bytes
, peek_len
, peek_buffer_len
, pa_held_bytes
;
78 BYTE
*local_buffer
, *tmp_buffer
, *peek_buffer
;
80 BOOL please_quit
, just_started
, just_underran
;
81 pa_usec_t mmdev_period_usec
;
83 INT64 clock_lastpos
, clock_written
;
85 struct list packet_free_head
;
86 struct list packet_filled_head
;
89 typedef struct _ACPacket
97 typedef struct _PhysDevice
{
100 enum phys_device_bus_type bus_type
;
101 USHORT vendor_id
, product_id
;
102 EndpointFormFactor form
;
105 REFERENCE_TIME min_period
, def_period
;
106 WAVEFORMATEXTENSIBLE fmt
;
110 static pa_context
*pulse_ctx
;
111 static pa_mainloop
*pulse_ml
;
113 static struct list g_phys_speakers
= LIST_INIT(g_phys_speakers
);
114 static struct list g_phys_sources
= LIST_INIT(g_phys_sources
);
116 static pthread_mutex_t pulse_mutex
;
117 static pthread_cond_t pulse_cond
= PTHREAD_COND_INITIALIZER
;
119 static ULONG_PTR zero_bits
= 0;
121 static NTSTATUS
pulse_not_implemented(void *args
)
123 return STATUS_SUCCESS
;
126 static void pulse_lock(void)
128 pthread_mutex_lock(&pulse_mutex
);
131 static void pulse_unlock(void)
133 pthread_mutex_unlock(&pulse_mutex
);
136 static int pulse_cond_wait(void)
138 return pthread_cond_wait(&pulse_cond
, &pulse_mutex
);
141 static void pulse_broadcast(void)
143 pthread_cond_broadcast(&pulse_cond
);
146 static struct pulse_stream
*handle_get_stream(stream_handle h
)
148 return (struct pulse_stream
*)(UINT_PTR
)h
;
151 static void dump_attr(const pa_buffer_attr
*attr
)
153 TRACE("maxlength: %u\n", attr
->maxlength
);
154 TRACE("minreq: %u\n", attr
->minreq
);
155 TRACE("fragsize: %u\n", attr
->fragsize
);
156 TRACE("tlength: %u\n", attr
->tlength
);
157 TRACE("prebuf: %u\n", attr
->prebuf
);
160 static void free_phys_device_lists(void)
162 static struct list
*const lists
[] = { &g_phys_speakers
, &g_phys_sources
, NULL
};
163 struct list
*const *list
= lists
;
164 PhysDevice
*dev
, *dev_next
;
167 LIST_FOR_EACH_ENTRY_SAFE(dev
, dev_next
, *list
, PhysDevice
, entry
) {
174 /* copied from kernelbase */
175 static int muldiv(int a
, int b
, int c
)
181 /* We want to deal with a positive divisor to simplify the logic. */
188 /* If the result is positive, we "add" to round. else, we subtract to round. */
189 if ((a
< 0 && b
< 0) || (a
>= 0 && b
>= 0))
190 ret
= (((LONGLONG
)a
* b
) + (c
/ 2)) / c
;
192 ret
= (((LONGLONG
)a
* b
) - (c
/ 2)) / c
;
194 if (ret
> 2147483647 || ret
< -2147483647) return -1;
198 static char *wstr_to_str(const WCHAR
*wstr
)
200 const int len
= wcslen(wstr
);
201 char *str
= malloc(len
* 3 + 1);
202 ntdll_wcstoumbs(wstr
, len
+ 1, str
, len
* 3 + 1, FALSE
);
206 /* Following pulseaudio design here, mainloop has the lock taken whenever
207 * it is handling something for pulse, and the lock is required whenever
208 * doing any pa_* call that can affect the state in any way
210 * pa_cond_wait is used when waiting on results, because the mainloop needs
211 * the same lock taken to affect the state
213 * This is basically the same as the pa_threaded_mainloop implementation,
214 * but that cannot be used because it uses pthread_create directly
216 * pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock
217 * pa_threaded_mainloop_signal -> pthread_cond_broadcast
218 * pa_threaded_mainloop_wait -> pthread_cond_wait
220 static int pulse_poll_func(struct pollfd
*ufds
, unsigned long nfds
, int timeout
, void *userdata
)
224 r
= poll(ufds
, nfds
, timeout
);
229 static NTSTATUS
pulse_process_attach(void *args
)
231 pthread_mutexattr_t attr
;
233 pthread_mutexattr_init(&attr
);
234 pthread_mutexattr_setprotocol(&attr
, PTHREAD_PRIO_INHERIT
);
236 if (pthread_mutex_init(&pulse_mutex
, &attr
) != 0)
237 pthread_mutex_init(&pulse_mutex
, NULL
);
240 if (NtCurrentTeb()->WowTebOffset
)
242 SYSTEM_BASIC_INFORMATION info
;
244 NtQuerySystemInformation(SystemEmulationBasicInformation
, &info
, sizeof(info
), NULL
);
245 zero_bits
= (ULONG_PTR
)info
.HighestUserAddress
| 0x7fffffff;
249 return STATUS_SUCCESS
;
252 static NTSTATUS
pulse_process_detach(void *args
)
254 free_phys_device_lists();
257 pa_context_disconnect(pulse_ctx
);
258 pa_context_unref(pulse_ctx
);
261 pa_mainloop_quit(pulse_ml
, 0);
263 return STATUS_SUCCESS
;
266 static NTSTATUS
pulse_main_loop(void *args
)
268 struct main_loop_params
*params
= args
;
271 pulse_ml
= pa_mainloop_new();
272 pa_mainloop_set_poll_func(pulse_ml
, pulse_poll_func
, NULL
);
273 NtSetEvent(params
->event
, NULL
);
274 pa_mainloop_run(pulse_ml
, &ret
);
275 pa_mainloop_free(pulse_ml
);
277 return STATUS_SUCCESS
;
280 static NTSTATUS
pulse_get_endpoint_ids(void *args
)
282 struct get_endpoint_ids_params
*params
= args
;
283 struct list
*list
= (params
->flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
284 struct endpoint
*endpoint
= params
->endpoints
;
285 size_t len
, name_len
, needed
;
289 params
->num
= list_count(list
);
290 offset
= needed
= params
->num
* sizeof(*params
->endpoints
);
292 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
293 name_len
= lstrlenW(dev
->name
) + 1;
294 len
= strlen(dev
->pulse_name
) + 1;
295 needed
+= name_len
* sizeof(WCHAR
) + ((len
+ 1) & ~1);
297 if (needed
<= params
->size
) {
298 endpoint
->name
= offset
;
299 memcpy((char *)params
->endpoints
+ offset
, dev
->name
, name_len
* sizeof(WCHAR
));
300 offset
+= name_len
* sizeof(WCHAR
);
301 endpoint
->device
= offset
;
302 memcpy((char *)params
->endpoints
+ offset
, dev
->pulse_name
, len
);
303 offset
+= (len
+ 1) & ~1;
307 params
->default_idx
= 0;
309 if (needed
> params
->size
) {
310 params
->size
= needed
;
311 params
->result
= HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
313 params
->result
= S_OK
;
314 return STATUS_SUCCESS
;
317 static void pulse_contextcallback(pa_context
*c
, void *userdata
)
319 switch (pa_context_get_state(c
)) {
321 FIXME("Unhandled state: %i\n", pa_context_get_state(c
));
324 case PA_CONTEXT_CONNECTING
:
325 case PA_CONTEXT_UNCONNECTED
:
326 case PA_CONTEXT_AUTHORIZING
:
327 case PA_CONTEXT_SETTING_NAME
:
328 case PA_CONTEXT_TERMINATED
:
329 TRACE("State change to %i\n", pa_context_get_state(c
));
332 case PA_CONTEXT_READY
:
336 case PA_CONTEXT_FAILED
:
337 WARN("Context failed: %s\n", pa_strerror(pa_context_errno(c
)));
343 static void pulse_stream_state(pa_stream
*s
, void *user
)
345 pa_stream_state_t state
= pa_stream_get_state(s
);
346 TRACE("Stream state changed to %i\n", state
);
350 static void pulse_attr_update(pa_stream
*s
, void *user
) {
351 const pa_buffer_attr
*attr
= pa_stream_get_buffer_attr(s
);
352 TRACE("New attributes or device moved:\n");
356 static void pulse_underflow_callback(pa_stream
*s
, void *userdata
)
358 struct pulse_stream
*stream
= userdata
;
359 WARN("%p: Underflow\n", userdata
);
360 stream
->just_underran
= TRUE
;
363 static void pulse_started_callback(pa_stream
*s
, void *userdata
)
365 TRACE("%p: (Re)started playing\n", userdata
);
368 static void pulse_op_cb(pa_stream
*s
, int success
, void *user
)
370 TRACE("Success: %i\n", success
);
371 *(int*)user
= success
;
375 static void silence_buffer(pa_sample_format_t format
, BYTE
*buffer
, UINT32 bytes
)
377 memset(buffer
, format
== PA_SAMPLE_U8
? 0x80 : 0, bytes
);
380 static BOOL
pulse_stream_valid(struct pulse_stream
*stream
)
382 return pa_stream_get_state(stream
->stream
) == PA_STREAM_READY
;
385 static HRESULT
pulse_connect(const char *name
)
387 pa_context_state_t state
;
389 if (pulse_ctx
&& PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx
)))
392 pa_context_unref(pulse_ctx
);
394 pulse_ctx
= pa_context_new(pa_mainloop_get_api(pulse_ml
), name
);
396 ERR("Failed to create context\n");
400 pa_context_set_state_callback(pulse_ctx
, pulse_contextcallback
, NULL
);
402 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx
), PA_API_VERSION
);
403 if (pa_context_connect(pulse_ctx
, NULL
, 0, NULL
) < 0)
406 /* Wait for connection */
407 while ((state
= pa_context_get_state(pulse_ctx
)) != PA_CONTEXT_READY
&&
408 state
!= PA_CONTEXT_FAILED
&& state
!= PA_CONTEXT_TERMINATED
)
411 if (state
!= PA_CONTEXT_READY
)
414 TRACE("Connected to server %s with protocol version: %i.\n",
415 pa_context_get_server(pulse_ctx
),
416 pa_context_get_server_protocol_version(pulse_ctx
));
420 pa_context_unref(pulse_ctx
);
425 static UINT
pulse_channel_map_to_channel_mask(const pa_channel_map
*map
)
430 for (i
= 0; i
< map
->channels
; ++i
) {
431 switch (map
->map
[i
]) {
432 default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map
->map
[i
])); break;
433 case PA_CHANNEL_POSITION_FRONT_LEFT
: mask
|= SPEAKER_FRONT_LEFT
; break;
434 case PA_CHANNEL_POSITION_MONO
:
435 case PA_CHANNEL_POSITION_FRONT_CENTER
: mask
|= SPEAKER_FRONT_CENTER
; break;
436 case PA_CHANNEL_POSITION_FRONT_RIGHT
: mask
|= SPEAKER_FRONT_RIGHT
; break;
437 case PA_CHANNEL_POSITION_REAR_LEFT
: mask
|= SPEAKER_BACK_LEFT
; break;
438 case PA_CHANNEL_POSITION_REAR_CENTER
: mask
|= SPEAKER_BACK_CENTER
; break;
439 case PA_CHANNEL_POSITION_REAR_RIGHT
: mask
|= SPEAKER_BACK_RIGHT
; break;
440 case PA_CHANNEL_POSITION_LFE
: mask
|= SPEAKER_LOW_FREQUENCY
; break;
441 case PA_CHANNEL_POSITION_SIDE_LEFT
: mask
|= SPEAKER_SIDE_LEFT
; break;
442 case PA_CHANNEL_POSITION_SIDE_RIGHT
: mask
|= SPEAKER_SIDE_RIGHT
; break;
443 case PA_CHANNEL_POSITION_TOP_CENTER
: mask
|= SPEAKER_TOP_CENTER
; break;
444 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT
: mask
|= SPEAKER_TOP_FRONT_LEFT
; break;
445 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER
: mask
|= SPEAKER_TOP_FRONT_CENTER
; break;
446 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
: mask
|= SPEAKER_TOP_FRONT_RIGHT
; break;
447 case PA_CHANNEL_POSITION_TOP_REAR_LEFT
: mask
|= SPEAKER_TOP_BACK_LEFT
; break;
448 case PA_CHANNEL_POSITION_TOP_REAR_CENTER
: mask
|= SPEAKER_TOP_BACK_CENTER
; break;
449 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT
: mask
|= SPEAKER_TOP_BACK_RIGHT
; break;
450 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
: mask
|= SPEAKER_FRONT_LEFT_OF_CENTER
; break;
451 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
: mask
|= SPEAKER_FRONT_RIGHT_OF_CENTER
; break;
458 #define MAX_DEVICE_NAME_LEN 62
460 static WCHAR
*get_device_name(const char *desc
, pa_proplist
*proplist
)
463 Some broken apps (e.g. Split/Second with fmodex) can't handle names that
464 are too long and crash even on native. If the device desc is too long,
465 we'll attempt to incrementally build it to try to stay under the limit.
466 ( + 1 is to check against truncated buffer after ntdll_umbstowcs )
468 WCHAR buf
[MAX_DEVICE_NAME_LEN
+ 1];
470 /* For monitors of sinks; this does not seem to be localized in PA either */
471 static const WCHAR monitor_of
[] = {'M','o','n','i','t','o','r',' ','o','f',' '};
473 size_t len
= strlen(desc
);
476 if (!(name
= malloc((len
+ 1) * sizeof(WCHAR
))))
478 if (!(len
= ntdll_umbstowcs(desc
, len
, name
, len
))) {
483 if (len
> MAX_DEVICE_NAME_LEN
&& proplist
) {
484 const char *prop
= pa_proplist_gets(proplist
, PA_PROP_DEVICE_CLASS
);
485 unsigned prop_len
, rem
= ARRAY_SIZE(buf
);
486 BOOL monitor
= FALSE
;
488 if (prop
&& !strcmp(prop
, "monitor")) {
489 rem
-= ARRAY_SIZE(monitor_of
);
493 prop
= pa_proplist_gets(proplist
, PA_PROP_DEVICE_PRODUCT_NAME
);
494 if (!prop
|| !prop
[0] ||
495 !(prop_len
= ntdll_umbstowcs(prop
, strlen(prop
), buf
, rem
)) || prop_len
== rem
) {
496 prop
= pa_proplist_gets(proplist
, "alsa.card_name");
497 if (!prop
|| !prop
[0] ||
498 !(prop_len
= ntdll_umbstowcs(prop
, strlen(prop
), buf
, rem
)) || prop_len
== rem
)
503 /* We know we have a name that fits within the limit now */
507 memcpy(p
, monitor_of
, sizeof(monitor_of
));
508 p
+= ARRAY_SIZE(monitor_of
);
510 len
= ntdll_umbstowcs(prop
, strlen(prop
), p
, rem
);
517 prop
= pa_proplist_gets(proplist
, PA_PROP_DEVICE_PROFILE_DESCRIPTION
);
518 if (prop
&& prop
[0] && (len
= ntdll_umbstowcs(prop
, strlen(prop
), p
+ 1, rem
)) && len
!= rem
) {
528 if ((tmp
= realloc(name
, (len
+ 1) * sizeof(WCHAR
))))
533 static void fill_device_info(PhysDevice
*dev
, pa_proplist
*p
)
537 dev
->bus_type
= phys_device_bus_invalid
;
544 if ((buffer
= pa_proplist_gets(p
, PA_PROP_DEVICE_BUS
))) {
545 if (!strcmp(buffer
, "usb"))
546 dev
->bus_type
= phys_device_bus_usb
;
547 else if (!strcmp(buffer
, "pci"))
548 dev
->bus_type
= phys_device_bus_pci
;
551 if ((buffer
= pa_proplist_gets(p
, PA_PROP_DEVICE_VENDOR_ID
)))
552 dev
->vendor_id
= strtol(buffer
, NULL
, 16);
554 if ((buffer
= pa_proplist_gets(p
, PA_PROP_DEVICE_PRODUCT_ID
)))
555 dev
->product_id
= strtol(buffer
, NULL
, 16);
558 static void pulse_add_device(struct list
*list
, pa_proplist
*proplist
, int index
, EndpointFormFactor form
,
559 UINT channel_mask
, const char *pulse_name
, const char *desc
)
561 size_t len
= strlen(pulse_name
);
562 PhysDevice
*dev
= malloc(FIELD_OFFSET(PhysDevice
, pulse_name
[len
+ 1]));
567 if (!(dev
->name
= get_device_name(desc
, proplist
))) {
573 dev
->channel_mask
= channel_mask
;
576 fill_device_info(dev
, proplist
);
577 memcpy(dev
->pulse_name
, pulse_name
, len
+ 1);
579 list_add_tail(list
, &dev
->entry
);
581 TRACE("%s\n", debugstr_w(dev
->name
));
584 static void pulse_phys_speakers_cb(pa_context
*c
, const pa_sink_info
*i
, int eol
, void *userdata
)
586 struct list
*speaker
;
589 if (!i
|| !i
->name
|| !i
->name
[0])
591 channel_mask
= pulse_channel_map_to_channel_mask(&i
->channel_map
);
593 /* For default PulseAudio render device, OR together all of the
594 * PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */
595 speaker
= list_head(&g_phys_speakers
);
597 LIST_ENTRY(speaker
, PhysDevice
, entry
)->channel_mask
|= channel_mask
;
599 pulse_add_device(&g_phys_speakers
, i
->proplist
, i
->index
, Speakers
, channel_mask
, i
->name
, i
->description
);
602 static void pulse_phys_sources_cb(pa_context
*c
, const pa_source_info
*i
, int eol
, void *userdata
)
604 if (!i
|| !i
->name
|| !i
->name
[0])
606 pulse_add_device(&g_phys_sources
, i
->proplist
, i
->index
,
607 (i
->monitor_of_sink
== PA_INVALID_INDEX
) ? Microphone
: LineLevel
, 0, i
->name
, i
->description
);
610 /* For most hardware on Windows, users must choose a configuration with an even
611 * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
612 * channels, but those channels are still reported to applications from
613 * GetMixFormat! Some applications behave badly if given an odd number of
614 * channels (e.g. 2.1). Here, we find the nearest configuration that Windows
615 * would report for a given channel layout. */
616 static void convert_channel_map(const pa_channel_map
*pa_map
, WAVEFORMATEXTENSIBLE
*fmt
)
618 UINT pa_mask
= pulse_channel_map_to_channel_mask(pa_map
);
620 TRACE("got mask for PA: 0x%x\n", pa_mask
);
622 if (pa_map
->channels
== 1)
624 fmt
->Format
.nChannels
= 1;
625 fmt
->dwChannelMask
= pa_mask
;
629 /* compare against known configurations and find smallest configuration
630 * which is a superset of the given speakers */
632 if (pa_map
->channels
<= 2 &&
633 (pa_mask
& ~KSAUDIO_SPEAKER_STEREO
) == 0)
635 fmt
->Format
.nChannels
= 2;
636 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_STEREO
;
640 if (pa_map
->channels
<= 4 &&
641 (pa_mask
& ~KSAUDIO_SPEAKER_QUAD
) == 0)
643 fmt
->Format
.nChannels
= 4;
644 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_QUAD
;
648 if (pa_map
->channels
<= 4 &&
649 (pa_mask
& ~KSAUDIO_SPEAKER_SURROUND
) == 0)
651 fmt
->Format
.nChannels
= 4;
652 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_SURROUND
;
656 if (pa_map
->channels
<= 6 &&
657 (pa_mask
& ~KSAUDIO_SPEAKER_5POINT1
) == 0)
659 fmt
->Format
.nChannels
= 6;
660 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_5POINT1
;
664 if (pa_map
->channels
<= 6 &&
665 (pa_mask
& ~KSAUDIO_SPEAKER_5POINT1_SURROUND
) == 0)
667 fmt
->Format
.nChannels
= 6;
668 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_5POINT1_SURROUND
;
672 if (pa_map
->channels
<= 8 &&
673 (pa_mask
& ~KSAUDIO_SPEAKER_7POINT1
) == 0)
675 fmt
->Format
.nChannels
= 8;
676 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_7POINT1
;
680 if (pa_map
->channels
<= 8 &&
681 (pa_mask
& ~KSAUDIO_SPEAKER_7POINT1_SURROUND
) == 0)
683 fmt
->Format
.nChannels
= 8;
684 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_7POINT1_SURROUND
;
688 /* oddball format, report truthfully */
689 fmt
->Format
.nChannels
= pa_map
->channels
;
690 fmt
->dwChannelMask
= pa_mask
;
693 static void pulse_probe_settings(int render
, const char *pulse_name
, WAVEFORMATEXTENSIBLE
*fmt
, REFERENCE_TIME
*def_period
, REFERENCE_TIME
*min_period
)
695 WAVEFORMATEX
*wfx
= &fmt
->Format
;
701 unsigned int length
= 0;
703 if (pulse_name
&& !pulse_name
[0])
706 pa_channel_map_init_auto(&map
, 2, PA_CHANNEL_MAP_ALSA
);
708 ss
.format
= PA_SAMPLE_FLOAT32LE
;
709 ss
.channels
= map
.channels
;
713 attr
.minreq
= attr
.fragsize
= pa_frame_size(&ss
);
716 stream
= pa_stream_new(pulse_ctx
, "format test stream", &ss
, &map
);
718 pa_stream_set_state_callback(stream
, pulse_stream_state
, NULL
);
722 ret
= pa_stream_connect_playback(stream
, pulse_name
, &attr
,
723 PA_STREAM_START_CORKED
|PA_STREAM_FIX_RATE
|PA_STREAM_FIX_CHANNELS
|PA_STREAM_EARLY_REQUESTS
, NULL
, NULL
);
725 ret
= pa_stream_connect_record(stream
, pulse_name
, &attr
, PA_STREAM_START_CORKED
|PA_STREAM_FIX_RATE
|PA_STREAM_FIX_CHANNELS
|PA_STREAM_EARLY_REQUESTS
);
727 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
728 pa_stream_get_state(stream
) == PA_STREAM_CREATING
)
730 if (pa_stream_get_state(stream
) == PA_STREAM_READY
) {
731 ss
= *pa_stream_get_sample_spec(stream
);
732 map
= *pa_stream_get_channel_map(stream
);
734 length
= pa_stream_get_buffer_attr(stream
)->minreq
;
736 length
= pa_stream_get_buffer_attr(stream
)->fragsize
;
737 pa_stream_disconnect(stream
);
738 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
739 pa_stream_get_state(stream
) == PA_STREAM_READY
)
745 pa_stream_unref(stream
);
748 *def_period
= *min_period
= pa_bytes_to_usec(10 * length
, &ss
);
750 wfx
->wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
751 wfx
->cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
753 convert_channel_map(&map
, fmt
);
755 wfx
->wBitsPerSample
= 8 * pa_sample_size_of_format(ss
.format
);
756 wfx
->nSamplesPerSec
= ss
.rate
;
757 wfx
->nBlockAlign
= wfx
->nChannels
* wfx
->wBitsPerSample
/ 8;
758 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
759 if (ss
.format
!= PA_SAMPLE_S24_32LE
)
760 fmt
->Samples
.wValidBitsPerSample
= wfx
->wBitsPerSample
;
762 fmt
->Samples
.wValidBitsPerSample
= 24;
763 if (ss
.format
== PA_SAMPLE_FLOAT32LE
)
764 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
766 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
769 /* some poorly-behaved applications call audio functions during DllMain, so we
770 * have to do as much as possible without creating a new thread. this function
771 * sets up a synchronous connection to verify the server is running and query
773 static NTSTATUS
pulse_test_connect(void *args
)
775 struct test_connect_params
*params
= args
;
779 char *name
= wstr_to_str(params
->name
);
782 pulse_ml
= pa_mainloop_new();
784 pa_mainloop_set_poll_func(pulse_ml
, pulse_poll_func
, NULL
);
786 pulse_ctx
= pa_context_new(pa_mainloop_get_api(pulse_ml
), name
);
791 ERR("Failed to create context\n");
792 pa_mainloop_free(pulse_ml
);
795 params
->priority
= Priority_Unavailable
;
796 return STATUS_SUCCESS
;
799 pa_context_set_state_callback(pulse_ctx
, pulse_contextcallback
, NULL
);
801 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx
), PA_API_VERSION
);
802 if (pa_context_connect(pulse_ctx
, NULL
, 0, NULL
) < 0)
805 /* Wait for connection */
806 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0) {
807 pa_context_state_t state
= pa_context_get_state(pulse_ctx
);
809 if (state
== PA_CONTEXT_FAILED
|| state
== PA_CONTEXT_TERMINATED
)
812 if (state
== PA_CONTEXT_READY
)
816 if (pa_context_get_state(pulse_ctx
) != PA_CONTEXT_READY
)
819 TRACE("Test-connected to server %s with protocol version: %i.\n",
820 pa_context_get_server(pulse_ctx
),
821 pa_context_get_server_protocol_version(pulse_ctx
));
823 free_phys_device_lists();
824 list_init(&g_phys_speakers
);
825 list_init(&g_phys_sources
);
827 /* Burnout Paradise Remastered expects device name to have a space. */
828 pulse_add_device(&g_phys_speakers
, NULL
, 0, Speakers
, 0, "", "PulseAudio Output");
829 pulse_add_device(&g_phys_sources
, NULL
, 0, Microphone
, 0, "", "PulseAudio Input");
831 o
= pa_context_get_sink_info_list(pulse_ctx
, &pulse_phys_speakers_cb
, NULL
);
833 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
834 pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
836 pa_operation_unref(o
);
839 o
= pa_context_get_source_info_list(pulse_ctx
, &pulse_phys_sources_cb
, NULL
);
841 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
842 pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
844 pa_operation_unref(o
);
847 LIST_FOR_EACH_ENTRY(dev
, &g_phys_speakers
, PhysDevice
, entry
) {
848 pulse_probe_settings(1, dev
->pulse_name
, &dev
->fmt
, &dev
->def_period
, &dev
->min_period
);
851 LIST_FOR_EACH_ENTRY(dev
, &g_phys_sources
, PhysDevice
, entry
) {
852 pulse_probe_settings(0, dev
->pulse_name
, &dev
->fmt
, &dev
->def_period
, &dev
->min_period
);
855 pa_context_unref(pulse_ctx
);
857 pa_mainloop_free(pulse_ml
);
862 params
->priority
= Priority_Preferred
;
863 return STATUS_SUCCESS
;
866 pa_context_unref(pulse_ctx
);
868 pa_mainloop_free(pulse_ml
);
871 params
->priority
= Priority_Unavailable
;
872 return STATUS_SUCCESS
;
875 static UINT
get_channel_mask(unsigned int channels
)
881 return KSAUDIO_SPEAKER_MONO
;
883 return KSAUDIO_SPEAKER_STEREO
;
885 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
887 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
889 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
891 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
893 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
895 return KSAUDIO_SPEAKER_7POINT1_SURROUND
; /* Vista deprecates 7POINT1 */
897 FIXME("Unknown speaker configuration: %u\n", channels
);
901 static const enum pa_channel_position pulse_pos_from_wfx
[] = {
902 PA_CHANNEL_POSITION_FRONT_LEFT
,
903 PA_CHANNEL_POSITION_FRONT_RIGHT
,
904 PA_CHANNEL_POSITION_FRONT_CENTER
,
905 PA_CHANNEL_POSITION_LFE
,
906 PA_CHANNEL_POSITION_REAR_LEFT
,
907 PA_CHANNEL_POSITION_REAR_RIGHT
,
908 PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
,
909 PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
,
910 PA_CHANNEL_POSITION_REAR_CENTER
,
911 PA_CHANNEL_POSITION_SIDE_LEFT
,
912 PA_CHANNEL_POSITION_SIDE_RIGHT
,
913 PA_CHANNEL_POSITION_TOP_CENTER
,
914 PA_CHANNEL_POSITION_TOP_FRONT_LEFT
,
915 PA_CHANNEL_POSITION_TOP_FRONT_CENTER
,
916 PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
,
917 PA_CHANNEL_POSITION_TOP_REAR_LEFT
,
918 PA_CHANNEL_POSITION_TOP_REAR_CENTER
,
919 PA_CHANNEL_POSITION_TOP_REAR_RIGHT
922 static HRESULT
pulse_spec_from_waveformat(struct pulse_stream
*stream
, const WAVEFORMATEX
*fmt
)
924 pa_channel_map_init(&stream
->map
);
925 stream
->ss
.rate
= fmt
->nSamplesPerSec
;
926 stream
->ss
.format
= PA_SAMPLE_INVALID
;
928 switch(fmt
->wFormatTag
) {
929 case WAVE_FORMAT_IEEE_FLOAT
:
930 if (!fmt
->nChannels
|| fmt
->nChannels
> 2 || fmt
->wBitsPerSample
!= 32)
932 stream
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
933 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
935 case WAVE_FORMAT_PCM
:
936 if (!fmt
->nChannels
|| fmt
->nChannels
> 2)
938 if (fmt
->wBitsPerSample
== 8)
939 stream
->ss
.format
= PA_SAMPLE_U8
;
940 else if (fmt
->wBitsPerSample
== 16)
941 stream
->ss
.format
= PA_SAMPLE_S16LE
;
943 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
944 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
946 case WAVE_FORMAT_EXTENSIBLE
: {
947 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)fmt
;
948 UINT mask
= wfe
->dwChannelMask
;
950 if (fmt
->cbSize
!= (sizeof(*wfe
) - sizeof(*fmt
)) && fmt
->cbSize
!= sizeof(*wfe
))
952 if (IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
953 (!wfe
->Samples
.wValidBitsPerSample
|| wfe
->Samples
.wValidBitsPerSample
== 32) &&
954 fmt
->wBitsPerSample
== 32)
955 stream
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
956 else if (IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
957 DWORD valid
= wfe
->Samples
.wValidBitsPerSample
;
959 valid
= fmt
->wBitsPerSample
;
960 if (!valid
|| valid
> fmt
->wBitsPerSample
)
962 switch (fmt
->wBitsPerSample
) {
965 stream
->ss
.format
= PA_SAMPLE_U8
;
969 stream
->ss
.format
= PA_SAMPLE_S16LE
;
973 stream
->ss
.format
= PA_SAMPLE_S24LE
;
977 stream
->ss
.format
= PA_SAMPLE_S24_32LE
;
978 else if (valid
== 32)
979 stream
->ss
.format
= PA_SAMPLE_S32LE
;
982 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
985 stream
->map
.channels
= fmt
->nChannels
;
986 if (!mask
|| (mask
& (SPEAKER_ALL
|SPEAKER_RESERVED
)))
987 mask
= get_channel_mask(fmt
->nChannels
);
988 for (j
= 0; j
< ARRAY_SIZE(pulse_pos_from_wfx
) && i
< fmt
->nChannels
; ++j
) {
990 stream
->map
.map
[i
++] = pulse_pos_from_wfx
[j
];
993 /* Special case for mono since pulse appears to map it differently */
994 if (mask
== SPEAKER_FRONT_CENTER
)
995 stream
->map
.map
[0] = PA_CHANNEL_POSITION_MONO
;
997 if (i
< fmt
->nChannels
|| (mask
& SPEAKER_RESERVED
)) {
998 stream
->map
.channels
= 0;
999 ERR("Invalid channel mask: %i/%i and %x(%x)\n", i
, fmt
->nChannels
, mask
, (unsigned)wfe
->dwChannelMask
);
1004 case WAVE_FORMAT_ALAW
:
1005 case WAVE_FORMAT_MULAW
:
1006 if (fmt
->wBitsPerSample
!= 8) {
1007 FIXME("Unsupported bpp %u for LAW\n", fmt
->wBitsPerSample
);
1008 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1010 if (fmt
->nChannels
!= 1 && fmt
->nChannels
!= 2) {
1011 FIXME("Unsupported channels %u for LAW\n", fmt
->nChannels
);
1012 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1014 stream
->ss
.format
= fmt
->wFormatTag
== WAVE_FORMAT_MULAW
? PA_SAMPLE_ULAW
: PA_SAMPLE_ALAW
;
1015 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
1018 WARN("Unhandled tag %x\n", fmt
->wFormatTag
);
1019 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1021 stream
->ss
.channels
= stream
->map
.channels
;
1022 if (!pa_channel_map_valid(&stream
->map
) || stream
->ss
.format
== PA_SAMPLE_INVALID
) {
1023 ERR("Invalid format! Channel spec valid: %i, format: %i\n",
1024 pa_channel_map_valid(&stream
->map
), stream
->ss
.format
);
1025 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1030 static HRESULT
pulse_stream_connect(struct pulse_stream
*stream
, const char *pulse_name
, UINT32 period_bytes
)
1032 pa_stream_flags_t flags
= PA_STREAM_START_CORKED
| PA_STREAM_START_UNMUTED
| PA_STREAM_ADJUST_LATENCY
;
1036 pa_buffer_attr attr
;
1038 ret
= InterlockedIncrement(&number
);
1039 sprintf(buffer
, "audio stream #%i", ret
);
1040 stream
->stream
= pa_stream_new(pulse_ctx
, buffer
, &stream
->ss
, &stream
->map
);
1042 if (!stream
->stream
) {
1043 WARN("pa_stream_new returned error %i\n", pa_context_errno(pulse_ctx
));
1044 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1047 pa_stream_set_state_callback(stream
->stream
, pulse_stream_state
, stream
);
1048 pa_stream_set_buffer_attr_callback(stream
->stream
, pulse_attr_update
, stream
);
1049 pa_stream_set_moved_callback(stream
->stream
, pulse_attr_update
, stream
);
1051 /* PulseAudio will fill in correct values */
1052 attr
.minreq
= attr
.fragsize
= period_bytes
;
1053 attr
.tlength
= period_bytes
* 3;
1054 attr
.maxlength
= stream
->bufsize_frames
* pa_frame_size(&stream
->ss
);
1055 attr
.prebuf
= pa_frame_size(&stream
->ss
);
1058 /* If specific device was requested, use it exactly */
1060 flags
|= PA_STREAM_DONT_MOVE
;
1062 pulse_name
= NULL
; /* use default */
1064 if (stream
->dataflow
== eRender
)
1065 ret
= pa_stream_connect_playback(stream
->stream
, pulse_name
, &attr
, flags
, NULL
, NULL
);
1067 ret
= pa_stream_connect_record(stream
->stream
, pulse_name
, &attr
, flags
);
1069 WARN("Returns %i\n", ret
);
1070 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1072 while (pa_stream_get_state(stream
->stream
) == PA_STREAM_CREATING
)
1074 if (pa_stream_get_state(stream
->stream
) != PA_STREAM_READY
)
1075 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1077 if (stream
->dataflow
== eRender
) {
1078 pa_stream_set_underflow_callback(stream
->stream
, pulse_underflow_callback
, stream
);
1079 pa_stream_set_started_callback(stream
->stream
, pulse_started_callback
, stream
);
1084 static HRESULT
get_device_period_helper(EDataFlow flow
, const char *pulse_name
, REFERENCE_TIME
*def
, REFERENCE_TIME
*min
)
1086 struct list
*list
= (flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
1093 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
1094 if (strcmp(pulse_name
, dev
->pulse_name
))
1098 *def
= dev
->def_period
;
1100 *min
= dev
->min_period
;
1107 static NTSTATUS
pulse_create_stream(void *args
)
1109 struct create_stream_params
*params
= args
;
1110 struct pulse_stream
*stream
;
1111 unsigned int i
, bufsize_bytes
;
1115 if (params
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
) {
1116 params
->result
= AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
1117 return STATUS_SUCCESS
;
1122 name
= wstr_to_str(params
->name
);
1123 params
->result
= pulse_connect(name
);
1126 if (FAILED(params
->result
))
1129 return STATUS_SUCCESS
;
1132 if (!(stream
= calloc(1, sizeof(*stream
))))
1135 params
->result
= E_OUTOFMEMORY
;
1136 return STATUS_SUCCESS
;
1139 stream
->dataflow
= params
->flow
;
1140 for (i
= 0; i
< ARRAY_SIZE(stream
->vol
); ++i
)
1141 stream
->vol
[i
] = 1.f
;
1143 hr
= pulse_spec_from_waveformat(stream
, params
->fmt
);
1144 TRACE("Obtaining format returns %08x\n", (unsigned)hr
);
1149 stream
->def_period
= params
->period
;
1151 stream
->period_bytes
= pa_frame_size(&stream
->ss
) * muldiv(params
->period
,
1155 stream
->bufsize_frames
= ceil((params
->duration
/ 10000000.) * params
->fmt
->nSamplesPerSec
);
1156 bufsize_bytes
= stream
->bufsize_frames
* pa_frame_size(&stream
->ss
);
1157 stream
->mmdev_period_usec
= params
->period
/ 10;
1159 stream
->share
= params
->share
;
1160 stream
->flags
= params
->flags
;
1161 hr
= pulse_stream_connect(stream
, params
->device
, stream
->period_bytes
);
1162 if (SUCCEEDED(hr
)) {
1164 const pa_buffer_attr
*attr
= pa_stream_get_buffer_attr(stream
->stream
);
1167 stream
->attr
= *attr
;
1168 /* Update frames according to new size */
1170 if (stream
->dataflow
== eRender
) {
1171 size
= stream
->real_bufsize_bytes
=
1172 stream
->bufsize_frames
* 2 * pa_frame_size(&stream
->ss
);
1173 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1174 zero_bits
, &size
, MEM_COMMIT
, PAGE_READWRITE
))
1177 UINT32 i
, capture_packets
;
1179 if ((unalign
= bufsize_bytes
% stream
->period_bytes
))
1180 bufsize_bytes
+= stream
->period_bytes
- unalign
;
1181 stream
->bufsize_frames
= bufsize_bytes
/ pa_frame_size(&stream
->ss
);
1182 stream
->real_bufsize_bytes
= bufsize_bytes
;
1184 capture_packets
= stream
->real_bufsize_bytes
/ stream
->period_bytes
;
1186 size
= stream
->real_bufsize_bytes
+ capture_packets
* sizeof(ACPacket
);
1187 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1188 zero_bits
, &size
, MEM_COMMIT
, PAGE_READWRITE
))
1191 ACPacket
*cur_packet
= (ACPacket
*)((char*)stream
->local_buffer
+ stream
->real_bufsize_bytes
);
1192 BYTE
*data
= stream
->local_buffer
;
1193 silence_buffer(stream
->ss
.format
, stream
->local_buffer
, stream
->real_bufsize_bytes
);
1194 list_init(&stream
->packet_free_head
);
1195 list_init(&stream
->packet_filled_head
);
1196 for (i
= 0; i
< capture_packets
; ++i
, ++cur_packet
) {
1197 list_add_tail(&stream
->packet_free_head
, &cur_packet
->entry
);
1198 cur_packet
->data
= data
;
1199 data
+= stream
->period_bytes
;
1205 *params
->channel_count
= stream
->ss
.channels
;
1206 *params
->stream
= (stream_handle
)(UINT_PTR
)stream
;
1209 if (FAILED(params
->result
= hr
)) {
1210 free(stream
->local_buffer
);
1211 if (stream
->stream
) {
1212 pa_stream_disconnect(stream
->stream
);
1213 pa_stream_unref(stream
->stream
);
1219 return STATUS_SUCCESS
;
1222 static NTSTATUS
pulse_release_stream(void *args
)
1224 struct release_stream_params
*params
= args
;
1225 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1228 if(params
->timer_thread
) {
1229 stream
->please_quit
= TRUE
;
1230 NtWaitForSingleObject(params
->timer_thread
, FALSE
, NULL
);
1231 NtClose(params
->timer_thread
);
1235 if (PA_STREAM_IS_GOOD(pa_stream_get_state(stream
->stream
))) {
1236 pa_stream_disconnect(stream
->stream
);
1237 while (PA_STREAM_IS_GOOD(pa_stream_get_state(stream
->stream
)))
1240 pa_stream_unref(stream
->stream
);
1243 if (stream
->tmp_buffer
) {
1245 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1246 &size
, MEM_RELEASE
);
1248 if (stream
->local_buffer
) {
1250 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1251 &size
, MEM_RELEASE
);
1253 free(stream
->peek_buffer
);
1255 return STATUS_SUCCESS
;
1258 static int write_buffer(const struct pulse_stream
*stream
, BYTE
*buffer
, UINT32 bytes
)
1260 const float *vol
= stream
->vol
;
1261 UINT32 i
, channels
, mute
= 0;
1262 BOOL adjust
= FALSE
;
1265 if (!bytes
) return 0;
1267 /* Adjust the buffer based on the volume for each channel */
1268 channels
= stream
->ss
.channels
;
1269 for (i
= 0; i
< channels
; i
++)
1271 adjust
|= vol
[i
] != 1.0f
;
1275 if (mute
== channels
)
1277 silence_buffer(stream
->ss
.format
, buffer
, bytes
);
1280 if (!adjust
) goto write
;
1282 end
= buffer
+ bytes
;
1283 switch (stream
->ss
.format
)
1285 #ifndef WORDS_BIGENDIAN
1286 #define PROCESS_BUFFER(type) do \
1288 type *p = (type*)buffer; \
1291 for (i = 0; i < channels; i++) \
1292 p[i] = p[i] * vol[i]; \
1294 } while ((BYTE*)p != end); \
1296 case PA_SAMPLE_S16LE
:
1297 PROCESS_BUFFER(INT16
);
1299 case PA_SAMPLE_S32LE
:
1300 PROCESS_BUFFER(INT32
);
1302 case PA_SAMPLE_FLOAT32LE
:
1303 PROCESS_BUFFER(float);
1305 #undef PROCESS_BUFFER
1306 case PA_SAMPLE_S24_32LE
:
1308 UINT32
*p
= (UINT32
*)buffer
;
1311 for (i
= 0; i
< channels
; i
++)
1313 p
[i
] = (INT32
)((INT32
)(p
[i
] << 8) * vol
[i
]);
1317 } while ((BYTE
*)p
!= end
);
1320 case PA_SAMPLE_S24LE
:
1322 /* do it 12 bytes at a time until it is no longer possible */
1323 UINT32
*q
= (UINT32
*)buffer
;
1327 while (end
- (BYTE
*)q
>= 12)
1331 v
[1] = q
[1] << 16 | (q
[0] >> 16 & ~0xff);
1332 v
[2] = q
[2] << 24 | (q
[1] >> 8 & ~0xff);
1333 v
[3] = q
[2] & ~0xff;
1334 for (k
= 0; k
< 4; k
++)
1336 v
[k
] = (INT32
)((INT32
)v
[k
] * vol
[i
]);
1337 if (++i
== channels
) i
= 0;
1339 *q
++ = v
[0] >> 8 | (v
[1] & ~0xff) << 16;
1340 *q
++ = v
[1] >> 16 | (v
[2] & ~0xff) << 8;
1341 *q
++ = v
[2] >> 24 | (v
[3] & ~0xff);
1346 UINT32 v
= (INT32
)((INT32
)(p
[0] << 8 | p
[1] << 16 | p
[2] << 24) * vol
[i
]);
1347 *p
++ = v
>> 8 & 0xff;
1348 *p
++ = v
>> 16 & 0xff;
1350 if (++i
== channels
) i
= 0;
1357 UINT8
*p
= (UINT8
*)buffer
;
1360 for (i
= 0; i
< channels
; i
++)
1361 p
[i
] = (int)((p
[i
] - 128) * vol
[i
]) + 128;
1363 } while ((BYTE
*)p
!= end
);
1366 case PA_SAMPLE_ALAW
:
1368 UINT8
*p
= (UINT8
*)buffer
;
1371 for (i
= 0; i
< channels
; i
++)
1372 p
[i
] = mult_alaw_sample(p
[i
], vol
[i
]);
1374 } while ((BYTE
*)p
!= end
);
1377 case PA_SAMPLE_ULAW
:
1379 UINT8
*p
= (UINT8
*)buffer
;
1382 for (i
= 0; i
< channels
; i
++)
1383 p
[i
] = mult_ulaw_sample(p
[i
], vol
[i
]);
1385 } while ((BYTE
*)p
!= end
);
1389 TRACE("Unhandled format %i, not adjusting volume.\n", stream
->ss
.format
);
1394 return pa_stream_write(stream
->stream
, buffer
, bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
1397 static void pulse_write(struct pulse_stream
*stream
)
1399 /* write as much data to PA as we can */
1401 BYTE
*buf
= stream
->local_buffer
+ stream
->pa_offs_bytes
;
1402 UINT32 bytes
= pa_stream_writable_size(stream
->stream
);
1404 if (stream
->just_underran
)
1406 /* prebuffer with silence if needed */
1407 if(stream
->pa_held_bytes
< bytes
){
1408 to_write
= bytes
- stream
->pa_held_bytes
;
1409 TRACE("prebuffering %u frames of silence\n",
1410 (int)(to_write
/ pa_frame_size(&stream
->ss
)));
1411 buf
= calloc(1, to_write
);
1412 pa_stream_write(stream
->stream
, buf
, to_write
, NULL
, 0, PA_SEEK_RELATIVE
);
1416 stream
->just_underran
= FALSE
;
1419 buf
= stream
->local_buffer
+ stream
->pa_offs_bytes
;
1420 TRACE("held: %lu, avail: %u\n", stream
->pa_held_bytes
, bytes
);
1421 bytes
= min(stream
->pa_held_bytes
, bytes
);
1423 if (stream
->pa_offs_bytes
+ bytes
> stream
->real_bufsize_bytes
)
1425 to_write
= stream
->real_bufsize_bytes
- stream
->pa_offs_bytes
;
1426 TRACE("writing small chunk of %u bytes\n", to_write
);
1427 write_buffer(stream
, buf
, to_write
);
1428 stream
->pa_held_bytes
-= to_write
;
1429 to_write
= bytes
- to_write
;
1430 stream
->pa_offs_bytes
= 0;
1431 buf
= stream
->local_buffer
;
1436 TRACE("writing main chunk of %u bytes\n", to_write
);
1437 write_buffer(stream
, buf
, to_write
);
1438 stream
->pa_offs_bytes
+= to_write
;
1439 stream
->pa_offs_bytes
%= stream
->real_bufsize_bytes
;
1440 stream
->pa_held_bytes
-= to_write
;
1443 static void pulse_read(struct pulse_stream
*stream
)
1445 size_t bytes
= pa_stream_readable_size(stream
->stream
);
1447 TRACE("Readable total: %zu, fragsize: %u\n", bytes
, pa_stream_get_buffer_attr(stream
->stream
)->fragsize
);
1449 bytes
+= stream
->peek_len
- stream
->peek_ofs
;
1451 while (bytes
>= stream
->period_bytes
)
1453 BYTE
*dst
= NULL
, *src
;
1454 size_t src_len
, copy
, rem
= stream
->period_bytes
;
1456 if (stream
->started
)
1458 LARGE_INTEGER stamp
, freq
;
1461 if (!(p
= (ACPacket
*)list_head(&stream
->packet_free_head
)))
1463 p
= (ACPacket
*)list_head(&stream
->packet_filled_head
);
1466 next
= (ACPacket
*)p
->entry
.next
;
1469 p
= (ACPacket
*)list_tail(&stream
->packet_filled_head
);
1473 stream
->held_bytes
+= stream
->period_bytes
;
1475 NtQueryPerformanceCounter(&stamp
, &freq
);
1476 p
->qpcpos
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1478 list_remove(&p
->entry
);
1479 list_add_tail(&stream
->packet_filled_head
, &p
->entry
);
1486 if (stream
->peek_len
)
1488 copy
= min(rem
, stream
->peek_len
- stream
->peek_ofs
);
1492 memcpy(dst
, stream
->peek_buffer
+ stream
->peek_ofs
, copy
);
1497 stream
->peek_ofs
+= copy
;
1498 if(stream
->peek_len
== stream
->peek_ofs
)
1499 stream
->peek_len
= stream
->peek_ofs
= 0;
1502 else if (pa_stream_peek(stream
->stream
, (const void**)&src
, &src_len
) == 0 && src_len
)
1504 copy
= min(rem
, src_len
);
1508 memcpy(dst
, src
, copy
);
1510 silence_buffer(stream
->ss
.format
, dst
, copy
);
1519 if (src_len
> stream
->peek_buffer_len
)
1521 free(stream
->peek_buffer
);
1522 stream
->peek_buffer
= malloc(src_len
);
1523 stream
->peek_buffer_len
= src_len
;
1527 memcpy(stream
->peek_buffer
, src
+ copy
, src_len
- copy
);
1529 silence_buffer(stream
->ss
.format
, stream
->peek_buffer
, src_len
- copy
);
1531 stream
->peek_len
= src_len
- copy
;
1532 stream
->peek_ofs
= 0;
1535 pa_stream_drop(stream
->stream
);
1539 bytes
-= stream
->period_bytes
;
1543 static NTSTATUS
pulse_timer_loop(void *args
)
1545 struct timer_loop_params
*params
= args
;
1546 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1547 LARGE_INTEGER delay
;
1548 pa_usec_t last_time
;
1554 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1555 pa_stream_get_time(stream
->stream
, &last_time
);
1558 while (!stream
->please_quit
)
1560 pa_usec_t now
, adv_usec
= 0;
1563 NtDelayExecution(FALSE
, &delay
);
1567 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1569 o
= pa_stream_update_timing_info(stream
->stream
, pulse_op_cb
, &success
);
1572 while (pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1574 pa_operation_unref(o
);
1576 err
= pa_stream_get_time(stream
->stream
, &now
);
1579 TRACE("got now: %s, last time: %s\n", wine_dbgstr_longlong(now
), wine_dbgstr_longlong(last_time
));
1580 if (stream
->started
&& (stream
->dataflow
== eCapture
|| stream
->held_bytes
))
1582 if(stream
->just_underran
)
1585 stream
->just_started
= TRUE
;
1588 if (stream
->just_started
)
1590 /* let it play out a period to absorb some latency and get accurate timing */
1591 pa_usec_t diff
= now
- last_time
;
1593 if (diff
> stream
->mmdev_period_usec
)
1595 stream
->just_started
= FALSE
;
1601 INT32 adjust
= last_time
+ stream
->mmdev_period_usec
- now
;
1603 adv_usec
= now
- last_time
;
1605 if(adjust
> ((INT32
)(stream
->mmdev_period_usec
/ 2)))
1606 adjust
= stream
->mmdev_period_usec
/ 2;
1607 else if(adjust
< -((INT32
)(stream
->mmdev_period_usec
/ 2)))
1608 adjust
= -1 * stream
->mmdev_period_usec
/ 2;
1610 delay
.QuadPart
= -(stream
->mmdev_period_usec
+ adjust
) * 10;
1612 last_time
+= stream
->mmdev_period_usec
;
1615 if (stream
->dataflow
== eRender
)
1617 pulse_write(stream
);
1619 /* regardless of what PA does, advance one period */
1620 adv_bytes
= min(stream
->period_bytes
, stream
->held_bytes
);
1621 stream
->lcl_offs_bytes
+= adv_bytes
;
1622 stream
->lcl_offs_bytes
%= stream
->real_bufsize_bytes
;
1623 stream
->held_bytes
-= adv_bytes
;
1625 else if(stream
->dataflow
== eCapture
)
1633 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1638 NtSetEvent(stream
->event
, NULL
);
1640 TRACE("%p after update, adv usec: %d, held: %u, delay usec: %u\n",
1641 stream
, (int)adv_usec
,
1642 (int)(stream
->held_bytes
/ pa_frame_size(&stream
->ss
)),
1643 (unsigned int)(-delay
.QuadPart
/ 10));
1648 return STATUS_SUCCESS
;
1651 static NTSTATUS
pulse_start(void *args
)
1653 struct start_params
*params
= args
;
1654 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1658 params
->result
= S_OK
;
1660 if (!pulse_stream_valid(stream
))
1663 params
->result
= S_OK
;
1664 return STATUS_SUCCESS
;
1667 if ((stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !stream
->event
)
1670 params
->result
= AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1671 return STATUS_SUCCESS
;
1674 if (stream
->started
)
1677 params
->result
= AUDCLNT_E_NOT_STOPPED
;
1678 return STATUS_SUCCESS
;
1681 pulse_write(stream
);
1683 if (pa_stream_is_corked(stream
->stream
))
1685 o
= pa_stream_cork(stream
->stream
, 0, pulse_op_cb
, &success
);
1688 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1690 pa_operation_unref(o
);
1695 params
->result
= E_FAIL
;
1698 if (SUCCEEDED(params
->result
))
1700 stream
->started
= TRUE
;
1701 stream
->just_started
= TRUE
;
1704 return STATUS_SUCCESS
;
1707 static NTSTATUS
pulse_stop(void *args
)
1709 struct stop_params
*params
= args
;
1710 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1715 if (!pulse_stream_valid(stream
))
1718 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1719 return STATUS_SUCCESS
;
1722 if (!stream
->started
)
1725 params
->result
= S_FALSE
;
1726 return STATUS_SUCCESS
;
1729 params
->result
= S_OK
;
1730 if (stream
->dataflow
== eRender
)
1732 o
= pa_stream_cork(stream
->stream
, 1, pulse_op_cb
, &success
);
1735 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1737 pa_operation_unref(o
);
1742 params
->result
= E_FAIL
;
1744 if (SUCCEEDED(params
->result
))
1745 stream
->started
= FALSE
;
1747 return STATUS_SUCCESS
;
1750 static NTSTATUS
pulse_reset(void *args
)
1752 struct reset_params
*params
= args
;
1753 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1756 if (!pulse_stream_valid(stream
))
1759 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1760 return STATUS_SUCCESS
;
1763 if (stream
->started
)
1766 params
->result
= AUDCLNT_E_NOT_STOPPED
;
1767 return STATUS_SUCCESS
;
1773 params
->result
= AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1774 return STATUS_SUCCESS
;
1777 if (stream
->dataflow
== eRender
)
1779 /* If there is still data in the render buffer it needs to be removed from the server */
1781 if (stream
->held_bytes
)
1783 pa_operation
*o
= pa_stream_flush(stream
->stream
, pulse_op_cb
, &success
);
1786 while (pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1788 pa_operation_unref(o
);
1791 if (success
|| !stream
->held_bytes
)
1793 stream
->clock_lastpos
= stream
->clock_written
= 0;
1794 stream
->pa_offs_bytes
= stream
->lcl_offs_bytes
= 0;
1795 stream
->held_bytes
= stream
->pa_held_bytes
= 0;
1801 stream
->clock_written
+= stream
->held_bytes
;
1802 stream
->held_bytes
= 0;
1804 if ((p
= stream
->locked_ptr
))
1806 stream
->locked_ptr
= NULL
;
1807 list_add_tail(&stream
->packet_free_head
, &p
->entry
);
1809 list_move_tail(&stream
->packet_free_head
, &stream
->packet_filled_head
);
1812 params
->result
= S_OK
;
1813 return STATUS_SUCCESS
;
1816 static BOOL
alloc_tmp_buffer(struct pulse_stream
*stream
, SIZE_T bytes
)
1820 if (stream
->tmp_buffer_bytes
>= bytes
)
1823 if (stream
->tmp_buffer
)
1826 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1827 &size
, MEM_RELEASE
);
1828 stream
->tmp_buffer
= NULL
;
1829 stream
->tmp_buffer_bytes
= 0;
1831 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1832 zero_bits
, &bytes
, MEM_COMMIT
, PAGE_READWRITE
))
1835 stream
->tmp_buffer_bytes
= bytes
;
1839 static UINT32
pulse_render_padding(struct pulse_stream
*stream
)
1841 return stream
->held_bytes
/ pa_frame_size(&stream
->ss
);
1844 static UINT32
pulse_capture_padding(struct pulse_stream
*stream
)
1846 ACPacket
*packet
= stream
->locked_ptr
;
1847 if (!packet
&& !list_empty(&stream
->packet_filled_head
))
1849 packet
= (ACPacket
*)list_head(&stream
->packet_filled_head
);
1850 stream
->locked_ptr
= packet
;
1851 list_remove(&packet
->entry
);
1853 return stream
->held_bytes
/ pa_frame_size(&stream
->ss
);
1856 static NTSTATUS
pulse_get_render_buffer(void *args
)
1858 struct get_render_buffer_params
*params
= args
;
1859 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1861 UINT32 wri_offs_bytes
;
1864 if (!pulse_stream_valid(stream
))
1867 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1868 return STATUS_SUCCESS
;
1874 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
1875 return STATUS_SUCCESS
;
1878 if (!params
->frames
)
1881 *params
->data
= NULL
;
1882 params
->result
= S_OK
;
1883 return STATUS_SUCCESS
;
1886 if (stream
->held_bytes
/ pa_frame_size(&stream
->ss
) + params
->frames
> stream
->bufsize_frames
)
1889 params
->result
= AUDCLNT_E_BUFFER_TOO_LARGE
;
1890 return STATUS_SUCCESS
;
1893 bytes
= params
->frames
* pa_frame_size(&stream
->ss
);
1894 wri_offs_bytes
= (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1895 if (wri_offs_bytes
+ bytes
> stream
->real_bufsize_bytes
)
1897 if (!alloc_tmp_buffer(stream
, bytes
))
1900 params
->result
= E_OUTOFMEMORY
;
1901 return STATUS_SUCCESS
;
1903 *params
->data
= stream
->tmp_buffer
;
1904 stream
->locked
= -bytes
;
1908 *params
->data
= stream
->local_buffer
+ wri_offs_bytes
;
1909 stream
->locked
= bytes
;
1912 silence_buffer(stream
->ss
.format
, *params
->data
, bytes
);
1915 params
->result
= S_OK
;
1916 return STATUS_SUCCESS
;
1919 static void pulse_wrap_buffer(struct pulse_stream
*stream
, BYTE
*buffer
, UINT32 written_bytes
)
1921 UINT32 wri_offs_bytes
= (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1922 UINT32 chunk_bytes
= stream
->real_bufsize_bytes
- wri_offs_bytes
;
1924 if (written_bytes
<= chunk_bytes
)
1926 memcpy(stream
->local_buffer
+ wri_offs_bytes
, buffer
, written_bytes
);
1930 memcpy(stream
->local_buffer
+ wri_offs_bytes
, buffer
, chunk_bytes
);
1931 memcpy(stream
->local_buffer
, buffer
+ chunk_bytes
, written_bytes
- chunk_bytes
);
1935 static NTSTATUS
pulse_release_render_buffer(void *args
)
1937 struct release_render_buffer_params
*params
= args
;
1938 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1939 UINT32 written_bytes
;
1943 if (!stream
->locked
|| !params
->written_frames
)
1947 params
->result
= params
->written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1948 return STATUS_SUCCESS
;
1951 if (params
->written_frames
* pa_frame_size(&stream
->ss
) >
1952 (stream
->locked
>= 0 ? stream
->locked
: -stream
->locked
))
1955 params
->result
= AUDCLNT_E_INVALID_SIZE
;
1956 return STATUS_SUCCESS
;
1959 if (stream
->locked
>= 0)
1960 buffer
= stream
->local_buffer
+ (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1962 buffer
= stream
->tmp_buffer
;
1964 written_bytes
= params
->written_frames
* pa_frame_size(&stream
->ss
);
1965 if (params
->flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1966 silence_buffer(stream
->ss
.format
, buffer
, written_bytes
);
1968 if (stream
->locked
< 0)
1969 pulse_wrap_buffer(stream
, buffer
, written_bytes
);
1971 stream
->held_bytes
+= written_bytes
;
1972 stream
->pa_held_bytes
+= written_bytes
;
1973 if (stream
->pa_held_bytes
> stream
->real_bufsize_bytes
)
1975 stream
->pa_offs_bytes
+= stream
->pa_held_bytes
- stream
->real_bufsize_bytes
;
1976 stream
->pa_offs_bytes
%= stream
->real_bufsize_bytes
;
1977 stream
->pa_held_bytes
= stream
->real_bufsize_bytes
;
1979 stream
->clock_written
+= written_bytes
;
1982 /* push as much data as we can to pulseaudio too */
1983 pulse_write(stream
);
1985 TRACE("Released %u, held %lu\n", params
->written_frames
, stream
->held_bytes
/ pa_frame_size(&stream
->ss
));
1988 params
->result
= S_OK
;
1989 return STATUS_SUCCESS
;
1992 static NTSTATUS
pulse_get_capture_buffer(void *args
)
1994 struct get_capture_buffer_params
*params
= args
;
1995 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1999 if (!pulse_stream_valid(stream
))
2002 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2003 return STATUS_SUCCESS
;
2008 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
2009 return STATUS_SUCCESS
;
2012 pulse_capture_padding(stream
);
2013 if ((packet
= stream
->locked_ptr
))
2015 *params
->frames
= stream
->period_bytes
/ pa_frame_size(&stream
->ss
);
2017 if (packet
->discont
)
2018 *params
->flags
|= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY
;
2021 if (packet
->discont
)
2022 *params
->devpos
= (stream
->clock_written
+ stream
->period_bytes
) / pa_frame_size(&stream
->ss
);
2024 *params
->devpos
= stream
->clock_written
/ pa_frame_size(&stream
->ss
);
2027 *params
->qpcpos
= packet
->qpcpos
;
2028 *params
->data
= packet
->data
;
2031 *params
->frames
= 0;
2032 stream
->locked
= *params
->frames
;
2034 params
->result
= *params
->frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
2035 return STATUS_SUCCESS
;
2038 static NTSTATUS
pulse_release_capture_buffer(void *args
)
2040 struct release_capture_buffer_params
*params
= args
;
2041 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2044 if (!stream
->locked
&& params
->done
)
2047 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
2048 return STATUS_SUCCESS
;
2050 if (params
->done
&& stream
->locked
!= params
->done
)
2053 params
->result
= AUDCLNT_E_INVALID_SIZE
;
2054 return STATUS_SUCCESS
;
2058 ACPacket
*packet
= stream
->locked_ptr
;
2059 stream
->locked_ptr
= NULL
;
2060 stream
->held_bytes
-= stream
->period_bytes
;
2061 if (packet
->discont
)
2062 stream
->clock_written
+= 2 * stream
->period_bytes
;
2064 stream
->clock_written
+= stream
->period_bytes
;
2065 list_add_tail(&stream
->packet_free_head
, &packet
->entry
);
2069 params
->result
= S_OK
;
2070 return STATUS_SUCCESS
;
2073 static NTSTATUS
pulse_is_format_supported(void *args
)
2075 struct is_format_supported_params
*params
= args
;
2076 WAVEFORMATEXTENSIBLE in
;
2077 WAVEFORMATEXTENSIBLE
*out
;
2078 const WAVEFORMATEX
*fmt
= &in
.Format
;
2079 const BOOLEAN exclusive
= params
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
;
2081 params
->result
= S_OK
;
2083 if (!params
->fmt_in
|| (params
->share
== AUDCLNT_SHAREMODE_SHARED
&& !params
->fmt_out
))
2084 params
->result
= E_POINTER
;
2085 else if (params
->share
!= AUDCLNT_SHAREMODE_SHARED
&& params
->share
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
2086 params
->result
= E_INVALIDARG
;
2088 memcpy(&in
, params
->fmt_in
, params
->fmt_in
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
?
2089 sizeof(in
) : sizeof(in
.Format
));
2091 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
2092 if (fmt
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
))
2093 params
->result
= E_INVALIDARG
;
2094 else if (fmt
->nAvgBytesPerSec
== 0 || fmt
->nBlockAlign
== 0 ||
2095 (in
.Samples
.wValidBitsPerSample
> fmt
->wBitsPerSample
))
2096 params
->result
= E_INVALIDARG
;
2097 else if (fmt
->nChannels
== 0)
2098 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2102 if (FAILED(params
->result
))
2103 return STATUS_SUCCESS
;
2108 out
= params
->fmt_out
;
2109 memcpy(out
, fmt
, fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
?
2110 sizeof(*out
) : sizeof((*out
).Format
));
2113 switch (fmt
->wFormatTag
) {
2114 case WAVE_FORMAT_EXTENSIBLE
: {
2115 if ((fmt
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
) &&
2116 fmt
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
)) ||
2117 fmt
->nBlockAlign
!= fmt
->wBitsPerSample
/ 8 * fmt
->nChannels
||
2118 in
.Samples
.wValidBitsPerSample
> fmt
->wBitsPerSample
||
2119 fmt
->nAvgBytesPerSec
!= fmt
->nBlockAlign
* fmt
->nSamplesPerSec
) {
2120 params
->result
= E_INVALIDARG
;
2125 UINT32 mask
= 0, i
, channels
= 0;
2127 if (!(in
.dwChannelMask
& (SPEAKER_ALL
| SPEAKER_RESERVED
))) {
2128 for (i
= 1; !(i
& SPEAKER_RESERVED
); i
<<= 1) {
2129 if (i
& in
.dwChannelMask
) {
2135 if (channels
!= fmt
->nChannels
|| (in
.dwChannelMask
& ~mask
)) {
2136 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2140 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2145 if (IsEqualGUID(&in
.SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
2146 if (fmt
->wBitsPerSample
!= 32) {
2147 params
->result
= E_INVALIDARG
;
2151 if (in
.Samples
.wValidBitsPerSample
!= fmt
->wBitsPerSample
) {
2152 params
->result
= S_FALSE
;
2153 out
->Samples
.wValidBitsPerSample
= fmt
->wBitsPerSample
;
2155 } else if (IsEqualGUID(&in
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
2156 if (!fmt
->wBitsPerSample
|| fmt
->wBitsPerSample
> 32 || fmt
->wBitsPerSample
% 8) {
2157 params
->result
= E_INVALIDARG
;
2161 if (in
.Samples
.wValidBitsPerSample
!= fmt
->wBitsPerSample
&&
2162 !(fmt
->wBitsPerSample
== 32 &&
2163 in
.Samples
.wValidBitsPerSample
== 24)) {
2164 params
->result
= S_FALSE
;
2165 out
->Samples
.wValidBitsPerSample
= fmt
->wBitsPerSample
;
2169 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2175 case WAVE_FORMAT_ALAW
:
2176 case WAVE_FORMAT_MULAW
:
2177 if (fmt
->wBitsPerSample
!= 8) {
2178 params
->result
= E_INVALIDARG
;
2182 case WAVE_FORMAT_IEEE_FLOAT
:
2183 if (fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
&& fmt
->wBitsPerSample
!= 32) {
2184 params
->result
= E_INVALIDARG
;
2188 case WAVE_FORMAT_PCM
: {
2189 if (fmt
->wFormatTag
== WAVE_FORMAT_PCM
&&
2190 (!fmt
->wBitsPerSample
|| fmt
->wBitsPerSample
> 32 || fmt
->wBitsPerSample
% 8)) {
2191 params
->result
= E_INVALIDARG
;
2195 if (fmt
->nChannels
> 2) {
2196 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2200 /* fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
2201 * ignored, invalid values are happily accepted. */
2205 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2209 if (exclusive
) { /* This driver does not support exclusive mode. */
2210 if (params
->result
== S_OK
)
2211 params
->result
= params
->flow
== eCapture
?
2212 AUDCLNT_E_UNSUPPORTED_FORMAT
:
2213 AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
2214 else if (params
->result
== S_FALSE
)
2215 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2218 return STATUS_SUCCESS
;
2221 static NTSTATUS
pulse_get_mix_format(void *args
)
2223 struct get_mix_format_params
*params
= args
;
2224 struct list
*list
= (params
->flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
2227 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
2228 if (strcmp(params
->device
, dev
->pulse_name
))
2231 *params
->fmt
= dev
->fmt
;
2232 params
->result
= S_OK
;
2234 return STATUS_SUCCESS
;
2237 params
->result
= E_FAIL
;
2238 return STATUS_SUCCESS
;
2241 static NTSTATUS
pulse_get_device_period(void *args
)
2243 struct get_device_period_params
*params
= args
;
2245 params
->result
= get_device_period_helper(params
->flow
, params
->device
, params
->def_period
, params
->min_period
);
2246 return STATUS_SUCCESS
;
2249 static NTSTATUS
pulse_get_buffer_size(void *args
)
2251 struct get_buffer_size_params
*params
= args
;
2252 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2254 params
->result
= S_OK
;
2257 if (!pulse_stream_valid(stream
))
2258 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2260 *params
->frames
= stream
->bufsize_frames
;
2263 return STATUS_SUCCESS
;
2266 static NTSTATUS
pulse_get_latency(void *args
)
2268 struct get_latency_params
*params
= args
;
2269 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2270 const pa_buffer_attr
*attr
;
2274 if (!pulse_stream_valid(stream
)) {
2276 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2277 return STATUS_SUCCESS
;
2279 attr
= pa_stream_get_buffer_attr(stream
->stream
);
2280 if (stream
->dataflow
== eRender
)
2281 lat
= attr
->minreq
/ pa_frame_size(&stream
->ss
);
2283 lat
= attr
->fragsize
/ pa_frame_size(&stream
->ss
);
2284 *params
->latency
= (lat
* 10000000) / stream
->ss
.rate
+ stream
->def_period
;
2286 TRACE("Latency: %u ms\n", (unsigned)(*params
->latency
/ 10000));
2287 params
->result
= S_OK
;
2288 return STATUS_SUCCESS
;
2291 static NTSTATUS
pulse_get_current_padding(void *args
)
2293 struct get_current_padding_params
*params
= args
;
2294 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2297 if (!pulse_stream_valid(stream
))
2300 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2301 return STATUS_SUCCESS
;
2304 if (stream
->dataflow
== eRender
)
2305 *params
->padding
= pulse_render_padding(stream
);
2307 *params
->padding
= pulse_capture_padding(stream
);
2310 TRACE("%p Pad: %u ms (%u)\n", stream
, muldiv(*params
->padding
, 1000, stream
->ss
.rate
),
2312 params
->result
= S_OK
;
2313 return STATUS_SUCCESS
;
2316 static NTSTATUS
pulse_get_next_packet_size(void *args
)
2318 struct get_next_packet_size_params
*params
= args
;
2319 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2322 pulse_capture_padding(stream
);
2323 if (stream
->locked_ptr
)
2324 *params
->frames
= stream
->period_bytes
/ pa_frame_size(&stream
->ss
);
2326 *params
->frames
= 0;
2328 params
->result
= S_OK
;
2330 return STATUS_SUCCESS
;
2333 static NTSTATUS
pulse_get_frequency(void *args
)
2335 struct get_frequency_params
*params
= args
;
2336 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2339 if (!pulse_stream_valid(stream
))
2342 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2343 return STATUS_SUCCESS
;
2346 *params
->freq
= stream
->ss
.rate
;
2347 if (stream
->share
== AUDCLNT_SHAREMODE_SHARED
)
2348 *params
->freq
*= pa_frame_size(&stream
->ss
);
2350 params
->result
= S_OK
;
2351 return STATUS_SUCCESS
;
2354 static NTSTATUS
pulse_get_position(void *args
)
2356 struct get_position_params
*params
= args
;
2357 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2360 if (!pulse_stream_valid(stream
))
2363 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2364 return STATUS_SUCCESS
;
2367 *params
->pos
= stream
->clock_written
- stream
->held_bytes
;
2369 if (stream
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
|| params
->device
)
2370 *params
->pos
/= pa_frame_size(&stream
->ss
);
2372 /* Make time never go backwards */
2373 if (*params
->pos
< stream
->clock_lastpos
)
2374 *params
->pos
= stream
->clock_lastpos
;
2376 stream
->clock_lastpos
= *params
->pos
;
2379 TRACE("%p Position: %u\n", stream
, (unsigned)*params
->pos
);
2381 if (params
->qpctime
)
2383 LARGE_INTEGER stamp
, freq
;
2384 NtQueryPerformanceCounter(&stamp
, &freq
);
2385 *params
->qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
2388 params
->result
= S_OK
;
2389 return STATUS_SUCCESS
;
2392 static NTSTATUS
pulse_set_volumes(void *args
)
2394 struct set_volumes_params
*params
= args
;
2395 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2398 for (i
= 0; i
< stream
->ss
.channels
; i
++)
2399 stream
->vol
[i
] = params
->volumes
[i
] * params
->master_volume
* params
->session_volumes
[i
];
2401 return STATUS_SUCCESS
;
2404 static NTSTATUS
pulse_set_event_handle(void *args
)
2406 struct set_event_handle_params
*params
= args
;
2407 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2411 if (!pulse_stream_valid(stream
))
2412 hr
= AUDCLNT_E_DEVICE_INVALIDATED
;
2413 else if (!(stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
2414 hr
= AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
2415 else if (stream
->event
)
2416 hr
= HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
2418 stream
->event
= params
->event
;
2421 params
->result
= hr
;
2422 return STATUS_SUCCESS
;
2425 static NTSTATUS
pulse_is_started(void *args
)
2427 struct is_started_params
*params
= args
;
2428 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2431 params
->result
= pulse_stream_valid(stream
) && stream
->started
? S_OK
: S_FALSE
;
2434 return STATUS_SUCCESS
;
2437 static BOOL
get_device_path(PhysDevice
*dev
, struct get_prop_value_params
*params
)
2439 const GUID
*guid
= params
->guid
;
2440 PROPVARIANT
*out
= params
->value
;
2445 /* As hardly any audio devices have serial numbers, Windows instead
2446 appears to use a persistent random number. We emulate this here
2447 by instead using the last 8 hex digits of the GUID. */
2448 serial_number
= (guid
->Data4
[4] << 24) | (guid
->Data4
[5] << 16) | (guid
->Data4
[6] << 8) | guid
->Data4
[7];
2450 switch (dev
->bus_type
) {
2451 case phys_device_bus_pci
:
2452 len
= sprintf(path
, "{1}.HDAUDIO\\FUNC_01&VEN_%04X&DEV_%04X\\%u&%08X", dev
->vendor_id
, dev
->product_id
, dev
->index
, serial_number
);
2454 case phys_device_bus_usb
:
2455 len
= sprintf(path
, "{1}.USB\\VID_%04X&PID_%04X\\%u&%08X", dev
->vendor_id
, dev
->product_id
, dev
->index
, serial_number
);
2458 len
= sprintf(path
, "{1}.ROOT\\MEDIA\\%04u", dev
->index
);
2462 if (*params
->buffer_size
< ++len
* sizeof(WCHAR
)) {
2463 params
->result
= E_NOT_SUFFICIENT_BUFFER
;
2464 *params
->buffer_size
= len
* sizeof(WCHAR
);
2468 out
->vt
= VT_LPWSTR
;
2469 out
->pwszVal
= params
->buffer
;
2471 ntdll_umbstowcs(path
, len
, out
->pwszVal
, len
);
2473 params
->result
= S_OK
;
2478 static NTSTATUS
pulse_get_prop_value(void *args
)
2480 static const GUID PKEY_AudioEndpoint_GUID
= {
2481 0x1da5d803, 0xd492, 0x4edd, {0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e}
2483 static const PROPERTYKEY devicepath_key
= { /* undocumented? - {b3f8fa53-0004-438e-9003-51a46e139bfc},2 */
2484 {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2
2486 struct get_prop_value_params
*params
= args
;
2487 struct list
*list
= (params
->flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
2490 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
2491 if (strcmp(params
->device
, dev
->pulse_name
))
2493 if (IsEqualPropertyKey(*params
->prop
, devicepath_key
)) {
2494 get_device_path(dev
, params
);
2495 return STATUS_SUCCESS
;
2496 } else if (IsEqualGUID(¶ms
->prop
->fmtid
, &PKEY_AudioEndpoint_GUID
)) {
2497 switch (params
->prop
->pid
) {
2498 case 0: /* FormFactor */
2499 params
->value
->vt
= VT_UI4
;
2500 params
->value
->ulVal
= dev
->form
;
2501 params
->result
= S_OK
;
2502 return STATUS_SUCCESS
;
2503 case 3: /* PhysicalSpeakers */
2504 if (!dev
->channel_mask
)
2506 params
->value
->vt
= VT_UI4
;
2507 params
->value
->ulVal
= dev
->channel_mask
;
2508 params
->result
= S_OK
;
2509 return STATUS_SUCCESS
;
2513 params
->result
= E_NOTIMPL
;
2514 return STATUS_SUCCESS
;
2518 params
->result
= E_FAIL
;
2519 return STATUS_SUCCESS
;
2522 const unixlib_entry_t __wine_unix_call_funcs
[] =
2524 pulse_process_attach
,
2525 pulse_process_detach
,
2527 pulse_get_endpoint_ids
,
2528 pulse_create_stream
,
2529 pulse_release_stream
,
2534 pulse_get_render_buffer
,
2535 pulse_release_render_buffer
,
2536 pulse_get_capture_buffer
,
2537 pulse_release_capture_buffer
,
2538 pulse_is_format_supported
,
2539 pulse_get_mix_format
,
2540 pulse_get_device_period
,
2541 pulse_get_buffer_size
,
2543 pulse_get_current_padding
,
2544 pulse_get_next_packet_size
,
2545 pulse_get_frequency
,
2548 pulse_set_event_handle
,
2551 pulse_get_prop_value
,
2552 pulse_not_implemented
,
2553 pulse_not_implemented
,
2554 pulse_not_implemented
,
2555 pulse_not_implemented
,
2556 pulse_not_implemented
,
2557 pulse_not_implemented
,
2560 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs
) == funcs_count
);
2566 static NTSTATUS
pulse_wow64_main_loop(void *args
)
2572 struct main_loop_params params
=
2574 .event
= ULongToHandle(params32
->event
)
2576 return pulse_main_loop(¶ms
);
2579 static NTSTATUS
pulse_wow64_get_endpoint_ids(void *args
)
2588 unsigned int default_idx
;
2590 struct get_endpoint_ids_params params
=
2592 .flow
= params32
->flow
,
2593 .endpoints
= ULongToPtr(params32
->endpoints
),
2594 .size
= params32
->size
2596 pulse_get_endpoint_ids(¶ms
);
2597 params32
->size
= params
.size
;
2598 params32
->result
= params
.result
;
2599 params32
->num
= params
.num
;
2600 params32
->default_idx
= params
.default_idx
;
2601 return STATUS_SUCCESS
;
2604 static NTSTATUS
pulse_wow64_create_stream(void *args
)
2611 AUDCLNT_SHAREMODE share
;
2613 REFERENCE_TIME duration
;
2614 REFERENCE_TIME period
;
2617 PTR32 channel_count
;
2620 struct create_stream_params params
=
2622 .name
= ULongToPtr(params32
->name
),
2623 .device
= ULongToPtr(params32
->device
),
2624 .flow
= params32
->flow
,
2625 .share
= params32
->share
,
2626 .flags
= params32
->flags
,
2627 .duration
= params32
->duration
,
2628 .period
= params32
->period
,
2629 .fmt
= ULongToPtr(params32
->fmt
),
2630 .channel_count
= ULongToPtr(params32
->channel_count
),
2631 .stream
= ULongToPtr(params32
->stream
)
2633 pulse_create_stream(¶ms
);
2634 params32
->result
= params
.result
;
2635 return STATUS_SUCCESS
;
2638 static NTSTATUS
pulse_wow64_release_stream(void *args
)
2642 stream_handle stream
;
2646 struct release_stream_params params
=
2648 .stream
= params32
->stream
,
2649 .timer_thread
= ULongToHandle(params32
->timer_thread
)
2651 pulse_release_stream(¶ms
);
2652 params32
->result
= params
.result
;
2653 return STATUS_SUCCESS
;
2656 static NTSTATUS
pulse_wow64_get_render_buffer(void *args
)
2660 stream_handle stream
;
2666 struct get_render_buffer_params params
=
2668 .stream
= params32
->stream
,
2669 .frames
= params32
->frames
,
2672 pulse_get_render_buffer(¶ms
);
2673 params32
->result
= params
.result
;
2674 *(unsigned int *)ULongToPtr(params32
->data
) = PtrToUlong(data
);
2675 return STATUS_SUCCESS
;
2678 static NTSTATUS
pulse_wow64_get_capture_buffer(void *args
)
2682 stream_handle stream
;
2691 struct get_capture_buffer_params params
=
2693 .stream
= params32
->stream
,
2695 .frames
= ULongToPtr(params32
->frames
),
2696 .flags
= ULongToPtr(params32
->flags
),
2697 .devpos
= ULongToPtr(params32
->devpos
),
2698 .qpcpos
= ULongToPtr(params32
->qpcpos
)
2700 pulse_get_capture_buffer(¶ms
);
2701 params32
->result
= params
.result
;
2702 *(unsigned int *)ULongToPtr(params32
->data
) = PtrToUlong(data
);
2703 return STATUS_SUCCESS
;
2706 static NTSTATUS
pulse_wow64_is_format_supported(void *args
)
2712 AUDCLNT_SHAREMODE share
;
2717 struct is_format_supported_params params
=
2719 .device
= ULongToPtr(params32
->device
),
2720 .flow
= params32
->flow
,
2721 .share
= params32
->share
,
2722 .fmt_in
= ULongToPtr(params32
->fmt_in
),
2723 .fmt_out
= ULongToPtr(params32
->fmt_out
)
2725 pulse_is_format_supported(¶ms
);
2726 params32
->result
= params
.result
;
2727 return STATUS_SUCCESS
;
2730 static NTSTATUS
pulse_wow64_get_mix_format(void *args
)
2739 struct get_mix_format_params params
=
2741 .device
= ULongToPtr(params32
->device
),
2742 .flow
= params32
->flow
,
2743 .fmt
= ULongToPtr(params32
->fmt
),
2745 pulse_get_mix_format(¶ms
);
2746 params32
->result
= params
.result
;
2747 return STATUS_SUCCESS
;
2750 static NTSTATUS
pulse_wow64_get_device_period(void *args
)
2760 struct get_device_period_params params
=
2762 .device
= ULongToPtr(params32
->device
),
2763 .flow
= params32
->flow
,
2764 .def_period
= ULongToPtr(params32
->def_period
),
2765 .min_period
= ULongToPtr(params32
->min_period
),
2767 pulse_get_device_period(¶ms
);
2768 params32
->result
= params
.result
;
2769 return STATUS_SUCCESS
;
2772 static NTSTATUS
pulse_wow64_get_buffer_size(void *args
)
2776 stream_handle stream
;
2780 struct get_buffer_size_params params
=
2782 .stream
= params32
->stream
,
2783 .frames
= ULongToPtr(params32
->frames
)
2785 pulse_get_buffer_size(¶ms
);
2786 params32
->result
= params
.result
;
2787 return STATUS_SUCCESS
;
2790 static NTSTATUS
pulse_wow64_get_latency(void *args
)
2794 stream_handle stream
;
2798 struct get_latency_params params
=
2800 .stream
= params32
->stream
,
2801 .latency
= ULongToPtr(params32
->latency
)
2803 pulse_get_latency(¶ms
);
2804 params32
->result
= params
.result
;
2805 return STATUS_SUCCESS
;
2808 static NTSTATUS
pulse_wow64_get_current_padding(void *args
)
2812 stream_handle stream
;
2816 struct get_current_padding_params params
=
2818 .stream
= params32
->stream
,
2819 .padding
= ULongToPtr(params32
->padding
)
2821 pulse_get_current_padding(¶ms
);
2822 params32
->result
= params
.result
;
2823 return STATUS_SUCCESS
;
2826 static NTSTATUS
pulse_wow64_get_next_packet_size(void *args
)
2830 stream_handle stream
;
2834 struct get_next_packet_size_params params
=
2836 .stream
= params32
->stream
,
2837 .frames
= ULongToPtr(params32
->frames
)
2839 pulse_get_next_packet_size(¶ms
);
2840 params32
->result
= params
.result
;
2841 return STATUS_SUCCESS
;
2844 static NTSTATUS
pulse_wow64_get_frequency(void *args
)
2848 stream_handle stream
;
2852 struct get_frequency_params params
=
2854 .stream
= params32
->stream
,
2855 .freq
= ULongToPtr(params32
->freq
)
2857 pulse_get_frequency(¶ms
);
2858 params32
->result
= params
.result
;
2859 return STATUS_SUCCESS
;
2862 static NTSTATUS
pulse_wow64_get_position(void *args
)
2866 stream_handle stream
;
2872 struct get_position_params params
=
2874 .stream
= params32
->stream
,
2875 .device
= params32
->device
,
2876 .pos
= ULongToPtr(params32
->pos
),
2877 .qpctime
= ULongToPtr(params32
->qpctime
)
2879 pulse_get_position(¶ms
);
2880 params32
->result
= params
.result
;
2881 return STATUS_SUCCESS
;
2884 static NTSTATUS
pulse_wow64_set_volumes(void *args
)
2888 stream_handle stream
;
2889 float master_volume
;
2891 PTR32 session_volumes
;
2893 struct set_volumes_params params
=
2895 .stream
= params32
->stream
,
2896 .master_volume
= params32
->master_volume
,
2897 .volumes
= ULongToPtr(params32
->volumes
),
2898 .session_volumes
= ULongToPtr(params32
->session_volumes
),
2900 return pulse_set_volumes(¶ms
);
2903 static NTSTATUS
pulse_wow64_set_event_handle(void *args
)
2907 stream_handle stream
;
2911 struct set_event_handle_params params
=
2913 .stream
= params32
->stream
,
2914 .event
= ULongToHandle(params32
->event
)
2916 pulse_set_event_handle(¶ms
);
2917 params32
->result
= params
.result
;
2918 return STATUS_SUCCESS
;
2921 static NTSTATUS
pulse_wow64_test_connect(void *args
)
2926 enum driver_priority priority
;
2928 struct test_connect_params params
=
2930 .name
= ULongToPtr(params32
->name
),
2932 pulse_test_connect(¶ms
);
2933 params32
->priority
= params
.priority
;
2934 return STATUS_SUCCESS
;
2937 static NTSTATUS
pulse_wow64_get_prop_value(void *args
)
2939 struct propvariant32
2942 WORD pad1
, pad2
, pad3
;
2947 ULARGE_INTEGER uhVal
;
2958 PTR32 buffer
; /* caller allocated buffer to hold value's strings */
2962 struct get_prop_value_params params
=
2964 .device
= ULongToPtr(params32
->device
),
2965 .flow
= params32
->flow
,
2966 .guid
= ULongToPtr(params32
->guid
),
2967 .prop
= ULongToPtr(params32
->prop
),
2969 .buffer
= ULongToPtr(params32
->buffer
),
2970 .buffer_size
= ULongToPtr(params32
->buffer_size
)
2972 pulse_get_prop_value(¶ms
);
2973 params32
->result
= params
.result
;
2974 if (SUCCEEDED(params
.result
))
2976 value32
= UlongToPtr(params32
->value
);
2977 value32
->vt
= value
.vt
;
2981 value32
->ulVal
= value
.ulVal
;
2984 value32
->ptr
= params32
->buffer
;
2987 FIXME("Unhandled vt %04x\n", value
.vt
);
2990 return STATUS_SUCCESS
;
2993 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
2995 pulse_process_attach
,
2996 pulse_process_detach
,
2997 pulse_wow64_main_loop
,
2998 pulse_wow64_get_endpoint_ids
,
2999 pulse_wow64_create_stream
,
3000 pulse_wow64_release_stream
,
3005 pulse_wow64_get_render_buffer
,
3006 pulse_release_render_buffer
,
3007 pulse_wow64_get_capture_buffer
,
3008 pulse_release_capture_buffer
,
3009 pulse_wow64_is_format_supported
,
3010 pulse_wow64_get_mix_format
,
3011 pulse_wow64_get_device_period
,
3012 pulse_wow64_get_buffer_size
,
3013 pulse_wow64_get_latency
,
3014 pulse_wow64_get_current_padding
,
3015 pulse_wow64_get_next_packet_size
,
3016 pulse_wow64_get_frequency
,
3017 pulse_wow64_get_position
,
3018 pulse_wow64_set_volumes
,
3019 pulse_wow64_set_event_handle
,
3020 pulse_wow64_test_connect
,
3022 pulse_wow64_get_prop_value
,
3023 pulse_not_implemented
,
3024 pulse_not_implemented
,
3025 pulse_not_implemented
,
3026 pulse_not_implemented
,
3027 pulse_not_implemented
,
3028 pulse_not_implemented
,
3031 C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs
) == funcs_count
);