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',