diff --git a/sys/bluez/gsta2dpsink.c b/sys/bluez/gsta2dpsink.c index dc0eb474a7..80486afb04 100644 --- a/sys/bluez/gsta2dpsink.c +++ b/sys/bluez/gsta2dpsink.c @@ -66,6 +66,18 @@ 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 gboolean gst_a2dp_sink_init_fakesink (GstA2dpSink * self); +static gboolean gst_a2dp_sink_remove_fakesink (GstA2dpSink * self); + +static void +gst_a2dp_sink_finalize (GObject * obj) +{ + GstA2dpSink *self = GST_A2DP_SINK (obj); + + g_mutex_free (self->cb_mutex); + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} /* * Helper function to create elements, add to the bin and link it @@ -90,9 +102,9 @@ gst_a2dp_sink_init_element (GstA2dpSink * self, goto cleanup_and_fail; } - if (gst_element_set_state (element, GST_STATE_READY) == + if (gst_element_set_state (element, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - GST_ERROR_OBJECT (self, "%s failed to go to ready", elementname); + GST_ERROR_OBJECT (self, "%s failed to go to playing", elementname); goto remove_element_and_fail; } @@ -221,6 +233,8 @@ gst_a2dp_sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: self->taglist = gst_tag_list_new (); + + gst_a2dp_sink_init_fakesink (self); break; case GST_STATE_CHANGE_NULL_TO_READY: @@ -257,6 +271,7 @@ gst_a2dp_sink_change_state (GstElement * element, GstStateChange transition) gst_event_unref (self->newseg_event); self->newseg_event = NULL; } + gst_a2dp_sink_remove_fakesink (self); break; case GST_STATE_CHANGE_READY_TO_NULL: @@ -271,7 +286,6 @@ gst_a2dp_sink_change_state (GstElement * element, GstStateChange transition) self->sink = NULL; gst_a2dp_sink_remove_dynamic_elements (self); - break; default: @@ -292,6 +306,8 @@ gst_a2dp_sink_class_init (GstA2dpSinkClass * klass) object_class->set_property = GST_DEBUG_FUNCPTR (gst_a2dp_sink_set_property); object_class->get_property = GST_DEBUG_FUNCPTR (gst_a2dp_sink_get_property); + object_class->finalize = GST_DEBUG_FUNCPTR (gst_a2dp_sink_finalize); + element_class->change_state = GST_DEBUG_FUNCPTR (gst_a2dp_sink_change_state); g_object_class_install_property (object_class, PROP_DEVICE, @@ -302,7 +318,7 @@ gst_a2dp_sink_class_init (GstA2dpSinkClass * klass) "A2DP sink element"); } -static GstCaps * +GstCaps * gst_a2dp_sink_get_device_caps (GstA2dpSink * self) { return gst_avdtp_sink_get_device_caps (self->sink); @@ -332,12 +348,16 @@ gst_a2dp_sink_get_caps (GstPad * pad) } static gboolean -gst_a2dp_sink_init_sender_sink (GstA2dpSink * self) +gst_a2dp_sink_init_avdtp_sink (GstA2dpSink * self) { GstElement *sink; + /* check if we don't need a new sink */ + if (self->sink_is_in_bin) + return TRUE; + if (self->sink == NULL) - sink = gst_element_factory_make ("avdtpsink", "avdtosink"); + sink = gst_element_factory_make ("avdtpsink", "avdtpsink"); else sink = GST_ELEMENT (self->sink); @@ -386,6 +406,10 @@ gst_a2dp_sink_init_rtp_sbc_element (GstA2dpSink * self) { GstElement *rtppay; + /* if we already have a rtp, we don't need a new one */ + if (self->rtp != NULL) + return TRUE; + rtppay = gst_a2dp_sink_init_element (self, "rtpsbcpay", "rtp", self->capsfilter); if (rtppay == NULL) @@ -404,8 +428,11 @@ gst_a2dp_sink_init_rtp_mpeg_element (GstA2dpSink * self) { GstElement *rtppay; - GST_LOG_OBJECT (self, "Initializing rtp mpeg element"); + /* check if we don't need a new rtp */ + if (self->rtp) + return TRUE; + GST_LOG_OBJECT (self, "Initializing rtp mpeg element"); /* if capsfilter is not created then we can't have our rtp element */ if (self->capsfilter == NULL) return FALSE; @@ -433,6 +460,9 @@ gst_a2dp_sink_init_dynamic_elements (GstA2dpSink * self, GstCaps * caps) structure = gst_caps_get_structure (caps, 0); + /* before everything we need to remove fakesink */ + gst_a2dp_sink_remove_fakesink (self); + /* first, we need to create our rtp payloader */ if (gst_structure_has_name (structure, "audio/x-sbc")) { GST_LOG_OBJECT (self, "sbc media received"); @@ -447,7 +477,7 @@ gst_a2dp_sink_init_dynamic_elements (GstA2dpSink * self, GstCaps * caps) return FALSE; } - if (!gst_a2dp_sink_init_sender_sink (self)) + if (!gst_a2dp_sink_init_avdtp_sink (self)) return FALSE; /* check if we should push the taglist FIXME should we push this? @@ -506,18 +536,18 @@ gst_a2dp_sink_handle_event (GstPad * pad, GstEvent * event) { GstA2dpSink *self; GstTagList *taglist = NULL; + GstObject *parent; self = GST_A2DP_SINK (GST_PAD_PARENT (pad)); + parent = gst_element_get_parent (GST_ELEMENT (self->sink)); if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT && - gst_element_get_parent (GST_ELEMENT (self->sink)) != - GST_OBJECT_CAST (self)) { + parent != GST_OBJECT_CAST (self)) { 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)) { + parent != GST_OBJECT_CAST (self)) { if (self->taglist == NULL) { gst_event_parse_tag (event, &self->taglist); } else { @@ -527,6 +557,9 @@ gst_a2dp_sink_handle_event (GstPad * pad, GstEvent * event) /* FIXME handle tag events */ } + if (parent != NULL) + gst_object_unref (GST_OBJECT (parent)); + return self->ghostpad_eventfunc (GST_PAD (self->ghostpad), event); } @@ -550,10 +583,42 @@ failed: return FALSE; } +static gboolean +gst_a2dp_sink_init_fakesink (GstA2dpSink * self) +{ + if (self->fakesink != NULL) + return TRUE; + + g_mutex_lock (self->cb_mutex); + self->fakesink = gst_a2dp_sink_init_element (self, "fakesink", + "fakesink", self->capsfilter); + g_mutex_unlock (self->cb_mutex); + + if (!self->fakesink) + return FALSE; + + return TRUE; +} + +static gboolean +gst_a2dp_sink_remove_fakesink (GstA2dpSink * self) +{ + g_mutex_lock (self->cb_mutex); + if (self->fakesink != NULL) { + 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; +} + static void gst_a2dp_sink_init (GstA2dpSink * self, GstA2dpSinkClass * klass) { self->sink = NULL; + self->fakesink = NULL; self->rtp = NULL; self->device = NULL; self->capsfilter = NULL; @@ -562,11 +627,15 @@ gst_a2dp_sink_init (GstA2dpSink * self, GstA2dpSinkClass * klass) self->ghostpad = NULL; self->sink_is_in_bin = FALSE; + self->cb_mutex = g_mutex_new (); + /* we initialize our capsfilter */ gst_a2dp_sink_init_caps_filter (self); g_object_set (self->capsfilter, "caps", gst_static_pad_template_get_caps (&gst_a2dp_sink_factory), NULL); + gst_a2dp_sink_init_fakesink (self); + gst_a2dp_sink_init_ghost_pad (self); } diff --git a/sys/bluez/gsta2dpsink.h b/sys/bluez/gsta2dpsink.h index 26da4c473f..676c37e530 100644 --- a/sys/bluez/gsta2dpsink.h +++ b/sys/bluez/gsta2dpsink.h @@ -25,6 +25,9 @@ #include #include "gstavdtpsink.h" +#ifndef __GST_A2DP_SINK_H__ +#define __GST_A2DP_SINK_H__ + G_BEGIN_DECLS #define GST_TYPE_A2DP_SINK \ @@ -47,6 +50,7 @@ struct _GstA2dpSink { GstBaseRTPPayload *rtp; GstAvdtpSink *sink; GstElement *capsfilter; + GstElement *fakesink; gchar *device; gboolean sink_is_in_bin; @@ -59,6 +63,8 @@ struct _GstA2dpSink { /* Store the tags received before the a2dpsender sink is created * when it is created we forward this to it */ GstTagList *taglist; + + GMutex *cb_mutex; }; struct _GstA2dpSinkClass { @@ -68,4 +74,8 @@ struct _GstA2dpSinkClass { GType gst_a2dp_sink_get_type(void); gboolean gst_a2dp_sink_plugin_init (GstPlugin * plugin); +GstCaps *gst_a2dp_sink_get_device_caps(GstA2dpSink *self); + G_END_DECLS + +#endif