diff options
Diffstat (limited to 'audio/headset.c')
-rw-r--r-- | audio/headset.c | 145 |
1 files changed, 77 insertions, 68 deletions
diff --git a/audio/headset.c b/audio/headset.c index 5c087312..723bc1ab 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -89,6 +89,8 @@ struct pending_connect { DBusMessage *msg; GIOChannel *io; guint io_id; + int sock; + struct ipc_data_cfg *cfg; }; struct headset { @@ -325,7 +327,7 @@ static void send_cancel_auth(audio_device_t *device) DBusMessage *cancel; char addr[18], *address = addr; const char *uuid; - + if (device->headset->type == SVC_HEADSET) uuid = HSP_AG_UUID; else @@ -475,9 +477,11 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond, g_io_add_watch(hs->sco, flags, (GIOFunc) sco_cb, device); - reply = dbus_message_new_method_return(hs->pending_connect->msg); - if (reply) - send_message_and_unref(connection, reply); + if (hs->pending_connect->msg) { + reply = dbus_message_new_method_return(hs->pending_connect->msg); + if (reply) + send_message_and_unref(connection, reply); + } pending_connect_free(hs->pending_connect); hs->pending_connect = NULL; @@ -514,6 +518,70 @@ failed: return FALSE; } +static int sco_connect(audio_device_t *device, struct pending_connect *c) +{ + struct headset *hs = device->headset; + struct sockaddr_sco addr; + gboolean do_callback = FALSE; + int sk, err; + + sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); + if (sk < 0) { + err = errno; + error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err); + return -err; + } + + c->io = g_io_channel_unix_new(sk); + if (!c->io) { + close(sk); + return -EINVAL; + } + + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + bacpy(&addr.sco_bdaddr, BDADDR_ANY); + + if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + err = errno; + error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err); + return -err; + } + + if (set_nonblocking(sk) < 0) { + err = errno; + return -err; + } + + memset(&addr, 0, sizeof(addr)); + addr.sco_family = AF_BLUETOOTH; + bacpy(&addr.sco_bdaddr, &device->bda); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (!(errno == EAGAIN || errno == EINPROGRESS)) { + err = errno; + error("connect: %s (%d)", strerror(errno), errno); + return -err; + } + + debug("SCO connect in progress"); + c->io_id = g_io_add_watch(c->io, + G_IO_OUT | G_IO_NVAL | G_IO_ERR | G_IO_HUP, + (GIOFunc) sco_connect_cb, device); + } else { + debug("SCO connect succeeded with first try"); + do_callback = TRUE; + } + + hs->state = HEADSET_STATE_PLAY_IN_PROGRESS; + hs->pending_connect = c; + + if (do_callback) + sco_connect_cb(c->io, G_IO_OUT, device); + + return 0; +} + static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, audio_device_t *device) { @@ -521,14 +589,14 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, char hs_address[18]; int sk, ret, err; socklen_t len; - + if (cond & G_IO_NVAL) return FALSE; hs = device->headset; assert(hs != NULL); - assert(hs->pending_connect != NULL); + assert(hs->pending_connect != NULL); assert(hs->rfcomm == NULL); assert(hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS); @@ -1406,10 +1474,7 @@ static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg, { audio_device_t *device = data; struct headset *hs = device->headset; - struct sockaddr_sco addr; struct pending_connect *c; - gboolean do_callback = FALSE; - int sk, err; if (hs->state < HEADSET_STATE_CONNECTED) return err_not_connected(connection, msg); @@ -1426,66 +1491,10 @@ static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg, c->msg = msg ? dbus_message_ref(msg) : NULL; - sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); - if (sk < 0) { - err = errno; - error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err); - err_connect_failed(connection, msg, err); - goto failed; - } - - c->io = g_io_channel_unix_new(sk); - if (!c->io) { - close(sk); - pending_connect_free(c); - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - memset(&addr, 0, sizeof(addr)); - addr.sco_family = AF_BLUETOOTH; - bacpy(&addr.sco_bdaddr, BDADDR_ANY); - - if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - err = errno; - error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err); - err_connect_failed(connection, msg, err); + if (sco_connect(device, c) < 0) goto failed; - } - - if (set_nonblocking(sk) < 0) { - err = errno; - err_connect_failed(connection, msg, err); - goto failed; - } - - memset(&addr, 0, sizeof(addr)); - addr.sco_family = AF_BLUETOOTH; - bacpy(&addr.sco_bdaddr, &device->bda); - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - if (!(errno == EAGAIN || errno == EINPROGRESS)) { - err = errno; - error("connect: %s (%d)", strerror(errno), errno); - goto failed; - } - - debug("SCO connect in progress"); - c->io_id = g_io_add_watch(c->io, - G_IO_OUT | G_IO_NVAL | G_IO_ERR | G_IO_HUP, - (GIOFunc) sco_connect_cb, device); - } else { - debug("SCO connect succeeded with first try"); - do_callback = TRUE; - } - - hs->state = HEADSET_STATE_PLAY_IN_PROGRESS; - hs->pending_connect = c; - - if (do_callback) - sco_connect_cb(c->io, G_IO_OUT, device); return 0; - failed: if (c) pending_connect_free(c); @@ -1772,7 +1781,7 @@ register_iface: } void headset_free(const char *object_path) -{ +{ audio_device_t *device; if (!dbus_connection_get_object_user_data(connection, object_path, @@ -2028,7 +2037,7 @@ void headset_exit(void) connection = NULL; } -int headset_get_config(headset_t *headset, struct ipc_data_cfg *cfg) +int headset_get_config(headset_t *headset, int sock, struct ipc_data_cfg *cfg) { if (!sco_over_hci) return -1; |