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

📄 a2dp.c

📁 实现bluez蓝牙profile需要的库
💻 C
📖 第 1 页 / 共 2 页
字号:
	setup = find_setup_by_session(session);	if (!setup)		return;	if (setup->canceled) {		if (!err)			avdtp_close(session, stream);		stream_setup_free(setup);		return;	}	if (err)		setup->stream = NULL;	finalize_stream_setup(setup);}static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,				struct avdtp_stream *stream, uint8_t *err,				void *user_data){	struct a2dp_sep *a2dp_sep = user_data;	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)		debug("SBC Sink: Suspend_Ind");	else		debug("SBC Source: Suspend_Ind");	return TRUE;}static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,			struct avdtp_stream *stream, struct avdtp_error *err,			void *user_data){	struct a2dp_sep *a2dp_sep = user_data;	struct a2dp_stream_setup *setup;	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)		debug("SBC Sink: Suspend_Cfm");	else		debug("SBC Source: Suspend_Cfm");	a2dp_sep->suspending = FALSE;	setup = find_setup_by_session(session);	if (!setup)		return;	if (err) {		finalize_stream_setup(setup);		return;	}	if (setup->start) {		if (avdtp_start(session, stream) < 0)			finalize_stream_setup(setup);	}}static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep,				struct avdtp_stream *stream, uint8_t *err,				void *user_data){	struct a2dp_sep *a2dp_sep = user_data;	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)		debug("SBC Sink: Close_Ind");	else		debug("SBC Source: Close_Ind");	return TRUE;}static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,			struct avdtp_stream *stream, struct avdtp_error *err,			void *user_data){	struct a2dp_sep *a2dp_sep = user_data;	struct a2dp_stream_setup *setup;	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)		debug("SBC Sink: Close_Cfm");	else		debug("SBC Source: Close_Cfm");	setup = find_setup_by_session(session);	if (!setup)		return;	if (setup->canceled) {		stream_setup_free(setup);		return;	}	if (err) {		setup->stream = NULL;		goto finalize;	}	if (setup->start) {		if (avdtp_discover(session, discovery_complete, setup) == 0)			return;		error("avdtp_discover failed");		setup->stream = NULL;	}finalize:	finalize_stream_setup(setup);}static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,				struct avdtp_stream *stream, uint8_t *err,				void *user_data){	struct a2dp_sep *a2dp_sep = user_data;	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)		debug("SBC Sink: Abort_Ind");	else		debug("SBC Source: Abort_Ind");	a2dp_sep->stream = NULL;	return TRUE;}static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,			struct avdtp_stream *stream, struct avdtp_error *err,			void *user_data){	struct a2dp_sep *a2dp_sep = user_data;	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)		debug("SBC Sink: Abort_Cfm");	else		debug("SBC Source: Abort_Cfm");}static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,				uint8_t *err, void *user_data){	struct a2dp_sep *a2dp_sep = user_data;	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)		debug("SBC Sink: ReConfigure_Ind");	else		debug("SBC Source: ReConfigure_Ind");	return TRUE;}static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,			struct avdtp_stream *stream, struct avdtp_error *err,			void *user_data){	struct a2dp_sep *a2dp_sep = user_data;	struct a2dp_stream_setup *setup;	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)		debug("SBC Sink: ReConfigure_Cfm");	else		debug("SBC Source: ReConfigure_Cfm");	setup = find_setup_by_session(session);	if (!setup)		return;	if (setup->canceled) {		if (!err)			avdtp_close(session, stream);		stream_setup_free(setup);		return;	}	if (err) {		setup->stream = NULL;		goto finalize;	}	if (setup->start) {		if (avdtp_start(session, stream) == 0)			return;		error("avdtp_start failed");		setup->stream = NULL;	}finalize:	finalize_stream_setup(setup);}static struct avdtp_sep_cfm cfm = {	.set_configuration	= setconf_cfm,	.get_configuration	= getconf_cfm,	.open			= open_cfm,	.start			= start_cfm,	.suspend		= suspend_cfm,	.close			= close_cfm,	.abort			= abort_cfm,	.reconfigure		= reconf_cfm};static struct avdtp_sep_ind ind = {	.get_capability		= getcap_ind,	.set_configuration	= setconf_ind,	.get_configuration	= getconf_ind,	.open			= open_ind,	.start			= start_ind,	.suspend		= suspend_ind,	.close			= close_ind,	.abort			= abort_ind,	.reconfigure		= reconf_ind};static int a2dp_source_record(sdp_buf_t *buf){	sdp_list_t *svclass_id, *pfseq, *apseq, *root;	uuid_t root_uuid, l2cap, avdtp, a2src;	sdp_profile_desc_t profile[1];	sdp_list_t *aproto, *proto[2];	sdp_record_t record;	sdp_data_t *psm, *version, *features;	uint16_t lp = AVDTP_UUID, ver = 0x0100, feat = 0x000F;	int ret = 0;	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(&a2src, AUDIO_SOURCE_SVCLASS_ID);	svclass_id = sdp_list_append(0, &a2src);	sdp_set_service_classes(&record, svclass_id);	sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);	profile[0].version = 0x0100;	pfseq = sdp_list_append(0, &profile[0]);	sdp_set_profile_descs(&record, pfseq);	sdp_uuid16_create(&l2cap, L2CAP_UUID);	proto[0] = sdp_list_append(0, &l2cap);	psm = sdp_data_alloc(SDP_UINT16, &lp);	proto[0] = sdp_list_append(proto[0], psm);	apseq = sdp_list_append(0, proto[0]);	sdp_uuid16_create(&avdtp, AVDTP_UUID);	proto[1] = sdp_list_append(0, &avdtp);	version = sdp_data_alloc(SDP_UINT16, &ver);	proto[1] = sdp_list_append(proto[1], version);	apseq = sdp_list_append(apseq, proto[1]);	aproto = sdp_list_append(0, apseq);	sdp_set_access_protos(&record, aproto);	features = sdp_data_alloc(SDP_UINT16, &feat);	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);	sdp_set_info_attr(&record, "Audio Source", 0, 0);	if (sdp_gen_record_pdu(&record, buf) < 0)		ret = -1;	else		ret = 0;	free(psm);	free(version);	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 a2dp_sink_record(sdp_buf_t *buf){	return 0;}static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type){	struct a2dp_sep *sep;	GSList **l;	int (*create_record)(sdp_buf_t *buf);	uint32_t *record_id;	sdp_buf_t buf;	sep = g_new0(struct a2dp_sep, 1);	sep->sep = avdtp_register_sep(type, AVDTP_MEDIA_TYPE_AUDIO,					&ind, &cfm, sep);	if (sep->sep == NULL) {		g_free(sep);		return NULL;	}	sep->type = type;	if (type == AVDTP_SEP_TYPE_SOURCE) {		l = &sources;		create_record = a2dp_source_record;		record_id = &source_record_id;	} else {		l = &sinks;		create_record = a2dp_sink_record;		record_id = &sink_record_id;	}	if (*record_id != 0)		goto add;	if (create_record(&buf) < 0) {		error("Unable to allocate new service record");		avdtp_unregister_sep(sep->sep);		g_free(sep);		return NULL;	}	*record_id = add_service_record(conn, &buf);	free(buf.data);	if (!*record_id) {		error("Unable to register A2DP service record");		avdtp_unregister_sep(sep->sep);		g_free(sep);		return NULL;	}add:	*l = g_slist_append(*l, sep);	return sep;}int a2dp_init(DBusConnection *conn, int sources, int sinks){	int i;	if (!sources && !sinks)		return 0;	connection = dbus_connection_ref(conn);	avdtp_init();	for (i = 0; i < sources; i++)		a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE);	for (i = 0; i < sinks; i++)		a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK);	return 0;}static void a2dp_unregister_sep(struct a2dp_sep *sep){	avdtp_unregister_sep(sep->sep);	g_free(sep);}void a2dp_exit(){	g_slist_foreach(sinks, (GFunc) a2dp_unregister_sep, NULL);	g_slist_free(sinks);	sinks = NULL;	g_slist_foreach(sources, (GFunc) a2dp_unregister_sep, NULL);	g_slist_free(sources);	sources = NULL;	if (source_record_id) {		remove_service_record(connection, source_record_id);		source_record_id = 0;	}	if (sink_record_id) {		remove_service_record(connection, sink_record_id);		sink_record_id = 0;	}	dbus_connection_unref(connection);}gboolean a2dp_source_cancel_stream(struct device *dev, unsigned int id){	struct a2dp_stream_cb *cb_data;	struct a2dp_stream_setup *setup;	GSList *l;	setup = find_setup_by_dev(dev);	if (!setup)		return FALSE;	for (cb_data = NULL, l = setup->cb; l != NULL; l = g_slist_next(l)) {		struct a2dp_stream_cb *cb = l->data;		if (cb->id == id) {			cb_data = cb;			break;		}	}	if (!cb_data)		return FALSE;	setup->cb = g_slist_remove(setup->cb, cb_data);	g_free(cb_data);	if (!setup->cb) {		setup->canceled = TRUE;		setup->sep = NULL;	}	return TRUE;}unsigned int a2dp_source_request_stream(struct avdtp *session,						gboolean start,						a2dp_stream_cb_t cb,						void *user_data,						struct avdtp_service_capability *media_codec){	struct a2dp_stream_cb *cb_data;	static unsigned int cb_id = 0;	GSList *l;	struct a2dp_stream_setup *setup;	struct a2dp_sep *sep = NULL;	for (l = sources; l != NULL; l = l->next) {		struct a2dp_sep *tmp = l->data;		if (tmp->locked)			continue;		if (!tmp->stream || avdtp_has_stream(session, tmp->stream)) {			sep = tmp;			break;		}	}	if (!sep) {		error("a2dp_source_request_stream: no available SEP found");		return 0;	}	setup = find_setup_by_session(session);	debug("a2dp_source_request_stream: selected SEP %p", sep);	cb_data = g_new(struct a2dp_stream_cb, 1);	cb_data->cb = cb;	cb_data->user_data = user_data;	cb_data->id = ++cb_id;	if (setup) {		setup->canceled = FALSE;		setup->sep = sep;		setup->cb = g_slist_append(setup->cb, cb_data);		if (start)			setup->start = TRUE;		return cb_data->id;	}	setup = g_new0(struct a2dp_stream_setup, 1);	setup->session = avdtp_ref(session);	setup->sep = sep;	setup->cb = g_slist_append(setup->cb, cb_data);	setup->start = start;	setup->stream = sep->stream;	setup->media_codec = media_codec;	switch (avdtp_sep_get_state(sep->sep)) {	case AVDTP_STATE_IDLE:		if (avdtp_discover(session, discovery_complete, setup) < 0) {			error("avdtp_discover failed");			goto failed;		}		break;	case AVDTP_STATE_OPEN:		if (!start) {			g_idle_add((GSourceFunc) finalize_stream_setup, setup);			break;		}		if (sep->starting)			break;		if (setup->media_codec) {			if (avdtp_stream_has_capability(setup->stream,							setup->media_codec)) {				if (avdtp_start(session, sep->stream) < 0) {					error("avdtp_start failed");					goto failed;				}			} else {				if (avdtp_close(session, sep->stream) < 0) {					error("avdtp_close failed");					goto failed;				}			}		}		else if (avdtp_start(session, sep->stream) < 0) {			error("avdtp_start failed");			goto failed;		}		break;	case AVDTP_STATE_STREAMING:		if (!start || !sep->suspending) {			if (sep->suspend_timer) {				g_source_remove(sep->suspend_timer);				sep->suspend_timer = 0;			}			g_idle_add((GSourceFunc) finalize_stream_setup, setup);		}		break;	default:		error("SEP in bad state for requesting a new stream");		goto failed;	}	setups = g_slist_append(setups, setup);	return cb_data->id;failed:	stream_setup_free(setup);	cb_id--;	return 0;}gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session){	if (sep->locked)		return FALSE;	debug("SBC Source SEP %p locked", sep);	sep->locked = TRUE;	return TRUE;}gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session){	avdtp_state_t state;	state = avdtp_sep_get_state(sep->sep);	sep->locked = FALSE;	debug("SBC Source SEP %p unlocked", sep);	if (!sep->stream || state == AVDTP_STATE_IDLE)		return TRUE;	switch (state) {	case AVDTP_STATE_OPEN:		/* Set timer here */		break;	case AVDTP_STATE_STREAMING:		if (avdtp_suspend(session, sep->stream) == 0)			sep->suspending = TRUE;		break;	default:		break;	}	return TRUE;}gboolean a2dp_source_suspend(struct device *dev, struct avdtp *session){	avdtp_state_t state;	GSList *l;	struct a2dp_sep *sep = NULL;	for (l = sources; l != NULL; l = l->next) {		struct a2dp_sep *tmp = l->data;		if (tmp->session && tmp->session == session) {			sep = tmp;			break;		}	}	if (!sep)		return FALSE;	state = avdtp_sep_get_state(sep->sep);	if (!sep->stream || state != AVDTP_STATE_STREAMING)		return TRUE;	if (avdtp_suspend(session, sep->stream) == 0) {		sep->suspending = TRUE;		return TRUE;	}	return FALSE;}gboolean a2dp_source_start_stream(struct device *dev, struct avdtp *session){	avdtp_state_t state;	GSList *l;	struct a2dp_sep *sep = NULL;	for (l = sources; l != NULL; l = l->next) {		struct a2dp_sep *tmp = l->data;		if (tmp->session && tmp->session == session) {			sep = tmp;			break;		}	}	if (!sep)		return FALSE;	state = avdtp_sep_get_state(sep->sep);	if (state < AVDTP_STATE_OPEN) {		error("a2dp_source_start_stream: no stream open");		return FALSE;	}	if (state == AVDTP_STATE_STREAMING)		return TRUE;	if (avdtp_start(session, sep->stream) < 0)		return FALSE;	return TRUE;}

⌨️ 快捷键说明

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