documentation: fixed a heap o' typos
[platform/upstream/gstreamer.git] / gst / rtp / gstrtpsrc.c
1 /* GStreamer
2  * Copyright (C) <2018> Marc Leeman <marc.leeman@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * SECTION: gstrtpsrc
22  * @title: GstRtpSrc
23  * @short description: element with Uri interface to get RTP data from
24  * the network.
25  *
26  * RTP (RFC 3550) is a protocol to stream media over the network while
27  * retaining the timing information and providing enough information to
28  * reconstruct the correct timing domain by the receiver.
29  *
30  * The RTP data port should be even, while the RTCP port should be
31  * odd. The URI that is entered defines the data port, the RTCP port will
32  * be allocated to the next port.
33  *
34  * This element hooks up the correct sockets to support both RTP as the
35  * accompanying RTCP layer.
36  *
37  * This Bin handles taking in of data from the network and provides the
38  * RTP payloaded data.
39  *
40  * This element also implements the URI scheme `rtp://` allowing to render
41  * RTP streams in GStreamer based media players. The RTP URI handler also
42  * allows setting properties through the URI query.
43  */
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 #include <gst/net/net.h>
49 #include <gst/rtp/gstrtppayloads.h>
50
51 #include "gstrtpsrc.h"
52 #include "gstrtp-utils.h"
53
54 GST_DEBUG_CATEGORY_STATIC (gst_rtp_src_debug);
55 #define GST_CAT_DEFAULT gst_rtp_src_debug
56
57 #define DEFAULT_PROP_TTL              64
58 #define DEFAULT_PROP_TTL_MC           1
59 #define DEFAULT_PROP_ENCODING_NAME    NULL
60 #define DEFAULT_PROP_LATENCY          200
61
62 #define DEFAULT_PROP_ADDRESS          "0.0.0.0"
63 #define DEFAULT_PROP_PORT             5004
64 #define DEFAULT_PROP_URI              "rtp://"DEFAULT_PROP_ADDRESS":"G_STRINGIFY(DEFAULT_PROP_PORT)
65
66 enum
67 {
68   PROP_0,
69
70   PROP_URI,
71   PROP_ADDRESS,
72   PROP_PORT,
73   PROP_TTL,
74   PROP_TTL_MC,
75   PROP_ENCODING_NAME,
76   PROP_LATENCY,
77
78   PROP_LAST
79 };
80
81 static void gst_rtp_src_uri_handler_init (gpointer g_iface,
82     gpointer iface_data);
83
84 #define gst_rtp_src_parent_class parent_class
85 G_DEFINE_TYPE_WITH_CODE (GstRtpSrc, gst_rtp_src, GST_TYPE_BIN,
86     G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_rtp_src_uri_handler_init);
87     GST_DEBUG_CATEGORY_INIT (gst_rtp_src_debug, "rtpsrc", 0, "RTP Source"));
88
89 #define GST_RTP_SRC_GET_LOCK(obj) (&((GstRtpSrc*)(obj))->lock)
90 #define GST_RTP_SRC_LOCK(obj) (g_mutex_lock (GST_RTP_SRC_GET_LOCK(obj)))
91 #define GST_RTP_SRC_UNLOCK(obj) (g_mutex_unlock (GST_RTP_SRC_GET_LOCK(obj)))
92
93 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
94     GST_PAD_SRC,
95     GST_PAD_SOMETIMES,
96     GST_STATIC_CAPS ("application/x-rtp"));
97
98 static GstStateChangeReturn
99 gst_rtp_src_change_state (GstElement * element, GstStateChange transition);
100
101 /**
102  * gst_rtp_src_rtpbin_request_pt_map_cb:
103  * @self: The current #GstRtpSrc object
104  *
105  * #GstRtpBin callback to map a pt on RTP caps.
106  *
107  * Returns: (transfer none): the guess on the RTP caps based on the PT
108  * and caps.
109  */
110 static GstCaps *
111 gst_rtp_src_rtpbin_request_pt_map_cb (GstElement * rtpbin, guint session_id,
112     guint pt, gpointer data)
113 {
114   GstRtpSrc *self = GST_RTP_SRC (data);
115   const GstRTPPayloadInfo *p = NULL;
116
117   GST_DEBUG_OBJECT (self,
118       "Requesting caps for session-id 0x%x and pt %u.", session_id, pt);
119
120   /* the encoding-name has more relevant information */
121   if (self->encoding_name != NULL) {
122     /* Unfortunately, the media needs to be passed in the function. Since
123      * it is not known, try for video if video not found. */
124     p = gst_rtp_payload_info_for_name ("video", self->encoding_name);
125     if (p == NULL)
126       p = gst_rtp_payload_info_for_name ("audio", self->encoding_name);
127
128   }
129
130   /* If info has been found before based on the encoding-name, go with
131    * it. If not, try to look it up on with a static one. Needs to be guarded
132    * because some encoders do not use dynamic values for H.264 */
133   if (p == NULL) {
134     /* Static payload types, this is a simple lookup */
135     if (!GST_RTP_PAYLOAD_IS_DYNAMIC (pt)) {
136       p = gst_rtp_payload_info_for_pt (pt);
137     }
138   }
139
140   if (p != NULL) {
141     GstCaps *ret = gst_caps_new_simple ("application/x-rtp",
142         "encoding-name", G_TYPE_STRING, p->encoding_name,
143         "clock-rate", G_TYPE_INT, p->clock_rate,
144         "media", G_TYPE_STRING, p->media, NULL);
145
146     GST_DEBUG_OBJECT (self, "Decided on caps %" GST_PTR_FORMAT, ret);
147
148     return ret;
149   }
150
151   GST_DEBUG_OBJECT (self, "Could not determine caps based on pt and"
152       " the encoding-name was not set.");
153   return NULL;
154 }
155
156 static void
157 gst_rtp_src_set_property (GObject * object, guint prop_id,
158     const GValue * value, GParamSpec * pspec)
159 {
160   GstRtpSrc *self = GST_RTP_SRC (object);
161   GstCaps *caps;
162
163   switch (prop_id) {
164     case PROP_URI:{
165       GstUri *uri = NULL;
166
167       GST_RTP_SRC_LOCK (object);
168       uri = gst_uri_from_string (g_value_get_string (value));
169       if (uri == NULL)
170         break;
171
172       if (self->uri)
173         gst_uri_unref (self->uri);
174       self->uri = uri;
175
176       /* Recursive set to self, do not use the same lock in all property
177        * setters. */
178       g_object_set (self, "address", gst_uri_get_host (self->uri), NULL);
179       g_object_set (self, "port", gst_uri_get_port (self->uri), NULL);
180       gst_rtp_utils_set_properties_from_uri_query (G_OBJECT (self), self->uri);
181       GST_RTP_SRC_UNLOCK (object);
182       break;
183     }
184     case PROP_ADDRESS:{
185       GInetAddress *addr;
186
187       gst_uri_set_host (self->uri, g_value_get_string (value));
188       g_object_set_property (G_OBJECT (self->rtp_src), "address", value);
189
190       addr = g_inet_address_new_from_string (gst_uri_get_host (self->uri));
191       if (g_inet_address_get_is_multicast (addr)) {
192         g_object_set (self->rtcp_src, "address", gst_uri_get_host (self->uri),
193             NULL);
194       }
195       g_object_unref (addr);
196       break;
197     }
198     case PROP_PORT:{
199       guint port = g_value_get_uint (value);
200
201       /* According to RFC 3550, 11, RTCP receiver port should be even
202        * number and RTCP port should be the RTP port + 1 */
203       if (port & 0x1)
204         GST_WARNING_OBJECT (self,
205             "Port %u is odd, this is not standard (see RFC 3550).", port);
206
207       gst_uri_set_port (self->uri, port);
208       g_object_set (self->rtp_src, "port", port, NULL);
209       g_object_set (self->rtcp_src, "port", port + 1, NULL);
210       break;
211     }
212     case PROP_TTL:
213       self->ttl = g_value_get_int (value);
214       break;
215     case PROP_TTL_MC:
216       self->ttl_mc = g_value_get_int (value);
217       break;
218     case PROP_ENCODING_NAME:
219       g_free (self->encoding_name);
220       self->encoding_name = g_value_dup_string (value);
221       if (self->rtp_src) {
222         caps = gst_rtp_src_rtpbin_request_pt_map_cb (NULL, 0, 96, self);
223         g_object_set (G_OBJECT (self->rtp_src), "caps", caps, NULL);
224         gst_caps_unref (caps);
225       }
226       break;
227     case PROP_LATENCY:
228       g_object_set (self->rtpbin, "latency", g_value_get_uint (value), NULL);
229       break;
230     default:
231       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232       break;
233   }
234 }
235
236 static void
237 gst_rtp_src_get_property (GObject * object, guint prop_id,
238     GValue * value, GParamSpec * pspec)
239 {
240   GstRtpSrc *self = GST_RTP_SRC (object);
241
242   switch (prop_id) {
243     case PROP_URI:
244       GST_RTP_SRC_LOCK (object);
245       if (self->uri)
246         g_value_take_string (value, gst_uri_to_string (self->uri));
247       else
248         g_value_set_string (value, NULL);
249       GST_RTP_SRC_UNLOCK (object);
250       break;
251     case PROP_ADDRESS:
252       g_value_set_string (value, gst_uri_get_host (self->uri));
253       break;
254     case PROP_PORT:
255       g_value_set_uint (value, gst_uri_get_port (self->uri));
256       break;
257     case PROP_TTL:
258       g_value_set_int (value, self->ttl);
259       break;
260     case PROP_TTL_MC:
261       g_value_set_int (value, self->ttl_mc);
262       break;
263     case PROP_ENCODING_NAME:
264       g_value_set_string (value, self->encoding_name);
265       break;
266     case PROP_LATENCY:
267       g_object_get_property (G_OBJECT (self->rtpbin), "latency", value);
268       break;
269     default:
270       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271       break;
272   }
273 }
274
275 static void
276 gst_rtp_src_finalize (GObject * gobject)
277 {
278   GstRtpSrc *self = GST_RTP_SRC (gobject);
279
280   if (self->uri)
281     gst_uri_unref (self->uri);
282   g_free (self->encoding_name);
283
284   g_mutex_clear (&self->lock);
285   G_OBJECT_CLASS (parent_class)->finalize (gobject);
286 }
287
288 static void
289 gst_rtp_src_class_init (GstRtpSrcClass * klass)
290 {
291   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
292   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
293
294   gobject_class->set_property = gst_rtp_src_set_property;
295   gobject_class->get_property = gst_rtp_src_get_property;
296   gobject_class->finalize = gst_rtp_src_finalize;
297   gstelement_class->change_state = gst_rtp_src_change_state;
298
299   /**
300    * GstRtpSrc:uri:
301    *
302    * uri to an RTP from. All GStreamer parameters can be
303    * encoded in the URI, this URI format is RFC compliant.
304    */
305   g_object_class_install_property (gobject_class, PROP_URI,
306       g_param_spec_string ("uri", "URI",
307           "URI in the form of rtp://host:port?query", DEFAULT_PROP_URI,
308           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
309
310   /**
311    * GstRtpSrc:address:
312    *
313    * Address to receive packets from (can be IPv4 or IPv6).
314    */
315   g_object_class_install_property (gobject_class, PROP_ADDRESS,
316       g_param_spec_string ("address", "Address",
317           "Address to receive packets from (can be IPv4 or IPv6).",
318           DEFAULT_PROP_ADDRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
319
320   /**
321    * GstRtpSrc:port:
322    *
323    * The port to listen to RTP packets, the RTCP port is this value
324    * +1. This port must be an even number.
325    */
326   g_object_class_install_property (gobject_class, PROP_PORT,
327       g_param_spec_uint ("port", "Port", "The port to listen for RTP packets, "
328           "the RTCP port is this value + 1. This port must be an even number.",
329           2, 65534, DEFAULT_PROP_PORT,
330           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
331
332   /**
333    * GstRtpSrc:ttl:
334    *
335    * Set the unicast TTL parameter. In RTP this of importance for RTCP.
336    */
337   g_object_class_install_property (gobject_class, PROP_TTL,
338       g_param_spec_int ("ttl", "Unicast TTL",
339           "Used for setting the unicast TTL parameter",
340           0, 255, DEFAULT_PROP_TTL,
341           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
342
343   /**
344    * GstRtpSrc:ttl-mc:
345    *
346    * Set the multicast TTL parameter. In RTP this of importance for RTCP.
347    */
348   g_object_class_install_property (gobject_class, PROP_TTL_MC,
349       g_param_spec_int ("ttl-mc", "Multicast TTL",
350           "Used for setting the multicast TTL parameter", 0, 255,
351           DEFAULT_PROP_TTL_MC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
352
353   /**
354    * GstRtpSrc:encoding-name:
355    *
356    * Set the encoding name of the stream to use. This is a short-hand for
357    * the full caps and maps typically to the encoding-name in the RTP caps.
358    */
359   g_object_class_install_property (gobject_class, PROP_ENCODING_NAME,
360       g_param_spec_string ("encoding-name", "Caps encoding name",
361           "Encoding name use to determine caps parameters",
362           DEFAULT_PROP_ENCODING_NAME,
363           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
364
365   /**
366    * GstRtpSrc:latency:
367    *
368    * Set the size of the latency buffer in the
369    * GstRtpBin/GstRtpJitterBuffer to compensate for network jitter.
370    */
371   g_object_class_install_property (gobject_class, PROP_LATENCY,
372       g_param_spec_uint ("latency", "Buffer latency in ms",
373           "Default amount of ms to buffer in the jitterbuffers", 0,
374           G_MAXUINT, DEFAULT_PROP_LATENCY,
375           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
376
377   gst_element_class_add_pad_template (gstelement_class,
378       gst_static_pad_template_get (&src_template));
379
380   gst_element_class_set_static_metadata (gstelement_class,
381       "RTP Source element",
382       "Generic/Bin/Src",
383       "Simple RTP src", "Marc Leeman <marc.leeman@gmail.com>");
384 }
385
386 static void
387 gst_rtp_src_rtpbin_pad_added_cb (GstElement * element, GstPad * pad,
388     gpointer data)
389 {
390   GstRtpSrc *self = GST_RTP_SRC (data);
391   GstCaps *caps = gst_pad_query_caps (pad, NULL);
392   GstPad *upad;
393   gchar name[48];
394
395   /* Expose RTP data pad only */
396   GST_INFO_OBJECT (self,
397       "Element %" GST_PTR_FORMAT " added pad %" GST_PTR_FORMAT "with caps %"
398       GST_PTR_FORMAT ".", element, pad, caps);
399
400   /* Sanity checks */
401   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
402     /* Sink pad, do not expose */
403     gst_caps_unref (caps);
404     return;
405   }
406
407   if (G_LIKELY (caps)) {
408     GstCaps *ref_caps = gst_caps_new_empty_simple ("application/x-rtcp");
409
410     if (gst_caps_can_intersect (caps, ref_caps)) {
411       /* SRC RTCP caps, do not expose */
412       gst_caps_unref (ref_caps);
413       gst_caps_unref (caps);
414
415       return;
416     }
417     gst_caps_unref (ref_caps);
418   } else {
419     GST_ERROR_OBJECT (self, "Pad with no caps detected.");
420     gst_caps_unref (caps);
421
422     return;
423   }
424   gst_caps_unref (caps);
425
426   GST_RTP_SRC_LOCK (self);
427   g_snprintf (name, 48, "src_%u", GST_ELEMENT (self)->numpads);
428   upad = gst_ghost_pad_new (name, pad);
429
430   gst_pad_set_active (upad, TRUE);
431   gst_element_add_pad (GST_ELEMENT (self), upad);
432
433   GST_RTP_SRC_UNLOCK (self);
434 }
435
436 static void
437 gst_rtp_src_rtpbin_pad_removed_cb (GstElement * element, GstPad * pad,
438     gpointer data)
439 {
440   GstRtpSrc *self = GST_RTP_SRC (data);
441   GST_INFO_OBJECT (self,
442       "Element %" GST_PTR_FORMAT " removed pad %" GST_PTR_FORMAT ".", element,
443       pad);
444 }
445
446 static void
447 gst_rtp_src_rtpbin_on_ssrc_collision_cb (GstElement * rtpbin, guint session_id,
448     guint ssrc, gpointer data)
449 {
450   GstRtpSrc *self = GST_RTP_SRC (data);
451
452   GST_INFO_OBJECT (self,
453       "Detected an SSRC collision: session-id 0x%x, ssrc 0x%x.", session_id,
454       ssrc);
455 }
456
457 static void
458 gst_rtp_src_rtpbin_on_new_ssrc_cb (GstElement * rtpbin, guint session_id,
459     guint ssrc, gpointer data)
460 {
461   GstRtpSrc *self = GST_RTP_SRC (data);
462
463   GST_INFO_OBJECT (self, "Detected a new SSRC: session-id 0x%x, ssrc 0x%x.",
464       session_id, ssrc);
465 }
466
467 static GstPadProbeReturn
468 gst_rtp_src_on_recv_rtcp (GstPad * pad, GstPadProbeInfo * info,
469     gpointer user_data)
470 {
471   GstRtpSrc *self = GST_RTP_SRC (user_data);
472   GstBuffer *buffer;
473   GstNetAddressMeta *meta;
474
475   if (info->type == GST_PAD_PROBE_TYPE_BUFFER_LIST) {
476     GstBufferList *buffer_list = info->data;
477     buffer = gst_buffer_list_get (buffer_list, 0);
478   } else {
479     buffer = info->data;
480   }
481
482   meta = gst_buffer_get_net_address_meta (buffer);
483
484   GST_OBJECT_LOCK (self);
485   g_clear_object (&self->rtcp_send_addr);
486   self->rtcp_send_addr = g_object_ref (meta->addr);
487   GST_OBJECT_UNLOCK (self);
488
489   return GST_PAD_PROBE_OK;
490 }
491
492 static inline void
493 gst_rtp_src_attach_net_address_meta (GstRtpSrc * self, GstBuffer * buffer)
494 {
495   GST_OBJECT_LOCK (self);
496   if (self->rtcp_send_addr)
497     gst_buffer_add_net_address_meta (buffer, self->rtcp_send_addr);
498   GST_OBJECT_UNLOCK (self);
499 }
500
501 static GstPadProbeReturn
502 gst_rtp_src_on_send_rtcp (GstPad * pad, GstPadProbeInfo * info,
503     gpointer user_data)
504 {
505   GstRtpSrc *self = GST_RTP_SRC (user_data);
506
507   if (info->type == GST_PAD_PROBE_TYPE_BUFFER_LIST) {
508     GstBufferList *buffer_list = info->data;
509     GstBuffer *buffer;
510     gint i;
511
512     info->data = buffer_list = gst_buffer_list_make_writable (buffer_list);
513     for (i = 0; i < gst_buffer_list_length (buffer_list); i++) {
514       buffer = gst_buffer_list_get (buffer_list, i);
515       gst_rtp_src_attach_net_address_meta (self, buffer);
516     }
517   } else {
518     GstBuffer *buffer = info->data;
519     info->data = buffer = gst_buffer_make_writable (buffer);
520     gst_rtp_src_attach_net_address_meta (self, buffer);
521   }
522
523   return GST_PAD_PROBE_OK;
524 }
525
526 static gboolean
527 gst_rtp_src_start (GstRtpSrc * self)
528 {
529   GstPad *pad;
530   GSocket *socket;
531   GInetAddress *addr;
532   GstCaps *caps;
533
534   /* Should not be NULL */
535   g_return_val_if_fail (self->uri != NULL, FALSE);
536
537   /* share the socket created by the source */
538   g_object_get (G_OBJECT (self->rtcp_src), "used-socket", &socket, NULL);
539   if (!G_IS_SOCKET (socket)) {
540     GST_WARNING_OBJECT (self, "Could not retrieve RTCP src socket.");
541   }
542
543   addr = g_inet_address_new_from_string (gst_uri_get_host (self->uri));
544   if (g_inet_address_get_is_multicast (addr)) {
545     /* mc-ttl is not supported by dynudpsink */
546     g_socket_set_multicast_ttl (socket, self->ttl_mc);
547     /* In multicast, send RTCP to the multicast group */
548     self->rtcp_send_addr =
549         g_inet_socket_address_new (addr, gst_uri_get_port (self->uri) + 1);
550   } else {
551     /* In unicast, send RTCP to the detected sender address */
552     g_socket_set_ttl (socket, self->ttl);
553     pad = gst_element_get_static_pad (self->rtcp_src, "src");
554     self->rtcp_recv_probe = gst_pad_add_probe (pad,
555         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST,
556         gst_rtp_src_on_recv_rtcp, self, NULL);
557     gst_object_unref (pad);
558   }
559   g_object_unref (addr);
560
561   /* no need to set address if unicast */
562   caps = gst_caps_new_empty_simple ("application/x-rtcp");
563   g_object_set (self->rtcp_src, "caps", caps, NULL);
564   gst_caps_unref (caps);
565
566   pad = gst_element_get_static_pad (self->rtcp_sink, "sink");
567   self->rtcp_send_probe = gst_pad_add_probe (pad,
568       GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST,
569       gst_rtp_src_on_send_rtcp, self, NULL);
570   gst_object_unref (pad);
571
572   g_object_set (self->rtcp_sink, "socket", socket, "close-socket", FALSE, NULL);
573   g_object_unref (socket);
574
575   gst_element_set_locked_state (self->rtcp_sink, FALSE);
576   gst_element_sync_state_with_parent (self->rtcp_sink);
577
578   return TRUE;
579 }
580
581 static void
582 gst_rtp_src_stop (GstRtpSrc * self)
583 {
584   GstPad *pad;
585
586   if (self->rtcp_recv_probe) {
587     pad = gst_element_get_static_pad (self->rtcp_src, "src");
588     gst_pad_remove_probe (pad, self->rtcp_recv_probe);
589     self->rtcp_recv_probe = 0;
590     gst_object_unref (pad);
591   }
592
593   pad = gst_element_get_static_pad (self->rtcp_sink, "sink");
594   gst_pad_remove_probe (pad, self->rtcp_send_probe);
595   self->rtcp_send_probe = 0;
596   gst_object_unref (pad);
597 }
598
599 static GstStateChangeReturn
600 gst_rtp_src_change_state (GstElement * element, GstStateChange transition)
601 {
602   GstRtpSrc *self = GST_RTP_SRC (element);
603   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
604
605   GST_DEBUG_OBJECT (self, "Changing state: %s => %s",
606       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
607       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
608
609   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
610   if (ret == GST_STATE_CHANGE_FAILURE)
611     return ret;
612
613   switch (transition) {
614     case GST_STATE_CHANGE_NULL_TO_READY:
615       if (gst_rtp_src_start (self) == FALSE)
616         return GST_STATE_CHANGE_FAILURE;
617       break;
618     case GST_STATE_CHANGE_READY_TO_PAUSED:
619       ret = GST_STATE_CHANGE_NO_PREROLL;
620       break;
621     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
622       ret = GST_STATE_CHANGE_NO_PREROLL;
623       break;
624     case GST_STATE_CHANGE_READY_TO_NULL:
625       gst_rtp_src_stop (self);
626       break;
627     default:
628       break;
629   }
630
631   return ret;
632 }
633
634 static void
635 gst_rtp_src_init (GstRtpSrc * self)
636 {
637   gchar name[48];
638   const gchar *missing_plugin = NULL;
639
640   self->rtpbin = NULL;
641   self->rtp_src = NULL;
642   self->rtcp_src = NULL;
643   self->rtcp_sink = NULL;
644
645   self->uri = gst_uri_from_string (DEFAULT_PROP_URI);
646   self->ttl = DEFAULT_PROP_TTL;
647   self->ttl_mc = DEFAULT_PROP_TTL_MC;
648   self->encoding_name = DEFAULT_PROP_ENCODING_NAME;
649
650   GST_OBJECT_FLAG_SET (GST_OBJECT (self), GST_ELEMENT_FLAG_SOURCE);
651   gst_bin_set_suppressed_flags (GST_BIN (self),
652       GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK);
653
654   g_mutex_init (&self->lock);
655
656   /* Construct the RTP receiver pipeline.
657    *
658    * udpsrc -> [recv_rtp_sink_%u]  --------  [recv_rtp_src_%u_%u_%u]
659    *                              | rtpbin |
660    * udpsrc -> [recv_rtcp_sink_%u] --------  [send_rtcp_src_%u] -> udpsink
661    *
662    * This pipeline is fixed for now, note that optionally an FEC stream could
663    * be added later.
664    */
665
666   self->rtpbin = gst_element_factory_make ("rtpbin", NULL);
667   if (self->rtpbin == NULL) {
668     missing_plugin = "rtpmanager";
669     goto missing_plugin;
670   }
671
672   gst_bin_add (GST_BIN (self), self->rtpbin);
673
674   /* Add rtpbin callbacks to monitor the operation of rtpbin */
675   g_signal_connect (self->rtpbin, "pad-added",
676       G_CALLBACK (gst_rtp_src_rtpbin_pad_added_cb), self);
677   g_signal_connect (self->rtpbin, "pad-removed",
678       G_CALLBACK (gst_rtp_src_rtpbin_pad_removed_cb), self);
679   g_signal_connect (self->rtpbin, "request-pt-map",
680       G_CALLBACK (gst_rtp_src_rtpbin_request_pt_map_cb), self);
681   g_signal_connect (self->rtpbin, "on-new-ssrc",
682       G_CALLBACK (gst_rtp_src_rtpbin_on_new_ssrc_cb), self);
683   g_signal_connect (self->rtpbin, "on-ssrc-collision",
684       G_CALLBACK (gst_rtp_src_rtpbin_on_ssrc_collision_cb), self);
685
686   self->rtp_src = gst_element_factory_make ("udpsrc", NULL);
687   if (self->rtp_src == NULL) {
688     missing_plugin = "udp";
689     goto missing_plugin;
690   }
691
692   self->rtcp_src = gst_element_factory_make ("udpsrc", NULL);
693   if (self->rtcp_src == NULL) {
694     missing_plugin = "udp";
695     goto missing_plugin;
696   }
697
698   self->rtcp_sink = gst_element_factory_make ("dynudpsink", NULL);
699   if (self->rtcp_sink == NULL) {
700     missing_plugin = "udp";
701     goto missing_plugin;
702   }
703
704   /* Add elements as needed, since udpsrc/udpsink for RTCP share a socket,
705    * not all at the same moment */
706   gst_bin_add (GST_BIN (self), self->rtp_src);
707   gst_bin_add (GST_BIN (self), self->rtcp_src);
708   gst_bin_add (GST_BIN (self), self->rtcp_sink);
709
710   g_object_set (self->rtcp_sink, "sync", FALSE, "async", FALSE, NULL);
711   gst_element_set_locked_state (self->rtcp_sink, TRUE);
712
713   /* pads are all named */
714   g_snprintf (name, 48, "recv_rtp_sink_%u", GST_ELEMENT (self)->numpads);
715   gst_element_link_pads (self->rtp_src, "src", self->rtpbin, name);
716   g_snprintf (name, 48, "recv_rtcp_sink_%u", GST_ELEMENT (self)->numpads);
717   gst_element_link_pads (self->rtcp_src, "src", self->rtpbin, name);
718   g_snprintf (name, 48, "send_rtcp_src_%u", GST_ELEMENT (self)->numpads);
719   gst_element_link_pads (self->rtpbin, name, self->rtcp_sink, "sink");
720
721   if (missing_plugin == NULL)
722     return;
723
724 missing_plugin:
725   {
726     GST_ERROR_OBJECT (self, "'%s' plugin is missing.", missing_plugin);
727   }
728 }
729
730 static GstURIType
731 gst_rtp_src_uri_get_type (GType type)
732 {
733   return GST_URI_SRC;
734 }
735
736 static const gchar *const *
737 gst_rtp_src_uri_get_protocols (GType type)
738 {
739   static const gchar *protocols[] = { (char *) "rtp", NULL };
740
741   return protocols;
742 }
743
744 static gchar *
745 gst_rtp_src_uri_get_uri (GstURIHandler * handler)
746 {
747   GstRtpSrc *self = (GstRtpSrc *) handler;
748
749   return gst_uri_to_string (self->uri);
750 }
751
752 static gboolean
753 gst_rtp_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
754     GError ** error)
755 {
756   GstRtpSrc *self = (GstRtpSrc *) handler;
757
758   g_object_set (G_OBJECT (self), "uri", uri, NULL);
759
760   return TRUE;
761 }
762
763 static void
764 gst_rtp_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
765 {
766   GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
767
768   iface->get_type = gst_rtp_src_uri_get_type;
769   iface->get_protocols = gst_rtp_src_uri_get_protocols;
770   iface->get_uri = gst_rtp_src_uri_get_uri;
771   iface->set_uri = gst_rtp_src_uri_set_uri;
772 }
773
774 /* ex: set tabstop=2 shiftwidth=2 expandtab: */