/* * Copyright (C) 2014 Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb" /* ---------------------------------------------------------------------------------------------------- */ static GDBusNodeInfo *introspection_data = NULL; /* Introspection data for the service we are exporting */ static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " ""; typedef struct { GDBusConnection *conn; GDBusProxy *manager; gchar *name; guint id; GHashTable *objs; } Agent; typedef struct { Agent *agent; gchar *obj; gint fd; GIOChannel *channel; } Connection; static Connection * connection_free (Connection *t) { g_print ("connection free %p\n", t); if (t->channel) g_io_channel_unref (t->channel); g_free (t->obj); g_free (t); } static gboolean sco_io_cb (GIOChannel *source, GIOCondition condition, gpointer data) { gchar buf[1024]; gsize length; gint fd = g_io_channel_unix_get_fd (source); if (condition & G_IO_IN) { length = recv (fd, buf, 1024, 0); if (length <= 0) perror ("recv()"); g_print ("-"); } else if (condition & G_IO_OUT) { gint i; for (i = 0; i < 48; i++) buf[i] = g_random_int_range (0, 255); length = send (fd, buf, 48, 0); if (length != 48) perror ("send()"); g_print ("+"); usleep(2500); } else if (condition & (G_IO_ERR | G_IO_HUP)) { g_print ("got error\n"); return FALSE; } return TRUE; } static Connection * connection_new (Agent *a, const gchar *obj, gint fd) { Connection *c; GError *error = NULL; GVariant *res, *var; const gchar *adapter; c = g_new0 (Connection, 1); c->agent = a; c->obj = g_strdup (obj); c->fd = fd; g_print ("new connection %p\n", c); c->channel = g_io_channel_unix_new (fd); g_io_channel_set_close_on_unref (c->channel, TRUE); g_io_add_watch (c->channel, G_IO_IN | G_IO_ERR | G_IO_HUP, sco_io_cb, c); g_hash_table_insert (a->objs, (gpointer) obj, c); return c; } static void agent_new_connection (Agent *a, GDBusConnection *connection, GVariant *parameters, GDBusMethodInvocation *invocation) { gchar *obj; gint32 fd; guint codec; GDBusMessage *message; GUnixFDList * fdlist; g_variant_get (parameters, "(ohy)", &obj, &fd, &codec); message = g_dbus_method_invocation_get_message (invocation); fdlist = g_dbus_message_get_unix_fd_list (message); fd = g_unix_fd_list_get (fdlist, fd, NULL); g_print ("NewConnection %s %d %d\n", obj, fd, codec); g_dbus_method_invocation_return_value (invocation, NULL); connection_new (a, obj, fd); } static void agent_release (Agent *a, GDBusConnection *connection, GVariant *parameters, GDBusMethodInvocation *invocation) { g_dbus_method_invocation_return_value (invocation, NULL); } static void agent_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { Agent *a = user_data; if (g_strcmp0 (method_name, "Release") == 0) { agent_release (a, connection, parameters, invocation); } else if (g_strcmp0 (method_name, "NewConnection") == 0) { agent_new_connection (a, connection, parameters, invocation); } else g_print ("Unhandled %s\n", method_name); } static const GDBusInterfaceVTable agent_interface_vtable = { agent_method_call, NULL, NULL }; static void agent_free (Agent *a) { if (a->id) g_dbus_connection_unregister_object (a->conn, a->id); g_free (a->name); g_hash_table_unref (a->objs); g_free (a); } static Agent * register_agent (GDBusConnection *connection, GDBusProxy * manager) { GError *error = NULL; guint registration_id; Agent *agent; GVariant *res; GVariantBuilder *b; agent = g_new0 (Agent, 1); agent->conn = connection; agent->manager = manager; agent->name = g_strdup_printf ("/org/test/HandsfreeAgent"); agent->objs = g_hash_table_new (g_str_hash, g_str_equal); agent->id = g_dbus_connection_register_object (connection, agent->name, introspection_data->interfaces[0], &agent_interface_vtable, agent, NULL, /* user_data_free_func */ &error); /* GError** */ if (agent->id == 0) { g_printerr ("error registering agent %s\n", error->message); agent_free (agent); return NULL; } g_print ("Register agent\n"); b = g_variant_builder_new (G_VARIANT_TYPE ("ay")); g_variant_builder_add (b, "y", 1); res = g_dbus_proxy_call_sync (manager, "Register", g_variant_new ("(oay)", agent->name, b, NULL), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (res == NULL) { g_printerr ("error registering %s\n", error->message); agent_free (agent); return NULL; } g_print ("Agent registered\n"); g_variant_unref (res); return agent; } int main (int argc, char *argv[]) { GDBusConnection * connection; GError *error = NULL; GMainLoop *loop; guint registration_id; GDBusProxy *manager; g_print ("connecting to system bus\n"); connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (error != NULL) { g_printerr ("error getting bus: %s", error->message); return -1; } introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); g_assert (introspection_data != NULL); g_print ("making proxy for HandsfreeAudioManager\n"); manager = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.ofono", "/", "org.ofono.HandsfreeAudioManager", NULL, &error); if (error != NULL) { g_printerr ("error getting HandsfreeAudioManager: %s", error->message); return -1; } if (register_agent (connection, manager) == NULL) return -1; g_print ("going into mainloop\n"); loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); g_print ("exit mainloop\n"); g_dbus_node_info_unref (introspection_data); return 0; }