From: Luiz Augusto von Dentz Date: Thu, 6 Oct 2011 12:46:31 +0000 (+0300) Subject: Add mpris-player to test X-Git-Tag: android-x86-4.4-r3~14045 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=291e838c934745e47d30563b4949cc297d79daf3;p=android-x86%2Fexternal-bluetooth-bluez.git Add mpris-player to test It gather information from players implementing mpris spec and convert to org.bluez.MediaPlayer spec. --- diff --git a/Makefile.tools b/Makefile.tools index 0f80c0814..5d1c7e060 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -155,7 +155,7 @@ noinst_PROGRAMS += test/gaptest test/sdptest test/scotest \ test/attest test/hstest test/avtest test/ipctest \ test/lmptest test/bdaddr test/agent \ test/btiotest test/test-textfile \ - test/uuidtest + test/uuidtest test/mpris-player test_hciemu_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la @@ -191,6 +191,8 @@ test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la test_uuidtest_SOURCES = test/uuidtest.c test_uuidtest_LDADD = lib/libbluetooth-private.la +test_mpris_player_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ + test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c dist_man_MANS += test/rctest.1 test/hciemu.1 diff --git a/test/mpris-player.c b/test/mpris-player.c new file mode 100644 index 000000000..9e63b4b4c --- /dev/null +++ b/test/mpris-player.c @@ -0,0 +1,959 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2004-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static volatile sig_atomic_t __io_canceled = 0; +static volatile sig_atomic_t __io_terminated = 0; +static char *adapter = NULL; +static DBusConnection *sys = NULL; +static DBusConnection *session = NULL; + +static void sig_term(int sig) +{ + __io_canceled = 1; +} + +static DBusMessage *get_all(DBusConnection *conn, const char *name) +{ + DBusMessage *msg, *reply; + DBusError err; + const char *iface = "org.mpris.MediaPlayer2.Player"; + + msg = dbus_message_new_method_call(name, "/org/mpris/MediaPlayer2", + DBUS_INTERFACE_PROPERTIES, "GetAll"); + if (!msg) { + fprintf(stderr, "Can't allocate new method call\n"); + return NULL; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, + DBUS_TYPE_INVALID); + + dbus_error_init(&err); + + reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); + + dbus_message_unref(msg); + + if (!reply) { + fprintf(stderr, "Can't get default adapter\n"); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } + return NULL; + } + + return reply; +} + +static void append_variant(DBusMessageIter *iter, int type, void *val) +{ + DBusMessageIter value; + char sig[2] = { type, '\0' }; + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value); + + dbus_message_iter_append_basic(&value, type, val); + + dbus_message_iter_close_container(iter, &value); +} + +static void dict_append_entry(DBusMessageIter *dict, const char *key, int type, + void *val) +{ + DBusMessageIter entry; + + if (type == DBUS_TYPE_STRING) { + const char *str = *((const char **) val); + if (str == NULL) + return; + } + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + append_variant(&entry, type, val); + + dbus_message_iter_close_container(dict, &entry); +} + +static dbus_bool_t emit_property_changed(DBusConnection *conn, + const char *path, + const char *interface, + const char *name, + int type, void *value) +{ + DBusMessage *signal; + DBusMessageIter iter; + + signal = dbus_message_new_signal(path, interface, "PropertyChanged"); + + if (!signal) { + fprintf(stderr, "Unable to allocate new %s.PropertyChanged" + " signal", interface); + return FALSE; + } + + dbus_message_iter_init_append(signal, &iter); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); + + append_variant(&iter, type, value); + + return dbus_connection_send(conn, signal, NULL); +} + +static int parse_property(DBusConnection *conn, const char *path, + const char *key, + DBusMessageIter *entry, + DBusMessageIter *properties) +{ + DBusMessageIter var; + + printf("property %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, "PlaybackStatus") == 0) { + const char *value; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&var, &value); + + if (properties) + dict_append_entry(properties, "Status", + DBUS_TYPE_STRING, &value); + else + emit_property_changed(sys, path, + "org.bluez.MediaPlayer", "Status", + DBUS_TYPE_STRING, &value); + } else if (strcasecmp(key, "Position") == 0) { + int64_t usec, msec; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_INT64) + return -EINVAL; + + dbus_message_iter_get_basic(&var, &usec); + msec = usec / 1000; + + if (properties) + dict_append_entry(properties, "Position", + DBUS_TYPE_UINT32, &msec); + else + emit_property_changed(sys, path, + "org.bluez.MediaPlayer", "Position", + DBUS_TYPE_UINT32, &msec); + } else if (strcasecmp(key, "Shuffle") == 0) { + dbus_bool_t value; + const char *str; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_BOOLEAN) + return -EINVAL; + + dbus_message_iter_get_basic(&var, &value); + + str = value ? "on" : "off"; + if (properties) + dict_append_entry(properties, "Shuffle", + DBUS_TYPE_STRING, &str); + else + emit_property_changed(sys, path, + "org.bluez.MediaPlayer", "Shuffle", + DBUS_TYPE_UINT32, &str); + } + + return 0; +} + +static int parse_properties(DBusConnection *conn, const char *path, + DBusMessageIter *args, + DBusMessageIter *properties) +{ + DBusMessageIter dict; + int ctype; + + ctype = dbus_message_iter_get_arg_type(args); + if (ctype != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(args, &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 (parse_property(conn, path, key, &entry, properties) < 0) + return -EINVAL; + + dbus_message_iter_next(&dict); + } + + return 0; +} + +static int parse_metadata_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, "xesam:title") == 0) { + const char *value; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&var, &value); + dict_append_entry(metadata, "Title", DBUS_TYPE_STRING, + &value); + } else if (strcasecmp(key, "xesam:artist") == 0) { + const char *value; + DBusMessageIter array; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(&var, &array); + + if (dbus_message_iter_get_arg_type(&array) != + DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&array, &value); + dict_append_entry(metadata, "Artist", DBUS_TYPE_STRING, + &value); + } else if (strcasecmp(key, "xesam:album") == 0) { + const char *value; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&var, &value); + dict_append_entry(metadata, "Album", DBUS_TYPE_STRING, + &value); + } else if (strcasecmp(key, "xesam:genre") == 0) { + const char *value; + DBusMessageIter array; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(&var, &array); + + if (dbus_message_iter_get_arg_type(&array) != + DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&array, &value); + dict_append_entry(metadata, "Genre", DBUS_TYPE_STRING, + &value); + } else if (strcasecmp(key, "mpris:length") == 0) { + int64_t usec, msec; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_INT64) + return -EINVAL; + + dbus_message_iter_get_basic(&var, &usec); + msec = usec / 1000; + + dict_append_entry(metadata, "Duration", DBUS_TYPE_UINT32, + &msec); + } else if (strcasecmp(key, "xesam:trackNumber") == 0) { + int32_t value; + + if (dbus_message_iter_get_arg_type(&var) != + DBUS_TYPE_INT32) + return -EINVAL; + + dbus_message_iter_get_basic(&var, &value); + + dict_append_entry(metadata, "Number", DBUS_TYPE_UINT32, + &value); + } + + return 0; +} + +static int parse_track(DBusMessageIter *args, DBusMessageIter *metadata) +{ + DBusMessageIter var, dict; + int ctype; + + ctype = dbus_message_iter_get_arg_type(args); + if (ctype != DBUS_TYPE_VARIANT) + return -EINVAL; + + dbus_message_iter_recurse(args, &var); + + ctype = dbus_message_iter_get_arg_type(&var); + if (ctype != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(&var, &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 (parse_metadata_entry(&entry, key, metadata) < 0) + return -EINVAL; + + dbus_message_iter_next(&dict); + } + + return 0; +} + +static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata) +{ + DBusMessageIter dict; + int ctype; + + ctype = dbus_message_iter_get_arg_type(args); + if (ctype != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(args, &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 (strcasecmp(key, "Metadata") == 0) + return parse_track(&entry, metadata); + + dbus_message_iter_next(&dict); + } + + return -EINVAL; +} + +static char *sender2path(const char *sender) +{ + char *path; + + path = g_strconcat("/", sender, NULL); + return g_strdelimit(path, ":.", '_'); +} + +static void add_player(DBusConnection *conn, const char *name, + const char *sender) +{ + DBusMessage *reply = get_all(conn, name); + DBusMessage *msg; + DBusMessageIter iter, args, properties, metadata; + DBusError err; + char *path; + + if (!reply) + return; + + msg = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Media", + "RegisterPlayer"); + if (!msg) { + fprintf(stderr, "Can't allocate new method call\n"); + return; + } + + dbus_message_iter_init_append(msg, &iter); + + path = sender2path(sender); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path); + + 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, &properties); + + dbus_message_iter_init(reply, &args); + + if (parse_properties(conn, path, &args, &properties) < 0) + goto done; + + dbus_message_iter_close_container(&iter, &properties); + + 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); + + dbus_message_iter_init(reply, &args); + + if (parse_metadata(&args, &metadata) < 0) + goto done; + + dbus_message_iter_close_container(&iter, &metadata); + + dbus_message_unref(reply); + + dbus_error_init(&err); + + reply = dbus_connection_send_with_reply_and_block(sys, msg, -1, &err); + if (!reply) { + fprintf(stderr, "Can't register player\n"); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } + goto done; + } + +done: + if (reply) + dbus_message_unref(reply); + dbus_message_unref(msg); + g_free(path); +} + +static void remove_player(DBusConnection *conn, const char *sender) +{ + DBusMessage *msg; + char *path; + + msg = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Media", + "UnregisterPlayer"); + if (!msg) { + fprintf(stderr, "Can't allocate new method call\n"); + return; + } + + path = sender2path(sender); + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID); + + dbus_connection_send(sys, msg, NULL); + + dbus_message_unref(msg); + g_free(path); +} + +static DBusHandlerResult properties_changed(DBusConnection *conn, + DBusMessage *msg) +{ + DBusMessage *signal; + DBusMessageIter iter, entry, metadata; + const char *iface; + char *path; + + dbus_message_iter_init(msg, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_message_iter_get_basic(&iter, &iface); + + printf("PropertiesChanged interface %s\n", iface); + + dbus_message_iter_next(&iter); + + path = sender2path(dbus_message_get_sender(msg)); + parse_properties(conn, path, &iter, NULL); + + signal = dbus_message_new_signal(path, "org.bluez.MediaPlayer", + "TrackChanged"); + if (!signal) { + fprintf(stderr, "Unable to allocate new PropertyChanged" + " signal\n"); + goto done; + } + + dbus_message_iter_init_append(signal, &entry); + + dbus_message_iter_open_container(&entry, 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); + + dbus_message_iter_init(msg, &iter); + dbus_message_iter_next(&iter); + + if (parse_metadata(&iter, &metadata) < 0) + goto done; + + dbus_message_iter_close_container(&entry, &metadata); + + dbus_connection_send(sys, signal, NULL); + +done: + g_free(path); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult session_filter(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const char *name, *old, *new; + + if (dbus_message_is_signal(msg, DBUS_INTERFACE_PROPERTIES, + "PropertiesChanged")) + return properties_changed(conn, msg); + + if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old, + DBUS_TYPE_STRING, &new, + DBUS_TYPE_INVALID)) { + fprintf(stderr, "Invalid arguments for NameOwnerChanged signal"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (!g_str_has_prefix(name, "org.mpris")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (*new == '\0') { + printf("player %s at %s disappear\n", name, old); + remove_player(conn, old); + } else { + printf("player %s at %s found\n", name, new); + add_player(conn, name, new); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult system_filter(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + const char *name, *old, *new; + + if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old, + DBUS_TYPE_STRING, &new, + DBUS_TYPE_INVALID)) { + fprintf(stderr, "Invalid arguments for NameOwnerChanged signal"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (!strcmp(name, "org.bluez") && *new == '\0') { + fprintf(stderr, "bluetoothd disconnected\n"); + __io_terminated = 1; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static char *get_default_adapter(DBusConnection *conn) +{ + DBusMessage *msg, *reply; + DBusError err; + const char *reply_path; + char *path; + + msg = dbus_message_new_method_call("org.bluez", "/", + "org.bluez.Manager", "DefaultAdapter"); + + if (!msg) { + fprintf(stderr, "Can't allocate new method call\n"); + return NULL; + } + + dbus_error_init(&err); + + reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); + + dbus_message_unref(msg); + + if (!reply) { + fprintf(stderr, "Can't get default adapter\n"); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } + return NULL; + } + + if (!dbus_message_get_args(reply, &err, + DBUS_TYPE_OBJECT_PATH, &reply_path, + DBUS_TYPE_INVALID)) { + fprintf(stderr, "Can't get reply arguments\n"); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } + return NULL; + } + + path = strdup(reply_path); + + dbus_message_unref(reply); + + dbus_connection_flush(conn); + + return path; +} + +static char *get_adapter(DBusConnection *conn, const char *adapter) +{ + DBusMessage *msg, *reply; + DBusError err; + const char *reply_path; + char *path; + + if (!adapter) + return get_default_adapter(conn); + + msg = dbus_message_new_method_call("org.bluez", "/", + "org.bluez.Manager", "FindAdapter"); + + if (!msg) { + fprintf(stderr, "Can't allocate new method call\n"); + return NULL; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &adapter, + DBUS_TYPE_INVALID); + + dbus_error_init(&err); + + reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); + + dbus_message_unref(msg); + + if (!reply) { + fprintf(stderr, "Can't find adapter %s\n", adapter); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } + return NULL; + } + + if (!dbus_message_get_args(reply, &err, + DBUS_TYPE_OBJECT_PATH, &reply_path, + DBUS_TYPE_INVALID)) { + fprintf(stderr, "Can't get reply arguments\n"); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } + return NULL; + } + + path = strdup(reply_path); + + dbus_message_unref(reply); + + dbus_connection_flush(conn); + + return path; +} + +static char *get_name_owner(DBusConnection *conn, const char *name) +{ + DBusMessage *msg, *reply; + DBusError err; + char *owner; + + msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, "GetNameOwner"); + + if (!msg) { + fprintf(stderr, "Can't allocate new method call\n"); + return NULL; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + + dbus_error_init(&err); + + reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); + + dbus_message_unref(msg); + + if (!reply) { + fprintf(stderr, "Can't find adapter %s\n", adapter); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } + return NULL; + } + + if (!dbus_message_get_args(reply, NULL, + DBUS_TYPE_STRING, &owner, + DBUS_TYPE_INVALID)) + return NULL; + + owner = g_strdup(owner); + + dbus_message_unref(reply); + + dbus_connection_flush(conn); + + return owner; +} + +static void parse_list_names(DBusConnection *conn, DBusMessageIter *args) +{ + DBusMessageIter array; + int ctype; + + ctype = dbus_message_iter_get_arg_type(args); + if (ctype != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(args, &array); + + while ((ctype = dbus_message_iter_get_arg_type(&array)) != + DBUS_TYPE_INVALID) { + const char *name; + char *owner; + + if (ctype != DBUS_TYPE_STRING) + goto next; + + dbus_message_iter_get_basic(&array, &name); + + if (!g_str_has_prefix(name, "org.mpris")) + goto next; + + owner = get_name_owner(conn, name); + + if (owner == NULL) + goto next; + + add_player(conn, name, owner); + + g_free(owner); +next: + dbus_message_iter_next(&array); + } +} + +static void list_names(DBusConnection *conn) +{ + DBusMessage *msg, *reply; + DBusMessageIter iter; + DBusError err; + + msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, "ListNames"); + + if (!msg) { + fprintf(stderr, "Can't allocate new method call\n"); + return; + } + + dbus_error_init(&err); + + reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); + + dbus_message_unref(msg); + + if (!reply) { + fprintf(stderr, "Can't find adapter %s\n", adapter); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } + return; + } + + dbus_message_iter_init(reply, &iter); + + parse_list_names(conn, &iter); + + dbus_message_unref(reply); + + dbus_connection_flush(conn); +} + +static void usage(void) +{ + printf("Bluetooth player ver %s\n\n", VERSION); + + printf("Usage:\n" + "\tplayer [--adapter adapter id]\n" + "\n"); +} + +static struct option main_options[] = { + { "adapter", 1, 0, 'a' }, + { 0, 0, 0, 0 } +}; + +int main(int argc, char *argv[]) +{ + struct sigaction sa; + char *adapter_id = NULL; + char match[128]; + int opt; + + while ((opt = getopt_long(argc, argv, "+a,h", main_options, NULL)) != EOF) { + switch(opt) { + case '1': + adapter_id = optarg; + break; + case 'h': + usage(); + exit(0); + default: + exit(1); + } + } + + sys = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + if (!sys) { + fprintf(stderr, "Can't get on system bus"); + exit(1); + } + + adapter = get_adapter(sys, adapter_id); + if (!adapter) + exit(1); + + if (!dbus_connection_add_filter(sys, system_filter, NULL, NULL)) { + fprintf(stderr, "Can't add signal filter"); + exit(1); + } + + snprintf(match, sizeof(match), + "interface=%s,member=NameOwnerChanged,arg0=%s", + DBUS_INTERFACE_DBUS, "org.bluez"); + + dbus_bus_add_match(sys, match, NULL); + + session = dbus_bus_get(DBUS_BUS_SESSION, NULL); + if (!session) { + fprintf(stderr, "Can't get on session bus"); + exit(1); + } + + if (!dbus_connection_add_filter(session, session_filter, NULL, NULL)) { + fprintf(stderr, "Can't add signal filter"); + exit(1); + } + + snprintf(match, sizeof(match), + "interface=%s,member=NameOwnerChanged", + DBUS_INTERFACE_DBUS); + + dbus_bus_add_match(session, match, NULL); + + snprintf(match, sizeof(match), + "interface=%s,member=PropertiesChanged,arg0=%s", + DBUS_INTERFACE_PROPERTIES, + "org.mpris.MediaPlayer2.Player"); + + list_names(session); + + dbus_bus_add_match(session, match, NULL); + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = sig_term; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + while (!__io_canceled && !__io_terminated) { + if (dbus_connection_read_write_dispatch(sys, 500) != TRUE) + break; + if (dbus_connection_read_write_dispatch(session, 500) != TRUE) + break; + } + + dbus_connection_unref(sys); + + return 0; +}