📄 headset.c
字号:
socklen_t len; if (cond & G_IO_NVAL) return FALSE; hs = device->headset; c = hs->pending->data; sk = g_io_channel_unix_get_fd(chan); len = sizeof(ret); if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { c->err = errno; error("getsockopt(SO_ERROR): %s (%d)", strerror(c->err), c->err); goto failed; } if (ret != 0) { c->err = ret; error("connect(): %s (%d)", strerror(ret), ret); goto failed; } ba2str(&device->dst, hs_address); hs->rfcomm = chan; c->io = NULL; headset_set_state(device, HEADSET_STATE_CONNECTED); debug("%s: Connected to %s", device->path, hs_address); g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL, (GIOFunc) rfcomm_io_cb, device); if (c->cb) { if (sco_connect(device, c) < 0) { c->err = EIO; goto failed; } return FALSE; } g_slist_foreach(hs->pending, (GFunc) pending_connect_ok, device); g_slist_free(hs->pending); hs->pending = NULL; return FALSE;failed: g_slist_foreach(hs->pending, (GFunc) pending_connect_failed, device); g_slist_free(hs->pending); hs->pending = NULL; if (hs->rfcomm) headset_set_state(device, HEADSET_STATE_CONNECTED); else headset_set_state(device, HEADSET_STATE_DISCONNECTED); return FALSE;}static void get_record_reply(DBusPendingCall *call, void *data){ DBusMessage *reply; DBusError derr; uint8_t *array; int array_len, record_len, err = EIO, ch = -1; sdp_record_t *record = NULL; sdp_list_t *protos, *classes = NULL; uuid_t uuid; struct device *device = data; struct headset *hs = device->headset; struct pending_connect *c; unsigned int id; c = hs->pending->data; 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"); goto failed_not_supported; } record = sdp_extract_pdu(array, &record_len); if (!record) { error("Unable to extract service record from reply"); goto failed_not_supported; } if (record_len != array_len) debug("warning: array len (%d) != record len (%d)", array_len, record_len); if (sdp_get_service_classes(record, &classes) < 0) { error("Unable to get service classes from record"); goto failed_not_supported; } memcpy(&uuid, classes->data, sizeof(uuid)); if (!sdp_uuid128_to_uuid(&uuid)) { error("Not a 16 bit UUID"); goto failed_not_supported; } id = hs->enable_hfp ? HANDSFREE_SVCLASS_ID : HEADSET_SVCLASS_ID; if ((uuid.type == SDP_UUID32 && uuid.value.uuid32 != id) || (uuid.type == SDP_UUID16 && uuid.value.uuid16 != id)) { error("Service classes did not contain the expected UUID"); goto failed_not_supported; } if (!sdp_get_access_protos(record, &protos)) { ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); protos = NULL; } if (ch == -1) { error("Unable to extract RFCOMM channel from service record"); goto failed_not_supported; } hs->rfcomm_ch = ch; err = rfcomm_connect(device, NULL); if (err < 0) { error("Unable to connect: %s (%s)", strerror(-err), -err); c->err = -err; goto failed; } sdp_list_free(classes, free); sdp_record_free(record); dbus_message_unref(reply); device_finish_sdp_transaction(device); return;failed_not_supported: if (c->msg) { error_not_supported(device->conn, c->msg); dbus_message_unref(c->msg); c->msg = NULL; }failed: if (classes) sdp_list_free(classes, free); if (record) sdp_record_free(record); if (reply) dbus_message_unref(reply); g_slist_foreach(hs->pending, (GFunc) pending_connect_failed, device); g_slist_free(hs->pending); hs->pending = NULL; headset_set_state(device, HEADSET_STATE_DISCONNECTED); 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->data; 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")) error_connection_attempt_failed(device->conn, c->msg, EHOSTDOWN); else error_not_supported(device->conn, c->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 (c->msg) error_not_supported(device->conn, c->msg); goto failed; } if (!array) { error("get_handles_reply: Unable to get handle array from reply"); if (c->msg) error_not_supported(device->conn, c->msg); goto failed; } if (array_len < 1) { if(hs->type == SVC_HANDSFREE) { debug("No record handles found for hfp"); hs->type = SVC_HEADSET; get_handles(device, c); dbus_message_unref(reply); return; } debug("No record handles found for hsp"); if (c->msg) error_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) error_out_of_memory(device->conn, c->msg); 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) error_connection_attempt_failed(device->conn, c->msg, 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); /* The reply was already sent above */ if (c->msg) { dbus_message_unref(c->msg); c->msg = NULL; } dbus_message_unref(reply); g_slist_foreach(hs->pending, (GFunc) pending_connect_failed, device); g_slist_free(hs->pending); hs->pending = NULL; headset_set_state(device, HEADSET_STATE_DISCONNECTED);}static int get_handles(struct device *device, struct pending_connect *c){ 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); 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; } dbus_pending_call_set_notify(pending, get_handles_reply, device, NULL); if (c) c->call = pending; else 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) { if (!g_slist_find(hs->pending, c)) hs->pending = g_slist_append(hs->pending, c); hs->type = hs->enable_hfp ? SVC_HANDSFREE : SVC_HEADSET; if (hs->state == HEADSET_STATE_DISCONNECTED) return get_handles(device, c); else return 0; } else c = hs->pending->data; ba2str(&device->dst, address); debug("%s: Connecting to %s channel %d", device->path, 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; c->io = g_io_channel_unix_new(sk); if (!c->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; } g_io_add_watch(c->io, G_IO_OUT | G_IO_NVAL, (GIOFunc) rfcomm_connect_cb, device); } else rfcomm_connect_cb(c->io, G_IO_OUT, device); return 0;failed: if (!c->io && sk >= 0) close(sk); return -err;}static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (hs->state < HEADSET_STATE_PLAY_IN_PROGRESS) return error_not_connected(conn, msg); headset_set_state(device, HEADSET_STATE_CONNECTED); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_is_playing(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply; dbus_bool_t playing; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; playing = (hs->state == HEADSET_STATE_PLAYING); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; char hs_address[18]; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (hs->state == HEADSET_STATE_DISCONNECTED) return error_not_connected(conn, msg); headset_set_state(device, HEADSET_STATE_DISCONNECTED); ba2str(&device->dst, hs_address); info("Disconnected from %s, %s", hs_address, device->path); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_is_connected(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; DBusMessage *reply; dbus_bool_t connected; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; connected = (device->headset->state >= HEADSET_STATE_CONNECTED); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; struct pending_connect *c; int err; if (hs->state > HEADSET_STATE_DISCONNECTED) return error_already_connected(conn, msg); 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; } c->msg = dbus_message_ref(msg); err = rfcomm_connect(device, c); if (err < 0) goto error; return DBUS_HANDLER_RESULT_HANDLED;error: pending_connect_free(c); return error_connection_attempt_failed(conn, msg, -err);}static gboolean ring_timer_cb(gpointer data){ struct device *device = data; int err; err = headset_send(device->headset, "\r\nRING\r\n"); if (err) error("Sending RING failed"); return TRUE;}static DBusHandlerResult hs_ring(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; int err; if (hs->state < HEADSET_STATE_CONNECTED) return error_not_connected(conn, msg); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (hs->ring_timer) { debug("IndicateCall received when already indicating"); goto done; } err = headset_send(device->headset, "\r\nRING\r\n"); if (err) { dbus_message_unref(reply);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -