diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index e6d0e72..3d54fbe 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
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)
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
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 {
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 */
{
struct media_player *mp = data;
- return mp->folder != NULL;
+ return mp->scope != NULL;
}
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");
{
struct media_player *mp = data;
- return mp->folder != NULL;
+ return mp->scope != NULL;
}
static gboolean get_searchable(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;
}
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)
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;
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;
{
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;
{ }
};
-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)
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);
"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,
{ }
};
-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;
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
} player_folder_type_t;
struct media_player;
+struct media_item;
struct media_player_callback {
bool (*set_setting) (struct media_player *mp, const char *key,
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,