From c205cc889023e733e56365e82dfbaad2d2b46942 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 27 Jun 2007 16:58:19 +0000 Subject: Make headset also connect rfcomm when it demands, remove asserts and some code cleanups. --- audio/headset.c | 613 ++++++++++++++++++++++++++++---------------------------- audio/headset.h | 4 +- 2 files changed, 310 insertions(+), 307 deletions(-) diff --git a/audio/headset.c b/audio/headset.c index a57c3e93..1e8b640a 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -96,6 +95,7 @@ struct headset { static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg, void *data); +static int rfcomm_connect(struct device *device, struct pending_connect *c); static void pending_connect_free(struct pending_connect *c) { @@ -177,7 +177,6 @@ static void close_sco(struct device *device) g_io_channel_close(hs->sco); g_io_channel_unref(hs->sco); hs->sco = NULL; - assert(hs->rfcomm); hs->state = HEADSET_STATE_CONNECTED; dbus_connection_emit_signal(device->conn, device->path, AUDIO_HEADSET_INTERFACE, "Stopped", @@ -311,8 +310,6 @@ static GIOError headset_send(struct headset *hs, const char *str) GIOError err; gsize total_written, written, count; - assert(hs != NULL); - if (hs->state < HEADSET_STATE_CONNECTED || !hs->rfcomm) { error("headset_send: the headset is not connected"); return G_IO_ERROR_UNKNOWN; @@ -346,11 +343,6 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond, hs = device->headset; - assert(hs != NULL); - assert(hs->pending_connect != NULL); - assert(hs->sco == NULL); - assert(hs->state == HEADSET_STATE_PLAY_IN_PROGRESS); - sk = g_io_channel_unix_get_fd(chan); len = sizeof(ret); @@ -411,13 +403,16 @@ static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond, return FALSE; failed: - err_connect_failed(device->conn, hs->pending_connect->msg, strerror(err)); + if (hs->pending_connect->msg) + err_connect_failed(device->conn, hs->pending_connect->msg, + strerror(err)); if (hs->pending_connect->io) g_io_channel_close(hs->pending_connect->io); + if (hs->pending_connect->pkt) + unix_send_cfg(hs->pending_connect->sock, + hs->pending_connect->pkt); pending_connect_free(hs->pending_connect); hs->pending_connect = NULL; - - assert(hs->rfcomm); hs->state = HEADSET_STATE_CONNECTED; return FALSE; @@ -492,7 +487,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, { struct headset *hs; char hs_address[18]; - int sk, ret, err; + int sk, ret, err = 0; socklen_t len; if (cond & G_IO_NVAL) @@ -500,11 +495,6 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, hs = device->headset; - assert(hs != NULL); - assert(hs->pending_connect != NULL); - assert(hs->rfcomm == NULL); - assert(hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS); - sk = g_io_channel_unix_get_fd(chan); len = sizeof(ret); @@ -529,6 +519,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, AUDIO_HEADSET_INTERFACE, "Connected", DBUS_TYPE_INVALID); + device_store(device, FALSE); debug("Connected to %s", hs_address); g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL, @@ -541,6 +532,11 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, if (reply) send_message_and_unref(device->conn, reply); } + else if (hs->pending_connect->pkt) { + if (sco_connect(device, hs->pending_connect) < 0) + goto failed; + return FALSE; + } pending_connect_free(hs->pending_connect); hs->pending_connect = NULL; @@ -548,98 +544,24 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, return FALSE; failed: - err_connect_failed(device->conn, hs->pending_connect->msg, strerror(err)); + if (hs->pending_connect->msg) + err_connect_failed(device->conn, hs->pending_connect->msg, + strerror(err)); + if (hs->pending_connect->pkt) + unix_send_cfg(hs->pending_connect->sock, + hs->pending_connect->pkt); if (hs->pending_connect->io) g_io_channel_close(hs->pending_connect->io); + if (hs->rfcomm) + hs->state = HEADSET_STATE_CONNECTED; + else + hs->state = HEADSET_STATE_DISCONNECTED; pending_connect_free(hs->pending_connect); hs->pending_connect = NULL; - hs->state = HEADSET_STATE_DISCONNECTED; - return FALSE; } -static int rfcomm_connect(struct device *device, int *err) -{ - struct headset *hs = device->headset; - struct sockaddr_rc addr; - char address[18]; - int sk; - - assert(hs != NULL); - assert(hs->pending_connect != NULL); - assert(hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS); - - ba2str(&device->dst, address); - - debug("Connecting to %s channel %d", address, hs->rfcomm_ch); - - sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (sk < 0) { - if (err) - *err = errno; - error("socket: %s (%d)", strerror(errno), errno); - goto failed; - } - - 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) { - if (err) - *err = errno; - error("bind: %s (%d)", strerror(errno), errno); - goto failed; - } - - if (set_nonblocking(sk) < 0) { - if (err) - *err = errno; - goto failed; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &device->dst); - addr.rc_channel = hs->rfcomm_ch; - - hs->pending_connect->io = g_io_channel_unix_new(sk); - if (!hs->pending_connect->io) { - if (err) - *err = ENOMEM; - error("channel_unix_new failed in rfcomm connect"); - goto failed; - } - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - if (!(errno == EAGAIN || errno == EINPROGRESS)) { - if (err) - *err = errno; - error("connect() failed: %s (%d)", strerror(errno), - errno); - goto failed; - } - - debug("Connect in progress"); - - g_io_add_watch(hs->pending_connect->io, G_IO_OUT | G_IO_NVAL, - (GIOFunc) rfcomm_connect_cb, device); - } else { - debug("Connect succeeded with first try"); - rfcomm_connect_cb(hs->pending_connect->io, G_IO_OUT, device); - } - - return 0; - -failed: - if (!hs->pending_connect->io && sk >= 0) - close(sk); - - return -1; -} - static void get_record_reply(DBusPendingCall *call, void *data) { DBusMessage *reply; @@ -653,10 +575,6 @@ static void get_record_reply(DBusPendingCall *call, void *data) struct headset *hs = device->headset; struct pending_connect *c; - assert(hs != NULL); - assert(hs->pending_connect); - assert(!hs->rfcomm); - c = hs->pending_connect; reply = dbus_pending_call_steal_reply(call); @@ -726,10 +644,11 @@ static void get_record_reply(DBusPendingCall *call, void *data) hs->rfcomm_ch = ch; - if (rfcomm_connect(device, &err) < 0) { + if ((err = rfcomm_connect(device, NULL)) < 0) { error("Unable to connect"); if (c->msg) - err_connect_failed(device->conn, c->msg, strerror(err)); + err_connect_failed(device->conn, c->msg, + strerror(-err)); goto failed; } @@ -757,6 +676,228 @@ failed: device_finish_sdp_transaction(device); } +static void get_handles_reply(DBusPendingCall *call, void *data) +{ + DBusMessage *msg = NULL, *reply; + DBusPendingCall *pending; + DBusError derr; + struct device *device = data; + struct headset *hs = device->headset; + struct pending_connect *c; + char address[18], *addr_ptr = address; + dbus_uint32_t *array = NULL; + dbus_uint32_t handle; + int array_len; + + c = hs->pending_connect; + + 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 (c->msg) { + if (dbus_error_has_name(&derr, + "org.bluez.Error.ConnectionAttemptFailed")) + err_connect_failed(device->conn, c->msg, + strerror(EHOSTDOWN)); + else + err_not_supported(device->conn, c->msg); + } + dbus_error_free(&derr); + goto failed; + } + + if (!dbus_message_get_args(reply, NULL, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, + &array, &array_len, + DBUS_TYPE_INVALID)) { + error("Unable to get args from reply"); + if (c->msg) + err_not_supported(device->conn, c->msg); + goto failed; + } + + if (!array) { + error("get_handles_reply: Unable to get handle array from reply"); + if (c->msg) + err_not_supported(device->conn, c->msg); + goto failed; + } + + if (array_len < 1) { + debug("No record handles found"); + if (c->msg) + err_not_supported(device->conn, c->msg); + goto failed; + } + + if (array_len > 1) + debug("Multiple records found. Using the first one."); + + msg = dbus_message_new_method_call("org.bluez", device->adapter_path, + "org.bluez.Adapter", + "GetRemoteServiceRecord"); + if (!msg) { + error("Unable to allocate new method call"); + if (c->msg) + err_connect_failed(device->conn, c->msg, strerror(ENOMEM)); + goto failed; + } + + ba2str(&device->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(device->conn, msg, &pending, -1)) { + error("Sending GetRemoteServiceRecord failed"); + if (c->msg) + err_connect_failed(device->conn, c->msg, strerror(EIO)); + goto failed; + } + + dbus_pending_call_set_notify(pending, get_record_reply, device, 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); + hs_disconnect(NULL, NULL, device); +} + +static int get_handles(struct device *device) +{ + 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 -EINVAL; + } + + if (hs->type == SVC_HEADSET) + hs_svc = "hsp"; + else + hs_svc = "hfp"; + + 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); + + hs->state = 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; + } + + dbus_pending_call_set_notify(pending, get_handles_reply, device, NULL); + dbus_pending_call_unref(pending); + dbus_message_unref(msg); + + return 0; +} + +static int rfcomm_connect(struct device *device, struct pending_connect *c) +{ + struct headset *hs = device->headset; + struct sockaddr_rc addr; + char address[18]; + int sk, err; + + if (c != NULL) { + hs->pending_connect = c; + hs->type = hs->hfp_handle ? SVC_HANDSFREE : SVC_HEADSET; + + if (hs->state != HEADSET_STATE_DISCONNECTED) + return -EBUSY; + + if (hs->rfcomm_ch < 0) + return get_handles(device); + } + + ba2str(&device->dst, address); + + debug("Connecting to %s channel %d", address, hs->rfcomm_ch); + + sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (sk < 0) { + err = errno; + error("socket: %s (%d)", strerror(err), err); + goto failed; + } + + 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, &device->dst); + addr.rc_channel = hs->rfcomm_ch; + + hs->pending_connect->io = g_io_channel_unix_new(sk); + if (!hs->pending_connect->io) { + err = ENOMEM; + error("channel_unix_new failed in rfcomm connect"); + goto failed; + } + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (!(errno == EAGAIN || errno == EINPROGRESS)) { + err = errno; + error("connect() failed: %s (%d)", strerror(err), err); + goto failed; + } + + debug("Connect in progress"); + + g_io_add_watch(hs->pending_connect->io, G_IO_OUT | G_IO_NVAL, + (GIOFunc) rfcomm_connect_cb, device); + } else { + debug("Connect succeeded with first try"); + rfcomm_connect_cb(hs->pending_connect->io, G_IO_OUT, device); + } + + return 0; + +failed: + if (!hs->pending_connect->io && sk >= 0) + close(sk); + + return -err; +} + static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -800,8 +941,6 @@ static DBusHandlerResult hs_is_playing(DBusConnection *conn, DBusMessage *msg, DBusMessage *reply; dbus_bool_t playing; - assert(hs); - reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -815,7 +954,7 @@ static DBusHandlerResult hs_is_playing(DBusConnection *conn, DBusMessage *msg, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); - + return DBUS_HANDLER_RESULT_HANDLED; } @@ -827,8 +966,6 @@ static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg, DBusMessage *reply = NULL; char hs_address[18]; - assert(hs); - if (msg) { reply = dbus_message_new_method_return(msg); if (!reply) @@ -876,7 +1013,7 @@ static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg, if (reply) send_message_and_unref(conn, reply); - + return DBUS_HANDLER_RESULT_HANDLED; } @@ -898,194 +1035,43 @@ static DBusHandlerResult hs_is_connected(DBusConnection *conn, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); - - return DBUS_HANDLER_RESULT_HANDLED; -} -static void get_handles_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *msg = NULL, *reply; - DBusPendingCall *pending; - DBusError derr; - struct device *device = data; - struct headset *hs = device->headset; - struct pending_connect *c; - char address[18], *addr_ptr = address; - dbus_uint32_t *array = NULL; - dbus_uint32_t handle; - int array_len; - - assert(hs != NULL); - assert(hs->pending_connect); - - c = hs->pending_connect; - - 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 (c->msg) { - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - err_connect_failed(device->conn, c->msg, - strerror(EHOSTDOWN)); - else - err_not_supported(device->conn, c->msg); - } - dbus_error_free(&derr); - goto failed; - } - - if (!dbus_message_get_args(reply, NULL, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, - &array, &array_len, - DBUS_TYPE_INVALID)) { - error("Unable to get args from reply"); - if (c->msg) - err_not_supported(device->conn, c->msg); - goto failed; - } - - if (!array) { - error("get_handles_reply: Unable to get handle array from reply"); - if (c->msg) - err_not_supported(device->conn, c->msg); - goto failed; - } - - if (array_len < 1) { - debug("No record handles found"); - if (c->msg) - err_not_supported(device->conn, c->msg); - goto failed; - } - - if (array_len > 1) - debug("Multiple records found. Using the first one."); - - msg = dbus_message_new_method_call("org.bluez", device->adapter_path, - "org.bluez.Adapter", - "GetRemoteServiceRecord"); - if (!msg) { - error("Unable to allocate new method call"); - if (c->msg) - err_connect_failed(device->conn, c->msg, strerror(ENOMEM)); - goto failed; - } - - ba2str(&device->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(device->conn, msg, &pending, -1)) { - error("Sending GetRemoteServiceRecord failed"); - if (c->msg) - err_connect_failed(device->conn, c->msg, strerror(EIO)); - goto failed; - } - - dbus_pending_call_set_notify(pending, get_record_reply, device, 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); - hs_disconnect(NULL, NULL, device); + return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg, void *data) { - DBusPendingCall *pending; struct device *device = data; struct headset *hs = device->headset; - const char *hs_svc; - const char *addr_ptr; - char hs_address[18]; + struct pending_connect *c; int err; - assert(hs != NULL); - if (hs->state > HEADSET_STATE_DISCONNECTED || hs->pending_connect) return err_already_connected(conn, msg); - hs->pending_connect = g_try_new0(struct pending_connect, 1); - if (!hs->pending_connect) { + c = g_try_new0(struct pending_connect, 1); + if (!c) { error("Out of memory when allocating struct pending_connect"); return DBUS_HANDLER_RESULT_NEED_MEMORY; } - hs->state = HEADSET_STATE_CONNECT_IN_PROGRESS; - - hs->pending_connect->msg = msg ? dbus_message_ref(msg) : NULL; - - hs->type = hs->hfp_handle ? SVC_HANDSFREE : SVC_HEADSET; - - if (hs->rfcomm_ch > 0) { - if (rfcomm_connect(device, &err) < 0) { - error("Unable to connect"); - pending_connect_free(hs->pending_connect); - hs->pending_connect = NULL; - hs->state = HEADSET_STATE_DISCONNECTED; - return err_connect_failed(conn, msg, strerror(err)); - } else - return DBUS_HANDLER_RESULT_HANDLED; - } - - 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"); - pending_connect_free(hs->pending_connect); - hs->pending_connect = NULL; - hs->state = HEADSET_STATE_DISCONNECTED; - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - if (hs->type == SVC_HEADSET) - hs_svc = "hsp"; - else - hs_svc = "hfp"; - - 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); + c->msg = dbus_message_ref(msg); - if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) { - error("Sending GetRemoteServiceHandles failed"); - pending_connect_free(hs->pending_connect); - hs->pending_connect = NULL; - hs->state = HEADSET_STATE_DISCONNECTED; - dbus_message_unref(msg); - return err_connect_failed(conn, msg, strerror(EIO)); - } - - dbus_pending_call_set_notify(pending, get_handles_reply, device, NULL); - dbus_pending_call_unref(pending); - dbus_message_unref(msg); + if ((err = rfcomm_connect(device, c)) < 0) + goto error; - return DBUS_HANDLER_RESULT_HANDLED;; + return DBUS_HANDLER_RESULT_HANDLED; +error: + if (c) + pending_connect_free(c); + return err_connect_failed(conn, msg, strerror(-err)); } static gboolean ring_timer_cb(gpointer data) { struct device *device = data; - assert(device != NULL); - if (headset_send(device->headset, "\r\nRING\r\n") != G_IO_ERROR_NONE) error("Sending RING failed"); @@ -1099,8 +1085,6 @@ static DBusHandlerResult hs_ring(DBusConnection *conn, DBusMessage *msg, struct headset *hs = device->headset; DBusMessage *reply = NULL; - assert(hs != NULL); - if (hs->state < HEADSET_STATE_CONNECTED) return err_not_connected(conn, msg); @@ -1167,6 +1151,7 @@ static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg, struct device *device = data; struct headset *hs = device->headset; struct pending_connect *c; + int err; if (hs->state < HEADSET_STATE_CONNECTED) return err_not_connected(conn, msg); @@ -1183,13 +1168,11 @@ static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg, c->msg = msg ? dbus_message_ref(msg) : NULL; - if (sco_connect(device, c) < 0) - goto failed; - - return 0; -failed: - if (c) + err = sco_connect(device, c); + if (err < 0) { pending_connect_free(c); + return err_failed(conn, msg, strerror(-err)); + } return DBUS_HANDLER_RESULT_HANDLED; } @@ -1203,8 +1186,6 @@ static DBusHandlerResult hs_get_speaker_gain(DBusConnection *conn, DBusMessage *reply; dbus_uint16_t gain; - assert(hs); - if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0) return err_not_available(conn, msg); @@ -1218,7 +1199,7 @@ static DBusHandlerResult hs_get_speaker_gain(DBusConnection *conn, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); - + return DBUS_HANDLER_RESULT_HANDLED; } @@ -1231,8 +1212,6 @@ static DBusHandlerResult hs_get_mic_gain(DBusConnection *conn, DBusMessage *reply; dbus_uint16_t gain; - assert(hs); - if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0) return err_not_available(conn, msg); @@ -1246,7 +1225,7 @@ static DBusHandlerResult hs_get_mic_gain(DBusConnection *conn, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); - + return DBUS_HANDLER_RESULT_HANDLED; } @@ -1261,8 +1240,6 @@ static DBusHandlerResult hs_set_gain(DBusConnection *conn, dbus_uint16_t gain; char str[13]; - assert(hs); - if (hs->state < HEADSET_STATE_CONNECTED) return err_not_connected(conn, msg); @@ -1313,7 +1290,7 @@ done: } send_message_and_unref(conn, reply); - + return DBUS_HANDLER_RESULT_HANDLED; } @@ -1419,12 +1396,12 @@ void headset_update(void *device, sdp_record_t *record, uint16_t svc) } struct headset *headset_init(void *device, sdp_record_t *record, - uint16_t svc) + uint16_t svc, int channel) { struct headset *headset; headset = g_new0(struct headset, 1); - headset->rfcomm_ch = -1; + headset->rfcomm_ch = channel; headset->sp_gain = -1; headset->mic_gain = -1; @@ -1446,19 +1423,17 @@ struct headset *headset_init(void *device, sdp_record_t *record, return NULL; } + headset_set_channel(headset, record); register_iface: if (!dbus_connection_register_interface(((struct device *) device)->conn, - ((struct device *) device)->path, - AUDIO_HEADSET_INTERFACE, - headset_methods, - headset_signals, NULL)) { + ((struct device *) device)->path, + AUDIO_HEADSET_INTERFACE, + headset_methods, + headset_signals, NULL)) { g_free(headset); return NULL; } - if (record) - headset_set_channel(headset, record); - return headset; } @@ -1466,8 +1441,15 @@ void headset_free(void *device) { struct headset *headset = ((struct device *) device)->headset; - if (headset->state != HEADSET_STATE_DISCONNECTED) - hs_disconnect(NULL, NULL, device); + if (headset->sco) { + g_io_channel_close(headset->sco); + g_io_channel_unref(headset->sco); + } + + if (headset->rfcomm) { + g_io_channel_close(headset->rfcomm); + g_io_channel_unref(headset->rfcomm); + } g_free(headset); headset = NULL; @@ -1480,7 +1462,17 @@ int headset_get_config(void *device, int sock, struct ipc_packet *pkt) int err = EINVAL; struct pending_connect *c; - if (headset->sco == NULL) { + if (headset->rfcomm == NULL) { + c = g_try_new0(struct pending_connect, 1); + if (c == NULL) + goto error; + c->sock = sock; + c->pkt = pkt; + if ((err = rfcomm_connect(device, c)) < 0) + goto error; + return 0; + } + else if (headset->sco == NULL) { c = g_try_new0(struct pending_connect, 1); if (c == NULL) goto error; @@ -1502,6 +1494,8 @@ int headset_get_config(void *device, int sock, struct ipc_packet *pkt) return 0; error: + if (c) + pending_connect_free(c); cfg->fd = -1; return -err; } @@ -1579,3 +1573,10 @@ headset_state_t headset_get_state(void *device) return headset->state; } + +int headset_get_channel(void *device) +{ + struct headset *headset = ((struct device *) device)->headset; + + return headset->rfcomm_ch; +} diff --git a/audio/headset.h b/audio/headset.h index 470fddc8..8ef08249 100644 --- a/audio/headset.h +++ b/audio/headset.h @@ -55,7 +55,7 @@ typedef enum { struct headset; struct headset *headset_init(void *device, sdp_record_t *record, - uint16_t svc); + uint16_t svc, int channel); void headset_free(void *device); @@ -71,3 +71,5 @@ int headset_close_rfcomm(void *device); headset_state_t headset_get_state(void *device); void headset_set_state(void *device, headset_state_t state); + +int headset_get_channel(void *device); -- cgit