uint32_t i;
for (i = 0; i < SPA_N_ELEMENTS(some_array); i++)
.. stuff with some_array[i].foo ...
becomes:
SPA_FOR_EACH_ELEMENT_VAR(some_array, p)
.. stuff with p->foo ..
When no maxlength is given, we use the MAXLENGTH value but we need to
round it DOWN (instead of up) because our buffer is only MAXLENGTH big.
Use CLAMP where we can.
When in capture mode, the maxlength exceeds MAXLENGTH, scale down the
fragsize instead.
Fixes noise in audacious when playing 6 channels sounds. float32 * 6
channels with the maximum buffer size would result in the ringbuffer
being overwritten.
Reducing the latency is just papering over the issue in #2702. The
real fix is to limit the blocksize to the fragsize like what is done
in 00a234daf2
Reducing the latency then also causes regressions like #2715 so don't
do that anymore.
Fixes#2715
When a client writes more then requested, let the requested field go
negative so that it is taken into account the next time we ask for more
data.
Also the requested field follows the difference in the write pointer
caused by seeks.
See #2626Fixes#2674
A client can sometimes send more data than we requested. PulseAudio
keeps the extra data around, it just asks for more data when it consumed
some of it.
PipeWire however always tries to keep tlength worth of data, as
specified in the PulseAudio docs... Keep track of how much extra data
has been sent and keep this around as well. Make sure we flush this
extra data as well.
Fixes#2626
Move the latency fraction calculation to fix_ functions so that the
new latency rate can be used when creating the streams.
Actually set the requested record attributes on the stream instead
of modifying the defaults.
See #2671
PulseAudio configures half of the fragsize as the source latency. It
also sends chunks as soon as they become available.
This means that we also need to configure the source with half of
the fragsize latency and send in chunks of fragsize/2. Keep this in
the unused (for record) minreq field.
Some Flatpak apps want to manage sound fully (change default outputs,
move streams from other applications). Real Pulseaudio always grants
full permissions, but pipewire-pulse doesn't, which breaks some
applications, e.g. Zoom.
Work around this by granting the manager permission if the application
also has devices=all access.
To do things properly, this probably should use the Portal media roles,
but this would need further work elsewhere.
The default metadata update may be delayed for some time after
SET_DEFAULT, since the session manager has to work on it.
MOVE_* commands need to know what the client thinks is the current
default sink, so that they can decide between "move to default" and
"move to specific device".
To avoid race condition here, stash the default value set by the client
and use it in the MOVE_* commands, until the metadata update arrives.
`client_update_quirks()` may modify `client::props` depending
on the "pulse.rules" section defined in the configuration file,
which means that it can change the value corresponding to the
"application.name" key. Therefore, `client::name` needs to
be queried after that.
`client::name` points to a string that is owned by `client::props`,
so when the property list is updated, it needs to be refreshed as well.
Otherwise, various use-after-frees can be triggered, for example:
==1471586==ERROR: AddressSanitizer: heap-use-after-free on address 0x60200007e7d0 at pc 0x7f14390755d0 bp 0x7ffe23edee30 sp 0x7ffe23ede5a8
READ of size 3 at 0x60200007e7d0 thread T0
#0 0x7f14390755cf in printf_common /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc:553
#1 0x7f1439077215 in __interceptor_vsnprintf /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1665
#2 0x7f1434ead47d in spa_vscnprintf ../spa/include/spa/utils/string.h:239
#3 0x7f1434eae2ae in impl_log_logtv ../spa/plugins/support/logger.c:138
#4 0x7f14385cacc7 in pw_log_logt ../src/pipewire/log.c:135
#5 0x7f1433aef8e9 in do_set_profile ../src/modules/module-protocol-pulse/pulse-server.c:4656
#6 0x7f1433b0af4d in handle_packet ../src/modules/module-protocol-pulse/server.c:109
#7 0x7f1433b0e747 in do_read ../src/modules/module-protocol-pulse/server.c:276
#8 0x7f1433b0eb04 in on_client_data ../src/modules/module-protocol-pulse/server.c:306
#9 0x7f1434ec56a0 in source_io_func ../spa/plugins/support/loop.c:442
#10 0x7f1434ec4a21 in loop_iterate ../spa/plugins/support/loop.c:430
#11 0x7f14385dc23d in pw_main_loop_run ../src/pipewire/main-loop.c:148
#12 0x55b065d73722 in main ../src/daemon/pipewire.c:131
#13 0x7f143742928f (/usr/lib/libc.so.6+0x2928f)
#14 0x7f1437429349 in __libc_start_main (/usr/lib/libc.so.6+0x29349)
#15 0x55b065d722a4 in _start (./src/daemon/pipewire-pulse+0x42a4)
0x60200007e7d0 is located 0 bytes inside of 16-byte region [0x60200007e7d0,0x60200007e7e0)
freed by thread T0 here:
#0 0x7f14390be672 in __interceptor_free /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:52
#1 0x7f14386a775a in do_replace ../src/pipewire/properties.c:414
#2 0x7f14386a785e in pw_properties_set ../src/pipewire/properties.c:441
#3 0x7f14386a658b in pw_properties_update ../src/pipewire/properties.c:309
#4 0x7f1433adb055 in do_update_proplist ../src/modules/module-protocol-pulse/pulse-server.c:3246
#5 0x7f1433b0af4d in handle_packet ../src/modules/module-protocol-pulse/server.c:109
#6 0x7f1433b0e747 in do_read ../src/modules/module-protocol-pulse/server.c:276
#7 0x7f1433b0eb04 in on_client_data ../src/modules/module-protocol-pulse/server.c:306
#8 0x7f1434ec56a0 in source_io_func ../spa/plugins/support/loop.c:442
#9 0x7f1434ec4a21 in loop_iterate ../spa/plugins/support/loop.c:430
#10 0x7f14385dc23d in pw_main_loop_run ../src/pipewire/main-loop.c:148
#11 0x55b065d73722 in main ../src/daemon/pipewire.c:131
#12 0x7f143742928f (/usr/lib/libc.so.6+0x2928f)
previously allocated by thread T0 here:
#0 0x7f1439072faa in __interceptor_strdup /usr/src/debug/gcc/libsanitizer/asan/asan_interceptors.cpp:439
#1 0x7f14386a6fe2 in do_replace ../src/pipewire/properties.c:394
#2 0x7f14386a785e in pw_properties_set ../src/pipewire/properties.c:441
#3 0x7f1433a6c52d in read_props ../src/modules/module-protocol-pulse/message.c:147
#4 0x7f1433a6f467 in message_get ../src/modules/module-protocol-pulse/message.c:359
#5 0x7f1433ab3191 in do_set_client_name ../src/modules/module-protocol-pulse/pulse-server.c:1030
#6 0x7f1433b0af4d in handle_packet ../src/modules/module-protocol-pulse/server.c:109
#7 0x7f1433b0e747 in do_read ../src/modules/module-protocol-pulse/server.c:276
#8 0x7f1433b0eb04 in on_client_data ../src/modules/module-protocol-pulse/server.c:306
#9 0x7f1434ec56a0 in source_io_func ../spa/plugins/support/loop.c:442
#10 0x7f1434ec4a21 in loop_iterate ../spa/plugins/support/loop.c:430
#11 0x7f14385dc23d in pw_main_loop_run ../src/pipewire/main-loop.c:148
#12 0x55b065d73722 in main ../src/daemon/pipewire.c:131
#13 0x7f143742928f (/usr/lib/libc.so.6+0x2928f)
Add some 'before' debug info of the attributes.
First clamp the fragsize to the maxlength and then clamp to the
minfrag or else we could bypass the configured minfrag by setting a
lower maxlength.
Scale the maxlength to at least twice the fragsize so that we can
buffer enough data in the ringbuffer to serve fragsize bytes.
See #2447
As Coverity points out, `ensure_size()` is not fully correct.
Let us assume that the message already has some allocated storage,
and the `realloc()` call in the next `ensure_size()` invocation fails.
In that case `message::data` is freed, but the pointer is left behind.
If another `ensure_size()` call is made, then `realloc()` will be called
(since the previous call left `message::allocated` as zero), but the
first argument of the `realloc()` call will be a dangling pointer.
In order to avoid the above, first of all, clear `message::data` after
a failed `realloc()` call, and immediately return `-ENOMEM` if
`message::length` is greater than `message::allocated` since
that signals if the message has even run into an out-of-memory
situation.
Store a pointer to the owner `impl` object instead of
the (embedded) `stat` object. This way `message_free()`
can be simplified since the owner `impl` does not need
to be passed explicitly.