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

📄 avdtp.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (omtu)		*omtu = stream->omtu;	if (imtu)		*imtu = stream->imtu;	if (caps)		*caps = stream->caps;	return TRUE;}static int process_queue(struct avdtp *session){	GSList **queue, *l;	struct pending_req *req;	if (session->req)		return 0;	if (session->prio_queue)		queue = &session->prio_queue;	else		queue = &session->req_queue;	if (!*queue)		return 0;	l = *queue;	req = l->data;	*queue = g_slist_remove(*queue, req);	return send_req(session, FALSE, req);}struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep){	return sep->codec;}struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,							void *data, int length){	struct avdtp_service_capability *cap;	if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_MEDIA_CODEC)		return NULL;	cap = g_malloc(sizeof(struct avdtp_service_capability) + length);	cap->category = category;	cap->length = length;	memcpy(cap->data, data, length);	return cap;}int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,			void *user_data){	struct gen_req req;	int ret;	if (session->discov_cb)		return -EBUSY;	if (session->seps) {		cb(session, session->seps, NULL, user_data);		return 0;	}	memset(&req, 0, sizeof(req));	init_request(&req.header, AVDTP_DISCOVER);	ret = send_request(session, FALSE, NULL, &req, sizeof(req));	if (ret == 0) {		session->discov_cb = cb;		session->user_data = user_data;	}	return ret;}int avdtp_get_seps(struct avdtp *session, uint8_t acp_type, uint8_t media_type,			uint8_t codec, struct avdtp_local_sep **lsep,			struct avdtp_remote_sep **rsep){	GSList *l;	uint8_t int_type;	int_type = acp_type == AVDTP_SEP_TYPE_SINK ?				AVDTP_SEP_TYPE_SOURCE : AVDTP_SEP_TYPE_SINK;	*lsep = find_local_sep(int_type, media_type, codec);	if (!*lsep)		return -EINVAL;	for (l = session->seps; l != NULL; l = g_slist_next(l)) {		struct avdtp_remote_sep *sep = l->data;		struct avdtp_service_capability *cap;		struct avdtp_media_codec_capability *codec_data;		if (sep->type != acp_type)			continue;		if (sep->media_type != media_type)			continue;		if (!sep->codec)			continue;		cap = sep->codec;		codec_data = (void *) cap->data;		if (codec_data->media_codec_type != codec)			continue;		if (!sep->stream) {			*rsep = sep;			return 0;		}	}	return -EINVAL;}gboolean avdtp_stream_remove_cb(struct avdtp *session,				struct avdtp_stream *stream,				unsigned int id){	GSList *l;	struct stream_callback *cb;	for (cb = NULL, l = stream->callbacks; l != NULL; l = l->next) {		struct stream_callback *tmp = l->data;		if (tmp->id == id) {			cb = tmp;			break;		}	}	if (!cb)		return FALSE;	stream->callbacks = g_slist_remove(stream->callbacks, cb);	g_free(cb);	return TRUE;}unsigned int avdtp_stream_add_cb(struct avdtp *session,					struct avdtp_stream *stream,					avdtp_stream_state_cb cb, void *data){	struct stream_callback *stream_cb;	static unsigned int id = 0;	stream_cb = g_new(struct stream_callback, 1);	stream_cb->cb = cb;	stream_cb->user_data = data;	stream_cb->id = ++id;	stream->callbacks = g_slist_append(stream->callbacks, stream_cb);;	return stream_cb->id;}int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream){	struct seid_req req;	if (session->state < AVDTP_SESSION_STATE_CONNECTED)		return -EINVAL;	memset(&req, 0, sizeof(req));	init_request(&req.header, AVDTP_GET_CONFIGURATION);	req.acp_seid = stream->rseid;	return send_request(session, FALSE, stream, &req, sizeof(req));}static void copy_capabilities(gpointer data, gpointer user_data){	struct avdtp_service_capability *src_cap = data;	struct avdtp_service_capability *dst_cap;	GSList **l = user_data;	dst_cap = avdtp_service_cap_new(src_cap->category, src_cap->data,					src_cap->length);	*l = g_slist_append(*l, dst_cap);}int avdtp_set_configuration(struct avdtp *session,				struct avdtp_remote_sep *rsep,				struct avdtp_local_sep *lsep,				GSList *caps,				struct avdtp_stream **stream){	struct setconf_req *req;	struct avdtp_stream *new_stream;	unsigned char *ptr;	int ret, caps_len;	struct avdtp_service_capability *cap;	GSList *l;	if (session->state != AVDTP_SESSION_STATE_CONNECTED)		return -ENOTCONN;	if (!(lsep && rsep))		return -EINVAL;	debug("avdtp_set_configuration(%p): int_seid=%u, acp_seid=%u",			session, lsep->info.seid, rsep->seid);	new_stream = g_new0(struct avdtp_stream, 1);	new_stream->session = session;	new_stream->lsep = lsep;	new_stream->rseid = rsep->seid;	g_slist_foreach(caps, copy_capabilities, &new_stream->caps);	/* Calculate total size of request */	for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) {		cap = l->data;		caps_len += cap->length + 2;	}	req = g_malloc0(sizeof(struct setconf_req) + caps_len);	init_request(&req->header, AVDTP_SET_CONFIGURATION);	req->int_seid = lsep->info.seid;	req->acp_seid = rsep->seid;	/* Copy the capabilities into the request */	for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {		cap = l->data;		memcpy(ptr, cap, cap->length + 2);		ptr += cap->length + 2;	}	ret = send_request(session, FALSE, new_stream, req,				sizeof(struct setconf_req) + caps_len);	if (ret < 0)		stream_free(new_stream);	else {		lsep->info.inuse = 1;		lsep->stream = new_stream;		rsep->stream = new_stream;		session->streams = g_slist_append(session->streams, new_stream);		if (stream)			*stream = new_stream;	}	g_free(req);	return ret;}int avdtp_reconfigure(struct avdtp *session, GSList *caps,			struct avdtp_stream *stream){	struct reconf_req *req;	unsigned char *ptr;	int caps_len;	GSList *l;	struct avdtp_service_capability *cap;	if (!g_slist_find(session->streams, stream))		return -EINVAL;	if (stream->lsep->state != AVDTP_STATE_OPEN)		return -EINVAL;	/* Calculate total size of request */	for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) {		cap = l->data;		caps_len += cap->length + 2;	}	req = g_malloc0(sizeof(struct reconf_req) + caps_len);	init_request(&req->header, AVDTP_RECONFIGURE);	req->acp_seid = stream->rseid;	/* Copy the capabilities into the request */	for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {		cap = l->data;		memcpy(ptr, cap, cap->length + 2);		ptr += cap->length + 2;	}	return send_request(session, FALSE, stream, req, sizeof(*req)				+ caps_len);}int avdtp_open(struct avdtp *session, struct avdtp_stream *stream){	struct seid_req req;	if (!g_slist_find(session->streams, stream))		return -EINVAL;	if (stream->lsep->state > AVDTP_STATE_CONFIGURED)		return -EINVAL;	memset(&req, 0, sizeof(req));	init_request(&req.header, AVDTP_OPEN);	req.acp_seid = stream->rseid;	return send_request(session, FALSE, stream, &req, sizeof(req));}int avdtp_start(struct avdtp *session, struct avdtp_stream *stream){	struct start_req req;	if (!g_slist_find(session->streams, stream))		return -EINVAL;	if (stream->lsep->state != AVDTP_STATE_OPEN)		return -EINVAL;	memset(&req, 0, sizeof(req));	init_request(&req.header, AVDTP_START);	req.first_seid.seid = stream->rseid;	return send_request(session, FALSE, stream, &req, sizeof(req));}int avdtp_close(struct avdtp *session, struct avdtp_stream *stream){	struct seid_req req;	int ret;	if (!g_slist_find(session->streams, stream))		return -EINVAL;	if (stream->lsep->state < AVDTP_STATE_OPEN)		return -EINVAL;	memset(&req, 0, sizeof(req));	init_request(&req.header, AVDTP_CLOSE);	req.acp_seid = stream->rseid;	ret = send_request(session, FALSE, stream, &req, sizeof(req));	if (ret == 0)		stream->close_int = TRUE;	return ret;}int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream){	struct seid_req req;	if (!g_slist_find(session->streams, stream))		return -EINVAL;	if (stream->lsep->state <= AVDTP_STATE_OPEN)		return -EINVAL;	memset(&req, 0, sizeof(req));	init_request(&req.header, AVDTP_SUSPEND);	req.acp_seid = stream->rseid;	return send_request(session, FALSE, stream, &req, sizeof(req));}int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream){	struct seid_req req;	int ret;	if (!g_slist_find(session->streams, stream))		return -EINVAL;	if (stream->lsep->state <= AVDTP_STATE_OPEN)		return -EINVAL;	memset(&req, 0, sizeof(req));	init_request(&req.header, AVDTP_ABORT);	req.acp_seid = stream->rseid;	ret = send_request(session, FALSE, stream, &req, sizeof(req));	if (ret == 0)		avdtp_sep_set_state(session, stream->lsep,					AVDTP_STATE_ABORTING);	return 0;}struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,						struct avdtp_sep_ind *ind,						struct avdtp_sep_cfm *cfm,						void *user_data){	struct avdtp_local_sep *sep;	if (free_seid > MAX_SEID)		return NULL;	sep = g_new0(struct avdtp_local_sep, 1);	sep->state = AVDTP_STATE_IDLE;	sep->info.seid = free_seid++;	sep->info.type = type;	sep->info.media_type = media_type;	sep->ind = ind;	sep->cfm = cfm;	sep->user_data = user_data;	local_seps = g_slist_append(local_seps, sep);	return sep;}int avdtp_unregister_sep(struct avdtp_local_sep *sep){	if (!sep)		return -EINVAL;	if (sep->info.inuse)		return -EBUSY;	local_seps = g_slist_remove(local_seps, sep);	g_free(sep);	return 0;}static void auth_cb(DBusPendingCall *call, void *data){	GIOChannel *io;	struct avdtp *session = data;	DBusMessage *reply = dbus_pending_call_steal_reply(call);	DBusError err;	struct device *dev;	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,							ADVANCED_AUDIO_UUID,							NULL);		}		dbus_error_free(&err);		connection_lost(session, -EACCES);		dbus_message_unref(reply);		return;	}	session->buf = g_malloc0(session->mtu);	set_disconnect_timer(session);	session->state = AVDTP_SESSION_STATE_CONNECTED;	dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE,					FALSE);	if (dev)		avrcp_connect(dev);	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 avdtp_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 avdtp *session;	GIOChannel *io;	char address[18];	if (cond & G_IO_NVAL)		return FALSE;	if (cond & (G_IO_HUP | G_IO_ERR)) {		error("Hangup or error on AVDTP 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("AVDTP accept: %s (%d)", strerror(errno), errno);		return TRUE;	}	bacpy(&dst, &addr.l2_bdaddr);	ba2str(&dst, address);	debug("AVDTP: 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 = avdtp_get_internal(&src, &dst);	if (session->pending_open && session->pending_open->open_acp) {		handle_transport_connect(session, cli_sk, l2o.imtu, l2o.omtu);		return TRUE;	}	if (session->sock >= 0) {		error("Refusing unexpected connect from %s", address);		close(cli_sk);		return TRUE;	}	if (!manager_authorize(&dst, ADVANCED_AUDIO_UUID, auth_cb, session,				&session->pending_auth)) {		close(cli_sk);		avdtp_unref(session);		return TRUE;	}	session->mtu = l2o.imtu;	session->sock = cli_sk;	io = g_io_channel_unix_new(session->sock);	session->io = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,					(GIOFunc) session_cb, session);	g_io_channel_unref(io);	return TRUE;}static GIOChannel *avdtp_server_socket(void){	int sock, lm;	struct sockaddr_l2 addr;	GIOChannel *io;	sock = socket(AF_

⌨️ 快捷键说明

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