📄 headset.c
字号:
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; 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; } if ((uuid.type == SDP_UUID32 && uuid.value.uuid32 != HEADSET_SVCLASS_ID) || (uuid.type == SDP_UUID16 && uuid.value.uuid16 != HEADSET_SVCLASS_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; if ((err = rfcomm_connect(device, NULL)) < 0) { error("Unable to connect"); if (c->msg) err_connect_failed(device->conn, c->msg, strerror(-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) err_not_supported(device->conn, c->msg);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")) err_connect_failed(device->conn, c->msg, strerror(EHOSTDOWN)); else err_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) 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); 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->hfp_handle ? 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 err_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 err_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 err_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 err_connect_failed(conn, msg, strerror(-err));}static gboolean ring_timer_cb(gpointer data){ struct device *device = data; if (headset_send(device->headset, "\r\nRING\r\n") != G_IO_ERROR_NONE) 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; if (hs->state < HEADSET_STATE_CONNECTED) return err_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; } if (headset_send(device->headset, "\r\nRING\r\n") != G_IO_ERROR_NONE) { dbus_message_unref(reply); return err_failed(conn, msg, "Failed"); } hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device);done: send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_cancel_ringing(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; if (hs->state < HEADSET_STATE_CONNECTED) return err_not_connected(conn, msg); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (!hs->ring_timer) { debug("Got CancelRinging method call but ringing is not in progress"); goto done; } g_source_remove(hs->ring_timer); hs->ring_timer = 0;done: send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -