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

📄 gstavdtpsink.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		g_free(list);		list = NULL;	}	/* subbands */	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);	value = g_value_init(value, G_TYPE_INT);	if (sbc->subbands & BT_A2DP_SUBBANDS_4) {		g_value_set_int(value, 4);		gst_value_list_prepend_value(list, value);	}	if (sbc->subbands & BT_A2DP_SUBBANDS_8) {		g_value_set_int(value, 8);		gst_value_list_prepend_value(list, value);	}	g_value_unset(value);	if (list) {		gst_structure_set_value(structure, "subbands", list);		g_free(list);		list = NULL;	}	/* blocks */	value = g_value_init(value, G_TYPE_INT);	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_16) {		g_value_set_int(value, 16);		gst_value_list_prepend_value(list, value);	}	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_12) {		g_value_set_int(value, 12);		gst_value_list_prepend_value(list, value);	}	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_8) {		g_value_set_int(value, 8);		gst_value_list_prepend_value(list, value);	}	if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_4) {		g_value_set_int(value, 4);		gst_value_list_prepend_value(list, value);	}	g_value_unset(value);	if (list) {		gst_structure_set_value(structure, "blocks", list);		g_free(list);		list = NULL;	}	/* allocation */	g_value_init(value, G_TYPE_STRING);	list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST);	if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) {		g_value_set_static_string(value, "loudness");		gst_value_list_prepend_value(list, value);	}	if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) {		g_value_set_static_string(value, "snr");		gst_value_list_prepend_value(list, value);	}	g_value_unset(value);	if (list) {		gst_structure_set_value(structure, "allocation", list);		g_free(list);		list = NULL;	}	/* rate */	g_value_init(value, G_TYPE_INT);	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);	if (sbc->frequency & BT_SBC_SAMPLING_FREQ_48000) {		g_value_set_int(value, 48000);		gst_value_list_prepend_value(list, value);	}	if (sbc->frequency & BT_SBC_SAMPLING_FREQ_44100) {		g_value_set_int(value, 44100);		gst_value_list_prepend_value(list, value);	}	if (sbc->frequency & BT_SBC_SAMPLING_FREQ_32000) {		g_value_set_int(value, 32000);		gst_value_list_prepend_value(list, value);	}	if (sbc->frequency & BT_SBC_SAMPLING_FREQ_16000) {		g_value_set_int(value, 16000);		gst_value_list_prepend_value(list, value);	}	g_value_unset(value);	if (list) {		gst_structure_set_value(structure, "rate", list);		g_free(list);		list = NULL;	}	/* bitpool */	value = g_value_init(value, GST_TYPE_INT_RANGE);	gst_value_set_int_range(value,			MIN(sbc->min_bitpool, TEMPLATE_MAX_BITPOOL),			MIN(sbc->max_bitpool, TEMPLATE_MAX_BITPOOL));	gst_structure_set_value(structure, "bitpool", value);	g_value_unset(value);	/* channels */	mono = FALSE;	stereo = FALSE;	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)		mono = TRUE;	if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||			(sbc->channel_mode &			BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||			(sbc->channel_mode &			BT_A2DP_CHANNEL_MODE_JOINT_STEREO))		stereo = TRUE;	if (mono && stereo) {		g_value_init(value, GST_TYPE_INT_RANGE);		gst_value_set_int_range(value, 1, 2);	} else {		g_value_init(value, G_TYPE_INT);		if (mono)			g_value_set_int(value, 1);		else if (stereo)			g_value_set_int(value, 2);		else {			GST_ERROR_OBJECT(self,				"Unexpected number of channels");			g_value_set_int(value, 0);		}	}	gst_structure_set_value(structure, "channels", value);	g_free(value);	return structure;}static GstStructure *gst_avdtp_sink_parse_mpeg_caps(			GstAvdtpSink *self, mpeg_capabilities_t *mpeg){	GstStructure *structure;	GValue *value;	GValue *list;	gboolean valid_layer = FALSE;	gboolean mono, stereo;	GST_LOG_OBJECT(self, "parsing mpeg caps");	structure = gst_structure_empty_new("audio/mpeg");	value = g_new0(GValue, 1);	g_value_init(value, G_TYPE_INT);	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);	g_value_set_int(value, 1);	gst_value_list_prepend_value(list, value);	g_value_set_int(value, 2);	gst_value_list_prepend_value(list, value);	gst_structure_set_value(structure, "mpegversion", list);	g_free(list);	/* layer */	GST_LOG_OBJECT(self, "setting mpeg layer");	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);	if (mpeg->layer & BT_MPEG_LAYER_1) {		g_value_set_int(value, 1);		gst_value_list_prepend_value(list, value);		valid_layer = TRUE;	}	if (mpeg->layer & BT_MPEG_LAYER_2) {		g_value_set_int(value, 2);		gst_value_list_prepend_value(list, value);		valid_layer = TRUE;	}	if (mpeg->layer & BT_MPEG_LAYER_3) {		g_value_set_int(value, 3);		gst_value_list_prepend_value(list, value);		valid_layer = TRUE;	}	if (list) {		gst_structure_set_value(structure, "layer", list);		g_free(list);		list = NULL;	}	if (!valid_layer) {		gst_structure_free(structure);		g_free(value);		return NULL;	}	/* rate */	GST_LOG_OBJECT(self, "setting mpeg rate");	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_48000) {		g_value_set_int(value, 48000);		gst_value_list_prepend_value(list, value);	}	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_44100) {		g_value_set_int(value, 44100);		gst_value_list_prepend_value(list, value);	}	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_32000) {		g_value_set_int(value, 32000);		gst_value_list_prepend_value(list, value);	}	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_24000) {		g_value_set_int(value, 24000);		gst_value_list_prepend_value(list, value);	}	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_22050) {		g_value_set_int(value, 22050);		gst_value_list_prepend_value(list, value);	}	if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_16000) {		g_value_set_int(value, 16000);		gst_value_list_prepend_value(list, value);	}	g_value_unset(value);	if (list) {		gst_structure_set_value(structure, "rate", list);		g_free(list);		list = NULL;	}	/* channels */	GST_LOG_OBJECT(self, "setting mpeg channels");	mono = FALSE;	stereo = FALSE;	if (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)		mono = TRUE;	if ((mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||			(mpeg->channel_mode &			BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||			(mpeg->channel_mode &			BT_A2DP_CHANNEL_MODE_JOINT_STEREO))		stereo = TRUE;	if (mono && stereo) {		g_value_init(value, GST_TYPE_INT_RANGE);		gst_value_set_int_range(value, 1, 2);	} else {		g_value_init(value, G_TYPE_INT);		if (mono)			g_value_set_int(value, 1);		else if (stereo)			g_value_set_int(value, 2);		else {			GST_ERROR_OBJECT(self,				"Unexpected number of channels");			g_value_set_int(value, 0);		}	}	gst_structure_set_value(structure, "channels", value);	g_free(value);	return structure;}static gboolean gst_avdtp_sink_update_caps(GstAvdtpSink *self){	sbc_capabilities_t *sbc = &self->data->caps.sbc_capabilities;	mpeg_capabilities_t *mpeg = &self->data->caps.mpeg_capabilities;	GstStructure *sbc_structure;	GstStructure *mpeg_structure;	gchar *tmp;	GST_LOG_OBJECT(self, "updating device caps");	sbc_structure = gst_avdtp_sink_parse_sbc_caps(self, sbc);	mpeg_structure = gst_avdtp_sink_parse_mpeg_caps(self, mpeg);	if (self->dev_caps != NULL)		gst_caps_unref(self->dev_caps);	self->dev_caps = gst_caps_new_full(sbc_structure, NULL);	if (mpeg_structure != NULL)		gst_caps_append_structure(self->dev_caps, mpeg_structure);	tmp = gst_caps_to_string(self->dev_caps);	GST_DEBUG_OBJECT(self, "Device capabilities: %s", tmp);	g_free(tmp);	return TRUE;}static gboolean gst_avdtp_sink_get_capabilities(GstAvdtpSink *self){	gchar *buf[BT_AUDIO_IPC_PACKET_SIZE];	struct bt_getcapabilities_req *req = (void *) buf;	struct bt_getcapabilities_rsp *rsp = (void *) buf;	GIOError io_error;	memset(req, 0, BT_AUDIO_IPC_PACKET_SIZE);	req->h.msg_type = BT_GETCAPABILITIES_REQ;	if (self->device == NULL)		return FALSE;	strncpy(req->device, self->device, 18);	if (self->autoconnect)		req->flags |= BT_FLAG_AUTOCONNECT;	io_error = gst_avdtp_sink_audioservice_send(self, &req->h);	if (io_error != G_IO_ERROR_NONE) {		GST_ERROR_OBJECT(self, "Error while asking device caps");		return FALSE;	}	io_error = gst_avdtp_sink_audioservice_expect(self,			&rsp->rsp_h.msg_h, BT_GETCAPABILITIES_RSP);	if (io_error != G_IO_ERROR_NONE) {		GST_ERROR_OBJECT(self, "Error while getting device caps");		return FALSE;	}	if (rsp->rsp_h.posix_errno != 0) {		GST_ERROR_OBJECT(self, "BT_GETCAPABILITIES failed : %s(%d)",					strerror(rsp->rsp_h.posix_errno),					rsp->rsp_h.posix_errno);		return FALSE;	}	memcpy(&self->data->caps, rsp, sizeof(*rsp));	if (!gst_avdtp_sink_update_caps(self)) {		GST_WARNING_OBJECT(self, "failed to update capabilities");		return FALSE;	}	return TRUE;}static gint gst_avdtp_sink_get_channel_mode(const gchar *mode){	if (strcmp(mode, "stereo") == 0)		return BT_A2DP_CHANNEL_MODE_STEREO;	else if (strcmp(mode, "joint") == 0)		return BT_A2DP_CHANNEL_MODE_JOINT_STEREO;	else if (strcmp(mode, "dual") == 0)		return BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;	else if (strcmp(mode, "mono") == 0)		return BT_A2DP_CHANNEL_MODE_MONO;	else		return -1;}static void gst_avdtp_sink_tag(const GstTagList *taglist,			const gchar* tag, gpointer user_data){	gboolean crc;	gchar *channel_mode = NULL;	GstAvdtpSink *self = GST_AVDTP_SINK(user_data);	if (strcmp(tag, "has-crc") == 0) {		if (!gst_tag_list_get_boolean(taglist, tag, &crc)) {			GST_WARNING_OBJECT(self, "failed to get crc tag");			return;		}		gst_avdtp_sink_set_crc(self, crc);	} else if (strcmp(tag, "channel-mode") == 0) {		if (!gst_tag_list_get_string(taglist, tag, &channel_mode)) {			GST_WARNING_OBJECT(self,				"failed to get channel-mode tag");			return;		}		self->channel_mode = gst_avdtp_sink_get_channel_mode(					channel_mode);		if (self->channel_mode == -1)			GST_WARNING_OBJECT(self, "Received invalid channel "					"mode: %s", channel_mode);		g_free(channel_mode);	} else		GST_DEBUG_OBJECT(self, "received unused tag: %s", tag);}static gboolean gst_avdtp_sink_event(GstBaseSink *basesink,			GstEvent *event){	GstAvdtpSink *self = GST_AVDTP_SINK(basesink);	GstTagList *taglist = NULL;	if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) {		/* we check the tags, mp3 has tags that are importants and		 * are outside caps */		gst_event_parse_tag(event, &taglist);		gst_tag_list_foreach(taglist, gst_avdtp_sink_tag, self);	}	return TRUE;}static gboolean gst_avdtp_sink_start(GstBaseSink *basesink){	GstAvdtpSink *self = GST_AVDTP_SINK(basesink);	gint sk;	gint err;	GST_INFO_OBJECT(self, "start");	self->watch_id = 0;	sk = bt_audio_service_open();	if (sk <= 0) {		err = errno;		GST_ERROR_OBJECT(self, "Cannot open connection to bt "			"audio service: %s %d", strerror(err), err);		goto failed;	}	self->server = g_io_channel_unix_new(sk);	self->watch_id = g_io_add_watch(self->server, G_IO_HUP | G_IO_ERR |					G_IO_NVAL, server_callback, self);	self->data = g_new0(struct bluetooth_data, 1);	memset(self->data, 0, sizeof(struct bluetooth_data));	self->stream = NULL;	self->stream_caps = NULL;	self->mp3_using_crc = -1;	self->channel_mode = -1;	if (!gst_avdtp_sink_get_capabilities(self)) {		GST_ERROR_OBJECT(self, "failed to get capabilities "				"from device");		goto failed;	}	return TRUE;failed:	bt_audio_service_close(sk);	return FALSE;}static gboolean gst_avdtp_sink_stream_start(GstAvdtpSink *self){	gchar buf[BT_AUDIO_IPC_PACKET_SIZE];	struct bt_streamstart_req *req = (void *) buf;	struct bt_streamstart_rsp *rsp = (void *) buf;	struct bt_streamfd_ind *ind = (void*) buf;	GIOError io_error;	GST_DEBUG_OBJECT(self, "stream start");	memset (req, 0, sizeof(buf));	req->h.msg_type = BT_STREAMSTART_REQ;	io_error = gst_avdtp_sink_audioservice_send(self, &req->h);	if (io_error != G_IO_ERROR_NONE) {		GST_ERROR_OBJECT(self, "Error ocurred while sending "					"start packet");		return FALSE;	}

⌨️ 快捷键说明

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