gstreamer1.0-plugins-good: ignore empty unicast address in rtp URIs
[opendreambox.git] / meta-opendreambox / recipes-multimedia / gstreamer / gstreamer1.0-plugins-good / 0001-udpsrc-add-support-for-IGMPv3-SSM.patch
1 From 2332c22ebf42c4c52e16b3ea5c702de2eb202429 Mon Sep 17 00:00:00 2001
2 From: Julien Isorce <julien.isorce@gmail.com>
3 Date: Fri, 13 Jan 2012 10:53:03 +0100
4 Subject: [PATCH] udpsrc: add support for IGMPv3 SSM
5
6 New property: 'multicast-source'
7 Source Specific Muliticast RFC 4604
8
9 Fixes https://bugzilla.gnome.org/show_bug.cgi?id=652711
10 ---
11  gst/udp/gstudpnetutils.c | 17 +++++++---
12  gst/udp/gstudpnetutils.h |  2 +-
13  gst/udp/gstudpsink.c     |  2 +-
14  gst/udp/gstudpsrc.c      | 82 ++++++++++++++++++++++++++++++++++++++----------
15  gst/udp/gstudpsrc.h      |  2 ++
16  5 files changed, 82 insertions(+), 23 deletions(-)
17
18 diff --git a/gst/udp/gstudpnetutils.c b/gst/udp/gstudpnetutils.c
19 index b4dc5ef..22b1378 100644
20 --- a/gst/udp/gstudpnetutils.c
21 +++ b/gst/udp/gstudpnetutils.c
22 @@ -29,7 +29,8 @@
23  #include "gstudpnetutils.h"
24  
25  gboolean
26 -gst_udp_parse_uri (const gchar * uristr, gchar ** host, guint16 * port)
27 +gst_udp_parse_uri (const gchar * uristr, gchar ** host, guint16 * port,
28 +    gchar ** source)
29  {
30    gchar *protocol, *location_start;
31    gchar *location, *location_end;
32 @@ -49,13 +50,19 @@ gst_udp_parse_uri (const gchar * uristr, gchar ** host, guint16 * port)
33  
34    GST_DEBUG ("got location '%s'", location_start);
35  
36 -  /* VLC compatibility, strip everything before the @ sign. VLC uses that as the
37 -   * remote address. */
38 +  /* parse source ip for igmpv3 */
39    location = g_strstr_len (location_start, -1, "@");
40 -  if (location == NULL)
41 +  if (location == NULL) {
42 +    if (source != NULL)
43 +      *source = NULL;
44      location = location_start;
45 -  else
46 +  } else {
47 +    if (source != NULL && location - location_start > 0) {
48 +      *source = g_strndup (location_start, location - location_start);
49 +      GST_DEBUG ("source ip address set to '%s'", *source);
50 +    }
51      location += 1;
52 +  }
53  
54    if (location[0] == '[') {
55      GST_DEBUG ("parse IPV6 address '%s'", location);
56 diff --git a/gst/udp/gstudpnetutils.h b/gst/udp/gstudpnetutils.h
57 index a62be56..c5e26c9 100644
58 --- a/gst/udp/gstudpnetutils.h
59 +++ b/gst/udp/gstudpnetutils.h
60 @@ -23,7 +23,7 @@
61  #ifndef __GST_UDP_NET_UTILS_H__
62  #define __GST_UDP_NET_UTILS_H__
63  
64 -gboolean     gst_udp_parse_uri            (const gchar *uristr, gchar **host, guint16 *port);
65 +gboolean     gst_udp_parse_uri            (const gchar *uristr, gchar **host, guint16 *port, gchar **source);
66  
67  #endif /* __GST_UDP_NET_UTILS_H__*/
68  
69 diff --git a/gst/udp/gstudpsink.c b/gst/udp/gstudpsink.c
70 index 224d578..bfc9ee6 100644
71 --- a/gst/udp/gstudpsink.c
72 +++ b/gst/udp/gstudpsink.c
73 @@ -130,7 +130,7 @@ gst_udpsink_set_uri (GstUDPSink * sink, const gchar * uri, GError ** error)
74  
75    gst_multiudpsink_remove (GST_MULTIUDPSINK (sink), sink->host, sink->port);
76  
77 -  if (!gst_udp_parse_uri (uri, &host, &port))
78 +  if (!gst_udp_parse_uri (uri, &host, &port, NULL))
79      goto wrong_uri;
80  
81    g_free (sink->host);
82 diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c
83 index da412ba..5f4c070 100644
84 --- a/gst/udp/gstudpsrc.c
85 +++ b/gst/udp/gstudpsrc.c
86 @@ -145,6 +145,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
87  #define UDP_DEFAULT_PORT                5004
88  #define UDP_DEFAULT_MULTICAST_GROUP     "0.0.0.0"
89  #define UDP_DEFAULT_MULTICAST_IFACE     NULL
90 +#define UDP_DEFAULT_MULTICAST_SOURCE    NULL
91  #define UDP_DEFAULT_URI                 "udp://"UDP_DEFAULT_MULTICAST_GROUP":"G_STRINGIFY(UDP_DEFAULT_PORT)
92  #define UDP_DEFAULT_CAPS                NULL
93  #define UDP_DEFAULT_SOCKET              NULL
94 @@ -164,6 +165,7 @@ enum
95    PROP_PORT,
96    PROP_MULTICAST_GROUP,
97    PROP_MULTICAST_IFACE,
98 +  PROP_MULTICAST_SOURCE,
99    PROP_URI,
100    PROP_CAPS,
101    PROP_SOCKET,
102 @@ -237,18 +239,22 @@ gst_udpsrc_class_init (GstUDPSrcClass * klass)
103            "The network interface on which to join the multicast group",
104            UDP_DEFAULT_MULTICAST_IFACE,
105            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
106 +  g_object_class_install_property (gobject_class, PROP_MULTICAST_SOURCE,
107 +      g_param_spec_string ("multicast-source", "Source Specific Multicast",
108 +          "The source to receive the stream from. (IGMPv3 SSM RFC 4604)",
109 +          UDP_DEFAULT_MULTICAST_SOURCE,
110 +          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
111    g_object_class_install_property (gobject_class, PROP_URI,
112        g_param_spec_string ("uri", "URI",
113 -          "URI in the form of udp://multicast_group:port", UDP_DEFAULT_URI,
114 -          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
115 +          "URI in the form of udp://multicast_group:port or udp://multicast_source@multicast_group:port",
116 +          UDP_DEFAULT_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
117    g_object_class_install_property (gobject_class, PROP_CAPS,
118 -      g_param_spec_boxed ("caps", "Caps",
119 -          "The caps of the source pad", GST_TYPE_CAPS,
120 -          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
121 +      g_param_spec_boxed ("caps", "Caps", "The caps of the source pad",
122 +          GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
123    g_object_class_install_property (gobject_class, PROP_SOCKET,
124        g_param_spec_object ("socket", "Socket",
125 -          "Socket to use for UDP reception. (NULL == allocate)",
126 -          G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
127 +          "Socket to use for UDP reception. (NULL == allocate)", G_TYPE_SOCKET,
128 +          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129    g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_SIZE,
130        g_param_spec_int ("buffer-size", "Buffer Size",
131            "Size of the kernel receive buffer in bytes, 0=default", 0, G_MAXINT,
132 @@ -318,6 +324,7 @@ gst_udpsrc_init (GstUDPSrc * udpsrc)
133        UDP_DEFAULT_PORT);
134  
135    udpsrc->address = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
136 +  udpsrc->source = g_strdup (UDP_DEFAULT_MULTICAST_SOURCE);
137    udpsrc->port = UDP_DEFAULT_PORT;
138    udpsrc->socket = UDP_DEFAULT_SOCKET;
139    udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE);
140 @@ -330,6 +337,7 @@ gst_udpsrc_init (GstUDPSrc * udpsrc)
141    udpsrc->used_socket = UDP_DEFAULT_USED_SOCKET;
142    udpsrc->reuse = UDP_DEFAULT_REUSE;
143    udpsrc->loop = UDP_DEFAULT_LOOP;
144 +  udpsrc->src_addr = NULL;
145  
146    /* configure basesrc to be a live source */
147    gst_base_src_set_live (GST_BASE_SRC (udpsrc), TRUE);
148 @@ -693,8 +701,9 @@ gst_udpsrc_set_uri (GstUDPSrc * src, const gchar * uri, GError ** error)
149  {
150    gchar *address;
151    guint16 port;
152 +  gchar *source;
153  
154 -  if (!gst_udp_parse_uri (uri, &address, &port))
155 +  if (!gst_udp_parse_uri (uri, &address, &port, &source))
156      goto wrong_uri;
157  
158    if (port == (guint16) - 1)
159 @@ -703,6 +712,8 @@ gst_udpsrc_set_uri (GstUDPSrc * src, const gchar * uri, GError ** error)
160    g_free (src->address);
161    src->address = address;
162    src->port = port;
163 +  g_free (src->source);
164 +  src->source = source;
165  
166    g_free (src->uri);
167    src->uri = g_strdup (uri);
168 @@ -733,8 +744,13 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
169      case PROP_PORT:
170        udpsrc->port = g_value_get_int (value);
171        g_free (udpsrc->uri);
172 -      udpsrc->uri =
173 -          g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
174 +      if (udpsrc->source)
175 +        udpsrc->uri =
176 +            g_strdup_printf ("udp://%s@%s:%u", udpsrc->source, udpsrc->address,
177 +            udpsrc->port);
178 +      else
179 +        udpsrc->uri =
180 +            g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
181        break;
182      case PROP_MULTICAST_GROUP:
183      case PROP_ADDRESS:
184 @@ -748,8 +764,13 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
185          udpsrc->address = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
186  
187        g_free (udpsrc->uri);
188 -      udpsrc->uri =
189 -          g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
190 +      if (udpsrc->source)
191 +        udpsrc->uri =
192 +            g_strdup_printf ("udp://%s@%s:%u", udpsrc->source, udpsrc->address,
193 +            udpsrc->port);
194 +      else
195 +        udpsrc->uri =
196 +            g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
197        break;
198      }
199      case PROP_MULTICAST_IFACE:
200 @@ -760,6 +781,17 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
201        else
202          udpsrc->multi_iface = g_value_dup_string (value);
203        break;
204 +    case PROP_MULTICAST_SOURCE:
205 +    {
206 +      const gchar *source = g_value_get_string (value);
207 +
208 +      g_free (udpsrc->source);
209 +      if (source != NULL)
210 +        udpsrc->source = g_strdup (source);
211 +      else
212 +        udpsrc->source = g_strdup (UDP_DEFAULT_MULTICAST_SOURCE);
213 +      break;
214 +    }
215      case PROP_URI:
216        gst_udpsrc_set_uri (udpsrc, g_value_get_string (value), NULL);
217        break;
218 @@ -844,6 +876,9 @@ gst_udpsrc_get_property (GObject * object, guint prop_id, GValue * value,
219      case PROP_MULTICAST_IFACE:
220        g_value_set_string (value, udpsrc->multi_iface);
221        break;
222 +    case PROP_MULTICAST_SOURCE:
223 +      g_value_set_string (value, udpsrc->source);
224 +      break;
225      case PROP_URI:
226        g_value_set_string (value, udpsrc->uri);
227        break;
228 @@ -929,6 +964,7 @@ static gboolean
229  gst_udpsrc_open (GstUDPSrc * src)
230  {
231    GInetAddress *addr, *bind_addr;
232 +  GInetAddress *src_addr = NULL;
233    GSocketAddress *bind_saddr;
234    GError *err = NULL;
235  
236 @@ -943,6 +979,13 @@ gst_udpsrc_open (GstUDPSrc * src)
237      if (!addr)
238        goto name_resolve;
239  
240 +    if (src->source) {
241 +      GST_DEBUG_OBJECT (src, "using source specific %s", src->source);
242 +      src_addr = gst_udpsrc_resolve (src, src->source);
243 +      if (!src_addr)
244 +        goto name_resolve;
245 +    }
246 +
247      if ((src->used_socket =
248              g_socket_new (g_inet_address_get_family (addr),
249                  G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
250 @@ -957,6 +1000,11 @@ gst_udpsrc_open (GstUDPSrc * src)
251      src->addr =
252          G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));
253  
254 +    if (src->src_addr)
255 +      g_object_unref (src->src_addr);
256 +    src->src_addr =
257 +        G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (src_addr, src->port));
258 +
259      GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
260  
261      /* On Windows it's not possible to bind to a multicast address
262 @@ -1109,9 +1157,10 @@ gst_udpsrc_open (GstUDPSrc * src)
263        g_inet_address_get_is_multicast (g_inet_socket_address_get_address
264            (src->addr))) {
265      GST_DEBUG_OBJECT (src, "joining multicast group %s", src->address);
266 -    if (!g_socket_join_multicast_group (src->used_socket,
267 +    if (!g_socket_join_multicast_group_ssm (src->used_socket,
268              g_inet_socket_address_get_address (src->addr),
269 -            FALSE, src->multi_iface, &err))
270 +            g_inet_socket_address_get_address (src->src_addr),
271 +            src->multi_iface, &err))
272        goto membership;
273    }
274  
275 @@ -1226,8 +1275,9 @@ gst_udpsrc_close (GstUDPSrc * src)
276  
277        GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->address);
278  
279 -      if (!g_socket_leave_multicast_group (src->used_socket,
280 -              g_inet_socket_address_get_address (src->addr), FALSE,
281 +      if (!g_socket_leave_multicast_group_ssm (src->used_socket,
282 +              g_inet_socket_address_get_address (src->addr),
283 +              g_inet_socket_address_get_address (src->src_addr),
284                src->multi_iface, &err)) {
285          GST_ERROR_OBJECT (src, "Failed to leave multicast group: %s",
286              err->message);
287 diff --git a/gst/udp/gstudpsrc.h b/gst/udp/gstudpsrc.h
288 index a476483..f77d022 100644
289 --- a/gst/udp/gstudpsrc.h
290 +++ b/gst/udp/gstudpsrc.h
291 @@ -49,6 +49,7 @@ struct _GstUDPSrc {
292  
293    /* properties */
294    gchar     *address;
295 +  gchar     *source;
296    gint       port;
297    gchar     *multi_iface;
298    gint       ttl;
299 @@ -68,6 +69,7 @@ struct _GstUDPSrc {
300    /* our sockets */
301    GSocket   *used_socket;
302    GInetSocketAddress *addr;
303 +  GInetSocketAddress *src_addr;
304    gboolean   external_socket;
305  
306    gboolean   made_cancel_fd;