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 const REFERENCE_TIME MinimumPeriod
= 30000;
117 static const REFERENCE_TIME DefaultPeriod
= 100000;
119 static pthread_mutex_t pulse_mutex
;
120 static pthread_cond_t pulse_cond
= PTHREAD_COND_INITIALIZER
;
122 static ULONG_PTR zero_bits
= 0;
124 static NTSTATUS
pulse_not_implemented(void *args
)
126 return STATUS_SUCCESS
;
129 static void pulse_lock(void)
131 pthread_mutex_lock(&pulse_mutex
);
134 static void pulse_unlock(void)
136 pthread_mutex_unlock(&pulse_mutex
);
139 static int pulse_cond_wait(void)
141 return pthread_cond_wait(&pulse_cond
, &pulse_mutex
);
144 static void pulse_broadcast(void)
146 pthread_cond_broadcast(&pulse_cond
);
149 static struct pulse_stream
*handle_get_stream(stream_handle h
)
151 return (struct pulse_stream
*)(UINT_PTR
)h
;
154 static void dump_attr(const pa_buffer_attr
*attr
)
156 TRACE("maxlength: %u\n", attr
->maxlength
);
157 TRACE("minreq: %u\n", attr
->minreq
);
158 TRACE("fragsize: %u\n", attr
->fragsize
);
159 TRACE("tlength: %u\n", attr
->tlength
);
160 TRACE("prebuf: %u\n", attr
->prebuf
);
163 static void free_phys_device_lists(void)
165 static struct list
*const lists
[] = { &g_phys_speakers
, &g_phys_sources
, NULL
};
166 struct list
*const *list
= lists
;
167 PhysDevice
*dev
, *dev_next
;
170 LIST_FOR_EACH_ENTRY_SAFE(dev
, dev_next
, *list
, PhysDevice
, entry
) {
177 /* copied from kernelbase */
178 static int muldiv(int a
, int b
, int c
)
184 /* We want to deal with a positive divisor to simplify the logic. */
191 /* If the result is positive, we "add" to round. else, we subtract to round. */
192 if ((a
< 0 && b
< 0) || (a
>= 0 && b
>= 0))
193 ret
= (((LONGLONG
)a
* b
) + (c
/ 2)) / c
;
195 ret
= (((LONGLONG
)a
* b
) - (c
/ 2)) / c
;
197 if (ret
> 2147483647 || ret
< -2147483647) return -1;
201 static char *wstr_to_str(const WCHAR
*wstr
)
203 const int len
= wcslen(wstr
);
204 char *str
= malloc(len
* 3 + 1);
205 ntdll_wcstoumbs(wstr
, len
+ 1, str
, len
* 3 + 1, FALSE
);
209 /* Following pulseaudio design here, mainloop has the lock taken whenever
210 * it is handling something for pulse, and the lock is required whenever
211 * doing any pa_* call that can affect the state in any way
213 * pa_cond_wait is used when waiting on results, because the mainloop needs
214 * the same lock taken to affect the state
216 * This is basically the same as the pa_threaded_mainloop implementation,
217 * but that cannot be used because it uses pthread_create directly
219 * pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock
220 * pa_threaded_mainloop_signal -> pthread_cond_broadcast
221 * pa_threaded_mainloop_wait -> pthread_cond_wait
223 static int pulse_poll_func(struct pollfd
*ufds
, unsigned long nfds
, int timeout
, void *userdata
)
227 r
= poll(ufds
, nfds
, timeout
);
232 static NTSTATUS
pulse_process_attach(void *args
)
234 pthread_mutexattr_t attr
;
236 pthread_mutexattr_init(&attr
);
237 pthread_mutexattr_setprotocol(&attr
, PTHREAD_PRIO_INHERIT
);
239 if (pthread_mutex_init(&pulse_mutex
, &attr
) != 0)
240 pthread_mutex_init(&pulse_mutex
, NULL
);
243 if (NtCurrentTeb()->WowTebOffset
)
245 SYSTEM_BASIC_INFORMATION info
;
247 NtQuerySystemInformation(SystemEmulationBasicInformation
, &info
, sizeof(info
), NULL
);
248 zero_bits
= (ULONG_PTR
)info
.HighestUserAddress
| 0x7fffffff;
252 return STATUS_SUCCESS
;
255 static NTSTATUS
pulse_process_detach(void *args
)
257 free_phys_device_lists();
260 pa_context_disconnect(pulse_ctx
);
261 pa_context_unref(pulse_ctx
);
264 pa_mainloop_quit(pulse_ml
, 0);
266 return STATUS_SUCCESS
;
269 static NTSTATUS
pulse_main_loop(void *args
)
271 struct main_loop_params
*params
= args
;
274 pulse_ml
= pa_mainloop_new();
275 pa_mainloop_set_poll_func(pulse_ml
, pulse_poll_func
, NULL
);
276 NtSetEvent(params
->event
, NULL
);
277 pa_mainloop_run(pulse_ml
, &ret
);
278 pa_mainloop_free(pulse_ml
);
280 return STATUS_SUCCESS
;
283 static NTSTATUS
pulse_get_endpoint_ids(void *args
)
285 struct get_endpoint_ids_params
*params
= args
;
286 struct list
*list
= (params
->flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
287 struct endpoint
*endpoint
= params
->endpoints
;
288 size_t len
, name_len
, needed
;
292 params
->num
= list_count(list
);
293 offset
= needed
= params
->num
* sizeof(*params
->endpoints
);
295 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
296 name_len
= lstrlenW(dev
->name
) + 1;
297 len
= strlen(dev
->pulse_name
) + 1;
298 needed
+= name_len
* sizeof(WCHAR
) + ((len
+ 1) & ~1);
300 if (needed
<= params
->size
) {
301 endpoint
->name
= offset
;
302 memcpy((char *)params
->endpoints
+ offset
, dev
->name
, name_len
* sizeof(WCHAR
));
303 offset
+= name_len
* sizeof(WCHAR
);
304 endpoint
->device
= offset
;
305 memcpy((char *)params
->endpoints
+ offset
, dev
->pulse_name
, len
);
306 offset
+= (len
+ 1) & ~1;
310 params
->default_idx
= 0;
312 if (needed
> params
->size
) {
313 params
->size
= needed
;
314 params
->result
= HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
316 params
->result
= S_OK
;
317 return STATUS_SUCCESS
;
320 static void pulse_contextcallback(pa_context
*c
, void *userdata
)
322 switch (pa_context_get_state(c
)) {
324 FIXME("Unhandled state: %i\n", pa_context_get_state(c
));
327 case PA_CONTEXT_CONNECTING
:
328 case PA_CONTEXT_UNCONNECTED
:
329 case PA_CONTEXT_AUTHORIZING
:
330 case PA_CONTEXT_SETTING_NAME
:
331 case PA_CONTEXT_TERMINATED
:
332 TRACE("State change to %i\n", pa_context_get_state(c
));
335 case PA_CONTEXT_READY
:
339 case PA_CONTEXT_FAILED
:
340 WARN("Context failed: %s\n", pa_strerror(pa_context_errno(c
)));
346 static void pulse_stream_state(pa_stream
*s
, void *user
)
348 pa_stream_state_t state
= pa_stream_get_state(s
);
349 TRACE("Stream state changed to %i\n", state
);
353 static void pulse_attr_update(pa_stream
*s
, void *user
) {
354 const pa_buffer_attr
*attr
= pa_stream_get_buffer_attr(s
);
355 TRACE("New attributes or device moved:\n");
359 static void pulse_underflow_callback(pa_stream
*s
, void *userdata
)
361 struct pulse_stream
*stream
= userdata
;
362 WARN("%p: Underflow\n", userdata
);
363 stream
->just_underran
= TRUE
;
366 static void pulse_started_callback(pa_stream
*s
, void *userdata
)
368 TRACE("%p: (Re)started playing\n", userdata
);
371 static void pulse_op_cb(pa_stream
*s
, int success
, void *user
)
373 TRACE("Success: %i\n", success
);
374 *(int*)user
= success
;
378 static void silence_buffer(pa_sample_format_t format
, BYTE
*buffer
, UINT32 bytes
)
380 memset(buffer
, format
== PA_SAMPLE_U8
? 0x80 : 0, bytes
);
383 static BOOL
pulse_stream_valid(struct pulse_stream
*stream
)
385 return pa_stream_get_state(stream
->stream
) == PA_STREAM_READY
;
388 static HRESULT
pulse_connect(const char *name
)
390 pa_context_state_t state
;
392 if (pulse_ctx
&& PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx
)))
395 pa_context_unref(pulse_ctx
);
397 pulse_ctx
= pa_context_new(pa_mainloop_get_api(pulse_ml
), name
);
399 ERR("Failed to create context\n");
403 pa_context_set_state_callback(pulse_ctx
, pulse_contextcallback
, NULL
);
405 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx
), PA_API_VERSION
);
406 if (pa_context_connect(pulse_ctx
, NULL
, 0, NULL
) < 0)
409 /* Wait for connection */
410 while ((state
= pa_context_get_state(pulse_ctx
)) != PA_CONTEXT_READY
&&
411 state
!= PA_CONTEXT_FAILED
&& state
!= PA_CONTEXT_TERMINATED
)
414 if (state
!= PA_CONTEXT_READY
)
417 TRACE("Connected to server %s with protocol version: %i.\n",
418 pa_context_get_server(pulse_ctx
),
419 pa_context_get_server_protocol_version(pulse_ctx
));
423 pa_context_unref(pulse_ctx
);
428 static UINT
pulse_channel_map_to_channel_mask(const pa_channel_map
*map
)
433 for (i
= 0; i
< map
->channels
; ++i
) {
434 switch (map
->map
[i
]) {
435 default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map
->map
[i
])); break;
436 case PA_CHANNEL_POSITION_FRONT_LEFT
: mask
|= SPEAKER_FRONT_LEFT
; break;
437 case PA_CHANNEL_POSITION_MONO
:
438 case PA_CHANNEL_POSITION_FRONT_CENTER
: mask
|= SPEAKER_FRONT_CENTER
; break;
439 case PA_CHANNEL_POSITION_FRONT_RIGHT
: mask
|= SPEAKER_FRONT_RIGHT
; break;
440 case PA_CHANNEL_POSITION_REAR_LEFT
: mask
|= SPEAKER_BACK_LEFT
; break;
441 case PA_CHANNEL_POSITION_REAR_CENTER
: mask
|= SPEAKER_BACK_CENTER
; break;
442 case PA_CHANNEL_POSITION_REAR_RIGHT
: mask
|= SPEAKER_BACK_RIGHT
; break;
443 case PA_CHANNEL_POSITION_LFE
: mask
|= SPEAKER_LOW_FREQUENCY
; break;
444 case PA_CHANNEL_POSITION_SIDE_LEFT
: mask
|= SPEAKER_SIDE_LEFT
; break;
445 case PA_CHANNEL_POSITION_SIDE_RIGHT
: mask
|= SPEAKER_SIDE_RIGHT
; break;
446 case PA_CHANNEL_POSITION_TOP_CENTER
: mask
|= SPEAKER_TOP_CENTER
; break;
447 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT
: mask
|= SPEAKER_TOP_FRONT_LEFT
; break;
448 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER
: mask
|= SPEAKER_TOP_FRONT_CENTER
; break;
449 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
: mask
|= SPEAKER_TOP_FRONT_RIGHT
; break;
450 case PA_CHANNEL_POSITION_TOP_REAR_LEFT
: mask
|= SPEAKER_TOP_BACK_LEFT
; break;
451 case PA_CHANNEL_POSITION_TOP_REAR_CENTER
: mask
|= SPEAKER_TOP_BACK_CENTER
; break;
452 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT
: mask
|= SPEAKER_TOP_BACK_RIGHT
; break;
453 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
: mask
|= SPEAKER_FRONT_LEFT_OF_CENTER
; break;
454 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
: mask
|= SPEAKER_FRONT_RIGHT_OF_CENTER
; break;
461 #define MAX_DEVICE_NAME_LEN 62
463 static WCHAR
*get_device_name(const char *desc
, pa_proplist
*proplist
)
466 Some broken apps (e.g. Split/Second with fmodex) can't handle names that
467 are too long and crash even on native. If the device desc is too long,
468 we'll attempt to incrementally build it to try to stay under the limit.
469 ( + 1 is to check against truncated buffer after ntdll_umbstowcs )
471 WCHAR buf
[MAX_DEVICE_NAME_LEN
+ 1];
473 /* For monitors of sinks; this does not seem to be localized in PA either */
474 static const WCHAR monitor_of
[] = {'M','o','n','i','t','o','r',' ','o','f',' '};
476 size_t len
= strlen(desc
);
479 if (!(name
= malloc((len
+ 1) * sizeof(WCHAR
))))
481 if (!(len
= ntdll_umbstowcs(desc
, len
, name
, len
))) {
486 if (len
> MAX_DEVICE_NAME_LEN
&& proplist
) {
487 const char *prop
= pa_proplist_gets(proplist
, PA_PROP_DEVICE_CLASS
);
488 unsigned prop_len
, rem
= ARRAY_SIZE(buf
);
489 BOOL monitor
= FALSE
;
491 if (prop
&& !strcmp(prop
, "monitor")) {
492 rem
-= ARRAY_SIZE(monitor_of
);
496 prop
= pa_proplist_gets(proplist
, PA_PROP_DEVICE_PRODUCT_NAME
);
497 if (!prop
|| !prop
[0] ||
498 !(prop_len
= ntdll_umbstowcs(prop
, strlen(prop
), buf
, rem
)) || prop_len
== rem
) {
499 prop
= pa_proplist_gets(proplist
, "alsa.card_name");
500 if (!prop
|| !prop
[0] ||
501 !(prop_len
= ntdll_umbstowcs(prop
, strlen(prop
), buf
, rem
)) || prop_len
== rem
)
506 /* We know we have a name that fits within the limit now */
510 memcpy(p
, monitor_of
, sizeof(monitor_of
));
511 p
+= ARRAY_SIZE(monitor_of
);
513 len
= ntdll_umbstowcs(prop
, strlen(prop
), p
, rem
);
520 prop
= pa_proplist_gets(proplist
, PA_PROP_DEVICE_PROFILE_DESCRIPTION
);
521 if (prop
&& prop
[0] && (len
= ntdll_umbstowcs(prop
, strlen(prop
), p
+ 1, rem
)) && len
!= rem
) {
531 if ((tmp
= realloc(name
, (len
+ 1) * sizeof(WCHAR
))))
536 static void fill_device_info(PhysDevice
*dev
, pa_proplist
*p
)
540 dev
->bus_type
= phys_device_bus_invalid
;
547 if ((buffer
= pa_proplist_gets(p
, PA_PROP_DEVICE_BUS
))) {
548 if (!strcmp(buffer
, "usb"))
549 dev
->bus_type
= phys_device_bus_usb
;
550 else if (!strcmp(buffer
, "pci"))
551 dev
->bus_type
= phys_device_bus_pci
;
554 if ((buffer
= pa_proplist_gets(p
, PA_PROP_DEVICE_VENDOR_ID
)))
555 dev
->vendor_id
= strtol(buffer
, NULL
, 16);
557 if ((buffer
= pa_proplist_gets(p
, PA_PROP_DEVICE_PRODUCT_ID
)))
558 dev
->product_id
= strtol(buffer
, NULL
, 16);
561 static void pulse_add_device(struct list
*list
, pa_proplist
*proplist
, int index
, EndpointFormFactor form
,
562 UINT channel_mask
, const char *pulse_name
, const char *desc
)
564 size_t len
= strlen(pulse_name
);
565 PhysDevice
*dev
= malloc(FIELD_OFFSET(PhysDevice
, pulse_name
[len
+ 1]));
570 if (!(dev
->name
= get_device_name(desc
, proplist
))) {
576 dev
->channel_mask
= channel_mask
;
579 fill_device_info(dev
, proplist
);
580 memcpy(dev
->pulse_name
, pulse_name
, len
+ 1);
582 list_add_tail(list
, &dev
->entry
);
584 TRACE("%s\n", debugstr_w(dev
->name
));
587 static void pulse_phys_speakers_cb(pa_context
*c
, const pa_sink_info
*i
, int eol
, void *userdata
)
589 struct list
*speaker
;
592 if (!i
|| !i
->name
|| !i
->name
[0])
594 channel_mask
= pulse_channel_map_to_channel_mask(&i
->channel_map
);
596 /* For default PulseAudio render device, OR together all of the
597 * PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */
598 speaker
= list_head(&g_phys_speakers
);
600 LIST_ENTRY(speaker
, PhysDevice
, entry
)->channel_mask
|= channel_mask
;
602 pulse_add_device(&g_phys_speakers
, i
->proplist
, i
->index
, Speakers
, channel_mask
, i
->name
, i
->description
);
605 static void pulse_phys_sources_cb(pa_context
*c
, const pa_source_info
*i
, int eol
, void *userdata
)
607 if (!i
|| !i
->name
|| !i
->name
[0])
609 pulse_add_device(&g_phys_sources
, i
->proplist
, i
->index
,
610 (i
->monitor_of_sink
== PA_INVALID_INDEX
) ? Microphone
: LineLevel
, 0, i
->name
, i
->description
);
613 /* For most hardware on Windows, users must choose a configuration with an even
614 * number of channels (stereo, quad, 5.1, 7.1). Users can then disable
615 * channels, but those channels are still reported to applications from
616 * GetMixFormat! Some applications behave badly if given an odd number of
617 * channels (e.g. 2.1). Here, we find the nearest configuration that Windows
618 * would report for a given channel layout. */
619 static void convert_channel_map(const pa_channel_map
*pa_map
, WAVEFORMATEXTENSIBLE
*fmt
)
621 UINT pa_mask
= pulse_channel_map_to_channel_mask(pa_map
);
623 TRACE("got mask for PA: 0x%x\n", pa_mask
);
625 if (pa_map
->channels
== 1)
627 fmt
->Format
.nChannels
= 1;
628 fmt
->dwChannelMask
= pa_mask
;
632 /* compare against known configurations and find smallest configuration
633 * which is a superset of the given speakers */
635 if (pa_map
->channels
<= 2 &&
636 (pa_mask
& ~KSAUDIO_SPEAKER_STEREO
) == 0)
638 fmt
->Format
.nChannels
= 2;
639 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_STEREO
;
643 if (pa_map
->channels
<= 4 &&
644 (pa_mask
& ~KSAUDIO_SPEAKER_QUAD
) == 0)
646 fmt
->Format
.nChannels
= 4;
647 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_QUAD
;
651 if (pa_map
->channels
<= 4 &&
652 (pa_mask
& ~KSAUDIO_SPEAKER_SURROUND
) == 0)
654 fmt
->Format
.nChannels
= 4;
655 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_SURROUND
;
659 if (pa_map
->channels
<= 6 &&
660 (pa_mask
& ~KSAUDIO_SPEAKER_5POINT1
) == 0)
662 fmt
->Format
.nChannels
= 6;
663 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_5POINT1
;
667 if (pa_map
->channels
<= 6 &&
668 (pa_mask
& ~KSAUDIO_SPEAKER_5POINT1_SURROUND
) == 0)
670 fmt
->Format
.nChannels
= 6;
671 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_5POINT1_SURROUND
;
675 if (pa_map
->channels
<= 8 &&
676 (pa_mask
& ~KSAUDIO_SPEAKER_7POINT1
) == 0)
678 fmt
->Format
.nChannels
= 8;
679 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_7POINT1
;
683 if (pa_map
->channels
<= 8 &&
684 (pa_mask
& ~KSAUDIO_SPEAKER_7POINT1_SURROUND
) == 0)
686 fmt
->Format
.nChannels
= 8;
687 fmt
->dwChannelMask
= KSAUDIO_SPEAKER_7POINT1_SURROUND
;
691 /* oddball format, report truthfully */
692 fmt
->Format
.nChannels
= pa_map
->channels
;
693 fmt
->dwChannelMask
= pa_mask
;
696 static void pulse_probe_settings(int render
, const char *pulse_name
, WAVEFORMATEXTENSIBLE
*fmt
, REFERENCE_TIME
*def_period
, REFERENCE_TIME
*min_period
)
698 WAVEFORMATEX
*wfx
= &fmt
->Format
;
704 unsigned int length
= 0;
706 if (pulse_name
&& !pulse_name
[0])
709 pa_channel_map_init_auto(&map
, 2, PA_CHANNEL_MAP_ALSA
);
711 ss
.format
= PA_SAMPLE_FLOAT32LE
;
712 ss
.channels
= map
.channels
;
716 attr
.minreq
= attr
.fragsize
= pa_frame_size(&ss
);
719 stream
= pa_stream_new(pulse_ctx
, "format test stream", &ss
, &map
);
721 pa_stream_set_state_callback(stream
, pulse_stream_state
, NULL
);
725 ret
= pa_stream_connect_playback(stream
, pulse_name
, &attr
,
726 PA_STREAM_START_CORKED
|PA_STREAM_FIX_RATE
|PA_STREAM_FIX_CHANNELS
|PA_STREAM_EARLY_REQUESTS
, NULL
, NULL
);
728 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
);
730 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
731 pa_stream_get_state(stream
) == PA_STREAM_CREATING
)
733 if (pa_stream_get_state(stream
) == PA_STREAM_READY
) {
734 ss
= *pa_stream_get_sample_spec(stream
);
735 map
= *pa_stream_get_channel_map(stream
);
737 length
= pa_stream_get_buffer_attr(stream
)->minreq
;
739 length
= pa_stream_get_buffer_attr(stream
)->fragsize
;
740 pa_stream_disconnect(stream
);
741 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
742 pa_stream_get_state(stream
) == PA_STREAM_READY
)
748 pa_stream_unref(stream
);
751 *def_period
= *min_period
= pa_bytes_to_usec(10 * length
, &ss
);
753 if (*min_period
< MinimumPeriod
)
754 *min_period
= MinimumPeriod
;
756 if (*def_period
< DefaultPeriod
)
757 *def_period
= DefaultPeriod
;
759 wfx
->wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
760 wfx
->cbSize
= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
);
762 convert_channel_map(&map
, fmt
);
764 wfx
->wBitsPerSample
= 8 * pa_sample_size_of_format(ss
.format
);
765 wfx
->nSamplesPerSec
= ss
.rate
;
766 wfx
->nBlockAlign
= wfx
->nChannels
* wfx
->wBitsPerSample
/ 8;
767 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
768 if (ss
.format
!= PA_SAMPLE_S24_32LE
)
769 fmt
->Samples
.wValidBitsPerSample
= wfx
->wBitsPerSample
;
771 fmt
->Samples
.wValidBitsPerSample
= 24;
772 if (ss
.format
== PA_SAMPLE_FLOAT32LE
)
773 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
775 fmt
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
778 /* some poorly-behaved applications call audio functions during DllMain, so we
779 * have to do as much as possible without creating a new thread. this function
780 * sets up a synchronous connection to verify the server is running and query
782 static NTSTATUS
pulse_test_connect(void *args
)
784 struct test_connect_params
*params
= args
;
788 char *name
= wstr_to_str(params
->name
);
791 pulse_ml
= pa_mainloop_new();
793 pa_mainloop_set_poll_func(pulse_ml
, pulse_poll_func
, NULL
);
795 pulse_ctx
= pa_context_new(pa_mainloop_get_api(pulse_ml
), name
);
800 ERR("Failed to create context\n");
801 pa_mainloop_free(pulse_ml
);
804 params
->priority
= Priority_Unavailable
;
805 return STATUS_SUCCESS
;
808 pa_context_set_state_callback(pulse_ctx
, pulse_contextcallback
, NULL
);
810 TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx
), PA_API_VERSION
);
811 if (pa_context_connect(pulse_ctx
, NULL
, 0, NULL
) < 0)
814 /* Wait for connection */
815 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0) {
816 pa_context_state_t state
= pa_context_get_state(pulse_ctx
);
818 if (state
== PA_CONTEXT_FAILED
|| state
== PA_CONTEXT_TERMINATED
)
821 if (state
== PA_CONTEXT_READY
)
825 if (pa_context_get_state(pulse_ctx
) != PA_CONTEXT_READY
)
828 TRACE("Test-connected to server %s with protocol version: %i.\n",
829 pa_context_get_server(pulse_ctx
),
830 pa_context_get_server_protocol_version(pulse_ctx
));
832 free_phys_device_lists();
833 list_init(&g_phys_speakers
);
834 list_init(&g_phys_sources
);
836 /* Burnout Paradise Remastered expects device name to have a space. */
837 pulse_add_device(&g_phys_speakers
, NULL
, 0, Speakers
, 0, "", "PulseAudio Output");
838 pulse_add_device(&g_phys_sources
, NULL
, 0, Microphone
, 0, "", "PulseAudio Input");
840 o
= pa_context_get_sink_info_list(pulse_ctx
, &pulse_phys_speakers_cb
, NULL
);
842 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
843 pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
845 pa_operation_unref(o
);
848 o
= pa_context_get_source_info_list(pulse_ctx
, &pulse_phys_sources_cb
, NULL
);
850 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
851 pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
853 pa_operation_unref(o
);
856 LIST_FOR_EACH_ENTRY(dev
, &g_phys_speakers
, PhysDevice
, entry
) {
857 pulse_probe_settings(1, dev
->pulse_name
, &dev
->fmt
, &dev
->def_period
, &dev
->min_period
);
860 LIST_FOR_EACH_ENTRY(dev
, &g_phys_sources
, PhysDevice
, entry
) {
861 pulse_probe_settings(0, dev
->pulse_name
, &dev
->fmt
, &dev
->def_period
, &dev
->min_period
);
864 pa_context_unref(pulse_ctx
);
866 pa_mainloop_free(pulse_ml
);
871 params
->priority
= Priority_Preferred
;
872 return STATUS_SUCCESS
;
875 pa_context_unref(pulse_ctx
);
877 pa_mainloop_free(pulse_ml
);
880 params
->priority
= Priority_Unavailable
;
881 return STATUS_SUCCESS
;
884 static UINT
get_channel_mask(unsigned int channels
)
890 return KSAUDIO_SPEAKER_MONO
;
892 return KSAUDIO_SPEAKER_STEREO
;
894 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
896 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
898 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
900 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
902 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
904 return KSAUDIO_SPEAKER_7POINT1_SURROUND
; /* Vista deprecates 7POINT1 */
906 FIXME("Unknown speaker configuration: %u\n", channels
);
910 static const enum pa_channel_position pulse_pos_from_wfx
[] = {
911 PA_CHANNEL_POSITION_FRONT_LEFT
,
912 PA_CHANNEL_POSITION_FRONT_RIGHT
,
913 PA_CHANNEL_POSITION_FRONT_CENTER
,
914 PA_CHANNEL_POSITION_LFE
,
915 PA_CHANNEL_POSITION_REAR_LEFT
,
916 PA_CHANNEL_POSITION_REAR_RIGHT
,
917 PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
,
918 PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
,
919 PA_CHANNEL_POSITION_REAR_CENTER
,
920 PA_CHANNEL_POSITION_SIDE_LEFT
,
921 PA_CHANNEL_POSITION_SIDE_RIGHT
,
922 PA_CHANNEL_POSITION_TOP_CENTER
,
923 PA_CHANNEL_POSITION_TOP_FRONT_LEFT
,
924 PA_CHANNEL_POSITION_TOP_FRONT_CENTER
,
925 PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
,
926 PA_CHANNEL_POSITION_TOP_REAR_LEFT
,
927 PA_CHANNEL_POSITION_TOP_REAR_CENTER
,
928 PA_CHANNEL_POSITION_TOP_REAR_RIGHT
931 static HRESULT
pulse_spec_from_waveformat(struct pulse_stream
*stream
, const WAVEFORMATEX
*fmt
)
933 pa_channel_map_init(&stream
->map
);
934 stream
->ss
.rate
= fmt
->nSamplesPerSec
;
935 stream
->ss
.format
= PA_SAMPLE_INVALID
;
937 switch(fmt
->wFormatTag
) {
938 case WAVE_FORMAT_IEEE_FLOAT
:
939 if (!fmt
->nChannels
|| fmt
->nChannels
> 2 || fmt
->wBitsPerSample
!= 32)
941 stream
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
942 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
944 case WAVE_FORMAT_PCM
:
945 if (!fmt
->nChannels
|| fmt
->nChannels
> 2)
947 if (fmt
->wBitsPerSample
== 8)
948 stream
->ss
.format
= PA_SAMPLE_U8
;
949 else if (fmt
->wBitsPerSample
== 16)
950 stream
->ss
.format
= PA_SAMPLE_S16LE
;
952 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
953 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
955 case WAVE_FORMAT_EXTENSIBLE
: {
956 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)fmt
;
957 UINT mask
= wfe
->dwChannelMask
;
959 if (fmt
->cbSize
!= (sizeof(*wfe
) - sizeof(*fmt
)) && fmt
->cbSize
!= sizeof(*wfe
))
961 if (IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
962 (!wfe
->Samples
.wValidBitsPerSample
|| wfe
->Samples
.wValidBitsPerSample
== 32) &&
963 fmt
->wBitsPerSample
== 32)
964 stream
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
965 else if (IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
966 DWORD valid
= wfe
->Samples
.wValidBitsPerSample
;
968 valid
= fmt
->wBitsPerSample
;
969 if (!valid
|| valid
> fmt
->wBitsPerSample
)
971 switch (fmt
->wBitsPerSample
) {
974 stream
->ss
.format
= PA_SAMPLE_U8
;
978 stream
->ss
.format
= PA_SAMPLE_S16LE
;
982 stream
->ss
.format
= PA_SAMPLE_S24LE
;
986 stream
->ss
.format
= PA_SAMPLE_S24_32LE
;
987 else if (valid
== 32)
988 stream
->ss
.format
= PA_SAMPLE_S32LE
;
991 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
994 stream
->map
.channels
= fmt
->nChannels
;
995 if (!mask
|| (mask
& (SPEAKER_ALL
|SPEAKER_RESERVED
)))
996 mask
= get_channel_mask(fmt
->nChannels
);
997 for (j
= 0; j
< ARRAY_SIZE(pulse_pos_from_wfx
) && i
< fmt
->nChannels
; ++j
) {
999 stream
->map
.map
[i
++] = pulse_pos_from_wfx
[j
];
1002 /* Special case for mono since pulse appears to map it differently */
1003 if (mask
== SPEAKER_FRONT_CENTER
)
1004 stream
->map
.map
[0] = PA_CHANNEL_POSITION_MONO
;
1006 if (i
< fmt
->nChannels
|| (mask
& SPEAKER_RESERVED
)) {
1007 stream
->map
.channels
= 0;
1008 ERR("Invalid channel mask: %i/%i and %x(%x)\n", i
, fmt
->nChannels
, mask
, (unsigned)wfe
->dwChannelMask
);
1013 case WAVE_FORMAT_ALAW
:
1014 case WAVE_FORMAT_MULAW
:
1015 if (fmt
->wBitsPerSample
!= 8) {
1016 FIXME("Unsupported bpp %u for LAW\n", fmt
->wBitsPerSample
);
1017 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1019 if (fmt
->nChannels
!= 1 && fmt
->nChannels
!= 2) {
1020 FIXME("Unsupported channels %u for LAW\n", fmt
->nChannels
);
1021 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1023 stream
->ss
.format
= fmt
->wFormatTag
== WAVE_FORMAT_MULAW
? PA_SAMPLE_ULAW
: PA_SAMPLE_ALAW
;
1024 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
1027 WARN("Unhandled tag %x\n", fmt
->wFormatTag
);
1028 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1030 stream
->ss
.channels
= stream
->map
.channels
;
1031 if (!pa_channel_map_valid(&stream
->map
) || stream
->ss
.format
== PA_SAMPLE_INVALID
) {
1032 ERR("Invalid format! Channel spec valid: %i, format: %i\n",
1033 pa_channel_map_valid(&stream
->map
), stream
->ss
.format
);
1034 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1039 static HRESULT
pulse_stream_connect(struct pulse_stream
*stream
, const char *pulse_name
, UINT32 period_bytes
)
1041 pa_stream_flags_t flags
= PA_STREAM_START_CORKED
| PA_STREAM_START_UNMUTED
| PA_STREAM_ADJUST_LATENCY
;
1045 pa_buffer_attr attr
;
1047 ret
= InterlockedIncrement(&number
);
1048 sprintf(buffer
, "audio stream #%i", ret
);
1049 stream
->stream
= pa_stream_new(pulse_ctx
, buffer
, &stream
->ss
, &stream
->map
);
1051 if (!stream
->stream
) {
1052 WARN("pa_stream_new returned error %i\n", pa_context_errno(pulse_ctx
));
1053 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1056 pa_stream_set_state_callback(stream
->stream
, pulse_stream_state
, stream
);
1057 pa_stream_set_buffer_attr_callback(stream
->stream
, pulse_attr_update
, stream
);
1058 pa_stream_set_moved_callback(stream
->stream
, pulse_attr_update
, stream
);
1060 /* PulseAudio will fill in correct values */
1061 attr
.minreq
= attr
.fragsize
= period_bytes
;
1062 attr
.tlength
= period_bytes
* 3;
1063 attr
.maxlength
= stream
->bufsize_frames
* pa_frame_size(&stream
->ss
);
1064 attr
.prebuf
= pa_frame_size(&stream
->ss
);
1067 /* If specific device was requested, use it exactly */
1069 flags
|= PA_STREAM_DONT_MOVE
;
1071 pulse_name
= NULL
; /* use default */
1073 if (stream
->dataflow
== eRender
)
1074 ret
= pa_stream_connect_playback(stream
->stream
, pulse_name
, &attr
, flags
, NULL
, NULL
);
1076 ret
= pa_stream_connect_record(stream
->stream
, pulse_name
, &attr
, flags
);
1078 WARN("Returns %i\n", ret
);
1079 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1081 while (pa_stream_get_state(stream
->stream
) == PA_STREAM_CREATING
)
1083 if (pa_stream_get_state(stream
->stream
) != PA_STREAM_READY
)
1084 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1086 if (stream
->dataflow
== eRender
) {
1087 pa_stream_set_underflow_callback(stream
->stream
, pulse_underflow_callback
, stream
);
1088 pa_stream_set_started_callback(stream
->stream
, pulse_started_callback
, stream
);
1093 static HRESULT
get_device_period_helper(EDataFlow flow
, const char *pulse_name
, REFERENCE_TIME
*def
, REFERENCE_TIME
*min
)
1095 struct list
*list
= (flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
1102 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
1103 if (strcmp(pulse_name
, dev
->pulse_name
))
1107 *def
= dev
->def_period
;
1109 *min
= dev
->min_period
;
1116 static NTSTATUS
pulse_create_stream(void *args
)
1118 struct create_stream_params
*params
= args
;
1119 REFERENCE_TIME period
, duration
= params
->duration
;
1120 struct pulse_stream
*stream
;
1121 unsigned int i
, bufsize_bytes
;
1125 if (params
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
) {
1126 params
->result
= AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
1127 return STATUS_SUCCESS
;
1132 name
= wstr_to_str(params
->name
);
1133 params
->result
= pulse_connect(name
);
1136 if (FAILED(params
->result
))
1139 return STATUS_SUCCESS
;
1142 if (!(stream
= calloc(1, sizeof(*stream
))))
1145 params
->result
= E_OUTOFMEMORY
;
1146 return STATUS_SUCCESS
;
1149 stream
->dataflow
= params
->flow
;
1150 for (i
= 0; i
< ARRAY_SIZE(stream
->vol
); ++i
)
1151 stream
->vol
[i
] = 1.f
;
1153 hr
= pulse_spec_from_waveformat(stream
, params
->fmt
);
1154 TRACE("Obtaining format returns %08x\n", (unsigned)hr
);
1160 hr
= get_device_period_helper(params
->flow
, params
->device
, &period
, NULL
);
1164 if (duration
< 3 * period
)
1165 duration
= 3 * period
;
1167 stream
->def_period
= period
;
1169 stream
->period_bytes
= pa_frame_size(&stream
->ss
) * muldiv(period
, stream
->ss
.rate
, 10000000);
1171 stream
->bufsize_frames
= ceil((duration
/ 10000000.) * params
->fmt
->nSamplesPerSec
);
1172 bufsize_bytes
= stream
->bufsize_frames
* pa_frame_size(&stream
->ss
);
1173 stream
->mmdev_period_usec
= period
/ 10;
1175 stream
->share
= params
->share
;
1176 stream
->flags
= params
->flags
;
1177 hr
= pulse_stream_connect(stream
, params
->device
, stream
->period_bytes
);
1178 if (SUCCEEDED(hr
)) {
1180 const pa_buffer_attr
*attr
= pa_stream_get_buffer_attr(stream
->stream
);
1183 stream
->attr
= *attr
;
1184 /* Update frames according to new size */
1186 if (stream
->dataflow
== eRender
) {
1187 size
= stream
->real_bufsize_bytes
=
1188 stream
->bufsize_frames
* 2 * pa_frame_size(&stream
->ss
);
1189 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1190 zero_bits
, &size
, MEM_COMMIT
, PAGE_READWRITE
))
1193 UINT32 i
, capture_packets
;
1195 if ((unalign
= bufsize_bytes
% stream
->period_bytes
))
1196 bufsize_bytes
+= stream
->period_bytes
- unalign
;
1197 stream
->bufsize_frames
= bufsize_bytes
/ pa_frame_size(&stream
->ss
);
1198 stream
->real_bufsize_bytes
= bufsize_bytes
;
1200 capture_packets
= stream
->real_bufsize_bytes
/ stream
->period_bytes
;
1202 size
= stream
->real_bufsize_bytes
+ capture_packets
* sizeof(ACPacket
);
1203 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1204 zero_bits
, &size
, MEM_COMMIT
, PAGE_READWRITE
))
1207 ACPacket
*cur_packet
= (ACPacket
*)((char*)stream
->local_buffer
+ stream
->real_bufsize_bytes
);
1208 BYTE
*data
= stream
->local_buffer
;
1209 silence_buffer(stream
->ss
.format
, stream
->local_buffer
, stream
->real_bufsize_bytes
);
1210 list_init(&stream
->packet_free_head
);
1211 list_init(&stream
->packet_filled_head
);
1212 for (i
= 0; i
< capture_packets
; ++i
, ++cur_packet
) {
1213 list_add_tail(&stream
->packet_free_head
, &cur_packet
->entry
);
1214 cur_packet
->data
= data
;
1215 data
+= stream
->period_bytes
;
1221 *params
->channel_count
= stream
->ss
.channels
;
1222 *params
->stream
= (stream_handle
)(UINT_PTR
)stream
;
1225 if (FAILED(params
->result
= hr
)) {
1226 free(stream
->local_buffer
);
1227 if (stream
->stream
) {
1228 pa_stream_disconnect(stream
->stream
);
1229 pa_stream_unref(stream
->stream
);
1235 return STATUS_SUCCESS
;
1238 static NTSTATUS
pulse_release_stream(void *args
)
1240 struct release_stream_params
*params
= args
;
1241 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1244 if(params
->timer_thread
) {
1245 stream
->please_quit
= TRUE
;
1246 NtWaitForSingleObject(params
->timer_thread
, FALSE
, NULL
);
1247 NtClose(params
->timer_thread
);
1251 if (PA_STREAM_IS_GOOD(pa_stream_get_state(stream
->stream
))) {
1252 pa_stream_disconnect(stream
->stream
);
1253 while (PA_STREAM_IS_GOOD(pa_stream_get_state(stream
->stream
)))
1256 pa_stream_unref(stream
->stream
);
1259 if (stream
->tmp_buffer
) {
1261 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1262 &size
, MEM_RELEASE
);
1264 if (stream
->local_buffer
) {
1266 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1267 &size
, MEM_RELEASE
);
1269 free(stream
->peek_buffer
);
1271 return STATUS_SUCCESS
;
1274 static int write_buffer(const struct pulse_stream
*stream
, BYTE
*buffer
, UINT32 bytes
)
1276 const float *vol
= stream
->vol
;
1277 UINT32 i
, channels
, mute
= 0;
1278 BOOL adjust
= FALSE
;
1281 if (!bytes
) return 0;
1283 /* Adjust the buffer based on the volume for each channel */
1284 channels
= stream
->ss
.channels
;
1285 for (i
= 0; i
< channels
; i
++)
1287 adjust
|= vol
[i
] != 1.0f
;
1291 if (mute
== channels
)
1293 silence_buffer(stream
->ss
.format
, buffer
, bytes
);
1296 if (!adjust
) goto write
;
1298 end
= buffer
+ bytes
;
1299 switch (stream
->ss
.format
)
1301 #ifndef WORDS_BIGENDIAN
1302 #define PROCESS_BUFFER(type) do \
1304 type *p = (type*)buffer; \
1307 for (i = 0; i < channels; i++) \
1308 p[i] = p[i] * vol[i]; \
1310 } while ((BYTE*)p != end); \
1312 case PA_SAMPLE_S16LE
:
1313 PROCESS_BUFFER(INT16
);
1315 case PA_SAMPLE_S32LE
:
1316 PROCESS_BUFFER(INT32
);
1318 case PA_SAMPLE_FLOAT32LE
:
1319 PROCESS_BUFFER(float);
1321 #undef PROCESS_BUFFER
1322 case PA_SAMPLE_S24_32LE
:
1324 UINT32
*p
= (UINT32
*)buffer
;
1327 for (i
= 0; i
< channels
; i
++)
1329 p
[i
] = (INT32
)((INT32
)(p
[i
] << 8) * vol
[i
]);
1333 } while ((BYTE
*)p
!= end
);
1336 case PA_SAMPLE_S24LE
:
1338 /* do it 12 bytes at a time until it is no longer possible */
1339 UINT32
*q
= (UINT32
*)buffer
;
1343 while (end
- (BYTE
*)q
>= 12)
1347 v
[1] = q
[1] << 16 | (q
[0] >> 16 & ~0xff);
1348 v
[2] = q
[2] << 24 | (q
[1] >> 8 & ~0xff);
1349 v
[3] = q
[2] & ~0xff;
1350 for (k
= 0; k
< 4; k
++)
1352 v
[k
] = (INT32
)((INT32
)v
[k
] * vol
[i
]);
1353 if (++i
== channels
) i
= 0;
1355 *q
++ = v
[0] >> 8 | (v
[1] & ~0xff) << 16;
1356 *q
++ = v
[1] >> 16 | (v
[2] & ~0xff) << 8;
1357 *q
++ = v
[2] >> 24 | (v
[3] & ~0xff);
1362 UINT32 v
= (INT32
)((INT32
)(p
[0] << 8 | p
[1] << 16 | p
[2] << 24) * vol
[i
]);
1363 *p
++ = v
>> 8 & 0xff;
1364 *p
++ = v
>> 16 & 0xff;
1366 if (++i
== channels
) i
= 0;
1373 UINT8
*p
= (UINT8
*)buffer
;
1376 for (i
= 0; i
< channels
; i
++)
1377 p
[i
] = (int)((p
[i
] - 128) * vol
[i
]) + 128;
1379 } while ((BYTE
*)p
!= end
);
1382 case PA_SAMPLE_ALAW
:
1384 UINT8
*p
= (UINT8
*)buffer
;
1387 for (i
= 0; i
< channels
; i
++)
1388 p
[i
] = mult_alaw_sample(p
[i
], vol
[i
]);
1390 } while ((BYTE
*)p
!= end
);
1393 case PA_SAMPLE_ULAW
:
1395 UINT8
*p
= (UINT8
*)buffer
;
1398 for (i
= 0; i
< channels
; i
++)
1399 p
[i
] = mult_ulaw_sample(p
[i
], vol
[i
]);
1401 } while ((BYTE
*)p
!= end
);
1405 TRACE("Unhandled format %i, not adjusting volume.\n", stream
->ss
.format
);
1410 return pa_stream_write(stream
->stream
, buffer
, bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
1413 static void pulse_write(struct pulse_stream
*stream
)
1415 /* write as much data to PA as we can */
1417 BYTE
*buf
= stream
->local_buffer
+ stream
->pa_offs_bytes
;
1418 UINT32 bytes
= pa_stream_writable_size(stream
->stream
);
1420 if (stream
->just_underran
)
1422 /* prebuffer with silence if needed */
1423 if(stream
->pa_held_bytes
< bytes
){
1424 to_write
= bytes
- stream
->pa_held_bytes
;
1425 TRACE("prebuffering %u frames of silence\n",
1426 (int)(to_write
/ pa_frame_size(&stream
->ss
)));
1427 buf
= calloc(1, to_write
);
1428 pa_stream_write(stream
->stream
, buf
, to_write
, NULL
, 0, PA_SEEK_RELATIVE
);
1432 stream
->just_underran
= FALSE
;
1435 buf
= stream
->local_buffer
+ stream
->pa_offs_bytes
;
1436 TRACE("held: %lu, avail: %u\n", stream
->pa_held_bytes
, bytes
);
1437 bytes
= min(stream
->pa_held_bytes
, bytes
);
1439 if (stream
->pa_offs_bytes
+ bytes
> stream
->real_bufsize_bytes
)
1441 to_write
= stream
->real_bufsize_bytes
- stream
->pa_offs_bytes
;
1442 TRACE("writing small chunk of %u bytes\n", to_write
);
1443 write_buffer(stream
, buf
, to_write
);
1444 stream
->pa_held_bytes
-= to_write
;
1445 to_write
= bytes
- to_write
;
1446 stream
->pa_offs_bytes
= 0;
1447 buf
= stream
->local_buffer
;
1452 TRACE("writing main chunk of %u bytes\n", to_write
);
1453 write_buffer(stream
, buf
, to_write
);
1454 stream
->pa_offs_bytes
+= to_write
;
1455 stream
->pa_offs_bytes
%= stream
->real_bufsize_bytes
;
1456 stream
->pa_held_bytes
-= to_write
;
1459 static void pulse_read(struct pulse_stream
*stream
)
1461 size_t bytes
= pa_stream_readable_size(stream
->stream
);
1463 TRACE("Readable total: %zu, fragsize: %u\n", bytes
, pa_stream_get_buffer_attr(stream
->stream
)->fragsize
);
1465 bytes
+= stream
->peek_len
- stream
->peek_ofs
;
1467 while (bytes
>= stream
->period_bytes
)
1469 BYTE
*dst
= NULL
, *src
;
1470 size_t src_len
, copy
, rem
= stream
->period_bytes
;
1472 if (stream
->started
)
1474 LARGE_INTEGER stamp
, freq
;
1477 if (!(p
= (ACPacket
*)list_head(&stream
->packet_free_head
)))
1479 p
= (ACPacket
*)list_head(&stream
->packet_filled_head
);
1482 next
= (ACPacket
*)p
->entry
.next
;
1485 p
= (ACPacket
*)list_tail(&stream
->packet_filled_head
);
1489 stream
->held_bytes
+= stream
->period_bytes
;
1491 NtQueryPerformanceCounter(&stamp
, &freq
);
1492 p
->qpcpos
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1494 list_remove(&p
->entry
);
1495 list_add_tail(&stream
->packet_filled_head
, &p
->entry
);
1502 if (stream
->peek_len
)
1504 copy
= min(rem
, stream
->peek_len
- stream
->peek_ofs
);
1508 memcpy(dst
, stream
->peek_buffer
+ stream
->peek_ofs
, copy
);
1513 stream
->peek_ofs
+= copy
;
1514 if(stream
->peek_len
== stream
->peek_ofs
)
1515 stream
->peek_len
= stream
->peek_ofs
= 0;
1518 else if (pa_stream_peek(stream
->stream
, (const void**)&src
, &src_len
) == 0 && src_len
)
1520 copy
= min(rem
, src_len
);
1524 memcpy(dst
, src
, copy
);
1526 silence_buffer(stream
->ss
.format
, dst
, copy
);
1535 if (src_len
> stream
->peek_buffer_len
)
1537 free(stream
->peek_buffer
);
1538 stream
->peek_buffer
= malloc(src_len
);
1539 stream
->peek_buffer_len
= src_len
;
1543 memcpy(stream
->peek_buffer
, src
+ copy
, src_len
- copy
);
1545 silence_buffer(stream
->ss
.format
, stream
->peek_buffer
, src_len
- copy
);
1547 stream
->peek_len
= src_len
- copy
;
1548 stream
->peek_ofs
= 0;
1551 pa_stream_drop(stream
->stream
);
1555 bytes
-= stream
->period_bytes
;
1559 static NTSTATUS
pulse_timer_loop(void *args
)
1561 struct timer_loop_params
*params
= args
;
1562 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1563 LARGE_INTEGER delay
;
1564 pa_usec_t last_time
;
1570 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1571 pa_stream_get_time(stream
->stream
, &last_time
);
1574 while (!stream
->please_quit
)
1576 pa_usec_t now
, adv_usec
= 0;
1579 NtDelayExecution(FALSE
, &delay
);
1583 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1585 o
= pa_stream_update_timing_info(stream
->stream
, pulse_op_cb
, &success
);
1588 while (pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1590 pa_operation_unref(o
);
1592 err
= pa_stream_get_time(stream
->stream
, &now
);
1595 TRACE("got now: %s, last time: %s\n", wine_dbgstr_longlong(now
), wine_dbgstr_longlong(last_time
));
1596 if (stream
->started
&& (stream
->dataflow
== eCapture
|| stream
->held_bytes
))
1598 if(stream
->just_underran
)
1601 stream
->just_started
= TRUE
;
1604 if (stream
->just_started
)
1606 /* let it play out a period to absorb some latency and get accurate timing */
1607 pa_usec_t diff
= now
- last_time
;
1609 if (diff
> stream
->mmdev_period_usec
)
1611 stream
->just_started
= FALSE
;
1617 INT32 adjust
= last_time
+ stream
->mmdev_period_usec
- now
;
1619 adv_usec
= now
- last_time
;
1621 if(adjust
> ((INT32
)(stream
->mmdev_period_usec
/ 2)))
1622 adjust
= stream
->mmdev_period_usec
/ 2;
1623 else if(adjust
< -((INT32
)(stream
->mmdev_period_usec
/ 2)))
1624 adjust
= -1 * stream
->mmdev_period_usec
/ 2;
1626 delay
.QuadPart
= -(stream
->mmdev_period_usec
+ adjust
) * 10;
1628 last_time
+= stream
->mmdev_period_usec
;
1631 if (stream
->dataflow
== eRender
)
1633 pulse_write(stream
);
1635 /* regardless of what PA does, advance one period */
1636 adv_bytes
= min(stream
->period_bytes
, stream
->held_bytes
);
1637 stream
->lcl_offs_bytes
+= adv_bytes
;
1638 stream
->lcl_offs_bytes
%= stream
->real_bufsize_bytes
;
1639 stream
->held_bytes
-= adv_bytes
;
1641 else if(stream
->dataflow
== eCapture
)
1649 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1654 NtSetEvent(stream
->event
, NULL
);
1656 TRACE("%p after update, adv usec: %d, held: %u, delay usec: %u\n",
1657 stream
, (int)adv_usec
,
1658 (int)(stream
->held_bytes
/ pa_frame_size(&stream
->ss
)),
1659 (unsigned int)(-delay
.QuadPart
/ 10));
1664 return STATUS_SUCCESS
;
1667 static NTSTATUS
pulse_start(void *args
)
1669 struct start_params
*params
= args
;
1670 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1674 params
->result
= S_OK
;
1676 if (!pulse_stream_valid(stream
))
1679 params
->result
= S_OK
;
1680 return STATUS_SUCCESS
;
1683 if ((stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !stream
->event
)
1686 params
->result
= AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1687 return STATUS_SUCCESS
;
1690 if (stream
->started
)
1693 params
->result
= AUDCLNT_E_NOT_STOPPED
;
1694 return STATUS_SUCCESS
;
1697 pulse_write(stream
);
1699 if (pa_stream_is_corked(stream
->stream
))
1701 o
= pa_stream_cork(stream
->stream
, 0, pulse_op_cb
, &success
);
1704 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1706 pa_operation_unref(o
);
1711 params
->result
= E_FAIL
;
1714 if (SUCCEEDED(params
->result
))
1716 stream
->started
= TRUE
;
1717 stream
->just_started
= TRUE
;
1720 return STATUS_SUCCESS
;
1723 static NTSTATUS
pulse_stop(void *args
)
1725 struct stop_params
*params
= args
;
1726 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1731 if (!pulse_stream_valid(stream
))
1734 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1735 return STATUS_SUCCESS
;
1738 if (!stream
->started
)
1741 params
->result
= S_FALSE
;
1742 return STATUS_SUCCESS
;
1745 params
->result
= S_OK
;
1746 if (stream
->dataflow
== eRender
)
1748 o
= pa_stream_cork(stream
->stream
, 1, pulse_op_cb
, &success
);
1751 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1753 pa_operation_unref(o
);
1758 params
->result
= E_FAIL
;
1760 if (SUCCEEDED(params
->result
))
1761 stream
->started
= FALSE
;
1763 return STATUS_SUCCESS
;
1766 static NTSTATUS
pulse_reset(void *args
)
1768 struct reset_params
*params
= args
;
1769 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1772 if (!pulse_stream_valid(stream
))
1775 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1776 return STATUS_SUCCESS
;
1779 if (stream
->started
)
1782 params
->result
= AUDCLNT_E_NOT_STOPPED
;
1783 return STATUS_SUCCESS
;
1789 params
->result
= AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1790 return STATUS_SUCCESS
;
1793 if (stream
->dataflow
== eRender
)
1795 /* If there is still data in the render buffer it needs to be removed from the server */
1797 if (stream
->held_bytes
)
1799 pa_operation
*o
= pa_stream_flush(stream
->stream
, pulse_op_cb
, &success
);
1802 while (pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1804 pa_operation_unref(o
);
1807 if (success
|| !stream
->held_bytes
)
1809 stream
->clock_lastpos
= stream
->clock_written
= 0;
1810 stream
->pa_offs_bytes
= stream
->lcl_offs_bytes
= 0;
1811 stream
->held_bytes
= stream
->pa_held_bytes
= 0;
1817 stream
->clock_written
+= stream
->held_bytes
;
1818 stream
->held_bytes
= 0;
1820 if ((p
= stream
->locked_ptr
))
1822 stream
->locked_ptr
= NULL
;
1823 list_add_tail(&stream
->packet_free_head
, &p
->entry
);
1825 list_move_tail(&stream
->packet_free_head
, &stream
->packet_filled_head
);
1828 params
->result
= S_OK
;
1829 return STATUS_SUCCESS
;
1832 static BOOL
alloc_tmp_buffer(struct pulse_stream
*stream
, SIZE_T bytes
)
1836 if (stream
->tmp_buffer_bytes
>= bytes
)
1839 if (stream
->tmp_buffer
)
1842 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1843 &size
, MEM_RELEASE
);
1844 stream
->tmp_buffer
= NULL
;
1845 stream
->tmp_buffer_bytes
= 0;
1847 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1848 zero_bits
, &bytes
, MEM_COMMIT
, PAGE_READWRITE
))
1851 stream
->tmp_buffer_bytes
= bytes
;
1855 static UINT32
pulse_render_padding(struct pulse_stream
*stream
)
1857 return stream
->held_bytes
/ pa_frame_size(&stream
->ss
);
1860 static UINT32
pulse_capture_padding(struct pulse_stream
*stream
)
1862 ACPacket
*packet
= stream
->locked_ptr
;
1863 if (!packet
&& !list_empty(&stream
->packet_filled_head
))
1865 packet
= (ACPacket
*)list_head(&stream
->packet_filled_head
);
1866 stream
->locked_ptr
= packet
;
1867 list_remove(&packet
->entry
);
1869 return stream
->held_bytes
/ pa_frame_size(&stream
->ss
);
1872 static NTSTATUS
pulse_get_render_buffer(void *args
)
1874 struct get_render_buffer_params
*params
= args
;
1875 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1877 UINT32 wri_offs_bytes
;
1880 if (!pulse_stream_valid(stream
))
1883 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1884 return STATUS_SUCCESS
;
1890 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
1891 return STATUS_SUCCESS
;
1894 if (!params
->frames
)
1897 *params
->data
= NULL
;
1898 params
->result
= S_OK
;
1899 return STATUS_SUCCESS
;
1902 if (stream
->held_bytes
/ pa_frame_size(&stream
->ss
) + params
->frames
> stream
->bufsize_frames
)
1905 params
->result
= AUDCLNT_E_BUFFER_TOO_LARGE
;
1906 return STATUS_SUCCESS
;
1909 bytes
= params
->frames
* pa_frame_size(&stream
->ss
);
1910 wri_offs_bytes
= (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1911 if (wri_offs_bytes
+ bytes
> stream
->real_bufsize_bytes
)
1913 if (!alloc_tmp_buffer(stream
, bytes
))
1916 params
->result
= E_OUTOFMEMORY
;
1917 return STATUS_SUCCESS
;
1919 *params
->data
= stream
->tmp_buffer
;
1920 stream
->locked
= -bytes
;
1924 *params
->data
= stream
->local_buffer
+ wri_offs_bytes
;
1925 stream
->locked
= bytes
;
1928 silence_buffer(stream
->ss
.format
, *params
->data
, bytes
);
1931 params
->result
= S_OK
;
1932 return STATUS_SUCCESS
;
1935 static void pulse_wrap_buffer(struct pulse_stream
*stream
, BYTE
*buffer
, UINT32 written_bytes
)
1937 UINT32 wri_offs_bytes
= (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1938 UINT32 chunk_bytes
= stream
->real_bufsize_bytes
- wri_offs_bytes
;
1940 if (written_bytes
<= chunk_bytes
)
1942 memcpy(stream
->local_buffer
+ wri_offs_bytes
, buffer
, written_bytes
);
1946 memcpy(stream
->local_buffer
+ wri_offs_bytes
, buffer
, chunk_bytes
);
1947 memcpy(stream
->local_buffer
, buffer
+ chunk_bytes
, written_bytes
- chunk_bytes
);
1951 static NTSTATUS
pulse_release_render_buffer(void *args
)
1953 struct release_render_buffer_params
*params
= args
;
1954 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1955 UINT32 written_bytes
;
1959 if (!stream
->locked
|| !params
->written_frames
)
1963 params
->result
= params
->written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1964 return STATUS_SUCCESS
;
1967 if (params
->written_frames
* pa_frame_size(&stream
->ss
) >
1968 (stream
->locked
>= 0 ? stream
->locked
: -stream
->locked
))
1971 params
->result
= AUDCLNT_E_INVALID_SIZE
;
1972 return STATUS_SUCCESS
;
1975 if (stream
->locked
>= 0)
1976 buffer
= stream
->local_buffer
+ (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1978 buffer
= stream
->tmp_buffer
;
1980 written_bytes
= params
->written_frames
* pa_frame_size(&stream
->ss
);
1981 if (params
->flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1982 silence_buffer(stream
->ss
.format
, buffer
, written_bytes
);
1984 if (stream
->locked
< 0)
1985 pulse_wrap_buffer(stream
, buffer
, written_bytes
);
1987 stream
->held_bytes
+= written_bytes
;
1988 stream
->pa_held_bytes
+= written_bytes
;
1989 if (stream
->pa_held_bytes
> stream
->real_bufsize_bytes
)
1991 stream
->pa_offs_bytes
+= stream
->pa_held_bytes
- stream
->real_bufsize_bytes
;
1992 stream
->pa_offs_bytes
%= stream
->real_bufsize_bytes
;
1993 stream
->pa_held_bytes
= stream
->real_bufsize_bytes
;
1995 stream
->clock_written
+= written_bytes
;
1998 /* push as much data as we can to pulseaudio too */
1999 pulse_write(stream
);
2001 TRACE("Released %u, held %lu\n", params
->written_frames
, stream
->held_bytes
/ pa_frame_size(&stream
->ss
));
2004 params
->result
= S_OK
;
2005 return STATUS_SUCCESS
;
2008 static NTSTATUS
pulse_get_capture_buffer(void *args
)
2010 struct get_capture_buffer_params
*params
= args
;
2011 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2015 if (!pulse_stream_valid(stream
))
2018 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2019 return STATUS_SUCCESS
;
2024 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
2025 return STATUS_SUCCESS
;
2028 pulse_capture_padding(stream
);
2029 if ((packet
= stream
->locked_ptr
))
2031 *params
->frames
= stream
->period_bytes
/ pa_frame_size(&stream
->ss
);
2033 if (packet
->discont
)
2034 *params
->flags
|= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY
;
2037 if (packet
->discont
)
2038 *params
->devpos
= (stream
->clock_written
+ stream
->period_bytes
) / pa_frame_size(&stream
->ss
);
2040 *params
->devpos
= stream
->clock_written
/ pa_frame_size(&stream
->ss
);
2043 *params
->qpcpos
= packet
->qpcpos
;
2044 *params
->data
= packet
->data
;
2047 *params
->frames
= 0;
2048 stream
->locked
= *params
->frames
;
2050 params
->result
= *params
->frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
2051 return STATUS_SUCCESS
;
2054 static NTSTATUS
pulse_release_capture_buffer(void *args
)
2056 struct release_capture_buffer_params
*params
= args
;
2057 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2060 if (!stream
->locked
&& params
->done
)
2063 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
2064 return STATUS_SUCCESS
;
2066 if (params
->done
&& stream
->locked
!= params
->done
)
2069 params
->result
= AUDCLNT_E_INVALID_SIZE
;
2070 return STATUS_SUCCESS
;
2074 ACPacket
*packet
= stream
->locked_ptr
;
2075 stream
->locked_ptr
= NULL
;
2076 stream
->held_bytes
-= stream
->period_bytes
;
2077 if (packet
->discont
)
2078 stream
->clock_written
+= 2 * stream
->period_bytes
;
2080 stream
->clock_written
+= stream
->period_bytes
;
2081 list_add_tail(&stream
->packet_free_head
, &packet
->entry
);
2085 params
->result
= S_OK
;
2086 return STATUS_SUCCESS
;
2089 static NTSTATUS
pulse_is_format_supported(void *args
)
2091 struct is_format_supported_params
*params
= args
;
2092 WAVEFORMATEXTENSIBLE in
;
2093 WAVEFORMATEXTENSIBLE
*out
;
2094 const WAVEFORMATEX
*fmt
= &in
.Format
;
2095 const BOOLEAN exclusive
= params
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
;
2097 params
->result
= S_OK
;
2099 if (!params
->fmt_in
|| (params
->share
== AUDCLNT_SHAREMODE_SHARED
&& !params
->fmt_out
))
2100 params
->result
= E_POINTER
;
2101 else if (params
->share
!= AUDCLNT_SHAREMODE_SHARED
&& params
->share
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
2102 params
->result
= E_INVALIDARG
;
2104 memcpy(&in
, params
->fmt_in
, params
->fmt_in
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
?
2105 sizeof(in
) : sizeof(in
.Format
));
2107 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
2108 if (fmt
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
))
2109 params
->result
= E_INVALIDARG
;
2110 else if (fmt
->nAvgBytesPerSec
== 0 || fmt
->nBlockAlign
== 0 ||
2111 (in
.Samples
.wValidBitsPerSample
> fmt
->wBitsPerSample
))
2112 params
->result
= E_INVALIDARG
;
2113 else if (fmt
->nChannels
== 0)
2114 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2118 if (FAILED(params
->result
))
2119 return STATUS_SUCCESS
;
2124 out
= params
->fmt_out
;
2125 memcpy(out
, fmt
, fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
?
2126 sizeof(*out
) : sizeof((*out
).Format
));
2129 switch (fmt
->wFormatTag
) {
2130 case WAVE_FORMAT_EXTENSIBLE
: {
2131 if ((fmt
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
) &&
2132 fmt
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
)) ||
2133 fmt
->nBlockAlign
!= fmt
->wBitsPerSample
/ 8 * fmt
->nChannels
||
2134 in
.Samples
.wValidBitsPerSample
> fmt
->wBitsPerSample
||
2135 fmt
->nAvgBytesPerSec
!= fmt
->nBlockAlign
* fmt
->nSamplesPerSec
) {
2136 params
->result
= E_INVALIDARG
;
2141 UINT32 mask
= 0, i
, channels
= 0;
2143 if (!(in
.dwChannelMask
& (SPEAKER_ALL
| SPEAKER_RESERVED
))) {
2144 for (i
= 1; !(i
& SPEAKER_RESERVED
); i
<<= 1) {
2145 if (i
& in
.dwChannelMask
) {
2151 if (channels
!= fmt
->nChannels
|| (in
.dwChannelMask
& ~mask
)) {
2152 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2156 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2161 if (IsEqualGUID(&in
.SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
2162 if (fmt
->wBitsPerSample
!= 32) {
2163 params
->result
= E_INVALIDARG
;
2167 if (in
.Samples
.wValidBitsPerSample
!= fmt
->wBitsPerSample
) {
2168 params
->result
= S_FALSE
;
2169 out
->Samples
.wValidBitsPerSample
= fmt
->wBitsPerSample
;
2171 } else if (IsEqualGUID(&in
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
2172 if (!fmt
->wBitsPerSample
|| fmt
->wBitsPerSample
> 32 || fmt
->wBitsPerSample
% 8) {
2173 params
->result
= E_INVALIDARG
;
2177 if (in
.Samples
.wValidBitsPerSample
!= fmt
->wBitsPerSample
&&
2178 !(fmt
->wBitsPerSample
== 32 &&
2179 in
.Samples
.wValidBitsPerSample
== 24)) {
2180 params
->result
= S_FALSE
;
2181 out
->Samples
.wValidBitsPerSample
= fmt
->wBitsPerSample
;
2185 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2191 case WAVE_FORMAT_ALAW
:
2192 case WAVE_FORMAT_MULAW
:
2193 if (fmt
->wBitsPerSample
!= 8) {
2194 params
->result
= E_INVALIDARG
;
2198 case WAVE_FORMAT_IEEE_FLOAT
:
2199 if (fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
&& fmt
->wBitsPerSample
!= 32) {
2200 params
->result
= E_INVALIDARG
;
2204 case WAVE_FORMAT_PCM
: {
2205 if (fmt
->wFormatTag
== WAVE_FORMAT_PCM
&&
2206 (!fmt
->wBitsPerSample
|| fmt
->wBitsPerSample
> 32 || fmt
->wBitsPerSample
% 8)) {
2207 params
->result
= E_INVALIDARG
;
2211 if (fmt
->nChannels
> 2) {
2212 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2216 /* fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
2217 * ignored, invalid values are happily accepted. */
2221 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2225 if (exclusive
) { /* This driver does not support exclusive mode. */
2226 if (params
->result
== S_OK
)
2227 params
->result
= params
->flow
== eCapture
?
2228 AUDCLNT_E_UNSUPPORTED_FORMAT
:
2229 AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
2230 else if (params
->result
== S_FALSE
)
2231 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2234 return STATUS_SUCCESS
;
2237 static NTSTATUS
pulse_get_mix_format(void *args
)
2239 struct get_mix_format_params
*params
= args
;
2240 struct list
*list
= (params
->flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
2243 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
2244 if (strcmp(params
->device
, dev
->pulse_name
))
2247 *params
->fmt
= dev
->fmt
;
2248 params
->result
= S_OK
;
2250 return STATUS_SUCCESS
;
2253 params
->result
= E_FAIL
;
2254 return STATUS_SUCCESS
;
2257 static NTSTATUS
pulse_get_device_period(void *args
)
2259 struct get_device_period_params
*params
= args
;
2261 params
->result
= get_device_period_helper(params
->flow
, params
->device
, params
->def_period
, params
->min_period
);
2262 return STATUS_SUCCESS
;
2265 static NTSTATUS
pulse_get_buffer_size(void *args
)
2267 struct get_buffer_size_params
*params
= args
;
2268 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2270 params
->result
= S_OK
;
2273 if (!pulse_stream_valid(stream
))
2274 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2276 *params
->frames
= stream
->bufsize_frames
;
2279 return STATUS_SUCCESS
;
2282 static NTSTATUS
pulse_get_latency(void *args
)
2284 struct get_latency_params
*params
= args
;
2285 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2286 const pa_buffer_attr
*attr
;
2290 if (!pulse_stream_valid(stream
)) {
2292 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2293 return STATUS_SUCCESS
;
2295 attr
= pa_stream_get_buffer_attr(stream
->stream
);
2296 if (stream
->dataflow
== eRender
)
2297 lat
= attr
->minreq
/ pa_frame_size(&stream
->ss
);
2299 lat
= attr
->fragsize
/ pa_frame_size(&stream
->ss
);
2300 *params
->latency
= (lat
* 10000000) / stream
->ss
.rate
+ stream
->def_period
;
2302 TRACE("Latency: %u ms\n", (unsigned)(*params
->latency
/ 10000));
2303 params
->result
= S_OK
;
2304 return STATUS_SUCCESS
;
2307 static NTSTATUS
pulse_get_current_padding(void *args
)
2309 struct get_current_padding_params
*params
= args
;
2310 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2313 if (!pulse_stream_valid(stream
))
2316 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2317 return STATUS_SUCCESS
;
2320 if (stream
->dataflow
== eRender
)
2321 *params
->padding
= pulse_render_padding(stream
);
2323 *params
->padding
= pulse_capture_padding(stream
);
2326 TRACE("%p Pad: %u ms (%u)\n", stream
, muldiv(*params
->padding
, 1000, stream
->ss
.rate
),
2328 params
->result
= S_OK
;
2329 return STATUS_SUCCESS
;
2332 static NTSTATUS
pulse_get_next_packet_size(void *args
)
2334 struct get_next_packet_size_params
*params
= args
;
2335 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2338 pulse_capture_padding(stream
);
2339 if (stream
->locked_ptr
)
2340 *params
->frames
= stream
->period_bytes
/ pa_frame_size(&stream
->ss
);
2342 *params
->frames
= 0;
2344 params
->result
= S_OK
;
2346 return STATUS_SUCCESS
;
2349 static NTSTATUS
pulse_get_frequency(void *args
)
2351 struct get_frequency_params
*params
= args
;
2352 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2355 if (!pulse_stream_valid(stream
))
2358 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2359 return STATUS_SUCCESS
;
2362 *params
->freq
= stream
->ss
.rate
;
2363 if (stream
->share
== AUDCLNT_SHAREMODE_SHARED
)
2364 *params
->freq
*= pa_frame_size(&stream
->ss
);
2366 params
->result
= S_OK
;
2367 return STATUS_SUCCESS
;
2370 static NTSTATUS
pulse_get_position(void *args
)
2372 struct get_position_params
*params
= args
;
2373 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2376 if (!pulse_stream_valid(stream
))
2379 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2380 return STATUS_SUCCESS
;
2383 *params
->pos
= stream
->clock_written
- stream
->held_bytes
;
2385 if (stream
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
|| params
->device
)
2386 *params
->pos
/= pa_frame_size(&stream
->ss
);
2388 /* Make time never go backwards */
2389 if (*params
->pos
< stream
->clock_lastpos
)
2390 *params
->pos
= stream
->clock_lastpos
;
2392 stream
->clock_lastpos
= *params
->pos
;
2395 TRACE("%p Position: %u\n", stream
, (unsigned)*params
->pos
);
2397 if (params
->qpctime
)
2399 LARGE_INTEGER stamp
, freq
;
2400 NtQueryPerformanceCounter(&stamp
, &freq
);
2401 *params
->qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
2404 params
->result
= S_OK
;
2405 return STATUS_SUCCESS
;
2408 static NTSTATUS
pulse_set_volumes(void *args
)
2410 struct set_volumes_params
*params
= args
;
2411 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2414 for (i
= 0; i
< stream
->ss
.channels
; i
++)
2415 stream
->vol
[i
] = params
->volumes
[i
] * params
->master_volume
* params
->session_volumes
[i
];
2417 return STATUS_SUCCESS
;
2420 static NTSTATUS
pulse_set_event_handle(void *args
)
2422 struct set_event_handle_params
*params
= args
;
2423 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2427 if (!pulse_stream_valid(stream
))
2428 hr
= AUDCLNT_E_DEVICE_INVALIDATED
;
2429 else if (!(stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
2430 hr
= AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
2431 else if (stream
->event
)
2432 hr
= HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
2434 stream
->event
= params
->event
;
2437 params
->result
= hr
;
2438 return STATUS_SUCCESS
;
2441 static NTSTATUS
pulse_is_started(void *args
)
2443 struct is_started_params
*params
= args
;
2444 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2447 params
->result
= pulse_stream_valid(stream
) && stream
->started
? S_OK
: S_FALSE
;
2450 return STATUS_SUCCESS
;
2453 static BOOL
get_device_path(PhysDevice
*dev
, struct get_prop_value_params
*params
)
2455 const GUID
*guid
= params
->guid
;
2456 PROPVARIANT
*out
= params
->value
;
2461 /* As hardly any audio devices have serial numbers, Windows instead
2462 appears to use a persistent random number. We emulate this here
2463 by instead using the last 8 hex digits of the GUID. */
2464 serial_number
= (guid
->Data4
[4] << 24) | (guid
->Data4
[5] << 16) | (guid
->Data4
[6] << 8) | guid
->Data4
[7];
2466 switch (dev
->bus_type
) {
2467 case phys_device_bus_pci
:
2468 len
= sprintf(path
, "{1}.HDAUDIO\\FUNC_01&VEN_%04X&DEV_%04X\\%u&%08X", dev
->vendor_id
, dev
->product_id
, dev
->index
, serial_number
);
2470 case phys_device_bus_usb
:
2471 len
= sprintf(path
, "{1}.USB\\VID_%04X&PID_%04X\\%u&%08X", dev
->vendor_id
, dev
->product_id
, dev
->index
, serial_number
);
2474 len
= sprintf(path
, "{1}.ROOT\\MEDIA\\%04u", dev
->index
);
2478 if (*params
->buffer_size
< ++len
* sizeof(WCHAR
)) {
2479 params
->result
= E_NOT_SUFFICIENT_BUFFER
;
2480 *params
->buffer_size
= len
* sizeof(WCHAR
);
2484 out
->vt
= VT_LPWSTR
;
2485 out
->pwszVal
= params
->buffer
;
2487 ntdll_umbstowcs(path
, len
, out
->pwszVal
, len
);
2489 params
->result
= S_OK
;
2494 static NTSTATUS
pulse_get_prop_value(void *args
)
2496 static const GUID PKEY_AudioEndpoint_GUID
= {
2497 0x1da5d803, 0xd492, 0x4edd, {0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e}
2499 static const PROPERTYKEY devicepath_key
= { /* undocumented? - {b3f8fa53-0004-438e-9003-51a46e139bfc},2 */
2500 {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2
2502 struct get_prop_value_params
*params
= args
;
2503 struct list
*list
= (params
->flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
2506 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
2507 if (strcmp(params
->device
, dev
->pulse_name
))
2509 if (IsEqualPropertyKey(*params
->prop
, devicepath_key
)) {
2510 get_device_path(dev
, params
);
2511 return STATUS_SUCCESS
;
2512 } else if (IsEqualGUID(¶ms
->prop
->fmtid
, &PKEY_AudioEndpoint_GUID
)) {
2513 switch (params
->prop
->pid
) {
2514 case 0: /* FormFactor */
2515 params
->value
->vt
= VT_UI4
;
2516 params
->value
->ulVal
= dev
->form
;
2517 params
->result
= S_OK
;
2518 return STATUS_SUCCESS
;
2519 case 3: /* PhysicalSpeakers */
2520 if (!dev
->channel_mask
)
2522 params
->value
->vt
= VT_UI4
;
2523 params
->value
->ulVal
= dev
->channel_mask
;
2524 params
->result
= S_OK
;
2525 return STATUS_SUCCESS
;
2529 params
->result
= E_NOTIMPL
;
2530 return STATUS_SUCCESS
;
2534 params
->result
= E_FAIL
;
2535 return STATUS_SUCCESS
;
2538 const unixlib_entry_t __wine_unix_call_funcs
[] =
2540 pulse_process_attach
,
2541 pulse_process_detach
,
2543 pulse_get_endpoint_ids
,
2544 pulse_create_stream
,
2545 pulse_release_stream
,
2550 pulse_get_render_buffer
,
2551 pulse_release_render_buffer
,
2552 pulse_get_capture_buffer
,
2553 pulse_release_capture_buffer
,
2554 pulse_is_format_supported
,
2555 pulse_get_mix_format
,
2556 pulse_get_device_period
,
2557 pulse_get_buffer_size
,
2559 pulse_get_current_padding
,
2560 pulse_get_next_packet_size
,
2561 pulse_get_frequency
,
2564 pulse_set_event_handle
,
2567 pulse_get_prop_value
,
2568 pulse_not_implemented
,
2569 pulse_not_implemented
,
2570 pulse_not_implemented
,
2571 pulse_not_implemented
,
2572 pulse_not_implemented
,
2573 pulse_not_implemented
,
2576 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs
) == funcs_count
);
2582 static NTSTATUS
pulse_wow64_main_loop(void *args
)
2588 struct main_loop_params params
=
2590 .event
= ULongToHandle(params32
->event
)
2592 return pulse_main_loop(¶ms
);
2595 static NTSTATUS
pulse_wow64_get_endpoint_ids(void *args
)
2604 unsigned int default_idx
;
2606 struct get_endpoint_ids_params params
=
2608 .flow
= params32
->flow
,
2609 .endpoints
= ULongToPtr(params32
->endpoints
),
2610 .size
= params32
->size
2612 pulse_get_endpoint_ids(¶ms
);
2613 params32
->size
= params
.size
;
2614 params32
->result
= params
.result
;
2615 params32
->num
= params
.num
;
2616 params32
->default_idx
= params
.default_idx
;
2617 return STATUS_SUCCESS
;
2620 static NTSTATUS
pulse_wow64_create_stream(void *args
)
2627 AUDCLNT_SHAREMODE share
;
2629 REFERENCE_TIME duration
;
2630 REFERENCE_TIME period
;
2633 PTR32 channel_count
;
2636 struct create_stream_params params
=
2638 .name
= ULongToPtr(params32
->name
),
2639 .device
= ULongToPtr(params32
->device
),
2640 .flow
= params32
->flow
,
2641 .share
= params32
->share
,
2642 .flags
= params32
->flags
,
2643 .duration
= params32
->duration
,
2644 .period
= params32
->period
,
2645 .fmt
= ULongToPtr(params32
->fmt
),
2646 .channel_count
= ULongToPtr(params32
->channel_count
),
2647 .stream
= ULongToPtr(params32
->stream
)
2649 pulse_create_stream(¶ms
);
2650 params32
->result
= params
.result
;
2651 return STATUS_SUCCESS
;
2654 static NTSTATUS
pulse_wow64_release_stream(void *args
)
2658 stream_handle stream
;
2662 struct release_stream_params params
=
2664 .stream
= params32
->stream
,
2665 .timer_thread
= ULongToHandle(params32
->timer_thread
)
2667 pulse_release_stream(¶ms
);
2668 params32
->result
= params
.result
;
2669 return STATUS_SUCCESS
;
2672 static NTSTATUS
pulse_wow64_get_render_buffer(void *args
)
2676 stream_handle stream
;
2682 struct get_render_buffer_params params
=
2684 .stream
= params32
->stream
,
2685 .frames
= params32
->frames
,
2688 pulse_get_render_buffer(¶ms
);
2689 params32
->result
= params
.result
;
2690 *(unsigned int *)ULongToPtr(params32
->data
) = PtrToUlong(data
);
2691 return STATUS_SUCCESS
;
2694 static NTSTATUS
pulse_wow64_get_capture_buffer(void *args
)
2698 stream_handle stream
;
2707 struct get_capture_buffer_params params
=
2709 .stream
= params32
->stream
,
2711 .frames
= ULongToPtr(params32
->frames
),
2712 .flags
= ULongToPtr(params32
->flags
),
2713 .devpos
= ULongToPtr(params32
->devpos
),
2714 .qpcpos
= ULongToPtr(params32
->qpcpos
)
2716 pulse_get_capture_buffer(¶ms
);
2717 params32
->result
= params
.result
;
2718 *(unsigned int *)ULongToPtr(params32
->data
) = PtrToUlong(data
);
2719 return STATUS_SUCCESS
;
2722 static NTSTATUS
pulse_wow64_is_format_supported(void *args
)
2728 AUDCLNT_SHAREMODE share
;
2733 struct is_format_supported_params params
=
2735 .device
= ULongToPtr(params32
->device
),
2736 .flow
= params32
->flow
,
2737 .share
= params32
->share
,
2738 .fmt_in
= ULongToPtr(params32
->fmt_in
),
2739 .fmt_out
= ULongToPtr(params32
->fmt_out
)
2741 pulse_is_format_supported(¶ms
);
2742 params32
->result
= params
.result
;
2743 return STATUS_SUCCESS
;
2746 static NTSTATUS
pulse_wow64_get_mix_format(void *args
)
2755 struct get_mix_format_params params
=
2757 .device
= ULongToPtr(params32
->device
),
2758 .flow
= params32
->flow
,
2759 .fmt
= ULongToPtr(params32
->fmt
),
2761 pulse_get_mix_format(¶ms
);
2762 params32
->result
= params
.result
;
2763 return STATUS_SUCCESS
;
2766 static NTSTATUS
pulse_wow64_get_device_period(void *args
)
2776 struct get_device_period_params params
=
2778 .device
= ULongToPtr(params32
->device
),
2779 .flow
= params32
->flow
,
2780 .def_period
= ULongToPtr(params32
->def_period
),
2781 .min_period
= ULongToPtr(params32
->min_period
),
2783 pulse_get_device_period(¶ms
);
2784 params32
->result
= params
.result
;
2785 return STATUS_SUCCESS
;
2788 static NTSTATUS
pulse_wow64_get_buffer_size(void *args
)
2792 stream_handle stream
;
2796 struct get_buffer_size_params params
=
2798 .stream
= params32
->stream
,
2799 .frames
= ULongToPtr(params32
->frames
)
2801 pulse_get_buffer_size(¶ms
);
2802 params32
->result
= params
.result
;
2803 return STATUS_SUCCESS
;
2806 static NTSTATUS
pulse_wow64_get_latency(void *args
)
2810 stream_handle stream
;
2814 struct get_latency_params params
=
2816 .stream
= params32
->stream
,
2817 .latency
= ULongToPtr(params32
->latency
)
2819 pulse_get_latency(¶ms
);
2820 params32
->result
= params
.result
;
2821 return STATUS_SUCCESS
;
2824 static NTSTATUS
pulse_wow64_get_current_padding(void *args
)
2828 stream_handle stream
;
2832 struct get_current_padding_params params
=
2834 .stream
= params32
->stream
,
2835 .padding
= ULongToPtr(params32
->padding
)
2837 pulse_get_current_padding(¶ms
);
2838 params32
->result
= params
.result
;
2839 return STATUS_SUCCESS
;
2842 static NTSTATUS
pulse_wow64_get_next_packet_size(void *args
)
2846 stream_handle stream
;
2850 struct get_next_packet_size_params params
=
2852 .stream
= params32
->stream
,
2853 .frames
= ULongToPtr(params32
->frames
)
2855 pulse_get_next_packet_size(¶ms
);
2856 params32
->result
= params
.result
;
2857 return STATUS_SUCCESS
;
2860 static NTSTATUS
pulse_wow64_get_frequency(void *args
)
2864 stream_handle stream
;
2868 struct get_frequency_params params
=
2870 .stream
= params32
->stream
,
2871 .freq
= ULongToPtr(params32
->freq
)
2873 pulse_get_frequency(¶ms
);
2874 params32
->result
= params
.result
;
2875 return STATUS_SUCCESS
;
2878 static NTSTATUS
pulse_wow64_get_position(void *args
)
2882 stream_handle stream
;
2888 struct get_position_params params
=
2890 .stream
= params32
->stream
,
2891 .device
= params32
->device
,
2892 .pos
= ULongToPtr(params32
->pos
),
2893 .qpctime
= ULongToPtr(params32
->qpctime
)
2895 pulse_get_position(¶ms
);
2896 params32
->result
= params
.result
;
2897 return STATUS_SUCCESS
;
2900 static NTSTATUS
pulse_wow64_set_volumes(void *args
)
2904 stream_handle stream
;
2905 float master_volume
;
2907 PTR32 session_volumes
;
2909 struct set_volumes_params params
=
2911 .stream
= params32
->stream
,
2912 .master_volume
= params32
->master_volume
,
2913 .volumes
= ULongToPtr(params32
->volumes
),
2914 .session_volumes
= ULongToPtr(params32
->session_volumes
),
2916 return pulse_set_volumes(¶ms
);
2919 static NTSTATUS
pulse_wow64_set_event_handle(void *args
)
2923 stream_handle stream
;
2927 struct set_event_handle_params params
=
2929 .stream
= params32
->stream
,
2930 .event
= ULongToHandle(params32
->event
)
2932 pulse_set_event_handle(¶ms
);
2933 params32
->result
= params
.result
;
2934 return STATUS_SUCCESS
;
2937 static NTSTATUS
pulse_wow64_test_connect(void *args
)
2942 enum driver_priority priority
;
2944 struct test_connect_params params
=
2946 .name
= ULongToPtr(params32
->name
),
2948 pulse_test_connect(¶ms
);
2949 params32
->priority
= params
.priority
;
2950 return STATUS_SUCCESS
;
2953 static NTSTATUS
pulse_wow64_get_prop_value(void *args
)
2955 struct propvariant32
2958 WORD pad1
, pad2
, pad3
;
2963 ULARGE_INTEGER uhVal
;
2974 PTR32 buffer
; /* caller allocated buffer to hold value's strings */
2978 struct get_prop_value_params params
=
2980 .device
= ULongToPtr(params32
->device
),
2981 .flow
= params32
->flow
,
2982 .guid
= ULongToPtr(params32
->guid
),
2983 .prop
= ULongToPtr(params32
->prop
),
2985 .buffer
= ULongToPtr(params32
->buffer
),
2986 .buffer_size
= ULongToPtr(params32
->buffer_size
)
2988 pulse_get_prop_value(¶ms
);
2989 params32
->result
= params
.result
;
2990 if (SUCCEEDED(params
.result
))
2992 value32
= UlongToPtr(params32
->value
);
2993 value32
->vt
= value
.vt
;
2997 value32
->ulVal
= value
.ulVal
;
3000 value32
->ptr
= params32
->buffer
;
3003 FIXME("Unhandled vt %04x\n", value
.vt
);
3006 return STATUS_SUCCESS
;
3009 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
3011 pulse_process_attach
,
3012 pulse_process_detach
,
3013 pulse_wow64_main_loop
,
3014 pulse_wow64_get_endpoint_ids
,
3015 pulse_wow64_create_stream
,
3016 pulse_wow64_release_stream
,
3021 pulse_wow64_get_render_buffer
,
3022 pulse_release_render_buffer
,
3023 pulse_wow64_get_capture_buffer
,
3024 pulse_release_capture_buffer
,
3025 pulse_wow64_is_format_supported
,
3026 pulse_wow64_get_mix_format
,
3027 pulse_wow64_get_device_period
,
3028 pulse_wow64_get_buffer_size
,
3029 pulse_wow64_get_latency
,
3030 pulse_wow64_get_current_padding
,
3031 pulse_wow64_get_next_packet_size
,
3032 pulse_wow64_get_frequency
,
3033 pulse_wow64_get_position
,
3034 pulse_wow64_set_volumes
,
3035 pulse_wow64_set_event_handle
,
3036 pulse_wow64_test_connect
,
3038 pulse_wow64_get_prop_value
,
3039 pulse_not_implemented
,
3040 pulse_not_implemented
,
3041 pulse_not_implemented
,
3042 pulse_not_implemented
,
3043 pulse_not_implemented
,
3044 pulse_not_implemented
,
3047 C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs
) == funcs_count
);