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

📄 control.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 2 页
字号:
	switch (operands[0] & 0x7F) {	case PLAY_OP:		debug("AVRCP: PLAY %s", status);		send_key(session->uinput, KEY_PLAYPAUSE, pressed);		break;	case STOP_OP:		debug("AVRCP: STOP %s", status);		send_key(session->uinput, KEY_STOP, pressed);		break;	case PAUSE_OP:		debug("AVRCP: PAUSE %s", status);		send_key(session->uinput, KEY_PLAYPAUSE, pressed);		break;	case NEXT_OP:		debug("AVRCP: NEXT %s", status);		send_key(session->uinput, KEY_NEXTSONG, pressed);		break;	case PREV_OP:		debug("AVRCP: PREV %s", status);		send_key(session->uinput, KEY_PREVIOUSSONG, pressed);		break;	case REWIND_OP:		debug("AVRCP: REWIND %s", status);		send_key(session->uinput, KEY_REWIND, pressed);		break;	case FAST_FORWARD_OP:		debug("AVRCP: FAST FORWARD %s", status);		send_key(session->uinput, KEY_FORWARD, pressed);		break;	default:		debug("AVRCP: unknown button 0x%02X %s", operands[0] & 0x7F, status);		break;	}}static gboolean session_cb(GIOChannel *chan, GIOCondition cond,				gpointer data){	struct avctp *session = data;	unsigned char buf[1024], *operands;	struct avctp_header *avctp;	struct avrcp_header *avrcp;	int ret, packet_size, operand_count;	if (!(cond | G_IO_IN))		goto failed;	ret = read(session->sock, buf, sizeof(buf));	if (ret <= 0)		goto failed;	debug("Got %d bytes of data for AVCTP session %p", ret, session);	if (ret < sizeof(struct avctp_header)) {		error("Too small AVCTP packet");		goto failed;	}	packet_size = ret;	avctp = (struct avctp_header *) buf;	debug("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, "			"PID 0x%04X",			avctp->transaction, avctp->packet_type,			avctp->cr, avctp->ipid, ntohs(avctp->pid));	ret -= sizeof(struct avctp_header);	if (ret < sizeof(struct avrcp_header)) {		error("Too small AVRCP packet");		goto failed;	}	avrcp = (struct avrcp_header *) (buf + sizeof(struct avctp_header));	ret -= sizeof(struct avrcp_header);	operands = buf + sizeof(struct avctp_header) + sizeof(struct avrcp_header);	operand_count = ret;	debug("AVRCP %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "			"opcode 0x%02X, %d operands",			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);	}	return TRUE;failed:	debug("AVCTP session %p got disconnected", session);	avctp_unref(session);	return FALSE;}static void auth_cb(DBusPendingCall *call, void *data){	GIOChannel *io;	struct avctp *session = data;	DBusMessage *reply = dbus_pending_call_steal_reply(call);	DBusError err;	dbus_pending_call_unref(session->pending_auth);	session->pending_auth = NULL;	dbus_error_init(&err);	if (dbus_set_error_from_message(&err, reply)) {		error("Access denied: %s", err.message);		if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {			debug("Canceling authorization request");			manager_cancel_authorize(&session->dst,							AVRCP_TARGET_UUID,							NULL);		}		avctp_unref(session);		dbus_message_unref(reply);		return;	}	session->state = AVCTP_STATE_CONNECTED;	session->dev = manager_device_connected(&session->dst,						AVRCP_TARGET_UUID);	session->dev->control->session = session;	init_uinput(session);	dbus_connection_emit_signal(session->dev->conn, session->dev->path,					AUDIO_CONTROL_INTERFACE, "Connected",					DBUS_TYPE_INVALID);	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 gboolean avctp_server_cb(GIOChannel *chan, GIOCondition cond, void *data){	int srv_sk, cli_sk;	socklen_t size;	struct sockaddr_l2 addr;	struct l2cap_options l2o;	bdaddr_t src, dst;	struct avctp *session;	GIOChannel *io;	GIOCondition flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL;	char address[18];	if (cond & G_IO_NVAL)		return FALSE;	if (cond & (G_IO_HUP | G_IO_ERR)) {		error("Hangup or error on AVCTP server socket");		g_io_channel_close(chan);		raise(SIGTERM);		return FALSE;	}	srv_sk = g_io_channel_unix_get_fd(chan);	size = sizeof(struct sockaddr_l2);	cli_sk = accept(srv_sk, (struct sockaddr *) &addr, &size);	if (cli_sk < 0) {		error("AVCTP accept: %s (%d)", strerror(errno), errno);		return TRUE;	}	bacpy(&dst, &addr.l2_bdaddr);	ba2str(&dst, address);	debug("AVCTP: incoming connect from %s", address);	size = sizeof(struct sockaddr_l2);	if (getsockname(cli_sk, (struct sockaddr *) &addr, &size) < 0) {		error("getsockname: %s (%d)", strerror(errno), errno);		close(cli_sk);		return TRUE;	}	bacpy(&src, &addr.l2_bdaddr);	memset(&l2o, 0, sizeof(l2o));	size = sizeof(l2o);	if (getsockopt(cli_sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &size) < 0) {		error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(errno),			errno);		close(cli_sk);		return TRUE;	}	session = avctp_get(&src, &dst);	if (!session) {		error("Unable to create new AVCTP session");		close(cli_sk);		return TRUE;	}	if (session->sock >= 0) {		error("Refusing unexpected connect from %s", address);		close(cli_sk);		return TRUE;	}	session->state = AVCTP_STATE_CONNECTING;	if (avdtp_is_connected(&src, &dst))		goto proceed;	if (!manager_authorize(&dst, AVRCP_TARGET_UUID, auth_cb, session,				&session->pending_auth)) {		close(cli_sk);		avctp_unref(session);		return TRUE;	}proceed:	session->mtu = l2o.imtu;	session->sock = cli_sk;	io = g_io_channel_unix_new(session->sock);	if (!session->pending_auth) {		session->state = AVCTP_STATE_CONNECTED;		session->dev = manager_device_connected(&dst,							AVRCP_TARGET_UUID);		session->dev->control->session = session;		init_uinput(session);		flags |= G_IO_IN;		dbus_connection_emit_signal(session->dev->conn,						session->dev->path,						AUDIO_CONTROL_INTERFACE,						"Connected",						DBUS_TYPE_INVALID);	}	session->io = g_io_add_watch(io, flags, (GIOFunc) session_cb, session);	g_io_channel_unref(io);	return TRUE;}static gboolean avctp_connect_cb(GIOChannel *chan, GIOCondition cond,					gpointer data){	struct avctp *session = data;	struct l2cap_options l2o;	socklen_t len;	int ret, err, sk;	char address[18];	if (cond & G_IO_NVAL)		return FALSE;	sk = g_io_channel_unix_get_fd(chan);	ba2str(&session->dst, address);	len = sizeof(ret);	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {		err = errno;		error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err);		goto failed;	}	if (ret != 0) {		err = ret;		error("AVCTP connect(%s): %s (%d)", address, strerror(err),				err);		goto failed;	}	if (cond & G_IO_HUP) {		err = EIO;		goto failed;	}	debug("AVCTP: connected to %s", address);	memset(&l2o, 0, sizeof(l2o));	len = sizeof(l2o);	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o,				&len) < 0) {		err = errno;		error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(err),				err);		goto failed;	}	init_uinput(session);	dbus_connection_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);	return FALSE;failed:	close(sk);	avctp_unref(session);	return FALSE;}gboolean avrcp_connect(struct device *dev){	struct control *control = dev->control;	struct avctp *session;	struct sockaddr_l2 l2a;	GIOChannel *io;	int sk;	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;	memset(&l2a, 0, sizeof(l2a));	l2a.l2_family = AF_BLUETOOTH;	bacpy(&l2a.l2_bdaddr, &dev->src);	sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);	if (sk < 0) {		error("Cannot create L2CAP socket. %s(%d)", strerror(errno),				errno);		goto failed;	}	if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a)) < 0) {		error("Bind failed. %s (%d)", strerror(errno), errno);		goto failed;	}	memset(&l2a, 0, sizeof(l2a));	l2a.l2_family = AF_BLUETOOTH;	bacpy(&l2a.l2_bdaddr, &dev->dst);	l2a.l2_psm = htobs(AVCTP_PSM);	if (set_nonblocking(sk) < 0) {		error("Set non blocking: %s (%d)", strerror(errno), errno);		goto failed;	}	io = g_io_channel_unix_new(sk);	g_io_channel_set_close_on_unref(io, FALSE);	session->sock = sk;	if (connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) < 0) {		if (!(errno == EAGAIN || errno == EINPROGRESS)) {			error("Connect failed. %s(%d)", strerror(errno),					errno);			g_io_channel_close(io);			g_io_channel_unref(io);			goto failed;		}		session->state = AVCTP_STATE_CONNECTING;		g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,				(GIOFunc) avctp_connect_cb, session);	} else		avctp_connect_cb(io, G_IO_OUT, session);	g_io_channel_unref(io);	control->session = session;	return TRUE;failed:	avctp_unref(session);	return FALSE;}void avrcp_disconnect(struct 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){	sdp_buf_t buf;	if (avctp_server)		return 0;	connection = dbus_connection_ref(conn);	if (avrcp_tg_record(&buf) < 0) {		error("Unable to allocate new service record");		return -1;	}	tg_record_id = add_service_record(conn, &buf);	free(buf.data);	if (!tg_record_id) {		error("Unable to register AVRCP target service record");		return -1;	}	if (avrcp_ct_record(&buf) < 0) {		error("Unable to allocate new service record");		return -1;	}	ct_record_id = add_service_record(conn, &buf);	free(buf.data);	if (!ct_record_id) {		error("Unable to register AVRCP controller service record");		return -1;	}	avctp_server = avctp_server_socket();	if (!avctp_server)		return -1;	g_io_add_watch(avctp_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,			(GIOFunc) avctp_server_cb, NULL);	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_service_record(connection, ct_record_id);	ct_record_id = 0;	remove_service_record(connection, ct_record_id);	ct_record_id = 0;	dbus_connection_unref(connection);	connection = NULL;}static DBusHandlerResult control_is_connected(DBusConnection *conn,						DBusMessage *msg,						void *data){	struct device *device = data;	struct control *control = device->control;	DBusMessage *reply;	dbus_bool_t connected;	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	connected = (control->session != NULL);	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,					DBUS_TYPE_INVALID);	send_message_and_unref(conn, reply);	return DBUS_HANDLER_RESULT_HANDLED;}static DBusMethodVTable control_methods[] = {	{ "IsConnected",	control_is_connected,	"",	"b"	},	{ NULL, NULL, NULL, NULL }};static DBusSignalVTable control_signals[] = {	{ "Connected",			""	},	{ "Disconnected",		""	},	{ NULL, NULL }};struct control *control_init(struct device *dev){	if (!dbus_connection_register_interface(dev->conn, dev->path,						AUDIO_CONTROL_INTERFACE,						control_methods,						control_signals, NULL))		return NULL;	return g_new0(struct control, 1);}void control_free(struct device *dev){	struct control *control = dev->control;	if (control->session)		avctp_unref(control->session);	g_free(control);	dev->control = NULL;}gboolean control_is_active(struct 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 + -