bluez5: require RegisterApplication() support

The `{Un}Register{Endpoint,Player}()` functions of the `org.bluez.Media1`
interface were deprecated with the introduction of the `{Un}RegisterApplication()`
functions[0][1]. Fallback to the deprecated interfaces has been present for a
long time in pipewire, but those parts in their current form are prone to
use-after-free issues (#5096). Instead of fixing them, remove them as they
have been deprecated for a long time. The first version of bluez that supports
the new interfaces is 5.51, released on 2019-09-19 [2].

[0]: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=65bd68b907a95b4748df6929383a833ecfb4b660
[1]: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=01f8fc2997524d85817adb8176e542bac9d0cdfa
[2]: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?h=5.51&id=6de4bdb957cdc85d89851420ab06ca8e226f8d4e
This commit is contained in:
Barnabás Pőcze 2026-05-04 21:03:16 +02:00
parent 31f0300c48
commit eec372ba9d
2 changed files with 5 additions and 143 deletions

View file

@ -2818,12 +2818,9 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru
if (!codec_target_profile)
return false;
if (!device->adapter->a2dp_application_registered && is_a2dp) {
/* Codec switching not supported: only plain SBC allowed */
return (codec->codec_id == A2DP_CODEC_SBC && spa_streq(codec->name, "sbc") &&
device->adapter->legacy_endpoints_registered);
}
if (!device->adapter->bap_application_registered && codec->kind == MEDIA_CODEC_BAP)
if (is_a2dp && !device->adapter->a2dp_application_registered)
return false;
if (is_bap && !device->adapter->bap_application_registered)
return false;
/* Check codec quirks */
@ -5504,28 +5501,6 @@ static DBusHandlerResult endpoint_handler(DBusConnection *c, DBusMessage *m, voi
return res;
}
static void bluez_register_endpoint_legacy_reply(DBusPendingCall *pending, void *user_data)
{
struct spa_bt_adapter *adapter = user_data;
struct spa_bt_monitor *monitor = adapter->monitor;
spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
if (r == NULL)
return;
if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) {
spa_log_warn(monitor->log, "BlueZ D-Bus ObjectManager not available");
return;
}
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
spa_log_error(monitor->log, "RegisterEndpoint() failed: %s",
dbus_message_get_error_name(r));
return;
}
adapter->legacy_endpoints_registered = true;
}
static void append_basic_variant_dict_entry(DBusMessageIter *dict, const char* key, int variant_type_int, const char* variant_type_str, void* variant) {
DBusMessageIter dict_entry_it, variant_it;
dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_it);
@ -5550,112 +5525,6 @@ static void append_basic_array_variant_dict_entry(DBusMessageIter *dict, const c
dbus_message_iter_close_container(dict, &dict_entry_it);
}
static int bluez_register_endpoint_legacy(struct spa_bt_adapter *adapter,
enum spa_bt_media_direction direction,
const char *uuid, const struct media_codec *codec)
{
struct spa_bt_monitor *monitor = adapter->monitor;
const char *path = adapter->path;
spa_autofree char *object_path = NULL;
spa_autoptr(DBusMessage) m = NULL;
DBusMessageIter object_it, dict_it;
uint8_t caps[A2DP_MAX_CAPS_SIZE];
int ret, caps_size;
uint16_t codec_id = codec->codec_id;
bool sink = (direction == SPA_BT_MEDIA_SINK);
spa_assert(codec->fill_caps);
ret = media_codec_to_endpoint(codec, direction, &object_path);
if (ret < 0)
return ret;
ret = caps_size = codec->fill_caps(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, &monitor->global_settings, caps);
if (ret < 0)
return ret;
m = dbus_message_new_method_call(BLUEZ_SERVICE,
path,
BLUEZ_MEDIA_INTERFACE,
"RegisterEndpoint");
if (m == NULL)
return -EIO;
dbus_message_iter_init_append(m, &object_it);
dbus_message_iter_append_basic(&object_it, DBUS_TYPE_OBJECT_PATH, &object_path);
dbus_message_iter_open_container(&object_it, DBUS_TYPE_ARRAY, "{sv}", &dict_it);
append_basic_variant_dict_entry(&dict_it,"UUID", DBUS_TYPE_STRING, "s", &uuid);
append_basic_variant_dict_entry(&dict_it, "Codec", DBUS_TYPE_BYTE, "y", &codec_id);
append_basic_array_variant_dict_entry(&dict_it, "Capabilities", "ay", "y", DBUS_TYPE_BYTE, caps, caps_size);
dbus_message_iter_close_container(&object_it, &dict_it);
if (!send_with_reply(monitor->conn, m, bluez_register_endpoint_legacy_reply, adapter))
return -EIO;
return 0;
}
static int adapter_register_endpoints_legacy(struct spa_bt_adapter *a)
{
struct spa_bt_monitor *monitor = a->monitor;
const struct media_codec * const * const media_codecs = monitor->media_codecs;
int i;
int err = 0;
bool registered = false;
if (a->legacy_endpoints_registered)
return err;
/* The legacy bluez5 api doesn't support codec switching
* It doesn't make sense to register codecs other than SBC
* as bluez5 will probably use SBC anyway and we have no control over it
* let's incentivize users to upgrade their bluez5 daemon
* if they want proper media codec support
* */
spa_log_warn(monitor->log,
"Using legacy bluez5 API for A2DP - only SBC will be supported. "
"Please upgrade bluez5.");
for (i = 0; media_codecs[i]; i++) {
const struct media_codec *codec = media_codecs[i];
if (codec->id != SPA_BLUETOOTH_AUDIO_CODEC_SBC)
continue;
if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SOURCE)) {
if ((err = bluez_register_endpoint_legacy(a, SPA_BT_MEDIA_SOURCE,
SPA_BT_UUID_A2DP_SOURCE,
codec)))
goto out;
}
if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SINK)) {
if ((err = bluez_register_endpoint_legacy(a, SPA_BT_MEDIA_SINK,
SPA_BT_UUID_A2DP_SINK,
codec)))
goto out;
}
registered = true;
break;
}
if (!registered) {
/* Should never happen as SBC support is always enabled */
spa_log_error(monitor->log, "Broken PipeWire build - unable to locate SBC codec");
err = -ENOSYS;
}
out:
if (err) {
spa_log_error(monitor->log, "Failed to register bluez5 endpoints");
}
return err;
}
static void append_supported_features(DBusMessageIter *dict, struct bap_features *features)
{
const char *key = "SupportedFeatures";
@ -5911,7 +5780,6 @@ static void bluez_register_application_a2dp_reply(DBusPendingCall *pending, void
{
struct spa_bt_adapter *adapter = user_data;
struct spa_bt_monitor *monitor = adapter->monitor;
bool fallback = true;
spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
if (r == NULL)
@ -5919,21 +5787,16 @@ static void bluez_register_application_a2dp_reply(DBusPendingCall *pending, void
if (dbus_message_is_error(r, BLUEZ_ERROR_NOT_SUPPORTED)) {
spa_log_warn(monitor->log, "Registering media applications for adapter %s is disabled in bluez5", adapter->path);
goto finish;
return;
}
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
spa_log_error(monitor->log, "RegisterApplication() failed: %s",
dbus_message_get_error_name(r));
goto finish;
return;
}
fallback = false;
adapter->a2dp_application_registered = true;
finish:
if (fallback)
adapter_register_endpoints_legacy(adapter);
}
static void bluez_register_application_bap_reply(DBusPendingCall *pending, void *user_data)

View file

@ -368,7 +368,6 @@ struct spa_bt_adapter {
int powered;
unsigned int has_msbc:1;
unsigned int msbc_probed:1;
unsigned int legacy_endpoints_registered:1;
unsigned int a2dp_application_registered:1;
unsigned int bap_application_registered:1;
unsigned int player_registered:1;