[PATCH v4 05/22] avrcp: implement ChangeTrack() method

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ChangeTrack() is used by applications to inform bluetoothd that current
track changed, passing also the metadata.
---
 audio/control.c |  163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/audio/control.c b/audio/control.c
index cb9dd76..7fe4af5 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -226,6 +226,13 @@ struct avctp_server {
 };
 
 struct media_info {
+	char *title;
+	char *artist;
+	char *album;
+	char *genre;
+	uint32_t ntracks;
+	uint32_t track;
+	uint32_t track_len;
 	uint32_t elapsed;
 };
 
@@ -582,6 +589,41 @@ static void mp_set_attribute(struct media_player *mp,
 	mp->settings[attr] = val;
 }
 
+static void mp_set_media_attributes(struct control *control,
+							struct media_info *mi)
+{
+	struct media_player *mp = control->mp;
+
+	g_free(mp->mi.title);
+	mp->mi.title = g_strdup(mi->title);
+
+	g_free(mp->mi.artist);
+	mp->mi.artist = g_strdup(mi->artist);
+
+	g_free(mp->mi.album);
+	mp->mi.album = g_strdup(mi->album);
+
+	g_free(mp->mi.genre);
+	mp->mi.genre = g_strdup(mi->genre);
+
+	mp->mi.ntracks = mi->ntracks;
+	mp->mi.track = mi->track;
+	mp->mi.track_len = mi->track_len;
+
+	/*
+	 * elapsed is special. Whenever the track changes, we reset it to 0,
+	 * so client doesn't have to make another call to change_playback
+	 */
+	mp->mi.elapsed = 0;
+	g_timer_start(mp->timer);
+
+	DBG("Track changed:\n\ttitle: %s\n\tartist: %s\n\talbum: %s\n"
+			   "\tgenre: %s\n\tNumber of tracks: %u\n"
+			   "\tTrack number: %u\n\tTrack duration: %u",
+			   mi->title, mi->artist, mi->album, mi->genre,
+			   mi->ntracks, mi->track, mi->track_len);
+}
+
 /* handle vendordep pdu inside an avctp packet */
 static int handle_vendordep_pdu(struct control *control,
 					struct avrcp_header *avrcp,
@@ -864,6 +906,19 @@ static void init_uinput(struct control *control)
 		DBG("AVRCP: uinput initialized for %s", address);
 }
 
+static void media_info_init(struct media_info *mi)
+{
+	memset(mi, 0, sizeof(*mi));
+
+	/*
+	 * As per section 5.4.1 of AVRCP 1.3 spec, return 0xFFFFFFFF if TG
+	 * does not support these attributes (i.e. they were never set via
+	 * D-Bus)
+	 */
+	mi->track_len = 0xFFFFFFFF;
+	mi->elapsed = 0xFFFFFFFF;
+}
+
 static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
 {
 	struct control *control = data;
@@ -1355,9 +1410,116 @@ static DBusMessage *mp_change_playback(DBusConnection *conn,
 	return dbus_message_new_method_return(msg);
 }
 
+static gboolean media_info_parse(DBusMessageIter *iter, struct media_info *mi)
+{
+	DBusMessageIter dict;
+	DBusMessageIter var;
+	int ctype;
+
+	ctype = dbus_message_iter_get_arg_type(iter);
+	if (ctype != DBUS_TYPE_ARRAY)
+		return FALSE;
+
+	media_info_init(mi);
+	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 FALSE;
+
+		dbus_message_iter_recurse(&dict, &entry);
+		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+			return FALSE;
+
+		dbus_message_iter_get_basic(&entry, &key);
+		dbus_message_iter_next(&entry);
+
+		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+			return FALSE;
+
+		dbus_message_iter_recurse(&entry, &var);
+
+		if (!strcmp(key, "Title")) {
+			if (dbus_message_iter_get_arg_type(&var) !=
+							DBUS_TYPE_STRING)
+				return FALSE;
+
+			dbus_message_iter_get_basic(&var, &mi->title);
+		} else if (!strcmp(key, "Artist")) {
+			if (dbus_message_iter_get_arg_type(&var) !=
+							DBUS_TYPE_STRING)
+				return FALSE;
+
+			dbus_message_iter_get_basic(&var, &mi->artist);
+		} else if (!strcmp(key, "Album")) {
+			if (dbus_message_iter_get_arg_type(&var) !=
+							DBUS_TYPE_STRING)
+				return FALSE;
+
+			dbus_message_iter_get_basic(&var, &mi->album);
+		} else if (!strcmp(key, "Genre")) {
+			if (dbus_message_iter_get_arg_type(&var) !=
+							DBUS_TYPE_STRING)
+				return FALSE;
+
+			dbus_message_iter_get_basic(&var, &mi->genre);
+		} else if (!strcmp(key, "NumberOfTracks")) {
+			if (dbus_message_iter_get_arg_type(&var) !=
+							DBUS_TYPE_UINT32)
+				return FALSE;
+
+			dbus_message_iter_get_basic(&var, &mi->ntracks);
+		} else if (!strcmp(key, "TrackNumber")) {
+			if (dbus_message_iter_get_arg_type(&var) !=
+							DBUS_TYPE_UINT32)
+				return FALSE;
+
+			dbus_message_iter_get_basic(&var, &mi->track);
+		} else if (!strcmp(key, "TrackDuration")) {
+			if (dbus_message_iter_get_arg_type(&var) !=
+							DBUS_TYPE_UINT32)
+				return FALSE;
+
+			dbus_message_iter_get_basic(&var, &mi->track_len);
+		} else {
+			return FALSE;
+		}
+
+		dbus_message_iter_next(&dict);
+	}
+
+	if (mi->title == NULL)
+		return FALSE;
+
+	return TRUE;
+}
+
+static DBusMessage *mp_change_track(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	struct audio_device *device = data;
+	struct control *control = device->control;
+	DBusMessageIter iter;
+	struct media_info mi;
+
+
+	dbus_message_iter_init(msg, &iter);
+	if (!media_info_parse(&iter, &mi))
+		return btd_error_invalid_args(msg);
+
+	mp_set_media_attributes(control, &mi);
+
+	return dbus_message_new_method_return(msg);
+}
+
 static GDBusMethodTable mp_methods[] = {
 	{ "SetProperty",	"sv",		"",	mp_set_property },
 	{ "ChangePlayback",	"su",		"",	mp_change_playback },
+	{ "ChangeTrack",	"a{sv}",	"",	mp_change_track },
 	{ }
 };
 
@@ -1434,6 +1596,7 @@ static void mp_register(struct control *control)
 					MEDIA_PLAYER_INTERFACE, dev->path);
 
 	mp->timer = g_timer_new();
+	media_info_init(&mp->mi);
 	control->mp = mp;
 }
 
-- 
1.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux