1 From 71db76f05b7aa2f45934c3bfee6a1ccaa262b763 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
6 New property: 'multicast-source'
7 Source Specific Muliticast RFC 4604
9 Fixes https://bugzilla.gnome.org/show_bug.cgi?id=652711
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(-)
18 diff --git a/gst/udp/gstudpnetutils.c b/gst/udp/gstudpnetutils.c
19 index b4dc5ef..c517a8e 100644
20 --- a/gst/udp/gstudpnetutils.c
21 +++ b/gst/udp/gstudpnetutils.c
23 #include "gstudpnetutils.h"
26 -gst_udp_parse_uri (const gchar * uristr, gchar ** host, guint16 * port)
27 +gst_udp_parse_uri (const gchar * uristr, gchar ** host, guint16 * port,
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)
34 GST_DEBUG ("got location '%s'", location_start);
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) {
44 location = location_start;
47 + if (source != NULL) {
48 + *source = g_strndup (location_start, location - location_start);
49 + GST_DEBUG ("source ip address set to '%s'", *source);
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
61 #ifndef __GST_UDP_NET_UTILS_H__
62 #define __GST_UDP_NET_UTILS_H__
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);
67 #endif /* __GST_UDP_NET_UTILS_H__*/
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)
75 gst_multiudpsink_remove (GST_MULTIUDPSINK (sink), sink->host, sink->port);
77 - if (!gst_udp_parse_uri (uri, &host, &port))
78 + if (!gst_udp_parse_uri (uri, &host, &port, NULL))
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
98 + PROP_MULTICAST_SOURCE,
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)
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;
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)
154 - if (!gst_udp_parse_uri (uri, &address, &port))
155 + if (!gst_udp_parse_uri (uri, &address, &port, &source))
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;
163 + g_free (src->source);
164 + src->source = source;
167 src->uri = g_strdup (uri);
168 @@ -733,8 +744,13 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
170 udpsrc->port = g_value_get_int (value);
171 g_free (udpsrc->uri);
173 - g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
174 + if (udpsrc->source)
176 + g_strdup_printf ("udp://%s@%s:%u", udpsrc->source, udpsrc->address,
180 + g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
182 case PROP_MULTICAST_GROUP:
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);
187 g_free (udpsrc->uri);
189 - g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
190 + if (udpsrc->source)
192 + g_strdup_printf ("udp://%s@%s:%u", udpsrc->source, udpsrc->address,
196 + g_strdup_printf ("udp://%s:%u", udpsrc->address, udpsrc->port);
199 case PROP_MULTICAST_IFACE:
200 @@ -760,6 +781,17 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
202 udpsrc->multi_iface = g_value_dup_string (value);
204 + case PROP_MULTICAST_SOURCE:
206 + const gchar *source = g_value_get_string (value);
208 + g_free (udpsrc->source);
209 + if (source != NULL)
210 + udpsrc->source = g_strdup (source);
212 + udpsrc->source = g_strdup (UDP_DEFAULT_MULTICAST_SOURCE);
216 gst_udpsrc_set_uri (udpsrc, g_value_get_string (value), NULL);
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);
222 + case PROP_MULTICAST_SOURCE:
223 + g_value_set_string (value, udpsrc->source);
226 g_value_set_string (value, udpsrc->uri);
228 @@ -929,6 +964,7 @@ static gboolean
229 gst_udpsrc_open (GstUDPSrc * src)
231 GInetAddress *addr, *bind_addr;
232 + GInetAddress *src_addr = NULL;
233 GSocketAddress *bind_saddr;
236 @@ -943,6 +979,13 @@ gst_udpsrc_open (GstUDPSrc * src)
241 + GST_DEBUG_OBJECT (src, "using source specific %s", src->source);
242 + src_addr = gst_udpsrc_resolve (src, src->source);
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)
252 G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));
255 + g_object_unref (src->src_addr);
257 + G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (src_addr, src->port));
259 GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
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
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))
275 @@ -1226,8 +1275,9 @@ gst_udpsrc_close (GstUDPSrc * src)
277 GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->address);
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",
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 {
299 @@ -68,6 +69,7 @@ struct _GstUDPSrc {
301 GSocket *used_socket;
302 GInetSocketAddress *addr;
303 + GInetSocketAddress *src_addr;
304 gboolean external_socket;
306 gboolean made_cancel_fd;