diff --git a/doc/dox/config/pipewire-props.7.md b/doc/dox/config/pipewire-props.7.md index e561979d5..5555e3408 100644 --- a/doc/dox/config/pipewire-props.7.md +++ b/doc/dox/config/pipewire-props.7.md @@ -1375,9 +1375,9 @@ Default: as per QoS preset. @PAR@ device-prop bluez5.bap.force-target-latency = "balanced" # string BAP QoS target latency profile forced for QoS configuration selection. -If not set or set to "balanced", both low-latency and high-reliabilty QoS configuration table are used. +If not set or set to "balanced", both low-latency and high-reliability QoS configuration table are used. This property is experimental. -Available: low-latency, high-reliabilty, balanced +Available: low-latency, high-reliability, balanced ## Node properties diff --git a/spa/plugins/bluez5/a2dp-codec-aac.c b/spa/plugins/bluez5/a2dp-codec-aac.c index c49f7a616..a82efe983 100644 --- a/spa/plugins/bluez5/a2dp-codec-aac.c +++ b/spa/plugins/bluez5/a2dp-codec-aac.c @@ -106,8 +106,8 @@ static int codec_fill_caps(const struct media_codec *codec, uint32_t flags, static const struct media_codec_config aac_frequencies[] = { - { AAC_SAMPLING_FREQ_48000, 48000, 11 }, { AAC_SAMPLING_FREQ_44100, 44100, 10 }, + { AAC_SAMPLING_FREQ_48000, 48000, 11 }, { AAC_SAMPLING_FREQ_96000, 96000, 9 }, { AAC_SAMPLING_FREQ_88200, 88200, 8 }, { AAC_SAMPLING_FREQ_64000, 64000, 7 }, @@ -194,75 +194,6 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, return sizeof(conf); } -static int codec_enum_config(const struct media_codec *codec, uint32_t flags, - const void *caps, size_t caps_size, uint32_t id, uint32_t idx, - struct spa_pod_builder *b, struct spa_pod **param) -{ - a2dp_aac_t conf; - struct spa_pod_frame f[2]; - struct spa_pod_choice *choice; - uint32_t position[2]; - uint32_t i = 0; - - if (caps_size < sizeof(conf)) - return -EINVAL; - - memcpy(&conf, caps, sizeof(conf)); - - if (idx > 0) - return 0; - - spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, id); - spa_pod_builder_add(b, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_S16), - 0); - spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0); - - spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_None, 0); - choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[1]); - i = 0; - SPA_FOR_EACH_ELEMENT_VAR(aac_frequencies, f) { - if (AAC_GET_FREQUENCY(conf) & f->config) { - if (i++ == 0) - spa_pod_builder_int(b, f->value); - spa_pod_builder_int(b, f->value); - } - } - if (i > 1) - choice->body.type = SPA_CHOICE_Enum; - spa_pod_builder_pop(b, &f[1]); - - if (i == 0) - return -EINVAL; - - if (SPA_FLAG_IS_SET(conf.channels, AAC_CHANNELS_1 | AAC_CHANNELS_2)) { - spa_pod_builder_add(b, - SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(2, 1, 2), - 0); - } else if (conf.channels & AAC_CHANNELS_1) { - position[0] = SPA_AUDIO_CHANNEL_MONO; - spa_pod_builder_add(b, - SPA_FORMAT_AUDIO_channels, SPA_POD_Int(1), - SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t), - SPA_TYPE_Id, 1, position), - 0); - } else if (conf.channels & AAC_CHANNELS_2) { - position[0] = SPA_AUDIO_CHANNEL_FL; - position[1] = SPA_AUDIO_CHANNEL_FR; - spa_pod_builder_add(b, - SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2), - SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t), - SPA_TYPE_Id, 2, position), - 0); - } else - return -EINVAL; - - *param = spa_pod_builder_pop(b, &f[0]); - return *param == NULL ? -EIO : 1; -} - static int codec_validate_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, struct spa_audio_info *info) @@ -283,8 +214,10 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags /* * A2DP v1.3.2, 4.5.2: only one bit shall be set in bitfields. * However, there is a report (#1342) of device setting multiple - * bits for AAC object type. It's not clear if this was due to - * a BlueZ bug, but we can be lax here and below in codec_init. + * bits for AAC object type. In addition AirPods set multiple bits. + * + * Some devices also set multiple bits in frequencies & channels. + * For these, pick a "preferred" choice. */ if (!(conf.object_type & (AAC_OBJECT_TYPE_MPEG2_AAC_LC | AAC_OBJECT_TYPE_MPEG4_AAC_LC | @@ -315,6 +248,35 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags return 0; } +static int codec_enum_config(const struct media_codec *codec, uint32_t flags, + const void *caps, size_t caps_size, uint32_t id, uint32_t idx, + struct spa_pod_builder *b, struct spa_pod **param) +{ + struct spa_audio_info info; + struct spa_pod_frame f[1]; + int res; + + if ((res = codec_validate_config(codec, flags, caps, caps_size, &info)) < 0) + return res; + + if (idx > 0) + return 0; + + spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(b, + SPA_FORMAT_mediaType, SPA_POD_Id(info.media_type), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(info.media_subtype), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(info.info.raw.format), + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info.info.raw.rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info.info.raw.channels), + SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t), + SPA_TYPE_Id, info.info.raw.channels, info.info.raw.position), + 0); + + *param = spa_pod_builder_pop(b, &f[0]); + return *param == NULL ? -EIO : 1; +} + static void *codec_init_props(const struct media_codec *codec, uint32_t flags, const struct spa_dict *settings) { struct props *p = calloc(1, sizeof(struct props)); @@ -369,14 +331,14 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags, goto error; /* If object type has multiple bits set (invalid per spec, see above), - * assume the device usually means AAC-LC. + * assume the device usually means MPEG2 AAC LC which is mandatory. */ - if (conf->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) { - res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_AAC_LC); + if (conf->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) { + res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_MP2_AAC_LC); if (res != AACENC_OK) goto error; - } else if (conf->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) { - res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_MP2_AAC_LC); + } else if (conf->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) { + res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_AAC_LC); if (res != AACENC_OK) goto error; } else if (conf->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_ELD) { diff --git a/spa/plugins/bluez5/a2dp-codec-sbc.c b/spa/plugins/bluez5/a2dp-codec-sbc.c index b4ebfc2a2..f1b86e76b 100644 --- a/spa/plugins/bluez5/a2dp-codec-sbc.c +++ b/spa/plugins/bluez5/a2dp-codec-sbc.c @@ -343,77 +343,27 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) { - a2dp_sbc_t conf; - struct spa_pod_frame f[2]; - struct spa_pod_choice *choice; - uint32_t i = 0; - uint32_t position[2]; + struct spa_audio_info info; + struct spa_pod_frame f[1]; + int res; - if (caps_size < sizeof(conf)) - return -EINVAL; - - memcpy(&conf, caps, sizeof(conf)); + if ((res = codec_validate_config(codec, flags, caps, caps_size, &info)) < 0) + return res; if (idx > 0) return 0; spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, id); spa_pod_builder_add(b, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_S16), + SPA_FORMAT_mediaType, SPA_POD_Id(info.media_type), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(info.media_subtype), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(info.info.raw.format), + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info.info.raw.rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info.info.raw.channels), + SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t), + SPA_TYPE_Id, info.info.raw.channels, info.info.raw.position), 0); - spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0); - spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_None, 0); - choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[1]); - i = 0; - if (conf.frequency & SBC_SAMPLING_FREQ_48000) { - if (i++ == 0) - spa_pod_builder_int(b, 48000); - spa_pod_builder_int(b, 48000); - } - if (conf.frequency & SBC_SAMPLING_FREQ_44100) { - if (i++ == 0) - spa_pod_builder_int(b, 44100); - spa_pod_builder_int(b, 44100); - } - if (conf.frequency & SBC_SAMPLING_FREQ_32000) { - if (i++ == 0) - spa_pod_builder_int(b, 32000); - spa_pod_builder_int(b, 32000); - } - if (conf.frequency & SBC_SAMPLING_FREQ_16000) { - if (i++ == 0) - spa_pod_builder_int(b, 16000); - spa_pod_builder_int(b, 16000); - } - if (i > 1) - choice->body.type = SPA_CHOICE_Enum; - spa_pod_builder_pop(b, &f[1]); - - if (conf.channel_mode & SBC_CHANNEL_MODE_MONO && - conf.channel_mode & (SBC_CHANNEL_MODE_JOINT_STEREO | - SBC_CHANNEL_MODE_STEREO | SBC_CHANNEL_MODE_DUAL_CHANNEL)) { - spa_pod_builder_add(b, - SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(2, 1, 2), - 0); - } else if (conf.channel_mode & SBC_CHANNEL_MODE_MONO) { - position[0] = SPA_AUDIO_CHANNEL_MONO; - spa_pod_builder_add(b, - SPA_FORMAT_AUDIO_channels, SPA_POD_Int(1), - SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t), - SPA_TYPE_Id, 1, position), - 0); - } else { - position[0] = SPA_AUDIO_CHANNEL_FL; - position[1] = SPA_AUDIO_CHANNEL_FR; - spa_pod_builder_add(b, - SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2), - SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t), - SPA_TYPE_Id, 2, position), - 0); - } *param = spa_pod_builder_pop(b, &f[0]); return *param == NULL ? -EIO : 1; } diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c index 4d14183e7..64a4c25c1 100644 --- a/spa/plugins/bluez5/backend-native.c +++ b/spa/plugins/bluez5/backend-native.c @@ -1969,6 +1969,9 @@ static void hfp_hf_remove_disconnected_calls(struct rfcomm *rfcomm) struct updated_call *updated_call; bool found; + if (!rfcomm->telephony_ag) + return; + spa_list_for_each_safe(call, call_tmp, &rfcomm->telephony_ag->call_list, link) { found = false; spa_list_for_each(updated_call, &rfcomm->updated_call_list, link) { @@ -2097,6 +2100,8 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) if (spa_streq(rfcomm->hf_indicators[indicator], "battchg")) { spa_bt_device_report_battery_level(rfcomm->device, value * 100 / 5); + } else if (!rfcomm->telephony_ag) { + /* noop */ } else if (spa_streq(rfcomm->hf_indicators[indicator], "callsetup")) { if (rfcomm->hfp_hf_clcc) { rfcomm_send_cmd(rfcomm, hfp_hf_clcc_update, NULL, "AT+CLCC"); @@ -2245,7 +2250,8 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) rfcomm->hfp_hf_in_progress = false; } } - } else if (sscanf(token, "+CLIP: \"%16[^\"]\",%u", number, &type) == 2) { + } else if (sscanf(token, "+CLIP: \"%16[^\"]\",%u", number, &type) == 2 + && rfcomm->telephony_ag) { struct spa_bt_telephony_call *call; spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { if (call->state == CALL_STATE_INCOMING && !spa_streq(number, call->line_identification)) { @@ -2256,7 +2262,8 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) break; } } - } else if (sscanf(token, "+CCWA: \"%16[^\"]\",%u", number, &type) == 2) { + } else if (sscanf(token, "+CCWA: \"%16[^\"]\",%u", number, &type) == 2 + && rfcomm->telephony_ag) { struct spa_bt_telephony_call *call; bool found = false; @@ -2273,7 +2280,7 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) if (call == NULL) spa_log_warn(backend->log, "failed to create waiting call"); } - } else if (spa_strstartswith(token, "+CLCC:")) { + } else if (spa_strstartswith(token, "+CLCC:") && rfcomm->telephony_ag) { struct spa_bt_telephony_call *call; size_t pos; char *token_end; @@ -2421,17 +2428,19 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) } } - rfcomm->telephony_ag = telephony_ag_new(backend->telephony, 0); - rfcomm->telephony_ag->address = strdup(rfcomm->device->address); - rfcomm->telephony_ag->volume[SPA_BT_VOLUME_ID_RX] = rfcomm->volumes[SPA_BT_VOLUME_ID_RX].hw_volume = backend->hfp_default_speaker_volume; - rfcomm->telephony_ag->volume[SPA_BT_VOLUME_ID_TX] = rfcomm->volumes[SPA_BT_VOLUME_ID_TX].hw_volume = backend->hfp_default_mic_volume; - telephony_ag_set_callbacks(rfcomm->telephony_ag, + if (backend->telephony) { + rfcomm->telephony_ag = telephony_ag_new(backend->telephony, 0); + rfcomm->telephony_ag->address = strdup(rfcomm->device->address); + rfcomm->telephony_ag->volume[SPA_BT_VOLUME_ID_RX] = rfcomm->volumes[SPA_BT_VOLUME_ID_RX].hw_volume = backend->hfp_default_speaker_volume; + rfcomm->telephony_ag->volume[SPA_BT_VOLUME_ID_TX] = rfcomm->volumes[SPA_BT_VOLUME_ID_TX].hw_volume = backend->hfp_default_mic_volume; + telephony_ag_set_callbacks(rfcomm->telephony_ag, &telephony_ag_callbacks, rfcomm); - if (rfcomm->transport) { - rfcomm->telephony_ag->transport.codec = rfcomm->transport->media_codec->codec_id; - rfcomm->telephony_ag->transport.state = rfcomm->transport->state; + if (rfcomm->transport) { + rfcomm->telephony_ag->transport.codec = rfcomm->transport->media_codec->codec_id; + rfcomm->telephony_ag->transport.state = rfcomm->transport->state; + } + telephony_ag_register(rfcomm->telephony_ag); } - telephony_ag_register(rfcomm->telephony_ag); rfcomm_send_cmd(rfcomm, hfp_hf_clip, NULL, "AT+CLIP=1"); break; @@ -2478,7 +2487,7 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token) break; case hfp_hf_chld1_hangup: /* For HFP/HF/TWC/BV-03-C - see 0e92ab9307e05758b3f70b4c0648e29c1d1e50be */ - if (!rfcomm->hfp_hf_clcc) { + if (!rfcomm->hfp_hf_clcc && rfcomm->telephony_ag) { struct spa_bt_telephony_call *call, *tcall; spa_list_for_each_safe(call, tcall, &rfcomm->telephony_ag->call_list, link) { if (call->state == CALL_STATE_ACTIVE) { diff --git a/spa/plugins/bluez5/bap-codec-lc3.c b/spa/plugins/bluez5/bap-codec-lc3.c index 74761f26b..b1b12cb78 100644 --- a/spa/plugins/bluez5/bap-codec-lc3.c +++ b/spa/plugins/bluez5/bap-codec-lc3.c @@ -126,22 +126,22 @@ static const struct bap_qos bap_qos_configs[] = { BAP_QOS("48_6_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 5, 20, 40000, 27, "low-latency"), /* 48_6_1 */ /* BAP v1.0.1 Table 5.2; high-reliability */ - BAP_QOS("8_1_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 13, 75, 40000, 10, "high-reliabilty"), /* 8_1_2 */ - BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 13, 95, 40000, 0, "high-reliabilty"), /* 8_2_2 */ - BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 13, 75, 40000, 11, "high-reliabilty"), /* 16_1_2 */ - BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 13, 95, 40000, 1, "high-reliabilty"), /* 16_2_2 */ - BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 13, 75, 40000, 12, "high-reliabilty"), /* 24_1_2 */ - BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 13, 95, 40000, 2, "high-reliabilty"), /* 24_2_2 */ - BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 13, 75, 40000, 13, "high-reliabilty"), /* 32_1_2 */ - BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 13, 95, 40000, 3, "high-reliabilty"), /* 32_2_2 */ - BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 13, 80, 40000, 54, "high-reliabilty"), /* 441_1_2 */ - BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 13, 85, 40000, 44, "high-reliabilty"), /* 441_2_2 */ - BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 13, 75, 40000, 55, "high-reliabilty"), /* 48_1_2 */ - BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 13, 95, 40000, 45, "high-reliabilty"), /* 48_2_2 */ - BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 13, 75, 40000, 56, "high-reliabilty"), /* 48_3_2 */ - BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 13, 100, 40000, 46, "high-reliabilty"), /* 48_4_2 */ - BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 13, 75, 40000, 57, "high-reliabilty"), /* 48_5_2 */ - BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 13, 100, 40000, 47, "high-reliabilty"), /* 48_6_2 */ + BAP_QOS("8_1_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 13, 75, 40000, 10, "high-reliability"), /* 8_1_2 */ + BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 13, 95, 40000, 0, "high-reliability"), /* 8_2_2 */ + BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 13, 75, 40000, 11, "high-reliability"), /* 16_1_2 */ + BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 13, 95, 40000, 1, "high-reliability"), /* 16_2_2 */ + BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 13, 75, 40000, 12, "high-reliability"), /* 24_1_2 */ + BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 13, 95, 40000, 2, "high-reliability"), /* 24_2_2 */ + BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 13, 75, 40000, 13, "high-reliability"), /* 32_1_2 */ + BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 13, 95, 40000, 3, "high-reliability"), /* 32_2_2 */ + BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 13, 80, 40000, 54, "high-reliability"), /* 441_1_2 */ + BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 13, 85, 40000, 44, "high-reliability"), /* 441_2_2 */ + BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 13, 75, 40000, 55, "high-reliability"), /* 48_1_2 */ + BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 13, 95, 40000, 45, "high-reliability"), /* 48_2_2 */ + BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 13, 75, 40000, 56, "high-reliability"), /* 48_3_2 */ + BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 13, 100, 40000, 46, "high-reliability"), /* 48_4_2 */ + BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 13, 75, 40000, 57, "high-reliability"), /* 48_5_2 */ + BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 13, 100, 40000, 47, "high-reliability"), /* 48_6_2 */ }; static const struct bap_qos bap_bcast_qos_configs[] = { @@ -167,22 +167,22 @@ static const struct bap_qos bap_bcast_qos_configs[] = { BAP_QOS("48_6_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 4, 20, 40000, 27, "low-latency"), /* 48_6_1 */ /* BAP v1.0.1 Table 6.4; high-reliability */ - BAP_QOS("8_1_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 4, 45, 40000, 10, "high-reliabilty"), /* 8_1_2 */ - BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 4, 60, 40000, 0, "high-reliabilty"), /* 8_2_2 */ - BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 4, 45, 40000, 11, "high-reliabilty"), /* 16_1_2 */ - BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 4, 60, 40000, 1, "high-reliabilty"), /* 16_2_2 */ - BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 4, 45, 40000, 12, "high-reliabilty"), /* 24_1_2 */ - BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 4, 60, 40000, 2, "high-reliabilty"), /* 24_2_2 */ - BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 4, 45, 40000, 13, "high-reliabilty"), /* 32_1_2 */ - BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 4, 60, 40000, 3, "high-reliabilty"), /* 32_2_2 */ - BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 4, 54, 40000, 14, "high-reliabilty"), /* 441_1_2 */ - BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 4, 60, 40000, 4, "high-reliabilty"), /* 441_2_2 */ - BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 4, 50, 40000, 15, "high-reliabilty"), /* 48_1_2 */ - BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 4, 65, 40000, 5, "high-reliabilty"), /* 48_2_2 */ - BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 4, 50, 40000, 16, "high-reliabilty"), /* 48_3_2 */ - BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 4, 65, 40000, 6, "high-reliabilty"), /* 48_4_2 */ - BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 4, 50, 40000, 17, "high-reliabilty"), /* 48_5_2 */ - BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 4, 65, 40000, 7, "high-reliabilty"), /* 48_6_2 */ + BAP_QOS("8_1_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 4, 45, 40000, 10, "high-reliability"), /* 8_1_2 */ + BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 4, 60, 40000, 0, "high-reliability"), /* 8_2_2 */ + BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 4, 45, 40000, 11, "high-reliability"), /* 16_1_2 */ + BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 4, 60, 40000, 1, "high-reliability"), /* 16_2_2 */ + BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 4, 45, 40000, 12, "high-reliability"), /* 24_1_2 */ + BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 4, 60, 40000, 2, "high-reliability"), /* 24_2_2 */ + BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 4, 45, 40000, 13, "high-reliability"), /* 32_1_2 */ + BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 4, 60, 40000, 3, "high-reliability"), /* 32_2_2 */ + BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 4, 54, 40000, 14, "high-reliability"), /* 441_1_2 */ + BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 4, 60, 40000, 4, "high-reliability"), /* 441_2_2 */ + BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 4, 50, 40000, 15, "high-reliability"), /* 48_1_2 */ + BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 4, 65, 40000, 5, "high-reliability"), /* 48_2_2 */ + BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 4, 50, 40000, 16, "high-reliability"), /* 48_3_2 */ + BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 4, 65, 40000, 6, "high-reliability"), /* 48_4_2 */ + BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 4, 50, 40000, 17, "high-reliability"), /* 48_5_2 */ + BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 4, 65, 40000, 7, "high-reliability"), /* 48_6_2 */ }; static unsigned int get_rate_mask(uint8_t rate) { diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index 7dfe45911..f4b384547 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -587,18 +587,35 @@ static enum spa_bt_profile get_codec_profile(const struct media_codec *codec, { switch (direction) { case SPA_BT_MEDIA_SOURCE: - return codec->kind == MEDIA_CODEC_BAP ? SPA_BT_PROFILE_BAP_SOURCE : SPA_BT_PROFILE_A2DP_SOURCE; + if (codec->kind == MEDIA_CODEC_A2DP) + return SPA_BT_PROFILE_A2DP_SOURCE; + else if (codec->kind == MEDIA_CODEC_BAP) + return SPA_BT_PROFILE_BAP_SOURCE; + else if (codec->kind == MEDIA_CODEC_HFP) + return SPA_BT_PROFILE_HEADSET_AUDIO; + else + return SPA_BT_PROFILE_NULL; case SPA_BT_MEDIA_SINK: - if (codec->kind == MEDIA_CODEC_ASHA) + if (codec->kind == MEDIA_CODEC_A2DP) + return SPA_BT_PROFILE_A2DP_SINK; + else if (codec->kind == MEDIA_CODEC_ASHA) return SPA_BT_PROFILE_ASHA_SINK; else if (codec->kind == MEDIA_CODEC_BAP) return SPA_BT_PROFILE_BAP_SINK; + else if (codec->kind == MEDIA_CODEC_HFP) + return SPA_BT_PROFILE_HEADSET_AUDIO; else - return SPA_BT_PROFILE_A2DP_SINK; + return SPA_BT_PROFILE_NULL; case SPA_BT_MEDIA_SOURCE_BROADCAST: - return SPA_BT_PROFILE_BAP_BROADCAST_SOURCE; + if (codec->kind == MEDIA_CODEC_BAP) + return SPA_BT_PROFILE_BAP_BROADCAST_SOURCE; + else + return SPA_BT_PROFILE_NULL; case SPA_BT_MEDIA_SINK_BROADCAST: - return SPA_BT_PROFILE_BAP_BROADCAST_SINK; + if (codec->kind == MEDIA_CODEC_BAP) + return SPA_BT_PROFILE_BAP_BROADCAST_SINK; + else + return SPA_BT_PROFILE_NULL; default: spa_assert_not_reached(); } @@ -2777,16 +2794,18 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru bool is_bap = codec->kind == MEDIA_CODEC_BAP; size_t i; - codec_target_profile = get_codec_target_profile(monitor, codec); - if (!codec_target_profile) - return false; - if (codec->kind == MEDIA_CODEC_HFP) { if (!(profile & SPA_BT_PROFILE_HEADSET_AUDIO)) return false; + if (!is_media_codec_enabled(monitor, codec)) + return false; return spa_bt_backend_supports_codec(monitor->backend, device, codec->codec_id) == 1; } + codec_target_profile = get_codec_target_profile(monitor, codec); + 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") && @@ -7078,7 +7097,7 @@ static void parse_broadcast_source_config(struct spa_bt_monitor *monitor, const memcpy(big_entry->broadcast_code, bcode, strlen(bcode)); spa_log_debug(monitor->log, "big_entry->broadcast_code %s", big_entry->broadcast_code); } else if (spa_streq(key, "adapter")) { - if (spa_json_get_string(&it[1], big_entry->adapter, sizeof(big_entry->adapter)) <= 0) + if (spa_json_get_string(&it[0], big_entry->adapter, sizeof(big_entry->adapter)) <= 0) goto parse_failed; spa_log_debug(monitor->log, "big_entry->adapter %s", big_entry->adapter); } else if (spa_streq(key, "encryption")) { diff --git a/spa/plugins/bluez5/media-source.c b/spa/plugins/bluez5/media-source.c index da2e57b5a..e1c01d90c 100644 --- a/spa/plugins/bluez5/media-source.c +++ b/spa/plugins/bluez5/media-source.c @@ -1784,7 +1784,7 @@ static uint32_t get_samples(struct impl *this, int64_t *duration_ns) static void update_target_latency(struct impl *this) { struct port *port = &this->port; - int32_t target; + int32_t target = 0; int samples; if (this->transport == NULL || !port->have_format) @@ -1803,7 +1803,7 @@ static void update_target_latency(struct impl *this) */ if (this->decode_buffer_target) target = this->decode_buffer_target; - else + else if (this->transport->iso_io) target = spa_bt_iso_io_get_source_target_latency(this->transport->iso_io); spa_bt_decode_buffer_set_target_latency(&port->buffer, target);