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

📄 control.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			avctp->cr ? "response" : "command",			avrcp->code, avrcp->subunit_type, avrcp->subunit_id,			avrcp->opcode, operand_count);	if (avctp->packet_type == AVCTP_PACKET_SINGLE &&			avctp->cr == AVCTP_COMMAND &&			avctp->pid == htons(AV_REMOTE_SVCLASS_ID) &&			avrcp->code == CTYPE_CONTROL &&			avrcp->subunit_type == SUBUNIT_PANEL &&			avrcp->opcode == OP_PASSTHROUGH) {		handle_panel_passthrough(session, operands, operand_count);		avctp->cr = AVCTP_RESPONSE;		avrcp->code = CTYPE_ACCEPTED;		ret = write(session->sock, buf, packet_size);	}	if (avctp->packet_type == AVCTP_PACKET_SINGLE &&			avctp->cr == AVCTP_COMMAND &&			avctp->pid == htons(AV_REMOTE_SVCLASS_ID) &&			avrcp->code == CTYPE_STATUS &&			(avrcp->opcode == OP_UNITINFO			|| avrcp->opcode == OP_SUBUNITINFO)) {		avctp->cr = AVCTP_RESPONSE;		avrcp->code = CTYPE_STABLE;		debug("reply to %s", avrcp->opcode == OP_UNITINFO ?				"OP_UNITINFO" : "OP_SUBUNITINFO");		ret = write(session->sock, buf, packet_size);	}	return TRUE;failed:	debug("AVCTP session %p got disconnected", session);	avctp_unref(session);	return FALSE;}static int uinput_create(char *name){	struct uinput_dev dev;	int fd, err;	fd = open("/dev/uinput", O_RDWR);	if (fd < 0) {		fd = open("/dev/input/uinput", O_RDWR);		if (fd < 0) {			fd = open("/dev/misc/uinput", O_RDWR);			if (fd < 0) {				err = errno;				error("Can't open input device: %s (%d)",							strerror(err), err);				return -err;			}		}	}	memset(&dev, 0, sizeof(dev));	if (name)		strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);	dev.id.bustype = BUS_BLUETOOTH;	dev.id.vendor  = 0x0000;	dev.id.product = 0x0000;	dev.id.version = 0x0000;	if (write(fd, &dev, sizeof(dev)) < 0) {		err = errno;		error("Can't write device information: %s (%d)",						strerror(err), err);		close(fd);		errno = err;		return -err;	}	ioctl(fd, UI_SET_EVBIT, EV_KEY);	ioctl(fd, UI_SET_EVBIT, EV_REL);	ioctl(fd, UI_SET_EVBIT, EV_REP);	ioctl(fd, UI_SET_EVBIT, EV_SYN);	ioctl(fd, UI_SET_KEYBIT, KEY_PLAYPAUSE);	ioctl(fd, UI_SET_KEYBIT, KEY_STOP);	ioctl(fd, UI_SET_KEYBIT, KEY_NEXTSONG);	ioctl(fd, UI_SET_KEYBIT, KEY_PREVIOUSSONG);	ioctl(fd, UI_SET_KEYBIT, KEY_REWIND);	ioctl(fd, UI_SET_KEYBIT, KEY_FORWARD);	if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {		err = errno;		error("Can't create uinput device: %s (%d)",						strerror(err), err);		close(fd);		errno = err;		return -err;	}	return fd;}static void init_uinput(struct avctp *session){	char address[18];	ba2str(&session->dst, address);	session->uinput = uinput_create(address);	if (session->uinput < 0)		error("AVRCP: failed to init uinput for %s", address);	else		debug("AVRCP: uinput initialized for %s", address);}static void avctp_connect_session(struct avctp *session){	GIOChannel *io;	session->state = AVCTP_STATE_CONNECTED;	session->dev = manager_find_device(&session->dst, NULL, FALSE);	if (!session->dev)		return;	session->dev->control->session = session;	init_uinput(session);	g_dbus_emit_signal(session->dev->conn, session->dev->path,					AUDIO_CONTROL_INTERFACE, "Connected",					DBUS_TYPE_INVALID);	if (session->io)		g_source_remove(session->io);	io = g_io_channel_unix_new(session->sock);	session->io = g_io_add_watch(io,			G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,			(GIOFunc) session_cb, session);	g_io_channel_unref(io);}static void auth_cb(DBusError *derr, void *user_data){	struct avctp *session = user_data;	if (derr && dbus_error_is_set(derr)) {		error("Access denied: %s", derr->message);		if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) {			debug("Canceling authorization request");			service_cancel_auth(&session->src, &session->dst);		}		avctp_unref(session);		return;	}	avctp_connect_session(session);}static void avctp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src,				const bdaddr_t *dst, gpointer data){	socklen_t size;	struct l2cap_options l2o;	struct avctp *session;	GIOCondition flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL;	char address[18];	if (err < 0) {		error("AVCTP server socket: %s (%d)", strerror(-err), -err);		return;	}	session = avctp_get(src, dst);	if (!session) {		error("Unable to create new AVCTP session");		goto drop;	}	if (session->sock >= 0) {		error("Refusing unexpected connect from %s", address);		goto drop;	}	session->state = AVCTP_STATE_CONNECTING;	session->sock = g_io_channel_unix_get_fd(chan);	memset(&l2o, 0, sizeof(l2o));	size = sizeof(l2o);	if (getsockopt(session->sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &size) < 0) {		err = errno;		error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(err),				err);		avctp_unref(session);		goto drop;	}	session->mtu = l2o.imtu;	session->io = g_io_add_watch(chan, flags, (GIOFunc) session_cb,				session);	g_io_channel_unref(chan);	if (avdtp_is_connected(src, dst))		goto proceed;	if (service_req_auth(src, dst, AVRCP_TARGET_UUID, auth_cb, session) < 0)		goto drop;	return;proceed:	avctp_connect_session(session);	return;drop:	close(session->sock);}static GIOChannel *avctp_server_socket(gboolean master){	int lm;	GIOChannel *io;	lm = L2CAP_LM_SECURE;	if (master)		lm |= L2CAP_LM_MASTER;	io = bt_l2cap_listen(BDADDR_ANY, AVCTP_PSM, 0, lm, avctp_server_cb,				NULL);	if (!io) {		error("Unable to allocate new io channel");		return NULL;	}	return io;}static void avctp_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,			const bdaddr_t *dst, gpointer data){	struct avctp *session = data;	struct l2cap_options l2o;	socklen_t len;	int sk;	char address[18];	if (err < 0) {		avctp_unref(session);		error("AVCTP connect(%s): %s (%d)", address, strerror(-err),				-err);		return;	}	ba2str(&session->dst, address);	debug("AVCTP: connected to %s", address);	g_io_channel_set_close_on_unref(chan, FALSE);	sk = g_io_channel_unix_get_fd(chan);	session->sock = sk;	memset(&l2o, 0, sizeof(l2o));	len = sizeof(l2o);	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {		err = errno;		avctp_unref(session);		error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(err),				err);		return;	}	init_uinput(session);	g_dbus_emit_signal(session->dev->conn, session->dev->path,					AUDIO_CONTROL_INTERFACE, "Connected",					DBUS_TYPE_INVALID);	session->state = AVCTP_STATE_CONNECTED;	session->mtu = l2o.imtu;	session->io = g_io_add_watch(chan,				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,				(GIOFunc) session_cb, session);}gboolean avrcp_connect(struct audio_device *dev){	struct control *control = dev->control;	struct avctp *session;	int err;	if (control->session)		return TRUE;	session = avctp_get(&dev->src, &dev->dst);	if (!session) {		error("Unable to create new AVCTP session");		return FALSE;	}	session->dev = dev;	session->state = AVCTP_STATE_CONNECTING;	err = bt_l2cap_connect(&dev->src, &dev->dst, AVCTP_PSM, 0,				avctp_connect_cb, session);	if (err < 0) {		avctp_unref(session);		error("Connect failed. %s(%d)", strerror(-err), -err);		return FALSE;	}	control->session = session;	return TRUE;}void avrcp_disconnect(struct audio_device *dev){	struct control *control = dev->control;	struct avctp *session = control->session;	if (!session)		return;	avctp_unref(session);	control->session = NULL;}int avrcp_init(DBusConnection *conn, GKeyFile *config){	sdp_record_t *record;	gboolean tmp, master = TRUE;	GError *err = NULL;	if (avctp_server)		return 0;	if (config) {		tmp = g_key_file_get_boolean(config, "General",							"Master", &err);		if (err) {			debug("audio.conf: %s", err->message);			g_error_free(err);		} else			master = tmp;	}	connection = dbus_connection_ref(conn);	record = avrcp_tg_record();	if (!record) {		error("Unable to allocate new service record");		return -1;	}	if (add_record_to_server(BDADDR_ANY, record) < 0) {		error("Unable to register AVRCP target service record");		sdp_record_free(record);		return -1;	}	tg_record_id = record->handle;	record = avrcp_ct_record();	if (!record) {		error("Unable to allocate new service record");		return -1;	}	if (add_record_to_server(BDADDR_ANY, record) < 0) {		error("Unable to register AVRCP controller service record");		sdp_record_free(record);		return -1;	}	ct_record_id = record->handle;	avctp_server = avctp_server_socket(master);	if (!avctp_server)		return -1;	return 0;}void avrcp_exit(void){	if (!avctp_server)		return;	g_io_channel_close(avctp_server);	g_io_channel_unref(avctp_server);	avctp_server = NULL;	remove_record_from_server(ct_record_id);	ct_record_id = 0;	remove_record_from_server(tg_record_id);	tg_record_id = 0;	dbus_connection_unref(connection);	connection = NULL;}static DBusMessage *control_is_connected(DBusConnection *conn,						DBusMessage *msg,						void *data){	struct audio_device *device = data;	struct control *control = device->control;	DBusMessage *reply;	dbus_bool_t connected;	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	connected = (control->session != NULL);	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,					DBUS_TYPE_INVALID);	return reply;}static GDBusMethodTable control_methods[] = {	{ "IsConnected",	"",	"b",	control_is_connected },	{ NULL, NULL, NULL, NULL }};static GDBusSignalTable control_signals[] = {	{ "Connected",			""	},	{ "Disconnected",		""	},	{ NULL, NULL }};static void control_free(struct audio_device *dev){	struct control *control = dev->control;	if (control->session)		avctp_unref(control->session);	g_free(control);	dev->control = NULL;}static void path_unregister(void *data){	struct audio_device *dev = data;	info("Unregistered interface %s on path %s",		AUDIO_CONTROL_INTERFACE, dev->path);	control_free(dev);}void control_unregister(struct audio_device *dev){	g_dbus_unregister_interface(dev->conn, dev->path,		AUDIO_CONTROL_INTERFACE);}struct control *control_init(struct audio_device *dev){	if (!g_dbus_register_interface(dev->conn, dev->path,					AUDIO_CONTROL_INTERFACE,					control_methods, control_signals, NULL,					dev, path_unregister))		return NULL;	info("Registered interface %s on path %s",		AUDIO_CONTROL_INTERFACE, dev->path);	return g_new0(struct control, 1);}gboolean control_is_active(struct audio_device *dev){	struct control *control = dev->control;	if (control->session &&			control->session->state != AVCTP_STATE_DISCONNECTED)		return TRUE;	return FALSE;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -