Diff between d2e642c78ad20d466f1cf7d04fd4c18f54153fa5 and 0a232a434d4b4da14c5d6b975ac1b55dc7ec92bb

Changed Files

File Additions Deletions Status
profiles/audio/avrcp.c +17 -3 modified
profiles/audio/player.c +95 -24 modified
profiles/audio/player.h +1 -0 modified

Full Patch

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index b198f7b..14cdece 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -2588,6 +2588,8 @@ static int ct_list_items(struct media_player *mp, const char *name,
 
 	if (g_str_has_prefix(name, "/NowPlaying"))
 		player->scope = 0x03;
+	else if (g_str_has_suffix(name, "/search"))
+		player->scope = 0x02;
 	else
 		player->scope = 0x01;
 
@@ -2642,12 +2644,24 @@ static gboolean avrcp_search_rsp(struct avctp *conn, uint8_t *operands,
 	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;
+	int ret;
 
-	if (pdu == NULL || pdu->params[0] != AVRCP_STATUS_SUCCESS ||
-							operand_count < 7)
-		return FALSE;
+	if (pdu == NULL) {
+		ret = -ETIMEDOUT;
+		goto done;
+	}
+
+	if (pdu->params[0] != AVRCP_STATUS_SUCCESS || operand_count < 7) {
+		ret = -EINVAL;
+		goto done;
+	}
 
 	player->uid_counter = bt_get_be16(&pdu->params[1]);
+	ret = bt_get_be32(&pdu->params[3]);
+
+done:
+	media_player_search_complete(mp, ret);
 
 	return FALSE;
 }
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
index 701d366..cd05313 100644
--- a/profiles/audio/player.c
+++ b/profiles/audio/player.c
@@ -87,6 +87,7 @@ struct media_player {
 	bool			searchable;	/* Player searching feature */
 	struct media_folder	*scope;		/* Player current scope */
 	struct media_folder	*folder;	/* Player current folder */
+	struct media_folder	*search;	/* Player search folder */
 	struct media_folder	*playlist;	/* Player current playlist */
 	char			*path;		/* Player object path */
 	GHashTable		*settings;	/* Player settings */
@@ -654,6 +655,58 @@ done:
 	folder->msg = NULL;
 }
 
+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;
+
+	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;
+}
+
+void media_player_search_complete(struct media_player *mp, int ret)
+{
+	struct media_folder *folder = mp->scope;
+	struct media_folder *search = mp->search;
+	DBusMessage *reply;
+
+	if (folder == NULL || folder->msg == NULL)
+		return;
+
+	if (ret < 0) {
+		reply = btd_error_failed(folder->msg, strerror(-ret));
+		goto done;
+	}
+
+	if (search == NULL) {
+		search = g_new0(struct media_folder, 1);
+		search->item = media_player_create_subfolder(mp, "search", 0);
+		mp->search = search;
+		mp->folders = g_slist_prepend(mp->folders, search);
+	}
+
+	search->number_of_items = ret;
+
+	reply = g_dbus_create_reply(folder->msg,
+				DBUS_TYPE_OBJECT_PATH, &search->item->path,
+				DBUS_TYPE_INVALID);
+
+done:
+	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) },
@@ -707,7 +760,36 @@ static const GDBusPropertyTable media_player_properties[] = {
 static DBusMessage *media_folder_search(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;
+	const char *string;
+	int err;
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return btd_error_failed(msg, strerror(EINVAL));
+
+	dbus_message_iter_get_basic(&iter, &string);
+
+	if (!mp->searchable || folder != mp->folder)
+		return btd_error_failed(msg, strerror(ENOTSUP));
+
+	if (folder->msg != NULL)
+		return btd_error_failed(msg, strerror(EINVAL));
+
+	if (cb->cbs->search == NULL)
+		return btd_error_failed(msg, strerror(ENOTSUP));
+
+	err = cb->cbs->search(mp, string, cb->user_data);
+	if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
+	folder->msg = dbus_message_ref(msg);
+
+	return NULL;
 }
 
 static int parse_filters(struct media_player *player, DBusMessageIter *iter,
@@ -838,8 +920,8 @@ static void media_player_change_scope(struct media_player *mp,
 
 	DBG("%s", folder->item->name);
 
-	/* Skip setting current folder if folder is current playlist */
-	if (folder == mp->playlist)
+	/* Skip setting current folder if folder is current playlist/search */
+	if (folder == mp->playlist || folder == mp->search)
 		goto cleanup;
 
 	mp->folder = folder;
@@ -852,6 +934,13 @@ cleanup:
 	g_slist_free_full(mp->scope->items, media_item_destroy);
 	mp->scope->items = NULL;
 
+	/* Destroy search folder if it exists and is not being set as scope */
+	if (mp->search != NULL && folder != mp->search) {
+		mp->folders = g_slist_remove(mp->folders, mp->search);
+		media_folder_destroy(mp->search);
+		mp->search = NULL;
+	}
+
 done:
 	mp->scope = folder;
 
@@ -912,7 +1001,8 @@ static DBusMessage *media_folder_change_folder(DBusConnection *conn,
 	if (mp->scope == folder)
 		return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 
-	if (folder == mp->playlist || folder == mp->folder) {
+	if (folder == mp->playlist || folder == mp->folder ||
+						folder == mp->search) {
 		media_player_change_scope(mp, folder);
 		return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 	}
@@ -984,7 +1074,7 @@ static gboolean get_items(const GDBusPropertyTable *property,
 }
 
 static const GDBusMethodTable media_folder_methods[] = {
-	{ GDBUS_EXPERIMENTAL_METHOD("Search",
+	{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("Search",
 			GDBUS_ARGS({ "string", "s" }, { "filter", "a{sv}" }),
 			GDBUS_ARGS({ "folder", "o" }),
 			media_folder_search) },
@@ -1660,25 +1750,6 @@ struct media_item *media_player_create_item(struct media_player *mp,
 	return item;
 }
 
-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;
-
-	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)
 {
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
index eecab1b..9edc51b 100644
--- a/profiles/audio/player.h
+++ b/profiles/audio/player.h
@@ -101,6 +101,7 @@ void media_player_list_complete(struct media_player *mp, GSList *items,
 								int err);
 void media_player_change_folder_complete(struct media_player *player,
 						const char *path, int ret);
+void media_player_search_complete(struct media_player *mp, int ret);
 
 void media_player_set_callbacks(struct media_player *mp,
 				const struct media_player_callback *cbs,