From 275d2bc603d60c1b6c715e0d74ca4bf14fbcdcec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Danis?= Date: Fri, 16 Sep 2022 14:43:37 +0200 Subject: [PATCH] bluez5: backend-native: Link with ModemManager Modem3GPP object The Modem3GPP provides information about the network the modem is registered to like the operator name and roaming status. --- spa/plugins/bluez5/backend-native.c | 55 +++++++++++++++++++++++-- spa/plugins/bluez5/modemmanager.c | 62 +++++++++++++++++++++++++++++ spa/plugins/bluez5/modemmanager.h | 2 + 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c index 4493bd2e5..9d29e8b00 100644 --- a/spa/plugins/bluez5/backend-native.c +++ b/spa/plugins/bluez5/backend-native.c @@ -68,19 +68,22 @@ enum { HFP_AG_INITIAL_CODEC_SETUP_WAIT }; -#define CIND_INDICATORS "(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5))" +#define CIND_INDICATORS "(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2)),(\"signal\",(0-5)),(\"roam\",(0-1))" enum { CIND_SERVICE = 1, CIND_CALL, CIND_CALLSETUP, CIND_CALLHELD, CIND_SIGNAL, + CIND_ROAM, CIND_MAX }; struct modem { bool network_has_service; unsigned int signal_strength; + bool network_is_roaming; + char *operator_name; }; struct impl { @@ -813,9 +816,9 @@ static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf) rfcomm_send_reply(rfcomm, "+CIND:%s", CIND_INDICATORS); rfcomm_send_reply(rfcomm, "OK"); } else if (spa_strstartswith(buf, "AT+CIND?")) { - rfcomm_send_reply(rfcomm, "+CIND: %d,%d,0,0,%d", backend->modem.network_has_service, + rfcomm_send_reply(rfcomm, "+CIND: %d,%d,0,0,%d,%d", backend->modem.network_has_service, rfcomm->cind_call_active, - backend->modem.signal_strength); + backend->modem.signal_strength, backend->modem.network_is_roaming); rfcomm_send_reply(rfcomm, "OK"); } else if (spa_strstartswith(buf, "AT+CMER")) { int mode, keyp, disp, ind; @@ -926,6 +929,25 @@ next_indicator: } rfcomm_send_reply(rfcomm, "OK"); + } else if (spa_strstartswith(buf, "AT+COPS=")) { + unsigned int mode, val; + + if (sscanf(buf, "AT+COPS=%u,%u", &mode, &val) != 2 || + mode != 3 || val != 0) { + rfcomm_send_reply(rfcomm, "ERROR"); + } else { + rfcomm_send_reply(rfcomm, "OK"); + } + } else if (spa_strstartswith(buf, "AT+COPS?")) { + if (!backend->modem.network_has_service) { + rfcomm_send_reply(rfcomm, "ERROR"); + } else { + if (backend->modem.operator_name) + rfcomm_send_reply(rfcomm, "+COPS: 0,0,\"%s\"", backend->modem.operator_name); + else + rfcomm_send_reply(rfcomm, "+COPS: 0,,"); + rfcomm_send_reply(rfcomm, "OK"); + } } else if (sscanf(buf, "AT+VGM=%u", &gain) == 1) { if (gain <= SPA_BT_VOLUME_HS_MAX) { if (!rfcomm->broken_mic_hw_volume) @@ -2311,6 +2333,29 @@ static void send_ciev_for_each_rfcomm(struct impl *backend, int indicator, int v } } +static void set_modem_operator_name(const char *name, void *user_data) +{ + struct impl *backend = user_data; + + if (backend->modem.operator_name) { + free(backend->modem.operator_name); + backend->modem.operator_name = NULL; + } + + if (name) + backend->modem.operator_name = strdup(name); +} + +static void set_modem_roaming(bool is_roaming, void *user_data) +{ + struct impl *backend = user_data; + + if (backend->modem.network_is_roaming != is_roaming) { + backend->modem.network_is_roaming = is_roaming; + send_ciev_for_each_rfcomm(backend, CIND_ROAM, is_roaming); + } +} + static void set_modem_service(bool available, void *user_data) { struct impl *backend = user_data; @@ -2357,6 +2402,8 @@ static int backend_native_free(void *data) spa_list_consume(rfcomm, &backend->rfcomm_list, link) rfcomm_free(rfcomm); + if (backend->modem.operator_name) + free(backend->modem.operator_name); free(backend); return 0; @@ -2394,6 +2441,8 @@ static const struct spa_bt_backend_implementation backend_impl = { static const struct mm_ops mm_ops = { .set_modem_service = set_modem_service, .set_modem_signal_strength = set_modem_signal_strength, + .set_modem_operator_name = set_modem_operator_name, + .set_modem_roaming = set_modem_roaming, }; struct spa_bt_backend *backend_native_new(struct spa_bt_monitor *monitor, diff --git a/spa/plugins/bluez5/modemmanager.c b/spa/plugins/bluez5/modemmanager.c index f994d5e4b..b231d35f7 100644 --- a/spa/plugins/bluez5/modemmanager.c +++ b/spa/plugins/bluez5/modemmanager.c @@ -77,6 +77,49 @@ static bool mm_dbus_connection_send_with_reply(struct impl *this, DBusMessage *m return true; } +static DBusHandlerResult mm_parse_modem3gpp_properties(struct impl *this, DBusMessageIter *props_i) +{ + while (dbus_message_iter_get_arg_type(props_i) != DBUS_TYPE_INVALID) { + DBusMessageIter i, value_i; + const char *key; + + dbus_message_iter_recurse(props_i, &i); + + dbus_message_iter_get_basic(&i, &key); + dbus_message_iter_next(&i); + dbus_message_iter_recurse(&i, &value_i); + + if (spa_streq(key, MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME)) { + char *operator_name; + + dbus_message_iter_get_basic(&value_i, &operator_name); + spa_log_debug(this->log, "Network operator code: %s", operator_name); + if (this->ops->set_modem_operator_name) + this->ops->set_modem_operator_name(operator_name, this->user_data); + } else if (spa_streq(key, MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)) { + MMModem3gppRegistrationState state; + bool is_roaming; + + dbus_message_iter_get_basic(&value_i, &state); + spa_log_debug(this->log, "Registration state: %d", state); + + if (state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING || + state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED || + state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY) + is_roaming = true; + else + is_roaming = false; + + if (this->ops->set_modem_roaming) + this->ops->set_modem_roaming(is_roaming, this->user_data); + } + + dbus_message_iter_next(props_i); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + static DBusHandlerResult mm_parse_modem_properties(struct impl *this, DBusMessageIter *props_i) { while (dbus_message_iter_get_arg_type(props_i) != DBUS_TYPE_INVALID) { @@ -175,6 +218,9 @@ static DBusHandlerResult mm_parse_interfaces(struct impl *this, DBusMessageIter this->modem.path = strdup(path); spa_log_debug(this->log, "Found Modem interface %s, path %s", interface, path); mm_parse_modem_properties(this, &props_i); + } else if (spa_streq(interface, MM_DBUS_INTERFACE_MODEM_MODEM3GPP)) { + spa_log_debug(this->log, "Found Modem3GPP interface %s, path %s", interface, path); + mm_parse_modem3gpp_properties(this, &props_i); } dbus_message_iter_next(&element_i); @@ -221,6 +267,14 @@ finish: dbus_message_unref(r); } +static void mm_clean_modem3gpp(struct impl *this) +{ + if (this->ops->set_modem_operator_name) + this->ops->set_modem_operator_name(NULL, this->user_data); + if (this->ops->set_modem_roaming) + this->ops->set_modem_roaming(false, this->user_data); +} + static void mm_clean_modem(struct impl *this) { if (this->modem.path) { @@ -258,6 +312,7 @@ static DBusHandlerResult mm_filter_cb(DBusConnection *bus, DBusMessage *m, void if (spa_streq(name, MM_DBUS_SERVICE)) { if (old_owner && *old_owner) { spa_log_debug(this->log, "ModemManager daemon disappeared (%s)", old_owner); + mm_clean_modem3gpp(this); mm_clean_modem(this); } @@ -297,6 +352,9 @@ static DBusHandlerResult mm_filter_cb(DBusConnection *bus, DBusMessage *m, void if (spa_streq(iface, MM_DBUS_INTERFACE_MODEM)) { spa_log_debug(this->log, "Modem interface %s removed, path %s", iface, path); mm_clean_modem(this); + } else if (spa_streq(iface, MM_DBUS_INTERFACE_MODEM_MODEM3GPP)) { + spa_log_debug(this->log, "Modem3GPP interface %s removed, path %s", iface, path); + mm_clean_modem3gpp(this); } dbus_message_iter_next(&element_i); @@ -322,6 +380,9 @@ static DBusHandlerResult mm_filter_cb(DBusConnection *bus, DBusMessage *m, void if (spa_streq(interface, MM_DBUS_INTERFACE_MODEM)) { spa_log_debug(this->log, "Properties changed on %s", path); mm_parse_modem_properties(this, &props_i); + } else if (spa_streq(interface, MM_DBUS_INTERFACE_MODEM_MODEM3GPP)) { + spa_log_debug(this->log, "Properties changed on %s", path); + mm_parse_modem3gpp_properties(this, &props_i); } } @@ -459,6 +520,7 @@ void mm_unregister(void *data) dbus_pending_call_unref(this->pending); } + mm_clean_modem3gpp(this); mm_clean_modem(this); if (this->filters_added) { diff --git a/spa/plugins/bluez5/modemmanager.h b/spa/plugins/bluez5/modemmanager.h index ee2b72203..550573ecf 100644 --- a/spa/plugins/bluez5/modemmanager.h +++ b/spa/plugins/bluez5/modemmanager.h @@ -30,6 +30,8 @@ struct mm_ops { void (*set_modem_service)(bool available, void *user_data); void (*set_modem_signal_strength)(unsigned int strength, void *user_data); + void (*set_modem_operator_name)(const char *name, void *user_data); + void (*set_modem_roaming)(bool is_roaming, void *user_data); }; #ifdef HAVE_BLUEZ_5_BACKEND_NATIVE_MM