diff options
Diffstat (limited to 'audio/gsta2dpsink.c')
-rw-r--r-- | audio/gsta2dpsink.c | 194 |
1 files changed, 113 insertions, 81 deletions
diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c index 091d5472..7c68d17f 100644 --- a/audio/gsta2dpsink.c +++ b/audio/gsta2dpsink.c @@ -69,6 +69,56 @@ 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); +/* + * Helper function to create elements, add to the bin and link it + * to another element. + */ +static GstElement* gst_a2dp_sink_init_element(GstA2dpSink *self, + const gchar* elementname, const gchar* name, + GstElement *link_to) +{ + GstElement *element; + + GST_LOG_OBJECT(self, "Initializing %s", elementname); + + element = gst_element_factory_make(elementname, name); + if (element == NULL) { + GST_ERROR_OBJECT(self, "Couldn't create %s", elementname); + return NULL; + } + + if (!gst_bin_add(GST_BIN(self), element)) { + GST_ERROR_OBJECT(self, "failed to add %s to the bin", + elementname); + goto cleanup_and_fail; + } + + if (gst_element_set_state(element, GST_STATE_READY) == + GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT(self, "%s failed to go to ready", + 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; + } + + return element; + +remove_element_and_fail: + gst_element_set_state(element, GST_STATE_NULL); + gst_bin_remove(GST_BIN(self), element); + return NULL; + +cleanup_and_fail: + if (element != NULL) + g_object_unref(G_OBJECT(element)); + + return NULL; +} + static void gst_a2dp_sink_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); @@ -153,6 +203,18 @@ static gboolean gst_a2dp_sink_init_ghost_pad(GstA2dpSink *self) return TRUE; } +static void gst_a2dp_sink_remove_dynamic_elements(GstA2dpSink *self) +{ + if (self->rtp) { + GST_LOG_OBJECT(self, "removing rtp element from the bin"); + if (!gst_bin_remove(GST_BIN(self), GST_ELEMENT(self->rtp))) + GST_WARNING_OBJECT(self, "failed to remove rtp " + "element from bin"); + else + self->rtp = NULL; + } +} + static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, GstStateChange transition) { @@ -165,6 +227,8 @@ static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, break; case GST_STATE_CHANGE_NULL_TO_READY: + self->sink_is_in_bin = FALSE; + self->sink = GST_A2DP_SENDER_SINK(gst_element_factory_make( "a2dpsendersink", "sendersink")); if (self->sink == NULL) { @@ -199,16 +263,24 @@ static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, 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"); + if (self->sink_is_in_bin) { + if (!gst_bin_remove(GST_BIN(self), + GST_ELEMENT(self->sink))) + GST_WARNING_OBJECT(self, "Failed to remove " + "a2dpsendersink from bin"); + } else if (self->sink != NULL) { + gst_element_set_state(GST_ELEMENT(self->sink), + GST_STATE_NULL); + g_object_unref(G_OBJECT(self->sink)); + } + + self->sink = NULL; + + gst_a2dp_sink_remove_dynamic_elements(self); + break; default: @@ -304,6 +376,7 @@ static gboolean gst_a2dp_sink_init_sender_sink(GstA2dpSink *self) } self->sink = GST_A2DP_SENDER_SINK(sink); + self->sink_is_in_bin = TRUE; g_object_set(G_OBJECT(self->sink), "device", self->device, NULL); gst_element_set_state(sink, GST_STATE_PAUSED); @@ -326,28 +399,10 @@ static gboolean gst_a2dp_sink_init_rtp_sbc_element(GstA2dpSink *self) { GstElement *rtppay; - rtppay = gst_element_factory_make("rtpsbcpay", "rtp"); - if (rtppay == NULL) { - GST_ERROR_OBJECT(self, "Couldn't create rtpsbcpay"); + rtppay = gst_a2dp_sink_init_element(self, "rtpsbcpay", "rtp", + self->capsfilter); + if (rtppay == NULL) return FALSE; - } - - if (!gst_bin_add(GST_BIN(self), rtppay)) { - GST_ERROR_OBJECT(self, "failed to add rtp sbc pay to the bin"); - goto cleanup_and_fail; - } - - if (gst_element_set_state(rtppay, GST_STATE_READY) == - GST_STATE_CHANGE_FAILURE) { - GST_ERROR_OBJECT(self, "rtpsbcpay 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 rtpsbcpay"); - goto remove_element_and_fail; - } self->rtp = GST_BASE_RTP_PAYLOAD(rtppay); g_object_set(G_OBJECT(self->rtp), "min-frames", -1, NULL); @@ -355,86 +410,48 @@ static gboolean gst_a2dp_sink_init_rtp_sbc_element(GstA2dpSink *self) 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; - -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 */ + GST_LOG_OBJECT(self, "Initializing rtp mpeg element"); - rtppay = gst_element_factory_make("rtpmpapay", "rtp"); - if (rtppay == NULL) { - GST_ERROR_OBJECT(self, "Couldn't create rtpmpapay"); + /* if capsfilter is not created then we can't have our rtp element */ + if (self->capsfilter == NULL) 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; - } + rtppay = gst_a2dp_sink_init_element(self, "rtpmpapay", "rtp", + self->capsfilter); + if (rtppay == NULL) + return FALSE; 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; - -cleanup_and_fail: - if (rtppay != NULL) - g_object_unref(G_OBJECT(rtppay)); - - return FALSE; } -static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps) +static gboolean gst_a2dp_sink_init_dynamic_elements(GstA2dpSink *self, + 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"); - 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_LOG_OBJECT(self, "sbc media received"); if (!gst_a2dp_sink_init_rtp_sbc_element(self)) return FALSE; } else if (gst_structure_has_name(structure, "audio/mpeg")) { + GST_LOG_OBJECT(self, "mp3 media received"); if (!gst_a2dp_sink_init_rtp_mpeg_element(self)) return FALSE; } else { @@ -473,9 +490,24 @@ static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps) gst_a2dp_sender_sink_get_link_mtu(self->sink), NULL); /* we forward our new segment here if we have one */ - gst_pad_send_event(GST_BASE_RTP_PAYLOAD_SINKPAD(self->rtp), - self->newseg_event); - self->newseg_event = NULL; + if (self->newseg_event) { + gst_pad_send_event(GST_BASE_RTP_PAYLOAD_SINKPAD(self->rtp), + self->newseg_event); + self->newseg_event = NULL; + } + + return TRUE; +} + +static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps) +{ + GstA2dpSink *self; + + self = GST_A2DP_SINK(GST_PAD_PARENT(pad)); + GST_INFO_OBJECT(self, "setting caps"); + + /* now we know the caps */ + gst_a2dp_sink_init_dynamic_elements(self, caps); return self->ghostpad_setcapsfunc(GST_PAD(self->ghostpad), caps); } @@ -537,10 +569,10 @@ static void gst_a2dp_sink_init(GstA2dpSink *self, self->rtp = NULL; self->device = NULL; self->capsfilter = NULL; - self->mpegparse = NULL; self->newseg_event = NULL; self->taglist = NULL; self->ghostpad = NULL; + self->sink_is_in_bin = FALSE; /* we initialize our capsfilter */ gst_a2dp_sink_init_caps_filter(self); |