📄 gstavdtpsink.c
字号:
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 + -