As pointed out by Tanu, checking both error conditions is redundant and
raises the question whether it's possible that one of the conditions is
true while the other is false.
Therefore, simplify the condition by just checking one part of the
disjunction.
The function was used to check whether the basic properties of the
Bluetooth device have been received. This can be simplified by just
checking d->device_info_valid, since the state of the audio interface
is only relevant inside pa_bluetooth_device_any_audio_connected(), which
is used to trigger the discovery callback.
While checking device_info_valid, special care must be taken with all
three possible values: when set to -1, it means some error was triggered
while getting the device properties. Therefore, these devices can also
be ignored outside bluetooth-util.
Besides that, the patch slightly modifies the behavior of the internal
API affecting pa_bluetooth_discovery_get_by_address() and
pa_bluetooth_discovery_get_by_path(), since they will return the device
no matter the state of the audio interface. This however makes sense and
should have no influence in the current codebase given that the modules
make use of devices only after the discovery hook has been triggered.
The function is used to make sure some basic information has already
been gathered before the device is being used. At this point profile
states can be ignored, since their initial value will be
PA_BT_AUDIO_STATE_INVALID and thus effectively similar to
PA_BT_AUDIO_STATE_DISCONNECTED due to audio_state_to_transport_state().
The change should make no difference given that the behavior of
pa_bluetooth_device_any_audio_connected() doesn't change: by the time
TRUE is returned, a transport needs to exist. This means a profile
will exist in CONNECTING or CONNECTED state and thus the old
implementation of device_audio_is_ready() would also have returned TRUE.
Trivially fix some style issues affecting line wrap (128 chars max with
the exception of multi-line comments, which are limited to 80),
indentation and unnecessary parentheses.
pa_bluetooth_discovery_sync() waited until all pending method calls
had completed. I don't understand what the benefit of that could be,
so I removed the function. We should avoid blocking as much as
possible, and the code that used pa_bluetooth_discovery_sync() didn't
look like it really needed to wait for anything.
In addition to moving the freeing a bit later, unnecessary checks for
t->device are removed. t->device is initialized to a non-NULL value
when the transport is created, and it's never changed.
The transport state also reflects the state of the audio interface. The
state redundancy can thus be minimized by always using the first one,
and avoiding the use of profile-specific states with the exception of
finding out the initial state of a transport.
The state of this interface is needed for one single reason: we need to
wait until all profiles have been connected (or more precisely, until
are connection attempts are finished). This can be made more explicit in
the code by just checking the CONNECTING state (and not loading
module-bluetooth-device during that state), but otherwise treating all
transport types equally.
Ideally, audio_state should be completely removed but it's left there to
avoid an issue with module-card-restore, as documented in the source
code's comments.
Transports can be acquired with different access rights, but in practice
"rw" was always used inside module-bluetooth-device. In addition, this
feature is removed in BlueZ 5.0 and therefore it is convenient to
abstract all this inside bluetooth-util.
Use transport state to calculate the corresponding port availability,
and while doing so use bluetooth-util to receive profile state updates
instead of directly parsing D-Bus PropertyChanged signals.
Move the function to the utility library where the enum is defined. At
same time avoid using the default clause in order to make sure the
compiler will complain if the enum type gets extended.
Similarly to the microphone gain, the speaker gain can be abstracted
inside the transport object, even though the actual D-Bus interface in
BlueZ differs.
The microphone gain represents the volume of the incoming audio stream
from the headset. This can be nicely abstracted inside the transport
object in bluetooth-util, so the modules don't have to take care about
the D-Bus details.
Add the transport-handling hooks to the centralized list of hooks in
pa_bluetooth_hook_t. These are intended to replace the now deprecated
transport-specific hook list in pa_bluetooth_transport_hook_t.
Transport objects have an associated state even though it's not
explicitly exposed in BlueZ's D-Bus API (prior to 5.0). Instead, the
state is implicitly represented in the profile-specific D-Bus interface
(i.e. org.bluez.Headset, org.bluez.AudioSink, etc.) but it can be
convenient that bluetooth-util would abstract this separation.
The old implementation is limited to parsing the profile state, but
the D-Bus API actually exposes many more properties that are currently
not being considered, specially within org.bluez.Headset.
Centralize the Bluetooth hooks in one single place, starting with
the device hooks, while removing the duplicated ones (in this case
PA_BLUETOOTH_DEVICE_HOOK_REMOVED).
Devices will have zero or one transports per profile, and besides the
typical lookup is also profile-based. Therefore, replace the old hashmap
(which used the transport path as key) with a simple array which holds
a transport pointer per profile.
Path-based transport lookups are required in a discovery basis, before
the associated device is known. Therefore, it makes more sense to
maintain a hashmap in the discovery structure itself, instead of
iterating all devices.
Transports always have an associated device, so add the pointer as a
member to the structure, and remove the discovery pointer since it
already exists in the device object.
d->hfgw_state is just another profile that should be considered exactly
as the rest inside device_audio_is_ready(), which is being used to
decide if the discovery hook gets triggered.
Therefore, there seems to be no reason to make an exception for this
profile and skip checking if the condition d->audio_state !=
PA_BT_AUDIO_STATE_INVALID holds true.
This change makes no practical difference but delaying the load of the
module also for HFGW until Audio.State is received. The benefit is
that the behavior and the code are more consistent across profiles.
With BlueZ 5 it is possible to have profile registered by a third party
process which does not share the same bus id as bluetoothd so it is
necessary to store the sender of the transport to be able to talk to it.
Note that this is backward compatible.
This is a minor optimization too, but the main benefit is that it's
makes the code easier to understand (I hope), since run_callback()
won't be called at times when it's not needed.
The new helper function makes it easier to check whether any audio
profiles are connected. That information is needed by the discovery
module for deciding whether a new device module should be loaded. The
device module should use this information too to unload itself at the
right time, but that's currently not implemented.
Use a more accurate name for the function since it doesn't just check
if it is an audio device (which can be detected quite early), but it
also checks if the most relevant properties (device info, etc.) have
been received.
Besides, add the const qualifier to the pointer since it's not going to
be modified.
The Device.Connected was only used for tracking whether a device module
should be loaded, but that information is already included in the
individual profile state properties. The property can therefore be
completely ignored without any loss in functionality.
UUIDs might be announced at any time, so a hook is needed to notify any
interested module. In practice, the UUIDs are quite stable with the
exception of the pairing procedure, where the UUIDs are reported by
BlueZ as soon as they are discovered.
The internal API in bluetooth-util should not use the const qualifier
for operations involving a device object. After all, the structure
contains many pointers and thus the const qualifier provides no real
protection.
The internal API in bluetooth-util should not use the const qualifier
for operations modifying the transport object. This is specially useful
in order to use the available hooks.
Handling the signal DisconnectRequested should be unnecessary since the
profile-specific interfaces will be later disconnected, leading to
module unload.
Additionally, the signal is problematic: if an interface (i.e.
A2DP AudioSource) is playing at the time DisconnectRequested is
signaled, the following sequence can occur:
1. AudioSource is playing
2. DisconnectRequested is received
3. Module is unloaded due to DisconnectRequested
4. AudioSource state changes from playing to connected
5. module-bluetooth-discover loads the module
6. AudioSource state changes from connected to disconnected
Therefore the module is unnecessarily loaded, to be unloaded immediately
afterwards. This can easily be reproduced if a device is unpaired while
the audio is streaming.
The simplest solution to this consists of removing step 3, by just
ignoring the DisconnectRequested signal. This reverts commit
8169a6a6c9.
If the acquisition of the transport fails, the profile should still be
set. In this case the audio is not actually streaming, so the sink and
source will be created but left suspended.
If the transport needs to be acquired later, for example because the
user wants to route the audio the remote device, the suspend flag should
have to be changed.
The return value of dbus_message_iter_next() doesn't need to be checked
since the while condition will be false anyway (arg type will be
DBUS_TYPE_INVALID).
The method ListDevices() in org.bluez.Adapter was deprecated in BlueZ
4.61, and is going to be removed in future releases. Instead, a property
was introduced for this purpose in BlueZ 4.7.