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

📄 avdtp.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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,						uint8_t codec_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->codec = codec_type;	sep->ind = ind;	sep->cfm = cfm;	sep->user_data = user_data;	debug("SEP %p registered: type:%d codec:%d seid:%d", sep,			sep->info.type, sep->codec, sep->info.seid);	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(DBusError *derr, void *user_data){	struct avdtp *session = user_data;	struct audio_device *dev;	GIOChannel *io;	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);		}		connection_lost(session, -EACCES);		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 void avdtp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src,		const bdaddr_t *dst, gpointer data){	int sk;	socklen_t size;	struct l2cap_options l2o;	struct avdtp *session;	char address[18];	if (err < 0) {		error("accept: %s (%d)", strerror(-err), -err);		return;	}	sk = g_io_channel_unix_get_fd(chan);	ba2str(dst, address);	debug("AVDTP: incoming connect from %s", address);	memset(&l2o, 0, sizeof(l2o));	size = sizeof(l2o);	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &size) < 0) {		error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(errno),			errno);		goto drop;	}	session = avdtp_get_internal(src, dst);	if (session->pending_open && session->pending_open->open_acp) {		handle_transport_connect(session, sk, l2o.imtu, l2o.omtu);		return;	}	if (session->sock >= 0) {		error("Refusing unexpected connect from %s", address);		goto drop;	}	session->mtu = l2o.imtu;	session->sock = sk;	session->io = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,					(GIOFunc) session_cb, session);	g_io_channel_unref(chan);	if (service_req_auth(src, dst, ADVANCED_AUDIO_UUID, auth_cb,			session) < 0) {		avdtp_unref(session);		goto drop;	}	return;drop:	g_io_channel_close(chan);	g_io_channel_unref(chan);}static GIOChannel *avdtp_server_socket(gboolean master){	int lm;	lm = L2CAP_LM_SECURE;	if (master)		lm |= L2CAP_LM_MASTER;	return bt_l2cap_listen(BDADDR_ANY, AVDTP_PSM, 0, lm, avdtp_server_cb,			NULL);}const char *avdtp_strerror(struct avdtp_error *err){	if (err->type == AVDTP_ERROR_ERRNO)		return strerror(err->err.posix_errno);	switch(err->err.error_code) {	case AVDTP_BAD_HEADER_FORMAT:		return "Bad Header Format";	case AVDTP_BAD_LENGTH:		return "Bad Packet Lenght";	case AVDTP_BAD_ACP_SEID:		return "Bad Acceptor SEID";	case AVDTP_SEP_IN_USE:		return "Stream End Point in Use";	case AVDTP_SEP_NOT_IN_USE:		return "Stream End Point Not in Use";	case AVDTP_BAD_SERV_CATEGORY:		return "Bad Service Category";	case AVDTP_BAD_PAYLOAD_FORMAT:		return "Bad Payload format";	case AVDTP_NOT_SUPPORTED_COMMAND:		return "Command Not Supported";	case AVDTP_INVALID_CAPABILITIES:		return "Invalid Capabilities";	case AVDTP_BAD_RECOVERY_TYPE:		return "Bad Recovery Type";	case AVDTP_BAD_MEDIA_TRANSPORT_FORMAT:		return "Bad Media Transport Format";	case AVDTP_BAD_RECOVERY_FORMAT:		return "Bad Recovery Format";	case AVDTP_BAD_ROHC_FORMAT:		return "Bad Header Compression Format";	case AVDTP_BAD_CP_FORMAT:		return "Bad Content Protetion Format";	case AVDTP_BAD_MULTIPLEXING_FORMAT:		return "Bad Multiplexing Format";	case AVDTP_UNSUPPORTED_CONFIGURATION:		return "Configuration not supported";	case AVDTP_BAD_STATE:		return "Bad State";	default:		return "Unknow error";	}}avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep){	return sep->state;}void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst){	if (src)		bacpy(src, &session->src);	if (dst)		bacpy(dst, &session->dst);}int avdtp_init(GKeyFile *config){	GError *err = NULL;	gboolean tmp, master = TRUE;	if (avdtp_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;	}	avdtp_server = avdtp_server_socket(master);	if (!avdtp_server)		return -1;	return 0;}void avdtp_exit(void){	if (!avdtp_server)		return;	g_io_channel_close(avdtp_server);	g_io_channel_unref(avdtp_server);	avdtp_server = NULL;}gboolean avdtp_has_stream(st

⌨️ 快捷键说明

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