From be9ac83d731efb8700be6f82805f12ecfbc30af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Correa=20G=C3=B3mez?= Date: Tue, 21 May 2024 10:26:17 +0200 Subject: [PATCH] temp/pulseaudio: drop (MR 5163) Upstream MR has been closed by Dylan 2 months ago, and this feature is already present in pipewire. We are doing considerably amount of work to get Pipewire production-ready in postmarketOS, including features to let users choose. Given HFP support is actually a nice-to-have feature, but not a great requirement, our fork is outdated (aports is on 17.0), and that the upstream MR has been dropped and is not being worked on, it might be time to drop this. --- ...ove-pa_bluetooth_discovery-to-header.patch | 110 -- .../0002-bluetooth-add-AT-BIA-support.patch | 194 -- .../0003-bluetooth-add-UPower-backend.patch | 393 ---- ...004-bluetooth-hook-up-UPower-backend.patch | 197 -- ...5-bluetooth-add-ModemManager-backend.patch | 1712 ----------------- ...-only-reply-OK-for-supported-AT-cmds.patch | 40 - ...07-bluetooth-Always-reply-to-AT-CIND.patch | 61 - .../0008-bluetooth-support-AT-CMEE.patch | 197 -- .../0009-bluetooth-support-AT-NREC.patch | 48 - .../0010-bluetooth-support-AT-BCC.patch | 33 - .../0011-bluetooth-support-AT-COPS.patch | 165 -- .../0012-bluetooth-support-AT-CNUM.patch | 68 - ...ooth-support-more-AT-CIND-indicators.patch | 67 - .../0014-bluetooth-support-AT-CLIP.patch | 60 - .../0015-bluetooth-support-AT-CREG.patch | 48 - .../0016-bluetooth-support-AT-CGMM.patch | 32 - .../0017-bluetooth-support-AT-CGMI.patch | 33 - .../0018-bluetooth-support-AT-CGMR.patch | 32 - .../0019-bluetooth-support-AT-CGSN.patch | 33 - .../0020-bluetooth-support-AT-CLCC.patch | 108 -- ...ooth-support-CIEV-RING-and-CLIP-URCs.patch | 365 ---- .../0022-bluetooth-support-AT-VTS.patch | 71 - .../0023-bluetooth-support-ATA.patch | 57 - .../0024-bluetooth-support-AT-CHUP.patch | 72 - .../0025-bluetooth-support-ATD-number.patch | 104 - ...rip-additional-out-of-spec-r-n-chars.patch | 60 - temp/pulseaudio/APKBUILD | 285 --- temp/pulseaudio/link-libintl.patch | 30 - temp/pulseaudio/pulseaudio.confd | 7 - temp/pulseaudio/pulseaudio.initd | 81 - temp/pulseaudio/pulseaudio.post-install | 11 - temp/pulseaudio/remove-once-test.patch | 16 - 32 files changed, 4790 deletions(-) delete mode 100644 temp/pulseaudio/0001-bluez5-util-move-pa_bluetooth_discovery-to-header.patch delete mode 100644 temp/pulseaudio/0002-bluetooth-add-AT-BIA-support.patch delete mode 100644 temp/pulseaudio/0003-bluetooth-add-UPower-backend.patch delete mode 100644 temp/pulseaudio/0004-bluetooth-hook-up-UPower-backend.patch delete mode 100644 temp/pulseaudio/0005-bluetooth-add-ModemManager-backend.patch delete mode 100644 temp/pulseaudio/0006-bluetooth-only-reply-OK-for-supported-AT-cmds.patch delete mode 100644 temp/pulseaudio/0007-bluetooth-Always-reply-to-AT-CIND.patch delete mode 100644 temp/pulseaudio/0008-bluetooth-support-AT-CMEE.patch delete mode 100644 temp/pulseaudio/0009-bluetooth-support-AT-NREC.patch delete mode 100644 temp/pulseaudio/0010-bluetooth-support-AT-BCC.patch delete mode 100644 temp/pulseaudio/0011-bluetooth-support-AT-COPS.patch delete mode 100644 temp/pulseaudio/0012-bluetooth-support-AT-CNUM.patch delete mode 100644 temp/pulseaudio/0013-bluetooth-support-more-AT-CIND-indicators.patch delete mode 100644 temp/pulseaudio/0014-bluetooth-support-AT-CLIP.patch delete mode 100644 temp/pulseaudio/0015-bluetooth-support-AT-CREG.patch delete mode 100644 temp/pulseaudio/0016-bluetooth-support-AT-CGMM.patch delete mode 100644 temp/pulseaudio/0017-bluetooth-support-AT-CGMI.patch delete mode 100644 temp/pulseaudio/0018-bluetooth-support-AT-CGMR.patch delete mode 100644 temp/pulseaudio/0019-bluetooth-support-AT-CGSN.patch delete mode 100644 temp/pulseaudio/0020-bluetooth-support-AT-CLCC.patch delete mode 100644 temp/pulseaudio/0021-bluetooth-support-CIEV-RING-and-CLIP-URCs.patch delete mode 100644 temp/pulseaudio/0022-bluetooth-support-AT-VTS.patch delete mode 100644 temp/pulseaudio/0023-bluetooth-support-ATA.patch delete mode 100644 temp/pulseaudio/0024-bluetooth-support-AT-CHUP.patch delete mode 100644 temp/pulseaudio/0025-bluetooth-support-ATD-number.patch delete mode 100644 temp/pulseaudio/0026-bluetooth-strip-additional-out-of-spec-r-n-chars.patch delete mode 100644 temp/pulseaudio/APKBUILD delete mode 100644 temp/pulseaudio/link-libintl.patch delete mode 100644 temp/pulseaudio/pulseaudio.confd delete mode 100644 temp/pulseaudio/pulseaudio.initd delete mode 100644 temp/pulseaudio/pulseaudio.post-install delete mode 100644 temp/pulseaudio/remove-once-test.patch diff --git a/temp/pulseaudio/0001-bluez5-util-move-pa_bluetooth_discovery-to-header.patch b/temp/pulseaudio/0001-bluez5-util-move-pa_bluetooth_discovery-to-header.patch deleted file mode 100644 index f52a85090..000000000 --- a/temp/pulseaudio/0001-bluez5-util-move-pa_bluetooth_discovery-to-header.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 355c4cc3f70abee505d2aad0a37d453a44ead1c2 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Wed, 6 Apr 2022 08:15:13 +0200 -Subject: [PATCH 01/26] bluez5-util: move pa_bluetooth_discovery to header - ---- - src/modules/bluetooth/bluez5-util.c | 23 ----------------------- - src/modules/bluetooth/bluez5-util.h | 24 ++++++++++++++++++++++++ - src/modules/meson.build | 2 +- - 3 files changed, 25 insertions(+), 24 deletions(-) - -diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c -index 83f2932e9..2f8d6faf1 100644 ---- a/src/modules/bluetooth/bluez5-util.c -+++ b/src/modules/bluetooth/bluez5-util.c -@@ -31,7 +31,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -128,28 +127,6 @@ static uint16_t volume_to_a2dp_gain(pa_volume_t volume) { - return gain; - } - --struct pa_bluetooth_discovery { -- PA_REFCNT_DECLARE; -- -- pa_core *core; -- pa_dbus_connection *connection; -- bool filter_added; -- bool matches_added; -- bool objects_listed; -- pa_hook hooks[PA_BLUETOOTH_HOOK_MAX]; -- pa_hashmap *adapters; -- pa_hashmap *devices; -- pa_hashmap *transports; -- pa_bluetooth_profile_status_t profiles_status[PA_BLUETOOTH_PROFILE_COUNT]; -- -- int headset_backend; -- pa_bluetooth_backend *ofono_backend, *native_backend; -- PA_LLIST_HEAD(pa_dbus_pending, pending); -- bool enable_native_hsp_hs; -- bool enable_native_hfp_hf; -- bool enable_msbc; --}; -- - static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, DBusMessage *m, - DBusPendingCallNotifyFunction func, void *call_data) { - pa_dbus_pending *p; -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index 86eb6301e..f899d9d0c 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -22,6 +22,7 @@ - ***/ - - #include -+#include - - #include "a2dp-codec-util.h" - -@@ -134,6 +135,29 @@ struct pa_bluetooth_transport { - void *userdata; - }; - -+struct pa_bluetooth_discovery { -+ PA_REFCNT_DECLARE; -+ -+ pa_core *core; -+ pa_dbus_connection *connection; -+ bool filter_added; -+ bool matches_added; -+ bool objects_listed; -+ pa_hook hooks[PA_BLUETOOTH_HOOK_MAX]; -+ pa_hashmap *adapters; -+ pa_hashmap *devices; -+ pa_hashmap *transports; -+ pa_bluetooth_profile_status_t profiles_status[PA_BLUETOOTH_PROFILE_COUNT]; -+ -+ int headset_backend; -+ pa_bluetooth_backend *ofono_backend, *native_backend; -+ PA_LLIST_HEAD(pa_dbus_pending, pending); -+ bool enable_native_hsp_hs; -+ bool enable_native_hfp_hf; -+ bool enable_msbc; -+}; -+ -+ - struct pa_bluetooth_device { - pa_bluetooth_discovery *discovery; - pa_bluetooth_adapter *adapter; -diff --git a/src/modules/meson.build b/src/modules/meson.build -index 1ae172971..08c754948 100644 ---- a/src/modules/meson.build -+++ b/src/modules/meson.build -@@ -123,7 +123,7 @@ if cdata.has('HAVE_BLUEZ_5') - all_modules += [ - [ 'module-bluetooth-discover', 'bluetooth/module-bluetooth-discover.c' ], - [ 'module-bluetooth-policy', 'bluetooth/module-bluetooth-policy.c', [], [], [dbus_dep] ], -- [ 'module-bluez5-device', 'bluetooth/module-bluez5-device.c', [], [], [], libbluez5_util ], -+ [ 'module-bluez5-device', 'bluetooth/module-bluez5-device.c', [], [], [dbus_dep], libbluez5_util ], - [ 'module-bluez5-discover', 'bluetooth/module-bluez5-discover.c', [], [], [dbus_dep], libbluez5_util ], - ] - endif --- -2.35.1 - diff --git a/temp/pulseaudio/0002-bluetooth-add-AT-BIA-support.patch b/temp/pulseaudio/0002-bluetooth-add-AT-BIA-support.patch deleted file mode 100644 index f8869ef8d..000000000 --- a/temp/pulseaudio/0002-bluetooth-add-AT-BIA-support.patch +++ /dev/null @@ -1,194 +0,0 @@ -From 5aebba47f8215d5c580602a34082fc27081d963d Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Tue, 5 Apr 2022 20:10:05 +0200 -Subject: [PATCH 02/26] bluetooth: add AT+BIA support - -AT+BIA is used to enable/disable CIND indicators by Bluetooth HFP spec. -By default, all indicators are enabled on connection. -AT+BIA will configure which indicators should be disabled then, -the disabled indicators may be enabled later on again with AT+BIA. -When the connection is lost and recovered, all indicators are enabled -again. The HF will reconfigure the indicators again with an AT+BIA -command. ---- - src/modules/bluetooth/backend-native.c | 93 ++++++++++++++++++++++++-- - 1 file changed, 87 insertions(+), 6 deletions(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index f6b85e90d..d26edc1c9 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -39,6 +39,11 @@ - #include "bluez5-util.h" - #include "bt-codec-msbc.h" - -+#define MANDATORY_CALL_INDICATORS \ -+ "(\"call\",(0-1))," \ -+ "(\"callsetup\",(0-3))," \ -+ "(\"callheld\",(0-2))" \ -+ - struct pa_bluetooth_backend { - pa_core *core; - pa_dbus_connection *connection; -@@ -47,6 +52,8 @@ struct pa_bluetooth_backend { - bool enable_shared_profiles; - bool enable_hsp_hs; - bool enable_hfp_hf; -+ bool cmer_indicator_reporting_enabled; -+ uint32_t cind_enabled_indicators; - - PA_LLIST_HEAD(pa_dbus_pending, pending); - }; -@@ -97,6 +104,20 @@ enum hfp_ag_features { - HFP_AG_INDICATORS = 10, - }; - -+/* -+ * Always keep this struct in sync with indicator discovery of AT+CIND=? -+ * These indicators are used in bitflags and intentionally start at 1 -+ * since AT+CIND indicators start at index 1. -+ */ -+typedef enum pa_bluetooth_ag_to_hf_indicators { -+ CIND_CALL_INDICATOR = 1, -+ CIND_CALL_SETUP_INDICATOR = 2, -+ CIND_CALL_HELD_INDICATOR = 3, -+ CIND_SERVICE_INDICATOR = 4, -+ CIND_BATT_CHG_INDICATOR = 5, -+ CIND_INDICATOR_MAX = 6 -+} pa_bluetooth_ag_to_hf_indicators_t; -+ - /* gateway features we support, which is as little as we can get away with */ - static uint32_t hfp_features = - /* HFP 1.6 requires this */ -@@ -588,8 +609,9 @@ static pa_volume_t set_source_volume(pa_bluetooth_transport *t, pa_volume_t volu - - static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf) - { -+ struct pa_bluetooth_discovery *discovery = t->device->discovery; - struct hfp_config *c = t->config; -- int indicator, val; -+ int indicator, mode, val; - char str[5]; - const char *r; - size_t len; -@@ -607,6 +629,34 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - c->supports_indicators = !!(1 << HFP_HF_INDICATORS); - c->state = 1; - -+ return true; -+ } else if (sscanf(buf, "AT+BIA=%s", str) == 1) { -+ /* Indicators start with index 1 and follow the order of the AT+CIND=? response */ -+ indicator = 1; -+ -+ while ((r = pa_split_in_place(str, ",", &len, &state))) { -+ /* Ignore updates to mandantory indicators which are always ON */ -+ if (indicator == CIND_CALL_INDICATOR -+ || indicator == CIND_CALL_SETUP_INDICATOR -+ || indicator == CIND_CALL_HELD_INDICATOR) -+ continue; -+ -+ /* Indicators may have no value and should be skipped */ -+ if (len == 0) -+ continue; -+ -+ if (len == 1 && r[0] == '1') -+ discovery->native_backend->cind_enabled_indicators |= (1 << indicator); -+ else if (len == 1 && r[0] == '0') -+ discovery->native_backend->cind_enabled_indicators &= ~(1 << indicator); -+ else { -+ pa_log_error("Unable to parse indicator of AT+BIA command: %s", buf); -+ rfcomm_write_response(fd, "ERROR"); -+ return false; -+ } -+ -+ indicator++; -+ } - return true; - } else if (sscanf(buf, "AT+BAC=%3s", str) == 1) { - c->support_msbc = false; -@@ -637,10 +687,8 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - rfcomm_write_response(fd, "+CIND: " - /* many indicators can be supported, only call and - * callheld are mandatory, so that's all we reply */ -- "(\"service\",(0-1))," -- "(\"call\",(0-1))," -- "(\"callsetup\",(0-3))," -- "(\"callheld\",(0-2))"); -+ MANDATORY_CALL_INDICATORS ",", -+ "(\"service\",(0-1))"); - c->state = 2; - - return true; -@@ -650,7 +698,24 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - - return true; - } else if ((c->state == 2 || c->state == 3) && pa_startswith(buf, "AT+CMER=")) { -- rfcomm_write_response(fd, "OK"); -+ if (sscanf(buf, "AT+CMER=%d,%*d,%*d,%d", &mode, &val) == 2) { -+ /* Bluetooth HFP spec only defines mode == 3 */ -+ if (mode != 3) { -+ pa_log_warn("Unexpected mode for AT+CMER: %d", mode); -+ } -+ -+ /* Configure CMER event reporting */ -+ discovery->native_backend->cmer_indicator_reporting_enabled = !!val; -+ -+ pa_log_debug("Event indications enabled? %s", pa_yes_no(val)); -+ -+ rfcomm_write_response(fd, "OK"); -+ } -+ else { -+ pa_log_error("Unable to parse AT+CMER command: %s", buf); -+ rfcomm_write_response(fd, "ERROR"); -+ return false; -+ } - - if (c->support_codec_negotiation) { - if (c->support_msbc && pa_bluetooth_discovery_get_enable_msbc(t->device->discovery)) { -@@ -740,6 +805,8 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - - 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; -+ int i; - - pa_assert(io); - pa_assert(t); -@@ -860,6 +927,11 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i - return; - - fail: -+ /* Service Connection lost, reset indicators and event reporting to default values */ -+ discovery->native_backend->cmer_indicator_reporting_enabled = false; -+ for (i = 1; i < CIND_INDICATOR_MAX; i++) -+ discovery->native_backend->cind_enabled_indicators |= (1 << i); -+ - pa_bluetooth_transport_unlink(t); - pa_bluetooth_transport_free(t); - } -@@ -1188,6 +1260,7 @@ void pa_bluetooth_native_backend_enable_shared_profiles(pa_bluetooth_backend *na - pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_discovery *y, bool enable_shared_profiles) { - pa_bluetooth_backend *backend; - DBusError err; -+ int i; - - pa_log_debug("Bluetooth Headset Backend API support using the native backend"); - -@@ -1220,6 +1293,14 @@ 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); - -+ /* 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); -+ -+ /* While all CIND indicators are enabled, event reporting is not enabled by default */ -+ backend->cmer_indicator_reporting_enabled = false; -+ -+ - return backend; - } - --- -2.35.1 - diff --git a/temp/pulseaudio/0003-bluetooth-add-UPower-backend.patch b/temp/pulseaudio/0003-bluetooth-add-UPower-backend.patch deleted file mode 100644 index 48f83da0f..000000000 --- a/temp/pulseaudio/0003-bluetooth-add-UPower-backend.patch +++ /dev/null @@ -1,393 +0,0 @@ -From 0c8451cae9c585793fa98fb99864d5228127bbf9 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Tue, 5 Apr 2022 20:26:09 +0200 -Subject: [PATCH 03/26] bluetooth: add UPower backend - -UPower provides information about the power supply and battery -level of the host. Add a backend to retrieve the host battery level. ---- - src/modules/bluetooth/meson.build | 4 +- - src/modules/bluetooth/upower.c | 300 ++++++++++++++++++++++++++++++ - src/modules/bluetooth/upower.h | 41 ++++ - 3 files changed, 344 insertions(+), 1 deletion(-) - create mode 100644 src/modules/bluetooth/upower.c - create mode 100644 src/modules/bluetooth/upower.h - -diff --git a/src/modules/bluetooth/meson.build b/src/modules/bluetooth/meson.build -index ca77ee6aa..0703d5086 100644 ---- a/src/modules/bluetooth/meson.build -+++ b/src/modules/bluetooth/meson.build -@@ -16,6 +16,8 @@ libbluez5_util_headers = [ - - if get_option('bluez5-native-headset') - libbluez5_util_sources += [ 'backend-native.c' ] -+ libbluez5_util_sources += [ 'upower.c' ] -+ libbluez5_util_headers += [ 'upower.h' ] - endif - - if get_option('bluez5-ofono-headset') -@@ -35,7 +37,7 @@ libbluez5_util = shared_library('bluez5-util', - c_args : [pa_c_args, server_c_args], - link_args : [nodelete_link_args], - include_directories : [configinc, topinc], -- dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, bluez_dep, dbus_dep, sbc_dep, libintl_dep, bluez5_gst_dep, bluez5_gstapp_dep], -+ dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, bluez_dep, dbus_dep, sbc_dep, libintl_dep, bluez5_gst_dep, bluez5_gstapp_dep, libm_dep], - install : true, - install_rpath : privlibdir, - install_dir : modlibexecdir, -diff --git a/src/modules/bluetooth/upower.c b/src/modules/bluetooth/upower.c -new file mode 100644 -index 000000000..b5cb89bfe ---- /dev/null -+++ b/src/modules/bluetooth/upower.c -@@ -0,0 +1,300 @@ -+/*** -+ This file is part of PulseAudio. -+ -+ Copyrigth 2022 Dylan Van Assche -+ -+ PulseAudio is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of the -+ License, or (at your option) any later version. -+ -+ PulseAudio is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with PulseAudio; if not, see . -+***/ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "upower.h" -+ -+static pa_dbus_pending* send_and_add_to_pending(pa_upower_backend *backend, DBusMessage *m, -+ DBusPendingCallNotifyFunction func, void *call_data) { -+ -+ pa_dbus_pending *p; -+ DBusPendingCall *call; -+ -+ pa_assert(backend); -+ pa_assert(m); -+ -+ pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(backend->connection), m, &call, -1)); -+ -+ p = pa_dbus_pending_new(pa_dbus_connection_get(backend->connection), m, call, backend, call_data); -+ PA_LLIST_PREPEND(pa_dbus_pending, backend->pending, p); -+ dbus_pending_call_set_notify(call, func, p, NULL); -+ -+ return p; -+} -+ -+static void parse_percentage(pa_upower_backend *b, DBusMessageIter *i) { -+ double percentage; -+ unsigned int battery_level; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_DOUBLE); -+ -+ dbus_message_iter_get_basic(i, &percentage); -+ battery_level = (unsigned int) round(percentage / 20.0); -+ -+ if (battery_level != b->battery_level) { -+ b->battery_level = battery_level; -+ pa_log_debug("AG battery level updated (%d/5)", b->battery_level); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED), b); -+ } -+} -+ -+static void get_percentage_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_upower_backend *b; -+ DBusMessage *r; -+ DBusMessageIter arg_i, variant_i; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("UPower D-Bus Display Device not available"); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("Get() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ goto finish; -+ } -+ -+ if (!dbus_message_iter_init(r, &arg_i) || !pa_streq(dbus_message_get_signature(r), "v")) { -+ pa_log_error("Invalid reply signature for Get()"); -+ goto finish; -+ } -+ -+ dbus_message_iter_recurse(&arg_i, &variant_i); -+ parse_percentage(b, &variant_i); -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static const char *check_variant_property(DBusMessageIter *i) { -+ const char *key; -+ -+ pa_assert(i); -+ -+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) { -+ pa_log_error("Property name not a string."); -+ return NULL; -+ } -+ -+ dbus_message_iter_get_basic(i, &key); -+ -+ if (!dbus_message_iter_next(i)) { -+ pa_log_error("Property value missing"); -+ return NULL; -+ } -+ -+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) { -+ pa_log_error("Property value not a variant."); -+ return NULL; -+ } -+ -+ return key; -+} -+ -+static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) { -+ DBusError err; -+ DBusMessage *m2; -+ static const char* upower_device_interface = UPOWER_SERVICE UPOWER_DEVICE_INTERFACE; -+ static const char* percentage_property = "Percentage"; -+ pa_upower_backend *b = data; -+ const char *path, *interface, *member; -+ -+ pa_assert(bus); -+ pa_assert(m); -+ pa_assert(b); -+ -+ dbus_error_init(&err); -+ -+ path = dbus_message_get_path(m); -+ interface = dbus_message_get_interface(m); -+ member = dbus_message_get_member(m); -+ -+ pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member); -+ -+ /* UPower D-Bus status change */ -+ if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { -+ const char *name, *old_owner, *new_owner; -+ -+ if (!dbus_message_get_args(m, &err, -+ DBUS_TYPE_STRING, &name, -+ DBUS_TYPE_STRING, &old_owner, -+ DBUS_TYPE_STRING, &new_owner, -+ DBUS_TYPE_INVALID)) { -+ pa_log_error("Failed to parse " DBUS_INTERFACE_DBUS ".NameOwnerChanged: %s", err.message); -+ goto fail; -+ } -+ -+ if (pa_streq(name, UPOWER_SERVICE)) { -+ -+ /* UPower disappeared from D-Bus */ -+ if (old_owner && *old_owner) { -+ pa_log_debug("UPower disappeared from D-Bus"); -+ b->battery_level = 0; -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED), b); -+ } -+ -+ /* UPower appeared on D-Bus */ -+ if (new_owner && *new_owner) { -+ pa_log_debug("UPower appeared on D-Bus"); -+ -+ /* Update battery level */ -+ pa_assert_se(m2 = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get")); -+ pa_assert_se(dbus_message_append_args(m2, -+ DBUS_TYPE_STRING, &upower_device_interface, -+ DBUS_TYPE_STRING, &percentage_property, -+ DBUS_TYPE_INVALID)); -+ send_and_add_to_pending(b, m2, get_percentage_reply, NULL); -+ } -+ } -+ -+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -+ /* UPower battery level property updates */ -+ } else if (dbus_message_is_signal(m, DBUS_INTERFACE_PROPERTIES, "PropertiesChanged")) { -+ DBusMessageIter arg_i, element_i; -+ -+ if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "sa{sv}as")) { -+ pa_log_error("Invalid signature found in PropertiesChanged"); -+ goto fail; -+ } -+ -+ /* Skip interface name */ -+ pa_assert_se(dbus_message_iter_next(&arg_i)); -+ pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY); -+ -+ dbus_message_iter_recurse(&arg_i, &element_i); -+ -+ /* Parse UPower property updates */ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { -+ DBusMessageIter dict_i, variant_i; -+ const char *key; -+ -+ dbus_message_iter_recurse(&element_i, &dict_i); -+ -+ /* Retrieve property name */ -+ key = check_variant_property(&dict_i); -+ if (key == NULL) { -+ pa_log_error("Received invalid property!"); -+ break; -+ } -+ -+ dbus_message_iter_recurse(&dict_i, &variant_i); -+ -+ if(pa_streq(path, UPOWER_DISPLAY_DEVICE_OBJECT)) { -+ pa_log_debug("UPower Device property updated: %s", key); -+ -+ if(pa_streq(key, "Percentage")) -+ parse_percentage(b, &variant_i); -+ } -+ -+ dbus_message_iter_next(&element_i); -+ } -+ } -+ -+fail: -+ dbus_error_free(&err); -+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -+} -+ -+unsigned int pa_upower_get_battery_level(pa_upower_backend *backend) { -+ return backend->battery_level; -+} -+ -+pa_upower_backend *pa_upower_backend_new(pa_core *c, pa_bluetooth_discovery *d) { -+ pa_upower_backend *backend; -+ DBusError err; -+ DBusMessage *m; -+ static const char* upower_device_interface = UPOWER_SERVICE UPOWER_DEVICE_INTERFACE; -+ static const char* percentage_property = "Percentage"; -+ -+ pa_log_debug("Native backend enabled UPower battery status reporting"); -+ -+ backend = pa_xnew0(pa_upower_backend, 1); -+ backend->core = c; -+ backend->discovery = d; -+ -+ /* Get DBus connection */ -+ dbus_error_init(&err); -+ if (!(backend->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) { -+ pa_log("Failed to get D-Bus connection: %s", err.message); -+ dbus_error_free(&err); -+ pa_xfree(backend); -+ return NULL; -+ } -+ -+ /* Add filter callback for DBus connection */ -+ if (!dbus_connection_add_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend, NULL)) { -+ pa_log_error("Failed to add filter function"); -+ pa_dbus_connection_unref(backend->connection); -+ pa_xfree(backend); -+ return NULL; -+ } -+ -+ /* Register for battery level changes from UPower */ -+ if (pa_dbus_add_matches(pa_dbus_connection_get(backend->connection), &err, -+ "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged'," -+ "arg0='" UPOWER_SERVICE "'", -+ "type='signal',sender='" UPOWER_SERVICE "',interface='" DBUS_INTERFACE_PROPERTIES "',member='PropertiesChanged'", -+ NULL) < 0) { -+ pa_log("Failed to add UPower D-Bus matches: %s", err.message); -+ dbus_connection_remove_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend); -+ pa_dbus_connection_unref(backend->connection); -+ pa_xfree(backend); -+ return NULL; -+ } -+ -+ /* Initialize battery level by requesting it from UPower */ -+ pa_assert_se(m = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get")); -+ pa_assert_se(dbus_message_append_args(m, -+ DBUS_TYPE_STRING, &upower_device_interface, -+ DBUS_TYPE_STRING, &percentage_property, -+ DBUS_TYPE_INVALID)); -+ send_and_add_to_pending(backend, m, get_percentage_reply, NULL); -+ -+ return backend; -+} -+ -+void pa_upower_backend_free(pa_upower_backend *backend) { -+ pa_assert(backend); -+ -+ pa_dbus_free_pending_list(&backend->pending); -+ -+ pa_dbus_connection_unref(backend->connection); -+ -+ pa_xfree(backend); -+} -+ -diff --git a/src/modules/bluetooth/upower.h b/src/modules/bluetooth/upower.h -new file mode 100644 -index 000000000..3e9ee9291 ---- /dev/null -+++ b/src/modules/bluetooth/upower.h -@@ -0,0 +1,41 @@ -+#pragma once -+ -+/*** -+ This file is part of PulseAudio. -+ -+ Copyrigth 2022 Dylan Van Assche -+ -+ PulseAudio is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of the -+ License, or (at your option) any later version. -+ -+ PulseAudio is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with PulseAudio; if not, see . -+***/ -+ -+#include "bluez5-util.h" -+ -+#define UPOWER_SERVICE "org.freedesktop.UPower" -+#define UPOWER_DEVICE_INTERFACE ".Device" -+#define UPOWER_DISPLAY_DEVICE_OBJECT "/org/freedesktop/UPower/devices/DisplayDevice" -+ -+struct pa_upower_backend { -+ pa_core *core; -+ pa_dbus_connection *connection; -+ pa_bluetooth_discovery *discovery; -+ unsigned int battery_level; -+ -+ PA_LLIST_HEAD(pa_dbus_pending, pending); -+}; -+ -+pa_upower_backend *pa_upower_backend_new(pa_core *c, pa_bluetooth_discovery *d); -+void pa_upower_backend_free(pa_upower_backend *backend); -+void pa_upower_register_transport(pa_upower_backend *backend, pa_bluetooth_transport *t); -+void pa_upower_unregister_transport(pa_upower_backend *backend); -+unsigned int pa_upower_get_battery_level(pa_upower_backend *backend); --- -2.35.1 - diff --git a/temp/pulseaudio/0004-bluetooth-hook-up-UPower-backend.patch b/temp/pulseaudio/0004-bluetooth-hook-up-UPower-backend.patch deleted file mode 100644 index 5f74a0fa6..000000000 --- a/temp/pulseaudio/0004-bluetooth-hook-up-UPower-backend.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 78e255eefb417275e73f8ed96ce08bf7c3a1dff9 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -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 - diff --git a/temp/pulseaudio/0005-bluetooth-add-ModemManager-backend.patch b/temp/pulseaudio/0005-bluetooth-add-ModemManager-backend.patch deleted file mode 100644 index 94fcd077c..000000000 --- a/temp/pulseaudio/0005-bluetooth-add-ModemManager-backend.patch +++ /dev/null @@ -1,1712 +0,0 @@ -From 67fc83f344dc0a308aad5619621edff3307f54d6 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Thu, 7 Apr 2022 20:30:24 +0200 -Subject: [PATCH 05/26] bluetooth: add ModemManager backend - -ModemManager is an alternative to oFono for interacting with -modems. Add a ModemManager backend to better support Bluetooth HFP 1.6 -with cellular support such as making and rejecting calls, retrieving -cellular status and in-band ringing. ---- - .gitlab-ci.yml | 3 +- - meson.build | 2 + - src/modules/bluetooth/bluez5-util.h | 7 + - src/modules/bluetooth/meson.build | 4 +- - src/modules/bluetooth/modemmanager.c | 1498 ++++++++++++++++++++++++++ - src/modules/bluetooth/modemmanager.h | 98 ++ - 6 files changed, 1610 insertions(+), 2 deletions(-) - create mode 100644 src/modules/bluetooth/modemmanager.c - create mode 100644 src/modules/bluetooth/modemmanager.h - -diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml -index e6b36da87..f2e20dd64 100644 ---- a/.gitlab-ci.yml -+++ b/.gitlab-ci.yml -@@ -19,7 +19,7 @@ variables: - # CI runs, for example when adding new packages to FDO_DISTRIBUTION_PACKAGES. - # The tag is an arbitrary string that identifies the exact container - # contents. -- FDO_DISTRIBUTION_TAG: '2021-11-03-00' -+ FDO_DISTRIBUTION_TAG: '2022-04-20-00' - FDO_DISTRIBUTION_VERSION: '20.04' - FDO_UPSTREAM_REPO: 'pulseaudio/pulseaudio' - UBUNTU_IMAGE: "$CI_REGISTRY_IMAGE/ubuntu/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG" -@@ -81,6 +81,7 @@ build-container: - libxml2-utils - libxtst-dev - m4 -+ modemmanager-dev - ninja-build - pkg-config - python3-setuptools -diff --git a/meson.build b/meson.build -index 3ae7ac69a..063390c7f 100644 ---- a/meson.build -+++ b/meson.build -@@ -773,6 +773,8 @@ if get_option('daemon') - endif - endif - -+ modemmanager_dep = dependency('ModemManager', version : '>= 1.10.0', required : get_option('bluez5-native-headset')) -+ - jack_dep = dependency('jack', version : '>= 0.117.0', required : get_option('jack')) - if jack_dep.found() - cdata.set('HAVE_JACK', 1) -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index a24a0b823..f69176425 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -64,6 +64,7 @@ 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 struct pa_modemmanager_backend pa_modemmanager_backend; - - typedef enum pa_bluetooth_hook { - PA_BLUETOOTH_HOOK_ADAPTER_UUIDS_CHANGED, /* Call data: pa_bluetooth_adapter */ -@@ -71,6 +72,12 @@ typedef enum pa_bluetooth_hook { - 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_HOST_CALLS_CHANGED, /* Call data: pa_modemmanager_transport */ -+ PA_BLUETOOTH_HOOK_HOST_SIGNAL_STRENGTH_CHANGED, /* Call data: pa_modemmanager_transport */ -+ PA_BLUETOOTH_HOOK_HOST_HAS_SERVICE_CHANGED, /* Call data: pa_modemmanager_transport */ -+ PA_BLUETOOTH_HOOK_HOST_IS_ROAMING_CHANGED, /* Call data: pa_modemmanager_transport */ -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED, /* Call data: pa_modemmanager_transport */ -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_SUCCEED, /* Call data: pa_modemmanager_transport */ - 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 */ -diff --git a/src/modules/bluetooth/meson.build b/src/modules/bluetooth/meson.build -index 0703d5086..fdcc8a521 100644 ---- a/src/modules/bluetooth/meson.build -+++ b/src/modules/bluetooth/meson.build -@@ -18,6 +18,8 @@ if get_option('bluez5-native-headset') - libbluez5_util_sources += [ 'backend-native.c' ] - libbluez5_util_sources += [ 'upower.c' ] - libbluez5_util_headers += [ 'upower.h' ] -+ libbluez5_util_sources += [ 'modemmanager.c' ] -+ libbluez5_util_headers += [ 'modemmanager.h' ] - endif - - if get_option('bluez5-ofono-headset') -@@ -37,7 +39,7 @@ libbluez5_util = shared_library('bluez5-util', - c_args : [pa_c_args, server_c_args], - link_args : [nodelete_link_args], - include_directories : [configinc, topinc], -- dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, bluez_dep, dbus_dep, sbc_dep, libintl_dep, bluez5_gst_dep, bluez5_gstapp_dep, libm_dep], -+ dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, bluez_dep, dbus_dep, sbc_dep, libintl_dep, bluez5_gst_dep, bluez5_gstapp_dep, libm_dep, modemmanager_dep], - install : true, - install_rpath : privlibdir, - install_dir : modlibexecdir, -diff --git a/src/modules/bluetooth/modemmanager.c b/src/modules/bluetooth/modemmanager.c -new file mode 100644 -index 000000000..60c3fabec ---- /dev/null -+++ b/src/modules/bluetooth/modemmanager.c -@@ -0,0 +1,1498 @@ -+/*** -+ This file is part of PulseAudio. -+ -+ Copyright 2022 Dylan Van Assche -+ -+ PulseAudio is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of the -+ License, or (at your option) any later version. -+ -+ PulseAudio is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with PulseAudio; if not, see . -+***/ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "modemmanager.h" -+ -+static pa_dbus_pending* send_and_add_to_pending(pa_modemmanager_backend *backend, DBusMessage *m, -+ DBusPendingCallNotifyFunction func, void *call_data) { -+ -+ pa_dbus_pending *p; -+ DBusPendingCall *call; -+ -+ pa_assert(backend); -+ pa_assert(m); -+ -+ pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(backend->connection), m, &call, -1)); -+ -+ p = pa_dbus_pending_new(pa_dbus_connection_get(backend->connection), m, call, backend, call_data); -+ PA_LLIST_PREPEND(pa_dbus_pending, backend->pending, p); -+ dbus_pending_call_set_notify(call, func, p, NULL); -+ -+ return p; -+} -+ -+static const char *check_variant_property(DBusMessageIter *i) { -+ const char *key; -+ -+ pa_assert(i); -+ -+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) { -+ pa_log_error("Property name not a string."); -+ return NULL; -+ } -+ -+ dbus_message_iter_get_basic(i, &key); -+ -+ if (!dbus_message_iter_next(i)) { -+ pa_log_error("Property value missing"); -+ return NULL; -+ } -+ -+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) { -+ pa_log_error("Property value not a variant."); -+ return NULL; -+ } -+ -+ return key; -+} -+ -+static void create_call_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus Voice not available"); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), b); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("CreateCall() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), b); -+ goto finish; -+ } -+ -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_SUCCEED), b); -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static void call_hangup_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus Call not available"); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), b); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("Hangup() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), b); -+ goto finish; -+ } -+ -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_SUCCEED), b); -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static void call_accept_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus Call not available"); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), b); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("Accept() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), b); -+ goto finish; -+ } -+ -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_SUCCEED), b); -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static void send_dtmf_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus Call not available"); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), b); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("SendDtmf() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), b); -+ goto finish; -+ } -+ -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_SUCCEED), b); -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static void parse_state(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ MMModemState state; -+ bool has_service; -+ -+ pa_assert(i); -+ -+ /* -+ * ModemManager emits the State property as UINT32 or INT32. -+ * Cast to unsigned int if needed. -+ */ -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_UINT32 -+ || dbus_message_iter_get_arg_type(i) == DBUS_TYPE_INT32); -+ -+ if (dbus_message_iter_get_arg_type(i) == DBUS_TYPE_INT32) { -+ int s; -+ -+ dbus_message_iter_get_basic(i, &s); -+ state = (unsigned int) s; -+ } else -+ dbus_message_iter_get_basic(i, &state); -+ -+ /* All states from REGISTERED and higher indicate that the modem has service */ -+ if (state >= MM_MODEM_STATE_REGISTERED) -+ has_service = true; -+ else -+ has_service = false; -+ -+ pa_log_debug("Network has service: %s", pa_yes_no(has_service)); -+ -+ if (b->modem->network_has_service != has_service) { -+ b->modem->network_has_service = has_service; -+ pa_log_debug("AG service status updated: %s", pa_yes_no(b->modem->network_has_service)); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_HAS_SERVICE_CHANGED), b); -+ } -+} -+ -+static void parse_registration(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ MMModem3gppRegistrationState registration; -+ bool is_roaming; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_UINT32); -+ -+ dbus_message_iter_get_basic(i, ®istration); -+ -+ /* All states containing ROAMING indicate that the modem is roaming */ -+ if (registration == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING -+ || registration == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED -+ || registration == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY) { -+ is_roaming = true; -+ } else -+ is_roaming = false; -+ -+ pa_log_debug("Network is roaming: %s", pa_yes_no(is_roaming)); -+ -+ if (b->modem->network_is_roaming != is_roaming) { -+ b->modem->network_is_roaming = is_roaming; -+ pa_log_debug("AG roaming status updated: %s", pa_yes_no(b->modem->network_is_roaming)); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_IS_ROAMING_CHANGED), b); -+ } -+} -+ -+static void parse_signal_quality(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ unsigned int percentage, signal_strength; -+ DBusMessageIter structIter; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_STRUCT); -+ -+ dbus_message_iter_recurse(i, &structIter); -+ -+ if (dbus_message_iter_get_arg_type(&structIter) == DBUS_TYPE_UINT32) { -+ dbus_message_iter_get_basic(&structIter, &percentage); -+ signal_strength = (unsigned int) round(percentage / 20.0); -+ -+ pa_log_debug("Network signal strength: %d/100", percentage); -+ -+ if (b->modem->network_signal_strength != signal_strength) { -+ b->modem->network_signal_strength = signal_strength; -+ pa_log_debug("AG signal strength updated (%d/5)", b->modem->network_signal_strength); -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_SIGNAL_STRENGTH_CHANGED), b); -+ } -+ } -+} -+ -+static void parse_operator_name(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ char *name; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_STRING); -+ -+ dbus_message_iter_get_basic(i, &name); -+ if (b->modem->network_operator_name) -+ pa_xfree(b->modem->network_operator_name); -+ b->modem->network_operator_name = pa_xstrdup(name); -+ -+ pa_log_debug("Network operator name: %s", b->modem->network_operator_name); -+} -+ -+static void parse_operator_code(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ char *code; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_STRING); -+ -+ dbus_message_iter_get_basic(i, &code); -+ if (b->modem->network_operator_code) -+ pa_xfree(b->modem->network_operator_code); -+ b->modem->network_operator_code = pa_xstrdup(code); -+ -+ pa_log_debug("Network operator code: %s", b->modem->network_operator_code); -+} -+ -+static void parse_own_number(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ DBusMessageIter element_i; -+ char *number; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_ARRAY); -+ -+ dbus_message_iter_recurse(i, &element_i); -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_STRING) { -+ dbus_message_iter_get_basic(&element_i, &number); -+ if (b->modem->modem_own_number) -+ pa_xfree(b->modem->modem_own_number); -+ b->modem->modem_own_number = pa_xstrdup(number); -+ pa_log_debug("Modem own number: %s", b->modem->modem_own_number); -+ -+ /* Bluetooth HFP cannot deal with multiple SIMs and numbers */ -+ break; -+ -+ dbus_message_iter_next(&element_i); -+ } -+} -+ -+static void parse_call_number(pa_modemmanager_backend *b, DBusMessageIter *i, const char *call_object) { -+ char *number; -+ call_status_t *call_state; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_STRING); -+ -+ dbus_message_iter_get_basic(i, &number); -+ -+ call_state = pa_hashmap_get(b->calls, call_object); -+ if (!call_state) { -+ return; -+ } -+ -+ if (call_state->number) -+ pa_xfree(call_state->number); -+ call_state->number = pa_xstrdup(number); -+ -+ pa_log_debug("Call number %s", call_state->number); -+} -+ -+static void parse_call_state(pa_modemmanager_backend *b, DBusMessageIter *i, const char *call_object) { -+ MMCallState state; -+ call_status_t *call_state; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_INT32); -+ -+ dbus_message_iter_get_basic(i, &state); -+ -+ call_state = pa_hashmap_get(b->calls, call_object); -+ if (!call_state) { -+ return; -+ } -+ -+ switch(state) { -+ case MM_CALL_STATE_UNKNOWN: -+ pa_log_warn("Call state unknown"); -+ call_state->status = PA_MODEMMANAGER_CALL_STATE_INVALID; -+ break; -+ case MM_CALL_STATE_ACTIVE: -+ pa_log_debug("Call active"); -+ call_state->status = PA_MODEMMANAGER_CALL_STATE_ACTIVE; -+ break; -+ /* FIXME: implement three-way calling */ -+ case MM_CALL_STATE_HELD: -+ pa_log_warn("Three-way calling is not implemented!"); -+ call_state->status = PA_MODEMMANAGER_CALL_STATE_INVALID; -+ break; -+ case MM_CALL_STATE_DIALING: -+ pa_log_debug("Call dailing"); -+ call_state->status = PA_MODEMMANAGER_CALL_STATE_DIALING; -+ break; -+ case MM_CALL_STATE_RINGING_OUT: -+ case MM_CALL_STATE_RINGING_IN: -+ pa_log_debug("Call ringing"); -+ call_state->status = PA_MODEMMANAGER_CALL_STATE_RINGING; -+ break; -+ /* FIXME: implement three-way calling */ -+ case MM_CALL_STATE_WAITING: -+ pa_log_warn("Three-way calling is not implemented!"); -+ call_state->status = PA_MODEMMANAGER_CALL_STATE_INVALID; -+ return; -+ case MM_CALL_STATE_TERMINATED: -+ pa_log_debug("Call terminated"); -+ call_state->status = PA_MODEMMANAGER_CALL_STATE_TERMINATED; -+ break; -+ default: -+ pa_assert_not_reached(); -+ } -+} -+ -+static void parse_call_direction(pa_modemmanager_backend *b, DBusMessageIter *i, const char *call_object) { -+ MMCallDirection direction; -+ call_status_t *call_state; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_INT32); -+ -+ dbus_message_iter_get_basic(i, &direction); -+ -+ call_state = pa_hashmap_get(b->calls, call_object); -+ if (!call_state) { -+ return; -+ } -+ -+ switch(direction) { -+ case MM_CALL_DIRECTION_UNKNOWN: -+ pa_log_warn("Unknown call direction"); -+ return; -+ case MM_CALL_DIRECTION_INCOMING: -+ call_state->is_incoming = true; -+ break; -+ case MM_CALL_DIRECTION_OUTGOING: -+ call_state->is_incoming = false; -+ break; -+ default: -+ pa_assert_not_reached(); -+ } -+ -+ pa_log_debug("Call direction updated. Is incoming? %s", pa_yes_no(call_state->is_incoming)); -+} -+ -+static void parse_manufacturer(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ char *manufacturer; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_STRING); -+ -+ dbus_message_iter_get_basic(i, &manufacturer); -+ if (b->modem->modem_manufacturer) -+ pa_xfree(b->modem->modem_manufacturer); -+ b->modem->modem_manufacturer = pa_xstrdup(manufacturer); -+ -+ pa_log_debug("Modem manufacturer: %s", b->modem->modem_manufacturer); -+} -+ -+static void parse_model(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ char *model; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_STRING); -+ -+ dbus_message_iter_get_basic(i, &model); -+ if (b->modem->modem_model) -+ pa_xfree(b->modem->modem_model); -+ b->modem->modem_model = pa_xstrdup(model); -+ -+ pa_log_debug("Modem model: %s", b->modem->modem_model); -+} -+ -+static void parse_revision(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ char *revision; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_STRING); -+ -+ dbus_message_iter_get_basic(i, &revision); -+ if (b->modem->modem_revision) -+ pa_xfree(b->modem->modem_revision); -+ b->modem->modem_revision = pa_xstrdup(revision); -+ -+ pa_log_debug("Modem revision: %s", b->modem->modem_revision); -+} -+ -+static void parse_imei(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ char *imei; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_STRING); -+ -+ dbus_message_iter_get_basic(i, &imei); -+ if (b->modem->modem_imei) -+ pa_xfree(b->modem->modem_imei); -+ b->modem->modem_imei = pa_xstrdup(imei); -+ -+ pa_log_debug("Modem IMEI: %s", b->modem->modem_imei); -+} -+ -+static void get_modem_properties_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ DBusMessageIter arg_i, element_i; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus Modem not available"); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("GetAll() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ goto finish; -+ } -+ -+ if (!dbus_message_iter_init(r, &arg_i) || !pa_streq(dbus_message_get_signature(r), "a{sv}")) { -+ pa_log_error("Invalid reply signature for GetAll()"); -+ goto finish; -+ } -+ -+ dbus_message_iter_recurse(&arg_i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { -+ DBusMessageIter dict_i, variant_i; -+ const char *key; -+ -+ dbus_message_iter_recurse(&element_i, &dict_i); -+ -+ /* Retrieve property name */ -+ key = check_variant_property(&dict_i); -+ if (key == NULL) { -+ pa_log_error("Received invalid property!"); -+ break; -+ } -+ -+ /* Retrieve and parse property value */ -+ dbus_message_iter_recurse(&dict_i, &variant_i); -+ -+ if(pa_streq(key, MM_MODEM_PROPERTY_OWNNUMBERS)) -+ parse_own_number(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER)) -+ parse_imei(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_MANUFACTURER)) -+ parse_manufacturer(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_MODEL)) -+ parse_model(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_REVISION)) -+ parse_revision(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_SIGNALQUALITY)) -+ parse_signal_quality(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_STATE)) -+ parse_state(b, &variant_i); -+ -+ dbus_message_iter_next(&element_i); -+ } -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static void get_modem_3gpp_properties_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ DBusMessageIter arg_i, element_i; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus Modem 3GPP not available"); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("GetAll() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ goto finish; -+ } -+ -+ if (!dbus_message_iter_init(r, &arg_i) || !pa_streq(dbus_message_get_signature(r), "a{sv}")) { -+ pa_log_error("Invalid reply signature for GetAll()"); -+ goto finish; -+ } -+ -+ dbus_message_iter_recurse(&arg_i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { -+ DBusMessageIter dict_i, variant_i; -+ const char *key; -+ -+ dbus_message_iter_recurse(&element_i, &dict_i); -+ -+ /* Retrieve property name */ -+ key = check_variant_property(&dict_i); -+ if (key == NULL) { -+ pa_log_error("Received invalid property!"); -+ break; -+ } -+ -+ /* Retrieve and parse property value */ -+ dbus_message_iter_recurse(&dict_i, &variant_i); -+ -+ if(pa_streq(key, MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)) -+ parse_registration(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE)) -+ parse_operator_code(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME)) -+ parse_operator_name(b, &variant_i); -+ -+ dbus_message_iter_next(&element_i); -+ } -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static void get_call_properties_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ DBusMessageIter arg_i, element_i; -+ char *call_object; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(call_object = p->call_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus Call not available"); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("GetAll() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ goto finish; -+ } -+ -+ if (!dbus_message_iter_init(r, &arg_i) || !pa_streq(dbus_message_get_signature(r), "a{sv}")) { -+ pa_log_error("Invalid reply signature for GetAll()"); -+ goto finish; -+ } -+ -+ dbus_message_iter_recurse(&arg_i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { -+ DBusMessageIter dict_i, variant_i; -+ const char *key; -+ -+ dbus_message_iter_recurse(&element_i, &dict_i); -+ -+ /* Retrieve property name */ -+ key = check_variant_property(&dict_i); -+ if (key == NULL) { -+ pa_log_error("Received invalid property!"); -+ break; -+ } -+ -+ /* Retrieve and parse property value */ -+ dbus_message_iter_recurse(&dict_i, &variant_i); -+ -+ if(pa_streq(key, MM_CALL_PROPERTY_NUMBER)) -+ parse_call_number(b, &variant_i, call_object); -+ else if(pa_streq(key, MM_CALL_PROPERTY_STATE)) -+ parse_call_state(b, &variant_i, call_object); -+ else if(pa_streq(key, MM_CALL_PROPERTY_DIRECTION)) -+ parse_call_direction(b, &variant_i, call_object); -+ -+ dbus_message_iter_next(&element_i); -+ } -+ -+ /* Notify change for call */ -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_CALLS_CHANGED), b); -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+ -+ pa_xfree(call_object); -+} -+ -+static void parse_calls(pa_modemmanager_backend *b, DBusMessageIter *i) { -+ const char *mm_call_interface = MM_DBUS_INTERFACE_CALL; -+ const char *call_object; -+ DBusMessageIter element_i; -+ DBusMessage *m; -+ -+ pa_assert(i); -+ pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_ARRAY); -+ -+ /* Iterate over array of dictonaries */ -+ dbus_message_iter_recurse(i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_OBJECT_PATH) { -+ dbus_message_iter_get_basic(&element_i, &call_object); -+ -+ if (pa_hashmap_put(b->calls, pa_xstrdup(call_object), pa_xnew0(call_status_t, 1)) != 0) -+ pa_log_error("Call %s already exist", call_object); -+ -+ /* Retrieve call properties */ -+ pa_assert_se(m = dbus_message_new_method_call(MM_DBUS_SERVICE, call_object, DBUS_INTERFACE_PROPERTIES, DBUS_INTERFACE_PROPERTIES_METHOD_GETALL)); -+ pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &mm_call_interface, DBUS_TYPE_INVALID)); -+ send_and_add_to_pending(b, m, get_call_properties_reply, pa_xstrdup(call_object)); -+ -+ // FIXME: Implement three-way calling. Only the first call is used. -+ return; -+ -+ dbus_message_iter_next(&element_i); -+ } -+} -+ -+static void get_modem_voice_properties_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ DBusMessageIter arg_i, element_i; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus Modem Voice not available"); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("GetAll() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ goto finish; -+ } -+ -+ if (!dbus_message_iter_init(r, &arg_i) || !pa_streq(dbus_message_get_signature(r), "a{sv}")) { -+ pa_log_error("Invalid reply signature for GetAll()"); -+ goto finish; -+ } -+ -+ dbus_message_iter_recurse(&arg_i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { -+ DBusMessageIter dict_i, variant_i; -+ const char *key; -+ -+ dbus_message_iter_recurse(&element_i, &dict_i); -+ -+ /* Retrieve property name */ -+ key = check_variant_property(&dict_i); -+ if (key == NULL) { -+ pa_log_error("Received invalid property!"); -+ break; -+ } -+ -+ /* Retrieve and parse property value */ -+ dbus_message_iter_recurse(&dict_i, &variant_i); -+ -+ if(pa_streq(key, MM_MODEM_VOICE_PROPERTY_CALLS)) -+ parse_calls(b, &variant_i); -+ -+ dbus_message_iter_next(&element_i); -+ } -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static void parse_interfaces_and_properties(pa_modemmanager_backend *b, DBusMessageIter *dict_i) { -+ DBusMessage *m; -+ DBusMessageIter element_i; -+ const char *path; -+ const char *mm_modem_interface = MM_DBUS_INTERFACE_MODEM; -+ const char *mm_modem_3gpp_interface = MM_DBUS_INTERFACE_MODEM_MODEM3GPP; -+ const char *mm_modem_voice_interface = MM_DBUS_INTERFACE_MODEM_VOICE; -+ -+ pa_assert(dbus_message_iter_get_arg_type(dict_i) == DBUS_TYPE_OBJECT_PATH); -+ dbus_message_iter_get_basic(dict_i, &path); -+ -+ pa_assert_se(dbus_message_iter_next(dict_i)); -+ pa_assert(dbus_message_iter_get_arg_type(dict_i) == DBUS_TYPE_ARRAY); -+ -+ dbus_message_iter_recurse(dict_i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { -+ DBusMessageIter dict_i; -+ const char *interface; -+ -+ dbus_message_iter_recurse(&element_i, &dict_i); -+ -+ pa_assert(dbus_message_iter_get_arg_type(&dict_i) == DBUS_TYPE_STRING); -+ dbus_message_iter_get_basic(&dict_i, &interface); -+ -+ pa_assert_se(dbus_message_iter_next(&dict_i)); -+ pa_assert(dbus_message_iter_get_arg_type(&dict_i) == DBUS_TYPE_ARRAY); -+ -+ /* ModemManager Modem inteface */ -+ if (pa_streq(interface, MM_DBUS_INTERFACE_MODEM)) { -+ pa_log_debug("Modem Interface %s found", path); -+ b->mm_modem = pa_xstrdup(path); -+ -+ /* Retrieve all modem properties */ -+ pa_assert_se(m = dbus_message_new_method_call(MM_DBUS_SERVICE, b->mm_modem, DBUS_INTERFACE_PROPERTIES, DBUS_INTERFACE_PROPERTIES_METHOD_GETALL)); -+ pa_assert_se(dbus_message_append_args(m, -+ DBUS_TYPE_STRING, &mm_modem_interface, -+ DBUS_TYPE_INVALID)); -+ send_and_add_to_pending(b, m, get_modem_properties_reply, NULL); -+ /* ModemManager Modem 3GPP interface */ -+ } else if (pa_streq(interface, MM_DBUS_INTERFACE_MODEM_MODEM3GPP)) { -+ pa_log_debug("Modem 3GPP Interface %s found", path); -+ b->mm_modem_3gpp = pa_xstrdup(path); -+ -+ /* Retrieve all network properties */ -+ pa_assert_se(m = dbus_message_new_method_call(MM_DBUS_SERVICE, b->mm_modem_3gpp, DBUS_INTERFACE_PROPERTIES, DBUS_INTERFACE_PROPERTIES_METHOD_GETALL)); -+ pa_assert_se(dbus_message_append_args(m, -+ DBUS_TYPE_STRING, &mm_modem_3gpp_interface, -+ DBUS_TYPE_INVALID)); -+ send_and_add_to_pending(b, m, get_modem_3gpp_properties_reply, NULL); -+ /* ModemManager Modem Voice interface */ -+ } else if (pa_streq(interface, MM_DBUS_INTERFACE_MODEM_VOICE)) { -+ pa_log_debug("Modem Voice Interface %s found", path); -+ b->mm_modem_voice = pa_xstrdup(path); -+ -+ /* Retrieve current call list and properties */ -+ pa_assert_se(m = dbus_message_new_method_call(MM_DBUS_SERVICE, b->mm_modem_voice, DBUS_INTERFACE_PROPERTIES, DBUS_INTERFACE_PROPERTIES_METHOD_GETALL)); -+ pa_assert_se(dbus_message_append_args(m, -+ DBUS_TYPE_STRING, &mm_modem_voice_interface, -+ DBUS_TYPE_INVALID)); -+ send_and_add_to_pending(b, m, get_modem_voice_properties_reply, NULL); -+ } else -+ pa_log_debug("Unknown interface %s found, skipping", interface); -+ -+ dbus_message_iter_next(&element_i); -+ } -+ -+ return; -+} -+ -+static void invalidate_modem_properties(pa_modemmanager_backend *b) { -+ if (b->modem) { -+ if (b->modem->modem_manufacturer) { -+ pa_xfree(b->modem->modem_manufacturer); -+ b->modem->modem_manufacturer = NULL; -+ } -+ if (b->modem->modem_model) { -+ pa_xfree(b->modem->modem_model); -+ b->modem->modem_model = NULL; -+ } -+ if (b->modem->modem_revision) { -+ pa_xfree(b->modem->modem_revision); -+ b->modem->modem_revision = NULL; -+ } -+ if (b->modem->modem_imei) { -+ pa_xfree(b->modem->modem_imei); -+ b->modem->modem_imei = NULL; -+ } -+ if (b->modem->modem_own_number) { -+ pa_xfree(b->modem->modem_own_number); -+ b->modem->modem_own_number = NULL; -+ } -+ } -+} -+ -+static void invalidate_modem_3gpp_properties(pa_modemmanager_backend *b) { -+ if (b->modem) { -+ if (b->modem->network_operator_name) { -+ pa_xfree(b->modem->network_operator_name); -+ b->modem->network_operator_name = NULL; -+ } -+ if (b->modem->network_operator_code) { -+ pa_xfree(b->modem->network_operator_code); -+ b->modem->network_operator_code = NULL; -+ } -+ b->modem->network_has_service = false; -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_HAS_SERVICE_CHANGED), b); -+ b->modem->network_is_roaming = false; -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_IS_ROAMING_CHANGED), b); -+ b->modem->network_signal_strength = 0; -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_SIGNAL_STRENGTH_CHANGED), b); -+ } -+} -+ -+static void invalidate_modem_voice_properties(pa_modemmanager_backend *b) { -+ call_status_t *c = NULL; -+ void *state = NULL; -+ -+ /* Remove all call objects */ -+ if (b->calls) { -+ while ((c = pa_hashmap_iterate(b->calls, &state, NULL))) { -+ if (!c) -+ continue; -+ -+ if (c->number) -+ pa_xfree(c->number); -+ pa_hashmap_remove_and_free(b->calls, c); -+ } -+ -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_CALLS_CHANGED), b); -+ } -+} -+ -+static void get_managed_objects_reply(DBusPendingCall *pending, void *userdata) { -+ pa_dbus_pending *p; -+ pa_modemmanager_backend *b; -+ DBusMessage *r; -+ DBusMessageIter arg_i, element_i; -+ -+ pa_assert(pending); -+ pa_assert_se(p = userdata); -+ pa_assert_se(b = p->context_data); -+ pa_assert_se(r = dbus_pending_call_steal_reply(pending)); -+ -+ if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { -+ pa_log_warn("ModemManager D-Bus ObjectManager not available"); -+ goto finish; -+ } -+ -+ if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { -+ pa_log_error("GetManagedObjects() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); -+ goto finish; -+ } -+ -+ if (!dbus_message_iter_init(r, &arg_i) || !pa_streq(dbus_message_get_signature(r), "a{oa{sa{sv}}}")) { -+ pa_log_error("Invalid reply signature for GetManagedObjects()"); -+ goto finish; -+ } -+ -+ dbus_message_iter_recurse(&arg_i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { -+ DBusMessageIter dict_i; -+ -+ dbus_message_iter_recurse(&element_i, &dict_i); -+ parse_interfaces_and_properties(b, &dict_i); -+ dbus_message_iter_next(&element_i); -+ } -+ -+finish: -+ dbus_message_unref(r); -+ -+ PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); -+ pa_dbus_pending_free(p); -+} -+ -+static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) { -+ DBusError err; -+ DBusMessage *m2; -+ const char *mm_call_interface = MM_DBUS_INTERFACE_CALL; -+ pa_modemmanager_backend *b = data; -+ const char *path, *interface, *member; -+ -+ pa_assert(bus); -+ pa_assert(m); -+ pa_assert(b); -+ -+ dbus_error_init(&err); -+ -+ path = dbus_message_get_path(m); -+ interface = dbus_message_get_interface(m); -+ member = dbus_message_get_member(m); -+ -+ pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member); -+ -+ /* ModemManager D-Bus status change */ -+ if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, DBUS_INTERFACE_DBUS_SIGNAL_NAMEOWNERCHANGED)) { -+ const char *name, *old_owner, *new_owner; -+ -+ if (!dbus_message_get_args(m, &err, -+ DBUS_TYPE_STRING, &name, -+ DBUS_TYPE_STRING, &old_owner, -+ DBUS_TYPE_STRING, &new_owner, -+ DBUS_TYPE_INVALID)) { -+ pa_log_error("Failed to parse " DBUS_INTERFACE_DBUS ".NameOwnerChanged: %s", err.message); -+ goto fail; -+ } -+ -+ if (pa_streq(name, MM_DBUS_SERVICE)) { -+ -+ /* ModemManager disappeared from D-Bus */ -+ if (old_owner && *old_owner) { -+ pa_log_debug("ModemManager disappeared from D-Bus"); -+ if (b->mm_bus_id) -+ pa_xfree(b->mm_bus_id); -+ b->mm_bus_id = NULL; -+ if (b->mm_modem) -+ pa_xfree(b->mm_modem); -+ b->mm_modem = NULL; -+ if (b->mm_modem_3gpp) -+ pa_xfree(b->mm_modem_3gpp); -+ b->mm_modem_3gpp = NULL; -+ if (b->mm_modem_voice) -+ pa_xfree(b->mm_modem_voice); -+ b->mm_modem_voice = NULL; -+ -+ /* Invalidate all properties since ModemManager is unavailable */ -+ invalidate_modem_properties(b); -+ invalidate_modem_3gpp_properties(b); -+ invalidate_modem_voice_properties(b); -+ } -+ -+ /* ModemManager appeared on D-Bus, properties are refreshed through the InterfacesAdded signal callback */ -+ if (new_owner && *new_owner) { -+ pa_log_debug("ModemManager appeared on D-Bus"); -+ b->mm_bus_id = pa_xstrdup(dbus_message_get_sender(m)); -+ if (b->modem) -+ pa_xfree(b->modem); -+ b->modem = pa_xnew0(modem_status_t, 1); -+ } -+ } -+ -+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -+ } -+ /* Modem added, refresh managed objects */ -+ else if (dbus_message_is_signal(m, DBUS_INTERFACE_OBJECT_MANAGER, DBUS_INTERFACE_OBJECT_MANAGER_SIGNAL_INTERFACESADDED)) { -+ DBusMessageIter arg_i; -+ -+ if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oa{sa{sv}}")) { -+ pa_log_error("Invalid signature found in InterfacesAdded"); -+ goto fail; -+ } -+ -+ parse_interfaces_and_properties(b, &arg_i); -+ } -+ /* Modem removed, refresh managed objects */ -+ else if (dbus_message_is_signal(m, DBUS_INTERFACE_OBJECT_MANAGER, DBUS_INTERFACE_OBJECT_MANAGER_SIGNAL_INTERFACESREMOVED)) { -+ const char *p; -+ DBusMessageIter arg_i; -+ DBusMessageIter element_i; -+ -+ if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "oas")) { -+ pa_log_error("Invalid signature found in InterfacesRemoved"); -+ goto fail; -+ } -+ -+ dbus_message_iter_get_basic(&arg_i, &p); -+ -+ pa_assert_se(dbus_message_iter_next(&arg_i)); -+ pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY); -+ -+ dbus_message_iter_recurse(&arg_i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_STRING) { -+ const char *iface; -+ -+ dbus_message_iter_get_basic(&element_i, &iface); -+ -+ /* ModemManager Modem interface removed */ -+ if (pa_streq(iface, MM_DBUS_INTERFACE_MODEM)) { -+ if (b->mm_modem) { -+ pa_xfree(b->mm_modem); -+ b->mm_modem = NULL; -+ } -+ invalidate_modem_properties(b); -+ pa_log_debug("Modem Interface removed"); -+ } -+ -+ /* ModemManager Modem 3GPP interface removed */ -+ if (pa_streq(iface, MM_DBUS_INTERFACE_MODEM_MODEM3GPP)) { -+ if (b->mm_modem_3gpp) { -+ pa_xfree(b->mm_modem_3gpp); -+ b->mm_modem_3gpp = NULL; -+ } -+ invalidate_modem_3gpp_properties(b); -+ pa_log_debug("Modem 3GPP Interface removed"); -+ } -+ -+ /* ModemManager Modem Voice interface removed */ -+ if (pa_streq(iface, MM_DBUS_INTERFACE_MODEM_VOICE)) { -+ if (b->mm_modem_voice) { -+ pa_xfree(b->mm_modem_voice); -+ b->mm_modem_voice = NULL; -+ } -+ invalidate_modem_voice_properties(b); -+ pa_log_debug("Modem Voice Interface removed"); -+ } -+ -+ dbus_message_iter_next(&element_i); -+ } -+ -+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -+ } -+ /* Update properties if updated by ModemManager */ -+ else if (dbus_message_is_signal(m, DBUS_INTERFACE_PROPERTIES, DBUS_INTERFACE_PROPERTIES_SIGNAL_PROPERTIESCHANGED)) { -+ DBusMessageIter arg_i, element_i; -+ -+ if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "sa{sv}as")) { -+ pa_log_error("Invalid signature found in PropertiesChanged"); -+ goto fail; -+ } -+ -+ /* Skip interface name */ -+ pa_assert_se(dbus_message_iter_next(&arg_i)); -+ pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY); -+ -+ dbus_message_iter_recurse(&arg_i, &element_i); -+ -+ while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { -+ DBusMessageIter dict_i, variant_i; -+ const char *key; -+ -+ dbus_message_iter_recurse(&element_i, &dict_i); -+ -+ /* Retrieve property name and parse value */ -+ key = check_variant_property(&dict_i); -+ if (key == NULL) { -+ pa_log_error("Received invalid property!"); -+ break; -+ } -+ dbus_message_iter_recurse(&dict_i, &variant_i); -+ -+ /* -+ * ModemManager Modem interface -+ * See https://www.freedesktop.org/software/ModemManager/api/latest/gdbus-org.freedesktop.ModemManager1.Modem.html -+ */ -+ if(b->mm_modem && pa_streq(path, b->mm_modem)) { -+ pa_log_debug("ModemManager Modem property updated: %s", key); -+ -+ if(pa_streq(key, MM_MODEM_PROPERTY_OWNNUMBERS)) -+ parse_own_number(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER)) -+ parse_imei(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_MANUFACTURER)) -+ parse_manufacturer(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_MODEL)) -+ parse_model(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_REVISION)) -+ parse_revision(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_SIGNALQUALITY)) -+ parse_signal_quality(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_PROPERTY_STATE)) -+ parse_state(b, &variant_i); -+ } -+ -+ /* -+ * ModemManager Modem 3GPP interface -+ * See https://www.freedesktop.org/software/ModemManager/api/latest/gdbus-org.freedesktop.ModemManager1.Modem.Modem3gpp.html -+ */ -+ if(b->mm_modem_3gpp && pa_streq(path, b->mm_modem_3gpp)) { -+ pa_log_debug("ModemManager Modem 3GPP property updated: %s", key); -+ -+ if(pa_streq(key, MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)) -+ parse_registration(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE)) -+ parse_operator_code(b, &variant_i); -+ else if(pa_streq(key, MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME)) -+ parse_operator_name(b, &variant_i); -+ } -+ -+ dbus_message_iter_next(&element_i); -+ } -+ } -+ /* Call started */ -+ else if (dbus_message_is_signal(m, MM_DBUS_INTERFACE_MODEM_VOICE, MM_MODEM_VOICE_SIGNAL_CALLADDED)) { -+ DBusMessageIter arg_i; -+ char *call_object; -+ -+ if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "o")) { -+ pa_log_error("Invalid signature found in CallAdded"); -+ goto fail; -+ } -+ -+ /* Create call state */ -+ dbus_message_iter_get_basic(&arg_i, &call_object); -+ pa_log_debug("Call added: %s", call_object); -+ -+ if (pa_hashmap_put(b->calls, pa_xstrdup(call_object), pa_xnew0(call_status_t, 1)) != 0) -+ pa_log_error("Call %s already exist", call_object); -+ -+ /* Retrieve call properties */ -+ pa_assert_se(m2 = dbus_message_new_method_call(MM_DBUS_SERVICE, call_object, DBUS_INTERFACE_PROPERTIES, DBUS_INTERFACE_PROPERTIES_METHOD_GETALL)); -+ pa_assert_se(dbus_message_append_args(m2, DBUS_TYPE_STRING, &mm_call_interface, DBUS_TYPE_INVALID)); -+ send_and_add_to_pending(b, m2, get_call_properties_reply, pa_xstrdup(call_object)); -+ } -+ /* Call rejected or ended */ -+ else if (dbus_message_is_signal(m, MM_DBUS_INTERFACE_MODEM_VOICE, MM_MODEM_VOICE_SIGNAL_CALLDELETED)) { -+ DBusMessageIter arg_i; -+ char *call_object; -+ -+ if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "o")) { -+ pa_log_error("Invalid signature found in CallDeleted"); -+ goto fail; -+ } -+ -+ /* Remove call state */ -+ dbus_message_iter_get_basic(&arg_i, &call_object); -+ pa_log_debug("Call removed: %s", call_object); -+ pa_hashmap_remove_and_free(b->calls, call_object); -+ -+ /* Notify about call deletion */ -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_CALLS_CHANGED), b); -+ } -+ /* Call state updated */ -+ else if (dbus_message_is_signal(m, MM_DBUS_INTERFACE_CALL, MM_CALL_SIGNAL_STATECHANGED)) { -+ DBusMessageIter arg_i; -+ -+ pa_log_debug("Call %s: state updated", path); -+ -+ if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "iiu")) { -+ pa_log_error("Invalid signature found in StateChanged"); -+ goto fail; -+ } -+ -+ /* Skip old call state */ -+ pa_assert_se(dbus_message_iter_next(&arg_i)); -+ -+ /* Parse new call state */ -+ pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_INT32); -+ parse_call_state(b, &arg_i, path); -+ -+ /* Skip call state change reason */ -+ pa_assert_se(dbus_message_iter_next(&arg_i)); -+ -+ /* Notify change for call */ -+ pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, -+ PA_BLUETOOTH_HOOK_HOST_CALLS_CHANGED), b); -+ } -+ -+fail: -+ dbus_error_free(&err); -+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -+} -+ -+/* Accept an incoming call */ -+void pa_modemmanager_accept_call(pa_modemmanager_backend *backend, char *call) { -+ DBusMessage *m; -+ call_status_t *call_state; -+ -+ /* Check if call is incoming ringing */ -+ call_state = pa_hashmap_get(backend->calls, call); -+ if (!call_state || call_state->status != PA_MODEMMANAGER_CALL_STATE_RINGING || !call_state->is_incoming) { -+ pa_log_error("Call is not ringing and/or incoming, unable to accept call"); -+ pa_hook_fire(pa_bluetooth_discovery_hook(backend->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), backend); -+ return; -+ } -+ -+ /* Accept call */ -+ pa_assert_se(m = dbus_message_new_method_call(MM_DBUS_SERVICE, call, MM_DBUS_INTERFACE_CALL, MM_CALL_METHOD_ACCEPT)); -+ send_and_add_to_pending(backend, m, call_accept_reply, NULL); -+} -+ -+/* End a call */ -+void pa_modemmanager_end_call(pa_modemmanager_backend *backend, char *call) { -+ DBusMessage *m; -+ call_status_t *call_state; -+ -+ /* Check if call is active or incoming ringing */ -+ call_state = pa_hashmap_get(backend->calls, call); -+ if (!call_state || (call_state->status != PA_MODEMMANAGER_CALL_STATE_ACTIVE -+ && (call_state->status != PA_MODEMMANAGER_CALL_STATE_RINGING && call_state->is_incoming))) { -+ pa_log_error("Call is not active or incoming ringing, unable to hangup call"); -+ pa_hook_fire(pa_bluetooth_discovery_hook(backend->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), backend); -+ return; -+ } -+ -+ /* End call */ -+ pa_assert_se(m = dbus_message_new_method_call(MM_DBUS_SERVICE, call, MM_DBUS_INTERFACE_CALL, MM_CALL_METHOD_HANGUP)); -+ send_and_add_to_pending(backend, m, call_hangup_reply, NULL); -+} -+ -+/* Create a new call by dialing the provided number */ -+void pa_modemmanager_start_call(pa_modemmanager_backend *backend, char *number) { -+ DBusMessage *m; -+ DBusMessageIter i, d; -+ char *call_number; -+ -+ /* Create call for filtered number */ -+ pa_assert_se(m = dbus_message_new_method_call(MM_DBUS_SERVICE, backend->mm_modem, MM_DBUS_INTERFACE_MODEM_VOICE, MM_MODEM_VOICE_METHOD_CREATECALL)); -+ dbus_message_iter_init_append(m, &i); -+ dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY, -+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING -+ DBUS_TYPE_STRING_AS_STRING -+ DBUS_TYPE_VARIANT_AS_STRING -+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, -+ &d); -+ call_number = pa_xstrdup(number); -+ pa_dbus_append_basic_variant_dict_entry(&d, "number", DBUS_TYPE_STRING, &call_number); -+ dbus_message_iter_close_container(&i, &d); -+ send_and_add_to_pending(backend, m, create_call_reply, NULL); -+} -+ -+/* Send a DTMF tone to a given call */ -+void pa_modemmanager_send_dtmf(pa_modemmanager_backend *backend, char *call, char *character) { -+ DBusMessage *m; -+ char *dtmf_char = pa_xstrdup(character); -+ call_status_t *call_state; -+ -+ /* Check if call is active */ -+ call_state = pa_hashmap_get(backend->calls, call); -+ if (call_state && (call_state->status != PA_MODEMMANAGER_CALL_STATE_ACTIVE)) { -+ pa_log_error("Call is not active, unable to send DTMF tone"); -+ pa_hook_fire(pa_bluetooth_discovery_hook(backend->discovery, -+ PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), backend); -+ return; -+ } -+ -+ /* Let ModemManager generate DTMF tone */ -+ pa_log_debug("Generating DTMF tone: '%s'", dtmf_char); -+ m = dbus_message_new_method_call(MM_DBUS_SERVICE, call, MM_DBUS_INTERFACE_CALL, MM_CALL_METHOD_SENDDTMF); -+ pa_assert_se(dbus_message_append_args(m, -+ DBUS_TYPE_STRING, &dtmf_char, -+ DBUS_TYPE_INVALID)); -+ send_and_add_to_pending(backend, m, send_dtmf_reply, NULL); -+} -+ -+/* Get network operator name */ -+char *pa_modemmanager_get_operator_name(const pa_modemmanager_backend *backend) { -+ return backend->modem->network_operator_name; -+} -+ -+/* Get network operator code */ -+char *pa_modemmanager_get_operator_code(const pa_modemmanager_backend *backend) { -+ return backend->modem->network_operator_code; -+} -+ -+/* Get service status */ -+bool pa_modemmanager_has_service(const pa_modemmanager_backend *backend) { -+ return backend->modem->network_has_service; -+} -+ -+/* Get roaming status */ -+bool pa_modemmanager_is_roaming(const pa_modemmanager_backend *backend) { -+ return backend->modem->network_is_roaming; -+} -+ -+/* Get signal strength percentage */ -+unsigned int pa_modemmanager_get_signal_strength(const pa_modemmanager_backend *backend) { -+ return backend->modem->network_signal_strength; -+} -+ -+/* Get all calls */ -+pa_hashmap *pa_modemmanager_get_calls(const pa_modemmanager_backend *backend) { -+ return backend->calls; -+} -+ -+/* Get active call */ -+char *pa_modemmanager_get_active_call_key(const pa_modemmanager_backend *backend) { -+ pa_hashmap *calls; -+ call_status_t *c; -+ const void *key; -+ void *state = NULL; -+ -+ calls = pa_modemmanager_get_calls(backend); -+ while ((c = pa_hashmap_iterate(calls, &state, &key))) { -+ if (key == NULL) -+ break; -+ /* FIXME: support three-way calling */ -+ return (char *) key; -+ } -+ -+ /* No active calls */ -+ return NULL; -+} -+ -+/* Get modem model */ -+char *pa_modemmanager_get_modem_model(const pa_modemmanager_backend *backend) { -+ return backend->modem->modem_model; -+} -+ -+/* Get modem manufacturer */ -+char *pa_modemmanager_get_modem_manufacturer(const pa_modemmanager_backend *backend) { -+ return backend->modem->modem_manufacturer; -+} -+ -+/* Get modem revision */ -+char *pa_modemmanager_get_modem_revision(const pa_modemmanager_backend *backend) { -+ return backend->modem->modem_revision; -+} -+ -+/* Get modem IMEI */ -+char *pa_modemmanager_get_modem_imei(const pa_modemmanager_backend *backend) { -+ return backend->modem->modem_imei; -+} -+ -+/* Get modem's own number */ -+char *pa_modemmanager_get_own_number(const pa_modemmanager_backend *backend) { -+ return backend->modem->modem_own_number; -+} -+ -+/* Check if modem is present */ -+bool pa_modemmanager_has_modem(const pa_modemmanager_backend *backend) { -+ if (!backend->mm_modem) -+ return false; -+ -+ if (!backend->mm_modem_3gpp) -+ return false; -+ -+ if (!backend->mm_modem_voice) -+ return false; -+ -+ if(!backend->modem) -+ return false; -+ -+ return true; -+} -+ -+pa_modemmanager_backend *pa_modemmanager_backend_new(pa_core *c, pa_bluetooth_discovery *d) { -+ pa_modemmanager_backend *backend; -+ DBusError err; -+ DBusMessage *m; -+ -+ pa_log_debug("Native backend enabled ModemManager modem & call status reporting"); -+ -+ backend = pa_xnew0(pa_modemmanager_backend, 1); -+ backend->core = c; -+ backend->discovery = d; -+ backend->calls = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); -+ backend->modem = pa_xnew0(modem_status_t, 1); -+ -+ /* Get DBus connection */ -+ dbus_error_init(&err); -+ if (!(backend->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) { -+ pa_log("Failed to get D-Bus connection: %s", err.message); -+ dbus_error_free(&err); -+ pa_xfree(backend); -+ return NULL; -+ } -+ -+ /* Add filter callback for DBus connection */ -+ if (!dbus_connection_add_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend, NULL)) { -+ pa_log_error("Failed to add filter function"); -+ pa_dbus_connection_unref(backend->connection); -+ pa_xfree(backend); -+ return NULL; -+ } -+ -+ /* Register for call & modem changes from ModemManager */ -+ if (pa_dbus_add_matches(pa_dbus_connection_get(backend->connection), &err, -+ "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='" DBUS_INTERFACE_DBUS_SIGNAL_NAMEOWNERCHANGED "'," -+ "arg0='" MM_DBUS_SERVICE "'", -+ "type='signal',sender='" MM_DBUS_SERVICE "',interface='" DBUS_INTERFACE_OBJECT_MANAGER "',member='" DBUS_INTERFACE_OBJECT_MANAGER_SIGNAL_INTERFACESADDED "'", -+ "type='signal',sender='" MM_DBUS_SERVICE "',interface='" DBUS_INTERFACE_OBJECT_MANAGER "',member='" DBUS_INTERFACE_OBJECT_MANAGER_SIGNAL_INTERFACESREMOVED "'", -+ "type='signal',sender='" MM_DBUS_SERVICE "',interface='" DBUS_INTERFACE_PROPERTIES "',member='" DBUS_INTERFACE_PROPERTIES_SIGNAL_PROPERTIESCHANGED "'", -+ "type='signal',sender='" MM_DBUS_SERVICE "',interface='" MM_DBUS_INTERFACE_MODEM_VOICE "',member='" MM_MODEM_VOICE_SIGNAL_CALLADDED "'", -+ "type='signal',sender='" MM_DBUS_SERVICE "',interface='" MM_DBUS_INTERFACE_MODEM_VOICE "',member='" MM_MODEM_VOICE_SIGNAL_CALLDELETED "'", -+ "type='signal',sender='" MM_DBUS_SERVICE "',interface='" MM_DBUS_INTERFACE_CALL "',member='" MM_CALL_SIGNAL_STATECHANGED "'", -+ NULL) < 0) { -+ pa_log("Failed to add ModemManager D-Bus matches: %s", err.message); -+ dbus_connection_remove_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend); -+ pa_dbus_connection_unref(backend->connection); -+ pa_xfree(backend); -+ return NULL; -+ } -+ -+ /* Initialize list of modems by requesting it from ModemManager */ -+ pa_assert_se(m = dbus_message_new_method_call(MM_DBUS_SERVICE, MM_DBUS_PATH, DBUS_INTERFACE_OBJECT_MANAGER, DBUS_INTERFACE_OBJECT_MANAGER_METHOD_GETMANAGEDOBJECTS)); -+ send_and_add_to_pending(backend, m, get_managed_objects_reply, NULL); -+ -+ return backend; -+} -+ -+void pa_modemmanager_backend_free(pa_modemmanager_backend *backend) { -+ pa_assert(backend); -+ -+ pa_dbus_free_pending_list(&backend->pending); -+ -+ pa_dbus_connection_unref(backend->connection); -+ -+ invalidate_modem_properties(backend); -+ invalidate_modem_3gpp_properties(backend); -+ invalidate_modem_voice_properties(backend); -+ -+ pa_xfree(backend); -+} -+ -diff --git a/src/modules/bluetooth/modemmanager.h b/src/modules/bluetooth/modemmanager.h -new file mode 100644 -index 000000000..9a1d82219 ---- /dev/null -+++ b/src/modules/bluetooth/modemmanager.h -@@ -0,0 +1,98 @@ -+#pragma once -+ -+/*** -+ This file is part of PulseAudio. -+ -+ Copyright 2022 Dylan Van Assche -+ -+ PulseAudio is free software; you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of the -+ License, or (at your option) any later version. -+ -+ PulseAudio is distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with PulseAudio; if not, see . -+***/ -+ -+#include "bluez5-util.h" -+#include "ModemManager.h" -+ -+#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager" -+#define DBUS_INTERFACE_OBJECT_MANAGER_METHOD_GETMANAGEDOBJECTS "GetManagedObjects" -+#define DBUS_INTERFACE_OBJECT_MANAGER_SIGNAL_INTERFACESADDED "InterfacesAdded" -+#define DBUS_INTERFACE_OBJECT_MANAGER_SIGNAL_INTERFACESREMOVED "InterfacesRemoved" -+#define DBUS_INTERFACE_DBUS_SIGNAL_NAMEOWNERCHANGED "NameOwnerChanged" -+#define DBUS_INTERFACE_PROPERTIES_METHOD_GETALL "GetAll" -+#define DBUS_INTERFACE_PROPERTIES_SIGNAL_PROPERTIESCHANGED "PropertiesChanged" -+ -+#define MAX_NUMBER_LENGTH 30 -+ -+#define STR_VALUE(x) STR(x) -+#define STR(x) #x -+ -+typedef enum pa_modemmanager_call_state { -+ PA_MODEMMANAGER_CALL_STATE_INVALID = 0, -+ PA_MODEMMANAGER_CALL_STATE_ACTIVE = 1, -+ PA_MODEMMANAGER_CALL_STATE_RINGING = 2, -+ PA_MODEMMANAGER_CALL_STATE_DIALING = 3, -+ PA_MODEMMANAGER_CALL_STATE_TERMINATED = 4 -+ /* FIXME: implement three-way calling */ -+} pa_modemmanager_call_state_t; -+ -+typedef struct call_status { -+ bool is_incoming; -+ pa_modemmanager_call_state_t status; -+ char *number; -+} call_status_t; -+ -+typedef struct modem_status { -+ char *network_operator_name; -+ char *network_operator_code; -+ unsigned int network_signal_strength; -+ bool network_has_service; -+ bool network_is_roaming; -+ char *modem_own_number; -+ char *modem_manufacturer; -+ char *modem_model; -+ char *modem_revision; -+ char *modem_imei; -+} modem_status_t; -+ -+struct pa_modemmanager_backend { -+ pa_core *core; -+ pa_dbus_connection *connection; -+ pa_bluetooth_discovery *discovery; -+ char *mm_bus_id; -+ char *mm_modem; -+ char *mm_modem_3gpp; -+ char *mm_modem_voice; -+ pa_hashmap *calls; -+ modem_status_t *modem; -+ -+ PA_LLIST_HEAD(pa_dbus_pending, pending); -+}; -+ -+pa_modemmanager_backend *pa_modemmanager_backend_new(pa_core *c, pa_bluetooth_discovery *d); -+void pa_modemmanager_backend_free(pa_modemmanager_backend *backend); -+bool pa_modemmanager_has_modem(const pa_modemmanager_backend *backend); -+void pa_modemmanager_accept_call(pa_modemmanager_backend *backend, char *call); -+void pa_modemmanager_end_call(pa_modemmanager_backend *backend, char *call); -+void pa_modemmanager_start_call(pa_modemmanager_backend *backend, char *number); -+void pa_modemmanager_send_dtmf(pa_modemmanager_backend *backend, char *call, char *character); -+pa_hashmap *pa_modemmanager_get_calls(const pa_modemmanager_backend *backend); -+char *pa_modemmanager_get_active_call_key(const pa_modemmanager_backend *backend); -+char *pa_modemmanager_get_operator_name(const pa_modemmanager_backend *backend); -+char *pa_modemmanager_get_operator_code(const pa_modemmanager_backend *backend); -+bool pa_modemmanager_has_service(const pa_modemmanager_backend *backend); -+bool pa_modemmanager_is_roaming(const pa_modemmanager_backend *backend); -+unsigned int pa_modemmanager_get_signal_strength(const pa_modemmanager_backend *backend); -+char *pa_modemmanager_get_modem_model(const pa_modemmanager_backend *backend); -+char *pa_modemmanager_get_modem_manufacturer(const pa_modemmanager_backend *backend); -+char *pa_modemmanager_get_modem_revision(const pa_modemmanager_backend *backend); -+char *pa_modemmanager_get_modem_imei(const pa_modemmanager_backend *backend); -+char *pa_modemmanager_get_own_number(const pa_modemmanager_backend *backend); --- -2.35.1 - diff --git a/temp/pulseaudio/0006-bluetooth-only-reply-OK-for-supported-AT-cmds.patch b/temp/pulseaudio/0006-bluetooth-only-reply-OK-for-supported-AT-cmds.patch deleted file mode 100644 index 770ac8375..000000000 --- a/temp/pulseaudio/0006-bluetooth-only-reply-OK-for-supported-AT-cmds.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 72b92267a8f906a3ecd10c571407802810e01bcc Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Wed, 13 Apr 2022 18:27:44 +0200 -Subject: [PATCH 06/26] bluetooth: only reply OK for supported AT cmds - -PulseAudio should always be honest to Bluetooth devices even when audio is connected. ---- - src/modules/bluetooth/backend-native.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index a490d6efd..1fadb4b14 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -2,6 +2,7 @@ - This file is part of PulseAudio. - - Copyright 2014 Wim Taymans -+ Copyright 2021-2022 Dylan Van Assche - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as -@@ -808,12 +809,8 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - return false; - } - -- /* -- * once we're fully connected, just reply OK to everything -- * it will just be the headset sending the occasional status -- * update, but we process only the ones we care about -- */ -- return true; -+ /* Unsupported commands return ERROR */ -+ return false - } - - static int get_rfcomm_fd (pa_bluetooth_discovery *discovery) { --- -2.35.1 - diff --git a/temp/pulseaudio/0007-bluetooth-Always-reply-to-AT-CIND.patch b/temp/pulseaudio/0007-bluetooth-Always-reply-to-AT-CIND.patch deleted file mode 100644 index 0e777f410..000000000 --- a/temp/pulseaudio/0007-bluetooth-Always-reply-to-AT-CIND.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 81045feccb25b627c2c6cfc105c27b2599573fd2 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Wed, 13 Apr 2022 18:29:08 +0200 -Subject: [PATCH 07/26] bluetooth: Always reply to AT+CIND - -Once the stateful negotiation is complete, still reply -to AT+CIND? and AT+CIND=? since we will report actual data here -such as cellular service status, roaming, signal, and battery level. ---- - src/modules/bluetooth/backend-native.c | 22 ++++++++++++++++++---- - 1 file changed, 18 insertions(+), 4 deletions(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 1fadb4b14..77792146a 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -686,7 +686,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - /* no state change */ - - return true; -- } else if (c->state == 1 && pa_startswith(buf, "AT+CIND=?")) { -+ } else if (c->state >= 1 && pa_startswith(buf, "AT+CIND=?")) { - /* UPower backend available, declare support for more indicators */ - if (discovery->native_backend->upower) { - rfcomm_write_response(fd, "+CIND: " -@@ -700,15 +700,29 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - MANDATORY_CALL_INDICATORS "," - "(\"service\",(0-1))"); - } -- c->state = 2; -+ -+ /* -+ * Only change codec negotiation state when the first AT+CIND=? command is received -+ * Bluetooth HFP 1.8 specification specifies that this AT command is issued 'at least once'. -+ */ -+ if (c->state < 2) -+ c->state = 2; - - return true; -- } else if (c->state == 2 && pa_startswith(buf, "AT+CIND?")) { -+ } else if (c->state >= 2 && pa_startswith(buf, "AT+CIND?")) { - 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; -+ -+ /* -+ * Only change codec negotiation state when the first AT+CIND? command is received. -+ * The Bluetooth HFP 1.8 specification does not define how many times this command is issued. -+ * Some HF devices issue this one multiple times breaking the codec negotiation stateful state, -+ * so only update the state once. -+ */ -+ if (c->state < 3) -+ c->state = 3; - - return true; - } else if ((c->state == 2 || c->state == 3) && pa_startswith(buf, "AT+CMER=")) { --- -2.35.1 - diff --git a/temp/pulseaudio/0008-bluetooth-support-AT-CMEE.patch b/temp/pulseaudio/0008-bluetooth-support-AT-CMEE.patch deleted file mode 100644 index 93a8609b4..000000000 --- a/temp/pulseaudio/0008-bluetooth-support-AT-CMEE.patch +++ /dev/null @@ -1,197 +0,0 @@ -From ff2d7b76bf4878f47a2df1261219c9d9e14f8c9e Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Wed, 13 Apr 2022 19:56:41 +0200 -Subject: [PATCH 08/26] bluetooth: support AT+CMEE - -AT+CMEE is now supported and extended error messages are returned -when an ERROR occurs. By default, these error codes are disabled, -the HF must enable them explicitely with AT+CMEE=1 (numeric mode). ---- - src/modules/bluetooth/backend-native.c | 71 +++++++++++++++++++++----- - src/modules/bluetooth/bluez5-util.h | 6 +++ - 2 files changed, 65 insertions(+), 12 deletions(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 77792146a..3110c5ef2 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -57,6 +57,7 @@ struct pa_bluetooth_backend { - bool enable_hsp_hs; - bool enable_hfp_hf; - bool cmer_indicator_reporting_enabled; -+ bool cmee_extended_error_reporting_enabled; - uint32_t cind_enabled_indicators; - - PA_LLIST_HEAD(pa_dbus_pending, pending); -@@ -125,7 +126,7 @@ typedef enum pa_bluetooth_ag_to_hf_indicators { - /* gateway features we support, which is as little as we can get away with */ - static uint32_t hfp_features = - /* HFP 1.6 requires this */ -- (1 << HFP_AG_ESTATUS ) | (1 << HFP_AG_CODECS) | (1 << HFP_AG_INDICATORS); -+ (1 << HFP_AG_ESTATUS ) | (1 << HFP_AG_CODECS) | (1 << HFP_AG_INDICATORS) | (1 << HFP_AG_EERR); - - #define HSP_AG_PROFILE "/Profile/HSPAGProfile" - #define HFP_AG_PROFILE "/Profile/HFPAGProfile" -@@ -256,6 +257,14 @@ static void rfcomm_write_response(int fd, const char *fmt, ...) - va_end(ap); - } - -+/* Send Extended Error messages if enabled */ -+static void rfcomm_write_error(pa_bluetooth_backend *b, int fd, unsigned int error) { -+ if (b->cmee_extended_error_reporting_enabled) -+ rfcomm_write_response(fd, "+CME ERROR: %d", error); -+ else -+ rfcomm_write_response(fd, "ERROR"); -+} -+ - static int sco_setsockopt_enable_bt_voice(pa_bluetooth_transport *t, int fd) { - /* the mSBC codec requires a special transparent eSCO connection */ - struct bt_voice voice; -@@ -621,6 +630,30 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - size_t len; - const char *state; - -+ /* Extended error reporting. Described in Bluetooth HFP 1.8 spec. */ -+ if (sscanf(buf, "AT+CMEE=%d", &val) == 1) { -+ switch(val) { -+ /* Disable extended error reporting */ -+ case 0: -+ discovery->native_backend->cmee_extended_error_reporting_enabled = false; -+ return true; -+ /* Enable extend error reporting in numeric mode */ -+ case 1: -+ discovery->native_backend->cmee_extended_error_reporting_enabled = true; -+ return true; -+ /* Enable extend error reporting in verbose mode */ -+ case 2: -+ pa_log_warn("Extended Error Reporting verbose mode is unsupported by Bluetooth HFP 1.8"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_SUPPORTED); -+ return false; -+ default: -+ pa_log_warn("Unknown AT+CMEE value: %d", val); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); -+ return false; -+ } -+ pa_assert_not_reached(); -+ } -+ - /* first-time initialize selected codec to CVSD */ - if (c->selected_codec == 0) - c->selected_codec = 1; -@@ -655,7 +688,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - discovery->native_backend->cind_enabled_indicators &= ~(1 << indicator); - else { - pa_log_error("Unable to parse indicator of AT+BIA command: %s", buf); -- rfcomm_write_response(fd, "ERROR"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); - return false; - } - -@@ -741,7 +774,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - } - else { - pa_log_error("Unable to parse AT+CMER command: %s", buf); -- rfcomm_write_response(fd, "ERROR"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); - return false; - } - -@@ -767,7 +800,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - pa_bluetooth_transport_reconfigure(t, pa_bluetooth_get_hf_codec("mSBC"), sco_transport_write, sco_setsockopt_enable_bt_voice); - } else { - pa_assert_fp(val != 1 && val != 2); -- rfcomm_write_response(fd, "ERROR"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); - return false; - } - -@@ -798,14 +831,14 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - pa_log_notice("Battery Level: %d%%", val); - if (val < 0 || val > 100) { - pa_log_error("Battery HF indicator %d out of [0, 100] range", val); -- rfcomm_write_response(fd, "ERROR"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); - return false; - } - pa_bluetooth_device_report_battery_level(t->device, val, "HFP 1.7 HF indicator"); - break; - default: - pa_log_error("Unknown HF indicator %u", indicator); -- rfcomm_write_response(fd, "ERROR"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_SUPPORTED); - return false; - } - return true; -@@ -819,12 +852,23 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - if (c->state != 5) { - pa_log_error("HFP negotiation failed in state %d with inbound %s\n", - c->state, buf); -- rfcomm_write_response(fd, "ERROR"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); - return false; - } - -- /* Unsupported commands return ERROR */ -- return false -+ /* -+ * Unsupported commands return ERROR. -+ * Unsupported AT commands from HFP 1.8: -+ * - AT+BINP -+ * - AT+BLDN -+ * - ATD> -+ * - AT+BVRA -+ * - AT+BTRH -+ * - AT+CHLD -+ * - AT+CCWA -+ */ -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_SUPPORTED); -+ return false; - } - - static int get_rfcomm_fd (pa_bluetooth_discovery *discovery) { -@@ -996,12 +1040,13 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i - break; - } - } -- if (!do_reply) -- rfcomm_write_response(fd, "ERROR"); -+ if (!do_reply) { -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); -+ } - } else if (t->config) { /* t->config is only non-null for hfp profile */ - do_reply = hfp_rfcomm_handle(fd, t, buf); - } else { -- rfcomm_write_response(fd, "ERROR"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); - do_reply = false; - } - -@@ -1391,6 +1436,8 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d - /* While all CIND indicators are enabled, event reporting is not enabled by default */ - backend->cmer_indicator_reporting_enabled = false; - -+ /* CMEE is disabled by default */ -+ backend->cmee_extended_error_reporting_enabled = false; - - return backend; - } -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index f69176425..4cc5c2882 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -211,6 +211,12 @@ struct pa_bluetooth_adapter { - bool battery_provider_registered; - }; - -+/* extended error reporting values, described in Bluetooth HFP 1.8 spec */ -+typedef enum pa_bluetooth_cmee { -+ CMEE_AG_FAILURE = 0, -+ CMEE_OPERATION_NOT_SUPPORTED = 4, -+} pa_bluetooth_cmee_t; -+ - #ifdef HAVE_BLUEZ_5_OFONO_HEADSET - pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y); - void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *b); --- -2.35.1 - diff --git a/temp/pulseaudio/0009-bluetooth-support-AT-NREC.patch b/temp/pulseaudio/0009-bluetooth-support-AT-NREC.patch deleted file mode 100644 index d42b6c2a8..000000000 --- a/temp/pulseaudio/0009-bluetooth-support-AT-NREC.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0dc5b589220e830ab18ddbcf90f2cfbe1c4927f7 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Wed, 13 Apr 2022 20:25:47 +0200 -Subject: [PATCH 09/26] bluetooth: support AT+NREC - -AT+NREC=0 disables Noise Reduction and Echo Canceling in the AG. -Bluetooth HFP 1.8 only supports the disable operation, so return -an CME ERROR extended error code if another value is send by the HF. ---- - src/modules/bluetooth/backend-native.c | 7 +++++++ - src/modules/bluetooth/bluez5-util.h | 3 ++- - 2 files changed, 9 insertions(+), 1 deletion(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 3110c5ef2..394c2a4da 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -652,6 +652,13 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - return false; - } - pa_assert_not_reached(); -+ } else if (sscanf(buf, "AT+NREC=%d", &val) == 1) { -+ if (val == 0) -+ return true; -+ -+ /* Noise Redction and Echo Canceling can only have value '0' (disable) following Bluetooth HFP 1.8 */ -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_ALLOWED); -+ return false; - } - - /* first-time initialize selected codec to CVSD */ -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index 4cc5c2882..fa26a8361 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -214,7 +214,8 @@ struct pa_bluetooth_adapter { - /* extended error reporting values, described in Bluetooth HFP 1.8 spec */ - typedef enum pa_bluetooth_cmee { - CMEE_AG_FAILURE = 0, -- CMEE_OPERATION_NOT_SUPPORTED = 4, -+ CMEE_OPERATION_NOT_ALLOWED = 3, -+ CMEE_OPERATION_NOT_SUPPORTED = 4 - } pa_bluetooth_cmee_t; - - #ifdef HAVE_BLUEZ_5_OFONO_HEADSET --- -2.35.1 - diff --git a/temp/pulseaudio/0010-bluetooth-support-AT-BCC.patch b/temp/pulseaudio/0010-bluetooth-support-AT-BCC.patch deleted file mode 100644 index e01cb786e..000000000 --- a/temp/pulseaudio/0010-bluetooth-support-AT-BCC.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 79d8cf24785fc52a3d0cee48590143fb409201b8 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Thu, 14 Apr 2022 19:15:34 +0200 -Subject: [PATCH 10/26] bluetooth: support AT+BCC - -HFs send AT+BCC to (re)start codec negotiations. -Support this command by (re)setting the codec negotiations state and -reply OK. ---- - src/modules/bluetooth/backend-native.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 394c2a4da..89a174f9a 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -666,7 +666,12 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - c->selected_codec = 1; - - /* stateful negotiation */ -- if (c->state == 0 && sscanf(buf, "AT+BRSF=%d", &val) == 1) { -+ if (strstr(buf, "AT+BCC")) { -+ pa_log_debug("HF asked to start codec negotiations"); -+ c->state = 0; -+ return true; -+ } -+ else if (c->state == 0 && sscanf(buf, "AT+BRSF=%d", &val) == 1) { - c->capabilities = val; - pa_log_info("HFP capabilities returns 0x%x", val); - rfcomm_write_response(fd, "+BRSF: %d", hfp_features); --- -2.35.1 - diff --git a/temp/pulseaudio/0011-bluetooth-support-AT-COPS.patch b/temp/pulseaudio/0011-bluetooth-support-AT-COPS.patch deleted file mode 100644 index a168c7ada..000000000 --- a/temp/pulseaudio/0011-bluetooth-support-AT-COPS.patch +++ /dev/null @@ -1,165 +0,0 @@ -From ccac2886c516aa0ac2e76406b782de0abc700e92 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Thu, 14 Apr 2022 19:47:46 +0200 -Subject: [PATCH 11/26] bluetooth: support AT+COPS - -AT+COPS=3,X sets the operator name format and AT+COPS? returns -the current network operator name. Supports this command when -ModemManager is available to provide this information. ---- - src/modules/bluetooth/backend-native.c | 72 +++++++++++++++++++++++++- - src/modules/bluetooth/bluez5-util.h | 11 +++- - 2 files changed, 81 insertions(+), 2 deletions(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 89a174f9a..c0c14acf3 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -40,6 +40,7 @@ - #include "bluez5-util.h" - #include "bt-codec-msbc.h" - #include "upower.h" -+#include "modemmanager.h" - - #define MANDATORY_CALL_INDICATORS \ - "(\"call\",(0-1))," \ -@@ -53,12 +54,14 @@ struct pa_bluetooth_backend { - pa_hook_slot *adapter_uuids_changed_slot; - pa_hook_slot *host_battery_level_changed_slot; - pa_upower_backend *upower; -+ pa_modemmanager_backend *modemmanager; - bool enable_shared_profiles; - bool enable_hsp_hs; - bool enable_hfp_hf; - bool cmer_indicator_reporting_enabled; - bool cmee_extended_error_reporting_enabled; - uint32_t cind_enabled_indicators; -+ pa_bluetooth_cops_t cops_format; - - PA_LLIST_HEAD(pa_dbus_pending, pending); - }; -@@ -624,7 +627,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - { - struct pa_bluetooth_discovery *discovery = t->device->discovery; - struct hfp_config *c = t->config; -- int indicator, mode, val; -+ int indicator, mode, val, val2; - char str[5]; - const char *r; - size_t len; -@@ -659,6 +662,68 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - /* Noise Redction and Echo Canceling can only have value '0' (disable) following Bluetooth HFP 1.8 */ - rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_ALLOWED); - return false; -+ } else if (sscanf(buf, "AT+COPS=%d,%d", &val, &val2) == 2) { -+ /* Return error if ModemManager is unavailable */ -+ if (!discovery->native_backend->modemmanager || !pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ pa_log_debug("ModemManager backend unavailable, cannot set AT+COPS format"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } -+ -+ /* Only AT+COPS=3,X is allowed by Bluetooth HFP 1.8 */ -+ if (val != 3) -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_ALLOWED); -+ -+ /* Set AT+COPS format */ -+ if (val2 == 0) { -+ discovery->native_backend->cops_format = COPS_LONG_FORMAT; -+ return true; -+ } else if (val2 == 2) { -+ discovery->native_backend->cops_format = COPS_NUMERIC_FORMAT; -+ return true; -+ } else { -+ discovery->native_backend->cops_format = COPS_UNKNOWN_FORMAT; -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_ALLOWED); -+ return false; -+ } -+ } else if (strstr(buf, "AT+COPS?")) { -+ /* Return error if ModemManager is unavailable */ -+ if (!discovery->native_backend->modemmanager || !pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ pa_log_debug("ModemManager backend unavailable, cannot answer AT+COPS?"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } else if (!pa_modemmanager_has_service(discovery->native_backend->modemmanager)) { -+ pa_log_debug("No network service, cannot answer AT+COPS?"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_NETWORK_SERVICE); -+ return false; -+ } -+ -+ switch(discovery->native_backend->cops_format) { -+ case COPS_LONG_FORMAT: { -+ char *operator_name = pa_modemmanager_get_operator_name(discovery->native_backend->modemmanager); -+ if (operator_name) { -+ rfcomm_write_response(fd, "+COPS: 0,0,\"%s\"", operator_name); -+ return true; -+ } -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_NETWORK_SERVICE); -+ return false; -+ } -+ case COPS_NUMERIC_FORMAT: { -+ char *operator_code = pa_modemmanager_get_operator_code(discovery->native_backend->modemmanager); -+ if (operator_code) { -+ rfcomm_write_response(fd, "+COPS: 2,0,\"%s\"", operator_code); -+ return true; -+ } -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_NETWORK_SERVICE); -+ return false; -+ } -+ case COPS_UNKNOWN_FORMAT: { -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); -+ return false; -+ } -+ default: -+ pa_assert_not_reached(); -+ } - } - - /* first-time initialize selected codec to CVSD */ -@@ -1441,6 +1506,8 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d - - backend->upower = pa_upower_backend_new(c, y); - -+ backend->modemmanager = pa_modemmanager_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); -@@ -1473,6 +1540,9 @@ void pa_bluetooth_native_backend_free(pa_bluetooth_backend *backend) { - - if (backend->upower) - pa_upower_backend_free(backend->upower); -+ -+ if (backend->modemmanager) -+ pa_modemmanager_backend_free(backend->modemmanager); - - pa_dbus_connection_unref(backend->connection); - -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index fa26a8361..9ac9880a8 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -214,10 +214,19 @@ struct pa_bluetooth_adapter { - /* extended error reporting values, described in Bluetooth HFP 1.8 spec */ - typedef enum pa_bluetooth_cmee { - CMEE_AG_FAILURE = 0, -+ CMEE_NO_CONNECTION_TO_PHONE = 1, - CMEE_OPERATION_NOT_ALLOWED = 3, -- CMEE_OPERATION_NOT_SUPPORTED = 4 -+ CMEE_OPERATION_NOT_SUPPORTED = 4, -+ CMEE_NO_NETWORK_SERVICE = 30 - } pa_bluetooth_cmee_t; - -+/* AT+COPS format, described in Bluetooth HFP 1.8 spec */ -+typedef enum pa_bluetooth_cops { -+ COPS_LONG_FORMAT = 0, -+ COPS_NUMERIC_FORMAT = 1, -+ COPS_UNKNOWN_FORMAT = 2 -+} pa_bluetooth_cops_t; -+ - #ifdef HAVE_BLUEZ_5_OFONO_HEADSET - pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y); - void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *b); --- -2.35.1 - diff --git a/temp/pulseaudio/0012-bluetooth-support-AT-CNUM.patch b/temp/pulseaudio/0012-bluetooth-support-AT-CNUM.patch deleted file mode 100644 index 4dc789da5..000000000 --- a/temp/pulseaudio/0012-bluetooth-support-AT-CNUM.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 739ca09cc36553703d2b24ba99b64f8641fcf987 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Thu, 14 Apr 2022 20:16:24 +0200 -Subject: [PATCH 12/26] bluetooth: support AT+CNUM - -AT+CNUM returns the phone number of the subscriber. -Supports this AT command when ModemManager is available. ---- - src/modules/bluetooth/backend-native.c | 25 +++++++++++++++++++++++++ - src/modules/bluetooth/bluez5-util.h | 6 ++++++ - 2 files changed, 31 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index c0c14acf3..19ca497d5 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -724,6 +724,31 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - default: - pa_assert_not_reached(); - } -+ } else if (strstr(buf, "AT+CNUM")) { -+ char *number; -+ unsigned int type; -+ -+ /* Return error if ModemManager is unavailable */ -+ if (!discovery->native_backend->modemmanager || !pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ pa_log_debug("ModemManager backend unavailable, cannot answer AT+CNUM"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } -+ -+ number = pa_modemmanager_get_own_number(discovery->native_backend->modemmanager); -+ if (!number) { -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); -+ return false; -+ } -+ -+ /* International numbers start with '+' */ -+ if (strncmp("+", number, 1) == 0) -+ type = CLIP_INTERNATIONAL_NUMBER; -+ else -+ type = CLIP_NATIONAL_NUMBER; -+ -+ rfcomm_write_response(fd, "+CNUM: ,\"%s\",%d,,4", number, type); -+ return true; - } - - /* first-time initialize selected codec to CVSD */ -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index 9ac9880a8..638a793b7 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -227,6 +227,12 @@ typedef enum pa_bluetooth_cops { - COPS_UNKNOWN_FORMAT = 2 - } pa_bluetooth_cops_t; - -+/* CLIP number formats, described in Bluetooth HFP 1.8 spec */ -+typedef enum pa_bluetooth_clip { -+ CLIP_INTERNATIONAL_NUMBER = 145, -+ CLIP_NATIONAL_NUMBER = 129 -+} pa_bluetooth_clip_t; -+ - #ifdef HAVE_BLUEZ_5_OFONO_HEADSET - pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y); - void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *b); --- -2.35.1 - diff --git a/temp/pulseaudio/0013-bluetooth-support-more-AT-CIND-indicators.patch b/temp/pulseaudio/0013-bluetooth-support-more-AT-CIND-indicators.patch deleted file mode 100644 index 3cf64a966..000000000 --- a/temp/pulseaudio/0013-bluetooth-support-more-AT-CIND-indicators.patch +++ /dev/null @@ -1,67 +0,0 @@ -From fafe1fc716a9482e2ea883fb79edf90a7c89d33d Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Thu, 14 Apr 2022 20:43:42 +0200 -Subject: [PATCH 13/26] bluetooth: support more AT+CIND? indicators - -If ModemManager is available, report service status, roaming status and -signal strength as well when an AT+CIND? command is received. ---- - src/modules/bluetooth/backend-native.c | 24 +++++++++++++++++------- - 1 file changed, 17 insertions(+), 7 deletions(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 19ca497d5..fcbae5540 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -123,7 +123,9 @@ typedef enum pa_bluetooth_ag_to_hf_indicators { - CIND_CALL_HELD_INDICATOR = 3, - CIND_SERVICE_INDICATOR = 4, - CIND_BATT_CHG_INDICATOR = 5, -- CIND_INDICATOR_MAX = 6 -+ CIND_ROAMING_INDICATOR = 6, -+ CIND_SIGNAL_STRENGTH_INDICATOR = 7, -+ CIND_INDICATOR_MAX = 8 - } pa_bluetooth_ag_to_hf_indicators_t; - - /* gateway features we support, which is as little as we can get away with */ -@@ -822,14 +824,16 @@ 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=?")) { -- /* UPower backend available, declare support for more indicators */ -- if (discovery->native_backend->upower) { -+ /* UPower and ModemManager backends available, declare support for more indicators */ -+ if (discovery->native_backend->upower && discovery->native_backend->modemmanager && pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { - rfcomm_write_response(fd, "+CIND: " - MANDATORY_CALL_INDICATORS "," - "(\"service\",(0-1))," -- "(\"battchg\",(0-5))"); -+ "(\"battchg\",(0-5))," -+ "(\"roam\",(0-1))," -+ "(\"signal\",(0-5))"); - -- /* Minimal indicators supported without any additional backend */ -+ /* Minimal indicators supported without any additional backends */ - } else { - rfcomm_write_response(fd, "+CIND: " - MANDATORY_CALL_INDICATORS "," -@@ -845,8 +849,14 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - - return true; - } else if (c->state >= 2 && pa_startswith(buf, "AT+CIND?")) { -- if (discovery->native_backend->upower) -- rfcomm_write_response(fd, "+CIND: 0,0,0,0,%u", pa_upower_get_battery_level(discovery->native_backend->upower)); -+ if (discovery->native_backend->upower && discovery->native_backend->modemmanager && pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) -+ rfcomm_write_response(fd, "+CIND: %u,%u,0,%u,%u,%u,%u", -+ discovery->native_backend->cind_call_indicator, -+ discovery->native_backend->cind_call_setup_indicator, -+ pa_modemmanager_has_service(discovery->native_backend->modemmanager), -+ pa_upower_get_battery_level(discovery->native_backend->upower), -+ pa_modemmanager_is_roaming(discovery->native_backend->modemmanager), -+ pa_modemmanager_get_signal_strength(discovery->native_backend->modemmanager)); - else - rfcomm_write_response(fd, "+CIND: 0,0,0,0"); - --- -2.35.1 - diff --git a/temp/pulseaudio/0014-bluetooth-support-AT-CLIP.patch b/temp/pulseaudio/0014-bluetooth-support-AT-CLIP.patch deleted file mode 100644 index 4081e8290..000000000 --- a/temp/pulseaudio/0014-bluetooth-support-AT-CLIP.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 07adf1b246ba1db7b4c5bb9555f1d392b856c049 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Thu, 14 Apr 2022 20:52:36 +0200 -Subject: [PATCH 14/26] bluetooth: support AT+CLIP - -Enable or disable Call Line Indication reporting (+CLIP) when -a call is incoming to display the number that is calling on the HF's -screen. ---- - src/modules/bluetooth/backend-native.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index fcbae5540..1eaa36b4a 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -62,6 +62,7 @@ struct pa_bluetooth_backend { - bool cmee_extended_error_reporting_enabled; - uint32_t cind_enabled_indicators; - pa_bluetooth_cops_t cops_format; -+ bool clip_call_line_reporting_enabled; - - PA_LLIST_HEAD(pa_dbus_pending, pending); - }; -@@ -751,6 +752,22 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - - rfcomm_write_response(fd, "+CNUM: ,\"%s\",%d,,4", number, type); - return true; -+ } else if (sscanf(buf, "AT+CLIP=%d", &val) == 1) { -+ switch(val) { -+ /* Disable call line reporting */ -+ case 0: -+ discovery->native_backend->clip_call_line_reporting_enabled = false; -+ return true; -+ /* Enable call line reporting */ -+ case 1: -+ discovery->native_backend->clip_call_line_reporting_enabled = true; -+ return true; -+ default: -+ pa_log_warn("Unknown AT+CLIP value: %d", val); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); -+ return false; -+ } -+ pa_assert_not_reached(); - } - - /* first-time initialize selected codec to CVSD */ -@@ -1553,6 +1570,9 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d - /* CMEE is disabled by default */ - backend->cmee_extended_error_reporting_enabled = false; - -+ /* CLIP is disabled by default */ -+ backend->clip_call_line_reporting_enabled = false; -+ - return backend; - } - --- -2.35.1 - diff --git a/temp/pulseaudio/0015-bluetooth-support-AT-CREG.patch b/temp/pulseaudio/0015-bluetooth-support-AT-CREG.patch deleted file mode 100644 index f74dccd07..000000000 --- a/temp/pulseaudio/0015-bluetooth-support-AT-CREG.patch +++ /dev/null @@ -1,48 +0,0 @@ -From d10422fafd9eececfa6755617c41b05f895e5a5b Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Thu, 14 Apr 2022 21:03:37 +0200 -Subject: [PATCH 15/26] bluetooth: support AT+CREG? - -AT+CREG? is not officialy supported by the Bluetooth HFP 1.8 spec, -but some car multimedia systems use it. AT+CREG? reports if the phone -has network available or not with a +CREG response. ---- - src/modules/bluetooth/backend-native.c | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 1eaa36b4a..2fa769d07 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -770,6 +770,28 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - pa_assert_not_reached(); - } - -+ /* -+ * Out-of-spec Bluetooth HFP 1.8 AT commands. -+ * Some car multimedia systems implement the HFP spec, -+ * but also use out-of-spec AT commands which are normally supported -+ * by any 3GPP compliant modem such as: -+ * - AT+CREG?: Get service status -+ * - AT+CGMM: Get modem model -+ * - AT+CGMI: Get modem manufacturer -+ * - AT+CGMR: Get modem revision -+ * - AT+CGSN: Get modem IMEI -+ * -+ * These AT commands are additionally supported if ModemManager is available. -+ */ -+ if (strstr(buf, "AT+CREG?")) { -+ if (discovery->native_backend->modemmanager && pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ rfcomm_write_response(fd, "+CREG: 0,%d", pa_modemmanager_has_service(discovery->native_backend->modemmanager)); -+ return true; -+ } -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } -+ - /* first-time initialize selected codec to CVSD */ - if (c->selected_codec == 0) - c->selected_codec = 1; --- -2.35.1 - diff --git a/temp/pulseaudio/0016-bluetooth-support-AT-CGMM.patch b/temp/pulseaudio/0016-bluetooth-support-AT-CGMM.patch deleted file mode 100644 index 1931e1a82..000000000 --- a/temp/pulseaudio/0016-bluetooth-support-AT-CGMM.patch +++ /dev/null @@ -1,32 +0,0 @@ -From ee52128fbb8bc953c43b8c53763443c715fa64c8 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Fri, 15 Apr 2022 07:29:49 +0200 -Subject: [PATCH 16/26] bluetooth: support AT+CGMM - -Return the modem model if ModemManager is available when the HF -sends an out-of-spec AT+CGMM command. ---- - src/modules/bluetooth/backend-native.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 2fa769d07..2c39a090c 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -790,6 +790,13 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - } - rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); - return false; -+ } else if (strstr(buf, "AT+CGMM") && pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ if (discovery->native_backend->modemmanager) { -+ rfcomm_write_response(fd, "%s", pa_modemmanager_get_modem_model(discovery->native_backend->modemmanager)); -+ return true; -+ } -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; - } - - /* first-time initialize selected codec to CVSD */ --- -2.35.1 - diff --git a/temp/pulseaudio/0017-bluetooth-support-AT-CGMI.patch b/temp/pulseaudio/0017-bluetooth-support-AT-CGMI.patch deleted file mode 100644 index 3dceb2f4e..000000000 --- a/temp/pulseaudio/0017-bluetooth-support-AT-CGMI.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 6e851563dbe4e90a37b0f8fef1604395acba47b4 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Fri, 15 Apr 2022 07:31:43 +0200 -Subject: [PATCH 17/26] bluetooth: support AT+CGMI - -Return the modem manufacturer if ModemManager is available. -AT+CGMI is an out-of-spec AT command for Bluetooth HFP, but car -multimedia units use it since it is a standard 3GPP command. ---- - src/modules/bluetooth/backend-native.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 2c39a090c..3099b13fc 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -797,6 +797,13 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - } - rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); - return false; -+ } else if (strstr(buf, "AT+CGMI") && pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ if (discovery->native_backend->modemmanager) { -+ rfcomm_write_response(fd, "%s", pa_modemmanager_get_modem_manufacturer(discovery->native_backend->modemmanager)); -+ return true; -+ } -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; - } - - /* first-time initialize selected codec to CVSD */ --- -2.35.1 - diff --git a/temp/pulseaudio/0018-bluetooth-support-AT-CGMR.patch b/temp/pulseaudio/0018-bluetooth-support-AT-CGMR.patch deleted file mode 100644 index 4868b22db..000000000 --- a/temp/pulseaudio/0018-bluetooth-support-AT-CGMR.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 5fd316c23c3051be2394c16bf97ee189fc07ce23 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Fri, 15 Apr 2022 07:33:19 +0200 -Subject: [PATCH 18/26] bluetooth: support AT+CGMR - -Return the modem revision when HF sends an out-of-spec AT+CGMR -command. This is a 3GPP standardized command so lets support it. ---- - src/modules/bluetooth/backend-native.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 3099b13fc..cf016a282 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -804,6 +804,13 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - } - rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); - return false; -+ } else if (strstr(buf, "AT+CGMR")) { -+ if (discovery->native_backend->modemmanager && pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ rfcomm_write_response(fd, "%s", pa_modemmanager_get_modem_revision(discovery->native_backend->modemmanager)); -+ return true; -+ } -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; - } - - /* first-time initialize selected codec to CVSD */ --- -2.35.1 - diff --git a/temp/pulseaudio/0019-bluetooth-support-AT-CGSN.patch b/temp/pulseaudio/0019-bluetooth-support-AT-CGSN.patch deleted file mode 100644 index 28193527c..000000000 --- a/temp/pulseaudio/0019-bluetooth-support-AT-CGSN.patch +++ /dev/null @@ -1,33 +0,0 @@ -From f39e071a558a9b3a301028c7f3506f024d60ceea Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Fri, 15 Apr 2022 07:35:11 +0200 -Subject: [PATCH 19/26] bluetooth: support AT+CGSN - -Return the modem's IMEI number when car multimedia systems (HF) -send an AT+CGSN 3GPP AT command, even though it is not supported by the -Bluetooth HFP 1.8 spec. ---- - src/modules/bluetooth/backend-native.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index cf016a282..fec24a57b 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -811,6 +811,13 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - } - rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); - return false; -+ } else if (strstr(buf, "AT+CGSN") && pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ if (discovery->native_backend->modemmanager) { -+ rfcomm_write_response(fd, "%s", pa_modemmanager_get_modem_imei(discovery->native_backend->modemmanager)); -+ return true; -+ } -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; - } - - /* first-time initialize selected codec to CVSD */ --- -2.35.1 - diff --git a/temp/pulseaudio/0020-bluetooth-support-AT-CLCC.patch b/temp/pulseaudio/0020-bluetooth-support-AT-CLCC.patch deleted file mode 100644 index 52220ce25..000000000 --- a/temp/pulseaudio/0020-bluetooth-support-AT-CLCC.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 320d906f8e64b1713dc09c8e95316c4de515f70f Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Fri, 15 Apr 2022 08:18:48 +0200 -Subject: [PATCH 20/26] bluetooth: support AT+CLCC - -Report ongoing calls when the HF sends an AT+CLCC command. -Currently, only one ongoing call is supported, three-way calling is not -implemented. Any additional calls are ignored. ---- - src/modules/bluetooth/backend-native.c | 61 ++++++++++++++++++++++++++ - src/modules/bluetooth/bluez5-util.h | 9 ++++ - 2 files changed, 70 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index fec24a57b..faefed9bd 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -768,6 +768,67 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - return false; - } - pa_assert_not_reached(); -+ } else if (strstr(buf, "AT+CLCC")) { -+ pa_hashmap *calls; -+ call_status_t *call; -+ unsigned int type; -+ unsigned int clcc_status; -+ -+ /* Return error if ModemManager is unavailable */ -+ if (!discovery->native_backend->modemmanager || !pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ pa_log_debug("ModemManager backend unavailable, cannot answer AT+CLCC"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } else if (!pa_modemmanager_has_service(discovery->native_backend->modemmanager)) { -+ pa_log_debug("No network service, cannot answer AT+CLCC"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_NETWORK_SERVICE); -+ return false; -+ } -+ -+ calls = pa_modemmanager_get_calls(discovery->native_backend->modemmanager); -+ -+ /* Check if we have any ongoing calls, if not return OK */ -+ if (pa_hashmap_isempty(calls)) -+ return true; -+ -+ /* FIXME: support three-way calling */ -+ call = pa_hashmap_first(calls); -+ -+ /* Map call status to CLCC status numbers */ -+ if (call->status == PA_MODEMMANAGER_CALL_STATE_INVALID) { -+ pa_log_warn("Unable to answer AT+CLCC, call state is unknown"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); -+ return false; -+ } else if (call->is_incoming && call->status == PA_MODEMMANAGER_CALL_STATE_RINGING) { -+ clcc_status = CLCC_INCOMING; -+ } else if (!call->is_incoming && call->status == PA_MODEMMANAGER_CALL_STATE_RINGING) { -+ clcc_status = CLCC_ALERTING; -+ } else if (!call->is_incoming && call->status == PA_MODEMMANAGER_CALL_STATE_DIALING) { -+ clcc_status = CLCC_DIALING; -+ } else if (call->status == PA_MODEMMANAGER_CALL_STATE_ACTIVE) { -+ clcc_status = CLCC_ACTIVE; -+ } else if (call->status == PA_MODEMMANAGER_CALL_STATE_TERMINATED) { -+ pa_log_debug("Call terminated already, do not report it."); -+ return true; -+ /* FIXME: support three-way calling */ -+ } else { -+ pa_assert_not_reached(); -+ } -+ -+ /* Check if call has a number, if not drop it since number and type are optional */ -+ if (!call->number) { -+ rfcomm_write_response(fd, "+CLCC: %d,%d,%d,%d,%d", 1, call->is_incoming, clcc_status, 0, 0); -+ return true; -+ } -+ -+ /* International numbers start with '+' */ -+ if (strncmp("+", call->number, 1) == 0) -+ type = CLIP_INTERNATIONAL_NUMBER; -+ else -+ type = CLIP_NATIONAL_NUMBER; -+ -+ rfcomm_write_response(fd, "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d", 1, call->is_incoming, clcc_status, 0, 0, call->number, type); -+ return true; - } - - /* -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index 638a793b7..fb88f00e2 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -233,6 +233,15 @@ typedef enum pa_bluetooth_clip { - CLIP_NATIONAL_NUMBER = 129 - } pa_bluetooth_clip_t; - -+/* CLCC call states, described in Bluetooth HFP 1.8 spec */ -+/* FIXME: support three-way calling */ -+typedef enum pa_bluetooth_clcc { -+ CLCC_ACTIVE = 0, -+ CLCC_DIALING = 2, -+ CLCC_ALERTING = 3, -+ CLCC_INCOMING = 4 -+} pa_bluetooth_clcc_t; -+ - #ifdef HAVE_BLUEZ_5_OFONO_HEADSET - pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y); - void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *b); --- -2.35.1 - diff --git a/temp/pulseaudio/0021-bluetooth-support-CIEV-RING-and-CLIP-URCs.patch b/temp/pulseaudio/0021-bluetooth-support-CIEV-RING-and-CLIP-URCs.patch deleted file mode 100644 index 9e3196e1b..000000000 --- a/temp/pulseaudio/0021-bluetooth-support-CIEV-RING-and-CLIP-URCs.patch +++ /dev/null @@ -1,365 +0,0 @@ -From 6861de91294c8bed206e8338d1074ebc57683ae4 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Sat, 16 Apr 2022 08:46:13 +0200 -Subject: [PATCH 21/26] bluetooth: support +CIEV, RING, and +CLIP URCs - -Report changes of the CIND indicators and calls to the HF with URCs: - -- +CIEV: report any change to the CIND indicators such as signal - strength, roaming status, service status, etc. -- RING: play a ringtone on the HF side for incoming calls. -- +CLIP: enhanced call status reports the subscriber number to the HF - for incoming calls. ---- - src/modules/bluetooth/backend-native.c | 258 +++++++++++++++++++++++++ - src/modules/bluetooth/bluez5-util.h | 12 ++ - 2 files changed, 270 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index faefed9bd..e12b38d71 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -29,6 +29,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -42,6 +44,7 @@ - #include "upower.h" - #include "modemmanager.h" - -+#define RING_WAIT_TIME ((pa_usec_t) (3 * PA_USEC_PER_SEC)) - #define MANDATORY_CALL_INDICATORS \ - "(\"call\",(0-1))," \ - "(\"callsetup\",(0-3))," \ -@@ -49,10 +52,17 @@ - - struct pa_bluetooth_backend { - pa_core *core; -+ pa_time_event *timer_ring_event; - pa_dbus_connection *connection; - pa_bluetooth_discovery *discovery; - pa_hook_slot *adapter_uuids_changed_slot; - pa_hook_slot *host_battery_level_changed_slot; -+ pa_hook_slot *host_operation_succeed_slot; -+ pa_hook_slot *host_operation_failed_slot; -+ pa_hook_slot *host_signal_strength_changed_slot; -+ pa_hook_slot *host_has_service_changed_slot; -+ pa_hook_slot *host_is_roaming_changed_slot; -+ pa_hook_slot *host_calls_changed_slot; - pa_upower_backend *upower; - pa_modemmanager_backend *modemmanager; - bool enable_shared_profiles; -@@ -63,6 +73,8 @@ struct pa_bluetooth_backend { - uint32_t cind_enabled_indicators; - pa_bluetooth_cops_t cops_format; - bool clip_call_line_reporting_enabled; -+ unsigned int cind_call_indicator; -+ unsigned int cind_call_setup_indicator; - - PA_LLIST_HEAD(pa_dbus_pending, pending); - }; -@@ -1172,6 +1184,206 @@ static pa_hook_result_t host_battery_level_changed_cb(pa_bluetooth_discovery *y, - return PA_HOOK_OK; - } - -+static pa_hook_result_t host_operation_failed_cb(pa_bluetooth_discovery *y, const pa_modemmanager_backend *m, pa_bluetooth_backend *b) { -+ int rfcomm_fd; -+ -+ pa_assert(y); -+ pa_assert(m); -+ 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 operation failure over RFCOMM */ -+ rfcomm_write_error(b, rfcomm_fd, CMEE_AG_FAILURE); -+ -+ return PA_HOOK_OK; -+} -+ -+static pa_hook_result_t host_operation_succeed_cb(pa_bluetooth_discovery *y, const pa_modemmanager_backend *m, pa_bluetooth_backend *b) { -+ int rfcomm_fd; -+ -+ pa_assert(y); -+ pa_assert(m); -+ 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 operation succeed over RFCOMM */ -+ rfcomm_write_response(rfcomm_fd, "OK"); -+ -+ return PA_HOOK_OK; -+} -+ -+static pa_hook_result_t host_signal_strength_changed_cb(pa_bluetooth_discovery *y, const pa_modemmanager_backend *m, pa_bluetooth_backend *b) { -+ int rfcomm_fd; -+ -+ pa_assert(y); -+ pa_assert(m); -+ 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 signal strength change */ -+ if (b->cmer_indicator_reporting_enabled && (b->cind_enabled_indicators & (1 << CIND_SIGNAL_STRENGTH_INDICATOR))) { -+ rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_SIGNAL_STRENGTH_INDICATOR, pa_modemmanager_get_signal_strength(m)); -+ /* Skip notification if indicator is disabled or event reporting is completely disabled */ -+ } else -+ pa_log_debug("Signal strength change indicator disabled, skipping notification"); -+ -+ return PA_HOOK_OK; -+} -+ -+static pa_hook_result_t host_has_service_changed_cb(pa_bluetooth_discovery *y, const pa_modemmanager_backend *m, pa_bluetooth_backend *b) { -+ int rfcomm_fd; -+ -+ pa_assert(y); -+ pa_assert(m); -+ 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 cellular service status change */ -+ if (b->cmer_indicator_reporting_enabled && (b->cind_enabled_indicators & (1 << CIND_SERVICE_INDICATOR))) { -+ rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_SERVICE_INDICATOR, pa_modemmanager_has_service(m)); -+ /* Skip notification if indicator is disabled or event reporting is completely disabled */ -+ } else -+ pa_log_debug("Cellular service status change indicator disabled, skipping notification"); -+ -+ return PA_HOOK_OK; -+} -+ -+static pa_hook_result_t host_is_roaming_changed_cb(pa_bluetooth_discovery *y, const pa_modemmanager_backend *m, pa_bluetooth_backend *b) { -+ int rfcomm_fd; -+ -+ pa_assert(y); -+ pa_assert(m); -+ 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 roaming status change */ -+ if (b->cmer_indicator_reporting_enabled && (b->cind_enabled_indicators & (1 << CIND_ROAMING_INDICATOR))) { -+ rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_ROAMING_INDICATOR, pa_modemmanager_is_roaming(m)); -+ /* Skip notification if indicator is disabled or event reporting is completely disabled */ -+ } else -+ pa_log_debug("Roaming status change indicator disabled, skipping notification"); -+ -+ return PA_HOOK_OK; -+} -+ -+static void timer_ring_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) { -+ int rfcomm_fd; -+ unsigned int type; -+ pa_bluetooth_discovery *y = userdata; -+ pa_hashmap *calls; -+ call_status_t *call; -+ -+ /* Get RFCOMM channel if available */ -+ rfcomm_fd = get_rfcomm_fd (y); -+ if (rfcomm_fd < 0) -+ return; -+ -+ calls = pa_modemmanager_get_calls(y->native_backend->modemmanager); -+ -+ /* Stop ringing if no calls are available */ -+ if (pa_hashmap_isempty(calls)) -+ return; -+ -+ /* FIXME: support three-way calling */ -+ call = pa_hashmap_first(calls); -+ -+ /* Send RING indicator */ -+ rfcomm_write_response(rfcomm_fd, "RING"); -+ -+ /* If enabled, send +CLIP indications to HF about the caller */ -+ if (y->native_backend->clip_call_line_reporting_enabled && call->number) { -+ /* International numbers start with '+' */ -+ if (strncmp("+", call->number, 1) == 0) -+ type = CLIP_INTERNATIONAL_NUMBER; -+ else -+ type = CLIP_NATIONAL_NUMBER; -+ rfcomm_write_response(rfcomm_fd, "+CLIP: \"%s\",%d", call->number, type); -+ } -+ -+ if (y->native_backend->timer_ring_event) -+ pa_core_rttime_restart(y->native_backend->core, y->native_backend->timer_ring_event, pa_rtclock_now() + RING_WAIT_TIME); -+} -+ -+static pa_hook_result_t host_calls_changed_cb(pa_bluetooth_discovery *y, const pa_modemmanager_backend *m, pa_bluetooth_backend *b) { -+ int rfcomm_fd; -+ unsigned int call_indicator; -+ unsigned int call_setup_indicator; -+ pa_hashmap *calls; -+ call_status_t *call; -+ -+ pa_assert(y); -+ pa_assert(m); -+ pa_assert(b); -+ -+ /* Get RFCOMM channel if available */ -+ rfcomm_fd = get_rfcomm_fd (y); -+ if (rfcomm_fd < 0) -+ return PA_HOOK_OK; -+ -+ calls = pa_modemmanager_get_calls(m); -+ call = pa_hashmap_isempty(calls)? NULL: pa_hashmap_first(calls); -+ -+ /* Notify HF about call indicator state, if changed */ -+ if (call && call->status == PA_MODEMMANAGER_CALL_STATE_ACTIVE) -+ call_indicator = CIND_CALL_AT_LEAST_ONE; -+ else -+ call_indicator = CIND_CALL_NONE; -+ -+ if (b->cind_call_indicator != call_indicator) { -+ b->cind_call_indicator = call_indicator; -+ rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_CALL_INDICATOR, b->cind_call_indicator); -+ } -+ -+ /* Notify HF about call setup indicator state, if changed */ -+ if (call && call->is_incoming && call->status == PA_MODEMMANAGER_CALL_STATE_RINGING) -+ call_setup_indicator = CIND_CALL_SETUP_INCOMING; -+ else if (call && !call->is_incoming && call->status == PA_MODEMMANAGER_CALL_STATE_DIALING) -+ call_setup_indicator = CIND_CALL_SETUP_OUTGOING_DIALING; -+ else if (call && !call->is_incoming && call->status == PA_MODEMMANAGER_CALL_STATE_RINGING) -+ call_setup_indicator = CIND_CALL_SETUP_OUTGOING_ALERTING; -+ else -+ call_setup_indicator = CIND_CALL_SETUP_NONE; -+ -+ if (b->cind_call_setup_indicator != call_setup_indicator) { -+ b->cind_call_setup_indicator = call_setup_indicator; -+ rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_CALL_SETUP_INDICATOR, b->cind_call_setup_indicator); -+ } -+ -+ /* Start/stop ringing */ -+ if (call && call->is_incoming && call->status == PA_MODEMMANAGER_CALL_STATE_RINGING) { -+ if (!b->timer_ring_event) { -+ pa_log_debug("RING indicator started"); -+ b->timer_ring_event = pa_core_rttime_new(b->core, pa_rtclock_now(), timer_ring_cb, y); -+ } -+ } else if (b->timer_ring_event) { -+ pa_log_debug("RING indicator stopped"); -+ b->core->mainloop->time_free(b->timer_ring_event); -+ b->timer_ring_event = NULL; -+ } -+ -+ 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; -@@ -1658,6 +1870,30 @@ 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_HOST_BATTERY_LEVEL_CHANGED), PA_HOOK_NORMAL, - (pa_hook_cb_t) host_battery_level_changed_cb, backend); - -+ backend->host_operation_failed_slot = -+ pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_OPERATION_FAILED), PA_HOOK_NORMAL, -+ (pa_hook_cb_t) host_operation_failed_cb, backend); -+ -+ backend->host_operation_succeed_slot = -+ pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_OPERATION_SUCCEED), PA_HOOK_NORMAL, -+ (pa_hook_cb_t) host_operation_succeed_cb, backend); -+ -+ backend->host_signal_strength_changed_slot = -+ pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_SIGNAL_STRENGTH_CHANGED), PA_HOOK_NORMAL, -+ (pa_hook_cb_t) host_signal_strength_changed_cb, backend); -+ -+ backend->host_has_service_changed_slot = -+ pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_HAS_SERVICE_CHANGED), PA_HOOK_NORMAL, -+ (pa_hook_cb_t) host_has_service_changed_cb, backend); -+ -+ backend->host_is_roaming_changed_slot = -+ pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_IS_ROAMING_CHANGED), PA_HOOK_NORMAL, -+ (pa_hook_cb_t) host_is_roaming_changed_cb, backend); -+ -+ backend->host_calls_changed_slot = -+ pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_CALLS_CHANGED), PA_HOOK_NORMAL, -+ (pa_hook_cb_t) host_calls_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."); - -@@ -1684,6 +1920,10 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d - /* CLIP is disabled by default */ - backend->clip_call_line_reporting_enabled = false; - -+ /* TODO: Initiate CIND call & callsetup indicators at startup */ -+ backend->cind_call_indicator = CIND_CALL_NONE; -+ backend->cind_call_setup_indicator = CIND_CALL_SETUP_NONE; -+ - return backend; - } - -@@ -1698,6 +1938,24 @@ void pa_bluetooth_native_backend_free(pa_bluetooth_backend *backend) { - if (backend->host_battery_level_changed_slot) - pa_hook_slot_free(backend->host_battery_level_changed_slot); - -+ if (backend->host_operation_failed_slot) -+ pa_hook_slot_free(backend->host_operation_failed_slot); -+ -+ if (backend->host_operation_succeed_slot) -+ pa_hook_slot_free(backend->host_operation_succeed_slot); -+ -+ if (backend->host_signal_strength_changed_slot) -+ pa_hook_slot_free(backend->host_signal_strength_changed_slot); -+ -+ if (backend->host_has_service_changed_slot) -+ pa_hook_slot_free(backend->host_has_service_changed_slot); -+ -+ if (backend->host_is_roaming_changed_slot) -+ pa_hook_slot_free(backend->host_is_roaming_changed_slot); -+ -+ if (backend->host_calls_changed_slot) -+ pa_hook_slot_free(backend->host_calls_changed_slot); -+ - if (backend->enable_shared_profiles) - native_backend_apply_profile_registration_change(backend, false); - -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index fb88f00e2..35b3153b8 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -242,6 +242,18 @@ typedef enum pa_bluetooth_clcc { - CLCC_INCOMING = 4 - } pa_bluetooth_clcc_t; - -+typedef enum pa_bluetooth_cind_call { -+ CIND_CALL_NONE = 0, -+ CIND_CALL_AT_LEAST_ONE = 1, -+} pa_bluetooth_cind_call_t; -+ -+typedef enum pa_bluetooth_cind_call_setup { -+ CIND_CALL_SETUP_NONE = 0, -+ CIND_CALL_SETUP_INCOMING = 1, -+ CIND_CALL_SETUP_OUTGOING_DIALING = 2, -+ CIND_CALL_SETUP_OUTGOING_ALERTING = 3 -+} pa_bluetooth_cind_call_setup_t; -+ - #ifdef HAVE_BLUEZ_5_OFONO_HEADSET - pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y); - void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *b); --- -2.35.1 - diff --git a/temp/pulseaudio/0022-bluetooth-support-AT-VTS.patch b/temp/pulseaudio/0022-bluetooth-support-AT-VTS.patch deleted file mode 100644 index 8eed861db..000000000 --- a/temp/pulseaudio/0022-bluetooth-support-AT-VTS.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 8d2504c42a1910b4b6bf80a0474f4b5502c4f490 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Sat, 16 Apr 2022 16:37:10 +0200 -Subject: [PATCH 22/26] bluetooth: support AT+VTS - -Send DTMF tones to the active call when the HF sends AT+VTS=$character. -Return an error if more than one character is given or ModemManager is -unavailable. ---- - src/modules/bluetooth/backend-native.c | 32 ++++++++++++++++++++++++++ - src/modules/bluetooth/bluez5-util.h | 1 + - 2 files changed, 33 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index e12b38d71..306de44a7 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -841,6 +841,38 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - - rfcomm_write_response(fd, "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d", 1, call->is_incoming, clcc_status, 0, 0, call->number, type); - return true; -+ } else if (strstr(buf, "AT+VTS=")) { -+ char *call_key = NULL; -+ char dtmf_char[2]; /* character and '\0' */ -+ -+ /* AT+VTS is only possible if ModemManager is availble */ -+ if (!discovery->native_backend->modemmanager || !pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ pa_log_debug("ModemManager backend unavailable, cannot send DTMF tone with AT+VTS"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } else if (!pa_modemmanager_has_service(discovery->native_backend->modemmanager)) { -+ pa_log_debug("No network service, cannot send DTMF tone with AT+VTS"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_NETWORK_SERVICE); -+ return false; -+ } -+ -+ /* Parse DTMF character, HFP spec allows 1 character. Return an error if parsing failed. */ -+ val = sscanf(buf, "AT+VTS=%1s", dtmf_char); -+ if (val != 1) { -+ pa_log_warn("Cannot parse DTMF character from \"%s\"", buf); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_INVALID_CHARACTERS_TEXT_STRING); -+ return false; -+ } -+ call_key = pa_modemmanager_get_active_call_key(discovery->native_backend->modemmanager); -+ if (call_key) -+ pa_modemmanager_send_dtmf(discovery->native_backend->modemmanager, call_key, dtmf_char); -+ else { -+ pa_log_warn("No active call, cannot send DTMF tone with AT+VTS"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_ALLOWED); -+ } -+ -+ /* AT response will be reported through PA_BLUETOOTH_HOST_OPERATION_{SUCCEED, FAILED} hook */ -+ return false; - } - - /* -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index 35b3153b8..4802cca69 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -217,6 +217,7 @@ typedef enum pa_bluetooth_cmee { - CMEE_NO_CONNECTION_TO_PHONE = 1, - CMEE_OPERATION_NOT_ALLOWED = 3, - CMEE_OPERATION_NOT_SUPPORTED = 4, -+ CMEE_INVALID_CHARACTERS_TEXT_STRING = 25, - CMEE_NO_NETWORK_SERVICE = 30 - } pa_bluetooth_cmee_t; - --- -2.35.1 - diff --git a/temp/pulseaudio/0023-bluetooth-support-ATA.patch b/temp/pulseaudio/0023-bluetooth-support-ATA.patch deleted file mode 100644 index f5c25813d..000000000 --- a/temp/pulseaudio/0023-bluetooth-support-ATA.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 48286245124ed08e57624b1e069cfa2ce4776568 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Sat, 16 Apr 2022 19:37:04 +0200 -Subject: [PATCH 23/26] bluetooth: support ATA - -Accept incoming calls if the HF sends 'ATA'. -The first call in the call list is accepted, -multiparty calling is not supported (yet). ---- - src/modules/bluetooth/backend-native.c | 31 ++++++++++++++++++++++++++ - 1 file changed, 31 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 306de44a7..6f6241479 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -873,6 +873,37 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - - /* AT response will be reported through PA_BLUETOOTH_HOST_OPERATION_{SUCCEED, FAILED} hook */ - return false; -+ } else if (strstr(buf, "ATA")) { -+ pa_hashmap *calls; -+ char *call_key = NULL; -+ call_status_t *call = NULL; -+ -+ /* ATA is only possible if ModemManager is availble */ -+ if (!discovery->native_backend->modemmanager || !pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ pa_log_debug("ModemManager backend unavailable, cannot reject call with ATA"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } else if (!pa_modemmanager_has_service(discovery->native_backend->modemmanager)) { -+ pa_log_debug("No network service, cannot accept call with ATA"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_NETWORK_SERVICE); -+ return false; -+ } -+ -+ /* Accept call is available */ -+ calls = pa_modemmanager_get_calls(discovery->native_backend->modemmanager); -+ call_key = pa_modemmanager_get_active_call_key(discovery->native_backend->modemmanager); -+ if (call_key) -+ call = pa_hashmap_get(calls, call_key); -+ -+ if (call && call->status == PA_MODEMMANAGER_CALL_STATE_RINGING && call->is_incoming) -+ pa_modemmanager_accept_call(discovery->native_backend->modemmanager, call_key); -+ else { -+ pa_log_warn("Cannot accept call, call must be incoming and ringing"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_ALLOWED); -+ } -+ -+ /* AT response will be reported through PA_BLUETOOTH_HOST_OPERATION_{SUCCEED, FAILED} hook */ -+ return false; - } - - /* --- -2.35.1 - diff --git a/temp/pulseaudio/0024-bluetooth-support-AT-CHUP.patch b/temp/pulseaudio/0024-bluetooth-support-AT-CHUP.patch deleted file mode 100644 index e37886306..000000000 --- a/temp/pulseaudio/0024-bluetooth-support-AT-CHUP.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 12610afa56b74e7db44086d81709faedda2b83e9 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Sat, 16 Apr 2022 19:53:38 +0200 -Subject: [PATCH 24/26] bluetooth: support AT+CHUP - -Hangup or reject a call when the HF sends 'AT+CHUP'. -If the call is on going, it is ended. If the call is ringing and -incoming, it is rejected. The same interface in ModemManager is used for -this functionality. This AT command is only available if ModemManager is -present. ---- - src/modules/bluetooth/backend-native.c | 37 ++++++++++++++++++++++++-- - 1 file changed, 35 insertions(+), 2 deletions(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index 6f6241479..d502cff78 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -144,7 +144,7 @@ typedef enum pa_bluetooth_ag_to_hf_indicators { - /* gateway features we support, which is as little as we can get away with */ - static uint32_t hfp_features = - /* HFP 1.6 requires this */ -- (1 << HFP_AG_ESTATUS ) | (1 << HFP_AG_CODECS) | (1 << HFP_AG_INDICATORS) | (1 << HFP_AG_EERR); -+ (1 << HFP_AG_ESTATUS ) | (1 << HFP_AG_CODECS) | (1 << HFP_AG_INDICATORS) | (1 << HFP_AG_EERR) | (1 << HFP_AG_REJECT); - - #define HSP_AG_PROFILE "/Profile/HSPAGProfile" - #define HFP_AG_PROFILE "/Profile/HFPAGProfile" -@@ -904,7 +904,40 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - - /* AT response will be reported through PA_BLUETOOTH_HOST_OPERATION_{SUCCEED, FAILED} hook */ - return false; -- } -+ } else if (strstr(buf, "AT+CHUP")) { -+ pa_hashmap *calls; -+ char *call_key = NULL; -+ call_status_t *call = NULL; -+ -+ /* AT+CHUP is only possible if ModemManager is availble */ -+ if (!discovery->native_backend->modemmanager || !pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ pa_log_debug("ModemManager backend unavailable, cannot reject call with AT+CHUP"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } else if (!pa_modemmanager_has_service(discovery->native_backend->modemmanager)) { -+ pa_log_debug("No network service, cannot reject call with ATD+CHUP"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_NETWORK_SERVICE); -+ return false; -+ } -+ -+ /* Hangup/reject call is available */ -+ calls = pa_modemmanager_get_calls(discovery->native_backend->modemmanager); -+ call_key = pa_modemmanager_get_active_call_key(discovery->native_backend->modemmanager); -+ if (call_key) -+ call = pa_hashmap_get(calls, call_key); -+ -+ if (call && (call->status == PA_MODEMMANAGER_CALL_STATE_ACTIVE -+ || call->status == PA_MODEMMANAGER_CALL_STATE_RINGING -+ || call->status == PA_MODEMMANAGER_CALL_STATE_DIALING)) -+ pa_modemmanager_end_call(discovery->native_backend->modemmanager, call_key); -+ else { -+ pa_log_warn("Cannot end call, call must be active, ringing or dialing"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_ALLOWED); -+ } -+ -+ /* AT response will be reported through PA_BLUETOOTH_HOST_OPERATION_{SUCCEED, FAILED} hook */ -+ return false; -+ } - - /* - * Out-of-spec Bluetooth HFP 1.8 AT commands. --- -2.35.1 - diff --git a/temp/pulseaudio/0025-bluetooth-support-ATD-number.patch b/temp/pulseaudio/0025-bluetooth-support-ATD-number.patch deleted file mode 100644 index eb92ce75c..000000000 --- a/temp/pulseaudio/0025-bluetooth-support-ATD-number.patch +++ /dev/null @@ -1,104 +0,0 @@ -From d2748e1952c282ce82e93daaeb2f25bb10ce46ab Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Sat, 16 Apr 2022 20:29:54 +0200 -Subject: [PATCH 25/26] bluetooth: support ATD$number; - -Start a call when HF sends 'ATD$number;' -This AT command is only available when ModemManager is present. -Number is filtered for any invalid characters, if an invalid character -is found, the call is aborted and an error is returned. ---- - src/modules/bluetooth/backend-native.c | 57 ++++++++++++++++++++++++++ - src/modules/bluetooth/bluez5-util.h | 1 + - 2 files changed, 58 insertions(+) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index d502cff78..b6991ae13 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -44,6 +44,9 @@ - #include "upower.h" - #include "modemmanager.h" - -+#define MAX_NUMBER_LENGTH 30 -+#define STR_VALUE(x) STR(x) -+#define STR(x) #x - #define RING_WAIT_TIME ((pa_usec_t) (3 * PA_USEC_PER_SEC)) - #define MANDATORY_CALL_INDICATORS \ - "(\"call\",(0-1))," \ -@@ -935,6 +938,60 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf - rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_ALLOWED); - } - -+ /* AT response will be reported through PA_BLUETOOTH_HOST_OPERATION_{SUCCEED, FAILED} hook */ -+ return false; -+ } else if (strstr(buf, "ATD")) { -+ int k, j; -+ char number[MAX_NUMBER_LENGTH]; -+ char number_filtered[MAX_NUMBER_LENGTH]; -+ -+ /* ATD$number; is only possible if ModemManager is availble */ -+ if (!discovery->native_backend->modemmanager || !pa_modemmanager_has_modem(discovery->native_backend->modemmanager)) { -+ pa_log_debug("ModemManager backend unavailable, cannot create call with ATD$number;"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_CONNECTION_TO_PHONE); -+ return false; -+ } else if (!pa_modemmanager_has_service(discovery->native_backend->modemmanager)) { -+ pa_log_debug("No network service, cannot create call with ATD$number;"); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_NO_NETWORK_SERVICE); -+ return false; -+ } -+ -+ /* Try to parse number from ATD command */ -+ if (sscanf(buf, "ATD%" STR_VALUE(MAX_NUMBER_LENGTH) "s;", number) != 1) { -+ pa_log_debug("Cannot parse ATD$number: \"%s\"", buf); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); -+ return false; -+ } -+ -+ /* -+ * Filter extracted number from invalid characters -+ * Allowed characters: 0-9, *, #, +, A-C -+ */ -+ k=0; -+ memset(number_filtered, '\0', sizeof(char) * MAX_NUMBER_LENGTH); -+ for (j=0; j < MAX_NUMBER_LENGTH; j++) { -+ if ((number[j] >= '0' && number[j] <= '9') -+ || (number[j] == '*') -+ || (number[j] == '#') -+ || (number[j] == '+') -+ || (number[j] >= 'A' && number[j] <= 'C')) { -+ number_filtered[k] = number[j]; -+ k++; -+ } -+ /* ATD commands ends with ';'. */ -+ else if (number[j] == ';') -+ break; -+ /* Send error for invalid characters */ -+ else { -+ pa_log_warn("Call creation canceled, invalid character found in dial string: %c", number[j]); -+ rfcomm_write_error(discovery->native_backend, fd, CMEE_INVALID_CHARACTERS_DIAL_STRING); -+ return false; -+ } -+ } -+ -+ /* Create call for filtered number */ -+ pa_modemmanager_start_call(discovery->native_backend->modemmanager, number_filtered); -+ - /* AT response will be reported through PA_BLUETOOTH_HOST_OPERATION_{SUCCEED, FAILED} hook */ - return false; - } -diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h -index 4802cca69..ccbe6ba78 100644 ---- a/src/modules/bluetooth/bluez5-util.h -+++ b/src/modules/bluetooth/bluez5-util.h -@@ -218,6 +218,7 @@ typedef enum pa_bluetooth_cmee { - CMEE_OPERATION_NOT_ALLOWED = 3, - CMEE_OPERATION_NOT_SUPPORTED = 4, - CMEE_INVALID_CHARACTERS_TEXT_STRING = 25, -+ CMEE_INVALID_CHARACTERS_DIAL_STRING = 27, - CMEE_NO_NETWORK_SERVICE = 30 - } pa_bluetooth_cmee_t; - --- -2.35.1 - diff --git a/temp/pulseaudio/0026-bluetooth-strip-additional-out-of-spec-r-n-chars.patch b/temp/pulseaudio/0026-bluetooth-strip-additional-out-of-spec-r-n-chars.patch deleted file mode 100644 index 1130009d0..000000000 --- a/temp/pulseaudio/0026-bluetooth-strip-additional-out-of-spec-r-n-chars.patch +++ /dev/null @@ -1,60 +0,0 @@ -From aff9bf69960c3e2ac1d7c35176e9f3b34389f656 Mon Sep 17 00:00:00 2001 -From: Dylan Van Assche -Date: Tue, 19 Apr 2022 20:15:09 +0200 -Subject: [PATCH 26/26] bluetooth: strip additional out-of-spec '\r\n' chars - -Some HF devices do not comply strictly with the HFP specification -and send additional '\r\n' sequences besides the expected ones. -This breaks AT command parsing in PulseAudio. - -To work around this problem, strip these characters before processing -the AT command and responses. ---- - src/modules/bluetooth/backend-native.c | 22 ++++++++++++++++++---- - 1 file changed, 18 insertions(+), 4 deletions(-) - -diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c -index b6991ae13..8aa83f025 100644 ---- a/src/modules/bluetooth/backend-native.c -+++ b/src/modules/bluetooth/backend-native.c -@@ -1556,19 +1556,33 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i - } - - if (events & PA_IO_EVENT_INPUT) { -- char buf[512]; -+ char buf[512], raw_buf[512]; - ssize_t len; - int gain, dummy; - bool do_reply = false; - int vendor, product, version, features; -- int num; -+ int num, i, j; - -- len = pa_read(fd, buf, 511, NULL); -+ len = pa_read(fd, raw_buf, 511, NULL); - if (len < 0) { - pa_log_error("RFCOMM read error: %s", pa_cstrerror(errno)); - goto fail; - } -- buf[len] = 0; -+ raw_buf[len] = 0; -+ -+ /* -+ * Filter '\r' and '\n' characters out since some HF devices -+ * send too much \r\n sequences in their responses -+ */ -+ memset(buf, '\0', sizeof(char) * 512); -+ j=0; -+ for (i=0; i<512; i++) { -+ if (raw_buf[i] == '\r' || raw_buf[i] == '\n') -+ continue; -+ buf[j] = raw_buf[i]; -+ j++; -+ } -+ buf[j] = 0; - pa_log_debug("RFCOMM << %s", buf); - - /* There are only four HSP AT commands: --- -2.35.1 - diff --git a/temp/pulseaudio/APKBUILD b/temp/pulseaudio/APKBUILD deleted file mode 100644 index 15136677f..000000000 --- a/temp/pulseaudio/APKBUILD +++ /dev/null @@ -1,285 +0,0 @@ -# Forked from Alpine for enhanced Bluetooth HFP support - -pkgname=pulseaudio -pkgver=9999_git20220621 -_pkgver=16.1 -pkgrel=2 -pkgdesc="featureful, general-purpose sound server" -provider_priority=10 -url="https://www.freedesktop.org/wiki/Software/PulseAudio/" -arch="all" -license="LGPL-2.1-or-later" -options="pmb:strict !check" -makedepends=" - meson - tdb-dev - alsa-lib-dev - libasyncns-dev - dbus-dev - glib-dev - gtk+3.0-dev - orc-dev - orc-compiler - libsndfile-dev - soxr-dev - libx11-dev - libxcb-dev - libice-dev - libsm-dev - libxtst-dev - avahi-dev - sbc-dev - fftw-dev - jack-dev - openssl-dev>3 - speexdsp-dev - eudev-dev - libcap-dev - bluez-dev - check-dev - libtool - perl - perl-xml-parser - m4 - gstreamer-dev - gst-plugins-base-dev - modemmanager-dev - " -depends_openrc="alsa-utils alsa-utils-openrc" -subpackages=" - $pkgname-dev - $pkgname-doc - $pkgname-bluez - libpulse-mainloop-glib:_libpulse_mainloop_glib - $pkgname-alsa - $pkgname-utils - $pkgname-jack - $pkgname-zeroconf - $pkgname-openrc - $pkgname-bash-completion - $pkgname-zsh-completion - $pkgname-lang - $pkgname-equalizer - libpulse:_libpulse - " -install="pulseaudio.post-install" -builddir="$srcdir/$pkgname-$_pkgver" -source="https://freedesktop.org/software/pulseaudio/releases/pulseaudio-$_pkgver.tar.xz - 0001-bluez5-util-move-pa_bluetooth_discovery-to-header.patch - 0002-bluetooth-add-AT-BIA-support.patch - 0003-bluetooth-add-UPower-backend.patch - 0004-bluetooth-hook-up-UPower-backend.patch - 0005-bluetooth-add-ModemManager-backend.patch - 0006-bluetooth-only-reply-OK-for-supported-AT-cmds.patch - 0007-bluetooth-Always-reply-to-AT-CIND.patch - 0008-bluetooth-support-AT-CMEE.patch - 0009-bluetooth-support-AT-NREC.patch - 0010-bluetooth-support-AT-BCC.patch - 0011-bluetooth-support-AT-COPS.patch - 0012-bluetooth-support-AT-CNUM.patch - 0013-bluetooth-support-more-AT-CIND-indicators.patch - 0014-bluetooth-support-AT-CLIP.patch - 0015-bluetooth-support-AT-CREG.patch - 0016-bluetooth-support-AT-CGMM.patch - 0017-bluetooth-support-AT-CGMI.patch - 0018-bluetooth-support-AT-CGMR.patch - 0019-bluetooth-support-AT-CGSN.patch - 0020-bluetooth-support-AT-CLCC.patch - 0021-bluetooth-support-CIEV-RING-and-CLIP-URCs.patch - 0022-bluetooth-support-AT-VTS.patch - 0023-bluetooth-support-ATA.patch - 0024-bluetooth-support-AT-CHUP.patch - 0025-bluetooth-support-ATD-number.patch - 0026-bluetooth-strip-additional-out-of-spec-r-n-chars.patch - link-libintl.patch - remove-once-test.patch - $pkgname.initd - $pkgname.confd - " - -case "$CARCH" in - x86|x86_64|aarch64) - makedepends="$makedepends webrtc-audio-processing-dev" - _webrtc_aec="enabled" - ;; - * ) - _webrtc_aec="disabled" # webrtc-audio-processing not available - ;; -esac - -prepare() { - default_prepare - - sed "s|sysconfdir, 'dbus-1'|datadir, 'dbus-1'|" \ - -i src/daemon/meson.build -} - -build() { - # See pma#2368 - _lto_enable="false" - abuild-meson \ - -Db_lto="$_lto_enable" \ - -Dgcov=false \ - -Dman=true \ - -Dtests="$(want_check && echo true || echo false)" \ - -Dsystem_user=pulse \ - -Dsystem_group=pulse \ - -Ddatabase=tdb \ - -Dalsa=enabled \ - -Dasyncns=enabled \ - -Davahi=enabled \ - -Dbluez5=enabled \ - -Ddbus=enabled \ - -Dfftw=enabled \ - -Dglib=enabled \ - -Dgsettings=enabled \ - -Dgtk=enabled \ - -Dhal-compat=false \ - -Dipv6=true \ - -Djack=enabled \ - -Dlirc=disabled \ - -Dopenssl=enabled \ - -Dorc=enabled \ - -Dsamplerate=disabled \ - -Dsoxr=enabled \ - -Dspeex=enabled \ - -Dsystemd=disabled \ - -Dudev=enabled \ - -Dx11=enabled \ - -Dudevrulesdir=/usr/lib/udev/rules.d \ - -Dgstreamer=enabled \ - -Dwebrtc-aec="$_webrtc_aec" \ - -Ddoxygen=false \ - -Dstream-restore-clear-old-devices=true \ - . output - meson compile -C output -} - -check() { - XDG_RUNTIME_DIR="$(mktemp -d)" \ - meson test --no-rebuild --print-errorlogs -C output -} - -package() { - DESTDIR="$pkgdir" meson install --no-rebuild -C output - - install -Dm755 "$srcdir"/$pkgname.initd "$pkgdir"/etc/init.d/$pkgname - install -Dm644 "$srcdir"/$pkgname.confd "$pkgdir"/etc/conf.d/$pkgname - - # Assumes that any volume adjustment is intended by the user, who can control - # each app's volume. Misbehaving clients can trigger earsplitting volume - # jumps. App volumes can diverge wildly and cause apps without their own - # volume control to fall below sink volume; a sink-only volume control will - # suddenly be unable to make such an app loud enough. - sed '/flat-volumes/iflat-volumes = no' -i "$pkgdir"/etc/pulse/daemon.conf - - # Disable cork-request module, can result in e.g. media players unpausing - # when there's a Skype call incoming - sed 's|/usr/bin/pactl load-module module-x11-cork-request|#&|' \ - -i "$pkgdir"/usr/bin/start-pulseaudio-x11 - - # Required by qpaeq - sed '/Load several protocols/aload-module module-dbus-protocol' \ - -i "$pkgdir"/etc/pulse/default.pa -} - -openrc() { - replaces="$pkgname-system" # Backward compatibility - default_openrc -} - -_libpulse() { - pkgdesc="Pulseaudio libraries" - replaces="$pkgname-libs" - - amove usr/lib/pulseaudio/libpulse* - amove usr/lib/libpulse.so.0* - amove usr/lib/libpulse-simple.so.0* - amove etc/pulse/client.conf -} - -_libpulse_mainloop_glib() { - pkgdesc="Pulseaudio mainloop-glib library" - - amove usr/lib/libpulse-mainloop-glib.so.* -} - -bluez() { - pkgdesc="Pulseaudio Bluetooth support" - install_if="$pkgname=$pkgver-r$pkgrel bluez" - provider_priority=10 # highest (other provider is pipewire-pulse) - - amove usr/lib/pulseaudio/modules/*bluez*.so - amove usr/lib/pulseaudio/modules/*bluetooth*.so -} - -alsa() { - pkgdesc="Pulseaudio ALSA support" - install_if="$pkgname=$pkgver-r$pkgrel alsa-lib" - - amove usr/lib/pulseaudio/modules/*alsa*.so -} - -utils() { - pkgdesc="Pulseaudio utilities" - - amove usr/bin/pa* - amove usr/bin/start-pulseaudio-x11 -} - -jack() { - pkgdesc="Pulseaudio JACK support" - - amove usr/lib/pulseaudio/modules/*jack*.so -} - -zeroconf() { - pkgdesc="Pulseaudio Zeroconf support" - depends="avahi" - - amove usr/lib/pulseaudio/modules/*avahi*.so - amove usr/lib/pulseaudio/modules/*zeroconf*.so - amove usr/lib/pulseaudio/modules/*raop*.so -} - -equalizer() { - pkgdesc="Equalizer for $pkgname" - depends="pulseaudio=$pkgver-r$pkgrel py3-qt5 py3-dbus" - - amove usr/bin/qpaeq - amove usr/lib/pulseaudio/modules/module-equalizer-sink.so -} - -sha512sums=" -33b0b4292f05e0882f3ec822cf5720414bb34c523d80fe287b9740d6be219787c562e8024c9b0d9e2ee010771ca72c7ae4f27df1bbef9c9cb6bb6a23cbcc412f pulseaudio-16.1.tar.xz -c0a5a4854be7f8c5421671b7c5b890d9f097f8d0a1ac20009549786c28a66c9f28ac58863eea12f467ced87cbdb6093ea1a8444b9f1c1abda2aaa7e64c6c640a 0001-bluez5-util-move-pa_bluetooth_discovery-to-header.patch -c84e4e0591c21348be197fae4b54bdd437a8e39803daa8448fcaf03119a39723214b81b8c32b5a6b166fc4449b78a44c7633bd09a77902903d15b17299a58234 0002-bluetooth-add-AT-BIA-support.patch -a2ceac55f6cc8097569fec5e7a76f9e6ce3c79dacb27f5f19baed3a808e9be30e3c9a22b84b74e3d774d16f2d45c93e64a1248fc56b6d3cd897f620d46f581f9 0003-bluetooth-add-UPower-backend.patch -ffe399905f400628c0bcb732c6000ced30a3835884dfd0910bebf4af81ca63e743bb144e845978fda02ec4c81295e87ccf596b55d68e4c59ff827e5b1102a72e 0004-bluetooth-hook-up-UPower-backend.patch -58f7fc83c3c15e9df3b36cc192113d29fc6020823a36b30b68702373248a93c6e60a174a3c71c693547d33de55a9d20e72cf65f3957cea323b04c222d5d701ff 0005-bluetooth-add-ModemManager-backend.patch -98c0b80638603899b1639fedcc5edcde721f22cd3e7abed425015c933e65769b295a80b0d6a444fc5144cd1c6851dce41710dd8361fce2bfe5022ed913ad82ba 0006-bluetooth-only-reply-OK-for-supported-AT-cmds.patch -535b242b76fc494138a16b326708eaa4d410fbc5a779bda1471e25c56440d7e9a4c80b0bccd3ba5e0026f40c09e3b7b84bbb409e51c020deff8c9b0ead74fb71 0007-bluetooth-Always-reply-to-AT-CIND.patch -cdd7d3d47932c11ff7bd2bd4589b26dd3d92180fd4c156e70f57dcf5b560e05cd37d548a6e5280e47d258804f9dcaa3dd498d9dcdbb2e5c4e87f9f81dc7de73a 0008-bluetooth-support-AT-CMEE.patch -7b6a99b1d76781c36007b746bf2a47f163efeca843f36d75d4485c688d8f3a7fcafc9c36c1aa2ff02759184e20d387a89beea36ca0da64e23bb29dfc71feb55c 0009-bluetooth-support-AT-NREC.patch -b2bda75da4a4a5a2511fd3cd9ac8da8b3c59276a6396106e2249dd31053b68797f3f923177e6cd06fd7ae3cb3e2110e8bf8facb269d80a0e637a6f38cd8bb68c 0010-bluetooth-support-AT-BCC.patch -53bdf256fb2db1d6997204ba9504b584423946e177f8e1a819de0fafea29092a1925a0f7cde253635aa1f83c67e6b91bf3608fe543bc2185cd2ddf4aa5942054 0011-bluetooth-support-AT-COPS.patch -f3063daac100ef5d1fba792bb900a434be8cd0f9093a9be1ab68d84b8f94f39efc16c59d749f293e9b7556632866688757dc3d6e922096102f4583acb3f3cf5a 0012-bluetooth-support-AT-CNUM.patch -19880702e533bb46a67f09e8848bc2741a275c20b847dea96a0dba0424639715b0cd3d25a9168916cdc4ae4462b67855a3bb3b1d8384c12292fbacc032c2f0fa 0013-bluetooth-support-more-AT-CIND-indicators.patch -cd3d67672ff77d7908b01b4a377901d5e008b31b88d0e2c86918263c10a250aaf807cbf54cc3b095b1bf38ee533b3c0f409c5e1e2ced1df045fc64f421e02f78 0014-bluetooth-support-AT-CLIP.patch -967983f1e589945da4c0139d3d7d7be2c796f4a9ab52b344acd19723170c220dd7e00feafd2ad0a0481940f27c01176ccd54418758acedbc1c686d3426df9812 0015-bluetooth-support-AT-CREG.patch -61c400797405120cb065dea285e79a0056d716ff5ade3c8ea5a7e9f205c6895c0885f5ddb8c1abeec08ce3cf195b79bf7dc4d20281c5f7d5ee668accddab8cb9 0016-bluetooth-support-AT-CGMM.patch -42a3739a44bdcc01df0f3fa6fac5efb88f4fcf69686b529f8390d58b4becfd9b948d3ddea80aa5b8d007d96e22b4a87dedb5cbff610f008c317b31c8ae700774 0017-bluetooth-support-AT-CGMI.patch -6a4cd357126ebe99647bd3f4780ca109f2e823e0653851663d1d000b98e156ac17293058c8b94263371e303233f1c8e56073b523c91588d75989acb45b660ac2 0018-bluetooth-support-AT-CGMR.patch -b83d00a32c8e28c566e74ab8edd35e107313f31f4ff2ead21d6f9446a79f6ec520e7a737ef79844d46fbcceaad74fdaeb14ad37a865284c259f768156514f858 0019-bluetooth-support-AT-CGSN.patch -c58265d7c8f201765a254b2b26ff38f89ac2392acfb57024592e01096a997394322e726425fd02c37e21f6ab72638206d891354b2cd950102e7c13d87e026d40 0020-bluetooth-support-AT-CLCC.patch -c93be49e11055af356a01cc3545f984348dcff052f8777ef0127e2a9cab241fa83682550a5ffd69589d6603f1fb47ad3da248ff055b6c983e50ed817c63d1008 0021-bluetooth-support-CIEV-RING-and-CLIP-URCs.patch -d0663f8962f916d2149f44fe6d598ddea6df3cee542ee5ba9b418d05397c88a9c16368f9da2f96750e8bfb6a8e747e59fdc10f52fa59d1096ed6e59625c5dabd 0022-bluetooth-support-AT-VTS.patch -a39cbab500be77e88a7b8dd615ce7e1a2f8d678b19fe823552bb5d1279e2ae06aac3c353e03e10d601c53a5befe731ce00f8163c7b3a1e7b4b0c26a4fdde1730 0023-bluetooth-support-ATA.patch -9b93fd3dd2859b600d9eed9097f89b2a26220603eccdc61c6edb9b3b7488a97dbc5cee0dd4c40da3d1cbd8849023fd48f30ea1da0668c0bae189337bc8d1db9f 0024-bluetooth-support-AT-CHUP.patch -3eec77a1b39dbab93a4284de433946b70d6b9f972e62b02f076cb4a45b1f288e32ae05d8d557ed13ef21eded407951f9c0f48c78bdac9d47f318d2c7b288e10c 0025-bluetooth-support-ATD-number.patch -76b486095b1f2bb5d23837ed8f08d5ac7533e7c9621b2534c85b39a932663ffcf86b7fefaba1f2abc6aa7a95660c658cbcdeef20427b8ebb6e05cf532ee48731 0026-bluetooth-strip-additional-out-of-spec-r-n-chars.patch -2c31c5bc592e748248215f8f62f85687cfec230b05f65441e6dafa5fa77d4967e97636209b2011a4501ed1337ecd880b264baa175586fc85183a980846cb8146 link-libintl.patch -c1223cf42538d91f31dbcb1a167537a1d3b6e8a3bf1b454cdebf95c25ca6f3b444848e9d546f092988851f71fe2c9dd9c4a781a58795e2f57d98563963a4630a remove-once-test.patch -d3a95453361d4b12e2d4df73a72bbdc9343e2a46e8f5f3aac07b3cb1f9e016fd89816745f485468d144911900a2b38741a371f91cf08285c4b4988e4403d91a0 pulseaudio.initd -75b54581591519d63a3362b155c0f9b0501a60763ab394693a456c44d0216138cf3a40bdd0f7442028663bc045e9ffee286f8f8eaf2ee3bb17379b43615fee0e pulseaudio.confd -" diff --git a/temp/pulseaudio/link-libintl.patch b/temp/pulseaudio/link-libintl.patch deleted file mode 100644 index 7dbbb3ecd..000000000 --- a/temp/pulseaudio/link-libintl.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/meson.build b/meson.build -index 658eeee..349752e 100644 ---- a/meson.build -+++ b/meson.build -@@ -307,6 +307,12 @@ else - libintl_dep = cc.find_library('intl') - endif - -+if cc.has_function('libintl_dgettext') -+ libintl_dep = [] -+else -+ libintl_dep = cc.find_library('intl') -+endif -+ - # Symbols - - if cc.has_header_symbol('signal.h', 'SIGXCPU') -diff --git a/src/pulse/meson.build b/src/pulse/meson.build -index aaebff5..3f68ac3 100644 ---- a/src/pulse/meson.build -+++ b/src/pulse/meson.build -@@ -84,7 +84,7 @@ libpulse = shared_library('pulse', - dependencies : [libm_dep, thread_dep, libpulsecommon_dep, dbus_dep, dl_dep, iconv_dep, libintl_dep], - implicit_include_directories : false) - --libpulse_dep = declare_dependency(link_with: libpulse) -+libpulse_dep = declare_dependency(link_with: libpulse, dependencies: libintl_dep) - - install_headers( - libpulse_headers, 'simple.h', diff --git a/temp/pulseaudio/pulseaudio.confd b/temp/pulseaudio/pulseaudio.confd deleted file mode 100644 index 1d31d342a..000000000 --- a/temp/pulseaudio/pulseaudio.confd +++ /dev/null @@ -1,7 +0,0 @@ -# Config file for /etc/init.d/pulseaudio -# $Header: /var/cvsroot/gentoo-x86/media-sound/pulseaudio/files/pulseaudio.conf.d,v 1.6 2006/07/29 15:34:18 flameeyes Exp $ - -# For more see "pulseaudio -h". - -# Startup options -PA_OPTS="--log-target=syslog --disallow-module-loading=1" diff --git a/temp/pulseaudio/pulseaudio.initd b/temp/pulseaudio/pulseaudio.initd deleted file mode 100644 index 0d95e7952..000000000 --- a/temp/pulseaudio/pulseaudio.initd +++ /dev/null @@ -1,81 +0,0 @@ -#!/sbin/openrc-run -# Copyright 1999-2011 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-x86/media-sound/pulseaudio/files/pulseaudio.init.d-5,v 1.1 2011/03/27 16:58:49 ssuominen Exp $ - -depend() { - need localmount - use net - - local script="/etc/pulse/system.pa" - - for opt in ${PA_OPTS}; do - case "$opt" in - --file=*) script="${opt#*=}" ;; - -F*) script="${opt#-F}" ;; - esac - done - - config "$script" - - local needs="$(get_options need)" - if [ -n "${needs}" ]; then - need ${needs} - return - fi - - if grep -E -q '^[[:space:]]*load-module[[:space:]]+module-console-kit' "$script"; then - needs="${needs} consolekit" - fi - -#ifdef UDEV - if grep -E -q '^[[:space:]]*load-module[[:space:]]+module-udev-detect' "$script"; then - needs="${needs} udev" - fi -#endif - -#ifdef AVAHI - if grep -E -q '^[[:space:]]*load-module[[:space:]]+module-zeroconf-publish' "$script"; then - needs="${needs} avahi-daemon" - fi -#endif - -#ifdef BLUETOOTH - if grep -E -q '^[[:space:]]*load-module[[:space:]]+module-bt-proximity' "$script"; then - needs="${needs} bluetooth" - fi -#endif - -#ifdef ALSA - if grep -E -q '^[[:space:]]*load-module[[:space:]]+module-alsa-(sink|source)' "$script" || - grep -E -q '^[[:space:]]*load-module[[:space:]]+module-(udev-)?detect' "$script" || - grep -E -q '^[[:space:]]*add-autoload-source[[:space:]]+(input|output)[[:space:]]+module-alsa-(sink|source)' "$script"; then - needs="${needs} alsa" # in Alpine install alsa-utils to provide /etc/init.d/alsa (not alsasound as in Gentoo). - fi -#endif - - need "${needs}" - save_options need "${needs}" -} - -start() { - if [ -z "${PULSEAUDIO_SHOULD_NOT_GO_SYSTEMWIDE}" ]; then - eerror "Please don't use system wide PulseAudio unless you read the" - eerror "documentation available at http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/SystemWide/" - eerror "" - eerror "When you're done, please set the variable PULSEAUDIO_SHOULD_NOT_GO_SYSTEMWIDE in" - eerror "/etc/conf.d/pulseaudio . Please remember that upstream does not support this mode" - eerror "when used for standard desktop configurations." - return 1 - fi - ebegin "Starting pulseaudio" - PA_ALL_OPTS="${PA_OPTS} --fail=1 --daemonize=1 --system" - start-stop-daemon --start --exec /usr/bin/pulseaudio -- ${PA_ALL_OPTS} - eend $? -} - -stop() { - ebegin "Stopping pulseaudio" - start-stop-daemon --stop --quiet --exec /usr/bin/pulseaudio --pidfile /var/run/pulse/pid - eend $? -} diff --git a/temp/pulseaudio/pulseaudio.post-install b/temp/pulseaudio/pulseaudio.post-install deleted file mode 100644 index 2464e7515..000000000 --- a/temp/pulseaudio/pulseaudio.post-install +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# Alpine Linux post-install script for socklog -# Copyright 2019 Leo (thinkabit.ukim@gmail.com) -# Distributed under the terms of the GNU General Public License, v2 or later - -addgroup -S pulse-access 2>/dev/null -addgroup -S pulse 2>/dev/null - -adduser -S -D -H -h /var/run/pulse -g "PulseAudio daemon" -G pulse pulse 2>/dev/null -adduser pulse audio 2>/dev/null - diff --git a/temp/pulseaudio/remove-once-test.patch b/temp/pulseaudio/remove-once-test.patch deleted file mode 100644 index 757bcbeb5..000000000 --- a/temp/pulseaudio/remove-once-test.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/src/tests/meson.build -+++ b/src/tests/meson.build -@@ -111,13 +111,6 @@ - ] - endif - -- if host_machine.system() != 'darwin' -- default_tests += [ -- [ 'once-test', 'once-test.c', -- [ check_dep, thread_dep, libpulse_dep, libpulsecommon_dep, libpulsecore_dep, libatomic_ops_dep ] ], -- ] -- endif -- - if alsa_dep.found() - default_tests += [ - [ 'alsa-mixer-path-test', 'alsa-mixer-path-test.c',