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

📄 control.c

📁 BlueZ源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 gboolean avctp_connect_session(struct avctp *session){	GIOChannel *io;	gboolean value;	session->dev = manager_find_device(&session->dst, NULL, FALSE);	if (!session->dev) {		error("Connecting audio device not known (SDP not completed)");		return FALSE;	}	session->state = AVCTP_STATE_CONNECTED;	session->dev->control->session = session;	init_uinput(session);	value = TRUE;	g_dbus_emit_signal(session->dev->conn, session->dev->path,				AUDIO_CONTROL_INTERFACE, "Connected",				DBUS_TYPE_INVALID);	emit_property_changed(session->dev->conn, session->dev->path,				AUDIO_CONTROL_INTERFACE, "Connected",				DBUS_TYPE_BOOLEAN, &value);	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);	return TRUE;}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);		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;	struct audio_device *dev;	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;	}	dev = manager_get_device(src, dst);	if (!dev) {		error("Unable to get audio device object for %s", address);		goto drop;	}	if (!dev->control)		dev->control = control_init(dev);	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);		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;	err = btd_request_authorization(src, dst, AVRCP_TARGET_UUID,				auth_cb, session);	if (err < 0)		goto drop;	return;proceed:	if (!avctp_connect_session(session))		goto drop;	return;drop:	g_io_channel_close(chan);	avctp_unref(session);}static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master){	GIOChannel *io;	int lm = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;	if (master)		lm |= L2CAP_LM_MASTER;	io = bt_l2cap_listen(src, 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 control *control = data;	struct avctp *session = control->session;	struct l2cap_options l2o;	socklen_t len;	int sk;	char address[18];	if (!session) {		debug("avctp_connect_cb: session removed while connecting");		g_io_channel_close(chan);		g_io_channel_unref(chan);		return;	}	ba2str(&session->dst, address);	if (err < 0) {		avctp_unref(session);		error("AVCTP connect(%s): %s (%d)", address, strerror(-err),				-err);		return;	}	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;		g_io_channel_unref(chan);		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);	g_io_channel_unref(chan);}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, control);	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_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config){	sdp_record_t *record;	gboolean tmp, master = TRUE;	GError *err = NULL;	struct avctp_server *server;	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;	}	server = g_new0(struct avctp_server, 1);	if (!server)		return -ENOMEM;	if (!connection)		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(src, record) < 0) {		error("Unable to register AVRCP target service record");		sdp_record_free(record);		return -1;	}	server->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(src, record) < 0) {		error("Unable to register AVRCP controller service record");		sdp_record_free(record);		return -1;	}	server->ct_record_id = record->handle;	server->io = avctp_server_socket(src, master);	if (!server->io) {		remove_record_from_server(server->ct_record_id);		remove_record_from_server(server->tg_record_id);		g_free(server);		return -1;	}	bacpy(&server->src, src);	servers = g_slist_append(servers, server);	return 0;}static struct avctp_server *find_server(GSList *list, const bdaddr_t *src){	GSList *l;	for (l = list; l; l = l->next) {		struct avctp_server *server = l->data;		if (bacmp(&server->src, src) == 0)			return server;	}	return NULL;}void avrcp_unregister(const bdaddr_t *src){	struct avctp_server *server;	server = find_server(servers, src);	if (!server)		return;	servers = g_slist_remove(servers, server);	remove_record_from_server(server->ct_record_id);	remove_record_from_server(server->tg_record_id);	g_io_channel_close(server->io);	g_io_channel_unref(server->io);	g_free(server);	if (servers)		return;	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 DBusMessage *control_get_properties(DBusConnection *conn,					DBusMessage *msg, void *data){	struct audio_device *device = data;	DBusMessage *reply;	DBusMessageIter iter;	DBusMessageIter dict;	gboolean value;	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	dbus_message_iter_init_append(reply, &iter);	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);	/* Connected */	value = (device->control->session != NULL);	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);	dbus_message_iter_close_container(&iter, &dict);	return reply;}static GDBusMethodTable control_methods[] = {	{ "IsConnected",	"",	"b",	control_is_connected,						G_DBUS_METHOD_FLAG_DEPRECATED },	{ "GetProperties",	"",	"a{sv}",control_get_properties },	{ NULL, NULL, NULL, NULL }};static GDBusSignalTable control_signals[] = {	{ "Connected",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED},	{ "Disconnected",		"",	G_DBUS_SIGNAL_FLAG_DEPRECATED},	{ "PropertyChanged",		"sv"	},	{ 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 + -