diff options
-rw-r--r-- | audio/headset.c | 308 |
1 files changed, 35 insertions, 273 deletions
diff --git a/audio/headset.c b/audio/headset.c index b2948da2..65e60e9e 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -57,6 +57,7 @@ #include "manager.h" #include "error.h" #include "headset.h" +#include "glib-helper.h" #define DC_TIMEOUT 3000 @@ -148,7 +149,7 @@ struct event { static int rfcomm_connect(struct device *device, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id); -static int get_handles(struct device *device, headset_stream_cb_t cb, +static int get_records(struct device *device, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id); static int headset_send(struct headset *hs, char *format, ...) @@ -733,33 +734,15 @@ static gboolean sco_cb(GIOChannel *chan, GIOCondition cond, return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, - struct device *dev) +static void rfcomm_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - struct headset *hs; - struct pending_connect *p; + struct device *dev = user_data; + struct headset *hs = dev->headset; + struct pending_connect *p = hs->pending; char hs_address[18]; - int sk, ret; - socklen_t len; - - if (cond & G_IO_NVAL) - return FALSE; - - hs = dev->headset; - p = hs->pending; - sk = g_io_channel_unix_get_fd(chan); - - len = sizeof(ret); - if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - p->err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(p->err), p->err); - goto failed; - } - - if (ret != 0) { - p->err = ret; - error("connect(): %s (%d)", strerror(ret), ret); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } @@ -779,7 +762,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, /* In HFP mode wait for Service Level Connection */ if (hs->hfp_active) - return FALSE; + return; headset_set_state(dev, HEADSET_STATE_CONNECTED); @@ -787,7 +770,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, p->err = sco_connect(dev, NULL, NULL, NULL); if (p->err < 0) goto failed; - return FALSE; + return; } if (p->msg) { @@ -797,7 +780,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, pending_connect_finalize(dev); - return FALSE; + return; failed: if (p->msg) @@ -807,56 +790,30 @@ failed: headset_set_state(dev, HEADSET_STATE_CONNECTED); else headset_set_state(dev, HEADSET_STATE_DISCONNECTED); - - return FALSE; } -static void get_record_reply(DBusPendingCall *call, void *data) +static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data) { - DBusMessage *reply; - DBusError derr; - uint8_t *array; - int array_len, record_len, err = EIO, ch = -1; + struct device *dev = user_data; + struct headset *hs = dev->headset; + struct pending_connect *p = hs->pending; + int ch = -1; sdp_record_t *record = NULL; sdp_list_t *protos, *classes = NULL; uuid_t uuid; - struct device *dev = data; - struct headset *hs = dev->headset; - struct pending_connect *p = hs->pending; - - reply = dbus_pending_call_steal_reply(call); - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - error("GetRemoteServiceRecord failed: %s", derr.message); - dbus_error_free(&derr); - goto failed_not_supported; - } - - dbus_error_init(&derr); - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &array, &array_len, - DBUS_TYPE_INVALID)) { - error("Unable to get args from GetRecordReply: %s", derr.message); - dbus_error_free(&derr); - goto failed_not_supported; - } - - if (!array) { - error("get_record_reply: Unable to get handle array from reply"); + if (err < 0) { + error("Unable to get service record: %s (%d)", strerror(-err), + -err); goto failed_not_supported; } - record = sdp_extract_pdu(array, &record_len); - if (!record) { - error("Unable to extract service record from reply"); + if (!recs || !recs->data) { + error("No records found"); goto failed_not_supported; } - if (record_len != array_len) - debug("warning: array len (%d) != record len (%d)", - array_len, record_len); + record = recs->data; if (sdp_get_service_classes(record, &classes) < 0) { error("Unable to get service classes from record"); @@ -909,9 +866,6 @@ static void get_record_reply(DBusPendingCall *call, void *data) sdp_list_free(classes, free); sdp_record_free(record); - dbus_message_unref(reply); - - device_finish_sdp_transaction(dev); return; @@ -926,157 +880,20 @@ failed: sdp_list_free(classes, free); if (record) sdp_record_free(record); - if (reply) - dbus_message_unref(reply); pending_connect_finalize(dev); headset_set_state(dev, HEADSET_STATE_DISCONNECTED); - device_finish_sdp_transaction(dev); } -static void get_handles_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *msg = NULL, *reply; - DBusPendingCall *pending; - DBusError derr; - struct device *dev = data; - struct headset *hs = dev->headset; - struct pending_connect *p = hs->pending; - char address[18], *addr_ptr = address; - dbus_uint32_t *array = NULL; - dbus_uint32_t handle; - int array_len; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - error("GetRemoteServiceHandles failed: %s", derr.message); - if (p->msg) { - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(dev->conn, p->msg, - EHOSTDOWN); - else - error_not_supported(dev->conn, p->msg); - } - dbus_error_free(&derr); - goto failed; - } - - dbus_error_init(&derr); - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, - &array, &array_len, - DBUS_TYPE_INVALID)) { - error("Unable to get args from reply: %s", derr.message); - dbus_error_free(&derr); - if (p->msg) - error_not_supported(dev->conn, p->msg); - goto failed; - } - - if (!array) { - error("get_handles_reply: Unable to get handle array from reply"); - if (p->msg) - error_not_supported(dev->conn, p->msg); - goto failed; - } - - if (array_len < 1) { - if (hs->search_hfp) { - debug("No record handles found for hfp"); - hs->search_hfp = FALSE; - get_handles(dev, NULL, NULL, NULL); - dbus_message_unref(reply); - return; - } - - debug("No record handles found for hsp"); - - if (p->msg) - error_not_supported(dev->conn, p->msg); - goto failed; - } - - if (array_len > 1) - debug("Multiple records found. Using the first one."); - - msg = dbus_message_new_method_call("org.bluez", dev->adapter_path, - "org.bluez.Adapter", - "GetRemoteServiceRecord"); - if (!msg) { - error("Unable to allocate new method call"); - if (p->msg) - error_out_of_memory(dev->conn, p->msg); - goto failed; - } - - ba2str(&dev->dst, address); - - handle = array[0]; - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_INVALID); - - if (!dbus_connection_send_with_reply(dev->conn, msg, &pending, -1)) { - error("Sending GetRemoteServiceRecord failed"); - if (p->msg) - error_connection_attempt_failed(dev->conn, p->msg, EIO); - goto failed; - } - - dbus_pending_call_set_notify(pending, get_record_reply, dev, NULL); - dbus_pending_call_unref(pending); - dbus_message_unref(msg); - dbus_message_unref(reply); - - return; - -failed: - if (msg) - dbus_message_unref(msg); - dbus_message_unref(reply); - p->err = EIO; - pending_connect_finalize(dev); - headset_set_state(dev, HEADSET_STATE_DISCONNECTED); -} - -static int get_handles(struct device *device, headset_stream_cb_t cb, +static int get_records(struct device *device, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id) { - DBusPendingCall *pending; struct headset *hs = device->headset; - const char *hs_svc; - const char *addr_ptr; - char hs_address[18]; - DBusMessage *msg; - - msg = dbus_message_new_method_call("org.bluez", device->adapter_path, - "org.bluez.Adapter", - "GetRemoteServiceHandles"); - if (!msg) { - error("Could not create a new dbus message"); - return -ENOMEM; - } - - if (hs->search_hfp) - hs_svc = "hfp"; - else - hs_svc = "hsp"; + uuid_t uuid; - ba2str(&device->dst, hs_address); - addr_ptr = hs_address; - dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_STRING, &hs_svc, - DBUS_TYPE_INVALID); + sdp_uuid16_create(&uuid, hs->search_hfp ? HANDSFREE_SVCLASS_ID : + HEADSET_SVCLASS_ID); headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS); - if (!dbus_connection_send_with_reply(device->conn, msg, &pending, -1)) { - error("Sending GetRemoteServiceHandles failed"); - dbus_message_unref(msg); - return -EIO; - } pending_connect_init(hs, HEADSET_STATE_CONNECTED); @@ -1088,75 +905,30 @@ static int get_handles(struct device *device, headset_stream_cb_t cb, *cb_id = id; } - dbus_pending_call_set_notify(pending, get_handles_reply, device, NULL); - - if (hs->pending) - hs->pending->call = pending; - else - dbus_pending_call_unref(pending); - - dbus_message_unref(msg); - - return 0; + return bt_search_service(&device->src, &device->dst, &uuid, + get_record_cb, device, NULL); } static int rfcomm_connect(struct device *dev, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id) { struct headset *hs = dev->headset; - struct sockaddr_rc addr; - GIOChannel *io; char address[18]; - int sk, err; + int err; if (hs->rfcomm_ch < 0) - return get_handles(dev, cb, user_data, cb_id); + return get_records(dev, cb, user_data, cb_id); ba2str(&dev->dst, address); debug("%s: Connecting to %s channel %d", dev->path, address, hs->rfcomm_ch); - sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (sk < 0) { - err = errno; - error("socket(BTPROTO_RFCOMM): %s (%d)", strerror(err), err); - return -err; - } - - io = g_io_channel_unix_new(sk); - if (!io) { - close(sk); - return -ENOMEM; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, BDADDR_ANY); - addr.rc_channel = 0; - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - err = errno; - error("bind: %s (%d)", strerror(errno), errno); - goto failed; - } - - if (set_nonblocking(sk) < 0) { - err = errno; - goto failed; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &dev->dst); - addr.rc_channel = hs->rfcomm_ch; - - err = connect(sk, (struct sockaddr *) &addr, sizeof(addr)); - - if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) { - err = errno; - error("connect() failed: %s (%d)", strerror(err), err); - goto failed; + err = bt_rfcomm_connect(&dev->src, &dev->dst, hs->rfcomm_ch, + rfcomm_connect_cb, dev); + if (err < 0) { + error("connect() failed: %s (%d)", strerror(-err), -err); + return err; } headset_set_state(dev, HEADSET_STATE_CONNECT_IN_PROGRESS); @@ -1170,17 +942,7 @@ static int rfcomm_connect(struct device *dev, headset_stream_cb_t cb, *cb_id = id; } - g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) rfcomm_connect_cb, dev); - - hs->pending->io = io; - return 0; - -failed: - g_io_channel_close(io); - g_io_channel_unref(io); - return -err; } static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg, |