mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-19 05:33:49 -04:00
bluez5: support specifying preferred delays as BAP Server
Add options to control advertised delays supported. Smaller delay needs smaller node.latency be used, so use 40ms as a reasonable minimum preferred delay.
This commit is contained in:
parent
ae9361bb34
commit
8b36e2d9b7
2 changed files with 123 additions and 34 deletions
|
|
@ -1256,6 +1256,18 @@ Available sink contexts PACS bitmask of the the server.
|
||||||
@PAR@ monitor-prop bluez5.bap-server-capabilities.sink.supported-contexts # integer
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.sink.supported-contexts # integer
|
||||||
Supported sink contexts PACS bitmask of the the server.
|
Supported sink contexts PACS bitmask of the the server.
|
||||||
|
|
||||||
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.sink.delay-min # integer
|
||||||
|
Minimum presentation delay supported, in microseconds.
|
||||||
|
|
||||||
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.sink.delay-max # integer
|
||||||
|
Maximum presentation delay supported, in microseconds.
|
||||||
|
|
||||||
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.sink.preferred-delay-min # integer
|
||||||
|
Minimum preferred presentation delay supported, in microseconds.
|
||||||
|
|
||||||
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.sink.preferred-delay-max # integer
|
||||||
|
Maximum preferred presentation delay supported, in microseconds.
|
||||||
|
|
||||||
@PAR@ monitor-prop bluez5.bap-server-capabilities.source.locations # JSON or integer
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.source.locations # JSON or integer
|
||||||
Source audio locations of the server, as channel positions or PACS bitmask.
|
Source audio locations of the server, as channel positions or PACS bitmask.
|
||||||
Example: `FL,FR`
|
Example: `FL,FR`
|
||||||
|
|
@ -1266,6 +1278,18 @@ Available source contexts PACS bitmask of the the server.
|
||||||
@PAR@ monitor-prop bluez5.bap-server-capabilities.source.supported-contexts # integer
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.source.supported-contexts # integer
|
||||||
Supported source contexts PACS bitmask of the the server.
|
Supported source contexts PACS bitmask of the the server.
|
||||||
|
|
||||||
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.source.delay-min # integer
|
||||||
|
Minimum presentation delay supported, in microseconds.
|
||||||
|
|
||||||
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.source.delay-max # integer
|
||||||
|
Maximum presentation delay supported, in microseconds.
|
||||||
|
|
||||||
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.source.preferred-delay-min # integer
|
||||||
|
Minimum preferred presentation delay supported, in microseconds.
|
||||||
|
|
||||||
|
@PAR@ monitor-prop bluez5.bap-server-capabilities.source.preferred-delay-max # integer
|
||||||
|
Maximum preferred presentation delay supported, in microseconds.
|
||||||
|
|
||||||
@PAR@ monitor-prop bluez5.bap-server-tmap-features = null # array of string
|
@PAR@ monitor-prop bluez5.bap-server-tmap-features = null # array of string
|
||||||
Override advertised TMAP service features. See TMAP specification for their meaning.
|
Override advertised TMAP service features. See TMAP specification for their meaning.
|
||||||
Possible values: "cg", "ct", "ums", "umr", "bms", "bmr".
|
Possible values: "cg", "ct", "ums", "umr", "bms", "bmr".
|
||||||
|
|
|
||||||
|
|
@ -129,12 +129,8 @@ struct spa_bt_monitor {
|
||||||
|
|
||||||
struct spa_list bcast_source_config_list;
|
struct spa_list bcast_source_config_list;
|
||||||
|
|
||||||
uint32_t bap_sink_locations;
|
struct bap_endpoint_qos bap_sink_qos;
|
||||||
uint32_t bap_sink_contexts;
|
struct bap_endpoint_qos bap_source_qos;
|
||||||
uint32_t bap_sink_supported_contexts;
|
|
||||||
uint32_t bap_source_locations;
|
|
||||||
uint32_t bap_source_contexts;
|
|
||||||
uint32_t bap_source_supported_contexts;
|
|
||||||
|
|
||||||
struct bap_features bap_features;
|
struct bap_features bap_features;
|
||||||
|
|
||||||
|
|
@ -5579,6 +5575,18 @@ static void append_supported_features(DBusMessageIter *dict, struct bap_features
|
||||||
dbus_message_iter_close_container(dict, &dict_entry);
|
dbus_message_iter_close_container(dict, &dict_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void append_endpoint_qos(DBusMessageIter *dict, struct bap_endpoint_qos *qos)
|
||||||
|
{
|
||||||
|
append_basic_variant_dict_entry(dict, "Framing", DBUS_TYPE_BYTE, "y", &qos->framing);
|
||||||
|
append_basic_variant_dict_entry(dict, "PHY", DBUS_TYPE_BYTE, "y", &qos->phy);
|
||||||
|
append_basic_variant_dict_entry(dict, "Retransmissions", DBUS_TYPE_BYTE, "y", &qos->retransmission);
|
||||||
|
append_basic_variant_dict_entry(dict, "MaximumLatency", DBUS_TYPE_UINT16, "q", &qos->latency);
|
||||||
|
append_basic_variant_dict_entry(dict, "MinimumDelay", DBUS_TYPE_UINT32, "u", &qos->delay_min);
|
||||||
|
append_basic_variant_dict_entry(dict, "MaximumDelay", DBUS_TYPE_UINT32, "u", &qos->delay_max);
|
||||||
|
append_basic_variant_dict_entry(dict, "PreferredMinimumDelay", DBUS_TYPE_UINT32, "u", &qos->preferred_delay_min);
|
||||||
|
append_basic_variant_dict_entry(dict, "PreferredMaximumDelay", DBUS_TYPE_UINT32, "u", &qos->preferred_delay_max);
|
||||||
|
}
|
||||||
|
|
||||||
static void append_media_object(struct spa_bt_monitor *monitor, DBusMessageIter *iter, const char *endpoint,
|
static void append_media_object(struct spa_bt_monitor *monitor, DBusMessageIter *iter, const char *endpoint,
|
||||||
const char *uuid, uint8_t codec_id, uint8_t *caps, size_t caps_size)
|
const char *uuid, uint8_t codec_id, uint8_t *caps, size_t caps_size)
|
||||||
{
|
{
|
||||||
|
|
@ -5605,25 +5613,25 @@ static void append_media_object(struct spa_bt_monitor *monitor, DBusMessageIter
|
||||||
append_basic_variant_dict_entry(&dict, "DelayReporting", DBUS_TYPE_BOOLEAN, "b", &delay_reporting);
|
append_basic_variant_dict_entry(&dict, "DelayReporting", DBUS_TYPE_BOOLEAN, "b", &delay_reporting);
|
||||||
}
|
}
|
||||||
if (spa_bt_profile_from_uuid(uuid) & (SPA_BT_PROFILE_BAP_SINK | SPA_BT_PROFILE_BAP_SOURCE)) {
|
if (spa_bt_profile_from_uuid(uuid) & (SPA_BT_PROFILE_BAP_SINK | SPA_BT_PROFILE_BAP_SOURCE)) {
|
||||||
dbus_uint32_t locations;
|
struct bap_endpoint_qos *qos;
|
||||||
dbus_uint16_t supported_contexts, contexts;
|
|
||||||
|
|
||||||
if (spa_bt_profile_from_uuid(uuid) & SPA_BT_PROFILE_BAP_SINK) {
|
if (spa_bt_profile_from_uuid(uuid) & SPA_BT_PROFILE_BAP_SINK)
|
||||||
locations = monitor->bap_sink_locations;
|
qos = &monitor->bap_sink_qos;
|
||||||
contexts = monitor->bap_sink_contexts;
|
else
|
||||||
supported_contexts = monitor->bap_sink_supported_contexts;
|
qos = &monitor->bap_source_qos;
|
||||||
} else {
|
|
||||||
locations = monitor->bap_source_locations;
|
|
||||||
contexts = monitor->bap_source_contexts;
|
|
||||||
supported_contexts = monitor->bap_source_supported_contexts;
|
|
||||||
}
|
|
||||||
|
|
||||||
spa_log_debug(monitor->log, "BAP endpoint %s locations:0x%x contexts:0x%x supported-contexs:0x%x",
|
spa_log_debug(monitor->log, "BAP endpoint %s locations:0x%x contexts:0x%x supported-contexs:0x%x "
|
||||||
endpoint, locations, contexts, supported_contexts);
|
"framing:0x%x phy:0x%x rtn:0x%x latency:0x%x min-delay:0x%x max-delay:0x%x "
|
||||||
|
"pref-min-delay:0x%x pref-max-delay:0x%x",
|
||||||
|
endpoint, qos->locations, qos->context, qos->supported_context,
|
||||||
|
qos->framing, qos->phy, qos->retransmission, qos->latency, qos->delay_min,
|
||||||
|
qos->delay_max, qos->preferred_delay_min, qos->preferred_delay_max);
|
||||||
|
|
||||||
append_basic_variant_dict_entry(&dict, "Locations", DBUS_TYPE_UINT32, "u", &locations);
|
append_basic_variant_dict_entry(&dict, "Locations", DBUS_TYPE_UINT32, "u", &qos->locations);
|
||||||
append_basic_variant_dict_entry(&dict, "Context", DBUS_TYPE_UINT16, "q", &contexts);
|
append_basic_variant_dict_entry(&dict, "Context", DBUS_TYPE_UINT16, "q", &qos->context);
|
||||||
append_basic_variant_dict_entry(&dict, "SupportedContext", DBUS_TYPE_UINT16, "q", &supported_contexts);
|
append_basic_variant_dict_entry(&dict, "SupportedContext", DBUS_TYPE_UINT16, "q", &qos->supported_context);
|
||||||
|
|
||||||
|
append_endpoint_qos(&dict, qos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spa_bt_profile_from_uuid(uuid) & SPA_BT_PROFILE_BAP_AUDIO)
|
if (spa_bt_profile_from_uuid(uuid) & SPA_BT_PROFILE_BAP_AUDIO)
|
||||||
|
|
@ -7191,24 +7199,80 @@ static void parse_bap_features(struct spa_bt_monitor *this, const struct spa_dic
|
||||||
bap_feature_parse(this, gmap_uuid, spa_dict_lookup(info, "bluez5.bap-server-gmap-features"));
|
bap_feature_parse(this, gmap_uuid, spa_dict_lookup(info, "bluez5.bap-server-gmap-features"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bap_init_qos(struct spa_bt_monitor *this)
|
||||||
|
{
|
||||||
|
/* BlueZ has default values for phy/rtn/latency/delays */
|
||||||
|
struct bap_endpoint_qos sink = {
|
||||||
|
.locations = BAP_CHANNEL_FL | BAP_CHANNEL_FR,
|
||||||
|
.context = BAP_CONTEXT_ALL,
|
||||||
|
.delay_min = 20000,
|
||||||
|
.delay_max = 200000,
|
||||||
|
.preferred_delay_min = 40000,
|
||||||
|
.framing = 0x00, /* unframed supported */
|
||||||
|
};
|
||||||
|
struct bap_endpoint_qos source = {
|
||||||
|
.locations = BAP_CHANNEL_FL | BAP_CHANNEL_FR,
|
||||||
|
.context = (BAP_CONTEXT_UNSPECIFIED | BAP_CONTEXT_CONVERSATIONAL |
|
||||||
|
BAP_CONTEXT_MEDIA | BAP_CONTEXT_GAME),
|
||||||
|
.delay_min = 20000,
|
||||||
|
.delay_max = 200000,
|
||||||
|
.preferred_delay_min = 40000,
|
||||||
|
.framing = 0x00, /* unframed supported */
|
||||||
|
};
|
||||||
|
|
||||||
|
sink.supported_context = sink.context;
|
||||||
|
source.supported_context = source.context;
|
||||||
|
|
||||||
|
this->bap_sink_qos = sink;
|
||||||
|
this->bap_source_qos = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bap_atou16(const char *str, uint16_t *value, int base)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
if (spa_atou32(str, &v, base)) {
|
||||||
|
*value = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bap_clamp_qos_delay(struct bap_endpoint_qos *qos)
|
||||||
|
{
|
||||||
|
qos->delay_max = SPA_MAX(qos->delay_max, qos->delay_min);
|
||||||
|
|
||||||
|
if (qos->preferred_delay_min && qos->preferred_delay_max)
|
||||||
|
qos->preferred_delay_max = SPA_MAX(qos->preferred_delay_max, qos->preferred_delay_min);
|
||||||
|
if (qos->preferred_delay_min)
|
||||||
|
qos->preferred_delay_min = SPA_CLAMP(qos->preferred_delay_min, qos->delay_min, qos->delay_max);
|
||||||
|
if (qos->preferred_delay_max)
|
||||||
|
qos->preferred_delay_max = SPA_CLAMP(qos->preferred_delay_max, qos->delay_min, qos->delay_max);
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_bap_server(struct spa_bt_monitor *this, const struct spa_dict *info)
|
static void parse_bap_server(struct spa_bt_monitor *this, const struct spa_dict *info)
|
||||||
{
|
{
|
||||||
this->bap_sink_locations = BAP_CHANNEL_FL | BAP_CHANNEL_FR;
|
|
||||||
this->bap_source_locations = BAP_CHANNEL_FL | BAP_CHANNEL_FR;
|
|
||||||
this->bap_sink_contexts = this->bap_sink_supported_contexts = BAP_CONTEXT_ALL;
|
|
||||||
this->bap_source_contexts = this->bap_source_supported_contexts = (BAP_CONTEXT_UNSPECIFIED | BAP_CONTEXT_CONVERSATIONAL |
|
|
||||||
BAP_CONTEXT_MEDIA | BAP_CONTEXT_GAME);
|
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
parse_bap_locations(this, info, "bluez5.bap-server-capabilities.sink.locations", &this->bap_sink_locations);
|
parse_bap_locations(this, info, "bluez5.bap-server-capabilities.sink.locations", &this->bap_sink_qos.locations);
|
||||||
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.sink.contexts"), &this->bap_sink_contexts, 0);
|
bap_atou16(spa_dict_lookup(info, "bluez5.bap-server-capabilities.sink.contexts"), &this->bap_sink_qos.context, 0);
|
||||||
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.sink.supported-contexts"), &this->bap_sink_supported_contexts, 0);
|
bap_atou16(spa_dict_lookup(info, "bluez5.bap-server-capabilities.sink.supported-contexts"), &this->bap_sink_qos.supported_context, 0);
|
||||||
|
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.sink.delay-min"), &this->bap_sink_qos.delay_min, 0);
|
||||||
|
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.sink.delay-max"), &this->bap_sink_qos.delay_max, 0);
|
||||||
|
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.sink.preferred-delay-min"), &this->bap_sink_qos.preferred_delay_min, 0);
|
||||||
|
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.sink.preferred-delay-max"), &this->bap_sink_qos.preferred_delay_max, 0);
|
||||||
|
|
||||||
parse_bap_locations(this, info, "bluez5.bap-server-capabilities.source.locations", &this->bap_source_locations);
|
parse_bap_locations(this, info, "bluez5.bap-server-capabilities.source.locations", &this->bap_source_qos.locations);
|
||||||
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.source.contexts"), &this->bap_source_contexts, 0);
|
bap_atou16(spa_dict_lookup(info, "bluez5.bap-server-capabilities.source.contexts"), &this->bap_source_qos.context, 0);
|
||||||
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.source.supported-contexts"), &this->bap_source_supported_contexts, 0);
|
bap_atou16(spa_dict_lookup(info, "bluez5.bap-server-capabilities.source.supported-contexts"), &this->bap_source_qos.supported_context, 0);
|
||||||
|
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.source.delay-min"), &this->bap_source_qos.delay_min, 0);
|
||||||
|
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.source.delay-max"), &this->bap_source_qos.delay_max, 0);
|
||||||
|
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.source.preferred-delay-min"), &this->bap_source_qos.preferred_delay_min, 0);
|
||||||
|
spa_atou32(spa_dict_lookup(info, "bluez5.bap-server-capabilities.source.preferred-delay-max"), &this->bap_source_qos.preferred_delay_max, 0);
|
||||||
|
|
||||||
|
bap_clamp_qos_delay(&this->bap_sink_qos);
|
||||||
|
bap_clamp_qos_delay(&this->bap_source_qos);
|
||||||
|
|
||||||
parse_bap_features(this, info);
|
parse_bap_features(this, info);
|
||||||
}
|
}
|
||||||
|
|
@ -7330,6 +7394,7 @@ impl_init(const struct spa_handle_factory *factory,
|
||||||
if ((res = parse_codec_array(this, info)) < 0)
|
if ((res = parse_codec_array(this, info)) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
bap_init_qos(this);
|
||||||
parse_roles(this, info);
|
parse_roles(this, info);
|
||||||
parse_broadcast_source_config(this, info);
|
parse_broadcast_source_config(this, info);
|
||||||
parse_bap_server(this, info);
|
parse_bap_server(this, info);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue