* [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface
@ 2013-01-24 9:57 Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 2/6 v2] tools: Add support for setting Shuffle and LoopStatus to mpris-player Luiz Augusto von Dentz
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2013-01-24 9:57 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Players found are exported in private connections using
org.mpris.MediaPlayer2.<device name> on the session bus.
---
v2: Fix generating invalid player bus name if device name contains invalid
chars.
tools/mpris-player.c | 644 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 623 insertions(+), 21 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 246791a..d58e53f 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -32,6 +32,7 @@
#include <signal.h>
#include <getopt.h>
#include <string.h>
+#include <inttypes.h>
#include <dbus/dbus.h>
#include <glib.h>
@@ -41,13 +42,29 @@
#define BLUEZ_PATH "/org/bluez"
#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
+#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
#define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
+#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
static GMainLoop *main_loop;
static GDBusProxy *adapter = NULL;
static DBusConnection *sys = NULL;
static DBusConnection *session = NULL;
+static GDBusClient *client = NULL;
+static GSList *players = NULL;
+
+struct player {
+ char *name;
+ char *bus_name;
+ DBusConnection *conn;
+ GDBusProxy *proxy;
+ GDBusProxy *device;
+};
+
+typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata);
static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
void *val);
@@ -190,7 +207,8 @@ static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
return 0;
}
-static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
+static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata,
+ parse_metadata_func func)
{
DBusMessageIter dict;
int ctype;
@@ -216,7 +234,7 @@ static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
dbus_message_iter_get_basic(&entry, &key);
dbus_message_iter_next(&entry);
- if (parse_metadata_entry(&entry, key, metadata) < 0)
+ if (func(&entry, key, metadata) < 0)
return -EINVAL;
dbus_message_iter_next(&dict);
@@ -225,7 +243,8 @@ static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
return 0;
}
-static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict)
+static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict,
+ parse_metadata_func func)
{
DBusMessageIter value, metadata;
@@ -237,7 +256,7 @@ static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict)
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
- parse_metadata(dict, &metadata);
+ parse_metadata(dict, &metadata, func);
dbus_message_iter_close_container(&value, &metadata);
dbus_message_iter_close_container(iter, &value);
@@ -260,7 +279,7 @@ static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
if (strcasecmp(key, "Metadata") == 0)
- append_metadata(&entry, val);
+ append_metadata(&entry, val, parse_metadata_entry);
else
append_variant(&entry, type, val);
@@ -509,21 +528,29 @@ done:
static void remove_player(DBusConnection *conn, const char *sender)
{
DBusMessage *msg;
- char *path;
+ char *path, *owner;
if (!adapter)
return;
+ path = sender2path(sender);
+ dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+ if (owner == NULL) {
+ g_free(path);
+ return;
+ }
+
msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
g_dbus_proxy_get_path(adapter),
BLUEZ_MEDIA_INTERFACE,
"UnregisterPlayer");
if (!msg) {
fprintf(stderr, "Can't allocate new method call\n");
+ g_free(path);
return;
}
- path = sender2path(sender);
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
@@ -540,10 +567,16 @@ static gboolean properties_changed(DBusConnection *conn,
{
DBusMessageIter iter;
const char *iface;
- char *path;
+ char *path, *owner;
dbus_message_iter_init(msg, &iter);
+ path = sender2path(dbus_message_get_sender(msg));
+ dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+ if (owner == NULL)
+ goto done;
+
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -553,14 +586,28 @@ static gboolean properties_changed(DBusConnection *conn,
dbus_message_iter_next(&iter);
- path = sender2path(dbus_message_get_sender(msg));
parse_properties(conn, path, &iter, NULL);
+done:
g_free(path);
return TRUE;
}
+static struct player *find_player_by_bus_name(const char *name)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (strcmp(player->bus_name, name) == 0)
+ return player;
+ }
+
+ return NULL;
+}
+
static gboolean name_owner_changed(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -581,7 +628,7 @@ static gboolean name_owner_changed(DBusConnection *conn,
if (*new == '\0') {
printf("player %s at %s disappear\n", name, old);
remove_player(conn, old);
- } else {
+ } else if (find_player_by_bus_name(name) == NULL) {
printf("player %s at %s found\n", name, new);
add_player(conn, name, new);
}
@@ -733,23 +780,570 @@ static void disconnect_handler(DBusConnection *connection, void *user_data)
printf("org.bluez disappeared\n");
}
-static void proxy_added(GDBusProxy *proxy, void *user_data)
+static void player_free(void *data)
{
- const char *interface;
+ struct player *player = data;
+
+ if (player->conn) {
+ dbus_connection_close(player->conn);
+ dbus_connection_unref(player->conn);
+ }
+
+ g_dbus_proxy_unref(player->device);
+ g_dbus_proxy_unref(player->proxy);
+
+ g_free(player->name);
+ g_free(player->bus_name);
+ g_free(player);
+}
+
+struct pending_call {
+ struct player *player;
+ DBusMessage *msg;
+};
+
+static void pending_call_free(void *data)
+{
+ struct pending_call *p = data;
+
+ if (p->msg)
+ dbus_message_unref(p->msg);
+
+ g_free(p);
+}
+
+static void player_reply(DBusMessage *message, void *user_data)
+{
+ struct pending_call *p = user_data;
+ struct player *player = p->player;
+ DBusMessage *msg = p->msg;
+ DBusMessage *reply;
+ DBusError err;
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, message)) {
+ fprintf(stderr, "error: %s", err.name);
+ reply = g_dbus_create_error(msg, err.name, err.message);
+ dbus_error_free(&err);
+ } else
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+ g_dbus_send_message(player->conn, reply);
+}
+
+static void player_control(struct player *player, DBusMessage *msg,
+ const char *name)
+{
+ struct pending_call *p;
+
+ p = g_new0(struct pending_call, 1);
+ p->player = player;
+ p->msg = dbus_message_ref(msg);
+
+ g_dbus_proxy_method_call(player->proxy, name, NULL, player_reply,
+ p, pending_call_free);
+}
+
+static DBusMessage *player_toggle(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Status", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ if (strcasecmp(status, "Playing") == 0)
+ player_control(player, msg, "Pause");
+ else
+ player_control(player, msg, "Play");
+
+ return NULL;
+}
+
+static DBusMessage *player_play(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Play");
+
+ return NULL;
+}
+
+static DBusMessage *player_pause(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Pause");
+
+ return NULL;
+}
+
+static DBusMessage *player_stop(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Stop");
+
+ return NULL;
+}
+
+static DBusMessage *player_next(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Next");
+
+ return NULL;
+}
+
+static DBusMessage *player_previous(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct player *player = data;
+
+ player_control(player, msg, "Previous");
+
+ return NULL;
+}
+
+static gboolean status_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Status", &iter);
+}
+
+static const char *status_to_playback(const char *status)
+{
+ if (strcasecmp(status, "playing") == 0)
+ return "Playing";
+ else if (strcasecmp(status, "paused") == 0)
+ return "Paused";
+ else
+ return "Stopped";
+}
+
+static gboolean get_status(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Status", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ status = status_to_playback(status);
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+ return TRUE;
+}
+
+static gboolean repeat_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Repeat", &iter);
+}
+
+static const char *repeat_to_loopstatus(const char *value)
+{
+ if (strcasecmp(value, "off") == 0)
+ return "None";
+ else if (strcasecmp(value, "singletrack") == 0)
+ return "Track";
+ else if (strcasecmp(value, "alltracks") == 0)
+ return "Playlist";
+
+ return NULL;
+}
+
+static gboolean get_repeat(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *status;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Repeat", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &status);
+
+ status = repeat_to_loopstatus(status);
+ if (status == NULL)
+ return FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+ return TRUE;
+}
+
+static gboolean get_double(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ double value = 1.0;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+ return TRUE;
+}
+
+static gboolean shuffle_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Shuffle", &iter);
+}
+
+static gboolean get_shuffle(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter value;
+ const char *string;
+ dbus_bool_t shuffle;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Shuffle", &value))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value, &string);
+
+ shuffle = strcmp(string, "off") != 0;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &shuffle);
+
+ return TRUE;
+}
+
+static gboolean position_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Position", &iter);
+}
- if (adapter != NULL)
+static gboolean get_position(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter var;
+ uint32_t position;
+ int64_t value;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Position", &var))
+ return FALSE;
+
+ dbus_message_iter_get_basic(&var, &position);
+
+ value = position * 1000;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &value);
+
+ return TRUE;
+}
+
+static gboolean track_exists(const GDBusPropertyTable *property, void *data)
+{
+ DBusMessageIter iter;
+ struct player *player = data;
+
+ return g_dbus_proxy_get_property(player->proxy, "Track", &iter);
+}
+
+static gboolean parse_string_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ dict_append_entry(metadata, key, DBUS_TYPE_STRING, &value);
+
+ return TRUE;
+}
+
+static gboolean parse_array_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ char **value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ value = dbus_malloc0(sizeof(char *));
+
+ dbus_message_iter_get_basic(iter, &(value[0]));
+
+ dict_append_array(metadata, key, DBUS_TYPE_STRING, &value, 1);
+
+ dbus_free(value);
+
+ return TRUE;
+}
+
+static gboolean parse_int64_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ uint32_t duration;
+ int64_t value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &duration);
+
+ value = duration * 1000;
+
+ dict_append_entry(metadata, key, DBUS_TYPE_INT64, &value);
+
+ return TRUE;
+}
+
+static gboolean parse_int32_metadata(DBusMessageIter *iter, const char *key,
+ DBusMessageIter *metadata)
+{
+ uint32_t value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+ return FALSE;
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ dict_append_entry(metadata, key, DBUS_TYPE_INT32, &value);
+
+ return TRUE;
+}
+
+static int parse_track_entry(DBusMessageIter *entry, const char *key,
+ DBusMessageIter *metadata)
+{
+ DBusMessageIter var;
+
+ printf("metadata %s found\n", key);
+
+ if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+ return -EINVAL;
+
+ dbus_message_iter_recurse(entry, &var);
+
+ if (strcasecmp(key, "Title") == 0) {
+ if (!parse_string_metadata(&var, "xesam:title", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Artist") == 0) {
+ if (!parse_array_metadata(&var, "xesam:artist", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Album") == 0) {
+ if (!parse_string_metadata(&var, "xesam:album", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Genre") == 0) {
+ if (!parse_array_metadata(&var, "xesam:genre", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "Duration") == 0) {
+ if (!parse_int64_metadata(&var, "mpris:length", metadata))
+ return -EINVAL;
+ } else if (strcasecmp(key, "TrackNumber") == 0) {
+ if (!parse_int32_metadata(&var, "xesam:trackNumber", metadata))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static gboolean get_track(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ DBusMessageIter var, metadata;
+
+ if (!g_dbus_proxy_get_property(player->proxy, "Track", &var))
+ return FALSE;
+
+ 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, &metadata);
+
+ parse_metadata(&var, &metadata, parse_track_entry);
+
+ dbus_message_iter_close_container(iter, &metadata);
+
+ return TRUE;
+}
+
+static gboolean get_enable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ dbus_bool_t value = TRUE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+ return TRUE;
+}
+
+static const GDBusMethodTable player_methods[] = {
+ { GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
+ { GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
+ { GDBUS_ASYNC_METHOD("Pause", NULL, NULL, player_pause) },
+ { GDBUS_ASYNC_METHOD("Stop", NULL, NULL, player_stop) },
+ { GDBUS_ASYNC_METHOD("Next", NULL, NULL, player_next) },
+ { GDBUS_ASYNC_METHOD("Previous", NULL, NULL, player_previous) },
+ { }
+};
+
+static const GDBusSignalTable player_signals[] = {
+ { GDBUS_SIGNAL("Seeked", GDBUS_ARGS({"Position", "x"})) },
+ { }
+};
+
+static const GDBusPropertyTable player_properties[] = {
+ { "PlaybackStatus", "s", get_status, NULL, status_exists },
+ { "LoopStatus", "s", get_repeat, NULL, repeat_exists },
+ { "Rate", "d", get_double, NULL, NULL },
+ { "MinimumRate", "d", get_double, NULL, NULL },
+ { "MaximumRate", "d", get_double, NULL, NULL },
+ { "Shuffle", "b", get_shuffle, NULL, shuffle_exists },
+ { "Position", "x", get_position, NULL, position_exists },
+ { "Metadata", "a{sv}", get_track, NULL, track_exists },
+ { "Volume", "d", get_double, NULL, NULL },
+ { "CanGoNext", "b", get_enable, NULL, NULL },
+ { "CanGoPrevious", "b", get_enable, NULL, NULL },
+ { "CanPlay", "b", get_enable, NULL, NULL },
+ { "CanPause", "b", get_enable, NULL, NULL },
+ { "CanSeek", "b", get_enable, NULL, NULL },
+ { "CanControl", "b", get_enable, NULL, NULL },
+ { }
+};
+
+
+#define a_z "abcdefghijklmnopqrstuvwxyz"
+#define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define _0_9 "_0123456789"
+
+static char *mpris_busname(char *name)
+{
+ return g_strconcat(MPRIS_BUS_NAME,
+ g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
+}
+
+static void register_player(GDBusProxy *proxy)
+{
+ struct player *player;
+ DBusMessageIter iter;
+ const char *path, *name;
+ GDBusProxy *device;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+ return;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ device = g_dbus_proxy_new(client, path, "org.bluez.Device1");
+ if (device == NULL)
+ return;
+
+ if (!g_dbus_proxy_get_property(device, "Name", &iter))
return;
+ dbus_message_iter_get_basic(&iter, &name);
+
+ player = g_new0(struct player, 1);
+ player->name = g_strdup(name);
+ player->bus_name = mpris_busname(player->name);
+ player->proxy = g_dbus_proxy_ref(proxy);
+ player->device = device;
+
+ players = g_slist_prepend(players, player);
+
+ printf("Player %s created\n", player->bus_name);
+
+ player->conn = g_dbus_setup_private(DBUS_BUS_SESSION, player->bus_name,
+ NULL);
+ if (!session) {
+ fprintf(stderr, "Could not register bus name %s",
+ player->bus_name);
+ goto fail;
+ }
+
+ if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ player_methods,
+ player_signals,
+ player_properties,
+ player, player_free)) {
+ fprintf(stderr, "Could not register interface %s",
+ MPRIS_PLAYER_INTERFACE);
+ goto fail;
+ }
+
+ return;
+
+fail:
+ players = g_slist_remove(players, player);
+ player_free(player);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface;
+
interface = g_dbus_proxy_get_interface(proxy);
if (!strcmp(interface, BLUEZ_ADAPTER_INTERFACE)) {
+ if (adapter != NULL)
+ return;
+
printf("Bluetooth Adapter %s found\n",
g_dbus_proxy_get_path(proxy));
adapter = proxy;
list_names(session);
+ } else if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) {
+ printf("Bluetooth Player %s found\n",
+ g_dbus_proxy_get_path(proxy));
+ register_player(proxy);
}
}
+static void unregister_player(struct player *player)
+{
+ players = g_slist_remove(players, player);
+
+ g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE);
+}
+
+static struct player *find_player(GDBusProxy *proxy)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (player->proxy == proxy)
+ return player;
+ }
+
+ return NULL;
+}
+
static void proxy_removed(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -759,19 +1353,27 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
interface = g_dbus_proxy_get_interface(proxy);
- if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE))
- return;
+ if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0) {
+ if (adapter != proxy)
+ return;
+ printf("Bluetooth Adapter %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ adapter = NULL;
+ } else if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0) {
+ struct player *player;
- if (adapter != proxy)
- return;
+ player = find_player(proxy);
+ if (player == NULL)
+ return;
- printf("Bluetooth Adapter %s removed\n", g_dbus_proxy_get_path(proxy));
- adapter = NULL;
+ printf("Bluetooth Player %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ unregister_player(player);
+ }
}
int main(int argc, char *argv[])
{
- GDBusClient *client;
guint owner_watch, properties_watch;
struct sigaction sa;
int opt;
@@ -825,7 +1427,7 @@ int main(int argc, char *argv[])
g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
- NULL, NULL);
+ NULL, NULL);
g_main_loop_run(main_loop);
--
1.8.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH BlueZ 2/6 v2] tools: Add support for setting Shuffle and LoopStatus to mpris-player
2013-01-24 9:57 [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Luiz Augusto von Dentz
@ 2013-01-24 9:58 ` Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 3/6 v2] tools: Convert player's properties changed signals to MPRIS Luiz Augusto von Dentz
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This add write support for Shuffle and LoopStatus properties of
org.mpris.MediaPlayer2.Player interface.
---
tools/mpris-player.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 78 insertions(+), 2 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index d58e53f..7183bf6 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -992,6 +992,58 @@ static gboolean get_repeat(const GDBusPropertyTable *property,
return TRUE;
}
+static const char *loopstatus_to_repeat(const char *value)
+{
+ if (strcasecmp(value, "None") == 0)
+ return "off";
+ else if (strcasecmp(value, "Track") == 0)
+ return "singletrack";
+ else if (strcasecmp(value, "Playlist") == 0)
+ return "alltracks";
+
+ return NULL;
+}
+
+static void property_result(const DBusError *err, void *user_data)
+{
+ GDBusPendingPropertySet id = GPOINTER_TO_UINT(user_data);
+
+ if (!dbus_error_is_set(err))
+ return g_dbus_pending_property_success(id);
+
+ g_dbus_pending_property_error(id, err->name, err->message);
+}
+
+static void set_repeat(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, GDBusPendingPropertySet id,
+ void *data)
+{
+ struct player *player = data;
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ dbus_message_iter_get_basic(iter, &value);
+
+ value = loopstatus_to_repeat(value);
+ if (value == NULL) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ g_dbus_proxy_set_property_basic(player->proxy, "Repeat",
+ DBUS_TYPE_STRING, value,
+ property_result, GUINT_TO_POINTER(id),
+ NULL);
+}
+
static gboolean get_double(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -1030,6 +1082,30 @@ static gboolean get_shuffle(const GDBusPropertyTable *property,
return TRUE;
}
+static void set_shuffle(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, GDBusPendingPropertySet id,
+ void *data)
+{
+ struct player *player = data;
+ dbus_bool_t shuffle;
+ const char *value;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return;
+ }
+
+ dbus_message_iter_get_basic(iter, &shuffle);
+ value = shuffle ? "alltracks" : "off";
+
+ g_dbus_proxy_set_property_basic(player->proxy, "Shuffle",
+ DBUS_TYPE_STRING, value,
+ property_result, GUINT_TO_POINTER(id),
+ NULL);
+}
+
static gboolean position_exists(const GDBusPropertyTable *property, void *data)
{
DBusMessageIter iter;
@@ -1216,11 +1292,11 @@ static const GDBusSignalTable player_signals[] = {
static const GDBusPropertyTable player_properties[] = {
{ "PlaybackStatus", "s", get_status, NULL, status_exists },
- { "LoopStatus", "s", get_repeat, NULL, repeat_exists },
+ { "LoopStatus", "s", get_repeat, set_repeat, repeat_exists },
{ "Rate", "d", get_double, NULL, NULL },
{ "MinimumRate", "d", get_double, NULL, NULL },
{ "MaximumRate", "d", get_double, NULL, NULL },
- { "Shuffle", "b", get_shuffle, NULL, shuffle_exists },
+ { "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
{ "Position", "x", get_position, NULL, position_exists },
{ "Metadata", "a{sv}", get_track, NULL, track_exists },
{ "Volume", "d", get_double, NULL, NULL },
--
1.8.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH BlueZ 3/6 v2] tools: Convert player's properties changed signals to MPRIS
2013-01-24 9:57 [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 2/6 v2] tools: Add support for setting Shuffle and LoopStatus to mpris-player Luiz Augusto von Dentz
@ 2013-01-24 9:58 ` Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 4/6 v2] tools: Make mpris-player to export org.mpris.MediaPlayer2 Luiz Augusto von Dentz
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thsi convert properties changed signals from org.bluez.MediaPlayer1 to
org.mpris.MediaPlayer2.Player interface.
---
tools/mpris-player.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 7183bf6..320309e 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -1448,6 +1448,46 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
}
}
+static const char *property_to_mpris(const char *property)
+{
+ if (strcasecmp(property, "Repeat") == 0)
+ return "LoopStatus";
+ else if (strcasecmp(property, "Shuffle") == 0)
+ return "Shuffle";
+ else if (strcasecmp(property, "Status") == 0)
+ return "PlaybackStatus";
+ else if (strcasecmp(property, "Position") == 0)
+ return "Position";
+ else if (strcasecmp(property, "Track") == 0)
+ return "Metadata";
+
+ return NULL;
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct player *player;
+ const char *interface, *property;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) != 0)
+ return;
+
+ player = find_player(proxy);
+ if (player == NULL)
+ return;
+
+ property = property_to_mpris(name);
+ if (property == NULL)
+ return;
+
+ g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ property);
+}
+
int main(int argc, char *argv[])
{
guint owner_watch, properties_watch;
@@ -1503,7 +1543,7 @@ int main(int argc, char *argv[])
g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
- NULL, NULL);
+ property_changed, NULL);
g_main_loop_run(main_loop);
--
1.8.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH BlueZ 4/6 v2] tools: Make mpris-player to export org.mpris.MediaPlayer2
2013-01-24 9:57 [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 2/6 v2] tools: Add support for setting Shuffle and LoopStatus to mpris-player Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 3/6 v2] tools: Convert player's properties changed signals to MPRIS Luiz Augusto von Dentz
@ 2013-01-24 9:58 ` Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 5/6 v2] tools: Add volume support for mpris-player Luiz Augusto von Dentz
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds support for org.mpris.MediaPlayer2 interface whic is also
mandatory accourding to MPRIS spec.
---
tools/mpris-player.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 320309e..c8377ec 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -44,6 +44,7 @@
#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
+#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
#define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
@@ -1275,6 +1276,7 @@ static gboolean get_enable(const GDBusPropertyTable *property,
return TRUE;
}
+
static const GDBusMethodTable player_methods[] = {
{ GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
{ GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
@@ -1309,6 +1311,39 @@ static const GDBusPropertyTable player_properties[] = {
{ }
};
+static gboolean get_disable(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ dbus_bool_t value = FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+ return TRUE;
+}
+
+static gboolean get_name(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &player->name);
+
+ return TRUE;
+}
+
+static const GDBusMethodTable mpris_methods[] = {
+ { }
+};
+
+static const GDBusPropertyTable mpris_properties[] = {
+ { "CanQuit", "b", get_disable, NULL, NULL },
+ { "Fullscreen", "b", get_disable, NULL, NULL },
+ { "CanSetFullscreen", "b", get_disable, NULL, NULL },
+ { "CanRaise", "b", get_disable, NULL, NULL },
+ { "HasTrackList", "b", get_disable, NULL, NULL },
+ { "Identity", "s", get_name, NULL, NULL },
+ { }
+};
#define a_z "abcdefghijklmnopqrstuvwxyz"
#define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -1360,6 +1395,17 @@ static void register_player(GDBusProxy *proxy)
}
if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_INTERFACE,
+ mpris_methods,
+ NULL,
+ mpris_properties,
+ player, NULL)) {
+ fprintf(stderr, "Could not register interface %s",
+ MPRIS_INTERFACE);
+ goto fail;
+ }
+
+ if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
MPRIS_PLAYER_INTERFACE,
player_methods,
player_signals,
--
1.8.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH BlueZ 5/6 v2] tools: Add volume support for mpris-player
2013-01-24 9:57 [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Luiz Augusto von Dentz
` (2 preceding siblings ...)
2013-01-24 9:58 ` [PATCH BlueZ 4/6 v2] tools: Make mpris-player to export org.mpris.MediaPlayer2 Luiz Augusto von Dentz
@ 2013-01-24 9:58 ` Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 6/6 v2] tools: Emit Seeked signal if Position changes Luiz Augusto von Dentz
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This uses MediaTransport1 to track the Volume changes.
---
tools/mpris-player.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 178 insertions(+), 9 deletions(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index c8377ec..5903ca1 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -43,6 +43,7 @@
#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
@@ -55,6 +56,7 @@ static DBusConnection *sys = NULL;
static DBusConnection *session = NULL;
static GDBusClient *client = NULL;
static GSList *players = NULL;
+static GSList *transports = NULL;
struct player {
char *name;
@@ -62,6 +64,7 @@ struct player {
DBusConnection *conn;
GDBusProxy *proxy;
GDBusProxy *device;
+ GDBusProxy *transport;
};
typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
@@ -793,6 +796,9 @@ static void player_free(void *data)
g_dbus_proxy_unref(player->device);
g_dbus_proxy_unref(player->proxy);
+ if (player->transport)
+ g_dbus_proxy_unref(player->transport);
+
g_free(player->name);
g_free(player->bus_name);
g_free(player);
@@ -1277,6 +1283,30 @@ static gboolean get_enable(const GDBusPropertyTable *property,
}
+static gboolean get_volume(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct player *player = data;
+ double value = 0.0;
+ uint16_t volume;
+ DBusMessageIter var;
+
+ if (player->transport == NULL)
+ goto done;
+
+ if (!g_dbus_proxy_get_property(player->transport, "Volume", &var))
+ goto done;
+
+ dbus_message_iter_get_basic(&var, &volume);
+
+ value = (double) volume / 127;
+
+done:
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+ return TRUE;
+}
+
static const GDBusMethodTable player_methods[] = {
{ GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
{ GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
@@ -1301,7 +1331,7 @@ static const GDBusPropertyTable player_properties[] = {
{ "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
{ "Position", "x", get_position, NULL, position_exists },
{ "Metadata", "a{sv}", get_track, NULL, track_exists },
- { "Volume", "d", get_double, NULL, NULL },
+ { "Volume", "d", get_volume, NULL, NULL },
{ "CanGoNext", "b", get_enable, NULL, NULL },
{ "CanGoPrevious", "b", get_enable, NULL, NULL },
{ "CanPlay", "b", get_enable, NULL, NULL },
@@ -1355,12 +1385,33 @@ static char *mpris_busname(char *name)
g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
}
+static GDBusProxy *find_transport_by_path(const char *path)
+{
+ GSList *l;
+
+ for (l = transports; l; l = l->next) {
+ GDBusProxy *transport = l->data;
+ DBusMessageIter iter;
+ const char *value;
+
+ if (!g_dbus_proxy_get_property(transport, "Device", &iter))
+ continue;
+
+ dbus_message_iter_get_basic(&iter, &value);
+
+ if (strcmp(path, value) == 0)
+ return transport;
+ }
+
+ return NULL;
+}
+
static void register_player(GDBusProxy *proxy)
{
struct player *player;
DBusMessageIter iter;
const char *path, *name;
- GDBusProxy *device;
+ GDBusProxy *device, *transport;
if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
return;
@@ -1416,6 +1467,10 @@ static void register_player(GDBusProxy *proxy)
goto fail;
}
+ transport = find_transport_by_path(path);
+ if (transport)
+ player->transport = g_dbus_proxy_ref(transport);
+
return;
fail:
@@ -1423,6 +1478,47 @@ fail:
player_free(player);
}
+static struct player *find_player_by_device(const char *device)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+ const char *path = g_dbus_proxy_get_path(player->device);
+
+ if (g_strcmp0(device, path) == 0)
+ return player;
+ }
+
+ return NULL;
+}
+
+static void register_transport(GDBusProxy *proxy)
+{
+ struct player *player;
+ DBusMessageIter iter;
+ const char *path;
+
+ if (g_slist_find(transports, proxy) != NULL)
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Volume", &iter))
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+ return;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ transports = g_slist_append(transports, proxy);
+
+ player = find_player_by_device(path);
+ if (player == NULL || player->transport != NULL)
+ return;
+
+ player->transport = g_dbus_proxy_ref(proxy);
+}
+
static void proxy_added(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -1441,6 +1537,10 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
printf("Bluetooth Player %s found\n",
g_dbus_proxy_get_path(proxy));
register_player(proxy);
+ } else if (!strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
+ printf("Bluetooth Transport %s found\n",
+ g_dbus_proxy_get_path(proxy));
+ register_transport(proxy);
}
}
@@ -1466,6 +1566,37 @@ static struct player *find_player(GDBusProxy *proxy)
return NULL;
}
+static struct player *find_player_by_transport(GDBusProxy *proxy)
+{
+ GSList *l;
+
+ for (l = players; l; l = l->next) {
+ struct player *player = l->data;
+
+ if (player->transport == proxy)
+ return player;
+ }
+
+ return NULL;
+}
+
+static void unregister_transport(GDBusProxy *proxy)
+{
+ struct player *player;
+
+ if (g_slist_find(transports, proxy) == NULL)
+ return;
+
+ transports = g_slist_remove(transports, proxy);
+
+ player = find_player_by_transport(proxy);
+ if (player == NULL)
+ return;
+
+ g_dbus_proxy_unref(player->transport);
+ player->transport = NULL;
+}
+
static void proxy_removed(GDBusProxy *proxy, void *user_data)
{
const char *interface;
@@ -1491,6 +1622,10 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
printf("Bluetooth Player %s removed\n",
g_dbus_proxy_get_path(proxy));
unregister_player(player);
+ } else if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0) {
+ printf("Bluetooth Transport %s removed\n",
+ g_dbus_proxy_get_path(proxy));
+ unregister_transport(proxy);
}
}
@@ -1510,16 +1645,11 @@ static const char *property_to_mpris(const char *property)
return NULL;
}
-static void property_changed(GDBusProxy *proxy, const char *name,
+static void player_property_changed(GDBusProxy *proxy, const char *name,
DBusMessageIter *iter, void *user_data)
{
struct player *player;
- const char *interface, *property;
-
- interface = g_dbus_proxy_get_interface(proxy);
-
- if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) != 0)
- return;
+ const char *property;
player = find_player(proxy);
if (player == NULL)
@@ -1534,6 +1664,45 @@ static void property_changed(GDBusProxy *proxy, const char *name,
property);
}
+static void transport_property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct player *player;
+ DBusMessageIter var;
+ const char *path;
+
+ if (strcasecmp(name, "Volume") != 0)
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Device", &var))
+ return;
+
+ dbus_message_iter_get_basic(&var, &path);
+
+ player = find_player_by_device(path);
+ if (player == NULL)
+ return;
+
+ g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE,
+ name);
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0)
+ return player_property_changed(proxy, name, iter, user_data);
+
+ if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0)
+ return transport_property_changed(proxy, name, iter,
+ user_data);
+}
+
int main(int argc, char *argv[])
{
guint owner_watch, properties_watch;
--
1.8.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH BlueZ 6/6 v2] tools: Emit Seeked signal if Position changes
2013-01-24 9:57 [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Luiz Augusto von Dentz
` (3 preceding siblings ...)
2013-01-24 9:58 ` [PATCH BlueZ 5/6 v2] tools: Add volume support for mpris-player Luiz Augusto von Dentz
@ 2013-01-24 9:58 ` Luiz Augusto von Dentz
2013-01-25 7:42 ` [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Johan Hedberg
2013-01-25 9:28 ` [PATCH] tools: Fix format string warnings for g_dbus_create_error Chan-yeol Park
6 siblings, 0 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2013-01-24 9:58 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
MPRIS spec says PropertiesChanged is not emitted for Position, which is
probably to make clear that progress is done using the rate, so instead
Seeked should be emitted.
---
tools/mpris-player.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 5903ca1..95ef8ab 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -1650,6 +1650,8 @@ static void player_property_changed(GDBusProxy *proxy, const char *name,
{
struct player *player;
const char *property;
+ uint32_t position;
+ uint64_t value;
player = find_player(proxy);
if (player == NULL)
@@ -1662,6 +1664,18 @@ static void player_property_changed(GDBusProxy *proxy, const char *name,
g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
MPRIS_PLAYER_INTERFACE,
property);
+
+ if (strcasecmp(name, "Position") != 0)
+ return;
+
+ dbus_message_iter_get_basic(iter, &position);
+
+ value = position * 1000;
+
+ g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
+ MPRIS_PLAYER_INTERFACE, "Seeked",
+ DBUS_TYPE_INT64, &value,
+ DBUS_TYPE_INVALID);
}
static void transport_property_changed(GDBusProxy *proxy, const char *name,
--
1.8.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface
2013-01-24 9:57 [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Luiz Augusto von Dentz
` (4 preceding siblings ...)
2013-01-24 9:58 ` [PATCH BlueZ 6/6 v2] tools: Emit Seeked signal if Position changes Luiz Augusto von Dentz
@ 2013-01-25 7:42 ` Johan Hedberg
2013-01-25 9:28 ` [PATCH] tools: Fix format string warnings for g_dbus_create_error Chan-yeol Park
6 siblings, 0 replies; 9+ messages in thread
From: Johan Hedberg @ 2013-01-25 7:42 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
Hi Luiz,
On Thu, Jan 24, 2013, Luiz Augusto von Dentz wrote:
> Players found are exported in private connections using
> org.mpris.MediaPlayer2.<device name> on the session bus.
> ---
> v2: Fix generating invalid player bus name if device name contains invalid
> chars.
>
> tools/mpris-player.c | 644 +++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 623 insertions(+), 21 deletions(-)
All patches in this set have been applied. Thanks.
Johan
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH] tools: Fix format string warnings for g_dbus_create_error
2013-01-24 9:57 [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Luiz Augusto von Dentz
` (5 preceding siblings ...)
2013-01-25 7:42 ` [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Johan Hedberg
@ 2013-01-25 9:28 ` Chan-yeol Park
2013-01-25 9:53 ` Luiz Augusto von Dentz
6 siblings, 1 reply; 9+ messages in thread
From: Chan-yeol Park @ 2013-01-25 9:28 UTC (permalink / raw)
To: linux-bluetooth
This patch fixes gcc warnings for "format not a string literal and no
format arguments".
---
tools/mpris-player.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 95ef8ab..aafa142 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -830,7 +830,7 @@ static void player_reply(DBusMessage *message, void *user_data)
dbus_error_init(&err);
if (dbus_set_error_from_message(&err, message)) {
fprintf(stderr, "error: %s", err.name);
- reply = g_dbus_create_error(msg, err.name, err.message);
+ reply = g_dbus_create_error(msg, err.name, "%s", err.message);
dbus_error_free(&err);
} else
reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH] tools: Fix format string warnings for g_dbus_create_error
2013-01-25 9:28 ` [PATCH] tools: Fix format string warnings for g_dbus_create_error Chan-yeol Park
@ 2013-01-25 9:53 ` Luiz Augusto von Dentz
0 siblings, 0 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2013-01-25 9:53 UTC (permalink / raw)
To: Chan-yeol Park; +Cc: linux-bluetooth@vger.kernel.org
Hi Chan-yeol,
On Fri, Jan 25, 2013 at 11:28 AM, Chan-yeol Park
<chanyeol.park@samsung.com> wrote:
> This patch fixes gcc warnings for "format not a string literal and no
> format arguments".
> ---
> tools/mpris-player.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/tools/mpris-player.c b/tools/mpris-player.c
> index 95ef8ab..aafa142 100644
> --- a/tools/mpris-player.c
> +++ b/tools/mpris-player.c
> @@ -830,7 +830,7 @@ static void player_reply(DBusMessage *message, void *user_data)
> dbus_error_init(&err);
> if (dbus_set_error_from_message(&err, message)) {
> fprintf(stderr, "error: %s", err.name);
> - reply = g_dbus_create_error(msg, err.name, err.message);
> + reply = g_dbus_create_error(msg, err.name, "%s", err.message);
> dbus_error_free(&err);
> } else
> reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> --
> 1.7.10.4
Applied, thanks.
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2013-01-25 9:53 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-24 9:57 [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 2/6 v2] tools: Add support for setting Shuffle and LoopStatus to mpris-player Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 3/6 v2] tools: Convert player's properties changed signals to MPRIS Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 4/6 v2] tools: Make mpris-player to export org.mpris.MediaPlayer2 Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 5/6 v2] tools: Add volume support for mpris-player Luiz Augusto von Dentz
2013-01-24 9:58 ` [PATCH BlueZ 6/6 v2] tools: Emit Seeked signal if Position changes Luiz Augusto von Dentz
2013-01-25 7:42 ` [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface Johan Hedberg
2013-01-25 9:28 ` [PATCH] tools: Fix format string warnings for g_dbus_create_error Chan-yeol Park
2013-01-25 9:53 ` 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).