From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Cc: Marcel Holtmann <marcel@holtmann.org>,
ChromeOS Bluetooth Upstreaming
<chromeos-bluetooth-upstreaming@chromium.org>,
"linux-bluetooth@vger.kernel.org"
<linux-bluetooth@vger.kernel.org>,
Sonny Sasaka <sonnysasaka@chromium.org>
Subject: Re: [RFC Bluez PATCH 3/3] adapter: Reconnect audio on controller resume
Date: Thu, 6 Aug 2020 10:20:54 -0700 [thread overview]
Message-ID: <CABBYNZKUMnFuJ74CSnWRqF8N08QK9mGjp33B8xVfOyPMdLritA@mail.gmail.com> (raw)
In-Reply-To: <CANFp7mVDnNCFm+sObXMwgAmV=uFAdeam-DM7eNd1rOTKUTf+hQ@mail.gmail.com>
Hi Abhishek,
On Wed, Aug 5, 2020 at 8:48 PM Abhishek Pandit-Subedi
<abhishekpandit@chromium.org> wrote:
>
> Hi Luiz,
>
> On Tue, Aug 4, 2020 at 11:54 AM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
> >
> > Hi Abhishek,
> >
> > On Tue, Jul 28, 2020 at 6:55 PM Abhishek Pandit-Subedi
> > <abhishekpandit@chromium.org> wrote:
> > >
> > > During system suspend, all peer devices are disconnected. On resume, HID
> > > devices will reconnect but audio devices stay disconnected. As a quality
> > > of life improvement, keep track of the last audio device disconnected
> > > during suspend and try to reconnect when the controller resumes from
> > > suspend.
> > >
> > > Reviewed-by: Sonny Sasaka <sonnysasaka@chromium.org>
> > > ---
> > > Hey Luiz,
> > >
> > > On our internal review, two things stood out in this commit that we
> > > weren't able to come to a consensus on internally:
> > >
> > > * Is it better to use the audio device class or should we compare to the
> > > A2DP, HFP and HSP uuids?
> > > * Constructing the dbus message internally before calling dev_connect
> > > looks a bit weird. I couldn't figure out how to internally trigger
> > > this function (since it seems to require a msg to respond to on
> > > success/failure). Any thoughts?
> > >
> > >
> > > src/adapter.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++
> > > src/device.c | 27 +++++++++++++++++
> > > src/device.h | 2 ++
> > > src/main.conf | 6 ++++
> > > 4 files changed, 117 insertions(+)
> > >
> > > diff --git a/src/adapter.c b/src/adapter.c
> > > index 5e896a9f0..b1073c439 100644
> > > --- a/src/adapter.c
> > > +++ b/src/adapter.c
> > > @@ -90,6 +90,7 @@
> > > #define IDLE_DISCOV_TIMEOUT (5)
> > > #define TEMP_DEV_TIMEOUT (3 * 60)
> > > #define BONDING_TIMEOUT (2 * 60)
> > > +#define RECONNECT_AUDIO_DELAY (5)
> > >
> > > #define SCAN_TYPE_BREDR (1 << BDADDR_BREDR)
> > > #define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM))
> > > @@ -269,6 +270,15 @@ struct btd_adapter {
> > > struct btd_device *connect_le; /* LE device waiting to be connected */
> > > sdp_list_t *services; /* Services associated to adapter */
> > >
> > > + /* audio device to reconnect after resuming from suspend */
> > > + struct reconnect_audio_info {
> > > + bdaddr_t addr;
> > > + uint8_t addr_type;
> > > + bool reconnect;
> > > + } reconnect_audio;
> > > + guint reconnect_audio_timeout; /* timeout for reconnect on resume */
> > > + uint32_t reconnect_audio_delay; /* delay reconnect after resume */
> > > +
> > > struct btd_gatt_database *database;
> > > struct btd_adv_manager *adv_manager;
> > >
> > > @@ -6256,6 +6266,7 @@ static void load_config(struct btd_adapter *adapter)
> > > /* Get discoverable mode */
> > > adapter->stored_discoverable = g_key_file_get_boolean(key_file,
> > > "General", "Discoverable", &gerr);
> > > +
> > > if (gerr) {
> > > adapter->stored_discoverable = false;
> > > g_error_free(gerr);
> > > @@ -6271,6 +6282,16 @@ static void load_config(struct btd_adapter *adapter)
> > > gerr = NULL;
> > > }
> > >
> > > + /* Get audio reconnect delay */
> > > + adapter->reconnect_audio_delay = g_key_file_get_integer(
> > > + key_file, "General", "ReconnectAudioDelay", &gerr);
> > > +
> > > + if (gerr) {
> > > + adapter->reconnect_audio_delay = RECONNECT_AUDIO_DELAY;
> > > + g_error_free(gerr);
> > > + gerr = NULL;
> > > + }
> > > +
> > > g_key_file_free(key_file);
> > > }
> > >
> > > @@ -7820,6 +7841,15 @@ static void dev_disconnected(struct btd_adapter *adapter,
> > > if (device) {
> > > adapter_remove_connection(adapter, device, addr->type);
> > > disconnect_notify(device, reason);
> > > +
> > > + if (reason == MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND &&
> > > + device_class_is_audio(device)) {
> > > + adapter->reconnect_audio.reconnect = true;
> > > + adapter->reconnect_audio.addr_type =
> > > + btd_device_get_bdaddr_type(device);
> > > + bacpy(&adapter->reconnect_audio.addr,
> > > + device_get_address(device));
> > > + }
> > > }
> > >
> > > bonding_attempt_complete(adapter, &addr->bdaddr, addr->type,
> > > @@ -8766,6 +8796,53 @@ static void connected_callback(uint16_t index, uint16_t length,
> > > eir_data_free(&eir_data);
> > > }
> > >
> > > +static gboolean reconnect_audio_timeout(gpointer user_data)
> > > +{
> > > + struct btd_adapter *adapter = user_data;
> > > +
> > > + adapter->reconnect_audio_timeout = 0;
> > > +
> > > + if (adapter->reconnect_audio.reconnect) {
> > > + struct btd_device *dev = btd_adapter_find_device(
> > > + adapter, &adapter->reconnect_audio.addr,
> > > + adapter->reconnect_audio.addr_type);
> > > +
> > > + adapter->reconnect_audio.reconnect = false;
> > > +
> > > + if (!dev || btd_device_is_connected(dev))
> > > + return FALSE;
> > > +
> > > + device_internal_connect(dev);
> > > + }
> > > +
> > > + return FALSE;
> > > +}
> > > +
> > > +static void controller_resume_callback(uint16_t index, uint16_t length,
> > > + const void *param, void *user_data)
> > > +{
> > > + const struct mgmt_ev_controller_resume *ev = param;
> > > + struct btd_adapter *adapter = user_data;
> > > +
> > > + if (length < sizeof(*ev)) {
> > > + btd_error(adapter->dev_id, "Too small device resume event");
> > > + return;
> > > + }
> > > +
> > > + DBG("Controller resume with wake event 0x%x", ev->wake_reason);
> > > +
> > > + if (adapter->reconnect_audio_timeout > 0) {
> > > + g_source_remove(adapter->reconnect_audio_timeout);
> > > + adapter->reconnect_audio_timeout = 0;
> > > + }
> > > +
> > > + if (adapter->reconnect_audio.reconnect) {
> > > + adapter->reconnect_audio_timeout =
> > > + g_timeout_add_seconds(adapter->reconnect_audio_delay,
> > > + reconnect_audio_timeout, adapter);
> > > + }
> > > +}
> > > +
> > > static void device_blocked_callback(uint16_t index, uint16_t length,
> > > const void *param, void *user_data)
> > > {
> > > @@ -9389,6 +9466,11 @@ static void read_info_complete(uint8_t status, uint16_t length,
> > > user_passkey_notify_callback,
> > > adapter, NULL);
> > >
> > > + mgmt_register(adapter->mgmt, MGMT_EV_CONTROLLER_RESUME,
> > > + adapter->dev_id,
> > > + controller_resume_callback,
> > > + adapter, NULL);
> > > +
> > > set_dev_class(adapter);
> > >
> > > set_name(adapter, btd_adapter_get_name(adapter));
> > > diff --git a/src/device.c b/src/device.c
> > > index bb8e07e8f..8b165ffa4 100644
> > > --- a/src/device.c
> > > +++ b/src/device.c
> > > @@ -747,6 +747,12 @@ gboolean device_is_trusted(struct btd_device *device)
> > > return device->trusted;
> > > }
> > >
> > > +bool device_class_is_audio(struct btd_device *device)
> > > +{
> > > + /* Look for major service classes Audio (0x20) + Rendering (0x4) */
> > > + return ((device->class >> 16) & 0x24) == 0x24;
> > > +}
> > > +
> > > static gboolean dev_property_get_address(const GDBusPropertyTable *property,
> > > DBusMessageIter *iter, void *data)
> > > {
> > > @@ -6853,6 +6859,27 @@ struct btd_service *btd_device_get_service(struct btd_device *dev,
> > > return NULL;
> > > }
> > >
> > > +/* Internal function to connect to a device. This fakes the dbus message used to
> > > + * call the "Connect" api on the device so that the same function can be called
> > > + * by bluez internally.
> > > + */
> > > +bool device_internal_connect(struct btd_device *dev)
> > > +{
> > > + DBusMessage *msg;
> > > +
> > > + if (!device_is_connectable(dev))
> > > + return false;
> > > +
> > > + msg = dbus_message_new_method_call("org.bluez",
> > > + device_get_path(dev),
> > > + DEVICE_INTERFACE,
> > > + "Connect");
> > > + /* Sending the message usually sets serial. Fake it here. */
> > > + dbus_message_set_serial(msg, 1);
> > > +
> > > + dev_connect(dbus_conn, msg, dev);
> > > +}
> > > +
> > > void btd_device_init(void)
> > > {
> > > dbus_conn = btd_get_dbus_connection();
> > > diff --git a/src/device.h b/src/device.h
> > > index 956fec1ae..82f97b5bd 100644
> > > --- a/src/device.h
> > > +++ b/src/device.h
> > > @@ -98,6 +98,7 @@ bool device_is_connectable(struct btd_device *device);
> > > bool device_is_paired(struct btd_device *device, uint8_t bdaddr_type);
> > > bool device_is_bonded(struct btd_device *device, uint8_t bdaddr_type);
> > > gboolean device_is_trusted(struct btd_device *device);
> > > +bool device_class_is_audio(struct btd_device *device);
> > > void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type);
> > > void device_set_unpaired(struct btd_device *dev, uint8_t bdaddr_type);
> > > void btd_device_set_temporary(struct btd_device *device, bool temporary);
> > > @@ -186,6 +187,7 @@ int btd_device_connect_services(struct btd_device *dev, GSList *services);
> > > uint32_t btd_device_get_current_flags(struct btd_device *dev);
> > > void btd_device_flags_changed(struct btd_device *dev, uint32_t supported_flags,
> > > uint32_t current_flags);
> > > +bool device_internal_connect(struct btd_device *dev);
> > >
> > > void btd_device_init(void);
> > > void btd_device_cleanup(void);
> > > diff --git a/src/main.conf b/src/main.conf
> > > index f41203b96..c6bb78a84 100644
> > > --- a/src/main.conf
> > > +++ b/src/main.conf
> > > @@ -82,6 +82,12 @@
> > > # 0 = disable timer, i.e. never keep temporary devices
> > > #TemporaryTimeout = 30
> > >
> > > +# How long to wait after controller resume before reconnecting to last used
> > > +# audio device.
> > > +# The value is in seconds.
> > > +# Default: 5
> > > +#ReconnectAudioDelay = 5
> > > +
> > > [Controller]
> > > # The following values are used to load default adapter parameters. BlueZ loads
> > > # the values into the kernel before the adapter is powered if the kernel
> > > --
> > > 2.28.0.rc0.142.g3c755180ce-goog
> >
> > Usually connection policy is handled by the policy plugin since there
> > may be platforms that want implement their own connection policies on
> > top of bluetoothd so they can just disable the policy plugin, iirc we
> > do have reconnection policies for unexpected disconnect which should
> > probably be used in the event a suspend actually trigger a
> > disconnection see:
> >
> > https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/plugins/policy.c#n761
> >
> > We might need a reason code to indicate to the policy when a
> > disconnect happens due to suspend logic.
>
> I am emitting a new reason code for disconnect (local disconnect due
> to suspend, 0x5). If this is just passing through the reason from the
> mgmt event, I can continue using that.
Yep.
> Will update this patch to use the policy plugin and send up another revision.
I'd use a switch to catch all reasons that should trigger a reconnection.
> Thanks
> Abhishek
>
> >
> > --
> > Luiz Augusto von Dentz
--
Luiz Augusto von Dentz
next prev parent reply other threads:[~2020-08-06 17:21 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-29 1:55 [RFC Bluez PATCH 0/3] adapter: Reconnect audio when resuming from suspend Abhishek Pandit-Subedi
2020-07-29 1:55 ` [RFC Bluez PATCH 1/3] mgmt: Add controller suspend and resume events Abhishek Pandit-Subedi
2020-07-29 1:55 ` [RFC Bluez PATCH 2/3] monitor: Add btmon support for Suspend and Resume events Abhishek Pandit-Subedi
2020-07-29 1:55 ` [RFC Bluez PATCH 3/3] adapter: Reconnect audio on controller resume Abhishek Pandit-Subedi
2020-08-04 18:54 ` Luiz Augusto von Dentz
2020-08-06 3:48 ` Abhishek Pandit-Subedi
2020-08-06 17:20 ` Luiz Augusto von Dentz [this message]
2020-08-04 17:12 ` [RFC Bluez PATCH 0/3] adapter: Reconnect audio when resuming from suspend Abhishek Pandit-Subedi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CABBYNZKUMnFuJ74CSnWRqF8N08QK9mGjp33B8xVfOyPMdLritA@mail.gmail.com \
--to=luiz.dentz@gmail.com \
--cc=abhishekpandit@chromium.org \
--cc=chromeos-bluetooth-upstreaming@chromium.org \
--cc=linux-bluetooth@vger.kernel.org \
--cc=marcel@holtmann.org \
--cc=sonnysasaka@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).