summaryrefslogtreecommitdiffstats
path: root/audio/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/manager.c')
-rw-r--r--audio/manager.c282
1 files changed, 227 insertions, 55 deletions
diff --git a/audio/manager.c b/audio/manager.c
index 5d381972..682158c2 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -56,9 +56,9 @@
static DBusConnection *connection = NULL;
-static char *default_hs = NULL;
+static audio_device_t *default_hs = NULL;
-static GSList *headsets = NULL;
+static GSList *devices = NULL;
static int unix_sock = -1;
@@ -116,85 +116,242 @@ static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data)
return TRUE;
}
-void manager_add_headset(const char *path)
+static audio_device_t *find_device(bdaddr_t *bda)
{
- char *my_path = g_strdup(path);
+ GSList *l;
+
+ for (l = devices; l != NULL; l = l->next) {
+ audio_device_t *device = l->data;
+ if (bacmp(&device->bda, bda) == 0)
+ return device;
+ }
+
+ return NULL;
+}
+
+static DBusHandlerResult device_get_address(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ audio_device_t *device = data;
+ DBusMessage *reply;
+ char address[18], *ptr = address;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
- headsets = g_slist_append(headsets, my_path);
+ ba2str(&device->bda, address);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusMethodVTable device_methods[] = {
+ { "GetAddress", device_get_address, "", "s" },
+ { NULL, NULL, NULL, NULL }
+};
+
+static audio_device_t *add_device(bdaddr_t *bda)
+{
+ static int device_id = 0;
+ audio_device_t *device;
+
+ device = g_new0(audio_device_t, 1);
+
+ bacpy(&device->bda, bda);
+
+ snprintf(device->object_path, sizeof(device->object_path) - 1,
+ "%s/device%d", AUDIO_MANAGER_PATH, device_id++);
+
+ if (!dbus_connection_create_object_path(connection, device->object_path,
+ device, NULL)) {
+ error("D-Bus failed to register %s path", device->object_path);
+ g_free(device);
+ return NULL;
+ }
+
+ if (!dbus_connection_register_interface(connection, device->object_path,
+ AUDIO_DEVICE_INTERFACE,
+ device_methods, NULL, NULL)) {
+ error("Failed to register %s interface to %s",
+ AUDIO_DEVICE_INTERFACE, device->object_path);
+ dbus_connection_destroy_object_path(connection,
+ device->object_path);
+ g_free(device);
+ return NULL;
+ }
+
+ devices = g_slist_append(devices, device);
+
+ return device;
+}
+
+static void remove_device(audio_device_t *device)
+{
+ devices = g_slist_remove(devices, device);
+ dbus_connection_destroy_object_path(connection, device->object_path);
+ g_free(device->headset);
+ g_free(device);
+}
+
+audio_device_t *manager_headset_connected(bdaddr_t *bda)
+{
+ audio_device_t *device;
+ const char *path;
+
+ device = find_device(bda);
+ if (device && device->headset)
+ return device;
+
+ if (!device)
+ device = add_device(bda);
+
+ if (!device)
+ return NULL;
+
+ if (!device->headset)
+ device->headset = headset_init(device->object_path);
+
+ if (!device->headset)
+ return NULL;
+
+ path = device->object_path;
dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
"HeadsetCreated",
- DBUS_TYPE_STRING, &my_path,
+ DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
if (!default_hs) {
- default_hs = my_path;
+ default_hs = device;
dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
"DefaultHeadsetChanged",
- DBUS_TYPE_STRING, &my_path,
+ DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
}
-}
-static void manager_remove_headset(char *path)
-{
- headset_remove(path);
- g_free(path);
+ return device;
}
-static DBusHandlerResult am_create_headset(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult am_create_device(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- const char *hs_path;
const char *address;
bdaddr_t bda;
- DBusMessage *reply;
+ audio_device_t *device;
DBusError derr;
+ DBusMessageIter iter, array_iter;
dbus_error_init(&derr);
- if (!dbus_message_get_args(msg, &derr,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID)) {
+ dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+ if (dbus_error_is_set(&derr)) {
err_invalid_args(connection, msg, derr.message);
+ dbus_error_free(&derr);
return DBUS_HANDLER_RESULT_HANDLED;
}
+
+ str2ba(address, &bda);
+
+ device = find_device(&bda);
+ if (device) {
+ const char *iface, *path = device->object_path;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &path);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ "s", &array_iter);
+ if (device->headset) {
+ iface = AUDIO_HEADSET_INTERFACE;
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &iface);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return send_message_and_unref(conn, reply);
+ }
+
+ device = add_device(&bda);
+ /*
+ resolve_services(conn, device, msg);
+ */
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult am_create_headset(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *path, *address;
+ bdaddr_t bda;
+ DBusMessage *reply;
+ DBusError derr;
+ audio_device_t *device;
+
+ dbus_error_init(&derr);
+ dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
if (dbus_error_is_set(&derr)) {
err_invalid_args(connection, msg, derr.message);
dbus_error_free(&derr);
return DBUS_HANDLER_RESULT_HANDLED;
}
+ str2ba(address, &bda);
+
+ device = find_device(&bda);
+ if (!device)
+ device = add_device(&bda);
+
+ if (!device)
+ return error_reply(connection, msg,
+ "org.bluez.audio.Error.Failed",
+ "Unable to create new audio device");
+
+ device->headset = headset_init(device->object_path);
+ if (!device->headset)
+ return error_reply(connection, msg,
+ "org.bluez.audio.Error.Failed",
+ "Unable to init Headset interface");
+
+ path = device->object_path;
+
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- str2ba(address, &bda);
-
- hs_path = headset_get(&bda);
- if (!hs_path) {
- hs_path = headset_add(&bda);
- if (!hs_path)
- return error_reply(connection, msg,
- "org.bluez.audio.Error.Failed",
- "Unable to create new headset object");
- manager_add_headset(hs_path);
- }
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &hs_path,
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
return send_message_and_unref(connection, reply);
}
+static gint device_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const audio_device_t *device = a;
+ const char *path = b;
+
+ return strcmp(device->object_path, path);
+}
+
static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *msg,
void *data)
{
DBusError derr;
DBusMessage *reply;
GSList *match;
- char *path;
+ const char *path;
+ audio_device_t *device;
dbus_error_init(&derr);
if (!dbus_message_get_args(msg, &derr,
@@ -209,7 +366,7 @@ static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *ms
return DBUS_HANDLER_RESULT_HANDLED;
}
- match = g_slist_find_custom(headsets, path, (GCompareFunc) strcmp);
+ match = g_slist_find_custom(devices, path, device_path_cmp);
if (!match)
return error_reply(connection, msg,
"org.bluez.audio.Error.DoesNotExist",
@@ -219,19 +376,24 @@ static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *ms
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- path = match->data;
+ device = match->data;
- headsets = g_slist_remove(headsets, path);
+ remove_device(device);
- if (default_hs == path) {
+ if (default_hs == device) {
const char *param;
+ GSList *l;
+
+ default_hs = NULL;
- if (!headsets)
- default_hs = NULL;
- else
- default_hs = headsets->data;
+ for (l = devices; l != NULL; l = l->next) {
+ device = l->data;
- param = default_hs ? default_hs : "";
+ if (device->headset)
+ default_hs = device;
+ }
+
+ param = default_hs ? default_hs->object_path : "";
dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
@@ -246,10 +408,6 @@ static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *ms
DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
- headset_remove(path);
-
- g_free(path);
-
return send_message_and_unref(connection, reply);
}
@@ -270,9 +428,18 @@ static DBusHandlerResult am_list_headsets(DBusConnection *conn, DBusMessage *msg
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING, &array_iter);
- for (l = headsets; l != NULL; l = l->next)
+ for (l = devices; l != NULL; l = l->next) {
+ audio_device_t *device = l->data;
+ const char *path;
+
+ if (!device->headset)
+ continue;
+
+ path = device->object_path;
+
dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_STRING, &l->data);
+ DBUS_TYPE_STRING, &path);
+ }
dbus_message_iter_close_container(&iter, &array_iter);
@@ -283,6 +450,7 @@ static DBusHandlerResult am_get_default_headset(DBusConnection *conn, DBusMessag
void *data)
{
DBusMessage *reply;
+ const char *path;
if (!default_hs)
return error_reply(connection, msg,
@@ -293,7 +461,9 @@ static DBusHandlerResult am_get_default_headset(DBusConnection *conn, DBusMessag
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_hs,
+ path = default_hs->object_path;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
return send_message_and_unref(connection, reply);
@@ -320,7 +490,7 @@ static DBusHandlerResult am_change_default_headset(DBusConnection *conn, DBusMes
return DBUS_HANDLER_RESULT_HANDLED;
}
- match = g_slist_find_custom(headsets, path, (GCompareFunc) strcmp);
+ match = g_slist_find_custom(devices, path, device_path_cmp);
if (!match)
return error_reply(connection, msg,
"org.bluez.audio.Error.DoesNotExist",
@@ -332,16 +502,20 @@ static DBusHandlerResult am_change_default_headset(DBusConnection *conn, DBusMes
default_hs = match->data;
+ path = default_hs->object_path;
+
dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
"DefaultHeadsetChanged",
- DBUS_TYPE_STRING, &default_hs,
+ DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
return send_message_and_unref(connection, reply);
}
static DBusMethodVTable manager_methods[] = {
+ { "CreateDevice", am_create_device,
+ "s", "sas" },
{ "CreateHeadset", am_create_headset,
"s", "s" },
{ "RemoveHeadset", am_remove_headset,
@@ -425,11 +599,9 @@ void audio_exit(void)
unix_sock = -1;
- if (headsets) {
- g_slist_foreach(headsets, (GFunc) manager_remove_headset, NULL);
- g_slist_free(headsets);
- headsets = NULL;
- }
+ g_slist_foreach(devices, (GFunc) remove_device, NULL);
+ g_slist_free(devices);
+ devices = NULL;
dbus_connection_unref(connection);