pmaports/temp/pulseaudio/0004-bluetooth-hook-up-UPower-backend.patch
Dylan Van Assche f9c7ffa9b6
temp/pulseaudio: fork for Bluetooth HFP/HSP support (MR 3080)
PulseAudio is used for handling all audio on postmarketOS.
This also involves Bluetooth audio such as A2DP, HSP and HFP audio.
In the case of HFP/HSP, the HF and AG can interact with each other
through AT commands defined in the Bluetooth HFP 1.8 spec.

This set of patches implements HFP support to allow Bluetooth devices
to accept/reject/hangup calls, dial numbers, DTMF tone generation,
query signal strength, roaming status, service status, AG battery level,
call status, etc.

More details in the upstream MR:
https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/693

Available in edge for testing this merge request with a broader user
base. Not intended for backporting to stable branches.

[ci:skip-build]: already built successfully in CI
2022-06-16 09:33:35 +02:00

197 lines
8.4 KiB
Diff

From 78e255eefb417275e73f8ed96ce08bf7c3a1dff9 Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Tue, 5 Apr 2022 20:39:11 +0200
Subject: [PATCH 04/26] bluetooth: hook up UPower backend
Hook up the UPower backend to backend-native to report
the host battery level to the HF.
---
src/modules/bluetooth/backend-native.c | 100 +++++++++++++++++++++++--
src/modules/bluetooth/bluez5-util.h | 2 +
2 files changed, 95 insertions(+), 7 deletions(-)
diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c
index d26edc1c9..a490d6efd 100644
--- a/src/modules/bluetooth/backend-native.c
+++ b/src/modules/bluetooth/backend-native.c
@@ -38,6 +38,7 @@
#include "bluez5-util.h"
#include "bt-codec-msbc.h"
+#include "upower.h"
#define MANDATORY_CALL_INDICATORS \
"(\"call\",(0-1))," \
@@ -49,6 +50,8 @@ struct pa_bluetooth_backend {
pa_dbus_connection *connection;
pa_bluetooth_discovery *discovery;
pa_hook_slot *adapter_uuids_changed_slot;
+ pa_hook_slot *host_battery_level_changed_slot;
+ pa_upower_backend *upower;
bool enable_shared_profiles;
bool enable_hsp_hs;
bool enable_hfp_hf;
@@ -683,17 +686,27 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf
return true;
} else if (c->state == 1 && pa_startswith(buf, "AT+CIND=?")) {
- /* we declare minimal no indicators */
- rfcomm_write_response(fd, "+CIND: "
- /* many indicators can be supported, only call and
- * callheld are mandatory, so that's all we reply */
- MANDATORY_CALL_INDICATORS ",",
- "(\"service\",(0-1))");
+ /* UPower backend available, declare support for more indicators */
+ if (discovery->native_backend->upower) {
+ rfcomm_write_response(fd, "+CIND: "
+ MANDATORY_CALL_INDICATORS ","
+ "(\"service\",(0-1)),"
+ "(\"battchg\",(0-5))");
+
+ /* Minimal indicators supported without any additional backend */
+ } else {
+ rfcomm_write_response(fd, "+CIND: "
+ MANDATORY_CALL_INDICATORS ","
+ "(\"service\",(0-1))");
+ }
c->state = 2;
return true;
} else if (c->state == 2 && pa_startswith(buf, "AT+CIND?")) {
- rfcomm_write_response(fd, "+CIND: 0,0,0,0");
+ if (discovery->native_backend->upower)
+ rfcomm_write_response(fd, "+CIND: 0,0,0,0,%u", pa_upower_get_battery_level(discovery->native_backend->upower));
+ else
+ rfcomm_write_response(fd, "+CIND: 0,0,0,0");
c->state = 3;
return true;
@@ -803,6 +816,67 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf
return true;
}
+static int get_rfcomm_fd (pa_bluetooth_discovery *discovery) {
+ struct pa_bluetooth_transport *t;
+ struct transport_data *trd = NULL;
+ pa_bluetooth_profile_t profiles[] = { PA_BLUETOOTH_PROFILE_HSP_HS, PA_BLUETOOTH_PROFILE_HSP_AG, PA_BLUETOOTH_PROFILE_HFP_HF };
+ int i;
+ bool found_transport = false;
+ void *state = NULL;
+
+ /* Find RFCOMM transport by checking if a HSP or HFP profile transport is available */
+ while ((t = pa_hashmap_iterate(discovery->transports, &state, NULL))) {
+ /* Skip non-connected transports */
+ if (!t || t->state == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED) {
+ pa_log_debug("Profile %d disconnected or unavailable", i);
+ continue;
+ }
+
+ /* Break when an RFCOMM capable transport profile is available */
+ for (i = 0; i < (sizeof profiles / sizeof *profiles); i++) {
+ if (t->profile == profiles[i]) {
+ trd = t->userdata;
+ found_transport = true;
+ break;
+ }
+ }
+
+ if (found_transport)
+ break;
+ }
+
+ /* Skip if RFCOMM channel is not available yet */
+ if (!trd) {
+ pa_log_info("RFCOMM not available yet, skipping notification");
+ return -1;
+ }
+
+ return trd->rfcomm_fd;
+}
+
+static pa_hook_result_t host_battery_level_changed_cb(pa_bluetooth_discovery *y, const pa_upower_backend *u, pa_bluetooth_backend *b) {
+ int rfcomm_fd;
+
+ pa_assert(y);
+ pa_assert(u);
+ pa_assert(b);
+
+ /* Get RFCOMM channel if available */
+ rfcomm_fd = get_rfcomm_fd (y);
+ if (rfcomm_fd < 0)
+ return PA_HOOK_OK;
+
+ /* Notify HF about AG battery level change over RFCOMM */
+ if (b->cmer_indicator_reporting_enabled && (b->cind_enabled_indicators & (1 << CIND_BATT_CHG_INDICATOR))) {
+ rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_BATT_CHG_INDICATOR, u->battery_level);
+ pa_log_debug("HG notified of AG's battery level change");
+ /* Skip notification if indicator is disabled or event reporting is completely disabled */
+ } else
+ pa_log_debug("Battery level change indicator disabled, skipping notification");
+
+ return PA_HOOK_OK;
+}
+
static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
pa_bluetooth_transport *t = userdata;
pa_bluetooth_discovery *discovery = t->device->discovery;
@@ -1284,6 +1358,10 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d
pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_ADAPTER_UUIDS_CHANGED), PA_HOOK_NORMAL,
(pa_hook_cb_t) adapter_uuids_changed_cb, backend);
+ backend->host_battery_level_changed_slot =
+ pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED), PA_HOOK_NORMAL,
+ (pa_hook_cb_t) host_battery_level_changed_cb, backend);
+
if (!backend->enable_hsp_hs && !backend->enable_hfp_hf)
pa_log_warn("Both HSP HS and HFP HF bluetooth profiles disabled in native backend. Native backend will not register for headset connections.");
@@ -1293,6 +1371,8 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d
if (backend->enable_shared_profiles)
native_backend_apply_profile_registration_change(backend, true);
+ backend->upower = pa_upower_backend_new(c, y);
+
/* All CIND indicators are enabled by default until overriden by AT+BIA */
for (i = 1; i < CIND_INDICATOR_MAX; i++)
backend->cind_enabled_indicators |= (1 << i);
@@ -1312,12 +1392,18 @@ void pa_bluetooth_native_backend_free(pa_bluetooth_backend *backend) {
if (backend->adapter_uuids_changed_slot)
pa_hook_slot_free(backend->adapter_uuids_changed_slot);
+ if (backend->host_battery_level_changed_slot)
+ pa_hook_slot_free(backend->host_battery_level_changed_slot);
+
if (backend->enable_shared_profiles)
native_backend_apply_profile_registration_change(backend, false);
if (backend->enable_hsp_hs)
profile_done(backend, PA_BLUETOOTH_PROFILE_HSP_HS);
+ if (backend->upower)
+ pa_upower_backend_free(backend->upower);
+
pa_dbus_connection_unref(backend->connection);
pa_xfree(backend);
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
index f899d9d0c..a24a0b823 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -63,12 +63,14 @@ typedef struct pa_bluetooth_device pa_bluetooth_device;
typedef struct pa_bluetooth_adapter pa_bluetooth_adapter;
typedef struct pa_bluetooth_discovery pa_bluetooth_discovery;
typedef struct pa_bluetooth_backend pa_bluetooth_backend;
+typedef struct pa_upower_backend pa_upower_backend;
typedef enum pa_bluetooth_hook {
PA_BLUETOOTH_HOOK_ADAPTER_UUIDS_CHANGED, /* Call data: pa_bluetooth_adapter */
PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED, /* Call data: pa_bluetooth_device */
PA_BLUETOOTH_HOOK_DEVICE_UNLINK, /* Call data: pa_bluetooth_device */
PA_BLUETOOTH_HOOK_DEVICE_BATTERY_LEVEL_CHANGED, /* Call data: pa_bluetooth_device */
+ PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED, /* Call data: pa_upower_backend */
PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED, /* Call data: pa_bluetooth_transport */
PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED, /* Call data: pa_bluetooth_transport */
PA_BLUETOOTH_HOOK_TRANSPORT_SINK_VOLUME_CHANGED, /* Call data: pa_bluetooth_transport */
--
2.35.1