diff options
author | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2008-01-23 13:19:32 +0000 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2008-01-23 13:19:32 +0000 |
commit | de8b4e7ab91bad2c1c6e796f53d4e69ecbadd0bd (patch) | |
tree | 463d60836eb333740023dabc85b68fe442e588c5 /audio/gsta2dpsink.c | |
parent | 489c2e0dbd76d9cecec62d19fafd9e7baddb72e7 (diff) |
Add mp3 support for gstreamer plugin.
Diffstat (limited to 'audio/gsta2dpsink.c')
-rw-r--r-- | audio/gsta2dpsink.c | 212 |
1 files changed, 176 insertions, 36 deletions
diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c index d90909c7..091d5472 100644 --- a/audio/gsta2dpsink.c +++ b/audio/gsta2dpsink.c @@ -61,8 +61,14 @@ static GstStaticPadTemplate gst_a2dp_sink_factory = "allocation = (string) { snr, loudness }, " "bitpool = (int) [ 2, " TEMPLATE_MAX_BITPOOL_STR " ]; " + "audio/mpeg;" )); +static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event); +static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps); +static GstCaps *gst_a2dp_sink_get_caps(GstPad *pad); +static gboolean gst_a2dp_sink_init_caps_filter(GstA2dpSink *self); + static void gst_a2dp_sink_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); @@ -116,30 +122,100 @@ static void gst_a2dp_sink_get_property(GObject *object, guint prop_id, } } +static gboolean gst_a2dp_sink_init_ghost_pad(GstA2dpSink *self) +{ + GstPad *capsfilter_pad; + + /* we search for the capsfilter sinkpad */ + capsfilter_pad = gst_element_get_static_pad(self->capsfilter, "sink"); + + /* now we add a ghostpad */ + self->ghostpad = GST_GHOST_PAD(gst_ghost_pad_new("sink", + capsfilter_pad)); + g_object_unref(capsfilter_pad); + + /* the getcaps of our ghostpad must reflect the device caps */ + gst_pad_set_getcaps_function(GST_PAD(self->ghostpad), + gst_a2dp_sink_get_caps); + self->ghostpad_setcapsfunc = GST_PAD_SETCAPSFUNC(self->ghostpad); + gst_pad_set_setcaps_function(GST_PAD(self->ghostpad), + GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_caps)); + + /* we need to handle events on our own and we also need the eventfunc + * of the ghostpad for forwarding calls */ + self->ghostpad_eventfunc = GST_PAD_EVENTFUNC(GST_PAD(self->ghostpad)); + gst_pad_set_event_function(GST_PAD(self->ghostpad), + gst_a2dp_sink_handle_event); + + if (!gst_element_add_pad(GST_ELEMENT(self), GST_PAD(self->ghostpad))) + GST_ERROR_OBJECT(self, "failed to add ghostpad"); + + return TRUE; +} + static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, GstStateChange transition) { + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstA2dpSink *self = GST_A2DP_SINK(element); switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + self->taglist = gst_tag_list_new(); + break; + case GST_STATE_CHANGE_NULL_TO_READY: - gst_element_set_state(GST_ELEMENT(self->sink), + self->sink = GST_A2DP_SENDER_SINK(gst_element_factory_make( + "a2dpsendersink", "sendersink")); + if (self->sink == NULL) { + GST_WARNING_OBJECT(self, "failed to create a2dpsendersink"); + return GST_STATE_CHANGE_FAILURE; + } + + if (self->device != NULL) + gst_a2dp_sender_sink_set_device(self->sink, + self->device); + + ret = gst_element_set_state(GST_ELEMENT(self->sink), GST_STATE_READY); break; + default: + break; + } - case GST_STATE_CHANGE_READY_TO_NULL: + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, + transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + if (self->taglist) { + gst_tag_list_free(self->taglist); + self->taglist = NULL; + } if (self->newseg_event != NULL) { gst_event_unref(self->newseg_event); self->newseg_event = NULL; } + if (self->taglist) { + gst_tag_list_free(self->taglist); + self->taglist = NULL; + } + break; + + case GST_STATE_CHANGE_READY_TO_NULL: + if (!gst_bin_remove(GST_BIN(self), GST_ELEMENT(self->sink))) + GST_WARNING_OBJECT(self, "Failed to remove " + "a2dpsendersink from bin"); break; default: break; } - return GST_ELEMENT_CLASS(parent_class)->change_state(element, - transition); + return ret; } static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass) @@ -281,6 +357,54 @@ static gboolean gst_a2dp_sink_init_rtp_sbc_element(GstA2dpSink *self) return TRUE; remove_element_and_fail: + gst_element_set_state(rtppay, GST_STATE_NULL); + gst_bin_remove(GST_BIN(self), rtppay); + return FALSE; + +cleanup_and_fail: + if (rtppay != NULL) + g_object_unref(G_OBJECT(rtppay)); + + return FALSE; +} + +static gboolean gst_a2dp_sink_init_rtp_mpeg_element(GstA2dpSink *self) +{ + GstElement *rtppay; + + /* FIXME we will need a internal mpegparse for identifying + * stream stuff */ + + rtppay = gst_element_factory_make("rtpmpapay", "rtp"); + if (rtppay == NULL) { + GST_ERROR_OBJECT(self, "Couldn't create rtpmpapay"); + return FALSE; + } + + if (!gst_bin_add(GST_BIN(self), rtppay)) { + GST_ERROR_OBJECT(self, "failed to add rtpmpapay to the bin"); + goto cleanup_and_fail; + } + + if (gst_element_set_state(rtppay, GST_STATE_READY) == + GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT(self, "rtpmpapay failed to go to ready"); + goto remove_element_and_fail; + } + + if (!gst_element_link(self->capsfilter, rtppay)) { + GST_ERROR_OBJECT(self, "couldn't link capsfilter " + "to rtpmpapay"); + goto remove_element_and_fail; + } + + self->rtp = GST_BASE_RTP_PAYLOAD(rtppay); + + gst_element_set_state(rtppay, GST_STATE_PAUSED); + + return TRUE; + +remove_element_and_fail: gst_element_set_state (rtppay, GST_STATE_NULL); gst_bin_remove(GST_BIN(self), rtppay); return FALSE; @@ -296,6 +420,10 @@ static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps) { GstA2dpSink *self; GstStructure *structure; + GstEvent *event; + GstPad *capsfilterpad; + gboolean crc; + gchar *mode = NULL; self = GST_A2DP_SINK(GST_PAD_PARENT(pad)); GST_INFO_OBJECT(self, "setting caps"); @@ -303,9 +431,13 @@ static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps) structure = gst_caps_get_structure(caps, 0); /* first, we need to create our rtp payloader */ - if (gst_structure_has_name(structure, "audio/x-sbc")) - gst_a2dp_sink_init_rtp_sbc_element(self); - else { + if (gst_structure_has_name(structure, "audio/x-sbc")) { + if (!gst_a2dp_sink_init_rtp_sbc_element(self)) + return FALSE; + } else if (gst_structure_has_name(structure, "audio/mpeg")) { + if (!gst_a2dp_sink_init_rtp_mpeg_element(self)) + return FALSE; + } else { GST_ERROR_OBJECT(self, "Unexpected media type"); return FALSE; } @@ -313,6 +445,27 @@ static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps) if (!gst_a2dp_sink_init_sender_sink(self)) return FALSE; + /* check if we should push the taglist FIXME should we push this? + * we can send the tags directly if needed */ + if (self->taglist != NULL && + gst_structure_has_name(structure, "audio/mpeg")) { + + event = gst_event_new_tag(self->taglist); + + /* send directly the crc */ + if (gst_tag_list_get_boolean(self->taglist, "has-crc", &crc)) + gst_a2dp_sender_sink_set_crc(self->sink, crc); + + if (gst_tag_list_get_string(self->taglist, "channel-mode", + &mode)) + gst_a2dp_sender_sink_set_channel_mode(self->sink, mode); + + capsfilterpad = gst_ghost_pad_get_target(self->ghostpad); + gst_pad_send_event(capsfilterpad, event); + self->taglist = NULL; + g_free(mode); + } + if (!gst_a2dp_sender_sink_set_device_caps(self->sink, caps)) return FALSE; @@ -332,6 +485,7 @@ static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps) static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event) { GstA2dpSink *self; + GstTagList *taglist = NULL; self = GST_A2DP_SINK(GST_PAD_PARENT(pad)); @@ -341,6 +495,17 @@ 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 && + gst_element_get_parent(GST_ELEMENT(self->sink)) != + GST_OBJECT_CAST(self)) { + if (self->taglist == NULL) { + gst_event_parse_tag(event, &self->taglist); + } else { + gst_event_parse_tag(event, &taglist); + gst_tag_list_insert(self->taglist, taglist, + GST_TAG_MERGE_REPLACE); + } + /* FIXME handle tag events */ } return self->ghostpad_eventfunc(GST_PAD(self->ghostpad), event); @@ -368,13 +533,14 @@ failed: static void gst_a2dp_sink_init(GstA2dpSink *self, GstA2dpSinkClass *klass) { - GstPad *capsfilter_pad; - self->sink = NULL; self->rtp = NULL; self->device = NULL; self->capsfilter = NULL; + self->mpegparse = NULL; self->newseg_event = NULL; + self->taglist = NULL; + self->ghostpad = NULL; /* we initialize our capsfilter */ gst_a2dp_sink_init_caps_filter(self); @@ -382,34 +548,8 @@ static void gst_a2dp_sink_init(GstA2dpSink *self, gst_static_pad_template_get_caps(&gst_a2dp_sink_factory), NULL); - /* we search for the capsfilter sinkpad */ - capsfilter_pad = gst_element_get_static_pad(self->capsfilter, "sink"); - - /* now we add a ghostpad */ - self->ghostpad = GST_GHOST_PAD(gst_ghost_pad_new("sink", - capsfilter_pad)); - g_object_unref(capsfilter_pad); + gst_a2dp_sink_init_ghost_pad(self); - /* the getcaps of our ghostpad must reflect the device caps */ - gst_pad_set_getcaps_function(GST_PAD(self->ghostpad), - gst_a2dp_sink_get_caps); - self->ghostpad_setcapsfunc = GST_PAD_SETCAPSFUNC(self->ghostpad); - gst_pad_set_setcaps_function(GST_PAD(self->ghostpad), - GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_caps)); - - /* we need to handle events on our own and we also need the eventfunc - * of the ghostpad for forwarding calls */ - self->ghostpad_eventfunc = GST_PAD_EVENTFUNC(GST_PAD(self->ghostpad)); - gst_pad_set_event_function(GST_PAD(self->ghostpad), - gst_a2dp_sink_handle_event); - - if (!gst_element_add_pad(GST_ELEMENT(self), GST_PAD(self->ghostpad))) - GST_ERROR_OBJECT(self, "failed to add ghostpad"); - - self->sink = GST_A2DP_SENDER_SINK(gst_element_factory_make( - "a2dpsendersink", "sendersink")); - if (self->sink == NULL) - GST_WARNING_OBJECT(self, "failed to create a2dpsendersink"); } gboolean gst_a2dp_sink_plugin_init (GstPlugin * plugin) |