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

📄 avdtp.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 5 页
字号:
	g_free(stream);}static gboolean stream_timeout(struct avdtp_stream *stream){	struct avdtp *session = stream->session;	avdtp_close(session, stream);	stream->idle_timer = 0;	return FALSE;}static gboolean transport_cb(GIOChannel *chan, GIOCondition cond,				gpointer data){	struct avdtp_stream *stream = data;	struct avdtp_local_sep *sep = stream->lsep;	if (stream->close_int && sep->cfm && sep->cfm->close)		sep->cfm->close(stream->session, sep, stream, NULL,				sep->user_data);	stream->io = 0;	avdtp_sep_set_state(stream->session, sep, AVDTP_STATE_IDLE);	return FALSE;}static void handle_transport_connect(struct avdtp *session, int sock,					uint16_t imtu, uint16_t omtu){	struct avdtp_stream *stream = session->pending_open;	struct avdtp_local_sep *sep = stream->lsep;	GIOChannel *channel;	session->pending_open = NULL;	if (stream->timer) {		g_source_remove(stream->timer);		stream->timer = 0;	}	if (sock < 0) {		if (!stream->open_acp && sep->cfm && sep->cfm->open) {			struct avdtp_error err;			avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);			sep->cfm->open(session, sep, NULL, &err,					sep->user_data);		}		return;	}	stream->sock = sock;	stream->omtu = omtu;	stream->imtu = imtu;	if (!stream->open_acp && sep->cfm && sep->cfm->open)		sep->cfm->open(session, sep, stream, NULL, sep->user_data);	channel = g_io_channel_unix_new(stream->sock);	stream->io = g_io_add_watch(channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL,					(GIOFunc) transport_cb, stream);	g_io_channel_unref(channel);}static void avdtp_sep_set_state(struct avdtp *session,				struct avdtp_local_sep *sep,				avdtp_state_t state){	struct avdtp_stream *stream = sep->stream;	avdtp_state_t old_state;	struct avdtp_error err, *err_ptr = NULL;	if (sep->state == state) {		avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);		debug("stream state change failed: %s", avdtp_strerror(&err));		err_ptr = &err;	} else {		err_ptr = NULL;		debug("stream state changed: %s -> %s",				avdtp_statestr(sep->state),				avdtp_statestr(state));	}	old_state = sep->state;	sep->state = state;	if (stream) {		GSList *l;		for (l = stream->callbacks; l != NULL; l = g_slist_next(l)) {			struct stream_callback *cb = l->data;			cb->cb(stream, old_state, state, err_ptr,					cb->user_data);		}	}	switch (state) {	case AVDTP_STATE_OPEN:		break;	case AVDTP_STATE_STREAMING:	case AVDTP_STATE_CLOSING:	case AVDTP_STATE_ABORTING:		if (stream->idle_timer) {			g_source_remove(stream->idle_timer);			stream->idle_timer = 0;		}		break;	case AVDTP_STATE_IDLE:		if (stream->idle_timer) {			g_source_remove(stream->idle_timer);			stream->idle_timer = 0;		}		session->streams = g_slist_remove(session->streams, stream);		if (session->pending_open == stream)			handle_transport_connect(session, -1, 0, 0);		if (session->req && session->req->stream == stream)			session->req->stream = NULL;		stream_free(stream);		if (session->ref == 1 && !session->streams)			set_disconnect_timer(session);		break;	default:		break;	}}static void finalize_discovery(struct avdtp *session, int err){	struct avdtp_error avdtp_err;	avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);	if (!session->discov_cb)		return;	session->discov_cb(session, session->seps,				err ? &avdtp_err : NULL,				session->user_data);	session->discov_cb = NULL;	session->user_data = NULL;}static void release_stream(struct avdtp_stream *stream, struct avdtp *session){	struct avdtp_local_sep *sep = stream->lsep;	if (sep->cfm && sep->cfm->abort)		sep->cfm->abort(session, sep, stream, NULL, sep->user_data);	avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);}static void connection_lost(struct avdtp *session, int err){	struct device *dev;	dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE,					FALSE);	if (dev)		avrcp_disconnect(dev);	if (session->state == AVDTP_SESSION_STATE_CONNECTED) {		char address[18];		ba2str(&session->dst, address);		debug("Disconnected from %s", address);	}	session->free_lock = 1;	finalize_discovery(session, err);	g_slist_foreach(session->streams, (GFunc) release_stream, session);	session->streams = NULL;	session->free_lock = 0;	if (session->sock >= 0) {		close(session->sock);		session->sock = -1;	}	session->state = AVDTP_SESSION_STATE_DISCONNECTED;	if (session->io) {		g_source_remove(session->io);		session->io = 0;	}	if (session->ref != 1)		error("connection_lost: ref count not 1 after all callbacks");	else		avdtp_unref(session);}void avdtp_unref(struct avdtp *session){	if (!session)		return;	if (!g_slist_find(sessions, session)) {		error("avdtp_unref: trying to unref a unknown session");		return;	}	session->ref--;	debug("avdtp_unref(%p): ref=%d", session, session->ref);	if (session->ref == 1) {		if (session->state == AVDTP_SESSION_STATE_CONNECTING) {			close(session->sock);			session->sock = -1;		}		if (session->sock >= 0)			set_disconnect_timer(session);		else if (!session->free_lock) /* Drop the local ref if we						 aren't connected */			session->ref--;	}	if (session->ref > 0)		return;	debug("avdtp_unref(%p): freeing session and removing from list",			session);	if (session->dc_timer)		remove_disconnect_timer(session);	sessions = g_slist_remove(sessions, session);	if (session->req)		pending_req_free(session->req);	g_slist_foreach(session->seps, (GFunc) g_free, NULL);	g_slist_free(session->seps);	g_free(session->buf);	g_free(session);}struct avdtp *avdtp_ref(struct avdtp *session){	session->ref++;	debug("avdtp_ref(%p): ref=%d", session, session->ref);	if (session->dc_timer)		remove_disconnect_timer(session);	return session;}static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid){	GSList *l;	for (l = local_seps; l != NULL; l = g_slist_next(l)) {		struct avdtp_local_sep *sep = l->data;		if (sep->info.seid == seid)			return sep;	}	return NULL;}static struct avdtp_local_sep *find_local_sep(uint8_t type, uint8_t media_type,						uint8_t codec){	GSList *l;	for (l = local_seps; l != NULL; l = g_slist_next(l)) {		struct avdtp_local_sep *sep = l->data;		if (sep->info.inuse)			continue;		if (sep->info.type == type &&				sep->info.media_type == media_type &&				sep->codec == codec)			return sep;	}	return NULL;}static GSList *caps_to_list(uint8_t *data, int size,				struct avdtp_service_capability **codec){	GSList *caps;	int processed;	for (processed = 0, caps = NULL; processed + 2 < size;) {		struct avdtp_service_capability *cap;		uint8_t length, category;		category = data[0];		length = data[1];		if (processed + 2 + length > size) {			error("Invalid capability data in getcap resp");			break;		}		cap = g_malloc(sizeof(struct avdtp_service_capability) +					length);		memcpy(cap, data, 2 + length);		processed += 2 + length;		data += 2 + length;		caps = g_slist_append(caps, cap);		if (category == AVDTP_MEDIA_CODEC &&				length >=				sizeof(struct avdtp_media_codec_capability))			*codec = cap;	}	return caps;}static void init_response(struct avdtp_header *rsp, struct avdtp_header *req,				gboolean accept){	rsp->packet_type = AVDTP_PKT_TYPE_SINGLE;	rsp->message_type = accept ? AVDTP_MSG_TYPE_ACCEPT :					AVDTP_MSG_TYPE_REJECT;	rsp->transaction = req->transaction;	rsp->signal_id = req->signal_id;	rsp->rfa0 = 0;}static gboolean avdtp_unknown_cmd(struct avdtp *session,					struct avdtp_header *req, int size){	struct avdtp_general_rej rej;	memset(&rej, 0, sizeof(rej));	rej.packet_type = AVDTP_PKT_TYPE_SINGLE;	rej.message_type = AVDTP_MSG_TYPE_REJECT;	rej.transaction = req->transaction;	return avdtp_send(session, &rej, sizeof(rej));}static gboolean avdtp_discover_cmd(struct avdtp *session,					struct gen_req *req, int size){	GSList *l;	struct discover_resp *rsp = (struct discover_resp *) session->buf;	struct seid_info *info;	int rsp_size;	init_response(&rsp->header, &req->header, TRUE);	rsp_size = sizeof(struct discover_resp);	info = rsp->seps;	for (l = local_seps; l != NULL; l = l->next) {		struct avdtp_local_sep *sep = l->data;		if (rsp_size + sizeof(struct seid_info) > session->mtu)			break;		memcpy(info, &sep->info, sizeof(struct seid_info));		rsp_size += sizeof(struct seid_info);		info++;	}	return avdtp_send(session, session->buf, rsp_size);}static gboolean avdtp_getcap_cmd(struct avdtp *session,					struct seid_req *req, int size){	GSList *l, *caps;	struct avdtp_local_sep *sep = NULL;	struct seid_rej rej;	struct getcap_resp *rsp = (struct getcap_resp *) session->buf;	int rsp_size;	unsigned char *ptr;	uint8_t err;	if (size < sizeof(struct seid_req)) {		error("Too short getcap request");		return FALSE;	}	sep = find_local_sep_by_seid(req->acp_seid);	if (!sep) {		err = AVDTP_BAD_ACP_SEID;		goto failed;	}	if (!sep->ind->get_capability(session, sep, &caps, &err,					sep->user_data))		goto failed;	init_response(&rsp->header, &req->header, TRUE);	rsp_size = sizeof(struct getcap_resp);	ptr = rsp->caps;	for (l = caps; l != NULL; l = g_slist_next(l)) {		struct avdtp_service_capability *cap = l->data;		if (rsp_size + cap->length + 2 > session->mtu)			break;		memcpy(ptr, cap, cap->length + 2);		rsp_size += cap->length + 2;		ptr += cap->length + 2;		g_free(cap);	}	g_slist_free(caps);	return avdtp_send(session, session->buf, rsp_size);failed:	init_response(&rej.header, &req->header, FALSE);	rej.error = AVDTP_BAD_ACP_SEID;	return avdtp_send(session, &rej, sizeof(rej));}static gboolean avdtp_setconf_cmd(struct avdtp *session,					struct setconf_req *req, int size){	struct conf_rej rej;	struct gen_resp *rsp = (struct gen_resp *) session->buf;	struct avdtp_local_sep *sep;	struct avdtp_stream *stream;	uint8_t err, category = 0x00;	if (size < sizeof(struct setconf_req)) {		error("Too short getcap request");		return FALSE;	}	sep = find_local_sep_by_seid(req->acp_seid);	if (!sep) {		err = AVDTP_BAD_ACP_SEID;		goto failed;	}	if (sep->stream) {		err = AVDTP_SEP_IN_USE;		goto failed;	}	stream = g_new0(struct avdtp_stream, 1);	stream->session = session;	stream->lsep = sep;	stream->rseid = req->int_seid;	stream->caps = caps_to_list(req->caps,					size - sizeof(struct setconf_req),					&stream->codec);	stream->sock = -1;	if (sep->ind && sep->ind->set_configuration) {		if (!sep->ind->set_configuration(session, sep, stream,							stream->caps, &err,							&category,							sep->user_data)) {			stream_free(stream);			goto failed;		}	}	init_response(&rsp->header, &req->header, TRUE);	if (!avdtp_send(session, rsp, sizeof(struct setconf_req))) {		stream_free(stream);		return FALSE;	}	sep->stream = stream;	session->streams = g_slist_append(session->streams, stream);	avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);	return TRUE;failed:	init_response(&rej.header, &req->header, FALSE);	rej.error = err;	rej.category = category;	return avdtp_send(session, &rej, sizeof(rej));}static gboolean avdtp_getconf_cmd(struct avdtp *session, struct seid_req *req,					int size){	return avdtp_unknown_cmd(session, (void *) req, size);}static gboolean avdtp_reconf_cmd(struct avdtp *session, struct seid_req *req,					int size){	return avdtp_unknown_cmd(session, (void *) req, size);}static gboolean avdtp_open_cmd(struct avdtp *session, struct seid_req *req,				int size){	struct avdtp_local_sep *sep;	struct avdtp_stream *stream;	struct gen_resp *rsp = (struct gen_resp *) session->buf;	struct seid_rej rej;	uint8_t err;	if (size < sizeof(struct seid_req)) {		error("Too short abort request");		return FALSE;	}	sep = find_local_sep_by_seid(req->acp_seid);	if (!sep) {		err = AVDTP_BAD_ACP_SEID;		goto failed;	}	if (sep->state != AVDTP_STATE_CONFIGURED) {		err = AVDTP_BAD_STATE;		goto failed;	}	stream = sep->stream;	if (sep->ind && sep->ind->open) {		if (!sep->ind->open(session, sep, stream, &err,					sep->user_data))			goto failed;	}	init_response(&rsp->header, &req->header, TRUE);	if (!avdtp_send(session, rsp, sizeof(struct gen_resp)))		return FALSE;	stream->open_acp = TRUE;	session->pending_open = stream;	avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);	stream->timer = g_timeout_add(REQ_TIMEOUT, stream_open_timeout,						stream);	return TRUE;failed:	init_response(&rej.header, &req->header, FALSE);	rej.error = err;	return avdtp_send(session, &rej, sizeof(rej));}static gboolean avdtp_start_cmd(struct avdtp *session, struct start_req *req,				int size){	struct avdtp_local_sep *sep;	struct avdtp_stream *stream;	struct gen_resp *rsp = (struct gen_resp *) session->buf;	struct stream_rej rej;	struct seid *seid;	uint8_t err, failed_seid;	int seid_count, i;	if (size < sizeof(struct start_req)) {		error("Too short start request");		return FALSE;	}

⌨️ 快捷键说明

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