From 3ad6867c8c7251c3192378a1a0e2ed937ee47d1b Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 30 Jan 2008 14:21:43 +0000 Subject: Fixes gstreamer caps and code cleanup. --- audio/gsta2dpsink.c | 40 ++++++++++++++++------- audio/gstavdtpsink.c | 53 ++++++++++++++++++------------ audio/gstavdtpsink.h | 1 - audio/gstrtpsbcpay.c | 13 ++++++-- audio/gstsbcdec.c | 45 +++++++++++++++---------- audio/gstsbcdec.h | 3 ++ audio/gstsbcparse.c | 92 +++------------------------------------------------- audio/gstsbcutil.c | 9 +++-- 8 files changed, 113 insertions(+), 143 deletions(-) diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c index a2b3286c..b5b1c576 100644 --- a/audio/gsta2dpsink.c +++ b/audio/gsta2dpsink.c @@ -80,6 +80,17 @@ static void gst_a2dp_sink_finalize(GObject *obj) G_OBJECT_CLASS (parent_class)->finalize (obj); } +static GstState gst_a2dp_sink_get_state(GstA2dpSink *self) +{ + GstState current, pending; + + gst_element_get_state(GST_ELEMENT(self), ¤t, &pending, 0); + if (pending == GST_STATE_VOID_PENDING) + return current; + + return pending; +} + /* * Helper function to create elements, add to the bin and link it * to another element. @@ -89,6 +100,7 @@ static GstElement* gst_a2dp_sink_init_element(GstA2dpSink *self, GstElement *link_to) { GstElement *element; + GstState state; GST_LOG_OBJECT(self, "Initializing %s", elementname); @@ -104,17 +116,19 @@ static GstElement* gst_a2dp_sink_init_element(GstA2dpSink *self, goto cleanup_and_fail; } - if (gst_element_set_state(element, GST_STATE_PLAYING) == + state = gst_a2dp_sink_get_state(self); + if (gst_element_set_state(element, state) == GST_STATE_CHANGE_FAILURE) { GST_ERROR_OBJECT(self, "%s failed to go to playing", elementname); goto remove_element_and_fail; } - if (!gst_element_link(link_to, element)) { - GST_ERROR_OBJECT(self, "couldn't link %s", elementname); - goto remove_element_and_fail; - } + if (link_to != NULL) + if (!gst_element_link(link_to, element)) { + GST_ERROR_OBJECT(self, "couldn't link %s", elementname); + goto remove_element_and_fail; + } return element; @@ -241,7 +255,6 @@ static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, case GST_STATE_CHANGE_NULL_TO_READY: self->sink_is_in_bin = FALSE; - self->sink = GST_AVDTP_SINK(gst_element_factory_make( "avdtpsink", "avdtpsink")); if (self->sink == NULL) { @@ -260,8 +273,10 @@ static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, break; } - if (ret == GST_STATE_CHANGE_FAILURE) + if (ret == GST_STATE_CHANGE_FAILURE) { + g_mutex_unlock(self->cb_mutex); return ret; + } ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); @@ -295,7 +310,6 @@ static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, gst_a2dp_sink_remove_dynamic_elements(self); break; - default: break; } @@ -558,16 +572,16 @@ static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event) if (self->newseg_event != NULL) gst_event_unref(self->newseg_event); self->newseg_event = gst_event_ref(event); + } else if (GST_EVENT_TYPE(event) == GST_EVENT_TAG && parent != GST_OBJECT_CAST(self)) { - if (self->taglist == NULL) { + if (self->taglist == NULL) gst_event_parse_tag(event, &self->taglist); - } else { + else { gst_event_parse_tag(event, &taglist); gst_tag_list_insert(self->taglist, taglist, GST_TAG_MERGE_REPLACE); } - /* FIXME handle tag events */ } if (parent != NULL) @@ -614,11 +628,15 @@ static gboolean gst_a2dp_sink_init_fakesink(GstA2dpSink *self) static gboolean gst_a2dp_sink_remove_fakesink(GstA2dpSink *self) { g_mutex_lock(self->cb_mutex); + if (self->fakesink != NULL) { + gst_element_set_locked_state(self->fakesink, TRUE); gst_element_set_state(self->fakesink, GST_STATE_NULL); + gst_bin_remove(GST_BIN(self), self->fakesink); self->fakesink = NULL; } + g_mutex_unlock(self->cb_mutex); return TRUE; diff --git a/audio/gstavdtpsink.c b/audio/gstavdtpsink.c index c956ecbd..25fc1ced 100644 --- a/audio/gstavdtpsink.c +++ b/audio/gstavdtpsink.c @@ -68,7 +68,7 @@ struct bluetooth_data { }; #define IS_SBC(n) (strcmp((n), "audio/x-sbc") == 0) -#define IS_MPEG(n) (strcmp((n), "audio/mpeg") == 0) +#define IS_MPEG_AUDIO(n) (strcmp((n), "audio/mpeg") == 0) enum { PROP_0, @@ -87,8 +87,12 @@ static const GstElementDetails avdtp_sink_details = static GstStaticPadTemplate avdtp_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("application/x-rtp, " - "media = (string) \"audio\", " - "encoding-name = (string) \"SBC\";" + "media = (string) \"audio\"," + "payload = (int) " + GST_RTP_PAYLOAD_DYNAMIC_STRING ", " + "clock-rate = (int) { 16000, 32000, " + "44100, 48000 }, " + "encoding-name = (string) \"SBC\"; " "application/x-rtp, " "media = (string) \"audio\", " "payload = (int) " @@ -231,7 +235,7 @@ static gint gst_avdtp_sink_bluetooth_recvmsg_fd(GstAvdtpSink *sink) return 0; } -static gboolean gst_avdtp_sink_init_pkt_conf(GstAvdtpSink *sink, +static gboolean gst_avdtp_sink_init_sbc_pkt_conf(GstAvdtpSink *sink, GstCaps *caps, sbc_capabilities_t *pkt) { @@ -242,9 +246,10 @@ static gboolean gst_avdtp_sink_init_pkt_conf(GstAvdtpSink *sink, GstStructure *structure = gst_caps_get_structure(caps, 0); name = gst_structure_get_name(structure); - /* FIXME only sbc supported here, should suport mp3 */ + if (!(IS_SBC(name))) { - GST_ERROR_OBJECT(sink, "Unsupported format %s", name); + GST_ERROR_OBJECT(sink, "Unexpected format %s, " + "was expecting sbc", name); return FALSE; } @@ -814,7 +819,7 @@ static void gst_avdtp_sink_tag(const GstTagList *taglist, if (!gst_tag_list_get_boolean(taglist, tag, &crc)) { GST_WARNING_OBJECT(self, "failed to get crc tag"); - self->mpeg_stream_changed = TRUE; + return; } gst_avdtp_sink_set_crc(self, crc); @@ -824,7 +829,7 @@ static void gst_avdtp_sink_tag(const GstTagList *taglist, if (!gst_tag_list_get_string(taglist, tag, &channel_mode)) { GST_WARNING_OBJECT(self, "failed to get channel-mode tag"); - self->mpeg_stream_changed = TRUE; + return; } self->channel_mode = gst_avdtp_sink_get_channel_mode( @@ -883,7 +888,6 @@ static gboolean gst_avdtp_sink_start(GstBaseSink *basesink) self->stream_caps = NULL; self->mp3_using_crc = -1; self->channel_mode = -1; - self->mpeg_stream_changed = FALSE; if (!gst_avdtp_sink_get_capabilities(self)) { GST_ERROR_OBJECT(self, "failed to get capabilities " @@ -957,8 +961,17 @@ static gboolean gst_avdtp_sink_init_mp3_pkt_conf( { const GValue *value = NULL; gint rate, layer; + const gchar* name; GstStructure *structure = gst_caps_get_structure(caps, 0); + name = gst_structure_get_name(structure); + + if (!(IS_MPEG_AUDIO(name))) { + GST_ERROR_OBJECT(self, "Unexpected format %s, " + "was expecting mp3", name); + return FALSE; + } + /* layer */ value = gst_structure_get_value(structure, "layer"); layer = g_value_get_int(value); @@ -1016,9 +1029,6 @@ static gboolean gst_avdtp_sink_init_mp3_pkt_conf( /* vbr - we always say its vbr, we don't have how to know it */ pkt->bitrate = 0x8000; - /* bitrate - we don't set anything, its vbr */ - /* FIXME - is this right? */ - return TRUE; } @@ -1044,7 +1054,7 @@ static gboolean gst_avdtp_sink_configure(GstAvdtpSink *self, structure = gst_caps_get_structure(caps, 0); if (gst_structure_has_name(structure, "audio/x-sbc")) - ret = gst_avdtp_sink_init_pkt_conf(self, caps, + ret = gst_avdtp_sink_init_sbc_pkt_conf(self, caps, &req->sbc_capabilities); else if (gst_structure_has_name(structure, "audio/mpeg")) ret = gst_avdtp_sink_init_mp3_pkt_conf(self, caps, @@ -1188,8 +1198,8 @@ static void gst_avdtp_sink_class_init(GstAvdtpSinkClass *klass) "Bluetooth remote device address", NULL, G_PARAM_READWRITE)); - GST_DEBUG_CATEGORY_INIT(avdtp_sink_debug, "a2dpsendersink", 0, - "A2DP sink element"); + GST_DEBUG_CATEGORY_INIT(avdtp_sink_debug, "avdtpsink", 0, + "A2DP headset sink element"); } static void gst_avdtp_sink_init(GstAvdtpSink *self, @@ -1203,6 +1213,11 @@ static void gst_avdtp_sink_init(GstAvdtpSink *self, self->dev_caps = NULL; self->sink_lock = g_mutex_new(); + + /* FIXME this is for not synchronizing with clock, should be tested + * with devices to see the behaviour + gst_base_sink_set_sync(GST_BASE_SINK(self), FALSE); + */ } static GIOError gst_avdtp_sink_audioservice_send( @@ -1325,9 +1340,7 @@ void gst_avdtp_sink_set_crc(GstAvdtpSink *self, gboolean crc) /* test if we already received a different crc */ if (self->mp3_using_crc != -1 && new_crc != self->mp3_using_crc) { - GST_ERROR_OBJECT(self, "crc changed during stream"); - /* FIXME test this, its not being used anywhere */ - self->mpeg_stream_changed = TRUE; + GST_WARNING_OBJECT(self, "crc changed during stream"); return; } self->mp3_using_crc = new_crc; @@ -1342,8 +1355,8 @@ void gst_avdtp_sink_set_channel_mode(GstAvdtpSink *self, new_mode = gst_avdtp_sink_get_channel_mode(mode); if (self->channel_mode != -1 && new_mode != self->channel_mode) { - GST_ERROR_OBJECT(self, "channel mode changed during stream"); - self->mpeg_stream_changed = TRUE; + GST_WARNING_OBJECT(self, "channel mode changed during stream"); + return; } self->channel_mode = new_mode; diff --git a/audio/gstavdtpsink.h b/audio/gstavdtpsink.h index d0380829..237597da 100644 --- a/audio/gstavdtpsink.h +++ b/audio/gstavdtpsink.h @@ -57,7 +57,6 @@ struct _GstAvdtpSink { GIOChannel *server; /* mp3 stream data (outside caps data)*/ - gboolean mpeg_stream_changed; gint mp3_using_crc; gint channel_mode; diff --git a/audio/gstrtpsbcpay.c b/audio/gstrtpsbcpay.c index 25bf70eb..ba2a4741 100644 --- a/audio/gstrtpsbcpay.c +++ b/audio/gstrtpsbcpay.c @@ -77,7 +77,7 @@ static const GstElementDetails gst_rtp_sbc_pay_details = static GstStaticPadTemplate gst_rtp_sbc_pay_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS("audio/x-sbc, " /* FIXME remove those caps? */ + GST_STATIC_CAPS("audio/x-sbc, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " "mode = (string) { mono, dual, stereo, joint }, " @@ -89,7 +89,12 @@ static GstStaticPadTemplate gst_rtp_sbc_pay_sink_factory = static GstStaticPadTemplate gst_rtp_sbc_pay_src_factory = GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS("application/x-rtp") /* FIXME put things here */ + GST_STATIC_CAPS( + "application/x-rtp, " + "media = (string) \"audio\"," + "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " + "clock-rate = (int) { 16000, 32000, 44100, 48000 }," + "encoding-name = (string) \"SBC\"") ); static void gst_rtp_sbc_pay_set_property (GObject * object, guint prop_id, @@ -148,7 +153,7 @@ static gboolean gst_rtp_sbc_pay_set_caps(GstBaseRTPPayload *payload, sbcpay->frame_length = frame_len; - gst_basertppayload_set_options (payload, "audio", FALSE, "SBC", rate); + gst_basertppayload_set_options (payload, "audio", TRUE, "SBC", rate); GST_DEBUG_OBJECT(payload, "calculated frame length: %d ", frame_len); @@ -209,6 +214,8 @@ static GstFlowReturn gst_rtp_sbc_pay_handle_buffer(GstBaseRTPPayload *payload, GstRtpSBCPay *sbcpay; guint available; + /* FIXME check for negotiation */ + sbcpay = GST_RTP_SBC_PAY(payload); gst_adapter_push(sbcpay->adapter, gst_buffer_copy(buffer)); diff --git a/audio/gstsbcdec.c b/audio/gstsbcdec.c index 8c27daba..a686a406 100644 --- a/audio/gstsbcdec.c +++ b/audio/gstsbcdec.c @@ -80,26 +80,12 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) while (offset < size) { GstBuffer *output; GstPadTemplate *template; - GstCaps *caps, *temp; + GstCaps *caps; int consumed; - caps = gst_caps_new_simple("audio/x-raw-int", - "rate", G_TYPE_INT, dec->sbc.rate, - "channels", G_TYPE_INT, dec->sbc.channels, - NULL); - - template = gst_static_pad_template_get(&sbc_dec_src_factory); - - temp = gst_caps_intersect(caps, - gst_pad_template_get_caps(template)); - - gst_caps_unref(caps); - res = gst_pad_alloc_buffer_and_set_caps(dec->srcpad, GST_BUFFER_OFFSET_NONE, - codesize, temp, &output); - - gst_caps_unref(temp); + codesize, NULL, &output); if (res != GST_FLOW_OK) goto done; @@ -110,7 +96,25 @@ static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) if (consumed <= 0) break; - GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); + /* we will reuse the same caps object */ + if (dec->outcaps == NULL) { + caps = gst_caps_new_simple("audio/x-raw-int", + "rate", G_TYPE_INT, dec->sbc.rate, + "channels", G_TYPE_INT, dec->sbc.channels, + NULL); + + template = gst_static_pad_template_get(&sbc_dec_src_factory); + + dec->outcaps = gst_caps_intersect(caps, + gst_pad_template_get_caps(template)); + + gst_caps_unref(caps); + } + + gst_buffer_set_caps(output, dec->outcaps); + + /* FIXME get a real timestamp */ + GST_BUFFER_TIMESTAMP(output) = GST_CLOCK_TIME_NONE; res = gst_pad_push(dec->srcpad, output); if (res != GST_FLOW_OK) @@ -143,6 +147,7 @@ static GstStateChangeReturn sbc_dec_change_state(GstElement *element, dec->buffer = NULL; } sbc_init(&dec->sbc, 0); + dec->outcaps = NULL; break; case GST_STATE_CHANGE_PAUSED_TO_READY: @@ -152,6 +157,10 @@ static GstStateChangeReturn sbc_dec_change_state(GstElement *element, dec->buffer = NULL; } sbc_finish(&dec->sbc); + if (dec->outcaps) { + gst_caps_unref(dec->outcaps); + dec->outcaps = NULL; + } break; default: @@ -197,6 +206,8 @@ static void gst_sbc_dec_init(GstSbcDec *self, GstSbcDecClass *klass) self->srcpad = gst_pad_new_from_static_template( &sbc_dec_src_factory, "src"); gst_element_add_pad(GST_ELEMENT(self), self->srcpad); + + self->outcaps = NULL; } gboolean gst_sbc_dec_plugin_init (GstPlugin * plugin) diff --git a/audio/gstsbcdec.h b/audio/gstsbcdec.h index 0bb0b57e..a88f8da5 100644 --- a/audio/gstsbcdec.h +++ b/audio/gstsbcdec.h @@ -49,6 +49,9 @@ struct _GstSbcDec { GstBuffer *buffer; + /* caps for outgoing buffers */ + GstCaps *outcaps; + sbc_t sbc; }; diff --git a/audio/gstsbcparse.c b/audio/gstsbcparse.c index 49d0bb6e..1f699620 100644 --- a/audio/gstsbcparse.c +++ b/audio/gstsbcparse.c @@ -43,7 +43,8 @@ static const GstElementDetails sbc_parse_details = static GstStaticPadTemplate sbc_parse_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS("audio/x-sbc")); + GST_STATIC_CAPS("audio/x-sbc," + "parsed = (boolean) false")); static GstStaticPadTemplate sbc_parse_src_factory = GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, @@ -54,86 +55,8 @@ static GstStaticPadTemplate sbc_parse_src_factory = "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " "allocation = (string) { snr, loudness }," - "bitpool = (int) [ 2, 64 ]")); - -static gboolean sbc_parse_sink_setcaps(GstPad * pad, GstCaps * caps) -{ - GstSbcParse *parse; - GstStructure *structure; - gint rate, channels; - - parse = GST_SBC_PARSE(GST_PAD_PARENT(pad)); - - structure = gst_caps_get_structure(caps, 0); - - if (!gst_structure_get_int(structure, "rate", &rate)) - return FALSE; - - if (!gst_structure_get_int(structure, "channels", &channels)) - return FALSE; - - if (!(parse->rate == 0 || rate == parse->rate)) - return FALSE; - - if (!(parse->channels == 0 || channels == parse->channels)) - return FALSE; - - parse->rate = rate; - parse->channels = channels; - - return gst_sbc_util_fill_sbc_params(&parse->sbc, caps); -} - -static GstCaps* sbc_parse_src_getcaps(GstPad *pad) -{ - GstCaps *caps; - const GstCaps *allowed_caps; - GstStructure *structure; - GValue *value; - GstSbcParse *parse = GST_SBC_PARSE(GST_PAD_PARENT(pad)); - - allowed_caps = gst_pad_get_allowed_caps(pad); - if (allowed_caps == NULL) - allowed_caps = gst_pad_get_pad_template_caps(pad); - caps = gst_caps_copy(allowed_caps); - - value = g_new0(GValue, 1); - - structure = gst_caps_get_structure(caps, 0); - - if (parse->rate != 0) - gst_sbc_util_set_structure_int_param(structure, "rate", - parse->rate, value); - if (parse->channels != 0) - gst_sbc_util_set_structure_int_param(structure, "channels", - parse->channels, value); - - g_free(value); - - return caps; -} - -static gboolean sbc_parse_src_acceptcaps(GstPad *pad, GstCaps *caps) -{ - GstStructure *structure; - GstSbcParse *parse; - gint rate, channels; - - parse = GST_SBC_PARSE(GST_PAD_PARENT(pad)); - - structure = gst_caps_get_structure(caps, 0); - - if (!gst_structure_get_int(structure, "rate", &rate)) - return FALSE; - if (!gst_structure_get_int(structure, "channels", &channels)) - return FALSE; - - if ((parse->rate == 0 || parse->rate == rate) - && (parse->channels == 0 || parse->channels == channels)) - return TRUE; - - return FALSE; -} + "bitpool = (int) [ 2, 64 ]," + "parsed = (boolean) true")); static GstFlowReturn sbc_parse_chain(GstPad *pad, GstBuffer *buffer) { @@ -261,17 +184,10 @@ static void gst_sbc_parse_init(GstSbcParse *self, GstSbcParseClass *klass) &sbc_parse_sink_factory, "sink"); gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_parse_chain)); - gst_pad_set_setcaps_function (self->sinkpad, - GST_DEBUG_FUNCPTR (sbc_parse_sink_setcaps)); gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); self->srcpad = gst_pad_new_from_static_template( &sbc_parse_src_factory, "src"); - gst_pad_set_getcaps_function (self->srcpad, - GST_DEBUG_FUNCPTR (sbc_parse_src_getcaps)); - gst_pad_set_acceptcaps_function (self->srcpad, - GST_DEBUG_FUNCPTR (sbc_parse_src_acceptcaps)); - /* FIXME get encoding parameters on set caps */ gst_element_add_pad(GST_ELEMENT(self), self->srcpad); } diff --git a/audio/gstsbcutil.c b/audio/gstsbcutil.c index 78024f7e..e5d21af0 100644 --- a/audio/gstsbcutil.c +++ b/audio/gstsbcutil.c @@ -364,9 +364,12 @@ GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message) goto error; } else { value = gst_structure_get_value(structure, "mode"); - if (GST_VALUE_HOLDS_LIST(value)) - mode = gst_sbc_get_mode_from_list(value); - else + if (GST_VALUE_HOLDS_LIST(value)) { + if (channels == 1) + mode = "mono"; + else + mode = gst_sbc_get_mode_from_list(value); + } else mode = g_value_get_string(value); } -- cgit