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

📄 manager.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 3 页
字号:
	else		ret = 0;	sdp_data_free(channel);	sdp_list_free(proto[0], 0);	sdp_list_free(proto[1], 0);	sdp_list_free(apseq, 0);	sdp_list_free(pfseq, 0);	sdp_list_free(aproto, 0);	sdp_list_free(root, 0);	sdp_list_free(svclass_id, 0);	sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);	sdp_list_free(record.pattern, free);	return ret;}static int hfp_ag_record(sdp_buf_t *buf, uint8_t ch){	sdp_list_t *svclass_id, *pfseq, *apseq, *root;	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;	uuid_t l2cap_uuid, rfcomm_uuid;	sdp_profile_desc_t profile;	sdp_list_t *aproto, *proto[2];	sdp_record_t record;	uint16_t u16 = 0x0009;	sdp_data_t *channel, *features;	uint8_t netid = 0x01;	sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);	int ret;	memset(&record, 0, sizeof(sdp_record_t));	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);	root = sdp_list_append(0, &root_uuid);	sdp_set_browse_groups(&record, root);	sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);	svclass_id = sdp_list_append(0, &svclass_uuid);	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);	sdp_set_service_classes(&record, svclass_id);	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);	profile.version = 0x0105;	pfseq = sdp_list_append(0, &profile);	sdp_set_profile_descs(&record, pfseq);	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);	proto[0] = sdp_list_append(0, &l2cap_uuid);	apseq = sdp_list_append(0, proto[0]);	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);	proto[1] = sdp_list_append(0, &rfcomm_uuid);	channel = sdp_data_alloc(SDP_UINT8, &ch);	proto[1] = sdp_list_append(proto[1], channel);	apseq = sdp_list_append(apseq, proto[1]);	features = sdp_data_alloc(SDP_UINT16, &u16);	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);	aproto = sdp_list_append(0, apseq);	sdp_set_access_protos(&record, aproto);	sdp_set_info_attr(&record, "Hands-Free Audio Gateway", 0, 0);	sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);	if (sdp_gen_record_pdu(&record, buf) < 0)		ret = -1;	else		ret = 0;	sdp_data_free(channel);	sdp_list_free(proto[0], 0);	sdp_list_free(proto[1], 0);	sdp_list_free(apseq, 0);	sdp_list_free(pfseq, 0);	sdp_list_free(aproto, 0);	sdp_list_free(root, 0);	sdp_list_free(svclass_id, 0);	sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);	sdp_list_free(record.pattern, free);	return ret;}uint32_t add_service_record(DBusConnection *conn, sdp_buf_t *buf){	DBusMessage *msg, *reply;	DBusError derr;	dbus_uint32_t rec_id;	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",						"org.bluez.Database",						"AddServiceRecord");	if (!msg) {		error("Can't allocate new method call");		return 0;	}	dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,						&buf->data, buf->data_size,							DBUS_TYPE_INVALID);	dbus_error_init(&derr);	reply = dbus_connection_send_with_reply_and_block(connection,							msg, -1, &derr);	dbus_message_unref(msg);	if (dbus_error_is_set(&derr) ||			dbus_set_error_from_message(&derr, reply)) {		error("Adding service record failed: %s", derr.message);		dbus_error_free(&derr);		return 0;	}	dbus_message_get_args(reply, &derr, DBUS_TYPE_UINT32, &rec_id,							DBUS_TYPE_INVALID);	if (dbus_error_is_set(&derr)) {		error("Invalid arguments to AddServiceRecord reply: %s",								derr.message);		dbus_message_unref(reply);		dbus_error_free(&derr);		return 0;	}	dbus_message_unref(reply);	debug("add_service_record: got record id 0x%x", rec_id);	return rec_id;}int remove_service_record(DBusConnection *conn, uint32_t rec_id){	DBusMessage *msg, *reply;	DBusError derr;	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",						"org.bluez.Database",						"RemoveServiceRecord");	if (!msg) {		error("Can't allocate new method call");		return 0;	}	dbus_message_append_args(msg, DBUS_TYPE_UINT32, &rec_id,							DBUS_TYPE_INVALID);	dbus_error_init(&derr);	reply = dbus_connection_send_with_reply_and_block(connection,							msg, -1, &derr);	dbus_message_unref(msg);	if (dbus_error_is_set(&derr)) {		error("Removing service record 0x%x failed: %s",						rec_id, derr.message);		dbus_error_free(&derr);		return 0;	}	dbus_message_unref(reply);	return 0;}static void auth_cb(DBusPendingCall *call, void *data){	struct device *device = data;	DBusMessage *reply = dbus_pending_call_steal_reply(call);	DBusError err;	const char *uuid;	if (headset_get_type(device) == SVC_HEADSET)		uuid = HSP_AG_UUID;	else		uuid = HFP_AG_UUID;	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(&device->dst, uuid, NULL);		}		dbus_error_free(&err);		headset_set_state(device, HEADSET_STATE_DISCONNECTED);	} else {		char hs_address[18];		headset_set_state(device, HEADSET_STATE_CONNECTED);		ba2str(&device->dst, hs_address);		debug("Accepted headset connection from %s for %s",						hs_address, device->path);	}	dbus_message_unref(reply);}static gboolean ag_io_cb(GIOChannel *chan, GIOCondition cond, void *data){	int srv_sk, cli_sk;	struct sockaddr_rc addr;	socklen_t size;	const char *uuid;	struct device *device;	headset_type_t type;	if (cond & G_IO_NVAL)		return FALSE;	if (cond & (G_IO_HUP | G_IO_ERR)) {		error("Hangup or error on rfcomm server socket");		g_io_channel_close(chan);		raise(SIGTERM);		return FALSE;	}	srv_sk = g_io_channel_unix_get_fd(chan);	size = sizeof(struct sockaddr_rc);	cli_sk = accept(srv_sk, (struct sockaddr *) &addr, &size);	if (cli_sk < 0) {		error("accept: %s (%d)", strerror(errno), errno);		return TRUE;	}	if (chan == hs_server) {		type = SVC_HEADSET;		uuid = HSP_AG_UUID;	} else {		type = SVC_HANDSFREE;		uuid = HFP_AG_UUID;	}	device = manager_device_connected(&addr.rc_bdaddr, uuid);	if (!device) {		close(cli_sk);		return TRUE;	}	if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {		debug("Refusing new connection since one already exists");		close(cli_sk);		return TRUE;	}	if (headset_connect_rfcomm(device, cli_sk) < 0) {		error("Allocating new GIOChannel failed!");		close(cli_sk);		return TRUE;	}	headset_set_type(device, type);	if (!manager_authorize(&device->dst, uuid, auth_cb, device, NULL))		goto failed;	headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);	return TRUE;failed:	headset_close_rfcomm(device);	return TRUE;}static GIOChannel *server_socket(uint8_t *channel){	int sock, lm;	struct sockaddr_rc addr;	socklen_t sa_len;	GIOChannel *io;	sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);	if (sock < 0) {		error("server socket: %s (%d)", strerror(errno), errno);		return NULL;	}	lm = RFCOMM_LM_SECURE;	if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {		error("server setsockopt: %s (%d)", strerror(errno), errno);		close(sock);		return NULL;	}	memset(&addr, 0, sizeof(addr));	addr.rc_family = AF_BLUETOOTH;	bacpy(&addr.rc_bdaddr, BDADDR_ANY);	addr.rc_channel = channel ? *channel : 0;	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {		error("server bind: %s", strerror(errno), errno);		close(sock);		return NULL;	}	if (listen(sock, 1) < 0) {		error("server listen: %s", strerror(errno), errno);		close(sock);		return NULL;	}	sa_len = sizeof(struct sockaddr_rc);	getsockname(sock, (struct sockaddr *) &addr, &sa_len);	*channel = addr.rc_channel;	io = g_io_channel_unix_new(sock);	if (!io) {		error("Unable to allocate new io channel");		close(sock);		return NULL;	}	return io;}static int headset_server_init(DBusConnection *conn, gboolean no_hfp){	uint8_t chan = DEFAULT_HS_AG_CHANNEL;	sdp_buf_t buf;	if (!(enabled->headset || enabled->gateway))		return 0;	hs_server = server_socket(&chan);	if (!hs_server)		return -1;	if (hsp_ag_record(&buf, chan) < 0) {		error("Unable to allocate new service record");		return -1;	}	hs_record_id = add_service_record(conn, &buf);	free(buf.data);	if (!hs_record_id) {		error("Unable to register HS AG service record");		g_io_channel_unref(hs_server);		hs_server = NULL;		return -1;	}	g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,						(GIOFunc) ag_io_cb, NULL);	if (no_hfp)		return 0;	enable_hfp = TRUE;	chan = DEFAULT_HF_AG_CHANNEL;	hf_server = server_socket(&chan);	if (!hf_server)		return -1;	if (hfp_ag_record(&buf, chan) < 0) {		error("Unable to allocate new service record");		return -1;	}	hf_record_id = add_service_record(conn, &buf);	free(buf.data);	if (!hf_record_id) {		error("Unable to register HS AG service record");		g_io_channel_unref(hf_server);		hs_server = NULL;		return -1;	}	g_io_add_watch(hf_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,						(GIOFunc) ag_io_cb, NULL);	return 0;}static void server_exit(void){	if (hs_record_id) {		remove_service_record(connection, hs_record_id);		hs_record_id = 0;	}	if (hs_server) {		g_io_channel_unref(hs_server);		hs_server = NULL;	}	if (hf_record_id) {		remove_service_record(connection, hf_record_id);		hf_record_id = 0;	}	if (hf_server) {		g_io_channel_unref(hf_server);		hf_server = NULL;	}}int audio_init(DBusConnection *conn, struct enabled_interfaces *enable,		gboolean no_hfp, gboolean sco_hci, int source_count){	int sinks, sources;	connection = dbus_connection_ref(conn);	enabled = enable;	if (!dbus_connection_create_object_path(conn, AUDIO_MANAGER_PATH,						NULL, manager_unregister)) {		error("D-Bus failed to register %s path", AUDIO_MANAGER_PATH);		goto failed;	}	if (headset_server_init(conn, no_hfp) < 0)		goto failed;	if (enable->sink)		sources = source_count;	else		sources = 0;	if (enable->source)		sinks = 1;	else		sinks = 0;	if (a2dp_init(conn, sources, sinks) < 0)		goto failed;	if (enable->control && avrcp_init(conn) < 0)		goto failed;	if (!dbus_connection_register_interface(conn, AUDIO_MANAGER_PATH,						AUDIO_MANAGER_INTERFACE,						manager_methods,						manager_signals, NULL)) {		error("Failed to register %s interface to %s",				AUDIO_MANAGER_INTERFACE, AUDIO_MANAGER_PATH);		goto failed;	}	info("Registered manager path:%s", AUDIO_MANAGER_PATH);	register_stored();	return 0;failed:	audio_exit();	return -1;}void audio_exit(void){	server_exit();	dbus_connection_destroy_object_path(connection, AUDIO_MANAGER_PATH);	dbus_connection_unref(connection);	connection = NULL;}struct device *manager_default_device(void){	return default_dev;}struct device *manager_get_connected_device(void){	GSList *l;	for (l = devices; l != NULL; l = g_slist_next(l)) {		struct device *device = l->data;		if ((device->sink || device->source) &&				avdtp_is_connected(&device->src, &device->dst))			return device;		if (device->headset && headset_is_active(device))			return device;	}	return NULL;}void manager_cancel_authorize(bdaddr_t *dba, const char *uuid,				DBusPendingCall *pending){	DBusMessage *cancel;	char addr[18], *address = addr;	if (pending)		dbus_pending_call_cancel(pending);	cancel = dbus_message_new_method_call("org.bluez", "/org/bluez",						"org.bluez.Database",						"CancelAuthorizationRequest");	if (!cancel) {		error("Unable to allocate new method call");		return;	}	ba2str(dba, addr);	dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address,					DBUS_TYPE_STRING, &uuid,					DBUS_TYPE_INVALID);	send_message_and_unref(connection, cancel);}gboolean manager_authorize(bdaddr_t *dba, const char *uuid,				DBusPendingCallNotifyFunction cb,				void *user_data,				DBusPendingCall **pending){	DBusMessage *auth;	char address[18], *addr_ptr = address;	DBusPendingCall *p;	ba2str(dba, address);	debug("Requesting authorization for device %s, UUID %s",			address, uuid);	auth = dbus_message_new_method_call("org.bluez", "/org/bluez",						"org.bluez.Database",						"RequestAuthorization");	if (!auth) {		error("Unable to allocate RequestAuthorization method call");		return FALSE;	}	dbus_message_append_args(auth, DBUS_TYPE_STRING, &addr_ptr,					DBUS_TYPE_STRING, &uuid,					DBUS_TYPE_INVALID);	if (!dbus_connection_send_with_reply(connection, auth, &p, -1)) {		error("Sending of authorization request failed");		dbus_message_unref(auth);		return FALSE;	}	dbus_pending_call_set_notify(p, cb, user_data, NULL);	if (pending)		*pending = p;	else		dbus_pending_call_unref(p);	dbus_message_unref(auth);	return TRUE;}struct device *manager_find_device(bdaddr_t *bda, const char *interface,					gboolean connected){	GSList *l;	if (!bacmp(bda, BDADDR_ANY) && !interface && !connected)		return default_dev;	for (l = devices; l != NULL; l = l->next) {		struct device *dev = l->data;		if (bacmp(bda, BDADDR_ANY) && bacmp(&dev->dst, bda))			continue;		if (interface && !strcmp(AUDIO_HEADSET_INTERFACE, interface)				&& !dev->headset)			continue;		if (interface && !strcmp(AUDIO_SINK_INTERFACE, interface)				&& !dev->sink)			continue;		if (interface && !strcmp(AUDIO_SOURCE_INTERFACE, interface)				&& !dev->source)			continue;		if (interface && !strcmp(AUDIO_CONTROL_INTERFACE, interface)				&& !dev->control)			continue;		if (connected && !device_is_connected(dev, interface))			continue;		return dev;	}	return NULL;}

⌨️ 快捷键说明

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