When a phone is connected via bluetooth and switches to HFP, the sinks
and sources will have higher priority than the built-in devices.
Therefore they are chosen as default and module-bluetooth-policy will
incorrectly insert loopback modules that loop the phone back to itself.
This patch fixes the problem by lowering the priority of sink and source
if PulseAudio is in the headset role. The priority is also lowered if the
device is an a2dp source. In both cases it does not make sense to make the
source or sink default unless there is no other sound device available.
This reverts commit 69c212f8c1.
Reasons:
The original reason for the patch was to work around some issue
regarding the profile not connecting immediately (sorry, I don't really
know the details), but that issue was fixed later by commit 998dfdf4cc,
so the original reason doesn't apply any more.
Automatically changing the profile when the transport state changes to
PLAYING has traditionally been handled by module-bluetooth-policy, and
as far as I can tell, there's no reason to change that.
The assertion is unsafe. It's not guaranteed that the profile change
will always succeed (at least pa_thread_mq_init() can fail due to
reaching the maximum file descriptor limit).
When the ofono backend released a tranport during suspend of sink or source, the
transport state was not changed to IDLE. Therefore pa_bluetooth_transport_set_state()
would return immediately when trying to resume. Even though the transport was acquired
correctly, setup_stream() would never be called and the resume failed.
This patch sets the transport state to IDLE when the transport is released. On resume,
the first call to transport_acquire() will be done from the message handler of the
*_SET_STATE message when source or sink are set to RUNNING. This call will only request
the setup of the connection, so setup_stream() cannot be called.
When the transport changes the state to PLAYING in hf_audio_agent_new_connection(),
handle_transport_state_change() is called. Because the sink or source state is already
RUNNING, the pa_{source,sink}_suspend() call will not lead to a state change message
and the I/O thread must be signaled explicitely to setup the stream.
The first setup of the device would also fail, which was only visible when the profile
was restored after connecting the headset. When trying to restore the headset_head_unit
profile, the profile was shortly set to off, so the headset always returned to a2dp.
This patch allows a delayed setup for the headset_head_unit profile, so that the profile
can successfully be restored.
When suspending due to idle timeout the transport will not change its
state, also in case the fd is closed due to POLLERR/POLLHUP events
the release shall check if the fd is still set otherwise it will fail
to be acquired again.
This means something went wrong, which in case of ofono backend it is
probably due to the profile not connecting immediately, but it can be
safely restored in that case the transport is playing which means the
profile has recovered connectivity.
If a HFP audio gateway was connected via the ofono backend, pulse would
segfault during shutdown of the daemon. pa_bluetooth_discovery_unref()
removed the devices and transports before the ofono backend was freed.
Because the ofono backend keeps its own list of transports, transport_free()
was then called during termination of the ofono backend with an invalid
transport. Bug reported by Andrew Hlynskyi.
This patch moves the termination of the ofono and native backends before
freeing the devices.
The reported latency of source or sink is based on measured initial conditions.
If the conditions contain an error, the estimated latency values may become negative.
This does not indicate that the latency is indeed negative but can be considered
merely an offset error. The current get_latency_in_thread() calls and the
implementations of the PA_{SINK,SOURCE}_MESSAGE_GET_LATENCY messages truncate negative
latencies because they do not make sense from a physical point of view. In fact,
the values are truncated twice, once in the message handler and a second time in
the pa_{source,sink}_get_latency_within_thread() call itself.
This leads to two problems for the latency controller within module-loopback:
- Truncating leads to discontinuities in the latency reports which then trigger
unwanted end to end latency corrections.
- If a large negative port latency offsets is set, the reported latency is always 0,
making it impossible to control the end to end latency at all.
This patch is a pre-condition for solving these problems.
It adds a new flag to pa_{sink,source}_get_latency_within_thread() to allow
negative return values. Truncating is also removed in all implementations of the
PA_{SINK,SOURCE}_MESSAGE_GET_LATENCY message handlers. The allow_negative flag
is set to false for all calls of pa_{sink,source}_get_latency_within_thread()
except when used within PA_{SINK,SOURCE}_MESSAGE_GET_LATENCY. This means that the
original behavior is not altered in most cases. Only if a positive latency offset
is set and the message returns a negative value, the reported latency is smaller
because the values are not truncated twice.
Additionally let PA_SOURCE_MESSAGE_GET_LATENCY return -pa_sink_get_latency_within_thread()
for monitor sources because the source gets the data before it is played.
Users may configure the device alias to have characters outside the
ASCII range, so our name cleanup routine was too aggressive. Let's just
make sure that the device description is a valid UTF-8 string.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=98160
The function can only fail if there's not enough memory available, and
if that happens, the convention in PulseAudio is to abort.
CID: 1353106, 1353108, 1353140
There were two bugs in the old logic. The first one:
If a device has two profiles, the old code would start the wait timer
when the first profile connects, but when the second profile connects,
the timer would not get stopped and the CONNECTION_CHANGED hook would
not get fired, because the code for that was inside an if block that
only gets executed when the first profile connects. As a result,
module-bluez5-device loading would always be delayed until the wait
timeout expires.
The second bug:
A crash was observed in device_start_waiting_for_profiles(). That
function is called whenever the connected profile count changes from 0
to 1. The function also has an assertion that checks that the timer is
not running when the function is called. That assertion crashed in the
following scenario with a headset that supports HSP and A2DP:
1. First HSP gets connected. The timer is started.
2. Then HSP gets disconnected for some reason. The timer is still
running.
3. Then A2DP gets connected. device_start_waiting_for_profiles() is
called, because the connected profile count changed from 0 to 1 again.
The timer is already running, so the assertion fails.
First I thought I'd remove the assertion from
device_start_waiting_for_profiles() and just restart the timer on the
second call, but then I figured that when the device returns to the
"everything disconnected" state in step 2, it would be better to stop
the timer. The purpose of the timer is to delay the notification of the
device becoming connected, but if the device becomes disconnected during
the waiting period, the notification doesn't make sense any more, and
therefore the timer doesn't make sense either.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=100237
The auto_switch argument was added in PulseAudio 10.0. In that release
the argument type was boolean. The type was changed to integer in commit
3397127f00. This patch adds backwards compatibility so that old
configuration files won't break when upgrading PulseAudio to 11.0.
With headset=auto it is possible that AG devices are connected and handled
via the native backend when ofono is started. Because the HS role will then
be disabled in the native backend, AG devices must be disconnected and any
future connections will be handled by ofono.
This patch changes the behavior of the headset=auto switch for module-bluez5-discover.
With headset=auto now both backends will be active at the same time for the AG role and
the switching between the backends is only done for the HS role.
headset=ofono and headset=native remain unchanged.
This allows to use old HSP only headsets while running ofono and to have headset support
via pulseaudio if ofono is started with the --noplugin=hfp_ag_bluez5 option.
This is a rebase of Wim Taymans patch to support the HSP headset role that has
somehow been forgotten. Original patch can be found at
https://lists.freedesktop.org/archives/pulseaudio-discuss/2015-February/023242.html
Rebase and minor changes by Georg Chini.
In addition to the HSP Audio Gateway, also add support for the headset
role in the native bluetooth backend. In this role, pulseaudio is used as
headset.
In the headset role, we create source and sink to receive and send the samples
from the gateway, respectively. Module-bluetooth-policy will automatically load
loopback modules to link these to a sink and source for playback. Because this
makes the source the speaker and the sink the microphone, we need to reverse the
roles of source and sink compared to the gateway role.
In the gateway role, adjusting the sink volume generates a +VGS command to set
the volume on the headset. Likewise, receiving AT+VGS updates the sink volume.
In the headset role, receiving a +VGS should set the source volume and any
source volume changes should be reported back to the gateway with AT+VGS.
A recent patch changed the MTU size from the default value of 48 to the value
returned by getsockopt(). This breaks HSP for some setups. To circumvent the
problem, this patch introduces a boolean parameter "autodetect_mtu" for
module-bluetooth-discover, module-bluez5-discover and module-bluez5-device to
make this use of getsockopt() configurable.
Issue: When HFP/HSP profile is used with certain BT chipsets, the
audio sounds heavily distorted, with very slow playback full of noise.
During recording, the samples are dropped and it distorts the recorded
audio samples.
The root cause of both the issues are related to the fixed MTU sizes
in the PA stack, which is 48 bytes. Here, the BT chipset CC256x had
180 bytes MTU and it was being under-utilized and the rate at which
the samples were being accepted where not matching the expected rate,
and hence the distortion.
Solution: The appropriate solution to this problem is by reading the
MTU size of the SCO socket using getsockopts dynamically.
BugLink: http://bit.ly/2gDpGPv
BugLink: http://bit.ly/2hQsARK
Not all VOIP applications (specially those which use alsa) set media.role to
phone. This means we need some heuristic to determinate if we want to switch
from a2dp to hsp profile based on number and types of source output (recording)
streams.
And also some people want to use their bluetooth headset (with microphone) as
their default recording device but some do not want to because of low quality.
This patch implements optional heuristic which is disabled by default. It is
disabled by default to not break experience of current pulseaudio users because
heuristic cannot be optimal. Heuristic is implemented in module-bluetooth-policy
module and decide if pulseaudio should switch to a hsp profile or not. It checks
if there is some source output with pass all these conditions:
* does not have set media.role
* does not use peak resample method (which is used by desktop volume programs)
* has assigned client/application (non virtual stream)
* does not record from monitor of sink
And if yes it switch to hsp profile.
By default this heuristic is disabled and can be enabled when loading module
module-bluetooth-policy with specifying parameter auto_switch=2
Because it is disabled by default nobody will be affected by this change unless
manually change auto_switch parameter.
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
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
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.
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>
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!
create_card_profile() used to get called separately for HSP and HFP,
so if a headset supports both profiles, a profile named
"headset_head_unit" would get created twice. The second instance would
get immediately freed, so that wasn't a particularly serious problem.
However, I think it makes more sense to create the profile only once.
This patch makes things so that before a profile is created, we check
what name that profile would have, and if a profile with that name
already exists, we don't create the profile.
A couple of Yocto releases (jethro and krogoth) have non-upstream
patches that suffer from this double creation. The patches add
associations between profiles and ports, and those associations use
the profile name as the key. When the second profile gets freed, the
associations between the profile and its ports get removed, and since
the profile name is used as the key, this erroneously affects the
first profile too. Crashing ensues.
BugLink: https://bugzilla.yoctoproject.org/show_bug.cgi?id=10018
Add transport_set_state() that encapsulates changing the variable,
logging and firing the change hook.
I also made a cosmetic change to the corresponding BlueZ 5 log
message so that both messages have the format that I like.
A hashmap is more convenient than a linked list for storing the UUIDs,
so change the BlueZ 4 code accordingly.
Rename the BlueZ 4 UUID constants to match the BlueZ 5 naming.
The only changes to the BlueZ 5 code are the addition of one comment
and making another comment a bit clearer.
The properties_received flag affects whether the device should be
considered valid, so let's update the valid flag after setting the
properties_received flag.
There's a call to device_update_valid() anyway later when setting
the device adapters, so this change isn't strictly necessary, but
this makes it more obvious that the code is correct (and less
fragile).
The CONNECTION_CHANGED hook is used to notify the discovery module
about new and removed devices. When a bluetooth device connects, the
hook used to be called immediately when the first profile connected.
That meant that only one profile was marked as available during the
card creation, other profiles would get marked as available later.
That makes it hard for module-card-restore to restore the saved
profile, if the saved profile becomes available with some delay.
module-card-restore has a workaround for this problem, but that turned
out to interfere with module-bluetooth-policy, so the workaround will
be removed in the next patch.
The BlueZ 4 code doesn't need changes, because we use the
org.bluez.Audio interface to get a notification when all profiles are
connected.
With this patch module-bluetooth-policy automatically switch from a2dp profile
to hsp profile if some VOIP application with media.role=phone wants to start
recording audio.
By default a2dp profile is used for listening music, but for VOIP calls is
needed profile with microphone support (hsp). So this patch will switch to
hsp profile if some application want to use microphone (and specify it in
media.role as "phone). After recording is stopped profile is switched back
to a2dp. So this patch allows to use bluetooth microphone for VOIP applications
with media.role=phone automatically without need of user interaction.
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
I want module-alsa-card to set the availability of unavailable
profiles before the initial card profile gets selected, so that the
selection logic can use correct availability information.
module-alsa-card initializes the jack state after calling
pa_card_new(), however, and the profile selection happens in
pa_card_new(). This patch solves that by moving parts of pa_card_new()
to pa_card_choose_initial_profile() and pa_card_put().
pa_card_choose_initial_profile() applies the profile selection policy,
so module-alsa-card can first call pa_card_new(), then initialize the
jack state, and then call pa_card_choose_initial_profile(). After that
module-alsa-card can still override the profile selection policy, in
case module-alsa-card was loaded with the "profile" argument. Finally,
pa_card_put() finalizes the card creation.
An alternative solution would have been to move the jack
initialization to happen before pa_card_new() and use pa_card_new_data
instead of pa_card in the jack initialization code, but I disliked
that idea (I want to get rid of the "new data" pattern eventually).
The order in which the initial profile policy is applied is reversed
in this patch. Previously the first one to set it won, now the last
one to set it wins. I think this is better, because if you have N
parties that want to set the profile, we avoid checking N times
whether someone else has already set the profile.
If 'pa_modargs_new' returns a NULL, we need to be careful to not call
'pa_modargs_free' in the failure path since it requires that we pass it
a non-null argument. Also updates 'module-bluetooth-policy.c:pa__init'
to follow the standard "goto fail" pattern used everywhere else.
Signed-off-by: Jason Gerecke <killertofu@gmail.com>
pa_module_unload() takes two pointers: pa_module and pa_core.
The pa_core pointer is also available via the pa_module object,
so the pa_core argument is redundant
[David Henningsson: Rebased to git HEAD]
Flushing the asyncmsgq can cause arbitrarily callbacks to run, potentially
causing recursion into pa_thread_mq_done again. Because of this; rtpoll which
is cleared in the second iteration is tried to free once again by the first
iteration leading to PA crash.