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 pulse_add_device(&g_phys_speakers
, NULL
, 0, Speakers
, 0, "", "PulseAudio");
837 pulse_add_device(&g_phys_sources
, NULL
, 0, Microphone
, 0, "", "PulseAudio");
839 o
= pa_context_get_sink_info_list(pulse_ctx
, &pulse_phys_speakers_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 o
= pa_context_get_source_info_list(pulse_ctx
, &pulse_phys_sources_cb
, NULL
);
849 while (pa_mainloop_iterate(pulse_ml
, 1, &ret
) >= 0 &&
850 pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
852 pa_operation_unref(o
);
855 LIST_FOR_EACH_ENTRY(dev
, &g_phys_speakers
, PhysDevice
, entry
) {
856 pulse_probe_settings(1, dev
->pulse_name
, &dev
->fmt
, &dev
->def_period
, &dev
->min_period
);
859 LIST_FOR_EACH_ENTRY(dev
, &g_phys_sources
, PhysDevice
, entry
) {
860 pulse_probe_settings(0, dev
->pulse_name
, &dev
->fmt
, &dev
->def_period
, &dev
->min_period
);
863 pa_context_unref(pulse_ctx
);
865 pa_mainloop_free(pulse_ml
);
870 params
->priority
= Priority_Preferred
;
871 return STATUS_SUCCESS
;
874 pa_context_unref(pulse_ctx
);
876 pa_mainloop_free(pulse_ml
);
879 params
->priority
= Priority_Unavailable
;
880 return STATUS_SUCCESS
;
883 static UINT
get_channel_mask(unsigned int channels
)
889 return KSAUDIO_SPEAKER_MONO
;
891 return KSAUDIO_SPEAKER_STEREO
;
893 return KSAUDIO_SPEAKER_STEREO
| SPEAKER_LOW_FREQUENCY
;
895 return KSAUDIO_SPEAKER_QUAD
; /* not _SURROUND */
897 return KSAUDIO_SPEAKER_QUAD
| SPEAKER_LOW_FREQUENCY
;
899 return KSAUDIO_SPEAKER_5POINT1
; /* not 5POINT1_SURROUND */
901 return KSAUDIO_SPEAKER_5POINT1
| SPEAKER_BACK_CENTER
;
903 return KSAUDIO_SPEAKER_7POINT1_SURROUND
; /* Vista deprecates 7POINT1 */
905 FIXME("Unknown speaker configuration: %u\n", channels
);
909 static const enum pa_channel_position pulse_pos_from_wfx
[] = {
910 PA_CHANNEL_POSITION_FRONT_LEFT
,
911 PA_CHANNEL_POSITION_FRONT_RIGHT
,
912 PA_CHANNEL_POSITION_FRONT_CENTER
,
913 PA_CHANNEL_POSITION_LFE
,
914 PA_CHANNEL_POSITION_REAR_LEFT
,
915 PA_CHANNEL_POSITION_REAR_RIGHT
,
916 PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
,
917 PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
,
918 PA_CHANNEL_POSITION_REAR_CENTER
,
919 PA_CHANNEL_POSITION_SIDE_LEFT
,
920 PA_CHANNEL_POSITION_SIDE_RIGHT
,
921 PA_CHANNEL_POSITION_TOP_CENTER
,
922 PA_CHANNEL_POSITION_TOP_FRONT_LEFT
,
923 PA_CHANNEL_POSITION_TOP_FRONT_CENTER
,
924 PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
,
925 PA_CHANNEL_POSITION_TOP_REAR_LEFT
,
926 PA_CHANNEL_POSITION_TOP_REAR_CENTER
,
927 PA_CHANNEL_POSITION_TOP_REAR_RIGHT
930 static HRESULT
pulse_spec_from_waveformat(struct pulse_stream
*stream
, const WAVEFORMATEX
*fmt
)
932 pa_channel_map_init(&stream
->map
);
933 stream
->ss
.rate
= fmt
->nSamplesPerSec
;
934 stream
->ss
.format
= PA_SAMPLE_INVALID
;
936 switch(fmt
->wFormatTag
) {
937 case WAVE_FORMAT_IEEE_FLOAT
:
938 if (!fmt
->nChannels
|| fmt
->nChannels
> 2 || fmt
->wBitsPerSample
!= 32)
940 stream
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
941 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
943 case WAVE_FORMAT_PCM
:
944 if (!fmt
->nChannels
|| fmt
->nChannels
> 2)
946 if (fmt
->wBitsPerSample
== 8)
947 stream
->ss
.format
= PA_SAMPLE_U8
;
948 else if (fmt
->wBitsPerSample
== 16)
949 stream
->ss
.format
= PA_SAMPLE_S16LE
;
951 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
952 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
954 case WAVE_FORMAT_EXTENSIBLE
: {
955 WAVEFORMATEXTENSIBLE
*wfe
= (WAVEFORMATEXTENSIBLE
*)fmt
;
956 UINT mask
= wfe
->dwChannelMask
;
958 if (fmt
->cbSize
!= (sizeof(*wfe
) - sizeof(*fmt
)) && fmt
->cbSize
!= sizeof(*wfe
))
960 if (IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
) &&
961 (!wfe
->Samples
.wValidBitsPerSample
|| wfe
->Samples
.wValidBitsPerSample
== 32) &&
962 fmt
->wBitsPerSample
== 32)
963 stream
->ss
.format
= PA_SAMPLE_FLOAT32LE
;
964 else if (IsEqualGUID(&wfe
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
965 DWORD valid
= wfe
->Samples
.wValidBitsPerSample
;
967 valid
= fmt
->wBitsPerSample
;
968 if (!valid
|| valid
> fmt
->wBitsPerSample
)
970 switch (fmt
->wBitsPerSample
) {
973 stream
->ss
.format
= PA_SAMPLE_U8
;
977 stream
->ss
.format
= PA_SAMPLE_S16LE
;
981 stream
->ss
.format
= PA_SAMPLE_S24LE
;
985 stream
->ss
.format
= PA_SAMPLE_S24_32LE
;
986 else if (valid
== 32)
987 stream
->ss
.format
= PA_SAMPLE_S32LE
;
990 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
993 stream
->map
.channels
= fmt
->nChannels
;
994 if (!mask
|| (mask
& (SPEAKER_ALL
|SPEAKER_RESERVED
)))
995 mask
= get_channel_mask(fmt
->nChannels
);
996 for (j
= 0; j
< ARRAY_SIZE(pulse_pos_from_wfx
) && i
< fmt
->nChannels
; ++j
) {
998 stream
->map
.map
[i
++] = pulse_pos_from_wfx
[j
];
1001 /* Special case for mono since pulse appears to map it differently */
1002 if (mask
== SPEAKER_FRONT_CENTER
)
1003 stream
->map
.map
[0] = PA_CHANNEL_POSITION_MONO
;
1005 if (i
< fmt
->nChannels
|| (mask
& SPEAKER_RESERVED
)) {
1006 stream
->map
.channels
= 0;
1007 ERR("Invalid channel mask: %i/%i and %x(%x)\n", i
, fmt
->nChannels
, mask
, (unsigned)wfe
->dwChannelMask
);
1012 case WAVE_FORMAT_ALAW
:
1013 case WAVE_FORMAT_MULAW
:
1014 if (fmt
->wBitsPerSample
!= 8) {
1015 FIXME("Unsupported bpp %u for LAW\n", fmt
->wBitsPerSample
);
1016 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1018 if (fmt
->nChannels
!= 1 && fmt
->nChannels
!= 2) {
1019 FIXME("Unsupported channels %u for LAW\n", fmt
->nChannels
);
1020 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1022 stream
->ss
.format
= fmt
->wFormatTag
== WAVE_FORMAT_MULAW
? PA_SAMPLE_ULAW
: PA_SAMPLE_ALAW
;
1023 pa_channel_map_init_auto(&stream
->map
, fmt
->nChannels
, PA_CHANNEL_MAP_ALSA
);
1026 WARN("Unhandled tag %x\n", fmt
->wFormatTag
);
1027 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1029 stream
->ss
.channels
= stream
->map
.channels
;
1030 if (!pa_channel_map_valid(&stream
->map
) || stream
->ss
.format
== PA_SAMPLE_INVALID
) {
1031 ERR("Invalid format! Channel spec valid: %i, format: %i\n",
1032 pa_channel_map_valid(&stream
->map
), stream
->ss
.format
);
1033 return AUDCLNT_E_UNSUPPORTED_FORMAT
;
1038 static HRESULT
pulse_stream_connect(struct pulse_stream
*stream
, const char *pulse_name
, UINT32 period_bytes
)
1040 pa_stream_flags_t flags
= PA_STREAM_START_CORKED
| PA_STREAM_START_UNMUTED
| PA_STREAM_ADJUST_LATENCY
;
1044 pa_buffer_attr attr
;
1046 ret
= InterlockedIncrement(&number
);
1047 sprintf(buffer
, "audio stream #%i", ret
);
1048 stream
->stream
= pa_stream_new(pulse_ctx
, buffer
, &stream
->ss
, &stream
->map
);
1050 if (!stream
->stream
) {
1051 WARN("pa_stream_new returned error %i\n", pa_context_errno(pulse_ctx
));
1052 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1055 pa_stream_set_state_callback(stream
->stream
, pulse_stream_state
, stream
);
1056 pa_stream_set_buffer_attr_callback(stream
->stream
, pulse_attr_update
, stream
);
1057 pa_stream_set_moved_callback(stream
->stream
, pulse_attr_update
, stream
);
1059 /* PulseAudio will fill in correct values */
1060 attr
.minreq
= attr
.fragsize
= period_bytes
;
1061 attr
.tlength
= period_bytes
* 3;
1062 attr
.maxlength
= stream
->bufsize_frames
* pa_frame_size(&stream
->ss
);
1063 attr
.prebuf
= pa_frame_size(&stream
->ss
);
1066 /* If specific device was requested, use it exactly */
1068 flags
|= PA_STREAM_DONT_MOVE
;
1070 pulse_name
= NULL
; /* use default */
1072 if (stream
->dataflow
== eRender
)
1073 ret
= pa_stream_connect_playback(stream
->stream
, pulse_name
, &attr
, flags
, NULL
, NULL
);
1075 ret
= pa_stream_connect_record(stream
->stream
, pulse_name
, &attr
, flags
);
1077 WARN("Returns %i\n", ret
);
1078 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1080 while (pa_stream_get_state(stream
->stream
) == PA_STREAM_CREATING
)
1082 if (pa_stream_get_state(stream
->stream
) != PA_STREAM_READY
)
1083 return AUDCLNT_E_ENDPOINT_CREATE_FAILED
;
1085 if (stream
->dataflow
== eRender
) {
1086 pa_stream_set_underflow_callback(stream
->stream
, pulse_underflow_callback
, stream
);
1087 pa_stream_set_started_callback(stream
->stream
, pulse_started_callback
, stream
);
1092 static HRESULT
get_device_period_helper(EDataFlow flow
, const char *pulse_name
, REFERENCE_TIME
*def
, REFERENCE_TIME
*min
)
1094 struct list
*list
= (flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
1101 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
1102 if (strcmp(pulse_name
, dev
->pulse_name
))
1106 *def
= dev
->def_period
;
1108 *min
= dev
->min_period
;
1115 static NTSTATUS
pulse_create_stream(void *args
)
1117 struct create_stream_params
*params
= args
;
1118 REFERENCE_TIME period
, duration
= params
->duration
;
1119 struct pulse_stream
*stream
;
1120 unsigned int i
, bufsize_bytes
;
1124 if (params
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
) {
1125 params
->result
= AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
1126 return STATUS_SUCCESS
;
1131 name
= wstr_to_str(params
->name
);
1132 params
->result
= pulse_connect(name
);
1135 if (FAILED(params
->result
))
1138 return STATUS_SUCCESS
;
1141 if (!(stream
= calloc(1, sizeof(*stream
))))
1144 params
->result
= E_OUTOFMEMORY
;
1145 return STATUS_SUCCESS
;
1148 stream
->dataflow
= params
->flow
;
1149 for (i
= 0; i
< ARRAY_SIZE(stream
->vol
); ++i
)
1150 stream
->vol
[i
] = 1.f
;
1152 hr
= pulse_spec_from_waveformat(stream
, params
->fmt
);
1153 TRACE("Obtaining format returns %08x\n", (unsigned)hr
);
1159 hr
= get_device_period_helper(params
->flow
, params
->device
, &period
, NULL
);
1163 if (duration
< 3 * period
)
1164 duration
= 3 * period
;
1166 stream
->def_period
= period
;
1168 stream
->period_bytes
= pa_frame_size(&stream
->ss
) * muldiv(period
, stream
->ss
.rate
, 10000000);
1170 stream
->bufsize_frames
= ceil((duration
/ 10000000.) * params
->fmt
->nSamplesPerSec
);
1171 bufsize_bytes
= stream
->bufsize_frames
* pa_frame_size(&stream
->ss
);
1172 stream
->mmdev_period_usec
= period
/ 10;
1174 stream
->share
= params
->share
;
1175 stream
->flags
= params
->flags
;
1176 hr
= pulse_stream_connect(stream
, params
->device
, stream
->period_bytes
);
1177 if (SUCCEEDED(hr
)) {
1179 const pa_buffer_attr
*attr
= pa_stream_get_buffer_attr(stream
->stream
);
1182 stream
->attr
= *attr
;
1183 /* Update frames according to new size */
1185 if (stream
->dataflow
== eRender
) {
1186 size
= stream
->real_bufsize_bytes
=
1187 stream
->bufsize_frames
* 2 * pa_frame_size(&stream
->ss
);
1188 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1189 zero_bits
, &size
, MEM_COMMIT
, PAGE_READWRITE
))
1192 UINT32 i
, capture_packets
;
1194 if ((unalign
= bufsize_bytes
% stream
->period_bytes
))
1195 bufsize_bytes
+= stream
->period_bytes
- unalign
;
1196 stream
->bufsize_frames
= bufsize_bytes
/ pa_frame_size(&stream
->ss
);
1197 stream
->real_bufsize_bytes
= bufsize_bytes
;
1199 capture_packets
= stream
->real_bufsize_bytes
/ stream
->period_bytes
;
1201 size
= stream
->real_bufsize_bytes
+ capture_packets
* sizeof(ACPacket
);
1202 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1203 zero_bits
, &size
, MEM_COMMIT
, PAGE_READWRITE
))
1206 ACPacket
*cur_packet
= (ACPacket
*)((char*)stream
->local_buffer
+ stream
->real_bufsize_bytes
);
1207 BYTE
*data
= stream
->local_buffer
;
1208 silence_buffer(stream
->ss
.format
, stream
->local_buffer
, stream
->real_bufsize_bytes
);
1209 list_init(&stream
->packet_free_head
);
1210 list_init(&stream
->packet_filled_head
);
1211 for (i
= 0; i
< capture_packets
; ++i
, ++cur_packet
) {
1212 list_add_tail(&stream
->packet_free_head
, &cur_packet
->entry
);
1213 cur_packet
->data
= data
;
1214 data
+= stream
->period_bytes
;
1220 *params
->channel_count
= stream
->ss
.channels
;
1221 *params
->stream
= (stream_handle
)(UINT_PTR
)stream
;
1224 if (FAILED(params
->result
= hr
)) {
1225 free(stream
->local_buffer
);
1226 if (stream
->stream
) {
1227 pa_stream_disconnect(stream
->stream
);
1228 pa_stream_unref(stream
->stream
);
1234 return STATUS_SUCCESS
;
1237 static NTSTATUS
pulse_release_stream(void *args
)
1239 struct release_stream_params
*params
= args
;
1240 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1243 if(params
->timer_thread
) {
1244 stream
->please_quit
= TRUE
;
1245 NtWaitForSingleObject(params
->timer_thread
, FALSE
, NULL
);
1246 NtClose(params
->timer_thread
);
1250 if (PA_STREAM_IS_GOOD(pa_stream_get_state(stream
->stream
))) {
1251 pa_stream_disconnect(stream
->stream
);
1252 while (PA_STREAM_IS_GOOD(pa_stream_get_state(stream
->stream
)))
1255 pa_stream_unref(stream
->stream
);
1258 if (stream
->tmp_buffer
) {
1260 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1261 &size
, MEM_RELEASE
);
1263 if (stream
->local_buffer
) {
1265 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->local_buffer
,
1266 &size
, MEM_RELEASE
);
1268 free(stream
->peek_buffer
);
1270 return STATUS_SUCCESS
;
1273 static int write_buffer(const struct pulse_stream
*stream
, BYTE
*buffer
, UINT32 bytes
)
1275 const float *vol
= stream
->vol
;
1276 UINT32 i
, channels
, mute
= 0;
1277 BOOL adjust
= FALSE
;
1280 if (!bytes
) return 0;
1282 /* Adjust the buffer based on the volume for each channel */
1283 channels
= stream
->ss
.channels
;
1284 for (i
= 0; i
< channels
; i
++)
1286 adjust
|= vol
[i
] != 1.0f
;
1290 if (mute
== channels
)
1292 silence_buffer(stream
->ss
.format
, buffer
, bytes
);
1295 if (!adjust
) goto write
;
1297 end
= buffer
+ bytes
;
1298 switch (stream
->ss
.format
)
1300 #ifndef WORDS_BIGENDIAN
1301 #define PROCESS_BUFFER(type) do \
1303 type *p = (type*)buffer; \
1306 for (i = 0; i < channels; i++) \
1307 p[i] = p[i] * vol[i]; \
1309 } while ((BYTE*)p != end); \
1311 case PA_SAMPLE_S16LE
:
1312 PROCESS_BUFFER(INT16
);
1314 case PA_SAMPLE_S32LE
:
1315 PROCESS_BUFFER(INT32
);
1317 case PA_SAMPLE_FLOAT32LE
:
1318 PROCESS_BUFFER(float);
1320 #undef PROCESS_BUFFER
1321 case PA_SAMPLE_S24_32LE
:
1323 UINT32
*p
= (UINT32
*)buffer
;
1326 for (i
= 0; i
< channels
; i
++)
1328 p
[i
] = (INT32
)((INT32
)(p
[i
] << 8) * vol
[i
]);
1332 } while ((BYTE
*)p
!= end
);
1335 case PA_SAMPLE_S24LE
:
1337 /* do it 12 bytes at a time until it is no longer possible */
1338 UINT32
*q
= (UINT32
*)buffer
;
1342 while (end
- (BYTE
*)q
>= 12)
1346 v
[1] = q
[1] << 16 | (q
[0] >> 16 & ~0xff);
1347 v
[2] = q
[2] << 24 | (q
[1] >> 8 & ~0xff);
1348 v
[3] = q
[2] & ~0xff;
1349 for (k
= 0; k
< 4; k
++)
1351 v
[k
] = (INT32
)((INT32
)v
[k
] * vol
[i
]);
1352 if (++i
== channels
) i
= 0;
1354 *q
++ = v
[0] >> 8 | (v
[1] & ~0xff) << 16;
1355 *q
++ = v
[1] >> 16 | (v
[2] & ~0xff) << 8;
1356 *q
++ = v
[2] >> 24 | (v
[3] & ~0xff);
1361 UINT32 v
= (INT32
)((INT32
)(p
[0] << 8 | p
[1] << 16 | p
[2] << 24) * vol
[i
]);
1362 *p
++ = v
>> 8 & 0xff;
1363 *p
++ = v
>> 16 & 0xff;
1365 if (++i
== channels
) i
= 0;
1372 UINT8
*p
= (UINT8
*)buffer
;
1375 for (i
= 0; i
< channels
; i
++)
1376 p
[i
] = (int)((p
[i
] - 128) * vol
[i
]) + 128;
1378 } while ((BYTE
*)p
!= end
);
1381 case PA_SAMPLE_ALAW
:
1383 UINT8
*p
= (UINT8
*)buffer
;
1386 for (i
= 0; i
< channels
; i
++)
1387 p
[i
] = mult_alaw_sample(p
[i
], vol
[i
]);
1389 } while ((BYTE
*)p
!= end
);
1392 case PA_SAMPLE_ULAW
:
1394 UINT8
*p
= (UINT8
*)buffer
;
1397 for (i
= 0; i
< channels
; i
++)
1398 p
[i
] = mult_ulaw_sample(p
[i
], vol
[i
]);
1400 } while ((BYTE
*)p
!= end
);
1404 TRACE("Unhandled format %i, not adjusting volume.\n", stream
->ss
.format
);
1409 return pa_stream_write(stream
->stream
, buffer
, bytes
, NULL
, 0, PA_SEEK_RELATIVE
);
1412 static void pulse_write(struct pulse_stream
*stream
)
1414 /* write as much data to PA as we can */
1416 BYTE
*buf
= stream
->local_buffer
+ stream
->pa_offs_bytes
;
1417 UINT32 bytes
= pa_stream_writable_size(stream
->stream
);
1419 if (stream
->just_underran
)
1421 /* prebuffer with silence if needed */
1422 if(stream
->pa_held_bytes
< bytes
){
1423 to_write
= bytes
- stream
->pa_held_bytes
;
1424 TRACE("prebuffering %u frames of silence\n",
1425 (int)(to_write
/ pa_frame_size(&stream
->ss
)));
1426 buf
= calloc(1, to_write
);
1427 pa_stream_write(stream
->stream
, buf
, to_write
, NULL
, 0, PA_SEEK_RELATIVE
);
1431 stream
->just_underran
= FALSE
;
1434 buf
= stream
->local_buffer
+ stream
->pa_offs_bytes
;
1435 TRACE("held: %lu, avail: %u\n", stream
->pa_held_bytes
, bytes
);
1436 bytes
= min(stream
->pa_held_bytes
, bytes
);
1438 if (stream
->pa_offs_bytes
+ bytes
> stream
->real_bufsize_bytes
)
1440 to_write
= stream
->real_bufsize_bytes
- stream
->pa_offs_bytes
;
1441 TRACE("writing small chunk of %u bytes\n", to_write
);
1442 write_buffer(stream
, buf
, to_write
);
1443 stream
->pa_held_bytes
-= to_write
;
1444 to_write
= bytes
- to_write
;
1445 stream
->pa_offs_bytes
= 0;
1446 buf
= stream
->local_buffer
;
1451 TRACE("writing main chunk of %u bytes\n", to_write
);
1452 write_buffer(stream
, buf
, to_write
);
1453 stream
->pa_offs_bytes
+= to_write
;
1454 stream
->pa_offs_bytes
%= stream
->real_bufsize_bytes
;
1455 stream
->pa_held_bytes
-= to_write
;
1458 static void pulse_read(struct pulse_stream
*stream
)
1460 size_t bytes
= pa_stream_readable_size(stream
->stream
);
1462 TRACE("Readable total: %zu, fragsize: %u\n", bytes
, pa_stream_get_buffer_attr(stream
->stream
)->fragsize
);
1464 bytes
+= stream
->peek_len
- stream
->peek_ofs
;
1466 while (bytes
>= stream
->period_bytes
)
1468 BYTE
*dst
= NULL
, *src
;
1469 size_t src_len
, copy
, rem
= stream
->period_bytes
;
1471 if (stream
->started
)
1473 LARGE_INTEGER stamp
, freq
;
1476 if (!(p
= (ACPacket
*)list_head(&stream
->packet_free_head
)))
1478 p
= (ACPacket
*)list_head(&stream
->packet_filled_head
);
1481 next
= (ACPacket
*)p
->entry
.next
;
1484 p
= (ACPacket
*)list_tail(&stream
->packet_filled_head
);
1488 stream
->held_bytes
+= stream
->period_bytes
;
1490 NtQueryPerformanceCounter(&stamp
, &freq
);
1491 p
->qpcpos
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
1493 list_remove(&p
->entry
);
1494 list_add_tail(&stream
->packet_filled_head
, &p
->entry
);
1501 if (stream
->peek_len
)
1503 copy
= min(rem
, stream
->peek_len
- stream
->peek_ofs
);
1507 memcpy(dst
, stream
->peek_buffer
+ stream
->peek_ofs
, copy
);
1512 stream
->peek_ofs
+= copy
;
1513 if(stream
->peek_len
== stream
->peek_ofs
)
1514 stream
->peek_len
= stream
->peek_ofs
= 0;
1517 else if (pa_stream_peek(stream
->stream
, (const void**)&src
, &src_len
) == 0 && src_len
)
1519 copy
= min(rem
, src_len
);
1523 memcpy(dst
, src
, copy
);
1525 silence_buffer(stream
->ss
.format
, dst
, copy
);
1534 if (src_len
> stream
->peek_buffer_len
)
1536 free(stream
->peek_buffer
);
1537 stream
->peek_buffer
= malloc(src_len
);
1538 stream
->peek_buffer_len
= src_len
;
1542 memcpy(stream
->peek_buffer
, src
+ copy
, src_len
- copy
);
1544 silence_buffer(stream
->ss
.format
, stream
->peek_buffer
, src_len
- copy
);
1546 stream
->peek_len
= src_len
- copy
;
1547 stream
->peek_ofs
= 0;
1550 pa_stream_drop(stream
->stream
);
1554 bytes
-= stream
->period_bytes
;
1558 static NTSTATUS
pulse_timer_loop(void *args
)
1560 struct timer_loop_params
*params
= args
;
1561 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1562 LARGE_INTEGER delay
;
1563 pa_usec_t last_time
;
1569 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1570 pa_stream_get_time(stream
->stream
, &last_time
);
1573 while (!stream
->please_quit
)
1575 pa_usec_t now
, adv_usec
= 0;
1578 NtDelayExecution(FALSE
, &delay
);
1582 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1584 o
= pa_stream_update_timing_info(stream
->stream
, pulse_op_cb
, &success
);
1587 while (pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1589 pa_operation_unref(o
);
1591 err
= pa_stream_get_time(stream
->stream
, &now
);
1594 TRACE("got now: %s, last time: %s\n", wine_dbgstr_longlong(now
), wine_dbgstr_longlong(last_time
));
1595 if (stream
->started
&& (stream
->dataflow
== eCapture
|| stream
->held_bytes
))
1597 if(stream
->just_underran
)
1600 stream
->just_started
= TRUE
;
1603 if (stream
->just_started
)
1605 /* let it play out a period to absorb some latency and get accurate timing */
1606 pa_usec_t diff
= now
- last_time
;
1608 if (diff
> stream
->mmdev_period_usec
)
1610 stream
->just_started
= FALSE
;
1616 INT32 adjust
= last_time
+ stream
->mmdev_period_usec
- now
;
1618 adv_usec
= now
- last_time
;
1620 if(adjust
> ((INT32
)(stream
->mmdev_period_usec
/ 2)))
1621 adjust
= stream
->mmdev_period_usec
/ 2;
1622 else if(adjust
< -((INT32
)(stream
->mmdev_period_usec
/ 2)))
1623 adjust
= -1 * stream
->mmdev_period_usec
/ 2;
1625 delay
.QuadPart
= -(stream
->mmdev_period_usec
+ adjust
) * 10;
1627 last_time
+= stream
->mmdev_period_usec
;
1630 if (stream
->dataflow
== eRender
)
1632 pulse_write(stream
);
1634 /* regardless of what PA does, advance one period */
1635 adv_bytes
= min(stream
->period_bytes
, stream
->held_bytes
);
1636 stream
->lcl_offs_bytes
+= adv_bytes
;
1637 stream
->lcl_offs_bytes
%= stream
->real_bufsize_bytes
;
1638 stream
->held_bytes
-= adv_bytes
;
1640 else if(stream
->dataflow
== eCapture
)
1648 delay
.QuadPart
= -stream
->mmdev_period_usec
* 10;
1653 NtSetEvent(stream
->event
, NULL
);
1655 TRACE("%p after update, adv usec: %d, held: %u, delay usec: %u\n",
1656 stream
, (int)adv_usec
,
1657 (int)(stream
->held_bytes
/ pa_frame_size(&stream
->ss
)),
1658 (unsigned int)(-delay
.QuadPart
/ 10));
1663 return STATUS_SUCCESS
;
1666 static NTSTATUS
pulse_start(void *args
)
1668 struct start_params
*params
= args
;
1669 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1673 params
->result
= S_OK
;
1675 if (!pulse_stream_valid(stream
))
1678 params
->result
= S_OK
;
1679 return STATUS_SUCCESS
;
1682 if ((stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
) && !stream
->event
)
1685 params
->result
= AUDCLNT_E_EVENTHANDLE_NOT_SET
;
1686 return STATUS_SUCCESS
;
1689 if (stream
->started
)
1692 params
->result
= AUDCLNT_E_NOT_STOPPED
;
1693 return STATUS_SUCCESS
;
1696 pulse_write(stream
);
1698 if (pa_stream_is_corked(stream
->stream
))
1700 o
= pa_stream_cork(stream
->stream
, 0, pulse_op_cb
, &success
);
1703 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1705 pa_operation_unref(o
);
1710 params
->result
= E_FAIL
;
1713 if (SUCCEEDED(params
->result
))
1715 stream
->started
= TRUE
;
1716 stream
->just_started
= TRUE
;
1719 return STATUS_SUCCESS
;
1722 static NTSTATUS
pulse_stop(void *args
)
1724 struct stop_params
*params
= args
;
1725 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1730 if (!pulse_stream_valid(stream
))
1733 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1734 return STATUS_SUCCESS
;
1737 if (!stream
->started
)
1740 params
->result
= S_FALSE
;
1741 return STATUS_SUCCESS
;
1744 params
->result
= S_OK
;
1745 if (stream
->dataflow
== eRender
)
1747 o
= pa_stream_cork(stream
->stream
, 1, pulse_op_cb
, &success
);
1750 while(pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1752 pa_operation_unref(o
);
1757 params
->result
= E_FAIL
;
1759 if (SUCCEEDED(params
->result
))
1760 stream
->started
= FALSE
;
1762 return STATUS_SUCCESS
;
1765 static NTSTATUS
pulse_reset(void *args
)
1767 struct reset_params
*params
= args
;
1768 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1771 if (!pulse_stream_valid(stream
))
1774 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1775 return STATUS_SUCCESS
;
1778 if (stream
->started
)
1781 params
->result
= AUDCLNT_E_NOT_STOPPED
;
1782 return STATUS_SUCCESS
;
1788 params
->result
= AUDCLNT_E_BUFFER_OPERATION_PENDING
;
1789 return STATUS_SUCCESS
;
1792 if (stream
->dataflow
== eRender
)
1794 /* If there is still data in the render buffer it needs to be removed from the server */
1796 if (stream
->held_bytes
)
1798 pa_operation
*o
= pa_stream_flush(stream
->stream
, pulse_op_cb
, &success
);
1801 while (pa_operation_get_state(o
) == PA_OPERATION_RUNNING
)
1803 pa_operation_unref(o
);
1806 if (success
|| !stream
->held_bytes
)
1808 stream
->clock_lastpos
= stream
->clock_written
= 0;
1809 stream
->pa_offs_bytes
= stream
->lcl_offs_bytes
= 0;
1810 stream
->held_bytes
= stream
->pa_held_bytes
= 0;
1816 stream
->clock_written
+= stream
->held_bytes
;
1817 stream
->held_bytes
= 0;
1819 if ((p
= stream
->locked_ptr
))
1821 stream
->locked_ptr
= NULL
;
1822 list_add_tail(&stream
->packet_free_head
, &p
->entry
);
1824 list_move_tail(&stream
->packet_free_head
, &stream
->packet_filled_head
);
1827 params
->result
= S_OK
;
1828 return STATUS_SUCCESS
;
1831 static BOOL
alloc_tmp_buffer(struct pulse_stream
*stream
, SIZE_T bytes
)
1835 if (stream
->tmp_buffer_bytes
>= bytes
)
1838 if (stream
->tmp_buffer
)
1841 NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1842 &size
, MEM_RELEASE
);
1843 stream
->tmp_buffer
= NULL
;
1844 stream
->tmp_buffer_bytes
= 0;
1846 if (NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream
->tmp_buffer
,
1847 zero_bits
, &bytes
, MEM_COMMIT
, PAGE_READWRITE
))
1850 stream
->tmp_buffer_bytes
= bytes
;
1854 static UINT32
pulse_render_padding(struct pulse_stream
*stream
)
1856 return stream
->held_bytes
/ pa_frame_size(&stream
->ss
);
1859 static UINT32
pulse_capture_padding(struct pulse_stream
*stream
)
1861 ACPacket
*packet
= stream
->locked_ptr
;
1862 if (!packet
&& !list_empty(&stream
->packet_filled_head
))
1864 packet
= (ACPacket
*)list_head(&stream
->packet_filled_head
);
1865 stream
->locked_ptr
= packet
;
1866 list_remove(&packet
->entry
);
1868 return stream
->held_bytes
/ pa_frame_size(&stream
->ss
);
1871 static NTSTATUS
pulse_get_render_buffer(void *args
)
1873 struct get_render_buffer_params
*params
= args
;
1874 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1876 UINT32 wri_offs_bytes
;
1879 if (!pulse_stream_valid(stream
))
1882 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
1883 return STATUS_SUCCESS
;
1889 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
1890 return STATUS_SUCCESS
;
1893 if (!params
->frames
)
1896 *params
->data
= NULL
;
1897 params
->result
= S_OK
;
1898 return STATUS_SUCCESS
;
1901 if (stream
->held_bytes
/ pa_frame_size(&stream
->ss
) + params
->frames
> stream
->bufsize_frames
)
1904 params
->result
= AUDCLNT_E_BUFFER_TOO_LARGE
;
1905 return STATUS_SUCCESS
;
1908 bytes
= params
->frames
* pa_frame_size(&stream
->ss
);
1909 wri_offs_bytes
= (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1910 if (wri_offs_bytes
+ bytes
> stream
->real_bufsize_bytes
)
1912 if (!alloc_tmp_buffer(stream
, bytes
))
1915 params
->result
= E_OUTOFMEMORY
;
1916 return STATUS_SUCCESS
;
1918 *params
->data
= stream
->tmp_buffer
;
1919 stream
->locked
= -bytes
;
1923 *params
->data
= stream
->local_buffer
+ wri_offs_bytes
;
1924 stream
->locked
= bytes
;
1927 silence_buffer(stream
->ss
.format
, *params
->data
, bytes
);
1930 params
->result
= S_OK
;
1931 return STATUS_SUCCESS
;
1934 static void pulse_wrap_buffer(struct pulse_stream
*stream
, BYTE
*buffer
, UINT32 written_bytes
)
1936 UINT32 wri_offs_bytes
= (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1937 UINT32 chunk_bytes
= stream
->real_bufsize_bytes
- wri_offs_bytes
;
1939 if (written_bytes
<= chunk_bytes
)
1941 memcpy(stream
->local_buffer
+ wri_offs_bytes
, buffer
, written_bytes
);
1945 memcpy(stream
->local_buffer
+ wri_offs_bytes
, buffer
, chunk_bytes
);
1946 memcpy(stream
->local_buffer
, buffer
+ chunk_bytes
, written_bytes
- chunk_bytes
);
1950 static NTSTATUS
pulse_release_render_buffer(void *args
)
1952 struct release_render_buffer_params
*params
= args
;
1953 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
1954 UINT32 written_bytes
;
1958 if (!stream
->locked
|| !params
->written_frames
)
1962 params
->result
= params
->written_frames
? AUDCLNT_E_OUT_OF_ORDER
: S_OK
;
1963 return STATUS_SUCCESS
;
1966 if (params
->written_frames
* pa_frame_size(&stream
->ss
) >
1967 (stream
->locked
>= 0 ? stream
->locked
: -stream
->locked
))
1970 params
->result
= AUDCLNT_E_INVALID_SIZE
;
1971 return STATUS_SUCCESS
;
1974 if (stream
->locked
>= 0)
1975 buffer
= stream
->local_buffer
+ (stream
->lcl_offs_bytes
+ stream
->held_bytes
) % stream
->real_bufsize_bytes
;
1977 buffer
= stream
->tmp_buffer
;
1979 written_bytes
= params
->written_frames
* pa_frame_size(&stream
->ss
);
1980 if (params
->flags
& AUDCLNT_BUFFERFLAGS_SILENT
)
1981 silence_buffer(stream
->ss
.format
, buffer
, written_bytes
);
1983 if (stream
->locked
< 0)
1984 pulse_wrap_buffer(stream
, buffer
, written_bytes
);
1986 stream
->held_bytes
+= written_bytes
;
1987 stream
->pa_held_bytes
+= written_bytes
;
1988 if (stream
->pa_held_bytes
> stream
->real_bufsize_bytes
)
1990 stream
->pa_offs_bytes
+= stream
->pa_held_bytes
- stream
->real_bufsize_bytes
;
1991 stream
->pa_offs_bytes
%= stream
->real_bufsize_bytes
;
1992 stream
->pa_held_bytes
= stream
->real_bufsize_bytes
;
1994 stream
->clock_written
+= written_bytes
;
1997 /* push as much data as we can to pulseaudio too */
1998 pulse_write(stream
);
2000 TRACE("Released %u, held %lu\n", params
->written_frames
, stream
->held_bytes
/ pa_frame_size(&stream
->ss
));
2003 params
->result
= S_OK
;
2004 return STATUS_SUCCESS
;
2007 static NTSTATUS
pulse_get_capture_buffer(void *args
)
2009 struct get_capture_buffer_params
*params
= args
;
2010 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2014 if (!pulse_stream_valid(stream
))
2017 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2018 return STATUS_SUCCESS
;
2023 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
2024 return STATUS_SUCCESS
;
2027 pulse_capture_padding(stream
);
2028 if ((packet
= stream
->locked_ptr
))
2030 *params
->frames
= stream
->period_bytes
/ pa_frame_size(&stream
->ss
);
2032 if (packet
->discont
)
2033 *params
->flags
|= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY
;
2036 if (packet
->discont
)
2037 *params
->devpos
= (stream
->clock_written
+ stream
->period_bytes
) / pa_frame_size(&stream
->ss
);
2039 *params
->devpos
= stream
->clock_written
/ pa_frame_size(&stream
->ss
);
2042 *params
->qpcpos
= packet
->qpcpos
;
2043 *params
->data
= packet
->data
;
2046 *params
->frames
= 0;
2047 stream
->locked
= *params
->frames
;
2049 params
->result
= *params
->frames
? S_OK
: AUDCLNT_S_BUFFER_EMPTY
;
2050 return STATUS_SUCCESS
;
2053 static NTSTATUS
pulse_release_capture_buffer(void *args
)
2055 struct release_capture_buffer_params
*params
= args
;
2056 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2059 if (!stream
->locked
&& params
->done
)
2062 params
->result
= AUDCLNT_E_OUT_OF_ORDER
;
2063 return STATUS_SUCCESS
;
2065 if (params
->done
&& stream
->locked
!= params
->done
)
2068 params
->result
= AUDCLNT_E_INVALID_SIZE
;
2069 return STATUS_SUCCESS
;
2073 ACPacket
*packet
= stream
->locked_ptr
;
2074 stream
->locked_ptr
= NULL
;
2075 stream
->held_bytes
-= stream
->period_bytes
;
2076 if (packet
->discont
)
2077 stream
->clock_written
+= 2 * stream
->period_bytes
;
2079 stream
->clock_written
+= stream
->period_bytes
;
2080 list_add_tail(&stream
->packet_free_head
, &packet
->entry
);
2084 params
->result
= S_OK
;
2085 return STATUS_SUCCESS
;
2088 static NTSTATUS
pulse_is_format_supported(void *args
)
2090 struct is_format_supported_params
*params
= args
;
2091 WAVEFORMATEXTENSIBLE in
;
2092 WAVEFORMATEXTENSIBLE
*out
;
2093 const WAVEFORMATEX
*fmt
= &in
.Format
;
2094 const BOOLEAN exclusive
= params
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
;
2096 params
->result
= S_OK
;
2098 if (!params
->fmt_in
|| (params
->share
== AUDCLNT_SHAREMODE_SHARED
&& !params
->fmt_out
))
2099 params
->result
= E_POINTER
;
2100 else if (params
->share
!= AUDCLNT_SHAREMODE_SHARED
&& params
->share
!= AUDCLNT_SHAREMODE_EXCLUSIVE
)
2101 params
->result
= E_INVALIDARG
;
2103 memcpy(&in
, params
->fmt_in
, params
->fmt_in
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
?
2104 sizeof(in
) : sizeof(in
.Format
));
2106 if (fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
2107 if (fmt
->cbSize
< sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
))
2108 params
->result
= E_INVALIDARG
;
2109 else if (fmt
->nAvgBytesPerSec
== 0 || fmt
->nBlockAlign
== 0 ||
2110 (in
.Samples
.wValidBitsPerSample
> fmt
->wBitsPerSample
))
2111 params
->result
= E_INVALIDARG
;
2112 else if (fmt
->nChannels
== 0)
2113 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2117 if (FAILED(params
->result
))
2118 return STATUS_SUCCESS
;
2123 out
= params
->fmt_out
;
2124 memcpy(out
, fmt
, fmt
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
?
2125 sizeof(*out
) : sizeof((*out
).Format
));
2128 switch (fmt
->wFormatTag
) {
2129 case WAVE_FORMAT_EXTENSIBLE
: {
2130 if ((fmt
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
) - sizeof(WAVEFORMATEX
) &&
2131 fmt
->cbSize
!= sizeof(WAVEFORMATEXTENSIBLE
)) ||
2132 fmt
->nBlockAlign
!= fmt
->wBitsPerSample
/ 8 * fmt
->nChannels
||
2133 in
.Samples
.wValidBitsPerSample
> fmt
->wBitsPerSample
||
2134 fmt
->nAvgBytesPerSec
!= fmt
->nBlockAlign
* fmt
->nSamplesPerSec
) {
2135 params
->result
= E_INVALIDARG
;
2140 UINT32 mask
= 0, i
, channels
= 0;
2142 if (!(in
.dwChannelMask
& (SPEAKER_ALL
| SPEAKER_RESERVED
))) {
2143 for (i
= 1; !(i
& SPEAKER_RESERVED
); i
<<= 1) {
2144 if (i
& in
.dwChannelMask
) {
2150 if (channels
!= fmt
->nChannels
|| (in
.dwChannelMask
& ~mask
)) {
2151 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2155 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2160 if (IsEqualGUID(&in
.SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
)) {
2161 if (fmt
->wBitsPerSample
!= 32) {
2162 params
->result
= E_INVALIDARG
;
2166 if (in
.Samples
.wValidBitsPerSample
!= fmt
->wBitsPerSample
) {
2167 params
->result
= S_FALSE
;
2168 out
->Samples
.wValidBitsPerSample
= fmt
->wBitsPerSample
;
2170 } else if (IsEqualGUID(&in
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
)) {
2171 if (!fmt
->wBitsPerSample
|| fmt
->wBitsPerSample
> 32 || fmt
->wBitsPerSample
% 8) {
2172 params
->result
= E_INVALIDARG
;
2176 if (in
.Samples
.wValidBitsPerSample
!= fmt
->wBitsPerSample
&&
2177 !(fmt
->wBitsPerSample
== 32 &&
2178 in
.Samples
.wValidBitsPerSample
== 24)) {
2179 params
->result
= S_FALSE
;
2180 out
->Samples
.wValidBitsPerSample
= fmt
->wBitsPerSample
;
2184 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2190 case WAVE_FORMAT_ALAW
:
2191 case WAVE_FORMAT_MULAW
:
2192 if (fmt
->wBitsPerSample
!= 8) {
2193 params
->result
= E_INVALIDARG
;
2197 case WAVE_FORMAT_IEEE_FLOAT
:
2198 if (fmt
->wFormatTag
== WAVE_FORMAT_IEEE_FLOAT
&& fmt
->wBitsPerSample
!= 32) {
2199 params
->result
= E_INVALIDARG
;
2203 case WAVE_FORMAT_PCM
: {
2204 if (fmt
->wFormatTag
== WAVE_FORMAT_PCM
&&
2205 (!fmt
->wBitsPerSample
|| fmt
->wBitsPerSample
> 32 || fmt
->wBitsPerSample
% 8)) {
2206 params
->result
= E_INVALIDARG
;
2210 if (fmt
->nChannels
> 2) {
2211 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2215 /* fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
2216 * ignored, invalid values are happily accepted. */
2220 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2224 if (exclusive
) { /* This driver does not support exclusive mode. */
2225 if (params
->result
== S_OK
)
2226 params
->result
= params
->flow
== eCapture
?
2227 AUDCLNT_E_UNSUPPORTED_FORMAT
:
2228 AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
;
2229 else if (params
->result
== S_FALSE
)
2230 params
->result
= AUDCLNT_E_UNSUPPORTED_FORMAT
;
2233 return STATUS_SUCCESS
;
2236 static NTSTATUS
pulse_get_mix_format(void *args
)
2238 struct get_mix_format_params
*params
= args
;
2239 struct list
*list
= (params
->flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
2242 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
2243 if (strcmp(params
->device
, dev
->pulse_name
))
2246 *params
->fmt
= dev
->fmt
;
2247 params
->result
= S_OK
;
2249 return STATUS_SUCCESS
;
2252 params
->result
= E_FAIL
;
2253 return STATUS_SUCCESS
;
2256 static NTSTATUS
pulse_get_device_period(void *args
)
2258 struct get_device_period_params
*params
= args
;
2260 params
->result
= get_device_period_helper(params
->flow
, params
->device
, params
->def_period
, params
->min_period
);
2261 return STATUS_SUCCESS
;
2264 static NTSTATUS
pulse_get_buffer_size(void *args
)
2266 struct get_buffer_size_params
*params
= args
;
2267 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2269 params
->result
= S_OK
;
2272 if (!pulse_stream_valid(stream
))
2273 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2275 *params
->frames
= stream
->bufsize_frames
;
2278 return STATUS_SUCCESS
;
2281 static NTSTATUS
pulse_get_latency(void *args
)
2283 struct get_latency_params
*params
= args
;
2284 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2285 const pa_buffer_attr
*attr
;
2289 if (!pulse_stream_valid(stream
)) {
2291 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2292 return STATUS_SUCCESS
;
2294 attr
= pa_stream_get_buffer_attr(stream
->stream
);
2295 if (stream
->dataflow
== eRender
)
2296 lat
= attr
->minreq
/ pa_frame_size(&stream
->ss
);
2298 lat
= attr
->fragsize
/ pa_frame_size(&stream
->ss
);
2299 *params
->latency
= (lat
* 10000000) / stream
->ss
.rate
+ stream
->def_period
;
2301 TRACE("Latency: %u ms\n", (unsigned)(*params
->latency
/ 10000));
2302 params
->result
= S_OK
;
2303 return STATUS_SUCCESS
;
2306 static NTSTATUS
pulse_get_current_padding(void *args
)
2308 struct get_current_padding_params
*params
= args
;
2309 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2312 if (!pulse_stream_valid(stream
))
2315 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2316 return STATUS_SUCCESS
;
2319 if (stream
->dataflow
== eRender
)
2320 *params
->padding
= pulse_render_padding(stream
);
2322 *params
->padding
= pulse_capture_padding(stream
);
2325 TRACE("%p Pad: %u ms (%u)\n", stream
, muldiv(*params
->padding
, 1000, stream
->ss
.rate
),
2327 params
->result
= S_OK
;
2328 return STATUS_SUCCESS
;
2331 static NTSTATUS
pulse_get_next_packet_size(void *args
)
2333 struct get_next_packet_size_params
*params
= args
;
2334 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2337 pulse_capture_padding(stream
);
2338 if (stream
->locked_ptr
)
2339 *params
->frames
= stream
->period_bytes
/ pa_frame_size(&stream
->ss
);
2341 *params
->frames
= 0;
2343 params
->result
= S_OK
;
2345 return STATUS_SUCCESS
;
2348 static NTSTATUS
pulse_get_frequency(void *args
)
2350 struct get_frequency_params
*params
= args
;
2351 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2354 if (!pulse_stream_valid(stream
))
2357 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2358 return STATUS_SUCCESS
;
2361 *params
->freq
= stream
->ss
.rate
;
2362 if (stream
->share
== AUDCLNT_SHAREMODE_SHARED
)
2363 *params
->freq
*= pa_frame_size(&stream
->ss
);
2365 params
->result
= S_OK
;
2366 return STATUS_SUCCESS
;
2369 static NTSTATUS
pulse_get_position(void *args
)
2371 struct get_position_params
*params
= args
;
2372 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2375 if (!pulse_stream_valid(stream
))
2378 params
->result
= AUDCLNT_E_DEVICE_INVALIDATED
;
2379 return STATUS_SUCCESS
;
2382 *params
->pos
= stream
->clock_written
- stream
->held_bytes
;
2384 if (stream
->share
== AUDCLNT_SHAREMODE_EXCLUSIVE
|| params
->device
)
2385 *params
->pos
/= pa_frame_size(&stream
->ss
);
2387 /* Make time never go backwards */
2388 if (*params
->pos
< stream
->clock_lastpos
)
2389 *params
->pos
= stream
->clock_lastpos
;
2391 stream
->clock_lastpos
= *params
->pos
;
2394 TRACE("%p Position: %u\n", stream
, (unsigned)*params
->pos
);
2396 if (params
->qpctime
)
2398 LARGE_INTEGER stamp
, freq
;
2399 NtQueryPerformanceCounter(&stamp
, &freq
);
2400 *params
->qpctime
= (stamp
.QuadPart
* (INT64
)10000000) / freq
.QuadPart
;
2403 params
->result
= S_OK
;
2404 return STATUS_SUCCESS
;
2407 static NTSTATUS
pulse_set_volumes(void *args
)
2409 struct set_volumes_params
*params
= args
;
2410 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2413 for (i
= 0; i
< stream
->ss
.channels
; i
++)
2414 stream
->vol
[i
] = params
->volumes
[i
] * params
->master_volume
* params
->session_volumes
[i
];
2416 return STATUS_SUCCESS
;
2419 static NTSTATUS
pulse_set_event_handle(void *args
)
2421 struct set_event_handle_params
*params
= args
;
2422 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2426 if (!pulse_stream_valid(stream
))
2427 hr
= AUDCLNT_E_DEVICE_INVALIDATED
;
2428 else if (!(stream
->flags
& AUDCLNT_STREAMFLAGS_EVENTCALLBACK
))
2429 hr
= AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED
;
2430 else if (stream
->event
)
2431 hr
= HRESULT_FROM_WIN32(ERROR_INVALID_NAME
);
2433 stream
->event
= params
->event
;
2436 params
->result
= hr
;
2437 return STATUS_SUCCESS
;
2440 static NTSTATUS
pulse_is_started(void *args
)
2442 struct is_started_params
*params
= args
;
2443 struct pulse_stream
*stream
= handle_get_stream(params
->stream
);
2446 params
->result
= pulse_stream_valid(stream
) && stream
->started
? S_OK
: S_FALSE
;
2449 return STATUS_SUCCESS
;
2452 static BOOL
get_device_path(PhysDevice
*dev
, struct get_prop_value_params
*params
)
2454 const GUID
*guid
= params
->guid
;
2455 PROPVARIANT
*out
= params
->value
;
2460 /* As hardly any audio devices have serial numbers, Windows instead
2461 appears to use a persistent random number. We emulate this here
2462 by instead using the last 8 hex digits of the GUID. */
2463 serial_number
= (guid
->Data4
[4] << 24) | (guid
->Data4
[5] << 16) | (guid
->Data4
[6] << 8) | guid
->Data4
[7];
2465 switch (dev
->bus_type
) {
2466 case phys_device_bus_pci
:
2467 len
= sprintf(path
, "{1}.HDAUDIO\\FUNC_01&VEN_%04X&DEV_%04X\\%u&%08X", dev
->vendor_id
, dev
->product_id
, dev
->index
, serial_number
);
2469 case phys_device_bus_usb
:
2470 len
= sprintf(path
, "{1}.USB\\VID_%04X&PID_%04X\\%u&%08X", dev
->vendor_id
, dev
->product_id
, dev
->index
, serial_number
);
2473 len
= sprintf(path
, "{1}.ROOT\\MEDIA\\%04u", dev
->index
);
2477 if (*params
->buffer_size
< ++len
* sizeof(WCHAR
)) {
2478 params
->result
= E_NOT_SUFFICIENT_BUFFER
;
2479 *params
->buffer_size
= len
* sizeof(WCHAR
);
2483 out
->vt
= VT_LPWSTR
;
2484 out
->pwszVal
= params
->buffer
;
2486 ntdll_umbstowcs(path
, len
, out
->pwszVal
, len
);
2488 params
->result
= S_OK
;
2493 static NTSTATUS
pulse_get_prop_value(void *args
)
2495 static const GUID PKEY_AudioEndpoint_GUID
= {
2496 0x1da5d803, 0xd492, 0x4edd, {0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e}
2498 static const PROPERTYKEY devicepath_key
= { /* undocumented? - {b3f8fa53-0004-438e-9003-51a46e139bfc},2 */
2499 {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2
2501 struct get_prop_value_params
*params
= args
;
2502 struct list
*list
= (params
->flow
== eRender
) ? &g_phys_speakers
: &g_phys_sources
;
2505 LIST_FOR_EACH_ENTRY(dev
, list
, PhysDevice
, entry
) {
2506 if (strcmp(params
->device
, dev
->pulse_name
))
2508 if (IsEqualPropertyKey(*params
->prop
, devicepath_key
)) {
2509 get_device_path(dev
, params
);
2510 return STATUS_SUCCESS
;
2511 } else if (IsEqualGUID(¶ms
->prop
->fmtid
, &PKEY_AudioEndpoint_GUID
)) {
2512 switch (params
->prop
->pid
) {
2513 case 0: /* FormFactor */
2514 params
->value
->vt
= VT_UI4
;
2515 params
->value
->ulVal
= dev
->form
;
2516 params
->result
= S_OK
;
2517 return STATUS_SUCCESS
;
2518 case 3: /* PhysicalSpeakers */
2519 if (!dev
->channel_mask
)
2521 params
->value
->vt
= VT_UI4
;
2522 params
->value
->ulVal
= dev
->channel_mask
;
2523 params
->result
= S_OK
;
2524 return STATUS_SUCCESS
;
2528 params
->result
= E_NOTIMPL
;
2529 return STATUS_SUCCESS
;
2533 params
->result
= E_FAIL
;
2534 return STATUS_SUCCESS
;
2537 const unixlib_entry_t __wine_unix_call_funcs
[] =
2539 pulse_process_attach
,
2540 pulse_process_detach
,
2542 pulse_get_endpoint_ids
,
2543 pulse_create_stream
,
2544 pulse_release_stream
,
2549 pulse_get_render_buffer
,
2550 pulse_release_render_buffer
,
2551 pulse_get_capture_buffer
,
2552 pulse_release_capture_buffer
,
2553 pulse_is_format_supported
,
2554 pulse_get_mix_format
,
2555 pulse_get_device_period
,
2556 pulse_get_buffer_size
,
2558 pulse_get_current_padding
,
2559 pulse_get_next_packet_size
,
2560 pulse_get_frequency
,
2563 pulse_set_event_handle
,
2566 pulse_get_prop_value
,
2567 pulse_not_implemented
,
2568 pulse_not_implemented
,
2569 pulse_not_implemented
,
2570 pulse_not_implemented
,
2571 pulse_not_implemented
,
2572 pulse_not_implemented
,
2579 static NTSTATUS
pulse_wow64_main_loop(void *args
)
2585 struct main_loop_params params
=
2587 .event
= ULongToHandle(params32
->event
)
2589 return pulse_main_loop(¶ms
);
2592 static NTSTATUS
pulse_wow64_get_endpoint_ids(void *args
)
2601 unsigned int default_idx
;
2603 struct get_endpoint_ids_params params
=
2605 .flow
= params32
->flow
,
2606 .endpoints
= ULongToPtr(params32
->endpoints
),
2607 .size
= params32
->size
2609 pulse_get_endpoint_ids(¶ms
);
2610 params32
->size
= params
.size
;
2611 params32
->result
= params
.result
;
2612 params32
->num
= params
.num
;
2613 params32
->default_idx
= params
.default_idx
;
2614 return STATUS_SUCCESS
;
2617 static NTSTATUS
pulse_wow64_create_stream(void *args
)
2624 AUDCLNT_SHAREMODE share
;
2626 REFERENCE_TIME duration
;
2627 REFERENCE_TIME period
;
2630 PTR32 channel_count
;
2633 struct create_stream_params params
=
2635 .name
= ULongToPtr(params32
->name
),
2636 .device
= ULongToPtr(params32
->device
),
2637 .flow
= params32
->flow
,
2638 .share
= params32
->share
,
2639 .flags
= params32
->flags
,
2640 .duration
= params32
->duration
,
2641 .period
= params32
->period
,
2642 .fmt
= ULongToPtr(params32
->fmt
),
2643 .channel_count
= ULongToPtr(params32
->channel_count
),
2644 .stream
= ULongToPtr(params32
->stream
)
2646 pulse_create_stream(¶ms
);
2647 params32
->result
= params
.result
;
2648 return STATUS_SUCCESS
;
2651 static NTSTATUS
pulse_wow64_release_stream(void *args
)
2655 stream_handle stream
;
2659 struct release_stream_params params
=
2661 .stream
= params32
->stream
,
2662 .timer_thread
= ULongToHandle(params32
->timer_thread
)
2664 pulse_release_stream(¶ms
);
2665 params32
->result
= params
.result
;
2666 return STATUS_SUCCESS
;
2669 static NTSTATUS
pulse_wow64_get_render_buffer(void *args
)
2673 stream_handle stream
;
2679 struct get_render_buffer_params params
=
2681 .stream
= params32
->stream
,
2682 .frames
= params32
->frames
,
2685 pulse_get_render_buffer(¶ms
);
2686 params32
->result
= params
.result
;
2687 *(unsigned int *)ULongToPtr(params32
->data
) = PtrToUlong(data
);
2688 return STATUS_SUCCESS
;
2691 static NTSTATUS
pulse_wow64_get_capture_buffer(void *args
)
2695 stream_handle stream
;
2704 struct get_capture_buffer_params params
=
2706 .stream
= params32
->stream
,
2708 .frames
= ULongToPtr(params32
->frames
),
2709 .flags
= ULongToPtr(params32
->flags
),
2710 .devpos
= ULongToPtr(params32
->devpos
),
2711 .qpcpos
= ULongToPtr(params32
->qpcpos
)
2713 pulse_get_capture_buffer(¶ms
);
2714 params32
->result
= params
.result
;
2715 *(unsigned int *)ULongToPtr(params32
->data
) = PtrToUlong(data
);
2716 return STATUS_SUCCESS
;
2719 static NTSTATUS
pulse_wow64_is_format_supported(void *args
)
2725 AUDCLNT_SHAREMODE share
;
2730 struct is_format_supported_params params
=
2732 .device
= ULongToPtr(params32
->device
),
2733 .flow
= params32
->flow
,
2734 .share
= params32
->share
,
2735 .fmt_in
= ULongToPtr(params32
->fmt_in
),
2736 .fmt_out
= ULongToPtr(params32
->fmt_out
)
2738 pulse_is_format_supported(¶ms
);
2739 params32
->result
= params
.result
;
2740 return STATUS_SUCCESS
;
2743 static NTSTATUS
pulse_wow64_get_mix_format(void *args
)
2752 struct get_mix_format_params params
=
2754 .device
= ULongToPtr(params32
->device
),
2755 .flow
= params32
->flow
,
2756 .fmt
= ULongToPtr(params32
->fmt
),
2758 pulse_get_mix_format(¶ms
);
2759 params32
->result
= params
.result
;
2760 return STATUS_SUCCESS
;
2763 static NTSTATUS
pulse_wow64_get_device_period(void *args
)
2773 struct get_device_period_params params
=
2775 .device
= ULongToPtr(params32
->device
),
2776 .flow
= params32
->flow
,
2777 .def_period
= ULongToPtr(params32
->def_period
),
2778 .min_period
= ULongToPtr(params32
->min_period
),
2780 pulse_get_device_period(¶ms
);
2781 params32
->result
= params
.result
;
2782 return STATUS_SUCCESS
;
2785 static NTSTATUS
pulse_wow64_get_buffer_size(void *args
)
2789 stream_handle stream
;
2793 struct get_buffer_size_params params
=
2795 .stream
= params32
->stream
,
2796 .frames
= ULongToPtr(params32
->frames
)
2798 pulse_get_buffer_size(¶ms
);
2799 params32
->result
= params
.result
;
2800 return STATUS_SUCCESS
;
2803 static NTSTATUS
pulse_wow64_get_latency(void *args
)
2807 stream_handle stream
;
2811 struct get_latency_params params
=
2813 .stream
= params32
->stream
,
2814 .latency
= ULongToPtr(params32
->latency
)
2816 pulse_get_latency(¶ms
);
2817 params32
->result
= params
.result
;
2818 return STATUS_SUCCESS
;
2821 static NTSTATUS
pulse_wow64_get_current_padding(void *args
)
2825 stream_handle stream
;
2829 struct get_current_padding_params params
=
2831 .stream
= params32
->stream
,
2832 .padding
= ULongToPtr(params32
->padding
)
2834 pulse_get_current_padding(¶ms
);
2835 params32
->result
= params
.result
;
2836 return STATUS_SUCCESS
;
2839 static NTSTATUS
pulse_wow64_get_next_packet_size(void *args
)
2843 stream_handle stream
;
2847 struct get_next_packet_size_params params
=
2849 .stream
= params32
->stream
,
2850 .frames
= ULongToPtr(params32
->frames
)
2852 pulse_get_next_packet_size(¶ms
);
2853 params32
->result
= params
.result
;
2854 return STATUS_SUCCESS
;
2857 static NTSTATUS
pulse_wow64_get_frequency(void *args
)
2861 stream_handle stream
;
2865 struct get_frequency_params params
=
2867 .stream
= params32
->stream
,
2868 .freq
= ULongToPtr(params32
->freq
)
2870 pulse_get_frequency(¶ms
);
2871 params32
->result
= params
.result
;
2872 return STATUS_SUCCESS
;
2875 static NTSTATUS
pulse_wow64_get_position(void *args
)
2879 stream_handle stream
;
2885 struct get_position_params params
=
2887 .stream
= params32
->stream
,
2888 .device
= params32
->device
,
2889 .pos
= ULongToPtr(params32
->pos
),
2890 .qpctime
= ULongToPtr(params32
->qpctime
)
2892 pulse_get_position(¶ms
);
2893 params32
->result
= params
.result
;
2894 return STATUS_SUCCESS
;
2897 static NTSTATUS
pulse_wow64_set_volumes(void *args
)
2901 stream_handle stream
;
2902 float master_volume
;
2904 PTR32 session_volumes
;
2906 struct set_volumes_params params
=
2908 .stream
= params32
->stream
,
2909 .master_volume
= params32
->master_volume
,
2910 .volumes
= ULongToPtr(params32
->volumes
),
2911 .session_volumes
= ULongToPtr(params32
->session_volumes
),
2913 return pulse_set_volumes(¶ms
);
2916 static NTSTATUS
pulse_wow64_set_event_handle(void *args
)
2920 stream_handle stream
;
2924 struct set_event_handle_params params
=
2926 .stream
= params32
->stream
,
2927 .event
= ULongToHandle(params32
->event
)
2929 pulse_set_event_handle(¶ms
);
2930 params32
->result
= params
.result
;
2931 return STATUS_SUCCESS
;
2934 static NTSTATUS
pulse_wow64_test_connect(void *args
)
2939 enum driver_priority priority
;
2941 struct test_connect_params params
=
2943 .name
= ULongToPtr(params32
->name
),
2945 pulse_test_connect(¶ms
);
2946 params32
->priority
= params
.priority
;
2947 return STATUS_SUCCESS
;
2950 static NTSTATUS
pulse_wow64_get_prop_value(void *args
)
2952 struct propvariant32
2955 WORD pad1
, pad2
, pad3
;
2960 ULARGE_INTEGER uhVal
;
2971 PTR32 buffer
; /* caller allocated buffer to hold value's strings */
2975 struct get_prop_value_params params
=
2977 .device
= ULongToPtr(params32
->device
),
2978 .flow
= params32
->flow
,
2979 .guid
= ULongToPtr(params32
->guid
),
2980 .prop
= ULongToPtr(params32
->prop
),
2982 .buffer
= ULongToPtr(params32
->buffer
),
2983 .buffer_size
= ULongToPtr(params32
->buffer_size
)
2985 pulse_get_prop_value(¶ms
);
2986 params32
->result
= params
.result
;
2987 if (SUCCEEDED(params
.result
))
2989 value32
= UlongToPtr(params32
->value
);
2990 value32
->vt
= value
.vt
;
2994 value32
->ulVal
= value
.ulVal
;
2997 value32
->ptr
= params32
->buffer
;
3000 FIXME("Unhandled vt %04x\n", value
.vt
);
3003 return STATUS_SUCCESS
;
3006 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
3008 pulse_process_attach
,
3009 pulse_process_detach
,
3010 pulse_wow64_main_loop
,
3011 pulse_wow64_get_endpoint_ids
,
3012 pulse_wow64_create_stream
,
3013 pulse_wow64_release_stream
,
3018 pulse_wow64_get_render_buffer
,
3019 pulse_release_render_buffer
,
3020 pulse_wow64_get_capture_buffer
,
3021 pulse_release_capture_buffer
,
3022 pulse_wow64_is_format_supported
,
3023 pulse_wow64_get_mix_format
,
3024 pulse_wow64_get_device_period
,
3025 pulse_wow64_get_buffer_size
,
3026 pulse_wow64_get_latency
,
3027 pulse_wow64_get_current_padding
,
3028 pulse_wow64_get_next_packet_size
,
3029 pulse_wow64_get_frequency
,
3030 pulse_wow64_get_position
,
3031 pulse_wow64_set_volumes
,
3032 pulse_wow64_set_event_handle
,
3033 pulse_wow64_test_connect
,
3035 pulse_wow64_get_prop_value
,
3036 pulse_not_implemented
,
3037 pulse_not_implemented
,
3038 pulse_not_implemented
,
3039 pulse_not_implemented
,
3040 pulse_not_implemented
,
3041 pulse_not_implemented
,