From f2aaebf3f8c1f9e71586a9d5f5c370d3338c07cf Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Tue, 4 Dec 2018 00:39:21 -0800 Subject: binding: bluetooth: add MediaTransport1 support Bug-AGL: SPEC-1630 SPEC-1986 Change-Id: I6ad1f85d4edc00239f891edf6994db416e8a2dbd Signed-off-by: Matt Ranostay --- README.md | 25 ++++++++++++++++ binding/bluetooth-api.c | 75 +++++++++++++++++++++++++++++++++++++++-------- binding/bluetooth-api.h | 33 +++++++++++++++++++++ binding/bluetooth-bluez.c | 15 +++++++++- 4 files changed, 134 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 13bd068..50870df 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ Playing audio reporting event (not all fields will be passed in every event): { "adapter": "hci0", "device": "dev_D0_81_7A_5A_BC_5E", + "type": "playback", "track": { "title": "True Colors", "duration": 228000, @@ -236,6 +237,30 @@ Playing audio reporting event (not all fields will be passed in every event): } +A2DP transport addition/removal (some fields are optional): + +
+{
+        "adapter": "hci0",
+        "device": "dev_D0_81_7A_5A_BC_5E",
+        "action": "added",
+        "type": "transport",
+        "endpoint": "fd0"
+        "properties": {
+                "uuid": "0000110B-0000-1000-8000-00805F9B34FB",
+                "state": "idle",
+                "volume": 127
+         },
+}
+...
+{
+        "adapter": "hci0",
+        "device": "dev_D0_81_7A_5A_BC_5E",
+        "action": "removed",
+        "type": "transport",
+        "endpoint": "fd0"
+}
+
### agent event diff --git a/binding/bluetooth-api.c b/binding/bluetooth-api.c index 23ce55d..8388695 100644 --- a/binding/bluetooth-api.c +++ b/binding/bluetooth-api.c @@ -300,18 +300,23 @@ static void bluez_devices_signal_callback( const char *name = NULL; GVariant *val = NULL; - if (g_strcmp0(key, BLUEZ_DEVICE_INTERFACE) != 0) + if (g_strcmp0(key, BLUEZ_DEVICE_INTERFACE) && + g_strcmp0(key, BLUEZ_MEDIATRANSPORT_INTERFACE)) continue; array1 = g_variant_iter_new(var); while (g_variant_iter_next(array1, "{&sv}", &name, &val)) { - ret = device_property_dbus2json(jobj, - name, val, &is_config, &error); + if (!g_strcmp0(key, BLUEZ_DEVICE_INTERFACE)) + ret = device_property_dbus2json(jobj, + name, val, &is_config, &error); + else + ret = mediatransport_property_dbus2json(jobj, + name, val, &is_config, &error); g_variant_unref(val); if (!ret) { - AFB_WARNING("%s property %s - %s", - "devices", + AFB_DEBUG("%s property %s - %s", + path, key, error->message); g_clear_error(&error); } @@ -323,12 +328,25 @@ static void bluez_devices_signal_callback( if (array1) { json_object_object_add(jresp, "action", json_object_new_string("added")); + + if (is_mediatransport1_interface(path)) { + gchar *endpoint = find_index(path, 5); + json_object_object_add(jresp, "type", + json_object_new_string("transport")); + json_object_object_add(jresp, "endpoint", + json_object_new_string(endpoint)); + g_free(endpoint); + + event = ns->media_event; + } json_object_object_add(jresp, "properties", jobj); } else if (is_mediaplayer1_interface(path) && g_str_has_suffix(path, BLUEZ_DEFAULT_PLAYER)) { json_object_object_add(jresp, "connected", json_object_new_boolean(TRUE)); + json_object_object_add(jresp, "type", + json_object_new_string("playback")); mediaplayer1_set_path(ns, path); event = ns->media_event; } else { @@ -344,10 +362,22 @@ static void bluez_devices_signal_callback( jresp = json_object_new_object(); json_process_path(jresp, path); - if (is_mediaplayer1_interface(path)) { + if (is_mediatransport1_interface(path)) { + gchar *endpoint = find_index(path, 5); + json_object_object_add(jresp, "type", + json_object_new_string("transport")); + json_object_object_add(jresp, "action", + json_object_new_string("removed")); + json_object_object_add(jresp, "endpoint", + json_object_new_string(endpoint)); + g_free(endpoint); + + event = ns->media_event; + } else if (is_mediaplayer1_interface(path)) { json_object_object_add(jresp, "connected", json_object_new_boolean(FALSE)); - //mediaplayer1_set_path(ns, NULL); + json_object_object_add(jresp, "type", + json_object_new_string("playback")); event = ns->media_event; } else if (split_length(path) == 5) { json_object_object_add(jresp, "action", @@ -377,7 +407,7 @@ static void bluez_devices_signal_callback( key, var, &is_config, &error); g_variant_unref(var); if (!ret) { - AFB_WARNING("%s property %s - %s", + AFB_DEBUG("%s property %s - %s", "devices", key, error->message); g_clear_error(&error); @@ -395,25 +425,44 @@ static void bluez_devices_signal_callback( jresp = NULL; } - } else if (!g_strcmp0(path, BLUEZ_MEDIAPLAYER_INTERFACE)) { + } else if (!g_strcmp0(path, BLUEZ_MEDIAPLAYER_INTERFACE) || + !g_strcmp0(path, BLUEZ_MEDIATRANSPORT_INTERFACE)) { int cnt = 0; jresp = json_object_new_object(); json_process_path(jresp, object_path); while (g_variant_iter_next(array, "{&sv}", &key, &var)) { - ret = mediaplayer_property_dbus2json(jresp, + if (!g_strcmp0(path, BLUEZ_MEDIAPLAYER_INTERFACE)) + ret = mediaplayer_property_dbus2json(jresp, + key, var, &is_config, &error); + else + ret = mediatransport_property_dbus2json(jresp, key, var, &is_config, &error); g_variant_unref(var); if (!ret) { - //AFB_WARNING("%s property %s - %s", - // "mediaplayer", - // key, error->message); + AFB_DEBUG("%s property %s - %s", + path, + key, error->message); g_clear_error(&error); continue; } cnt++; } + if (!g_strcmp0(path, BLUEZ_MEDIAPLAYER_INTERFACE)) { + json_object_object_add(jresp, "type", + json_object_new_string("playback")); + } else { + gchar *endpoint = find_index(object_path, 5); + json_object_object_add(jresp, "action", + json_object_new_string("changed")); + json_object_object_add(jresp, "type", + json_object_new_string("transport")); + json_object_object_add(jresp, "endpoint", + json_object_new_string(endpoint)); + g_free(endpoint); + } + // NOTE: Possible to get a changed property for something we don't care about if (!cnt) { json_object_put(jresp); diff --git a/binding/bluetooth-api.h b/binding/bluetooth-api.h index 5fa417a..31418ae 100644 --- a/binding/bluetooth-api.h +++ b/binding/bluetooth-api.h @@ -34,6 +34,7 @@ #define BLUEZ_AGENTMANAGER_INTERFACE BLUEZ_SERVICE ".AgentManager1" #define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device1" #define BLUEZ_MEDIAPLAYER_INTERFACE BLUEZ_SERVICE ".MediaPlayer1" +#define BLUEZ_MEDIATRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1" #define BLUEZ_OBJECT_PATH "/" #define BLUEZ_PATH "/org/bluez" @@ -68,6 +69,7 @@ #define BLUEZ_AT_AGENT "agent" #define BLUEZ_AT_AGENTMANAGER "agent-manager" #define BLUEZ_AT_MEDIAPLAYER "mediaplayer" +#define BLUEZ_AT_MEDIATRANSPORT "mediatransport" #define BLUEZ_DEFAULT_ADAPTER "hci0" #define BLUEZ_DEFAULT_PLAYER "player0" @@ -122,6 +124,22 @@ static inline gboolean is_mediaplayer1_interface(const char *path) return ret; } +static inline gboolean is_mediatransport1_interface(const char *path) +{ + gchar *data = NULL; + gboolean ret; + + // Don't trigger on NowPlaying, Item, etc paths + if (split_length(path) != 6) + return FALSE; + + data = find_index(path, 5); + ret = g_str_has_prefix(data, "fd"); + g_free(data); + + return ret; +} + struct bluetooth_state *bluetooth_get_userdata(afb_req_t request); struct call_work *call_work_create_unlocked(struct bluetooth_state *ns, @@ -192,6 +210,14 @@ static inline gboolean mediaplayer_property_dbus2json(json_object *jprop, jprop, key, var, is_config, error); } +static inline gboolean mediatransport_property_dbus2json(json_object *jprop, + const gchar *key, GVariant *var, gboolean *is_config, + GError **error) +{ + return bluez_property_dbus2json(BLUEZ_AT_MEDIATRANSPORT, + jprop, key, var, is_config, error); +} + static inline GVariant *device_call(struct bluetooth_state *ns, const char *device, const char *method, GVariant *params, GError **error) @@ -252,6 +278,13 @@ static inline json_object *mediaplayer_properties(struct bluetooth_state *ns, BLUEZ_AT_MEDIAPLAYER, player, error); } +static inline json_object *mediatransport_properties(struct bluetooth_state *ns, + GError **error, const gchar *player) +{ + return bluez_get_properties(ns, + BLUEZ_AT_MEDIATRANSPORT, player, error); +} + static inline json_object *object_properties(struct bluetooth_state *ns, GError **error) { diff --git a/binding/bluetooth-bluez.c b/binding/bluetooth-bluez.c index 1c46106..a52d225 100644 --- a/binding/bluetooth-bluez.c +++ b/binding/bluetooth-bluez.c @@ -68,7 +68,6 @@ static const struct property_info device_props[] = { { .name = "Connected", .fmt = "b", }, { .name = "UUIDs", .fmt = "as", }, { .name = "Adapter", .fmt = "s", }, - { .name = "ServicesResolved", .fmt = "b", }, { }, }; @@ -92,6 +91,14 @@ static const struct property_info mediaplayer_props[] = { { }, }; +static const struct property_info mediatransport_props[] = { + { .name = "UUID", .fmt = "s", }, + { .name = "State", .fmt = "s", }, + { .name = "Delay", .fmt = "q", }, + { .name = "Volume", .fmt = "q", }, + { }, +}; + const struct property_info *bluez_get_property_info( const char *access_type, GError **error) { @@ -103,6 +110,8 @@ const struct property_info *bluez_get_property_info( pi = device_props; else if (!strcmp(access_type, BLUEZ_AT_MEDIAPLAYER)) pi = mediaplayer_props; + else if (!strcmp(access_type, BLUEZ_AT_MEDIATRANSPORT)) + pi = mediatransport_props; else g_set_error(error, NB_ERROR, NB_ERROR_ILLEGAL_ARGUMENT, "illegal %s argument", access_type); @@ -347,6 +356,7 @@ json_object *bluez_get_properties(struct bluetooth_state *ns, if (!strcmp(access_type, BLUEZ_AT_DEVICE) || !strcmp(access_type, BLUEZ_AT_MEDIAPLAYER) || + !strcmp(access_type, BLUEZ_AT_MEDIATRANSPORT) || !strcmp(access_type, BLUEZ_AT_ADAPTER)) { pi = bluez_get_property_info(access_type, error); @@ -366,6 +376,8 @@ json_object *bluez_get_properties(struct bluetooth_state *ns, interface2 = BLUEZ_DEVICE_INTERFACE; else if (!strcmp(access_type, BLUEZ_AT_MEDIAPLAYER)) interface2 = BLUEZ_MEDIAPLAYER_INTERFACE; + else if (!strcmp(access_type, BLUEZ_AT_MEDIATRANSPORT)) + interface2 = BLUEZ_MEDIATRANSPORT_INTERFACE; else if (!strcmp(access_type, BLUEZ_AT_ADAPTER)) interface2 = BLUEZ_ADAPTER_INTERFACE; else if (!strcmp(access_type, BLUEZ_AT_OBJECT)) @@ -391,6 +403,7 @@ json_object *bluez_get_properties(struct bluetooth_state *ns, if (!strcmp(access_type, BLUEZ_AT_DEVICE) || !strcmp(access_type, BLUEZ_AT_MEDIAPLAYER) || + !strcmp(access_type, BLUEZ_AT_MEDIATRANSPORT) || !strcmp(access_type, BLUEZ_AT_ADAPTER)) { jprop = json_object_new_object(); g_variant_get(reply, "(a{sv})", &array); -- cgit 1.2.3-korg