Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem
@ 2013-02-15 14:02 Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 2/7] AVRCP: Parse browsing and searching features bits Luiz Augusto von Dentz
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2013-02-15 14:02 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This separate the scopes of the folder as documented in doc/media-api.txt
---
 profiles/audio/avrcp.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 00eeea1..5967180 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -1935,9 +1935,10 @@ static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
 
 	depth = operands[13];
 
-	folders = g_new0(char *, depth + 1);
+	folders = g_new0(char *, depth + 2);
+	folders[0] = g_strdup("/Filesystem");
 
-	for (i = 14, count = 0; count < depth; count++) {
+	for (i = 14, count = 1; count - 1 < depth; count++) {
 		char *part;
 		uint8_t len;
 
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 2/7] AVRCP: Parse browsing and searching features bits
  2013-02-15 14:02 [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Luiz Augusto von Dentz
@ 2013-02-15 14:02 ` Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 3/7] media-api: Fix referencing to MediaLibrary instead of MediaFolder Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2013-02-15 14:02 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This parses browsing and searching features bits and set the respective
property.
---
 profiles/audio/avrcp.c  | 18 ++++++++----
 profiles/audio/player.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++-
 profiles/audio/player.h |  2 ++
 3 files changed, 87 insertions(+), 6 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 5967180..cabe2ee 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -1976,6 +1976,18 @@ static void avrcp_set_browsed_player(struct avrcp *session,
 				avrcp_set_browsed_player_rsp, session);
 }
 
+static void avrcp_player_parse_features(struct avrcp_player *player,
+							uint8_t *features)
+{
+	struct media_player *mp = player->user_data;
+
+	if (features[7] & 0x08)
+		media_player_set_browsable(mp, true);
+
+	if (features[7] & 0x10)
+		media_player_set_searchable(mp, true);
+}
+
 static void avrcp_parse_media_player_item(struct avrcp *session,
 					uint8_t *operands, uint16_t len)
 {
@@ -1984,7 +1996,6 @@ static void avrcp_parse_media_player_item(struct avrcp *session,
 	uint16_t id;
 	uint32_t subtype;
 	const char *curval, *strval;
-	uint64_t features[2];
 	char name[255];
 
 	if (len < 28)
@@ -2009,10 +2020,7 @@ static void avrcp_parse_media_player_item(struct avrcp *session,
 		avrcp_get_play_status(session);
 	}
 
-	features[0] = bt_get_be64(&operands[8]);
-	features[1] = bt_get_be64(&operands[16]);
-
-	media_player_set_features(mp, features);
+	avrcp_player_parse_features(player, &operands[8]);
 
 	if (operands[26] != 0) {
 		memcpy(name, &operands[27], operands[26]);
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index f875ee7..7879193 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -67,7 +67,9 @@ struct media_player {
 	char			*name;		/* Player name */
 	char			*type;		/* Player type */
 	char			*subtype;	/* Player subtype */
-	uint64_t		features[2];	/* Player features */
+	bool			browsable;	/* Player browsing feature */
+	bool			searchable;	/* Player searching feature */
+	uint8_t			*features;	/* Player features */
 	struct media_folder	*folder;	/* Player currenct folder */
 	char			*path;		/* Player object path */
 	GHashTable		*settings;	/* Player settings */
@@ -350,6 +352,57 @@ static gboolean get_subtype(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static gboolean browsable_exists(const GDBusPropertyTable *property, void *data)
+{
+	struct media_player *mp = data;
+
+	return mp->folder != NULL;
+}
+
+static gboolean get_browsable(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct media_player *mp = data;
+	dbus_bool_t value;
+
+	if (mp->folder == NULL)
+		return FALSE;
+
+	DBG("%s", mp->browsable ? "true" : "false");
+
+	value = mp->browsable;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+	return TRUE;
+}
+
+static gboolean searchable_exists(const GDBusPropertyTable *property,
+								void *data)
+{
+	struct media_player *mp = data;
+
+	return mp->folder != NULL;
+}
+
+static gboolean get_searchable(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct media_player *mp = data;
+	dbus_bool_t value;
+
+	if (mp->folder == NULL)
+		return FALSE;
+
+	DBG("%s", mp->searchable ? "true" : "false");
+
+	value = mp->searchable;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+	return TRUE;
+}
+
 static DBusMessage *media_player_play(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
@@ -510,6 +563,10 @@ static const GDBusPropertyTable media_player_properties[] = {
 					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
 	{ "Device", "s", get_device, NULL, NULL,
 					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+	{ "Browsable", "b", get_browsable, NULL, browsable_exists,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+	{ "Searchable", "b", get_searchable, NULL, searchable_exists,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
 	{ }
 };
 
@@ -843,6 +900,20 @@ void media_player_set_name(struct media_player *mp, const char *name)
 					"Name");
 }
 
+void media_player_set_browsable(struct media_player *mp, bool enabled)
+{
+	DBG("%s", enabled ? "true" : "false");
+
+	mp->browsable = enabled;
+}
+
+void media_player_set_searchable(struct media_player *mp, bool enabled)
+{
+	DBG("%s", enabled ? "true" : "false");
+
+	mp->searchable = enabled;
+}
+
 void media_player_set_folder(struct media_player *mp, const char *path,
 								uint32_t items)
 {
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index 1ac9800..e9a7d1c 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -51,6 +51,8 @@ void media_player_set_type(struct media_player *mp, const char *type);
 void media_player_set_subtype(struct media_player *mp, const char *subtype);
 void media_player_set_features(struct media_player *mp, uint64_t *features);
 void media_player_set_name(struct media_player *mp, const char *name);
+void media_player_set_browsable(struct media_player *mp, bool enabled);
+void media_player_set_searchable(struct media_player *mp, bool enabled);
 void media_player_set_folder(struct media_player *mp, const char *path,
 								uint32_t items);
 
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 3/7] media-api: Fix referencing to MediaLibrary instead of MediaFolder
  2013-02-15 14:02 [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 2/7] AVRCP: Parse browsing and searching features bits Luiz Augusto von Dentz
@ 2013-02-15 14:02 ` Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 4/7] AVRCP: Move features to avrcp.c Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2013-02-15 14:02 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

MediaLibrary was replaced by MediaFolder so doesn't exist anymore.
---
 doc/media-api.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/doc/media-api.txt b/doc/media-api.txt
index db1575f..2656a9e 100644
--- a/doc/media-api.txt
+++ b/doc/media-api.txt
@@ -233,7 +233,7 @@ Properties	string Equalizer [readwrite]
 		boolean Browsable [readonly]
 
 			If present indicates the player can be browsed using
-			MediaLibrary interface.
+			MediaFolder interface.
 
 			Possible values:
 
@@ -248,7 +248,7 @@ Properties	string Equalizer [readwrite]
 		boolean Searchable [readonly]
 
 			If present indicates the player can be searched using
-			MediaLibrary interface.
+			MediaFolder interface.
 
 			Possible values:
 
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 4/7] AVRCP: Move features to avrcp.c
  2013-02-15 14:02 [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 2/7] AVRCP: Parse browsing and searching features bits Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 3/7] media-api: Fix referencing to MediaLibrary instead of MediaFolder Luiz Augusto von Dentz
@ 2013-02-15 14:02 ` Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 5/7] AVRCP: Create folders for /Filesystem and /NowPlaying Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2013-02-15 14:02 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

avrcp.c should be responsible for specifics of AVRCP not player.c which
is more high level abstraction.
---
 profiles/audio/avrcp.c  | 4 ++++
 profiles/audio/player.c | 8 --------
 profiles/audio/player.h | 1 -
 3 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index cabe2ee..55887bc 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -180,6 +180,7 @@ struct avrcp_player {
 	GSList *sessions;
 	uint16_t id;
 	uint16_t uid_counter;
+	uint8_t *features;
 
 	struct avrcp_player_cb *cb;
 	void *user_data;
@@ -1981,6 +1982,8 @@ static void avrcp_player_parse_features(struct avrcp_player *player,
 {
 	struct media_player *mp = player->user_data;
 
+	player->features = g_memdup(features, 16);
+
 	if (features[7] & 0x08)
 		media_player_set_browsable(mp, true);
 
@@ -2553,6 +2556,7 @@ static void player_destroy(gpointer data)
 		player->destroy(player->user_data);
 
 	g_slist_free(player->sessions);
+	g_free(player->features);
 	g_free(player);
 }
 
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index 7879193..07fd457 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -69,7 +69,6 @@ struct media_player {
 	char			*subtype;	/* Player subtype */
 	bool			browsable;	/* Player browsing feature */
 	bool			searchable;	/* Player searching feature */
-	uint8_t			*features;	/* Player features */
 	struct media_folder	*folder;	/* Player currenct folder */
 	char			*path;		/* Player object path */
 	GHashTable		*settings;	/* Player settings */
@@ -941,13 +940,6 @@ void media_player_set_folder(struct media_player *mp, const char *path,
 	}
 }
 
-void media_player_set_features(struct media_player *mp, uint64_t *features)
-{
-	DBG("0x%016" PRIx64 "%016" PRIx64, features[0], features[1]);
-
-	memcpy(features, mp->features, sizeof(mp->features));
-}
-
 void media_player_set_callbacks(struct media_player *mp,
 				const struct media_player_callback *cbs,
 				void *user_data)
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index e9a7d1c..9109b1f 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -49,7 +49,6 @@ void media_player_set_metadata(struct media_player *mp, const char *key,
 						void *data, size_t len);
 void media_player_set_type(struct media_player *mp, const char *type);
 void media_player_set_subtype(struct media_player *mp, const char *subtype);
-void media_player_set_features(struct media_player *mp, uint64_t *features);
 void media_player_set_name(struct media_player *mp, const char *name);
 void media_player_set_browsable(struct media_player *mp, bool enabled);
 void media_player_set_searchable(struct media_player *mp, bool enabled);
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 5/7] AVRCP: Create folders for /Filesystem and /NowPlaying
  2013-02-15 14:02 [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2013-02-15 14:02 ` [PATCH BlueZ 4/7] AVRCP: Move features to avrcp.c Luiz Augusto von Dentz
@ 2013-02-15 14:02 ` Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 6/7] AVRCP: Add support for GetItemAttributes Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2013-02-15 14:02 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

If browsing is supported create objects representing /Filesystem and
/NowPlaying, these object implement MediaItem interface and can be
passed to ChangeFolder to change the scope.
---
 profiles/audio/avrcp.c  |   7 +-
 profiles/audio/player.c | 233 ++++++++++++++++++++++++++++++++++++++++++------
 profiles/audio/player.h |   2 +
 3 files changed, 216 insertions(+), 26 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 55887bc..3b9aad6 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -1984,11 +1984,16 @@ static void avrcp_player_parse_features(struct avrcp_player *player,
 
 	player->features = g_memdup(features, 16);
 
-	if (features[7] & 0x08)
+	if (features[7] & 0x08) {
 		media_player_set_browsable(mp, true);
+		media_player_create_folder(mp, "/Filesystem");
+	}
 
 	if (features[7] & 0x10)
 		media_player_set_searchable(mp, true);
+
+	if (features[8] & 0x02)
+		media_player_create_folder(mp, "/NowPlaying");
 }
 
 static void avrcp_parse_media_player_item(struct avrcp *session,
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index 07fd457..466b44a 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -45,6 +45,7 @@
 
 #define MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
 #define MEDIA_FOLDER_INTERFACE "org.bluez.MediaFolder1"
+#define MEDIA_ITEM_INTERFACE "org.bluez.MediaItem1"
 
 struct player_callback {
 	const struct media_player_callback *cbs;
@@ -57,9 +58,17 @@ struct pending_req {
 	const char *value;
 };
 
+struct media_item {
+	struct media_player	*player;
+	char			*path;		/* Item object path */
+	char			*name;		/* Item name */
+	bool			folder;		/* Item folder flag */
+	bool			playable;	/* Item playable flag */
+};
+
 struct media_folder {
-	char			*name;		/* Folder name */
-	uint32_t		items;		/* Number of items */
+	struct media_item	*item;		/* Folder item */
+	uint32_t		number_of_items;/* Number of items */
 };
 
 struct media_player {
@@ -79,6 +88,7 @@ struct media_player {
 	guint			process_id;
 	struct player_callback	*cb;
 	GSList			*pending;
+	GSList			*folders;
 };
 
 static void append_metadata(void *key, void *value, void *user_data)
@@ -592,25 +602,27 @@ static gboolean folder_name_exists(const GDBusPropertyTable *property,
 								void *data)
 {
 	struct media_player *mp = data;
+	struct media_folder *folder = mp->folder;
 
-	if (mp->folder == NULL)
+	if (folder == NULL || folder->item == NULL)
 		return FALSE;
 
-	return mp->folder->name != NULL;
+	return folder->item->name != NULL;
 }
 
 static gboolean get_folder_name(const GDBusPropertyTable *property,
 					DBusMessageIter *iter, void *data)
 {
 	struct media_player *mp = data;
+	struct media_folder *folder = mp->folder;
 
-	if (mp->folder == NULL || mp->folder->name == NULL)
+	if (folder == NULL || folder->item == NULL)
 		return FALSE;
 
-	DBG("%s", mp->folder->name);
+	DBG("%s", folder->item->name);
 
 	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
-							&mp->folder->name);
+							&folder->item->name);
 
 	return TRUE;
 }
@@ -626,14 +638,15 @@ static gboolean get_items(const GDBusPropertyTable *property,
 					DBusMessageIter *iter, void *data)
 {
 	struct media_player *mp = data;
+	struct media_folder *folder = mp->folder;
 
-	if (mp->folder == NULL)
+	if (folder == NULL)
 		return FALSE;
 
-	DBG("%u", mp->folder->items);
+	DBG("%u", folder->number_of_items);
 
 	dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32,
-							&mp->folder->items);
+						&folder->number_of_items);
 
 	return TRUE;
 }
@@ -661,9 +674,22 @@ static const GDBusPropertyTable media_folder_properties[] = {
 	{ }
 };
 
+static void media_item_destroy(void *data)
+{
+	struct media_item *item = data;
+
+	DBG("%s", item->path);
+
+	g_dbus_unregister_interface(btd_get_dbus_connection(), item->path,
+						MEDIA_ITEM_INTERFACE);
+
+	g_free(item->path);
+	g_free(item->name);
+	g_free(item);
+}
+
 static void media_folder_destroy(struct media_folder *folder)
 {
-	g_free(folder->name);
 	g_free(folder);
 }
 
@@ -691,6 +717,7 @@ void media_player_destroy(struct media_player *mp)
 	}
 
 	g_slist_free_full(mp->pending, g_free);
+	g_slist_free_full(mp->folders, media_item_destroy);
 
 	g_timer_destroy(mp->progress);
 	g_free(mp->cb);
@@ -913,31 +940,187 @@ void media_player_set_searchable(struct media_player *mp, bool enabled)
 	mp->searchable = enabled;
 }
 
-void media_player_set_folder(struct media_player *mp, const char *path,
-								uint32_t items)
+static void media_player_set_folder_item(struct media_player *mp,
+						struct media_item *item,
+						uint32_t number_of_items)
 {
 	struct media_folder *folder;
 
-	DBG("%s items %u", path, items);
+	folder = mp->folder;
 
-	if (mp->folder != NULL)
-		media_folder_destroy(mp->folder);
+	if (folder == NULL) {
+		folder = g_new0(struct media_folder, 1);
+		mp->folder = folder;
 
-	folder = g_new0(struct media_folder, 1);
-	folder->name = g_strdup(path);
-	folder->items = items;
-	mp->folder = folder;
-
-	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+		if (!g_dbus_register_interface(btd_get_dbus_connection(),
 					mp->path, MEDIA_FOLDER_INTERFACE,
 					media_folder_methods,
 					NULL,
 					media_folder_properties, mp, NULL)) {
-		error("D-Bus failed to register %s on %s path",
+			error("D-Bus failed to register %s on %s path",
 					MEDIA_FOLDER_INTERFACE, mp->path);
-		media_folder_destroy(mp->folder);
-		mp->folder = NULL;
+			media_folder_destroy(mp->folder);
+			mp->folder = NULL;
+			return;
+		}
+	}
+
+	folder->item = item;
+	folder->number_of_items = number_of_items;
+
+	g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+				MEDIA_FOLDER_INTERFACE, "Name");
+	g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+				MEDIA_FOLDER_INTERFACE, "NumberOfItems");
+}
+
+static struct media_item *media_player_find_folder(struct media_player *mp,
+							const char *name)
+{
+	GSList *l;
+
+	for (l = mp->folders; l; l = l->next) {
+		struct media_item *item = l->data;
+
+		if (!item->folder)
+			continue;
+
+		if (g_str_equal(item->name, name))
+			return item;
 	}
+
+	return NULL;
+}
+
+void media_player_set_folder(struct media_player *mp, const char *name,
+						uint32_t number_of_items)
+{
+	struct media_item *item;
+
+	DBG("%s number of items %u", name, number_of_items);
+
+	item = media_player_find_folder(mp, name);
+	if (item == NULL) {
+		error("Unknown folder: %s", name);
+		return;
+	}
+
+	media_player_set_folder_item(mp, item, number_of_items);
+}
+
+static DBusMessage *media_item_play(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	return btd_error_failed(msg, strerror(ENOTSUP));
+}
+
+static DBusMessage *media_item_add_to_nowplaying(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	return btd_error_failed(msg, strerror(ENOTSUP));
+}
+
+static gboolean item_name_exists(const GDBusPropertyTable *property,
+								void *data)
+{
+	struct media_item *item = data;
+
+	return item->name != NULL;
+}
+
+static gboolean get_item_name(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct media_item *item = data;
+
+	if (item->name == NULL)
+		return FALSE;
+
+	DBG("%s", item->name);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &item->name);
+
+	return TRUE;
+}
+
+static gboolean get_folder_flag(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct media_item *item = data;
+	dbus_bool_t value;
+
+	DBG("%s", item->folder ? "true" : "false");
+
+	value = item->folder;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+	return TRUE;
+}
+
+static gboolean get_playable(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct media_item *item = data;
+	dbus_bool_t value;
+
+	DBG("%s", item->playable ? "true" : "false");
+
+	value = item->playable;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+	return TRUE;
+}
+
+static const GDBusMethodTable media_item_methods[] = {
+	{ GDBUS_EXPERIMENTAL_METHOD("Play", NULL, NULL,
+					media_item_play) },
+	{ GDBUS_EXPERIMENTAL_METHOD("AddtoNowPlaying", NULL, NULL,
+					media_item_add_to_nowplaying) },
+	{ }
+};
+
+static const GDBusPropertyTable media_item_properties[] = {
+	{ "Name", "s", get_item_name, NULL, item_name_exists,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+	{ "Folder", "b", get_folder_flag, NULL, NULL,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+	{ "Playable", "b", get_playable, NULL, NULL,
+					G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+	{ }
+};
+
+int media_player_create_folder(struct media_player *mp, const char *name)
+{
+	struct media_item *item;
+
+	DBG("%s", name);
+
+	item = g_new0(struct media_item, 1);
+	item->player = mp;
+	item->path = g_strdup_printf("%s%s", mp->path, name);
+	item->name = g_strdup(name);
+	item->folder = true;
+	item->playable = false;
+
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+					item->path, MEDIA_ITEM_INTERFACE,
+					media_item_methods,
+					NULL,
+					media_item_properties, item, NULL)) {
+		error("D-Bus failed to register %s on %s path",
+					MEDIA_ITEM_INTERFACE, item->path);
+		media_item_destroy(item);
+		return -EINVAL;
+	}
+
+	if (mp->folder == NULL)
+		media_player_set_folder_item(mp, item, 0);
+
+	mp->folders = g_slist_prepend(mp->folders, item);
+
+	return 0;
 }
 
 void media_player_set_callbacks(struct media_player *mp,
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index 9109b1f..a59cc66 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -55,6 +55,8 @@ void media_player_set_searchable(struct media_player *mp, bool enabled);
 void media_player_set_folder(struct media_player *mp, const char *path,
 								uint32_t items);
 
+int media_player_create_folder(struct media_player *mp, const char *path);
+
 void media_player_set_callbacks(struct media_player *mp,
 				const struct media_player_callback *cbs,
 				void *user_data);
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 6/7] AVRCP: Add support for GetItemAttributes
  2013-02-15 14:02 [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2013-02-15 14:02 ` [PATCH BlueZ 5/7] AVRCP: Create folders for /Filesystem and /NowPlaying Luiz Augusto von Dentz
@ 2013-02-15 14:02 ` Luiz Augusto von Dentz
  2013-02-15 14:02 ` [PATCH BlueZ 7/7] AVRCP: Fix parsing of SetBrowsedPlayer response Luiz Augusto von Dentz
  2013-02-15 14:45 ` [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Johan Hedberg
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2013-02-15 14:02 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

GetItemAttributes should be used instead of GetElementAttributes if
browsing is supported.
---
 profiles/audio/avrcp.c | 112 ++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 83 insertions(+), 29 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 3b9aad6..9833a3a 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -100,6 +100,7 @@
 #define AVRCP_ABORT_CONTINUING		0x41
 #define AVRCP_SET_ABSOLUTE_VOLUME	0x50
 #define AVRCP_SET_BROWSED_PLAYER	0x70
+#define AVRCP_GET_ITEM_ATTRIBUTES	0x73
 #define AVRCP_GET_FOLDER_ITEMS		0x71
 #define AVRCP_GENERAL_REJECT		0xA0
 
@@ -1788,42 +1789,23 @@ static void avrcp_list_player_attributes(struct avrcp *session)
 					session);
 }
 
-static gboolean avrcp_get_attributes_rsp(struct avctp *conn,
-					uint8_t code, uint8_t subunit,
-					uint8_t *operands, size_t operand_count,
-					void *user_data)
+static void avrcp_parse_attribute_list(struct avrcp_player *player,
+					uint8_t *operands, uint8_t count)
 {
-	struct avrcp *session = user_data;
-	struct avrcp_player *player = session->player;
 	struct media_player *mp = player->user_data;
-	struct avrcp_header *pdu = (void *) operands;
-	uint8_t count;
 	int i;
 
-	if (code == AVC_CTYPE_REJECTED)
-		return FALSE;
-
-	count = pdu->params[0];
-
-	if (ntohs(pdu->params_len) - 1 < count * 8) {
-		error("Invalid parameters");
-		return FALSE;
-	}
-
-	for (i = 1; count > 0; count--) {
+	for (i = 0; count > 0; count--) {
 		uint32_t id;
 		uint16_t charset, len;
 
-		memcpy(&id, &pdu->params[i], sizeof(uint32_t));
-		id = ntohl(id);
+		id = bt_get_be32(&operands[i]);
 		i += sizeof(uint32_t);
 
-		memcpy(&charset, &pdu->params[i], sizeof(uint16_t));
-		charset = ntohs(charset);
+		charset = bt_get_be16(&operands[i]);
 		i += sizeof(uint16_t);
 
-		memcpy(&len, &pdu->params[i], sizeof(uint16_t));
-		len = ntohs(len);
+		len = bt_get_be16(&operands[i]);
 		i += sizeof(uint16_t);
 
 		if (charset == 106) {
@@ -1832,11 +1814,35 @@ static gboolean avrcp_get_attributes_rsp(struct avctp *conn,
 			if (key != NULL)
 				media_player_set_metadata(mp,
 							metadata_to_str(id),
-							&pdu->params[i], len);
+							&operands[i], len);
 		}
 
 		i += len;
 	}
+}
+
+static gboolean avrcp_get_element_attributes_rsp(struct avctp *conn,
+						uint8_t code, uint8_t subunit,
+						uint8_t *operands,
+						size_t operand_count,
+						void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_header *pdu = (void *) operands;
+	uint8_t count;
+
+	if (code == AVC_CTYPE_REJECTED)
+		return FALSE;
+
+	count = pdu->params[0];
+
+	if (ntohs(pdu->params_len) - 1 < count * 8) {
+		error("Invalid parameters");
+		return FALSE;
+	}
+
+	avrcp_parse_attribute_list(player, &pdu->params[1], count);
 
 	return FALSE;
 }
@@ -1858,7 +1864,7 @@ static void avrcp_get_element_attributes(struct avrcp *session)
 
 	avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
 					AVC_SUBUNIT_PANEL, buf, length,
-					avrcp_get_attributes_rsp,
+					avrcp_get_element_attributes_rsp,
 					session);
 }
 
@@ -1977,6 +1983,48 @@ static void avrcp_set_browsed_player(struct avrcp *session,
 				avrcp_set_browsed_player_rsp, session);
 }
 
+static gboolean avrcp_get_item_attributes_rsp(struct avctp *conn,
+						uint8_t *operands,
+						size_t operand_count,
+						void *user_data)
+{
+	struct avrcp *session = user_data;
+	struct avrcp_player *player = session->player;
+	struct avrcp_browsing_header *pdu = (void *) operands;
+	uint8_t count;
+
+	if (pdu->params[0] != AVRCP_STATUS_SUCCESS || operand_count < 4)
+		return FALSE;
+
+	count = pdu->params[1];
+
+	if (ntohs(pdu->param_len) - 1 < count * 8) {
+		error("Invalid parameters");
+		return FALSE;
+	}
+
+	avrcp_parse_attribute_list(player, &pdu->params[2], count);
+
+	return FALSE;
+}
+
+static void avrcp_get_item_attributes(struct avrcp *session, uint64_t uid)
+{
+	uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 12];
+	struct avrcp_browsing_header *pdu = (void *) buf;
+
+	memset(buf, 0, sizeof(buf));
+
+	pdu->pdu_id = AVRCP_GET_ITEM_ATTRIBUTES;
+	pdu->params[0] = 0x03;
+	bt_put_be64(uid, &pdu->params[1]);
+	bt_put_be16(session->player->uid_counter, &pdu->params[9]);
+	pdu->param_len = htons(12);
+
+	avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+				avrcp_get_item_attributes_rsp, session);
+}
+
 static void avrcp_player_parse_features(struct avrcp_player *player,
 							uint8_t *features)
 {
@@ -2122,9 +2170,15 @@ static void avrcp_status_changed(struct avrcp *session,
 static void avrcp_track_changed(struct avrcp *session,
 						struct avrcp_header *pdu)
 {
-	avrcp_get_element_attributes(session);
-	avrcp_get_play_status(session);
+	uint64_t uid;
+
+	if (session->browsing_id) {
+		uid = bt_get_be64(&pdu->params[1]);
+		avrcp_get_item_attributes(session, uid);
+	} else
+		avrcp_get_element_attributes(session);
 
+	avrcp_get_play_status(session);
 }
 
 static void avrcp_setting_changed(struct avrcp *session,
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH BlueZ 7/7] AVRCP: Fix parsing of SetBrowsedPlayer response
  2013-02-15 14:02 [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2013-02-15 14:02 ` [PATCH BlueZ 6/7] AVRCP: Add support for GetItemAttributes Luiz Augusto von Dentz
@ 2013-02-15 14:02 ` Luiz Augusto von Dentz
  2013-02-15 14:45 ` [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Johan Hedberg
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2013-02-15 14:02 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Folder depth is actually the byte 13 not 14 of the response.
---
 profiles/audio/avrcp.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 9833a3a..9be977e 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -1928,29 +1928,30 @@ static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
 	struct avrcp *session = user_data;
 	struct avrcp_player *player = session->player;
 	struct media_player *mp = player->user_data;
+	struct avrcp_browsing_header *pdu = (void *) operands;
 	uint32_t items;
 	char **folders, *path;
 	uint8_t depth, count;
 	int i;
 
-	if (operands[3] != AVRCP_STATUS_SUCCESS || operand_count < 13)
+	if (pdu->params[0] != AVRCP_STATUS_SUCCESS || operand_count < 13)
 		return FALSE;
 
-	player->uid_counter = bt_get_be16(&operands[4]);
+	player->uid_counter = bt_get_be16(&pdu->params[1]);
 
-	items = bt_get_be32(&operands[6]);
+	items = bt_get_be32(&pdu->params[3]);
 
-	depth = operands[13];
+	depth = operands[9];
 
 	folders = g_new0(char *, depth + 2);
 	folders[0] = g_strdup("/Filesystem");
 
-	for (i = 14, count = 1; count - 1 < depth; count++) {
+	for (i = 10, count = 1; count - 1 < depth; count++) {
 		char *part;
 		uint8_t len;
 
-		len = operands[i++];
-		part = g_memdup(&operands[i], len);
+		len = pdu->params[i++];
+		part = g_memdup(&pdu->params[i], len);
 		i += len;
 		folders[count] = part;
 	}
-- 
1.8.1.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem
  2013-02-15 14:02 [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2013-02-15 14:02 ` [PATCH BlueZ 7/7] AVRCP: Fix parsing of SetBrowsedPlayer response Luiz Augusto von Dentz
@ 2013-02-15 14:45 ` Johan Hedberg
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hedberg @ 2013-02-15 14:45 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth

Hi Luiz,

On Fri, Feb 15, 2013, Luiz Augusto von Dentz wrote:
> This separate the scopes of the folder as documented in doc/media-api.txt
> ---
>  profiles/audio/avrcp.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)

All patches in this set have been applied. Thanks.

Johan

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-02-15 14:45 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-02-15 14:02 [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Luiz Augusto von Dentz
2013-02-15 14:02 ` [PATCH BlueZ 2/7] AVRCP: Parse browsing and searching features bits Luiz Augusto von Dentz
2013-02-15 14:02 ` [PATCH BlueZ 3/7] media-api: Fix referencing to MediaLibrary instead of MediaFolder Luiz Augusto von Dentz
2013-02-15 14:02 ` [PATCH BlueZ 4/7] AVRCP: Move features to avrcp.c Luiz Augusto von Dentz
2013-02-15 14:02 ` [PATCH BlueZ 5/7] AVRCP: Create folders for /Filesystem and /NowPlaying Luiz Augusto von Dentz
2013-02-15 14:02 ` [PATCH BlueZ 6/7] AVRCP: Add support for GetItemAttributes Luiz Augusto von Dentz
2013-02-15 14:02 ` [PATCH BlueZ 7/7] AVRCP: Fix parsing of SetBrowsedPlayer response Luiz Augusto von Dentz
2013-02-15 14:45 ` [PATCH BlueZ 1/7] AVRCP: Prefix folder name with /Filesystem Johan Hedberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox