⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 headset.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -