diff options
-rw-r--r-- | audio/a2dp.c | 2 | ||||
-rw-r--r-- | audio/control.c | 19 | ||||
-rw-r--r-- | audio/device.c | 332 | ||||
-rw-r--r-- | audio/device.h | 14 | ||||
-rw-r--r-- | audio/headset.c | 3 | ||||
-rw-r--r-- | audio/main.c | 90 | ||||
-rw-r--r-- | audio/manager.c | 816 | ||||
-rw-r--r-- | audio/manager.h | 2 | ||||
-rw-r--r-- | audio/sink.c | 3 | ||||
-rw-r--r-- | audio/unix.c | 30 |
10 files changed, 99 insertions, 1212 deletions
diff --git a/audio/a2dp.c b/audio/a2dp.c index 3e89d6b1..5e8cfd85 100644 --- a/audio/a2dp.c +++ b/audio/a2dp.c @@ -137,7 +137,7 @@ static struct audio_device *a2dp_get_dev(struct avdtp *session) avdtp_get_peers(session, NULL, &addr); - return manager_device_connected(&addr, A2DP_SOURCE_UUID); + return manager_find_device(&addr, NULL, FALSE); } static gboolean finalize_config(struct a2dp_setup *s) diff --git a/audio/control.c b/audio/control.c index 9139213b..02fb8cd1 100644 --- a/audio/control.c +++ b/audio/control.c @@ -583,17 +583,15 @@ static int uinput_create(char *name) static void init_uinput(struct avctp *session) { - char address[18], *name; + char address[18]; ba2str(&session->dst, address); - name = session->dev->name ? session->dev->name : address; - - session->uinput = uinput_create(name); + session->uinput = uinput_create(address); if (session->uinput < 0) - error("AVRCP: failed to init uinput for %s", name); + error("AVRCP: failed to init uinput for %s", address); else - debug("AVRCP: uinput initialized for %s", name); + debug("AVRCP: uinput initialized for %s", address); } static void avctp_connect_session(struct avctp *session) @@ -601,8 +599,10 @@ static void avctp_connect_session(struct avctp *session) GIOChannel *io; session->state = AVCTP_STATE_CONNECTED; - session->dev = manager_device_connected(&session->dst, - AVRCP_TARGET_UUID); + session->dev = manager_find_device(&session->dst, NULL, FALSE); + if (!session->dev) + return; + session->dev->control->session = session; init_uinput(session); @@ -923,6 +923,9 @@ struct control *control_init(struct audio_device *dev) dev, NULL)) return NULL; + info("Registered interface %s on path %s", + AUDIO_CONTROL_INTERFACE, dev->path); + return g_new0(struct control, 1); } diff --git a/audio/device.c b/audio/device.c index 2f5f834f..19ce3b41 100644 --- a/audio/device.c +++ b/audio/device.c @@ -54,114 +54,6 @@ #include "headset.h" #include "sink.h" -static DBusMessage *device_get_address(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct audio_device *device = data; - DBusMessage *reply; - char address[18], *ptr = address; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - ba2str(&device->dst, address); - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr, - DBUS_TYPE_INVALID); - - return reply; -} - -static char *get_dev_name(DBusConnection *conn, const bdaddr_t *src, - const bdaddr_t *bda) -{ - char address[18], filename[PATH_MAX + 1]; - - ba2str(src, address); - - /* check if it is in the cache */ - create_name(filename, PATH_MAX, STORAGEDIR, address, "names"); - - ba2str(bda, address); - return textfile_caseget(filename, address); -} - -static DBusMessage *device_get_name(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct audio_device *dev = data; - DBusMessage *reply; - const char *name = dev->name ? dev->name : ""; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID); - - return reply; -} - -static DBusMessage *device_get_adapter(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct audio_device *device = data; - DBusMessage *reply; - char address[18], *ptr = address; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - ba2str(&device->src, address); - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr, - DBUS_TYPE_INVALID); - - return reply; -} - - -static DBusMessage *device_get_connected(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - DBusMessageIter iter, array_iter; - struct audio_device *device = data; - DBusMessage *reply; - const char *iface; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_iter_init_append(reply, &iter); - - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, - &array_iter); - - if (device->headset && - headset_get_state(device) >= HEADSET_STATE_CONNECTED) { - iface = AUDIO_HEADSET_INTERFACE; - dbus_message_iter_append_basic(&array_iter, - DBUS_TYPE_STRING, &iface); - } - - dbus_message_iter_close_container(&iter, &array_iter); - - return reply; -} - -static GDBusMethodTable device_methods[] = { - { "GetAddress", "", "s", device_get_address }, - { "GetName", "", "s", device_get_name }, - { "GetAdapter", "", "s", device_get_adapter }, - { "GetConnectedInterfaces", "", "as", device_get_connected }, - { } -}; - static void device_free(struct audio_device *dev) { if (dev->headset) @@ -176,238 +68,29 @@ static void device_free(struct audio_device *dev) if (dev->conn) dbus_connection_unref(dev->conn); - g_free(dev->adapter_path); g_free(dev->path); - g_free(dev->name); - g_free(dev); } -static void device_unregister(void *data) -{ - struct audio_device *device = data; - - info("Unregistered device path:%s", device->path); - - device_free(device); -} - struct audio_device *device_register(DBusConnection *conn, - const char *path, const bdaddr_t *bda) + const char *path, const bdaddr_t *src, + const bdaddr_t *dst) { struct audio_device *dev; - bdaddr_t src; - int dev_id; if (!conn || !path) return NULL; - bacpy(&src, BDADDR_ANY); - dev_id = hci_get_route(&src); - if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0)) - return NULL; - dev = g_new0(struct audio_device, 1); - /* FIXME just to maintain compatibility */ - dev->adapter_path = g_strdup_printf("/org/bluez/hci%d", dev_id); - if (!dev->adapter_path) { - device_free(dev); - return NULL; - } - - if (!g_dbus_register_interface(conn, path, - AUDIO_DEVICE_INTERFACE, - device_methods, NULL, NULL, - dev, device_unregister)) { - error("Failed to register %s interface to %s", - AUDIO_DEVICE_INTERFACE, path); - device_free(dev); - return NULL; - } - - dev->name = get_dev_name(conn, &src, bda); dev->path = g_strdup(path); - bacpy(&dev->dst, bda); - bacpy(&dev->src, &src); - bacpy(&dev->store, &src); + bacpy(&dev->dst, dst); + bacpy(&dev->src, src); dev->conn = dbus_connection_ref(conn); return dev; } -int device_store(struct audio_device *dev, gboolean is_default) -{ - char value[64]; - char filename[PATH_MAX + 1]; - char src_addr[18], dst_addr[18]; - int offset = 0; - - if (!dev->path) - return -EINVAL; - - ba2str(&dev->dst, dst_addr); - ba2str(&dev->store, src_addr); - - create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio"); - create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - if (is_default) - textfile_put(filename, "default", dst_addr); - if (dev->headset) { - snprintf(value, 64, "headset "); - offset += strlen("headset "); - } - if (dev->gateway) { - snprintf(value + offset, 64 - offset, "gateway "); - offset += strlen("gateway "); - } - if (dev->sink) { - snprintf(value + offset, 64 - offset, "sink "); - offset += strlen("sink "); - } - if (dev->source) { - snprintf(value + offset, 64 - offset, "source "); - offset += strlen("source "); - } - if (dev->control) { - snprintf(value + offset, 64 - offset, "control "); - offset += strlen("control "); - } - if (dev->target) - snprintf(value + offset, 64 - offset, "target"); - - return textfile_put(filename, dst_addr, value); -} - -int device_remove_stored(struct audio_device *dev) -{ - char filename[PATH_MAX + 1]; - char src_addr[18], dst_addr[18]; - - ba2str(&dev->dst, dst_addr); - ba2str(&dev->store, src_addr); - - create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio"); - - return textfile_del(filename, dst_addr); -} - -void device_finish_sdp_transaction(struct audio_device *dev) -{ - char address[18], *addr_ptr = address; - DBusMessage *msg; - - ba2str(&dev->dst, address); - - msg = dbus_message_new_method_call("org.bluez", dev->adapter_path, - "org.bluez.Adapter", - "FinishRemoteServiceTransaction"); - if (!msg) { - error("Unable to allocate new method call"); - return; - } - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID); - - dbus_connection_send(dev->conn, msg, NULL); - - dbus_message_unref(msg); -} - -#if 0 -static avdtp_state_t ipc_to_avdtp_state(uint8_t ipc_state) -{ - switch (ipc_state) { - case STATE_DISCONNECTED: - return AVDTP_STATE_IDLE; - case STATE_CONNECTING: - return AVDTP_STATE_CONFIGURED; - case STATE_CONNECTED: - return AVDTP_STATE_OPEN; - case STATE_STREAM_STARTING: - case STATE_STREAMING: - return AVDTP_STATE_STREAMING; - default: - error("Unknown ipc state"); - return AVDTP_STATE_IDLE; - } -} - -static headset_state_t ipc_to_hs_state(uint8_t ipc_state) -{ - switch (ipc_state) { - case STATE_DISCONNECTED: - return HEADSET_STATE_DISCONNECTED; - case STATE_CONNECTING: - return HEADSET_STATE_CONNECT_IN_PROGRESS; - case STATE_CONNECTED: - return HEADSET_STATE_CONNECTED; - case STATE_STREAM_STARTING: - return HEADSET_STATE_PLAY_IN_PROGRESS; - case STATE_STREAMING: - return HEADSET_STATE_PLAYING; - default: - error("Unknown ipc state"); - return HEADSET_STATE_DISCONNECTED; - } -} - -static uint8_t avdtp_to_ipc_state(avdtp_state_t state) -{ - switch (state) { - case AVDTP_STATE_IDLE: - return STATE_DISCONNECTED; - case AVDTP_STATE_CONFIGURED: - return STATE_CONNECTING; - case AVDTP_STATE_OPEN: - return STATE_CONNECTED; - case AVDTP_STATE_STREAMING: - return STATE_STREAMING; - default: - error("Unknown avdt state"); - return AVDTP_STATE_IDLE; - } -} - -static uint8_t hs_to_ipc_state(headset_state_t state) -{ - switch (state) { - case HEADSET_STATE_DISCONNECTED: - return STATE_DISCONNECTED; - case HEADSET_STATE_CONNECT_IN_PROGRESS: - return STATE_CONNECTING; - case HEADSET_STATE_CONNECTED: - return STATE_CONNECTED; - case HEADSET_STATE_PLAY_IN_PROGRESS: - return STATE_STREAMING; - default: - error("Unknown headset state"); - return AVDTP_STATE_IDLE; - } -} - -uint8_t device_get_state(struct audio_device *dev) -{ - avdtp_state_t sink_state; - headset_state_t hs_state; - - if (dev->sink && sink_is_active(dev)) { - sink_state = sink_get_state(dev); - return avdtp_to_ipc_state(sink_state); - } - else if (dev->headset && headset_is_active(dev)) { - hs_state = headset_get_state(dev); - return hs_to_ipc_state(hs_state); - } - else if (dev->control && control_is_active(dev)) - return STATE_CONNECTED; - - return STATE_DISCONNECTED; -} -#endif - gboolean device_is_connected(struct audio_device *dev, const char *interface) { if (!interface) { @@ -433,3 +116,10 @@ gboolean device_is_connected(struct audio_device *dev, const char *interface) return FALSE; } + +void device_unregister(struct audio_device *device) +{ + g_dbus_unregister_all_interfaces(device->conn, device->path); + + device_free(device); +} diff --git a/audio/device.h b/audio/device.h index 5dc99b9d..96bb0705 100644 --- a/audio/device.h +++ b/audio/device.h @@ -54,10 +54,7 @@ struct gateway; struct audio_device { DBusConnection *conn; - char *adapter_path; char *path; - char *name; - bdaddr_t store; bdaddr_t src; bdaddr_t dst; @@ -70,14 +67,9 @@ struct audio_device { }; struct audio_device *device_register(DBusConnection *conn, - const char *path, const bdaddr_t *bda); + const char *path, const bdaddr_t *src, + const bdaddr_t *dst); -int device_store(struct audio_device *device, gboolean is_default); - -int device_remove_stored(struct audio_device *dev); - -void device_finish_sdp_transaction(struct audio_device *device); - -uint8_t device_get_state(struct audio_device *dev); +void device_unregister(struct audio_device *device); gboolean device_is_connected(struct audio_device *dev, const char *interface); diff --git a/audio/headset.c b/audio/headset.c index 0adc1e9d..7faab78c 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -1498,6 +1498,9 @@ register_iface: return NULL; } + info("Registered interface %s on path %s", + AUDIO_HEADSET_INTERFACE, dev->path); + return hs; } diff --git a/audio/main.c b/audio/main.c index f0301c12..0d0257dc 100644 --- a/audio/main.c +++ b/audio/main.c @@ -35,86 +35,11 @@ #include <dbus/dbus.h> #include "plugin.h" -#include "../hcid/device.h" #include "logging.h" #include "unix.h" #include "device.h" #include "manager.h" -static DBusConnection *conn; - -static int headset_probe(struct btd_device_driver *driver, - struct btd_device *device, GSList *records) -{ - const gchar *path = device_get_path(device); - DBG("path %s", path); - - return 0; -} - -static void headset_remove(struct btd_device_driver *driver, - struct btd_device *device) -{ - const gchar *path = device_get_path(device); - DBG("path %s", path); -} - -static struct btd_device_driver headset_driver = { - .name = "headset", - .uuids = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID), - .probe = headset_probe, - .remove = headset_remove, -}; - -static int a2dp_probe(struct btd_device_driver *driver, - struct btd_device *device, GSList *records) -{ - const gchar *path = device_get_path(device); - DBG("path %s", path); - - return 0; -} - -static void a2dp_remove(struct btd_device_driver *driver, - struct btd_device *device) -{ - const gchar *path = device_get_path(device); - DBG("path %s", path); -} - -static struct btd_device_driver a2dp_driver = { - .name = "sink", - .uuids = BTD_UUIDS(A2DP_SINK_UUID), - .probe = a2dp_probe, - .remove = a2dp_remove, -}; - -static int audio_probe(struct btd_device_driver *driver, - struct btd_device *device, GSList *records) -{ - const gchar *path = device_get_path(device); - DBG("path %s", path); - - return 0; -} - -static void audio_remove(struct btd_device_driver *driver, - struct btd_device *device) -{ - const gchar *path = device_get_path(device); - DBG("path %s", path); -} - -static struct btd_device_driver audio_driver = { - .name = "audio", - .uuids = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID, - ADVANCED_AUDIO_UUID, A2DP_SOURCE_UUID, A2DP_SINK_UUID, - AVRCP_TARGET_UUID, AVRCP_REMOTE_UUID), - .probe = audio_probe, - .remove = audio_remove, -}; - - static GKeyFile *load_config_file(const char *file) { GError *err = NULL; @@ -134,6 +59,7 @@ static GKeyFile *load_config_file(const char *file) static int audio_init(void) { + DBusConnection *conn; GKeyFile *config; conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); @@ -155,28 +81,14 @@ static int audio_init(void) if (config) g_key_file_free(config); - btd_register_device_driver(&headset_driver); - - btd_register_device_driver(&a2dp_driver); - - btd_register_device_driver(&audio_driver); - return 0; } static void audio_exit(void) { - btd_unregister_device_driver(&audio_driver); - - btd_unregister_device_driver(&a2dp_driver); - - btd_unregister_device_driver(&headset_driver); - audio_manager_exit(); unix_exit(); - - dbus_connection_unref(conn); } BLUETOOTH_PLUGIN_DEFINE("audio", audio_init, audio_exit) diff --git a/audio/manager.c b/audio/manager.c index 18ef9eb4..cb33158a 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -49,6 +49,8 @@ #include <gdbus.h> #include "glib-helper.h" +#include "../hcid/adapter.h" +#include "../hcid/device.h" #include "dbus-service.h" #include "logging.h" @@ -97,9 +99,6 @@ struct audio_sdp_data { static DBusConnection *connection = NULL; -static struct audio_device *default_hs = NULL; -static struct audio_device *default_dev = NULL; - static GSList *devices = NULL; static uint32_t hsp_ag_record_id = 0; @@ -120,74 +119,6 @@ static struct enabled_interfaces enabled = { .control = TRUE, }; -static DBusMessage *get_records(uuid_t *uuid, struct audio_sdp_data *data); - -static struct audio_device *create_device(const bdaddr_t *bda) -{ - static int device_id = 0; - char path[128]; - - snprintf(path, sizeof(path) - 1, - "%s/device%d", AUDIO_MANAGER_PATH, device_id++); - - return device_register(connection, path, bda); -} - -static void destroy_device(struct audio_device *device) -{ - g_dbus_unregister_all_interfaces(connection, device->path); -} - -static void remove_device(struct audio_device *device) -{ - if (device == default_dev) { - debug("Removing default device"); - default_dev = NULL; - } - - if (device == default_hs) { - debug("Removing default headset"); - default_hs = NULL; - } - - devices = g_slist_remove(devices, device); - - destroy_device(device); -} - -static gboolean add_device(struct audio_device *device, gboolean send_signals) -{ - if (!send_signals) - goto add; - - g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DeviceCreated", - DBUS_TYPE_STRING, &device->path, - DBUS_TYPE_INVALID); - - if (device->headset) - g_dbus_emit_signal(connection, - AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "HeadsetCreated", - DBUS_TYPE_STRING, &device->path, - DBUS_TYPE_INVALID); -add: - - if (default_dev == NULL && g_slist_length(devices) == 0) { - debug("Selecting default device"); - default_dev = device; - } - - if (!default_hs && device->headset && !devices) - default_hs = device; - - devices = g_slist_append(devices, device); - - return TRUE; -} - static uint16_t get_service_uuid(const sdp_record_t *record) { sdp_list_t *classes; @@ -254,7 +185,6 @@ gboolean server_is_enabled(uint16_t svc) static void handle_record(sdp_record_t *record, struct audio_device *device) { - gboolean is_default; uint16_t uuid16; uuid16 = get_service_uuid(record); @@ -311,666 +241,6 @@ static void handle_record(sdp_record_t *record, struct audio_device *device) debug("Unrecognized UUID: 0x%04X", uuid16); break; } - - is_default = (default_dev == device) ? TRUE : FALSE; - - device_store(device, is_default); -} - -static void finish_sdp(struct audio_sdp_data *data, gboolean success) -{ - const char *addr; - DBusMessage *reply = NULL; - DBusError derr; - - debug("Audio service discovery completed with %s", - success ? "success" : "failure"); - - if (!success) - goto done; - - if (!data->msg) - goto update; - - dbus_error_init(&derr); - dbus_message_get_args(data->msg, &derr, - DBUS_TYPE_STRING, &addr, - DBUS_TYPE_INVALID); - - if (dbus_error_is_set(&derr)) { - error("Unable to get message args"); - success = FALSE; - error_failed(connection, data->msg, derr.message); - dbus_error_free(&derr); - goto done; - } - - /* Return error if no audio related service records were found */ - if (!data->records) { - debug("No audio audio related service records were found"); - success = FALSE; - error_not_supported(connection, data->msg); - goto done; - } - - reply = dbus_message_new_method_return(data->msg); - if (!reply) { - success = FALSE; - error_failed(connection, data->msg, "Out of memory"); - goto done; - } - -update: - g_slist_foreach(data->records, (GFunc) handle_record, data->device); - - if (!g_slist_find(devices, data->device)) - add_device(data->device, TRUE); - - if (reply) { - dbus_message_append_args(reply, DBUS_TYPE_STRING, - &data->device->path, - DBUS_TYPE_INVALID); - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); - } - -done: - if (success) { - if (data->cb) - data->cb(data->device, data->cb_data); - } else { - if (data->cb) - data->cb(NULL, data->cb_data); - if (!g_slist_find(devices, data->device)) - destroy_device(data->device); - } - if (data->msg) - dbus_message_unref(data->msg); - g_slist_foreach(data->records, (GFunc) sdp_record_free, NULL); - g_slist_free(data->records); - g_free(data); -} - -static void get_records_cb(sdp_list_t *recs, int err, gpointer user_data) -{ - struct audio_sdp_data *data = user_data; - sdp_list_t *seq; - uuid_t uuid; - - if (err < 0) { - error_connection_attempt_failed(connection, data->msg, -err); - finish_sdp(data, FALSE); - return; - } - - for (seq = recs; seq; seq = seq->next) { - sdp_record_t *rec = (sdp_record_t *) seq->data; - - if (!rec) - break; - - data->records = g_slist_append(data->records, rec); - } - - sdp_list_free(recs, NULL); - - data->state++; - - switch (data->state) { - case ADVANCED_AUDIO: - sdp_uuid16_create(&uuid, ADVANCED_AUDIO_SVCLASS_ID); - break; - case AV_REMOTE: - sdp_uuid16_create(&uuid, AV_REMOTE_SVCLASS_ID); - break; - default: - finish_sdp(data, TRUE); - return; - } - - get_records(&uuid, data); -} - -static DBusMessage *get_records(uuid_t *uuid, struct audio_sdp_data *data) -{ - struct audio_device *device = data->device; - DBusMessage *reply = NULL; - int err; - - err = bt_search_service(&device->src, &device->dst, uuid, - get_records_cb, data, NULL); - if (!err) - return NULL; - - if (data->msg) - reply = g_dbus_create_error(data->msg, - ERROR_INTERFACE ".ConnectionAttemptFailed", - strerror(-err)); - - finish_sdp(data, FALSE); - - return reply; -} - -static DBusMessage *resolve_services(DBusMessage *msg, - struct audio_device *device, - create_dev_cb_t cb, - void *user_data) -{ - struct audio_sdp_data *sdp_data; - uuid_t uuid; - - sdp_data = g_new0(struct audio_sdp_data, 1); - if (msg) - sdp_data->msg = dbus_message_ref(msg); - sdp_data->device = device; - sdp_data->cb = cb; - sdp_data->cb_data = user_data; - - sdp_uuid16_create(&uuid, GENERIC_AUDIO_SVCLASS_ID); - - return get_records(&uuid, sdp_data); -} - -struct audio_device *manager_device_connected(const bdaddr_t *bda, const char *uuid) -{ - struct audio_device *device; - const char *path; - gboolean headset = FALSE, created = FALSE; - - device = manager_find_device(bda, NULL, FALSE); - if (!device) { - device = create_device(bda); - if (!device) - return NULL; - if (!add_device(device, TRUE)) { - destroy_device(device); - return NULL; - } - created = TRUE; - } - - if (!strcmp(uuid, HSP_AG_UUID) || !strcmp(uuid, HFP_AG_UUID)) { - if (device->headset) - return device; - - device->headset = headset_init(device, NULL, 0); - - if (!device->headset) - return NULL; - - headset = TRUE; - } else if (!strcmp(uuid, A2DP_SOURCE_UUID)) { - if (device->sink) - return device; - - device->sink = sink_init(device); - - if (!device->sink) - return NULL; - } else if (!strcmp(uuid, AVRCP_TARGET_UUID)) { - if (device->control) - return device; - - device->control = control_init(device); - - if (!device->control) - return NULL; - } else - return NULL; - - path = device->path; - - if (created) { - g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DeviceCreated", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - resolve_services(NULL, device, NULL, NULL); - } - - if (headset) - g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "HeadsetCreated", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - if (headset && !default_hs) { - default_hs = device; - g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DefaultHeadsetChanged", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - } - - if (!default_dev) { - default_dev = device; - g_dbus_emit_signal(connection, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DefaultDeviceChanged", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - } - - return device; -} - -gboolean manager_create_device(bdaddr_t *bda, create_dev_cb_t cb, - void *user_data) -{ - struct audio_device *dev; - - dev = create_device(bda); - if (!dev) - return FALSE; - - resolve_services(NULL, dev, cb, user_data); - - return TRUE; -} - -static DBusMessage *am_create_device(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - const char *address, *path; - bdaddr_t bda; - struct audio_device *device; - DBusMessage *reply; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) - return NULL; - - str2ba(address, &bda); - - device = manager_find_device(&bda, NULL, FALSE); - if (!device) { - device = create_device(&bda); - return resolve_services(msg, device, NULL, NULL); - } - - path = device->path; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - return reply; -} - -static DBusMessage *am_list_devices(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessageIter iter, array_iter; - DBusMessage *reply; - DBusError derr; - GSList *l; - gboolean hs_only = FALSE; - - dbus_error_init(&derr); - - if (dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE, - "ListHeadsets")) - hs_only = TRUE; - else - hs_only = FALSE; - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_iter_init_append(reply, &iter); - - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &array_iter); - - for (l = devices; l != NULL; l = l->next) { - struct audio_device *device = l->data; - - if (hs_only && !device->headset) - continue; - - dbus_message_iter_append_basic(&array_iter, - DBUS_TYPE_STRING, &device->path); - } - - dbus_message_iter_close_container(&iter, &array_iter); - - return reply; -} - -static gint device_path_cmp(gconstpointer a, gconstpointer b) -{ - const struct audio_device *device = a; - const char *path = b; - - return strcmp(device->path, path); -} - -static DBusMessage *am_remove_device(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessage *reply; - GSList *match; - const char *path; - struct audio_device *device; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID)) - return NULL; - - match = g_slist_find_custom(devices, path, device_path_cmp); - if (!match) - return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists", - "Device does not exists"); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - device = match->data; - device_remove_stored(device); - remove_device(device); - - /* Fallback to a valid default */ - if (default_dev == NULL) { - const char *param; - GSList *l; - - default_dev = manager_find_device(BDADDR_ANY, NULL, TRUE); - - if (!default_dev && devices) { - l = devices; - default_dev = (g_slist_last(l))->data; - } - - param = default_dev ? default_dev->path : ""; - - g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DefaultHeadsetChanged", - DBUS_TYPE_STRING, ¶m, - DBUS_TYPE_INVALID); - - g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DefaultDeviceChanged", - DBUS_TYPE_STRING, ¶m, - DBUS_TYPE_INVALID); - - if (default_dev) - device_store(default_dev, TRUE); - } - - g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "HeadsetRemoved", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DeviceRemoved", - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); - - return reply; -} - -static DBusMessage *am_find_by_addr(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - const char *address; - DBusMessage *reply; - struct audio_device *device; - bdaddr_t bda; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &address, - DBUS_TYPE_INVALID)) - return NULL; - - str2ba(address, &bda); - device = manager_find_device(&bda, NULL, FALSE); - - if (!device) - return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists", - "Device does not exists"); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &device->path, - DBUS_TYPE_INVALID); - - return reply; -} - -static DBusMessage *am_default_device(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessage *reply; - - if (!default_dev) - return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists", - "Device does not exists"); - - if (default_dev->headset == NULL && - dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE, - "DefaultHeadset")) - return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists", - "Device does not exists"); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_dev->path, - DBUS_TYPE_INVALID); - - return reply; -} - -static DBusMessage *am_change_default_device(DBusConnection *conn, - DBusMessage *msg, - void *data) -{ - DBusMessage *reply; - GSList *match; - const char *path; - struct audio_device *device; - - if (!dbus_message_get_args(msg, NULL, - DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID)) - return NULL; - - match = g_slist_find_custom(devices, path, device_path_cmp); - if (!match) - return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists", - "Device does not exists"); - - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; - - device = match->data; - - if (!dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE, - "ChangeDefaultHeadset")) - g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DefaultDeviceChanged", - DBUS_TYPE_STRING, &device->path, - DBUS_TYPE_INVALID); - else if (device->headset) - g_dbus_emit_signal(conn, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - "DefaultHeadsetChanged", - DBUS_TYPE_STRING, &device->path, - DBUS_TYPE_INVALID); - else - return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExists", - "Device does not exists"); - - default_dev = device; - device_store(device, TRUE); - - return reply; -} - -static GDBusMethodTable manager_methods[] = { - { "CreateDevice", "s", "s", am_create_device, - G_DBUS_METHOD_FLAG_ASYNC }, - { "RemoveDevice", "s", "", am_remove_device }, - { "ListDevices", "", "as", am_list_devices }, - { "DefaultDevice", "", "s", am_default_device }, - { "ChangeDefaultDevice", "s", "", am_change_default_device }, - { "CreateHeadset", "s", "s", am_create_device, - G_DBUS_METHOD_FLAG_ASYNC }, - { "RemoveHeadset", "s", "", am_remove_device }, - { "ListHeadsets", "", "as", am_list_devices }, - { "FindDeviceByAddress", "s", "s", am_find_by_addr }, - { "DefaultHeadset", "", "s", am_default_device }, - { "ChangeDefaultHeadset", "s", "", am_change_default_device }, - { } -}; - -static GDBusSignalTable manager_signals[] = { - { "DeviceCreated", "s" }, - { "DeviceRemoved", "s" }, - { "HeadsetCreated", "s" }, - { "HeadsetRemoved", "s" }, - { "DefaultDeviceChanged", "s" }, - { "DefaultHeadsetChanged", "s" }, - { } -}; - -static void parse_stored_devices(char *key, char *value, void *data) -{ - bdaddr_t *src = data; - struct audio_device *device; - bdaddr_t dst; - - if (!key || !value || strcmp(key, "default") == 0) - return; - - str2ba(key, &dst); - device = manager_find_device(&dst, NULL, FALSE); - - if (device) - return; - - info("Loading device %s (%s)", key, value); - - device = create_device(&dst); - if (!device) - return; - - /* Change storage to source adapter */ - bacpy(&device->store, src); - - if (enabled.headset && strstr(value, "headset")) - device->headset = headset_init(device, NULL, 0); - if (enabled.sink && strstr(value, "sink")) - device->sink = sink_init(device); - if (enabled.control && strstr(value, "control")) - device->control = control_init(device); - add_device(device, FALSE); -} - -static void register_devices_stored(const char *adapter) -{ - char filename[PATH_MAX + 1]; - struct stat st; - struct audio_device *device; - bdaddr_t default_src; - bdaddr_t dst; - bdaddr_t src; - char *addr; - int dev_id; - - create_name(filename, PATH_MAX, STORAGEDIR, adapter, "audio"); - - str2ba(adapter, &src); - - if (stat(filename, &st) < 0) - return; - - if (!(st.st_mode & __S_IFREG)) - return; - - textfile_foreach(filename, parse_stored_devices, &src); - - bacpy(&default_src, BDADDR_ANY); - dev_id = hci_get_route(&default_src); - if (dev_id < 0 || hci_devba(dev_id, &default_src) < 0) - return; - - if (bacmp(&default_src, &src) != 0) - return; - - addr = textfile_get(filename, "default"); - if (!addr) - return; - - str2ba(addr, &dst); - device = manager_find_device(&dst, NULL, FALSE); - - if (device) { - info("Setting %s as default device", addr); - default_dev = device; - } - - free(addr); -} - -static void register_stored(void) -{ - char dirname[PATH_MAX + 1]; - struct dirent *de; - DIR *dir; - - snprintf(dirname, PATH_MAX, "%s", STORAGEDIR); - - dir = opendir(dirname); - if (!dir) - return; - - while ((de = readdir(dir)) != NULL) { - if (!isdigit(de->d_name[0])) - continue; - - /* Device objects */ - register_devices_stored(de->d_name); - } - - closedir(dir); -} - -static void manager_unregister(void *data) -{ - info("Unregistered manager path"); - - if (devices) { - g_slist_foreach(devices, (GFunc) remove_device, NULL); - g_slist_free(devices); - devices = NULL; - } } static sdp_record_t *hsp_ag_record(uint8_t ch) @@ -1201,7 +471,7 @@ static void ag_io_cb(GIOChannel *chan, int err, const bdaddr_t *src, uuid = HFP_AG_UUID; } - device = manager_device_connected(dst, uuid); + device = manager_find_device(dst, NULL, FALSE); if (!device) goto drop; @@ -1416,6 +686,61 @@ static void server_exit(void) } } +static int audio_probe(struct btd_device_driver *driver, + struct btd_device *device, GSList *records) +{ + struct adapter *adapter = device_get_adapter(device); + const gchar *path = device_get_path(device); + const char *source, *destination; + bdaddr_t src, dst; + struct audio_device *dev; + + source = adapter_get_address(adapter); + destination = device_get_address(device); + + str2ba(source, &src); + str2ba(destination, &dst); + + dev = manager_find_device(&dst, NULL, FALSE); + if (!dev) { + dev = device_register(connection, path, &src, &dst); + if (!dev) + return -EINVAL; + devices = g_slist_append(devices, dev); + } + + g_slist_foreach(records, (GFunc) handle_record, dev); + + return 0; +} + +static void audio_remove(struct btd_device_driver *driver, + struct btd_device *device) +{ + struct audio_device *dev; + const char *destination = device_get_address(device); + bdaddr_t dst; + + str2ba(destination, &dst); + + dev = manager_find_device(&dst, NULL, FALSE); + if (!dev) + return; + + devices = g_slist_remove(devices, dev); + + device_unregister(dev); +} + +static struct btd_device_driver audio_driver = { + .name = "audio", + .uuids = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID, + ADVANCED_AUDIO_UUID, A2DP_SOURCE_UUID, A2DP_SINK_UUID, + AVRCP_TARGET_UUID, AVRCP_REMOTE_UUID), + .probe = audio_probe, + .remove = audio_remove, +}; + int audio_manager_init(DBusConnection *conn, GKeyFile *config) { char **list; @@ -1477,18 +802,7 @@ proceed: if (enabled.control && avrcp_init(conn, config) < 0) goto failed; - if (!g_dbus_register_interface(conn, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE, - manager_methods, manager_signals, - NULL, NULL, manager_unregister)) { - error("Failed to register %s interface to %s", - AUDIO_MANAGER_INTERFACE, AUDIO_MANAGER_PATH); - goto failed; - } - - info("Registered manager path:%s", AUDIO_MANAGER_PATH); - - register_stored(); + btd_register_device_driver(&audio_driver); return 0; failed: @@ -1500,17 +814,11 @@ void audio_manager_exit(void) { server_exit(); - g_dbus_unregister_interface(connection, AUDIO_MANAGER_PATH, - AUDIO_MANAGER_INTERFACE); - dbus_connection_unref(connection); - connection = NULL; -} + btd_unregister_device_driver(&audio_driver); -struct audio_device *manager_default_device(void) -{ - return default_dev; + connection = NULL; } struct audio_device *manager_get_connected_device(void) @@ -1537,7 +845,7 @@ struct audio_device *manager_find_device(const bdaddr_t *bda, const char *interf GSList *l; if (!bacmp(bda, BDADDR_ANY) && !interface && !connected) - return default_dev; + return devices->data; for (l = devices; l != NULL; l = l->next) { struct audio_device *dev = l->data; diff --git a/audio/manager.h b/audio/manager.h index 8f7f6be3..701511a1 100644 --- a/audio/manager.h +++ b/audio/manager.h @@ -44,7 +44,5 @@ gboolean server_is_enabled(uint16_t svc); struct audio_device *manager_find_device(const bdaddr_t *bda, const char *interface, gboolean connected); -struct audio_device *manager_device_connected(const bdaddr_t *bda, const char *uuid); - gboolean manager_create_device(bdaddr_t *bda, create_dev_cb_t cb, void *user_data); diff --git a/audio/sink.c b/audio/sink.c index 2af74bb3..0aa14542 100644 --- a/audio/sink.c +++ b/audio/sink.c @@ -502,6 +502,9 @@ struct sink *sink_init(struct audio_device *dev) dev, NULL)) return NULL; + info("Registered interface %s on path %s", + AUDIO_SINK_INTERFACE, dev->path); + return g_new0(struct sink, 1); } diff --git a/audio/unix.c b/audio/unix.c index 93f5788b..10e6021e 100644 --- a/audio/unix.c +++ b/audio/unix.c @@ -744,16 +744,6 @@ failed: unix_ipc_error(client, BT_STREAMSTOP_RSP, EIO); } -static void create_cb(struct audio_device *dev, void *user_data) -{ - struct unix_client *client = user_data; - - if (!dev) - unix_ipc_error(client, BT_GETCAPABILITIES_RSP, EIO); - else - start_discovery(dev, client); -} - static void handle_getcapabilities_req(struct unix_client *client, struct bt_getcapabilities_req *req) { @@ -772,15 +762,8 @@ static void handle_getcapabilities_req(struct unix_client *client, else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP) client->interface = g_strdup(AUDIO_SINK_INTERFACE); - if (!manager_find_device(&bdaddr, NULL, FALSE)) { - if (!(req->flags & BT_FLAG_AUTOCONNECT)) - goto failed; - if (!bacmp(&bdaddr, BDADDR_ANY)) - goto failed; - if (!manager_create_device(&bdaddr, create_cb, client)) - goto failed; - return; - } + if (!manager_find_device(&bdaddr, NULL, FALSE)) + goto failed; dev = manager_find_device(&bdaddr, client->interface, TRUE); if (!dev) { @@ -918,13 +901,8 @@ static void handle_setconfiguration_req(struct unix_client *client, } } - if (!manager_find_device(&bdaddr, NULL, FALSE)) { - if (!bacmp(&bdaddr, BDADDR_ANY)) - goto failed; - if (!manager_create_device(&bdaddr, create_cb, client)) - goto failed; - return; - } + if (!manager_find_device(&bdaddr, NULL, FALSE)) + goto failed; dev = manager_find_device(&bdaddr, client->interface, TRUE); if (!dev) |