bluez5: set BAP channel location from transport if unset

If BAP codec configuration is mono channel with unspecified location,
set the channel position from transport location.

This in principle should be set in SelectProperties, but currently BlueZ
doesn't tell us that yet there, so we hack it up later on.
This commit is contained in:
Pauli Virtanen 2023-04-02 19:45:12 +03:00 committed by Wim Taymans
parent 8f840e703b
commit 6e94487057
4 changed files with 80 additions and 6 deletions

View file

@ -90,6 +90,12 @@
#define BT_ISO_QOS_TARGET_LATENCY_BALANCED 0x02
#define BT_ISO_QOS_TARGET_LATENCY_RELIABILITY 0x03
struct __attribute__((packed)) ltv {
uint8_t len;
uint8_t type;
uint8_t value[];
};
struct bap_endpoint_qos {
uint8_t framing;
uint8_t phy;

View file

@ -34,12 +34,6 @@ struct impl {
unsigned int codesize;
};
struct __attribute__((packed)) ltv {
uint8_t len;
uint8_t type;
uint8_t value[];
};
struct pac_data {
const uint8_t *data;
size_t size;

View file

@ -38,6 +38,8 @@
#include "iso-io.h"
#include "defs.h"
#include "bap-codec-caps.h"
static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5");
#undef SPA_LOG_TOPIC_DEFAULT
#define SPA_LOG_TOPIC_DEFAULT &log_topic
@ -2878,6 +2880,16 @@ static int transport_update_props(struct spa_bt_transport *transport,
else
transport->bap_cis = value;
}
else if (spa_streq(key, "Location")) {
uint32_t value;
if (type != DBUS_TYPE_UINT32)
goto next;
dbus_message_iter_get_basic(&it[1], &value);
spa_log_debug(monitor->log, "transport %p: %s=%d", transport, key, (int)value);
transport->bap_location = value;
}
next:
dbus_message_iter_next(props_iter);
}
@ -3845,6 +3857,64 @@ int spa_bt_device_supports_hfp_codec(struct spa_bt_device *device, unsigned int
return spa_bt_backend_supports_codec(monitor->backend, device, codec);
}
static void bap_update_codec_location(struct spa_bt_transport *t)
{
uint8_t *data = t->configuration;
size_t size = t->configuration_len;
struct ltv *ltv;
uint32_t location;
int i;
if (!t->bap_location)
return;
/*
* Append channel location from BAP transport location, if no channel
* configuration is present in the configuration.
*
* XXX: The codec select_configuration should set the location
* XXX: for mono channels from the device location. We have to do
* XXX: this here because transport location is not know
* XXX: in SelectProperties (TODO: should be fixed in bluez).
*/
while (size > 0) {
ltv = (struct ltv *)data;
if (ltv->len < sizeof(struct ltv) || ltv->len >= size)
return;
if (ltv->type == LC3_TYPE_CHAN)
return; /* already has the channel info */
size -= ltv->len + 1;
data += ltv->len + 1;
}
/* Pick the first location bit set */
location = t->bap_location;
for (i = 0; i < 32; ++i) {
if (location & (1 << i)) {
location = (1 << i);
break;
}
}
/* Append LTV value to transport configuration */
size = t->configuration_len + sizeof(struct ltv) + sizeof(uint32_t);
data = realloc(t->configuration, size);
if (!data)
return;
ltv = SPA_PTROFF(data, t->configuration_len, struct ltv);
ltv->len = 5;
ltv->type = LC3_TYPE_CHAN;
memcpy(ltv->value, &location, sizeof(uint32_t));
t->configuration = data;
t->configuration_len = size;
}
static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn,
const char *path, DBusMessage *m, void *userdata)
{
@ -3929,6 +3999,9 @@ static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn,
|= transport->device->a2dp_volume_active[SPA_BT_VOLUME_ID_TX];
}
if (codec->bap)
bap_update_codec_location(transport);
if (codec->validate_config) {
struct spa_audio_info info;
if (codec->validate_config(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0,

View file

@ -612,6 +612,7 @@ struct spa_bt_transport {
unsigned int latency_us;
uint8_t bap_cig;
uint8_t bap_cis;
uint32_t bap_location;
struct spa_bt_iso_io *iso_io;
struct spa_bt_sco_io *sco_io;