mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-28 06:46:42 -04:00
Merge branch 'bt-16' into '1.6'
[1.6] bluez5: backports to 1.6 branch See merge request pipewire/pipewire!2797
This commit is contained in:
commit
4260688335
8 changed files with 99 additions and 13 deletions
|
|
@ -286,7 +286,7 @@ static void *codec_init_props(const struct media_codec *codec, uint32_t flags, c
|
|||
return NULL;
|
||||
|
||||
if (settings == NULL || (str = spa_dict_lookup(settings, "bluez5.a2dp.aac.bitratemode")) == NULL)
|
||||
str = "0";
|
||||
str = "5";
|
||||
|
||||
p->bitratemode = SPA_CLAMP(atoi(str), 0, 5);
|
||||
return p;
|
||||
|
|
@ -380,8 +380,12 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags,
|
|||
// Fragmentation is not implemented yet,
|
||||
// so make sure every encoded AAC frame fits in (mtu - header)
|
||||
this->max_bitrate = ((this->mtu - sizeof(struct rtp_header)) * 8 * this->rate) / 1024;
|
||||
this->max_bitrate = SPA_MIN(this->max_bitrate, get_valid_aac_bitrate(conf));
|
||||
this->cur_bitrate = this->max_bitrate;
|
||||
this->cur_bitrate = SPA_MIN(this->max_bitrate, get_valid_aac_bitrate(conf));
|
||||
spa_log_debug(log, "AAC: max (peak) bitrate: %d, cur bitrate: %d, mode: %d (vbr: %d)",
|
||||
this->max_bitrate,
|
||||
this->cur_bitrate,
|
||||
bitratemode,
|
||||
conf->vbr);
|
||||
|
||||
res = aacEncoder_SetParam(this->aacenc, AACENC_BITRATE, this->cur_bitrate);
|
||||
if (res != AACENC_OK)
|
||||
|
|
@ -391,6 +395,15 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags,
|
|||
if (res != AACENC_OK)
|
||||
goto error;
|
||||
|
||||
// Assume >110 kbit/s as a "high bitrate" CBR and increase the
|
||||
// band pass cutout up to 19.3 kHz (as in mode 5 VBR).
|
||||
if (!conf->vbr && this->cur_bitrate > 110000) {
|
||||
res = aacEncoder_SetParam(this->aacenc, AACENC_BANDWIDTH,
|
||||
19293);
|
||||
if (res != AACENC_OK)
|
||||
goto error;
|
||||
}
|
||||
|
||||
res = aacEncoder_SetParam(this->aacenc, AACENC_TRANSMUX, TT_MP4_LATM_MCP1);
|
||||
if (res != AACENC_OK)
|
||||
goto error;
|
||||
|
|
|
|||
|
|
@ -904,7 +904,7 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de
|
|||
{
|
||||
int res;
|
||||
bool alt6_ok = true, alt1_ok = true;
|
||||
bool msbc_alt6_ok = true, msbc_alt1_ok = true;
|
||||
bool msbc_alt6_ok = true, msbc_alt1_ok = true, lc3_a127_ok = true;
|
||||
uint32_t bt_features;
|
||||
|
||||
if (device->adapter == NULL)
|
||||
|
|
@ -913,6 +913,7 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de
|
|||
if (backend->quirks && spa_bt_quirks_get_features(backend->quirks, device->adapter, device, &bt_features) == 0) {
|
||||
msbc_alt1_ok = (bt_features & (SPA_BT_FEATURE_MSBC_ALT1 | SPA_BT_FEATURE_MSBC_ALT1_RTL));
|
||||
msbc_alt6_ok = (bt_features & SPA_BT_FEATURE_MSBC);
|
||||
lc3_a127_ok = (bt_features & SPA_BT_FEATURE_LC3_A127);
|
||||
}
|
||||
|
||||
switch (codec) {
|
||||
|
|
@ -922,6 +923,10 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de
|
|||
alt1_ok = msbc_alt1_ok;
|
||||
alt6_ok = msbc_alt6_ok;
|
||||
break;
|
||||
case SPA_BLUETOOTH_AUDIO_CODEC_LC3_A127:
|
||||
alt1_ok = false;
|
||||
alt6_ok = lc3_a127_ok;
|
||||
break;
|
||||
case SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB:
|
||||
default:
|
||||
/* LC3-SWB has same transport requirements as msbc.
|
||||
|
|
@ -986,8 +991,11 @@ static void make_available_codec_list(struct impl *backend, struct spa_bt_device
|
|||
|
||||
for (i = 0; backend->codecs[i]; ++i) {
|
||||
const struct media_codec *codec = backend->codecs[i];
|
||||
|
||||
if (codec->kind != MEDIA_CODEC_HFP)
|
||||
continue;
|
||||
if (!spa_bt_get_hfp_codec(backend->monitor, codec->codec_id))
|
||||
continue;
|
||||
if (device_supports_codec(backend, device, codec->id))
|
||||
codec_list_add(codec_list, codec);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1503,6 +1503,10 @@ static int codec_get_bis_config(const struct media_codec *codec, uint8_t *caps,
|
|||
struct ltv_writer writer = LTV_WRITER(caps, *caps_size);
|
||||
const struct bap_qos *preset = NULL;
|
||||
|
||||
uint32_t retransmissions = 0;
|
||||
uint8_t rtn_manual_set = 0;
|
||||
uint32_t max_transport_latency = 0;
|
||||
uint32_t presentation_delay = 0;
|
||||
*caps_size = 0;
|
||||
|
||||
if (settings) {
|
||||
|
|
@ -1511,6 +1515,14 @@ static int codec_get_bis_config(const struct media_codec *codec, uint8_t *caps,
|
|||
sscanf(settings->items[i].value, "%"PRIu32, &channel_allocation);
|
||||
if (spa_streq(settings->items[i].key, "preset"))
|
||||
preset_name = settings->items[i].value;
|
||||
if (spa_streq(settings->items[i].key, "max_transport_latency"))
|
||||
spa_atou32(settings->items[i].value, &max_transport_latency, 0);
|
||||
if (spa_streq(settings->items[i].key, "presentation_delay"))
|
||||
spa_atou32(settings->items[i].value, &presentation_delay, 0);
|
||||
if (spa_streq(settings->items[i].key, "retransmissions")) {
|
||||
spa_atou32(settings->items[i].value, &retransmissions, 0);
|
||||
rtn_manual_set = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1537,9 +1549,9 @@ static int codec_get_bis_config(const struct media_codec *codec, uint8_t *caps,
|
|||
else
|
||||
qos->framing = 0;
|
||||
qos->sdu = preset->framelen * get_channel_count(channel_allocation);
|
||||
qos->retransmission = preset->retransmission;
|
||||
qos->latency = preset->latency;
|
||||
qos->delay = preset->delay;
|
||||
qos->retransmission = rtn_manual_set ? retransmissions : preset->retransmission;
|
||||
qos->latency = max_transport_latency ? max_transport_latency : preset->latency;
|
||||
qos->delay = presentation_delay ? presentation_delay : preset->delay;
|
||||
qos->phy = 2;
|
||||
qos->interval = (preset->frame_duration == LC3_CONFIG_DURATION_7_5 ? 7500 : 10000);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
# sbc-xq "nonstandard" SBC codec setting with better sound quality
|
||||
# faststream FastStream codec support
|
||||
# a2dp-duplex A2DP duplex codec support
|
||||
# lc3-a127 HFP LC3-24KHz codec support
|
||||
#
|
||||
# Features are disabled with the key "no-features" whose value is an
|
||||
# array of strings in the match rule.
|
||||
|
|
@ -83,6 +84,12 @@ bluez5.features.adapter = [
|
|||
# Realtek Semiconductor Corp.
|
||||
{ bus-type = "usb", vendor-id = "usb:0bda" },
|
||||
|
||||
# Mediatek MT7925, #pipewire-5213
|
||||
{ bus-type = "usb", vendor-id = "usb:0e8d", product-id = "~(e025)", no-features = [ lc3-a127 ] },
|
||||
{ bus-type = "usb", vendor-id = "usb:0489", product-id = "~(e111|e113|e118|e11e|e124|e139|e14e|e14f|e150|e151)", no-features = [ lc3-a127 ] },
|
||||
{ bus-type = "usb", vendor-id = "usb:13d3", product-id = "~(3602|3603|3604|3608|3613|3627|3628|3630)", no-features = [ lc3-a127 ] },
|
||||
{ bus-type = "usb", vendor-id = "usb:2c7c", product-id = "~(7009)", no-features = [ lc3-a127 ] },
|
||||
|
||||
# Generic USB adapters
|
||||
{ bus-type = "usb", no-features = [ msbc-alt1-rtl ] },
|
||||
|
||||
|
|
|
|||
|
|
@ -188,9 +188,16 @@ struct spa_bt_metadata {
|
|||
uint8_t value[METADATA_MAX_LEN - 1];
|
||||
};
|
||||
|
||||
#define RTN_MAX 0x1E
|
||||
#define MAX_TRANSPORT_LATENCY_MIN 0x5
|
||||
#define MAX_TRANSPORT_LATENCY_MAX 0x0FA0
|
||||
|
||||
struct spa_bt_bis {
|
||||
struct spa_list link;
|
||||
char qos_preset[255];
|
||||
int retransmissions;
|
||||
int rtn_manual_set;
|
||||
int max_transport_latency;
|
||||
int channel_allocation;
|
||||
struct spa_list metadata_list;
|
||||
};
|
||||
|
|
@ -6192,8 +6199,11 @@ static void configure_bis(struct spa_bt_monitor *monitor,
|
|||
struct bap_codec_qos qos;
|
||||
struct spa_bt_metadata *metadata_entry;
|
||||
struct spa_dict settings;
|
||||
struct spa_dict_item setting_items[2];
|
||||
struct spa_dict_item setting_items[4];
|
||||
uint32_t n_items = 0;
|
||||
char channel_allocation[64] = {0};
|
||||
char retransmissions[3] = {0};
|
||||
char max_transport_latency[5] = {0};
|
||||
|
||||
int mse = 0;
|
||||
int options = 0;
|
||||
|
|
@ -6218,12 +6228,27 @@ static void configure_bis(struct spa_bt_monitor *monitor,
|
|||
metadata_size += metadata_entry->length - 1;
|
||||
}
|
||||
|
||||
|
||||
spa_log_debug(monitor->log, "bis->channel_allocation %d", bis->channel_allocation);
|
||||
if (bis->channel_allocation)
|
||||
if (bis->channel_allocation) {
|
||||
spa_scnprintf(channel_allocation, sizeof(channel_allocation), "%"PRIu32, bis->channel_allocation);
|
||||
setting_items[0] = SPA_DICT_ITEM_INIT("channel_allocation", channel_allocation);
|
||||
setting_items[1] = SPA_DICT_ITEM_INIT("preset", bis->qos_preset);
|
||||
settings = SPA_DICT_INIT(setting_items, 2);
|
||||
}
|
||||
spa_log_debug(monitor->log, "bis->rtn_manual_set %d", bis->rtn_manual_set);
|
||||
spa_log_debug(monitor->log, "bis->retransmissions %d", bis->retransmissions);
|
||||
if (bis->rtn_manual_set) {
|
||||
spa_scnprintf(retransmissions, sizeof(retransmissions), "%"PRIu8, bis->retransmissions);
|
||||
setting_items[n_items++] = SPA_DICT_ITEM_INIT("retransmissions", retransmissions);
|
||||
}
|
||||
spa_log_debug(monitor->log, "bis->max_transport_latency %d", bis->max_transport_latency);
|
||||
if (bis->max_transport_latency) {
|
||||
spa_scnprintf(max_transport_latency, sizeof(max_transport_latency), "%"PRIu32, bis->max_transport_latency);
|
||||
setting_items[n_items++] = SPA_DICT_ITEM_INIT("max_transport_latency", max_transport_latency);
|
||||
}
|
||||
|
||||
setting_items[n_items++] = SPA_DICT_ITEM_INIT("preset", bis->qos_preset);
|
||||
setting_items[n_items++] = SPA_DICT_ITEM_INIT("channel_allocation", channel_allocation);
|
||||
|
||||
settings = SPA_DICT_INIT(setting_items, n_items);
|
||||
|
||||
caps_size = sizeof(caps);
|
||||
ret = codec->get_bis_config(codec, caps, &caps_size, &settings, &qos);
|
||||
|
|
@ -7126,6 +7151,20 @@ static void parse_broadcast_source_config(struct spa_bt_monitor *monitor, const
|
|||
if (spa_json_get_string(&it[1], bis_entry->qos_preset, sizeof(bis_entry->qos_preset)) <= 0)
|
||||
goto parse_failed;
|
||||
spa_log_debug(monitor->log, "bis_entry->qos_preset %s", bis_entry->qos_preset);
|
||||
} else if (spa_streq(bis_key, "retransmissions")) {
|
||||
if (spa_json_get_int(&it[2], &bis_entry->retransmissions) <= 0)
|
||||
goto parse_failed;
|
||||
if (bis_entry->retransmissions > RTN_MAX)
|
||||
goto parse_failed;
|
||||
bis_entry->rtn_manual_set = 1;
|
||||
spa_log_debug(monitor->log, "bis_entry->retransmissions %d", bis_entry->retransmissions);
|
||||
} else if (spa_streq(bis_key, "max_transport_latency")) {
|
||||
if (spa_json_get_int(&it[2], &bis_entry->max_transport_latency) <= 0)
|
||||
goto parse_failed;
|
||||
if (bis_entry->max_transport_latency < MAX_TRANSPORT_LATENCY_MIN &&
|
||||
bis_entry->max_transport_latency > MAX_TRANSPORT_LATENCY_MAX)
|
||||
goto parse_failed;
|
||||
spa_log_debug(monitor->log, "bis_entry->max_transport_latency %d", bis_entry->max_transport_latency);
|
||||
} else if (spa_streq(bis_key, "audio_channel_allocation")) {
|
||||
if (spa_json_get_int(&it[1], &bis_entry->channel_allocation) <= 0)
|
||||
goto parse_failed;
|
||||
|
|
|
|||
|
|
@ -811,6 +811,7 @@ enum spa_bt_feature {
|
|||
SPA_BT_FEATURE_SBC_XQ = (1 << 5),
|
||||
SPA_BT_FEATURE_FASTSTREAM = (1 << 6),
|
||||
SPA_BT_FEATURE_A2DP_DUPLEX = (1 << 7),
|
||||
SPA_BT_FEATURE_LC3_A127 = (1 << 8),
|
||||
};
|
||||
|
||||
struct spa_bt_quirks;
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ static void group_on_timeout(struct spa_source *source)
|
|||
/* Ensure controller fill level */
|
||||
fill_count = UINT_MAX;
|
||||
spa_list_for_each(stream, &group->streams, link) {
|
||||
if (!stream->sink || !group->started)
|
||||
if (!stream->sink || !group->started || !stream->tx_latency.enabled)
|
||||
continue;
|
||||
if (stream->tx_latency.queue < MIN_FILL)
|
||||
fill_count = SPA_MIN(fill_count, MIN_FILL - stream->tx_latency.queue);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ struct spa_bt_quirks {
|
|||
int force_sbc_xq;
|
||||
int force_faststream;
|
||||
int force_a2dp_duplex;
|
||||
int force_lc3_a127;
|
||||
|
||||
char *device_rules;
|
||||
char *adapter_rules;
|
||||
|
|
@ -69,6 +70,7 @@ static enum spa_bt_feature parse_feature(const char *str)
|
|||
{ "sbc-xq", SPA_BT_FEATURE_SBC_XQ },
|
||||
{ "faststream", SPA_BT_FEATURE_FASTSTREAM },
|
||||
{ "a2dp-duplex", SPA_BT_FEATURE_A2DP_DUPLEX },
|
||||
{ "lc3-a127", SPA_BT_FEATURE_LC3_A127 },
|
||||
};
|
||||
SPA_FOR_EACH_ELEMENT_VAR(feature_keys, f) {
|
||||
if (spa_streq(str, f->key))
|
||||
|
|
@ -228,6 +230,7 @@ struct spa_bt_quirks *spa_bt_quirks_create(const struct spa_dict *info, struct s
|
|||
this->force_hw_volume = parse_force_flag(info, "bluez5.enable-hw-volume");
|
||||
this->force_faststream = parse_force_flag(info, "bluez5.enable-faststream");
|
||||
this->force_a2dp_duplex = parse_force_flag(info, "bluez5.enable-a2dp-duplex");
|
||||
this->force_lc3_a127 = parse_force_flag(info, "bluez5.enable-lc3-a127");
|
||||
|
||||
if ((str = spa_dict_lookup(info, "bluez5.hardware-database")) != NULL) {
|
||||
spa_log_debug(this->log, "loading session manager provided data");
|
||||
|
|
@ -385,6 +388,9 @@ static int get_features(const struct spa_bt_quirks *this,
|
|||
if (this->force_a2dp_duplex != -1)
|
||||
SPA_FLAG_UPDATE(*features, SPA_BT_FEATURE_A2DP_DUPLEX, this->force_a2dp_duplex);
|
||||
|
||||
if (this->force_lc3_a127 != -1)
|
||||
SPA_FLAG_UPDATE(*features, SPA_BT_FEATURE_LC3_A127, this->force_lc3_a127);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue