* [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation
@ 2013-05-28 12:51 Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 01/13] player: Split item creation Luiz Augusto von Dentz
` (12 more replies)
0 siblings, 13 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
v2: Fixes ChangeFolder not working for subfolders past /Filesystem
This set of patches implements most of the functionality of MediaFolder and
MediaItem interfaces.
Some remarks:
- ChangeFolder can only change one level at time, this perhaps gonna be
changed in the future but for now this matches the limitation of AVRCP
itself.
- ListItems returns the items in the correct order but GetManagedObjects does
the reverse order due to use of g_slist_prepend.
- PlayItem and AddToNowPlaying works fine with iPhone but with WP8 is not
working probably because the UIDCounter changes more frequently which needs
some new notifications that are currently not implemented.
This can be tested using tools/mpris-player which will browse the NowPlaying
list and show which item is currently being played, but the gnome extention
itself needs patching which can be found here:
https://github.com/Vudentz/gnome-shell-extensions-mediaplayer
Luiz Augusto von Dentz (13):
player: Split item creation
AVRCP: Add browsed flag to player
AVRCP: Add support for GetFolderItems command
player: Add implementation of MediaFolder.ListItems
player: Add support for setting current Item object
player: Add function media_item_set_playable
player: Add support for MediaItem.Metadata property
AVRCP: Add support for ChangePath command
player: Add implementation of MediaFolder.ChangeFolder
AVRCP: Add support for PlayItem command
player: Add implementation of MediaItem.Play
AVRCP: Add support for AddToNowPlaying command
player: Add implementation of MediaItem.AddToNowPlaying
profiles/audio/avrcp.c | 390 +++++++++++++++++++++++++++++-
profiles/audio/player.c | 623 ++++++++++++++++++++++++++++++++++++++++--------
profiles/audio/player.h | 23 +-
3 files changed, 916 insertions(+), 120 deletions(-)
--
1.8.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 01/13] player: Split item creation
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 02/13] AVRCP: Add browsed flag to player Luiz Augusto von Dentz
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This split item creation into two functions, media_player_create_folder
for folders and media_player_create_item for regular items.
---
profiles/audio/avrcp.c | 4 +-
profiles/audio/player.c | 343 +++++++++++++++++++++++++++++++++---------------
profiles/audio/player.h | 11 +-
3 files changed, 250 insertions(+), 108 deletions(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 4558407..39882e4 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -2138,7 +2138,7 @@ static void avrcp_player_parse_features(struct avrcp_player *player,
if (features[7] & 0x08) {
media_player_set_browsable(mp, true);
media_player_create_folder(mp, "/Filesystem",
- PLAYER_FOLDER_TYPE_MIXED);
+ PLAYER_FOLDER_TYPE_MIXED, 0);
}
if (features[7] & 0x10)
@@ -2146,7 +2146,7 @@ static void avrcp_player_parse_features(struct avrcp_player *player,
if (features[8] & 0x02) {
media_player_create_folder(mp, "/NowPlaying",
- PLAYER_FOLDER_TYPE_MIXED);
+ PLAYER_FOLDER_TYPE_MIXED, 0);
media_player_set_playlist(mp, "/NowPlaying");
}
}
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index e08e373..c774cfe 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -65,11 +65,15 @@ struct media_item {
player_item_type_t type; /* Item type */
player_folder_type_t folder_type; /* Folder type */
bool playable; /* Item playable flag */
+ uint64_t uid; /* Item uid */
};
struct media_folder {
+ struct media_folder *parent;
struct media_item *item; /* Folder item */
uint32_t number_of_items;/* Number of items */
+ GSList *subfolders;
+ GSList *items;
};
struct media_player {
@@ -79,8 +83,9 @@ struct media_player {
char *subtype; /* Player subtype */
bool browsable; /* Player browsing feature */
bool searchable; /* Player searching feature */
+ struct media_folder *scope; /* Player current scope */
struct media_folder *folder; /* Player current folder */
- struct media_item *playlist; /* Player current playlist */
+ struct media_folder *playlist; /* Player current playlist */
char *path; /* Player object path */
GHashTable *settings; /* Player settings */
GHashTable *track; /* Player current track */
@@ -375,7 +380,7 @@ static gboolean browsable_exists(const GDBusPropertyTable *property, void *data)
{
struct media_player *mp = data;
- return mp->folder != NULL;
+ return mp->scope != NULL;
}
static gboolean get_browsable(const GDBusPropertyTable *property,
@@ -384,7 +389,7 @@ static gboolean get_browsable(const GDBusPropertyTable *property,
struct media_player *mp = data;
dbus_bool_t value;
- if (mp->folder == NULL)
+ if (mp->scope == NULL)
return FALSE;
DBG("%s", mp->browsable ? "true" : "false");
@@ -401,7 +406,7 @@ static gboolean searchable_exists(const GDBusPropertyTable *property,
{
struct media_player *mp = data;
- return mp->folder != NULL;
+ return mp->scope != NULL;
}
static gboolean get_searchable(const GDBusPropertyTable *property,
@@ -434,13 +439,13 @@ static gboolean get_playlist(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
struct media_player *mp = data;
- struct media_item *playlist = mp->playlist;
+ struct media_folder *playlist = mp->playlist;
if (playlist == NULL)
return FALSE;
dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
- &playlist->path);
+ &playlist->item->path);
return TRUE;
}
@@ -626,6 +631,93 @@ static DBusMessage *media_folder_list_items(DBusConnection *conn,
return btd_error_failed(msg, strerror(ENOTSUP));
}
+static void media_item_free(struct media_item *item)
+{
+ g_free(item->path);
+ g_free(item->name);
+ g_free(item);
+}
+
+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);
+
+ media_item_free(item);
+}
+
+static void media_folder_destroy(void *data)
+{
+ struct media_folder *folder = data;
+
+ g_slist_free_full(folder->subfolders, media_folder_destroy);
+ g_slist_free_full(folder->items, media_item_destroy);
+
+ media_item_destroy(folder->item);
+ g_free(folder);
+}
+
+static void media_player_change_scope(struct media_player *mp,
+ struct media_folder *folder)
+{
+ if (mp->scope == folder)
+ return;
+
+ DBG("%s", folder->item->name);
+
+ /* Skip setting current folder if folder is current playlist */
+ if (folder == mp->playlist)
+ goto cleanup;
+
+ mp->folder = folder;
+
+ /* Skip item cleanup if scope is the current playlist */
+ if (mp->scope == mp->playlist)
+ goto done;
+
+cleanup:
+ g_slist_free_full(mp->scope->items, media_item_destroy);
+ mp->scope->items = NULL;
+
+done:
+ mp->scope = folder;
+
+ 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_folder *find_folder(GSList *folders, const char *pattern)
+{
+ GSList *l;
+
+ for (l = folders; l; l = l->next) {
+ struct media_folder *folder = l->data;
+
+ if (g_str_equal(folder->item->name, pattern))
+ return folder;
+
+ if (g_str_equal(folder->item->path, pattern))
+ return folder;
+
+ folder = find_folder(folder->subfolders, pattern);
+ if (folder != NULL)
+ return folder;
+ }
+
+ return NULL;
+}
+
+static struct media_folder *media_player_find_folder(struct media_player *mp,
+ const char *pattern)
+{
+ return find_folder(mp->folders, pattern);
+}
static DBusMessage *media_folder_change_folder(DBusConnection *conn,
DBusMessage *msg, void *data)
@@ -637,7 +729,7 @@ static gboolean folder_name_exists(const GDBusPropertyTable *property,
void *data)
{
struct media_player *mp = data;
- struct media_folder *folder = mp->folder;
+ struct media_folder *folder = mp->scope;
if (folder == NULL || folder->item == NULL)
return FALSE;
@@ -649,7 +741,7 @@ static gboolean get_folder_name(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
struct media_player *mp = data;
- struct media_folder *folder = mp->folder;
+ struct media_folder *folder = mp->scope;
if (folder == NULL || folder->item == NULL)
return FALSE;
@@ -666,14 +758,14 @@ static gboolean items_exists(const GDBusPropertyTable *property, void *data)
{
struct media_player *mp = data;
- return mp->folder != NULL;
+ return mp->scope != NULL;
}
static gboolean get_items(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
struct media_player *mp = data;
- struct media_folder *folder = mp->folder;
+ struct media_folder *folder = mp->scope;
if (folder == NULL)
return FALSE;
@@ -709,23 +801,24 @@ static const GDBusPropertyTable media_folder_properties[] = {
{ }
};
-static void media_item_destroy(void *data)
+static void media_player_set_scope(struct media_player *mp,
+ struct media_folder *folder)
{
- 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);
-}
+ if (mp->scope == NULL) {
+ 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",
+ MEDIA_FOLDER_INTERFACE, mp->path);
+ return;
+ }
+ mp->scope = folder;
+ return;
+ }
-static void media_folder_destroy(struct media_folder *folder)
-{
- g_free(folder);
+ return media_player_change_scope(mp, folder);
}
void media_player_destroy(struct media_player *mp)
@@ -744,15 +837,13 @@ void media_player_destroy(struct media_player *mp)
if (mp->process_id > 0)
g_source_remove(mp->process_id);
- if (mp->folder) {
+ if (mp->scope)
g_dbus_unregister_interface(btd_get_dbus_connection(),
mp->path,
MEDIA_FOLDER_INTERFACE);
- media_folder_destroy(mp->folder);
- }
g_slist_free_full(mp->pending, g_free);
- g_slist_free_full(mp->folders, media_item_destroy);
+ g_slist_free_full(mp->folders, media_folder_destroy);
g_timer_destroy(mp->progress);
g_free(mp->cb);
@@ -1006,90 +1097,58 @@ void media_player_set_searchable(struct media_player *mp, bool enabled)
"Searchable");
}
-static void media_player_set_folder_item(struct media_player *mp,
- struct media_item *item,
+void media_player_set_folder(struct media_player *mp, const char *name,
uint32_t number_of_items)
{
struct media_folder *folder;
- folder = mp->folder;
+ DBG("%s number of items %u", name, number_of_items);
+ folder = media_player_find_folder(mp, name);
if (folder == NULL) {
- folder = g_new0(struct media_folder, 1);
- mp->folder = folder;
-
- 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",
- MEDIA_FOLDER_INTERFACE, mp->path);
- media_folder_destroy(mp->folder);
- mp->folder = NULL;
- return;
- }
+ error("Unknown folder: %s", name);
+ 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->type != PLAYER_ITEM_TYPE_FOLDER)
- continue;
-
- if (g_str_equal(item->name, name))
- return item;
- }
-
- return NULL;
+ media_player_set_scope(mp, folder);
}
-void media_player_set_folder(struct media_player *mp, const char *name,
- uint32_t number_of_items)
+void media_player_set_playlist(struct media_player *mp, const char *name)
{
- struct media_item *item;
+ struct media_folder *folder;
- DBG("%s number of items %u", name, number_of_items);
+ DBG("%s", name);
- item = media_player_find_folder(mp, name);
- if (item == NULL) {
+ folder = media_player_find_folder(mp, name);
+ if (folder == NULL) {
error("Unknown folder: %s", name);
return;
}
- media_player_set_folder_item(mp, item, number_of_items);
+ mp->playlist = folder;
+
+ g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+ MEDIA_PLAYER_INTERFACE, "Playlist");
}
-void media_player_set_playlist(struct media_player *mp, const char *name)
+static struct media_item *media_folder_find_item(struct media_folder *folder,
+ uint64_t uid)
{
- struct media_item *item;
+ GSList *l;
- DBG("%s", name);
+ if (uid == 0)
+ return NULL;
- item = media_player_find_folder(mp, name);
- if (item == NULL) {
- error("Unknown folder: %s", name);
- return;
- }
+ for (l = folder->items; l; l = l->next) {
+ struct media_item *item = l->data;
- mp->playlist = item;
+ if (item->uid == uid)
+ return item;
+ }
- g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
- MEDIA_PLAYER_INTERFACE, "Playlist");
+ return NULL;
}
static DBusMessage *media_item_play(DBusConnection *conn, DBusMessage *msg,
@@ -1238,22 +1297,35 @@ static const GDBusPropertyTable media_item_properties[] = {
{ }
};
-static struct media_item *media_player_create_item(struct media_player *mp,
+struct media_item *media_player_create_item(struct media_player *mp,
const char *name,
- player_item_type_t type)
+ player_item_type_t type,
+ uint64_t uid)
{
+ struct media_folder *folder = mp->scope;
struct media_item *item;
const char *strtype;
+ item = media_folder_find_item(folder, uid);
+ if (item != NULL)
+ return item;
+
strtype = type_to_string(type);
if (strtype == NULL)
return NULL;
- DBG("%s type %s", name, strtype);
+ DBG("%s type %s uid %" PRIu64 "", name, strtype, uid);
item = g_new0(struct media_item, 1);
item->player = mp;
- item->path = g_strdup_printf("%s%s", mp->path, name);
+ item->uid = uid;
+
+ if (uid > 0)
+ item->path = g_strdup_printf("%s/item%" PRIu64 "",
+ folder->item->path, uid);
+ else
+ item->path = g_strdup_printf("%s%s", mp->path, name);
+
item->name = g_strdup(name);
item->type = type;
item->folder_type = PLAYER_FOLDER_TYPE_INVALID;
@@ -1265,35 +1337,98 @@ static struct media_item *media_player_create_item(struct media_player *mp,
media_item_properties, item, NULL)) {
error("D-Bus failed to register %s on %s path",
MEDIA_ITEM_INTERFACE, item->path);
- media_item_destroy(item);
+ media_item_free(item);
return NULL;
}
+ if (type != PLAYER_ITEM_TYPE_FOLDER)
+ folder->items = g_slist_prepend(folder->items, item);
+
+ DBG("%s", item->path);
+
return item;
}
-int media_player_create_folder(struct media_player *mp, const char *name,
- player_folder_type_t type)
+static struct media_item *
+media_player_create_subfolder(struct media_player *mp, const char *name,
+ uint64_t uid)
{
+ struct media_folder *folder = mp->scope;
struct media_item *item;
+ char *path;
- item = media_player_find_folder(mp, name);
- if (item != NULL)
- return 0;
+ path = g_strdup_printf("%s/%s", folder->item->name, name);
+
+ DBG("%s", path);
+
+ item = media_player_create_item(mp, path, PLAYER_ITEM_TYPE_FOLDER,
+ uid);
+ g_free(path);
+
+ return item;
+}
+
+static struct media_folder *
+media_player_find_folder_by_uid(struct media_player *mp, uint64_t uid)
+{
+ struct media_folder *folder = mp->scope;
+ GSList *l;
+
+ for (l = folder->subfolders; l; l = l->next) {
+ struct media_folder *folder = l->data;
+
+ if (folder->item->uid == uid)
+ return folder;
+ }
+
+ return NULL;
+}
+
+struct media_item *media_player_create_folder(struct media_player *mp,
+ const char *name,
+ player_folder_type_t type,
+ uint64_t uid)
+{
+ struct media_folder *folder;
+ struct media_item *item;
+
+ if (uid > 0)
+ folder = media_player_find_folder_by_uid(mp, uid);
+ else
+ folder = media_player_find_folder(mp, name);
+
+ if (folder != NULL)
+ return folder->item;
+
+ if (uid > 0)
+ item = media_player_create_subfolder(mp, name, uid);
+ else
+ item = media_player_create_item(mp, name,
+ PLAYER_ITEM_TYPE_FOLDER, uid);
- item = media_player_create_item(mp, name,
- PLAYER_ITEM_TYPE_FOLDER);
if (item == NULL)
- return -EINVAL;
+ return NULL;
+
+ folder = g_new0(struct media_folder, 1);
+ folder->item = item;
item->folder_type = type;
- if (mp->folder == NULL)
- media_player_set_folder_item(mp, item, 0);
+ if (mp->folder != NULL)
+ goto done;
- mp->folders = g_slist_prepend(mp->folders, item);
+ mp->folder = folder;
- return 0;
+done:
+ if (uid > 0) {
+ folder->parent = mp->folder;
+ mp->folder->subfolders = g_slist_prepend(
+ mp->folder->subfolders,
+ folder);
+ } else
+ mp->folders = g_slist_prepend(mp->folders, folder);
+
+ return item;
}
void media_player_set_callbacks(struct media_player *mp,
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index 852042e..6e44308 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -42,6 +42,7 @@ typedef enum {
} player_folder_type_t;
struct media_player;
+struct media_item;
struct media_player_callback {
bool (*set_setting) (struct media_player *mp, const char *key,
@@ -75,8 +76,14 @@ void media_player_set_folder(struct media_player *mp, const char *path,
uint32_t items);
void media_player_set_playlist(struct media_player *mp, const char *name);
-int media_player_create_folder(struct media_player *mp, const char *name,
- player_folder_type_t type);
+struct media_item *media_player_create_folder(struct media_player *mp,
+ const char *name,
+ player_folder_type_t type,
+ uint64_t uid);
+struct media_item *media_player_create_item(struct media_player *mp,
+ const char *name,
+ player_item_type_t type,
+ uint64_t uid);
void media_player_set_callbacks(struct media_player *mp,
const struct media_player_callback *cbs,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 02/13] AVRCP: Add browsed flag to player
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 01/13] player: Split item creation Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 03/13] AVRCP: Add support for GetFolderItems command Luiz Augusto von Dentz
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This flag indicates if the player is browsed and are checked to avoid
setting the same player as browsed multiple times.
---
profiles/audio/avrcp.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 39882e4..5477016 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -182,6 +182,7 @@ struct avrcp_player {
GSList *sessions;
uint16_t id;
uint16_t uid_counter;
+ bool browsed;
uint8_t *features;
struct avrcp_player_cb *cb;
@@ -2030,6 +2031,7 @@ static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
return FALSE;
player->uid_counter = bt_get_be16(&pdu->params[1]);
+ player->browsed = true;
items = bt_get_be32(&pdu->params[3]);
@@ -2375,7 +2377,7 @@ avrcp_parse_media_player_item(struct avrcp *session, uint8_t *operands,
media_player_set_name(mp, name);
}
- if (session->player == player)
+ if (session->player == player && !player->browsed)
avrcp_set_browsed_player(session, player);
return player;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 03/13] AVRCP: Add support for GetFolderItems command
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 01/13] player: Split item creation Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 02/13] AVRCP: Add browsed flag to player Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 04/13] player: Add implementation of MediaFolder.ListItems Luiz Augusto von Dentz
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds support for GetFolderItems command via player callback.
---
profiles/audio/avrcp.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++-
profiles/audio/player.h | 2 +
2 files changed, 195 insertions(+), 4 deletions(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 5477016..9b54ae9 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -177,14 +177,24 @@ struct pending_pdu {
uint16_t offset;
};
+struct pending_list_items {
+ GSList *items;
+ uint32_t start;
+ uint32_t end;
+};
+
struct avrcp_player {
struct avrcp_server *server;
GSList *sessions;
uint16_t id;
+ uint8_t scope;
+ uint64_t uid;
uint16_t uid_counter;
bool browsed;
uint8_t *features;
+ struct pending_list_items *p;
+
struct avrcp_player_cb *cb;
void *user_data;
GDestroyNotify destroy;
@@ -2013,6 +2023,158 @@ static const char *subtype_to_string(uint32_t subtype)
return "None";
}
+static struct media_item *parse_media_element(struct avrcp *session,
+ uint8_t *operands, uint16_t len)
+{
+ struct avrcp_player *player;
+ struct media_player *mp;
+ uint16_t namelen;
+ char name[255];
+ uint64_t uid;
+
+ if (len < 13)
+ return NULL;
+
+ uid = bt_get_be64(&operands[0]);
+
+ namelen = MIN(bt_get_be16(&operands[11]), sizeof(name) - 1);
+ if (namelen > 0) {
+ memcpy(name, &operands[13], namelen);
+ name[namelen] = '\0';
+ }
+
+ player = session->player;
+ mp = player->user_data;
+
+ return media_player_create_item(mp, name, PLAYER_ITEM_TYPE_AUDIO, uid);
+}
+
+static struct media_item *parse_media_folder(struct avrcp *session,
+ uint8_t *operands, uint16_t len)
+{
+ struct avrcp_player *player = session->player;
+ struct media_player *mp = player->user_data;
+ uint16_t namelen;
+ char name[255];
+ uint64_t uid;
+ uint8_t type;
+
+ if (len < 12)
+ return NULL;
+
+ uid = bt_get_be64(&operands[0]);
+ type = operands[9];
+
+ namelen = MIN(bt_get_be16(&operands[12]), sizeof(name) - 1);
+ if (namelen > 0) {
+ memcpy(name, &operands[14], namelen);
+ name[namelen] = '\0';
+ }
+
+ return media_player_create_folder(mp, name, type, uid);
+}
+
+static void avrcp_list_items(struct avrcp *session, uint32_t start,
+ uint32_t end);
+static gboolean avrcp_list_items_rsp(struct avctp *conn, uint8_t *operands,
+ size_t operand_count, void *user_data)
+{
+ struct avrcp_browsing_header *pdu = (void *) operands;
+ struct avrcp *session = user_data;
+ struct avrcp_player *player = session->player;
+ struct pending_list_items *p = player->p;
+ uint16_t count;
+ uint32_t items, total;
+ size_t i;
+
+ if (pdu->params[0] != AVRCP_STATUS_SUCCESS || operand_count < 5)
+ goto done;
+
+ count = bt_get_be16(&operands[6]);
+ if (count == 0)
+ goto done;
+
+ for (i = 8; count && i + 3 < operand_count; count--) {
+ struct media_item *item;
+ uint8_t type;
+ uint16_t len;
+
+ type = operands[i++];
+ len = bt_get_be16(&operands[i]);
+ i += 2;
+
+ if (type != 0x03 && type != 0x02) {
+ i += len;
+ continue;
+ }
+
+ if (i + len > operand_count) {
+ error("Invalid item length");
+ break;
+ }
+
+ if (type == 0x03)
+ item = parse_media_element(session, &operands[i], len);
+ else if (type == 0x02)
+ item = parse_media_folder(session, &operands[i], len);
+
+ if (item) {
+ if (g_slist_find(p->items, item))
+ goto done;
+ p->items = g_slist_append(p->items, item);
+ }
+
+ i += len;
+ }
+
+ items = g_slist_length(p->items);
+ total = p->end - p->start;
+ if (items < total) {
+ avrcp_list_items(session, p->start + items + 1, p->end);
+ return FALSE;
+ }
+
+done:
+ g_slist_free(p->items);
+ g_free(p);
+ player->p = NULL;
+
+ return FALSE;
+}
+
+static void avrcp_list_items(struct avrcp *session, uint32_t start,
+ uint32_t end)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 10 +
+ AVRCP_MEDIA_ATTRIBUTE_LAST * sizeof(uint32_t)];
+ struct avrcp_player *player = session->player;
+ struct avrcp_browsing_header *pdu = (void *) buf;
+ uint16_t length = AVRCP_BROWSING_HEADER_LENGTH + 10;
+ uint32_t attribute;
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_GET_FOLDER_ITEMS;
+ pdu->param_len = htons(10 + sizeof(uint32_t));
+
+ pdu->params[0] = player->scope;
+
+ bt_put_be32(start, &pdu->params[1]);
+ bt_put_be32(end, &pdu->params[5]);
+
+ pdu->params[9] = 1;
+
+ /* Only the title (0x01) is mandatory. This can be extended to
+ * support AVRCP_MEDIA_ATTRIBUTE_* attributes */
+ attribute = htonl(AVRCP_MEDIA_ATTRIBUTE_TITLE);
+ memcpy(&pdu->params[10], &attribute, sizeof(uint32_t));
+
+ length += sizeof(uint32_t);
+
+ avctp_send_browsing_req(session->conn, buf, length,
+ avrcp_list_items_rsp, session);
+}
+
static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
uint8_t *operands,
size_t operand_count,
@@ -2270,6 +2432,33 @@ static int ct_rewind(struct media_player *mp, void *user_data)
return ct_press(player, AVC_REWIND);
}
+static int ct_list_items(struct media_player *mp, const char *name,
+ uint32_t start, uint32_t end, void *user_data)
+{
+ struct avrcp_player *player = user_data;
+ struct avrcp *session;
+ struct pending_list_items *p;
+
+ if (player->p != NULL)
+ return -EBUSY;
+
+ session = player->sessions->data;
+
+ if (g_str_has_prefix(name, "/NowPlaying"))
+ player->scope = 0x03;
+ else
+ player->scope = 0x01;
+
+ avrcp_list_items(session, start, end);
+
+ p = g_new0(struct pending_list_items, 1);
+ p->start = start;
+ p->end = end;
+ player->p = p;
+
+ return 0;
+}
+
static const struct media_player_callback ct_cbs = {
.set_setting = ct_set_setting,
.play = ct_play,
@@ -2279,6 +2468,7 @@ static const struct media_player_callback ct_cbs = {
.previous = ct_previous,
.fast_forward = ct_fast_forward,
.rewind = ct_rewind,
+ .list_items = ct_list_items,
};
static struct avrcp_player *create_ct_player(struct avrcp *session,
@@ -2495,11 +2685,10 @@ static void avrcp_status_changed(struct avrcp *session,
static void avrcp_track_changed(struct avrcp *session,
struct avrcp_header *pdu)
{
- uint64_t uid;
-
if (session->browsing_id) {
- uid = bt_get_be64(&pdu->params[1]);
- avrcp_get_item_attributes(session, uid);
+ struct avrcp_player *player = session->player;
+ player->uid = bt_get_be64(&pdu->params[1]);
+ avrcp_get_item_attributes(session, player->uid);
} else
avrcp_get_element_attributes(session);
}
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index 6e44308..e7a885e 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -54,6 +54,8 @@ struct media_player_callback {
int (*previous) (struct media_player *mp, void *user_data);
int (*fast_forward) (struct media_player *mp, void *user_data);
int (*rewind) (struct media_player *mp, void *user_data);
+ int (*list_items) (struct media_player *mp, const char *name,
+ uint32_t start, uint32_t end, void *user_data);
};
struct media_player *media_player_controller_create(const char *path,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 04/13] player: Add implementation of MediaFolder.ListItems
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (2 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 03/13] AVRCP: Add support for GetFolderItems command Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 05/13] player: Add support for setting current Item object Luiz Augusto von Dentz
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
profiles/audio/avrcp.c | 2 +
profiles/audio/player.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++-
profiles/audio/player.h | 2 +
3 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 9b54ae9..f86dc9a 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -2135,6 +2135,8 @@ static gboolean avrcp_list_items_rsp(struct avctp *conn, uint8_t *operands,
}
done:
+ media_player_list_complete(player->user_data, p->items);
+
g_slist_free(p->items);
g_free(p);
player->p = NULL;
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index c774cfe..9fccb2f 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -74,6 +74,7 @@ struct media_folder {
uint32_t number_of_items;/* Number of items */
GSList *subfolders;
GSList *items;
+ DBusMessage *msg;
};
struct media_player {
@@ -569,6 +570,57 @@ static DBusMessage *media_player_rewind(DBusConnection *conn, DBusMessage *msg,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
+static void parse_folder_list(gpointer data, gpointer user_data)
+{
+ struct media_item *item = data;
+ DBusMessageIter *array = user_data;
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+ &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+ &item->path);
+
+ g_dbus_get_properties(btd_get_dbus_connection(), item->path,
+ MEDIA_ITEM_INTERFACE, &entry);
+
+ dbus_message_iter_close_container(array, &entry);
+}
+
+void media_player_list_complete(struct media_player *mp, GSList *items)
+{
+ struct media_folder *folder = mp->scope;
+ DBusMessage *reply;
+ DBusMessageIter iter, array;
+
+ if (folder == NULL || folder->msg == NULL)
+ return;
+
+ reply = dbus_message_new_method_return(folder->msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_OBJECT_PATH_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &array);
+
+ g_slist_foreach(items, parse_folder_list, &array);
+ dbus_message_iter_close_container(&iter, &array);
+
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+ dbus_message_unref(folder->msg);
+ folder->msg = NULL;
+}
+
static const GDBusMethodTable media_player_methods[] = {
{ GDBUS_EXPERIMENTAL_METHOD("Play", NULL, NULL, media_player_play) },
{ GDBUS_EXPERIMENTAL_METHOD("Pause", NULL, NULL, media_player_pause) },
@@ -625,10 +677,83 @@ static DBusMessage *media_folder_search(DBusConnection *conn, DBusMessage *msg,
return btd_error_failed(msg, strerror(ENOTSUP));
}
+static int parse_filters(struct media_player *player, DBusMessageIter *iter,
+ uint32_t *start, uint32_t *end)
+{
+ struct media_folder *folder = player->scope;
+ DBusMessageIter dict;
+ int ctype;
+
+ *start = 0;
+ *end = folder->number_of_items ? folder->number_of_items : UINT32_MAX;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ dbus_message_iter_recurse(iter, &dict);
+
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID) {
+ DBusMessageIter entry;
+ const char *key;
+
+ if (ctype != DBUS_TYPE_DICT_ENTRY)
+ return -EINVAL;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ return -EINVAL;
+
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_UINT32)
+ return -EINVAL;
+
+ if (strcasecmp(key, "Start") == 0)
+ dbus_message_iter_get_basic(&entry, start);
+ else if (strcasecmp(key, "End") == 0)
+ dbus_message_iter_get_basic(&entry, end);
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (folder->number_of_items > 0 && *end > folder->number_of_items)
+ *end = folder->number_of_items;
+
+ return 0;
+}
+
static DBusMessage *media_folder_list_items(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- return btd_error_failed(msg, strerror(ENOTSUP));
+ struct media_player *mp = data;
+ struct media_folder *folder = mp->scope;
+ struct player_callback *cb = mp->cb;
+ DBusMessageIter iter;
+ uint32_t start, end;
+ int err;
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (parse_filters(mp, &iter, &start, &end) < 0)
+ return btd_error_invalid_args(msg);
+
+ if (cb->cbs->list_items == NULL)
+ return btd_error_not_supported(msg);
+
+ if (folder->msg != NULL)
+ return btd_error_failed(msg, strerror(EBUSY));
+
+ err = cb->cbs->list_items(mp, folder->item->name, start, end,
+ cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ folder->msg = dbus_message_ref(msg);
+
+ return NULL;
}
static void media_item_free(struct media_item *item)
@@ -657,6 +782,9 @@ static void media_folder_destroy(void *data)
g_slist_free_full(folder->subfolders, media_folder_destroy);
g_slist_free_full(folder->items, media_item_destroy);
+ if (folder->msg != NULL)
+ dbus_message_unref(folder->msg);
+
media_item_destroy(folder->item);
g_free(folder);
}
@@ -783,7 +911,7 @@ static const GDBusMethodTable media_folder_methods[] = {
GDBUS_ARGS({ "string", "s" }, { "filter", "a{sv}" }),
GDBUS_ARGS({ "folder", "o" }),
media_folder_search) },
- { GDBUS_EXPERIMENTAL_METHOD("ListItems",
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ListItems",
GDBUS_ARGS({ "filter", "a{sv}" }),
GDBUS_ARGS({ "items", "a{oa{sv}}" }),
media_folder_list_items) },
@@ -818,6 +946,9 @@ static void media_player_set_scope(struct media_player *mp,
return;
}
+ if (mp->scope->msg != NULL)
+ return;
+
return media_player_change_scope(mp, folder);
}
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index e7a885e..0f75f4f 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -87,6 +87,8 @@ struct media_item *media_player_create_item(struct media_player *mp,
player_item_type_t type,
uint64_t uid);
+void media_player_list_complete(struct media_player *mp, GSList *items);
+
void media_player_set_callbacks(struct media_player *mp,
const struct media_player_callback *cbs,
void *user_data);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 05/13] player: Add support for setting current Item object
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (3 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 04/13] player: Add implementation of MediaFolder.ListItems Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 06/13] player: Add function media_item_set_playable Luiz Augusto von Dentz
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This introduces media_player_set_playlist_item which is used when the
current item UID is known, with this the application can tell what
is the current item in the playlist.
---
profiles/audio/avrcp.c | 3 +++
profiles/audio/player.c | 42 ++++++++++++++++++++++++++++++++++++------
profiles/audio/player.h | 1 +
3 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index f86dc9a..6ae0a68 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -1896,6 +1896,9 @@ static void avrcp_parse_attribute_list(struct avrcp_player *player,
struct media_player *mp = player->user_data;
int i;
+ if (player->uid > 0)
+ media_player_set_playlist_item(mp, player->uid);
+
for (i = 0; count > 0; count--) {
uint32_t id;
uint16_t charset, len;
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index 9fccb2f..77009c7 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -102,16 +102,18 @@ struct media_player {
static void append_metadata(void *key, void *value, void *user_data)
{
DBusMessageIter *dict = user_data;
+ const char *strkey = key;
- if (strcasecmp((char *) key, "Duration") == 0 ||
- strcasecmp((char *) key, "TrackNumber") == 0 ||
- strcasecmp((char *) key, "NumberOfTracks") == 0) {
+ if (strcasecmp(strkey, "Duration") == 0 ||
+ strcasecmp(strkey, "TrackNumber") == 0 ||
+ strcasecmp(strkey, "NumberOfTracks") == 0) {
uint32_t num = atoi(value);
dict_append_entry(dict, key, DBUS_TYPE_UINT32, &num);
- return;
+ } else if (strcasecmp(strkey, "Item") == 0) {
+ dict_append_entry(dict, key, DBUS_TYPE_OBJECT_PATH, &value);
+ } else {
+ dict_append_entry(dict, key, DBUS_TYPE_STRING, &value);
}
-
- dict_append_entry(dict, key, DBUS_TYPE_STRING, &value);
}
static struct pending_req *find_pending(struct media_player *mp,
@@ -1282,6 +1284,34 @@ static struct media_item *media_folder_find_item(struct media_folder *folder,
return NULL;
}
+void media_player_set_playlist_item(struct media_player *mp, uint64_t uid)
+{
+ struct media_folder *folder = mp->playlist;
+ struct media_item *item;
+
+ DBG("%" PRIu64 "", uid);
+
+ if (folder == NULL)
+ return;
+
+ item = media_folder_find_item(folder, uid);
+ if (item == NULL) {
+ warn("Item not found");
+ return;
+ }
+
+ if (item == g_hash_table_lookup(mp->track, "Item"))
+ return;
+
+ if (mp->process_id == 0) {
+ g_hash_table_remove_all(mp->track);
+ mp->process_id = g_idle_add(process_metadata_changed, mp);
+ }
+
+ g_hash_table_replace(mp->track, g_strdup("Item"),
+ g_strdup(item->path));
+}
+
static DBusMessage *media_item_play(DBusConnection *conn, DBusMessage *msg,
void *data)
{
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index 0f75f4f..843c71b 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -77,6 +77,7 @@ 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);
void media_player_set_playlist(struct media_player *mp, const char *name);
+void media_player_set_playlist_item(struct media_player *mp, uint64_t uid);
struct media_item *media_player_create_folder(struct media_player *mp,
const char *name,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 06/13] player: Add function media_item_set_playable
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (4 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 05/13] player: Add support for setting current Item object Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 07/13] player: Add support for MediaItem.Metadata property Luiz Augusto von Dentz
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
profiles/audio/avrcp.c | 9 ++++++++-
profiles/audio/player.c | 11 +++++++++++
profiles/audio/player.h | 1 +
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 6ae0a68..c141d24 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -2031,6 +2031,7 @@ static struct media_item *parse_media_element(struct avrcp *session,
{
struct avrcp_player *player;
struct media_player *mp;
+ struct media_item *item;
uint16_t namelen;
char name[255];
uint64_t uid;
@@ -2049,7 +2050,13 @@ static struct media_item *parse_media_element(struct avrcp *session,
player = session->player;
mp = player->user_data;
- return media_player_create_item(mp, name, PLAYER_ITEM_TYPE_AUDIO, uid);
+ item = media_player_create_item(mp, name, PLAYER_ITEM_TYPE_AUDIO, uid);
+ if (item == NULL)
+ return NULL;
+
+ media_item_set_playable(item, true);
+
+ return item;
}
static struct media_item *parse_media_folder(struct avrcp *session,
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index 77009c7..e7fe6ba 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -1458,6 +1458,17 @@ static const GDBusPropertyTable media_item_properties[] = {
{ }
};
+void media_item_set_playable(struct media_item *item, bool value)
+{
+ if (item->playable == value)
+ return;
+
+ item->playable = value;
+
+ g_dbus_emit_property_changed(btd_get_dbus_connection(), item->path,
+ MEDIA_ITEM_INTERFACE, "Playable");
+}
+
struct media_item *media_player_create_item(struct media_player *mp,
const char *name,
player_item_type_t type,
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index 843c71b..4e15c36 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -88,6 +88,7 @@ struct media_item *media_player_create_item(struct media_player *mp,
player_item_type_t type,
uint64_t uid);
+void media_item_set_playable(struct media_item *item, bool value);
void media_player_list_complete(struct media_player *mp, GSList *items);
void media_player_set_callbacks(struct media_player *mp,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 07/13] player: Add support for MediaItem.Metadata property
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (5 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 06/13] player: Add function media_item_set_playable Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 08/13] AVRCP: Add support for ChangePath command Luiz Augusto von Dentz
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
profiles/audio/player.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index e7fe6ba..deae112 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -66,6 +66,7 @@ struct media_item {
player_folder_type_t folder_type; /* Folder type */
bool playable; /* Item playable flag */
uint64_t uid; /* Item uid */
+ GHashTable *metadata; /* Item metadata */
};
struct media_folder {
@@ -760,6 +761,9 @@ static DBusMessage *media_folder_list_items(DBusConnection *conn,
static void media_item_free(struct media_item *item)
{
+ if (item->metadata != NULL)
+ g_hash_table_unref(item->metadata);
+
g_free(item->path);
g_free(item->name);
g_free(item);
@@ -1438,6 +1442,37 @@ static gboolean get_folder_type(const GDBusPropertyTable *property,
return TRUE;
}
+static gboolean metadata_exists(const GDBusPropertyTable *property, void *data)
+{
+ struct media_item *item = data;
+
+ return item->metadata != NULL;
+}
+
+static gboolean get_metadata(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_item *item = data;
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &dict);
+
+ if (g_hash_table_size(item->metadata) > 0)
+ g_hash_table_foreach(item->metadata, append_metadata, &dict);
+ else if (item->name != NULL)
+ dict_append_entry(&dict, "Title", DBUS_TYPE_STRING,
+ &item->name);
+
+ dbus_message_iter_close_container(iter, &dict);
+
+ return TRUE;
+}
+
static const GDBusMethodTable media_item_methods[] = {
{ GDBUS_EXPERIMENTAL_METHOD("Play", NULL, NULL,
media_item_play) },
@@ -1455,6 +1490,8 @@ static const GDBusPropertyTable media_item_properties[] = {
G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
{ "Playable", "b", get_playable, NULL, NULL,
G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+ { "Metadata", "a{sv}", get_metadata, NULL, metadata_exists,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
{ }
};
@@ -1513,8 +1550,11 @@ struct media_item *media_player_create_item(struct media_player *mp,
return NULL;
}
- if (type != PLAYER_ITEM_TYPE_FOLDER)
+ if (type != PLAYER_ITEM_TYPE_FOLDER) {
folder->items = g_slist_prepend(folder->items, item);
+ item->metadata = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+ }
DBG("%s", item->path);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 08/13] AVRCP: Add support for ChangePath command
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (6 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 07/13] player: Add support for MediaItem.Metadata property Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 09/13] player: Add implementation of MediaFolder.ChangeFolder Luiz Augusto von Dentz
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds support for ChangePath command via player callback.
---
profiles/audio/avrcp.c | 77 +++++++++++++++++++++++++++++++++++++++++++++----
profiles/audio/player.h | 2 ++
2 files changed, 73 insertions(+), 6 deletions(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index c141d24..e44ab3c 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -101,8 +101,9 @@
#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_CHANGE_PATH 0x72
+#define AVRCP_GET_ITEM_ATTRIBUTES 0x73
#define AVRCP_GENERAL_REJECT 0xA0
/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
@@ -192,8 +193,10 @@ struct avrcp_player {
uint16_t uid_counter;
bool browsed;
uint8_t *features;
+ char *path;
struct pending_list_items *p;
+ char *change_path;
struct avrcp_player_cb *cb;
void *user_data;
@@ -2187,6 +2190,32 @@ static void avrcp_list_items(struct avrcp *session, uint32_t start,
avrcp_list_items_rsp, session);
}
+static gboolean avrcp_change_path_rsp(struct avctp *conn,
+ uint8_t *operands, size_t operand_count,
+ void *user_data)
+{
+ struct avrcp_browsing_header *pdu = (void *)operands;
+ struct avrcp *session = (void *)user_data;
+ struct avrcp_player *player = session->player;
+ struct media_player *mp = player->user_data;
+ uint8_t status;
+ uint32_t num_of_items;
+
+ status = pdu->params[0];
+ if (status != AVRCP_STATUS_SUCCESS)
+ return FALSE;
+
+ num_of_items = bt_get_be32(&pdu->params[1]);
+
+ g_free(player->path);
+ player->path = player->change_path;
+ player->change_path = NULL;
+
+ media_player_set_folder(mp, player->path, num_of_items);
+
+ return FALSE;
+}
+
static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
uint8_t *operands,
size_t operand_count,
@@ -2197,7 +2226,7 @@ static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
struct media_player *mp = player->user_data;
struct avrcp_browsing_header *pdu = (void *) operands;
uint32_t items;
- char **folders, *path;
+ char **folders;
uint8_t depth, count;
size_t i;
@@ -2229,12 +2258,10 @@ static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
i += len;
}
- path = g_build_pathv("/", folders);
+ player->path = g_build_pathv("/", folders);
g_strfreev(folders);
- media_player_set_folder(mp, path, items);
-
- g_free(path);
+ media_player_set_folder(mp, player->path, items);
return FALSE;
}
@@ -2471,6 +2498,41 @@ static int ct_list_items(struct media_player *mp, const char *name,
return 0;
}
+static void avrcp_change_path(struct avrcp *session, uint8_t direction,
+ uint64_t uid)
+{
+ struct avrcp_player *player = session->player;
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 11];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+ bt_put_be16(player->uid_counter, &pdu->params[0]);
+ pdu->params[2] = direction;
+ bt_put_be64(uid, &pdu->params[3]);
+ pdu->pdu_id = AVRCP_CHANGE_PATH;
+ pdu->param_len = htons(11);
+
+ avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+ avrcp_change_path_rsp, session);
+}
+
+static int ct_change_folder(struct media_player *mp, const char *path,
+ uint64_t uid, void *user_data)
+{
+ struct avrcp_player *player = user_data;
+ struct avrcp *session;
+ uint8_t direction;
+
+ session = player->sessions->data;
+ player->change_path = g_strdup(path);
+
+ direction = g_str_has_prefix(path, player->path) ? 0x01 : 0x00;
+
+ avrcp_change_path(session, direction, uid);
+
+ return 0;
+}
+
static const struct media_player_callback ct_cbs = {
.set_setting = ct_set_setting,
.play = ct_play,
@@ -2481,6 +2543,7 @@ static const struct media_player_callback ct_cbs = {
.fast_forward = ct_fast_forward,
.rewind = ct_rewind,
.list_items = ct_list_items,
+ .change_folder = ct_change_folder,
};
static struct avrcp_player *create_ct_player(struct avrcp *session,
@@ -2593,6 +2656,8 @@ static void player_destroy(gpointer data)
player->destroy(player->user_data);
g_slist_free(player->sessions);
+ g_free(player->path);
+ g_free(player->change_path);
g_free(player->features);
g_free(player);
}
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index 4e15c36..75ce36b 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -56,6 +56,8 @@ struct media_player_callback {
int (*rewind) (struct media_player *mp, void *user_data);
int (*list_items) (struct media_player *mp, const char *name,
uint32_t start, uint32_t end, void *user_data);
+ int (*change_folder) (struct media_player *mp, const char *path,
+ uint64_t uid, void *user_data);
};
struct media_player *media_player_controller_create(const char *path,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 09/13] player: Add implementation of MediaFolder.ChangeFolder
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (7 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 08/13] AVRCP: Add support for ChangePath command Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 10/13] AVRCP: Add support for PlayItem command Luiz Augusto von Dentz
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
profiles/audio/player.c | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index deae112..371487c 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -856,7 +856,42 @@ static struct media_folder *media_player_find_folder(struct media_player *mp,
static DBusMessage *media_folder_change_folder(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- return btd_error_failed(msg, strerror(ENOTSUP));
+ struct media_player *mp = data;
+ struct media_folder *folder = mp->scope;
+ struct player_callback *cb = mp->cb;
+ const char *path;
+ int err;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_failed(msg, strerror(EINVAL));
+
+ if (folder->msg != NULL)
+ return btd_error_failed(msg, strerror(EINVAL));
+
+ folder = media_player_find_folder(mp, path);
+ if (folder == NULL)
+ return btd_error_failed(msg, strerror(EINVAL));
+
+ if (mp->scope == folder)
+ goto done;
+
+ if (folder == mp->playlist || folder == mp->folder) {
+ media_player_change_scope(mp, folder);
+ goto done;
+ }
+
+ if (cb->cbs->change_folder == NULL)
+ return btd_error_failed(msg, strerror(ENOTSUP));
+
+ err = cb->cbs->change_folder(mp, folder->item->name, folder->item->uid,
+ cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+done:
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
static gboolean folder_name_exists(const GDBusPropertyTable *property,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 10/13] AVRCP: Add support for PlayItem command
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (8 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 09/13] player: Add implementation of MediaFolder.ChangeFolder Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 11/13] player: Add implementation of MediaItem.Play Luiz Augusto von Dentz
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds support for PlayItem command via player callback.
---
profiles/audio/avrcp.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
profiles/audio/player.h | 2 ++
2 files changed, 50 insertions(+)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index e44ab3c..e9e2645 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -104,6 +104,7 @@
#define AVRCP_GET_FOLDER_ITEMS 0x71
#define AVRCP_CHANGE_PATH 0x72
#define AVRCP_GET_ITEM_ATTRIBUTES 0x73
+#define AVRCP_PLAY_ITEM 0x74
#define AVRCP_GENERAL_REJECT 0xA0
/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
@@ -2533,6 +2534,52 @@ static int ct_change_folder(struct media_player *mp, const char *path,
return 0;
}
+static void avrcp_play_item(struct avrcp *session, uint64_t uid)
+{
+ uint8_t buf[AVRCP_HEADER_LENGTH + 11];
+ struct avrcp_player *player = session->player;
+ struct avrcp_header *pdu = (void *) buf;
+ uint16_t length;
+
+ memset(buf, 0, sizeof(buf));
+
+ set_company_id(pdu->company_id, IEEEID_BTSIG);
+ pdu->pdu_id = AVRCP_PLAY_ITEM;
+ pdu->params_len = htons(11);
+ pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+ pdu->params[0] = player->scope;
+ bt_put_be64(uid, &pdu->params[1]);
+ bt_put_be16(player->uid_counter, &pdu->params[9]);
+
+ length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+ avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+ AVC_SUBUNIT_PANEL, buf, length,
+ NULL, session);
+}
+
+static int ct_play_item(struct media_player *mp, const char *name,
+ uint64_t uid, void *user_data)
+{
+ struct avrcp_player *player = user_data;
+ struct avrcp *session;
+
+ if (player->p != NULL)
+ return -EBUSY;
+
+ session = player->sessions->data;
+
+ if (g_strrstr(name, "/NowPlaying"))
+ player->scope = 0x03;
+ else
+ player->scope = 0x01;
+
+ avrcp_play_item(session, uid);
+
+ return 0;
+}
+
static const struct media_player_callback ct_cbs = {
.set_setting = ct_set_setting,
.play = ct_play,
@@ -2544,6 +2591,7 @@ static const struct media_player_callback ct_cbs = {
.rewind = ct_rewind,
.list_items = ct_list_items,
.change_folder = ct_change_folder,
+ .play_item = ct_play_item,
};
static struct avrcp_player *create_ct_player(struct avrcp *session,
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index 75ce36b..a8732f5 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -58,6 +58,8 @@ struct media_player_callback {
uint32_t start, uint32_t end, void *user_data);
int (*change_folder) (struct media_player *mp, const char *path,
uint64_t uid, void *user_data);
+ int (*play_item) (struct media_player *mp, const char *name,
+ uint64_t uid, void *user_data);
};
struct media_player *media_player_controller_create(const char *path,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 11/13] player: Add implementation of MediaItem.Play
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (9 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 10/13] AVRCP: Add support for PlayItem command Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 12/13] AVRCP: Add support for AddToNowPlaying command Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 13/13] player: Add implementation of MediaItem.AddToNowPlaying Luiz Augusto von Dentz
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
profiles/audio/player.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index 371487c..a34757a 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -1354,7 +1354,22 @@ void media_player_set_playlist_item(struct media_player *mp, uint64_t uid)
static DBusMessage *media_item_play(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- return btd_error_failed(msg, strerror(ENOTSUP));
+ struct media_item *item = data;
+ struct media_player *mp = item->player;
+ struct player_callback *cb = mp->cb;
+ int err;
+
+ if (!item->playable)
+ return btd_error_failed(msg, strerror(ENOTSUP));
+
+ if (cb->cbs->play_item == NULL)
+ return btd_error_failed(msg, strerror(ENOTSUP));
+
+ err = cb->cbs->play_item(mp, item->path, item->uid, cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
static DBusMessage *media_item_add_to_nowplaying(DBusConnection *conn,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 12/13] AVRCP: Add support for AddToNowPlaying command
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (10 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 11/13] player: Add implementation of MediaItem.Play Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 13/13] player: Add implementation of MediaItem.AddToNowPlaying Luiz Augusto von Dentz
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds support for AddToNowPlaying command via player callback.
---
profiles/audio/avrcp.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
profiles/audio/player.h | 2 ++
2 files changed, 50 insertions(+)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index e9e2645..234cd3a 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -105,6 +105,7 @@
#define AVRCP_CHANGE_PATH 0x72
#define AVRCP_GET_ITEM_ATTRIBUTES 0x73
#define AVRCP_PLAY_ITEM 0x74
+#define AVRCP_ADD_TO_NOW_PLAYING 0x90
#define AVRCP_GENERAL_REJECT 0xA0
/* Capabilities for AVRCP_GET_CAPABILITIES pdu */
@@ -2580,6 +2581,52 @@ static int ct_play_item(struct media_player *mp, const char *name,
return 0;
}
+static void avrcp_add_to_nowplaying(struct avrcp *session, uint64_t uid)
+{
+ uint8_t buf[AVRCP_HEADER_LENGTH + 11];
+ struct avrcp_player *player = session->player;
+ struct avrcp_header *pdu = (void *) buf;
+ uint16_t length;
+
+ memset(buf, 0, sizeof(buf));
+
+ set_company_id(pdu->company_id, IEEEID_BTSIG);
+ pdu->pdu_id = AVRCP_ADD_TO_NOW_PLAYING;
+ pdu->params_len = htons(11);
+ pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+ pdu->params[0] = player->scope;
+ bt_put_be64(uid, &pdu->params[1]);
+ bt_put_be16(player->uid_counter, &pdu->params[9]);
+
+ length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+ avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+ AVC_SUBUNIT_PANEL, buf, length,
+ NULL, session);
+}
+
+static int ct_add_to_nowplaying(struct media_player *mp, const char *name,
+ uint64_t uid, void *user_data)
+{
+ struct avrcp_player *player = user_data;
+ struct avrcp *session;
+
+ if (player->p != NULL)
+ return -EBUSY;
+
+ session = player->sessions->data;
+
+ if (g_strrstr(name, "/NowPlaying"))
+ player->scope = 0x03;
+ else
+ player->scope = 0x01;
+
+ avrcp_add_to_nowplaying(session, uid);
+
+ return 0;
+}
+
static const struct media_player_callback ct_cbs = {
.set_setting = ct_set_setting,
.play = ct_play,
@@ -2592,6 +2639,7 @@ static const struct media_player_callback ct_cbs = {
.list_items = ct_list_items,
.change_folder = ct_change_folder,
.play_item = ct_play_item,
+ .add_to_nowplaying = ct_add_to_nowplaying,
};
static struct avrcp_player *create_ct_player(struct avrcp *session,
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index a8732f5..259110f 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -60,6 +60,8 @@ struct media_player_callback {
uint64_t uid, void *user_data);
int (*play_item) (struct media_player *mp, const char *name,
uint64_t uid, void *user_data);
+ int (*add_to_nowplaying) (struct media_player *mp, const char *name,
+ uint64_t uid, void *user_data);
};
struct media_player *media_player_controller_create(const char *path,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH BlueZ v2 13/13] player: Add implementation of MediaItem.AddToNowPlaying
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
` (11 preceding siblings ...)
2013-05-28 12:51 ` [PATCH BlueZ v2 12/13] AVRCP: Add support for AddToNowPlaying command Luiz Augusto von Dentz
@ 2013-05-28 12:51 ` Luiz Augusto von Dentz
12 siblings, 0 replies; 14+ messages in thread
From: Luiz Augusto von Dentz @ 2013-05-28 12:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
profiles/audio/player.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index a34757a..57753b3 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -1375,7 +1375,23 @@ static DBusMessage *media_item_play(DBusConnection *conn, DBusMessage *msg,
static DBusMessage *media_item_add_to_nowplaying(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- return btd_error_failed(msg, strerror(ENOTSUP));
+ struct media_item *item = data;
+ struct media_player *mp = item->player;
+ struct player_callback *cb = mp->cb;
+ int err;
+
+ if (!item->playable)
+ return btd_error_failed(msg, strerror(ENOTSUP));
+
+ if (cb->cbs->play_item == NULL)
+ return btd_error_failed(msg, strerror(ENOTSUP));
+
+ err = cb->cbs->add_to_nowplaying(mp, item->path, item->uid,
+ cb->user_data);
+ if (err < 0)
+ return btd_error_failed(msg, strerror(-err));
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
static gboolean item_name_exists(const GDBusPropertyTable *property,
--
1.8.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-05-28 12:51 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-28 12:51 [PATCH BlueZ v2 00/13] MediaFolder and MediaItem implementation Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 01/13] player: Split item creation Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 02/13] AVRCP: Add browsed flag to player Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 03/13] AVRCP: Add support for GetFolderItems command Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 04/13] player: Add implementation of MediaFolder.ListItems Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 05/13] player: Add support for setting current Item object Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 06/13] player: Add function media_item_set_playable Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 07/13] player: Add support for MediaItem.Metadata property Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 08/13] AVRCP: Add support for ChangePath command Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 09/13] player: Add implementation of MediaFolder.ChangeFolder Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 10/13] AVRCP: Add support for PlayItem command Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 11/13] player: Add implementation of MediaItem.Play Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 12/13] AVRCP: Add support for AddToNowPlaying command Luiz Augusto von Dentz
2013-05-28 12:51 ` [PATCH BlueZ v2 13/13] player: Add implementation of MediaItem.AddToNowPlaying Luiz Augusto von Dentz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).