The intuitive meaning of "missing" would be the difference between
tlength and the current queue length, and that's how memblockq-test
assumed pa_memblockq_pop_missing() to define the term "missing", but
that was an incorrect assumption, causing the last
pa_memblockq_pop_missing() return value assertion to fail.
This patch fixes the failing assertion and adds some comments about how
the "missing" and "requested" variables in memblockq work.
The function isn't used anywhere else than memblockq-test. Also, the
function is confusing, because it defines "missing" differently than
pa_memblockq_pop_missing(). pa_memblockq_missing() calculated the
missing amount like this:
missing = tlength - length,
where "length" is the current queue length. pa_memblockq_pop_missing(),
on the other hand, calculates the missing amount like this:
missing = tlength - length - requested,
where "requested" is an internal variable that keeps track of how much
the server has requested data from the client and how much of the
requests are yet to be fulfilled by the client.
memblockq-test is broken at the moment, because it assumes that
pa_memblockq_pop_missing() calculates "missing" the same way that
pa_memblockq_missing() used to calculate it. A patch for fixing that
will follow.
This reverts commit 74251f0786.
The reverted commit was not intended to make any behavioral changes, but
it broke at least the case where a client writes more data than the
server has requested.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=99211
Current pacat code reads whatever available from STDIN and writes
it directly to the playback stream. A minimal buffer is created
for each read operation; no further reads are then allowed unless
earlier read buffer has been fully consumed by a stream write.
While quite simple, this model breaks upon the new requirements of
writing only frame-aligned data to the stream (commits #1 and #2).
The kernel read syscall can return a length much smaller than the
frame-aligned size requested, leading to invalid unaligned writes.
This can easily be reproduced by choosing a starved STDIN backend:
pacat /dev/random pa_stream_write() failed: EINVAL
echo 1234 | pacat pa_stream_write() failed: EINVAL
or by playing an incomplete WAV file in raw, non-paplay, mode.
So guard against such incomplete kernel reads by writing only in
frame-aligned sizes, while caching any trailing partial frame for
subsequent writes.
Other operation modes are not affected. Non-raw paplay playback is
handled by libsndfile, ensuring complete reads, and recording mode
just writes to the STDOUT fd without any special needs.
CommitReference #1: 22827a5e1e
CommitReference #2: 150ace90f3
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=98475
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=77595
Suggested-by: David Henningsson <diwic@ubuntu.com>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Streams are detached when they are removed or moved away from a device,
or when a filter device that they're connected to is removed or moved.
If these cases overlap, a crash will happen due to "double-detaching".
This can happen if a filter sink is removed, and a stream connected to
that filter sink removes itself when its sink goes away.
Here are the steps in more detail: When a filter sink is unloaded, first
it will unlink its own sink input. This will cause the filter sink's
input to be detached. The filter sink propagates the detachment to all
inputs connected to it using pa_sink_detach_within_thread(). After the
filter sink is done unlinking its own sink input, it will unlink the
sink. This will cause at least module-combine-sink to remove its sink
input if it had one connected to the removed filter sink. When the
combine sink removes its sink input, that input will get detached again,
and a crash follows.
We can relax the assertions a bit, and skip the detach() call if the
sink input is already detached.
I think a better fix would be to unlink the sink before the sink input
when unloading a filter sink - that way we could avoid the
double-detaching - but that would be a much more complicated change. I
decided to go with this simple fix for now.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=98617
The functions that call attach()/detach() for all streams on a sink or
source didn't update the "attached" flag accordingly. Since the flag is
only used in assertions, this omission didn't cause any harm in normal
use.
The "attached" flag is only used for asserting that the stream is in the
expected state when attaching or detaching.
Sometimes the flag was checked and updated before calling the attach or
detach callback, and sometimes after. I think it makes more sense to
always check it before calling the callback.
At the time the "unlink post" hook is fired, the stream is not any more
connected to its old device, so it makes sense to reset the sink/source
pointer to NULL before firing the hook. If this is not done, the pointer
may become stale during the "unlink post" hook, because
module-bluetooth-policy does a card profile change in its "unlink post"
callback, so even if the pointer is valid when module-bluetooth-policy's
callback is called, it will be invalid in subsequent callbacks.
In the "unlink post" hook it's not guaranteed that the stream's old
device exists any more, so let's use the "unlink" hook that is safer.
For example, module-bluetooth-policy does a card profile change in the
source-output "unlink post" hook, which invalidates the source-output's
source pointer.
When the "unlink" hook is fired, the stream is still linked to its
device, which affects the return values of the check_suspend()
functions. The unlinked streams should be ignored by the check_suspend()
functions, so I had to add extra parameters to those functions.
This fixes a crash that happens if the bluetooth headset is the only
non-monitor source in the system and the last "phone" stream dies.
When the stream dies, the native protocol calls pa_source_output_unlink()
and would call pa_source_output_unref() next, but without this patch,
things happen during the unlinking, and the unreffing ends up being
performed on a stream that is already freed.
pa_source_output_unlink() fires the "unlink" hook before doing anything
else. module-bluetooth-policy then switches the headset profile from HSP
to A2DP within that hook. The HSP source gets removed, and at this point
the dying stream is still connected to it, and needs to be rescued.
Rescuing fails, because there are no other sources in the system, so the
stream gets killed. The native protocol has a kill callback, which again
calls pa_source_output_unlink() and pa_source_output_unref(). This is
the point where the native protocol drops its own reference to the
stream, but another unref call is waiting to be executed once we return
from the original unlink call.
I first tried to avoid the double unreffing by making it safe to do
unlinking recursively, but I found out that there's code that assumes
that once unlink() returns, unlinking has actually occurred (a
reasonable assumption), and at least with my implementation this was not
guaranteed. I now think that we must avoid situations where unlinking
happens recursively. It's just too hairy to deal with. This patch moves
the bluetooth profile switch to happen at a time when the dead stream
isn't any more connected to the source, so it doesn't have to be
rescued or killed.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=97906
Bug 96741 shows a case where an assertion is hit, because
pa_asyncq_new() failed due to running out of file descriptors.
pa_asyncq_new() is used in only one place (not counting the call in
asyncq-test): pa_asyncmsgq_new(). Now pa_asyncmsgq_new() can fail too,
which requires error handling in many places. One of those places is
pa_thread_mq_init(), which can now fail too, and that needs additional
error handling in many more places. Luckily there weren't any places
where adding better error handling wouldn't have been easy, so there are
many changes in this patch, but they are not complicated.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96741
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
When unloading a module, lt_dlclose() may remove the module from memory.
If a module unloads itself, it's not safe to call lt_dlclose()
synchronously from pa_module_unload(), because the execution may return
to the module code that was removed from memory. To avoid this
situation, let's postpone lt_dlclose() until it's safe to call it.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96831
The module doesn't build any more[1], and when starting to investigate
the build failure, I asked the module author if he'd know something
about the breakage. He said that he didn't know about backward
compatibility problems with libxen, but more importantly, he said that
the module probably doesn't have any users[2]. It doesn't make sense to
keep maintaining a module that doesn't have users, so let's drop it.
[1] https://bugs.freedesktop.org/show_bug.cgi?id=98793
[2] https://lists.freedesktop.org/archives/pulseaudio-discuss/2016-November/027172.html
SW: Pulseaudio 8.0 / BlueZ 5.39
Symptoms:
While disconnecting/reconnecting a paired bluetooth headset (LG HBS750)
audio fails roughly on every other connection.
On a failed connection "pactl list cards" shows the bluetooth device's
card but "Active Profile: off". Issuing "pacmd set-card-profile X
a2dp_sink" makes audio work immediately.
I realized that when this happened, the previous disconnection did not
remove the card, instead it was only configured for "Active Profile:
off" but otherwise left in place.
Upon looking at PA debug logs I saw that the transport for the a2dp_sink
was first set into disconnected state and then into idle state. In
"device_connection_changed_cb()" this causes the
"pa_bluetooth_device_any_transport_connected()" return true and the
module-bluez5-device is not unloaded.
Further investigation shows that this is caused by a race of
module-bluez5-device.c:thread_func() and
MediaPoint1::ClearConfiguration().
When the FD in thread_func() is closed (POLLHUP) an
BLUETOOTH_MESSAGE_STREAM_FD_HUP message is sent into the main thread.
The handler of this message unconditionally sets the transport into IDLE
state. This is a problem if it has already been set into DISCONNECTED
state.
Executing below command will not produce any audio:
pacat --channels=3 /dev/urandom
Turns out that pa_stream_write() breaks large audio buffers into
segments of the maximum memblock size available -- a value which
is not necessarily frame aligned.
Meanwhile the server discards any non-aligned client audio, as a
security measure, due to some earlier reported daemon crashes.
Thus divide sent audio to the expected aligned form.
CommitReference-1: 22827a5e1e
CommitReference-2: 150ace90f3
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=98475
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=77595
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Users reported pacat crashes when playing certain multi-channel
audio. For example:
pacat --channels=2 /dev/zero works
pacat --channels=3 /dev/zero pa_stream_write() failed: EINVAL
pacat --channels=4 /dev/zero works
pacat --channels=5 /dev/zero pa_stream_write() failed: EINVAL
pacat audio playback is pipe-like, from STDIN to PA write stream.
Meanwhile STDIN "ready to read" events got regularly triggered
before the write stream was even created, or at moments where the
stream could not accept any more audio.
In these out-of-sync cases, the write stream could not report the
appropriate buffer lengths it accepts, thus a default of 4K bytes
was chosen -- compatible by luck with some channel counts and
incompatible with others.
Instead of choosing a faulty default in these scenarios, mute the
the STDIN events until the write stream is available & queriable.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=98475
Reported-by: Tanu Kaskinen <tanuk@iki.fi>
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Although such 9.0 clients support memfd transport, they have an
iochannel bug that would break memfd audio if they're run in 32
bit mode over a 64-bit kernel. Influence them to use the POSIX
shared memory model instead.
Also bump the protocol version to exclusively mark such v9.0
libraries. Check commit 451d1d6762 for further details.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=97769
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Users reported audio breakage for 32-bit pulse clients connected
to a 64-bit server over memfds. Investigating the issue further,
the problem is twofold:
1. iochannel's file-descriptor passing code is liberal in what it
issues: produced ancillary data object's "data" section exceeds
length field. How such an extra space is handled is a grey area
in the POSIX.1g spec, the IETF RFC #2292 "Advanced Sockets API
for IPv6" memo, and the cmsg(3) manpage.
2. A 64-bit kernel handling of such extra space differs by whether
the app is 64-bit or 32-bit. For 64-bit apps, the kernel
smartly ducks the issue. For 32-bit apps, an -EINVAL is
directly returned; that's due to a kernel CMSG header traversal
bug in the networking stack "32-bit sockets emulation layer".
Compare Linux Kernel's socket.h cmsg_nxthdr() code and the
32-bit emulation layer version of it at net/compat.c
cmsg_compat_nxthdr() for further info. Notice how the former
graciously ignores incomplete CMSGs while the latter _directly_
complains about them -- as of kernel version 4.9-rc5.
(A kernel patch is to be submitted)
Details:
iochannel typically uses sendmsg() for passing FDs & credentials.
>From RFC 2292, sendmsg() control data is just a heterogeneous
array of embedded ancillary objects that can differ in length.
Linguistically, a "control message" is an ancillary data object.
For example, below is a sendmsg() "msg_control" containing two
ancillary objects:
|<---------------------- msg_controllen---------------------->|
| |
|<--- ancillary data object -->|<----- ancillary data object->|
|<------- CMSG_SPACE() ------->|<------- CMSG_SPACE() ------->|
| | |
|<-------- cmsg_len ------->| |<-------- cmsg_len ------->| |
|<------- CMSG_LEN() ------>| |<------- CMSG_LEN() ------>| |
| | | | |
+-----+-----+-----+--+------+--+-----+-----+-----+--+------+--+
|cmsg_|cmsg_|cmsg_|XX|cmsg_ |XX|cmsg_|cmsg_|cmsg_|XX|cmsg_ |XX|
|len |level|type |XX|data[]|XX|len |level|type |XX|data[]|XX|
+-----+-----+-----+--+------+--+-----+-----+-----+--+----+-+--+
^^^^^^^ Ancil Object #1 ^^^^^^^ Ancil Object #2
(control message) (control message)
^
|
+--- sendmsg() "msg_control" points here
Problem is, while passing FDs, iochannel's code try to avoid
variable-length arrays by creating a single cmsg object that can
fit as much FDs as possible:
union {
struct cmsghdr hdr;
uint8_t data[CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)];
} cmsg; ^^^^^^^^^^^^^^^^^^
Most of the time though the number of FDs to be passed is less
than the maximum above, thus "cmsg_len" is set to the _actual_ FD
array size:
cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int) * nfd);
^^^
This inconsistency tricks the kernel into thinking that we have 2
ancillay data objects instead of one! First cmsg is valid as
intended, but the second is instantly _corrupt_ since it has a
cmsg_len size of 0 -- thus failing kernel's CMSG_OK() tests.
For 32-bit apps on a 32-bit kernel, and 64-bit apps over a 64-bit
one, the kernel's own CMSG header traversal macros just ignore the
second "incomplete" cmsg. For 32-bit apps over a 64-bit kernel
though, the kernel 32-bit socket emulation macros does not forgive
such incompleteness and directly complains of invalid args (due to
a subtle bug).
Avoid this ugly problem, which can also bite us in a pure 64-bit
environment if MAX_ANCIL_DATA_FDS got extended to 5 FDs, by
setting "cmsg_data[]" array size to "cmsg_len".
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=97769
Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Openssl 1.1.0 made all structs opaque, which caused a build failure in
raop_client.c. The struct member assignments are now replaced with a
call to RSA_set0_key().
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96726
Reviewed-by: Felipe Sateler <fsateler@debian.org>
KTH is a Swedish institution of higher education, and in its full name
spelled Kungliga Tekniska högskolan.
Signed-off-by: Anton Lundin <glance@acc.umu.se>
Bluez5 uses different profile names as bluez4, so we need to check for
a2dp_sink and headset_head_unit too for bluez5 support.
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
module-xenpv-sink.c - In pa__init(...), memory for pa_modargs *ma is not released before returning from function.
Signed-off-by: Deepak Srivastava <srivastava.d@samsung.com>
systemd-hostnamed provides an icon for the machine it is running on.
If it is running, module-zeroconf-publish uses this icon for the
'icon-name' attribute in the Avahi properties. module-zeroconf-discover
passes this icon to module-tunnel using the module parameter
{sink/source}_properties.
This allows to display a portable, desktop or phone instead of
the generic sound card icon.
passing an invalid sample_spec to
pa_sample_size_of_format(),
pa_frame_size(),
pa_bytes_per_second(),
pa_bytes_to_usec(),
pa_usec_to_bytes()
currently gives a result of 0
this is problematic as
(a) it leads to many potential divide-by-zero issues flagged by Coverity,
(b) pa_sample_spec_valid() is called often and the mostly unnecessary validation
of the sample_spec cannot be optimized away due to pa_return_val_if_fail()
(c) nobody checks the result for 0 and the behaviour is not documented
this patch replaces pa_return_val_if_fail() with pa_assert()
note that this commit changes the API!
note that pa_return_val_if_fail() strangely logs an assertion, but then happily
continues...
fixes numerious CIDs
PA_PAGE_SIZE using sysconf() may return a negative number
CID 1137925, CID 1137926, CID 1138485
instead of calling sysconf() directly, add function pa_page_size()
which uses the guestimate 4096 in case sysconf(_SC_PAGE_SIZE) fails
using PA_ONCE to only evaluate sysconf() once
CID 1353122
this is a false-positive because
if (dbus_message_has_interface(p->message, "org.bluez.Manager") ||
dbus_message_has_interface(p->message, "org.bluez.Adapter"))
d = NULL;
else if (!(d = pa_hashmap_get(y->devices, dbus_message_get_path(p->message)))) {
pa_log_warn("Received GetProperties() reply from unknown device: %s (device removed?)",
dbus_message_get_path(p->message));
goto finish2;
}
d can be NULL only if p->message interface is org.bluez.Manager or
org.bluez.Adapter. If
dbus_message_is_method_call(p->message, "org.bluez.Device", "GetProperties")
returns true, we know that the interface is org.bluez.Device.
thanks, Tanu!