mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: fix device supported codec checks
Make supported codec checks to use profiles, not "is-a-sink" flag, to determine which codecs can be used. Fixes bluez5-device checking only source profiles, even when the local device is only a sink.
This commit is contained in:
parent
6abc6e6693
commit
186b730c9c
3 changed files with 59 additions and 66 deletions
|
|
@ -526,6 +526,26 @@ static enum spa_bt_profile get_codec_profile(const struct media_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
static enum spa_bt_profile swap_profile(enum spa_bt_profile profile)
|
||||
{
|
||||
switch (profile) {
|
||||
case SPA_BT_PROFILE_A2DP_SOURCE:
|
||||
return SPA_BT_PROFILE_A2DP_SINK;
|
||||
case SPA_BT_PROFILE_A2DP_SINK:
|
||||
return SPA_BT_PROFILE_A2DP_SOURCE;
|
||||
case SPA_BT_PROFILE_BAP_SOURCE:
|
||||
return SPA_BT_PROFILE_BAP_SINK;
|
||||
case SPA_BT_PROFILE_BAP_SINK:
|
||||
return SPA_BT_PROFILE_BAP_SOURCE;
|
||||
case SPA_BT_PROFILE_BAP_BROADCAST_SOURCE:
|
||||
return SPA_BT_PROFILE_BAP_BROADCAST_SINK;
|
||||
case SPA_BT_PROFILE_BAP_BROADCAST_SINK:
|
||||
return SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
|
||||
default:
|
||||
return SPA_BT_PROFILE_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool endpoint_should_be_registered(struct spa_bt_monitor *monitor,
|
||||
const struct media_codec *codec,
|
||||
enum spa_bt_media_direction direction)
|
||||
|
|
@ -2230,11 +2250,11 @@ static bool device_props_ready(struct spa_bt_device *device)
|
|||
return device->adapter && device->address;
|
||||
}
|
||||
|
||||
bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, bool sink)
|
||||
bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, enum spa_bt_profile profile)
|
||||
{
|
||||
struct spa_bt_monitor *monitor = device->monitor;
|
||||
struct spa_bt_remote_endpoint *ep;
|
||||
enum spa_bt_profile codec_profile;
|
||||
enum spa_bt_profile codec_target_profile;
|
||||
struct spa_bt_transport *t;
|
||||
const struct { enum spa_bluetooth_audio_codec codec; uint32_t mask; } quirks[] = {
|
||||
{ SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_BT_FEATURE_SBC_XQ },
|
||||
|
|
@ -2270,17 +2290,14 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru
|
|||
return false;
|
||||
}
|
||||
|
||||
spa_list_for_each(ep, &device->remote_endpoint_list, device_link) {
|
||||
enum spa_bt_profile profile = spa_bt_profile_from_uuid(ep->uuid);
|
||||
if (codec->bap) {
|
||||
if ((profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) || (profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE))
|
||||
codec_profile = sink ? SPA_BT_PROFILE_BAP_BROADCAST_SINK : SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
|
||||
else
|
||||
codec_profile = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE;
|
||||
} else
|
||||
codec_profile = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE;
|
||||
for (i = 0, codec_target_profile = 0; i < (size_t)SPA_BT_MEDIA_DIRECTION_LAST; ++i)
|
||||
if (codec_has_direction(codec, i))
|
||||
codec_target_profile |= swap_profile(get_codec_profile(codec, i));
|
||||
|
||||
if (profile != codec_profile)
|
||||
spa_list_for_each(ep, &device->remote_endpoint_list, device_link) {
|
||||
enum spa_bt_profile ep_profile = spa_bt_profile_from_uuid(ep->uuid);
|
||||
|
||||
if (!(ep_profile & codec_target_profile & profile))
|
||||
continue;
|
||||
|
||||
if (media_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len,
|
||||
|
|
@ -2296,15 +2313,7 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru
|
|||
* can only know that the currently configured codec is supported.
|
||||
*/
|
||||
spa_list_for_each(t, &device->transport_list, device_link) {
|
||||
if (codec->bap) {
|
||||
if((t->profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) || (t->profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE))
|
||||
codec_profile = sink ? SPA_BT_PROFILE_BAP_BROADCAST_SINK : SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
|
||||
else
|
||||
codec_profile = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE;
|
||||
} else
|
||||
codec_profile = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE;
|
||||
|
||||
if (t->profile != codec_profile)
|
||||
if (!(t->profile & codec_target_profile & profile))
|
||||
continue;
|
||||
|
||||
if (codec == t->media_codec)
|
||||
|
|
@ -2314,7 +2323,7 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru
|
|||
return false;
|
||||
}
|
||||
|
||||
const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count, bool sink)
|
||||
const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count)
|
||||
{
|
||||
struct spa_bt_monitor *monitor = device->monitor;
|
||||
const struct media_codec * const * const media_codecs = monitor->media_codecs;
|
||||
|
|
@ -2329,7 +2338,7 @@ const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_b
|
|||
|
||||
j = 0;
|
||||
for (i = 0; media_codecs[i] != NULL; ++i) {
|
||||
if (spa_bt_device_supports_media_codec(device, media_codecs[i], sink)) {
|
||||
if (spa_bt_device_supports_media_codec(device, media_codecs[i], device->connected_profiles)) {
|
||||
supported_codecs[j] = media_codecs[i];
|
||||
++j;
|
||||
}
|
||||
|
|
@ -3048,29 +3057,9 @@ static int transport_update_props(struct spa_bt_transport *transport,
|
|||
spa_log_debug(monitor->log, "transport %p: %s=%s", transport, key, value);
|
||||
|
||||
if (spa_streq(key, "UUID")) {
|
||||
switch (spa_bt_profile_from_uuid(value)) {
|
||||
case SPA_BT_PROFILE_A2DP_SOURCE:
|
||||
transport->profile = SPA_BT_PROFILE_A2DP_SINK;
|
||||
break;
|
||||
case SPA_BT_PROFILE_A2DP_SINK:
|
||||
transport->profile = SPA_BT_PROFILE_A2DP_SOURCE;
|
||||
break;
|
||||
case SPA_BT_PROFILE_BAP_SOURCE:
|
||||
transport->profile = SPA_BT_PROFILE_BAP_SINK;
|
||||
break;
|
||||
case SPA_BT_PROFILE_BAP_SINK:
|
||||
transport->profile = SPA_BT_PROFILE_BAP_SOURCE;
|
||||
break;
|
||||
case SPA_BT_PROFILE_BAP_BROADCAST_SOURCE:
|
||||
transport->profile = SPA_BT_PROFILE_BAP_BROADCAST_SINK;
|
||||
break;
|
||||
case SPA_BT_PROFILE_BAP_BROADCAST_SINK:
|
||||
transport->profile = SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
|
||||
break;
|
||||
default:
|
||||
transport->profile = swap_profile(spa_bt_profile_from_uuid(value));
|
||||
if (transport->profile == SPA_BT_PROFILE_NULL)
|
||||
spa_log_warn(monitor->log, "unknown profile %s", value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (spa_streq(key, "State")) {
|
||||
enum spa_bt_transport_state state = spa_bt_transport_state_from_string(value);
|
||||
|
|
@ -4154,7 +4143,7 @@ int spa_bt_device_ensure_media_codec(struct spa_bt_device *device, const struct
|
|||
}
|
||||
|
||||
for (i = 0; codecs[i] != NULL; ++i) {
|
||||
if (spa_bt_device_supports_media_codec(device, codecs[i], true)) {
|
||||
if (spa_bt_device_supports_media_codec(device, codecs[i], device->connected_profiles)) {
|
||||
preferred_codec = codecs[i];
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,10 +190,12 @@ static void get_media_codecs(struct impl *this, enum spa_bluetooth_audio_codec i
|
|||
*codecs = NULL;
|
||||
}
|
||||
|
||||
static const struct media_codec *get_supported_media_codec(struct impl *this, enum spa_bluetooth_audio_codec id, size_t *idx)
|
||||
static const struct media_codec *get_supported_media_codec(struct impl *this, enum spa_bluetooth_audio_codec id,
|
||||
size_t *idx, enum spa_bt_profile profile)
|
||||
{
|
||||
const struct media_codec *media_codec = NULL;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < this->supported_codec_count; ++i) {
|
||||
if (this->supported_codecs[i]->id == id) {
|
||||
media_codec = this->supported_codecs[i];
|
||||
|
|
@ -201,6 +203,13 @@ static const struct media_codec *get_supported_media_codec(struct impl *this, en
|
|||
*idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!media_codec)
|
||||
return NULL;
|
||||
|
||||
if (!spa_bt_device_supports_media_codec(this->bt_dev, media_codec, profile))
|
||||
return NULL;
|
||||
|
||||
return media_codec;
|
||||
}
|
||||
|
||||
|
|
@ -625,6 +634,8 @@ static void emit_node(struct impl *this, struct spa_bt_transport *t,
|
|||
char transport[32], str_id[32], object_path[512];
|
||||
bool is_dyn_node = SPA_FLAG_IS_SET(id, DYNAMIC_NODE_ID_FLAG);
|
||||
|
||||
spa_log_debug(this->log, "node, transport:%p id:%08x factory:%s", t, id, factory_name);
|
||||
|
||||
snprintf(transport, sizeof(transport), "pointer:%p", t);
|
||||
items[0] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_TRANSPORT, transport);
|
||||
items[1] = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_PROFILE, spa_bt_profile_name(t->profile));
|
||||
|
|
@ -1016,9 +1027,6 @@ static int emit_nodes(struct impl *this)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (get_supported_media_codec(this, this->props.codec, NULL) == NULL)
|
||||
this->props.codec = 0;
|
||||
break;
|
||||
case DEVICE_PROFILE_BAP:
|
||||
if (this->bt_dev->connected_profiles & (SPA_BT_PROFILE_BAP_SOURCE)) {
|
||||
|
|
@ -1070,9 +1078,6 @@ static int emit_nodes(struct impl *this)
|
|||
DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_MEDIA_SOURCE, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (get_supported_media_codec(this, this->props.codec, NULL) == NULL)
|
||||
this->props.codec = 0;
|
||||
break;
|
||||
case DEVICE_PROFILE_HSP_HFP:
|
||||
if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT) {
|
||||
|
|
@ -1119,6 +1124,8 @@ static void emit_info(struct impl *this, bool full)
|
|||
|
||||
static void emit_remove_nodes(struct impl *this)
|
||||
{
|
||||
spa_log_debug(this->log, "remove nodes");
|
||||
|
||||
remove_dynamic_node (&this->dyn_media_source);
|
||||
remove_dynamic_node (&this->dyn_media_sink);
|
||||
remove_dynamic_node (&this->dyn_sco_source);
|
||||
|
|
@ -1278,11 +1285,9 @@ static void profiles_changed(void *userdata, uint32_t prev_profiles, uint32_t pr
|
|||
if (this->switching_codec)
|
||||
return;
|
||||
|
||||
if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_MEDIA_SINK) {
|
||||
free(this->supported_codecs);
|
||||
this->supported_codecs = spa_bt_device_get_supported_media_codecs(
|
||||
this->bt_dev, &this->supported_codec_count, true);
|
||||
}
|
||||
free(this->supported_codecs);
|
||||
this->supported_codecs = spa_bt_device_get_supported_media_codecs(
|
||||
this->bt_dev, &this->supported_codec_count);
|
||||
|
||||
switch (this->profile) {
|
||||
case DEVICE_PROFILE_OFF:
|
||||
|
|
@ -1297,8 +1302,6 @@ static void profiles_changed(void *userdata, uint32_t prev_profiles, uint32_t pr
|
|||
break;
|
||||
case DEVICE_PROFILE_A2DP:
|
||||
case DEVICE_PROFILE_BAP:
|
||||
if (get_supported_media_codec(this, this->props.codec, NULL) == NULL)
|
||||
this->props.codec = 0;
|
||||
nodes_changed = (connected_change & (SPA_BT_PROFILE_MEDIA_SINK |
|
||||
SPA_BT_PROFILE_MEDIA_SOURCE));
|
||||
spa_log_debug(this->log, "profiles changed: media nodes changed: %d",
|
||||
|
|
@ -1419,7 +1422,7 @@ static uint32_t profile_direction_mask(struct impl *this, uint32_t index, enum s
|
|||
if (device->connected_profiles & SPA_BT_PROFILE_A2DP_SINK)
|
||||
have_output = true;
|
||||
|
||||
media_codec = get_supported_media_codec(this, codec, NULL);
|
||||
media_codec = get_supported_media_codec(this, codec, NULL, device->connected_profiles);
|
||||
if (media_codec && media_codec->duplex_codec)
|
||||
have_input = true;
|
||||
break;
|
||||
|
|
@ -1533,7 +1536,7 @@ static void set_initial_profile(struct impl *this)
|
|||
if (this->supported_codecs)
|
||||
free(this->supported_codecs);
|
||||
this->supported_codecs = spa_bt_device_get_supported_media_codecs(
|
||||
this->bt_dev, &this->supported_codec_count, true);
|
||||
this->bt_dev, &this->supported_codec_count);
|
||||
|
||||
/* Prefer BAP, then A2DP, then HFP, then null, but select AG if the device
|
||||
appears not to have BAP_SINK, A2DP_SINK or any HEAD_UNIT profile */
|
||||
|
|
@ -1625,7 +1628,7 @@ static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder *
|
|||
n_sink++;
|
||||
if (codec) {
|
||||
size_t idx;
|
||||
const struct media_codec *media_codec = get_supported_media_codec(this, codec, &idx);
|
||||
const struct media_codec *media_codec = get_supported_media_codec(this, codec, &idx, profile);
|
||||
if (media_codec == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
|
|
@ -1686,7 +1689,7 @@ static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder *
|
|||
name = spa_bt_profile_name(profile);
|
||||
|
||||
if (codec) {
|
||||
media_codec = get_supported_media_codec(this, codec, &idx);
|
||||
media_codec = get_supported_media_codec(this, codec, &idx, profile);
|
||||
if (media_codec == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ enum spa_bt_media_direction {
|
|||
SPA_BT_MEDIA_SINK,
|
||||
SPA_BT_MEDIA_SOURCE_BROADCAST,
|
||||
SPA_BT_MEDIA_SINK_BROADCAST,
|
||||
SPA_BT_MEDIA_DIRECTION_LAST,
|
||||
};
|
||||
|
||||
enum spa_bt_profile {
|
||||
|
|
@ -538,8 +539,8 @@ int spa_bt_device_add_profile(struct spa_bt_device *device, enum spa_bt_profile
|
|||
int spa_bt_device_connect_profile(struct spa_bt_device *device, enum spa_bt_profile profile);
|
||||
int spa_bt_device_check_profiles(struct spa_bt_device *device, bool force);
|
||||
int spa_bt_device_ensure_media_codec(struct spa_bt_device *device, const struct media_codec * const *codecs);
|
||||
bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, bool sink);
|
||||
const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count, bool sink);
|
||||
bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, enum spa_bt_profile profile);
|
||||
const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count);
|
||||
int spa_bt_device_ensure_hfp_codec(struct spa_bt_device *device, unsigned int codec);
|
||||
int spa_bt_device_supports_hfp_codec(struct spa_bt_device *device, unsigned int codec);
|
||||
int spa_bt_device_release_transports(struct spa_bt_device *device);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue