aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--profiles/audio/bap.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index b07d65e68b..0dcc57eb5e 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -46,6 +46,8 @@
#include "src/shared/gatt-client.h"
#include "src/shared/gatt-server.h"
#include "src/shared/bap.h"
+#include "src/shared/tmap.h"
+#include "src/shared/gmap.h"
#include "btio/btio.h"
#include "src/plugin.h"
@@ -65,6 +67,10 @@
#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
#define MEDIA_INTERFACE "org.bluez.Media1"
+#define VCS_UUID_STR "00001844-0000-1000-8000-00805f9b34fb"
+#define TMAS_UUID_STR "00001855-0000-1000-8000-00805f9b34fb"
+#define GMAS_UUID_STR "00001858-0000-1000-8000-00805f9b34fb"
+
struct bap_setup;
typedef void (*bap_setup_ready_func_t)(struct bap_setup *setup, int code,
@@ -438,6 +444,120 @@ static gboolean get_qos(const GDBusPropertyTable *property,
return TRUE;
}
+static bool probe_tmap_role(struct bap_ep *ep, uint32_t data)
+{
+ struct gatt_db *db = bt_bap_get_db(ep->data->bap, true);
+
+ return bt_tmap_get_role(bt_tmap_find(db)) & data;
+}
+
+static bool probe_gmap_role(struct bap_ep *ep, uint32_t data)
+{
+ struct gatt_db *db = bt_bap_get_db(ep->data->bap, true);
+
+ return bt_gmap_get_role(bt_gmap_find(db)) & data;
+}
+
+static bool probe_gmap_feature(struct bap_ep *ep, uint32_t data)
+{
+ struct gatt_db *db = bt_bap_get_db(ep->data->bap, true);
+
+ return bt_gmap_get_features(bt_gmap_find(db)) & data;
+}
+
+struct feature {
+ const char *name;
+ bool (*probe)(struct bap_ep *ep, uint32_t data);
+ uint32_t data;
+};
+
+static const struct feature tmap_features[] = {
+ { "cg", probe_tmap_role, BT_TMAP_ROLE_CG },
+ { "ct", probe_tmap_role, BT_TMAP_ROLE_CT },
+ { "ums", probe_tmap_role, BT_TMAP_ROLE_UMS },
+ { "umr", probe_tmap_role, BT_TMAP_ROLE_UMR },
+ { "bms", probe_tmap_role, BT_TMAP_ROLE_BMS },
+ { "bmr", probe_tmap_role, BT_TMAP_ROLE_BMR },
+};
+
+static const struct feature gmap_features[] = {
+ { "ugg", probe_gmap_role, BT_GMAP_ROLE_UGG },
+ { "ugt", probe_gmap_role, BT_GMAP_ROLE_UGT },
+ { "bgs", probe_gmap_role, BT_GMAP_ROLE_BGS },
+ { "bgr", probe_gmap_role, BT_GMAP_ROLE_BGR },
+ { "ugg-multiplex", probe_gmap_feature, BT_GMAP_UGG_MULTIPLEX },
+ { "ugg-96kbps-source", probe_gmap_feature, BT_GMAP_UGG_96KBPS },
+ { "ugg-multisink", probe_gmap_feature, BT_GMAP_UGG_MULTISINK },
+ { "ugt-source", probe_gmap_feature, BT_GMAP_UGT_SOURCE },
+ { "ugt-80kbps-source", probe_gmap_feature,
+ BT_GMAP_UGT_80KBPS_SOURCE },
+ { "ugt-sink", probe_gmap_feature, BT_GMAP_UGT_SINK },
+ { "ugt-64kbps-sink", probe_gmap_feature, BT_GMAP_UGT_64KBPS_SINK },
+ { "ugt-multiplex", probe_gmap_feature, BT_GMAP_UGT_MULTIPLEX },
+ { "ugt-multisink", probe_gmap_feature, BT_GMAP_UGT_MULTISINK },
+ { "ugt-multisource", probe_gmap_feature, BT_GMAP_UGT_MULTISOURCE },
+ { "bgs-96kbps", probe_gmap_feature, BT_GMAP_BGS_96KBPS },
+ { "bgr-multisink", probe_gmap_feature, BT_GMAP_BGR_MULTISINK },
+ { "bgr-multiplex", probe_gmap_feature, BT_GMAP_BGR_MULTIPLEX },
+};
+
+static const struct {
+ const char *uuid;
+ const struct feature *items;
+ size_t count;
+} features[] = {
+ { TMAS_UUID_STR, tmap_features, ARRAY_SIZE(tmap_features) },
+ { GMAS_UUID_STR, gmap_features, ARRAY_SIZE(gmap_features) },
+};
+
+static gboolean supported_features(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct bap_ep *ep = data;
+ DBusMessageIter dict, entry, variant, list;
+ size_t i, j;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+ for (i = 0; i < ARRAY_SIZE(features); ++i) {
+ for (j = 0; j < features[i].count; ++j) {
+ const struct feature *feature = &features[i].items[j];
+
+ if (feature->probe(ep, feature->data))
+ break;
+ }
+ if (j == features[i].count)
+ continue;
+
+ dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
+ &features[i].uuid);
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ "as", &variant);
+ dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+ "s", &list);
+
+ for (j = 0; j < features[i].count; ++j) {
+ const struct feature *feature = &features[i].items[j];
+
+ if (!feature->probe(ep, feature->data))
+ continue;
+
+ dbus_message_iter_append_basic(&list, DBUS_TYPE_STRING,
+ &feature->name);
+ }
+
+ dbus_message_iter_close_container(&variant, &list);
+ dbus_message_iter_close_container(&entry, &variant);
+ dbus_message_iter_close_container(&dict, &entry);
+ }
+
+ dbus_message_iter_close_container(iter, &dict);
+
+ return TRUE;
+}
+
static const GDBusPropertyTable ep_properties[] = {
{ "UUID", "s", get_uuid, NULL, NULL,
G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
@@ -457,6 +577,8 @@ static const GDBusPropertyTable ep_properties[] = {
G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
{ "QoS", "a{sv}", get_qos, NULL, qos_exists,
G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "SupportedFeatures", "a{sv}", supported_features, NULL, NULL,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
{ }
};