From 290c1e764a2b8c7d166681152c6f458bcade00ee Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 26 Sep 2010 21:40:08 +0900 Subject: [PATCH] tools: Update Huawei audio utility with call tracking --- tools/huawei-audio.c | 606 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 605 insertions(+), 1 deletion(-) diff --git a/tools/huawei-audio.c b/tools/huawei-audio.c index ca304bcf..5928d6e1 100644 --- a/tools/huawei-audio.c +++ b/tools/huawei-audio.c @@ -23,7 +23,611 @@ #include #endif -int main(int argc, char **argv) +#include +#include +#include +#include +#include + +#include + +#define OFONO_SERVICE "org.ofono" + +#define OFONO_MANAGER_INTERFACE OFONO_SERVICE ".Manager" +#define OFONO_MODEM_INTERFACE OFONO_SERVICE ".Modem" +#define OFONO_CALLMANAGER_INTERFACE OFONO_SERVICE ".VoiceCallManager" +#define OFONO_CALL_INTERFACE OFONO_SERVICE ".VoiceCall" + +struct modem_data { + char *path; + GHashTable *call_list; + + DBusConnection *conn; + guint call_added_watch; + guint call_removed_watch; + guint call_changed_watch; + + gboolean has_callmanager; +}; + +struct call_data { + char *path; +}; + +static GHashTable *modem_list; + +static void call_set(struct call_data *call, const char *key, + DBusMessageIter *iter) { + const char *str = NULL; + + if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) + dbus_message_iter_get_basic(iter, &str); + + g_print("updating call (%s) [ %s = %s ]\n", call->path, + key, str ? str : "..."); +} + +static void destroy_call(gpointer data) +{ + struct call_data *call = data; + + g_print("call removed (%s)\n", call->path); + + g_free(call->path); + g_free(call); +} + +static void create_call(struct modem_data *modem, + const char *path, DBusMessageIter *iter) +{ + struct call_data *call; + DBusMessageIter dict; + + call = g_try_new0(struct call_data, 1); + if (call == NULL) + return; + + call->path = g_strdup(path); + + g_hash_table_replace(modem->call_list, call->path, call); + + g_print("call added (%s)\n", call->path); + + dbus_message_iter_recurse(iter, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value; + const char *key; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + call_set(call, key, &value); + + dbus_message_iter_next(&dict); + } + +} + +static gboolean call_added(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct modem_data *modem = user_data; + DBusMessageIter iter, dict; + const char *path; + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return TRUE; + + dbus_message_iter_get_basic(&iter, &path); + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &dict); + + create_call(modem, path, &iter); + + return TRUE; +} + +static gboolean call_removed(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct modem_data *modem = user_data; + DBusMessageIter iter; + const char *path; + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return TRUE; + + dbus_message_iter_get_basic(&iter, &path); + + g_hash_table_remove(modem->call_list, path); + + return TRUE; +} + +static gboolean call_changed(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct modem_data *modem = user_data; + struct call_data *call; + DBusMessageIter iter, value; + const char *path, *key; + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return TRUE; + + path = dbus_message_get_path(msg); + + call = g_hash_table_lookup(modem->call_list, path); + if (call == NULL) + return TRUE; + + dbus_message_iter_get_basic(&iter, &key); + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &value); + + call_set(call, key, &value); + + return TRUE; +} + +static void get_calls_reply(DBusPendingCall *call, void *user_data) +{ + struct modem_data *modem = user_data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter, list; + DBusError err; + + dbus_error_init(&err); + + if (dbus_set_error_from_message(&err, reply) == TRUE) { + g_printerr("%s: %s\n", err.name, err.message); + dbus_error_free(&err); + goto done; + } + + if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE) + goto done; + + if (dbus_message_iter_init(reply, &iter) == FALSE) + goto done; + + dbus_message_iter_recurse(&iter, &list); + + while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) { + DBusMessageIter entry, dict; + const char *path; + + dbus_message_iter_recurse(&list, &entry); + dbus_message_iter_get_basic(&entry, &path); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &dict); + + create_call(modem, path, &dict); + + dbus_message_iter_next(&list); + } + +done: + dbus_message_unref(reply); +} + +static int get_calls(struct modem_data *modem) +{ + DBusMessage *msg; + DBusPendingCall *call; + + msg = dbus_message_new_method_call(OFONO_SERVICE, modem->path, + OFONO_CALLMANAGER_INTERFACE, "GetCalls"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_set_auto_start(msg, FALSE); + + g_print("getting calls (%s)\n", modem->path); + + if (dbus_connection_send_with_reply(modem->conn, msg, + &call, -1) == FALSE) { + dbus_message_unref(msg); + return -EIO; + } + + dbus_message_unref(msg); + + if (call == NULL) + return -EINVAL; + + dbus_pending_call_set_notify(call, get_calls_reply, modem, NULL); + + dbus_pending_call_unref(call); + + return 0; +} + +static void check_interfaces(struct modem_data *modem, DBusMessageIter *iter) +{ + DBusMessageIter entry; + gboolean has_callmanager = FALSE; + + dbus_message_iter_recurse(iter, &entry); + + while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) { + const char *interface; + + dbus_message_iter_get_basic(&entry, &interface); + + if (g_str_equal(interface, OFONO_CALLMANAGER_INTERFACE) == TRUE) + has_callmanager = TRUE; + + dbus_message_iter_next(&entry); + } + + if (modem->has_callmanager == has_callmanager) + return; + + modem->has_callmanager = has_callmanager; + if (modem->has_callmanager == TRUE) + get_calls(modem); +} + +static void destroy_modem(gpointer data) +{ + struct modem_data *modem = data; + + g_dbus_remove_watch(modem->conn, modem->call_added_watch); + g_dbus_remove_watch(modem->conn, modem->call_removed_watch); + g_dbus_remove_watch(modem->conn, modem->call_changed_watch); + + g_hash_table_destroy(modem->call_list); + + g_print("modem removed (%s)\n", modem->path); + + g_free(modem->path); + g_free(modem); +} + +static void create_modem(DBusConnection *conn, + const char *path, DBusMessageIter *iter) +{ + struct modem_data *modem; + DBusMessageIter dict; + + modem = g_try_new0(struct modem_data, 1); + if (modem == NULL) + return; + + modem->path = g_strdup(path); + + modem->call_list = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, destroy_call); + + modem->conn = conn; + + modem->call_added_watch = g_dbus_add_signal_watch(conn, NULL, + modem->path, OFONO_CALLMANAGER_INTERFACE, + "CallAdded", call_added, modem, NULL); + modem->call_removed_watch = g_dbus_add_signal_watch(conn, NULL, + modem->path, OFONO_CALLMANAGER_INTERFACE, + "CallRemoved", call_removed, modem, NULL); + modem->call_changed_watch = g_dbus_add_signal_watch(conn, NULL, + NULL, OFONO_CALL_INTERFACE, + "PropertyChanged", call_changed, modem, NULL); + + g_hash_table_replace(modem_list, modem->path, modem); + + g_print("modem added (%s)\n", modem->path); + + dbus_message_iter_recurse(iter, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value; + const char *key; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + if (g_str_equal(key, "Interfaces") == TRUE) + check_interfaces(modem, &value); + + dbus_message_iter_next(&dict); + } +} + +static gboolean modem_added(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBusMessageIter iter, dict; + const char *path; + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return TRUE; + + dbus_message_iter_get_basic(&iter, &path); + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &dict); + + create_modem(conn, path, &iter); + + return TRUE; +} + +static gboolean modem_removed(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBusMessageIter iter; + const char *path; + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return TRUE; + + dbus_message_iter_get_basic(&iter, &path); + + g_hash_table_remove(modem_list, path); + + return TRUE; +} + +static gboolean modem_changed(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct modem_data *modem; + DBusMessageIter iter, value; + const char *path, *key; + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return TRUE; + + path = dbus_message_get_path(msg); + + modem = g_hash_table_lookup(modem_list, path); + if (modem == NULL) + return TRUE; + + dbus_message_iter_get_basic(&iter, &key); + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &value); + + if (g_str_equal(key, "Interfaces") == TRUE) + check_interfaces(modem, &value); + + return TRUE; +} + +static void get_modems_reply(DBusPendingCall *call, void *user_data) +{ + DBusConnection *conn = user_data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter, list; + DBusError err; + + dbus_error_init(&err); + + if (dbus_set_error_from_message(&err, reply) == TRUE) { + g_printerr("%s: %s\n", err.name, err.message); + dbus_error_free(&err); + goto done; + } + + if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE) + goto done; + + if (dbus_message_iter_init(reply, &iter) == FALSE) + goto done; + + dbus_message_iter_recurse(&iter, &list); + + while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) { + DBusMessageIter entry, dict; + const char *path; + + dbus_message_iter_recurse(&list, &entry); + dbus_message_iter_get_basic(&entry, &path); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &dict); + + create_modem(conn, path, &entry); + + dbus_message_iter_next(&list); + } + +done: + dbus_message_unref(reply); +} + +static int get_modems(DBusConnection *conn) +{ + DBusMessage *msg; + DBusPendingCall *call; + + msg = dbus_message_new_method_call(OFONO_SERVICE, "/", + OFONO_MANAGER_INTERFACE, "GetModems"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_set_auto_start(msg, FALSE); + + g_print("getting modems\n"); + + if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) { + dbus_message_unref(msg); + return -EIO; + } + + dbus_message_unref(msg); + + if (call == NULL) + return -EINVAL; + + dbus_pending_call_set_notify(call, get_modems_reply, conn, NULL); + + dbus_pending_call_unref(call); + + return 0; +} + +static gboolean ofono_running = FALSE; + +static guint modem_added_watch; +static guint modem_removed_watch; +static guint modem_changed_watch; + +static void ofono_connect(DBusConnection *conn, void *user_data) +{ + g_print("starting telephony interface\n"); + + ofono_running = TRUE; + + modem_list = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, destroy_modem); + + modem_added_watch = g_dbus_add_signal_watch(conn, NULL, NULL, + OFONO_MANAGER_INTERFACE, "ModemAdded", + modem_added, NULL, NULL); + modem_removed_watch = g_dbus_add_signal_watch(conn, NULL, NULL, + OFONO_MANAGER_INTERFACE, "ModemRemoved", + modem_removed, NULL, NULL); + modem_changed_watch = g_dbus_add_signal_watch(conn, NULL, NULL, + OFONO_MODEM_INTERFACE, "PropertyChanged", + modem_changed, NULL, NULL); + + get_modems(conn); +} + +static void ofono_disconnect(DBusConnection *conn, void *user_data) +{ + g_print("stopping telephony interface\n"); + + ofono_running = FALSE; + + g_dbus_remove_watch(conn, modem_added_watch); + modem_added_watch = 0; + g_dbus_remove_watch(conn, modem_removed_watch); + modem_removed_watch = 0; + g_dbus_remove_watch(conn, modem_changed_watch); + modem_changed_watch = 0; + + g_hash_table_destroy(modem_list); + modem_list = NULL; +} + +static GMainLoop *main_loop = NULL; + +static volatile sig_atomic_t __terminated = 0; + +static void sig_term(int sig) +{ + if (__terminated > 0) + return; + + __terminated = 1; + + g_print("Terminating\n"); + + g_main_loop_quit(main_loop); +} + +static void disconnect_callback(DBusConnection *conn, void *user_data) +{ + g_printerr("D-Bus disconnect\n"); + + g_main_loop_quit(main_loop); +} + +static gboolean option_version = FALSE; + +static GOptionEntry options[] = { + { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version, + "Show version information and exit" }, + { NULL }, +}; + +int main(int argc, char **argv) +{ + GOptionContext *context; + GError *error = NULL; + DBusConnection *conn; + DBusError err; + guint watch; + struct sigaction sa; + +#ifdef NEED_THREADS + if (g_thread_supported() == FALSE) + g_thread_init(NULL); +#endif + + context = g_option_context_new(NULL); + g_option_context_add_main_entries(context, options, NULL); + + if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) { + if (error != NULL) { + g_printerr("%s\n", error->message); + g_error_free(error); + } else + g_printerr("An unknown error occurred\n"); + exit(1); + } + + g_option_context_free(context); + + if (option_version == TRUE) { + printf("%s\n", VERSION); + exit(0); + } + + main_loop = g_main_loop_new(NULL, FALSE); + +#ifdef NEED_THREADS + if (dbus_threads_init_default() == FALSE) { + fprintf(stderr, "Can't init usage of threads\n"); + exit(1); + } +#endif + + dbus_error_init(&err); + + conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &err); + if (conn == NULL) { + if (dbus_error_is_set(&err) == TRUE) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } else + fprintf(stderr, "Can't register with system bus\n"); + exit(1); + } + + g_dbus_set_disconnect_function(conn, disconnect_callback, NULL, NULL); + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sig_term; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + watch = g_dbus_add_service_watch(conn, OFONO_SERVICE, + ofono_connect, ofono_disconnect, NULL, NULL); + + g_main_loop_run(main_loop); + + g_dbus_remove_watch(conn, watch); + + if (ofono_running == TRUE) + ofono_disconnect(conn, NULL); + + dbus_connection_unref(conn); + + g_main_loop_unref(main_loop); + return 0; }