rtp: Introduce source IP configuration
authorRobin H. Johnson <robbat2@gentoo.org>
Sat, 17 Nov 2012 23:31:18 +0000 (23:31 +0000)
committerArun Raghavan <arun.raghavan@collabora.co.uk>
Mon, 25 Mar 2013 09:47:04 +0000 (09:47 +0000)
On a multi-homed system, the user may wish RTP to be used only on
specific interfaces. The default binding of 0.0.0.0 for the source
address causes SAP multicast on all interfaces, which is not ideal.

Introduce a new module argument, that allows selection of the source IP,
and thus interface.

(changes in v2: s/srcip/source_ip)

Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
src/modules/rtp/module-rtp-send.c

index 00cc6c919ad8b1f8e3df1bf223164a9f154769c1..acabcf5bf0b9b5b46edf8cceb8212c2f2bc0b182 100644 (file)
@@ -64,6 +64,7 @@ PA_MODULE_USAGE(
         "channels=<number of channels> "
         "rate=<sample rate> "
         "destination_ip=<destination IP address> "
+        "source_ip=<source IP address> "
         "port=<port number> "
         "mtu=<maximum transfer unit> "
         "loop=<loopback to local host?> "
@@ -73,6 +74,7 @@ PA_MODULE_USAGE(
 #define DEFAULT_PORT 46000
 #define DEFAULT_TTL 1
 #define SAP_PORT 9875
+#define DEFAULT_SOURCE_IP "0.0.0.0"
 #define DEFAULT_DESTINATION_IP "224.0.0.56"
 #define MEMBLOCKQ_MAXLENGTH (1024*170)
 #define DEFAULT_MTU 1280
@@ -85,6 +87,7 @@ static const char* const valid_modargs[] = {
     "rate",
     "destination", /* Compatbility */
     "destination_ip",
+    "source_ip",
     "port",
     "mtu" ,
     "loop",
@@ -165,6 +168,7 @@ int pa__init(pa_module*m) {
     struct userdata *u;
     pa_modargs *ma = NULL;
     const char *dst_addr;
+    const char *src_addr;
     uint32_t port = DEFAULT_PORT, mtu;
     uint32_t ttl = DEFAULT_TTL;
     sa_family_t af;
@@ -172,9 +176,9 @@ int pa__init(pa_module*m) {
     pa_source *s;
     pa_sample_spec ss;
     pa_channel_map cm;
-    struct sockaddr_in dst_sa4, dst_sap_sa4;
+    struct sockaddr_in dst_sa4, dst_sap_sa4, src_sa4, src_sap_sa4;
 #ifdef HAVE_IPV6
-    struct sockaddr_in6 dst_sa6, dst_sap_sa6;
+    struct sockaddr_in6 dst_sa6, dst_sap_sa6, src_sa6, src_sap_sa6;
 #endif
     struct sockaddr_storage sa_dst;
     pa_source_output *o = NULL;
@@ -242,6 +246,23 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    src_addr = pa_modargs_get_value(ma, "source_ip", DEFAULT_SOURCE_IP);
+
+    if (inet_pton(AF_INET, src_addr, &src_sa4.sin_addr) > 0) {
+        src_sa4.sin_family = af = AF_INET;
+        src_sa4.sin_port = htons(0);
+        src_sap_sa4 = src_sa4;
+#ifdef HAVE_IPV6
+    } else if (inet_pton(AF_INET6, src_addr, &src_sa6.sin6_addr) > 0) {
+        src_sa6.sin6_family = af = AF_INET6;
+        src_sa6.sin6_port = htons(0);
+        src_sap_sa6 = src_sa6;
+#endif
+    } else {
+        pa_log("Invalid source address '%s'", src_addr);
+        goto fail;
+    }
+
     dst_addr = pa_modargs_get_value(ma, "destination", NULL);
     if (dst_addr == NULL)
         dst_addr = pa_modargs_get_value(ma, "destination_ip", DEFAULT_DESTINATION_IP);
@@ -268,6 +289,16 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    if (af == AF_INET && bind(fd, (struct sockaddr*) &src_sa4, sizeof(src_sa4)) < 0) {
+        pa_log("bind() failed: %s", pa_cstrerror(errno));
+        goto fail;
+#ifdef HAVE_IPV6
+    } else if (af == AF_INET6 && bind(fd, (struct sockaddr*) &src_sa6, sizeof(src_sa6)) < 0) {
+        pa_log("bind() failed: %s", pa_cstrerror(errno));
+        goto fail;
+#endif
+    }
+
     if (af == AF_INET && connect(fd, (struct sockaddr*) &dst_sa4, sizeof(dst_sa4)) < 0) {
         pa_log("connect() failed: %s", pa_cstrerror(errno));
         goto fail;
@@ -283,6 +314,16 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    if (af == AF_INET && bind(sap_fd, (struct sockaddr*) &src_sap_sa4, sizeof(src_sap_sa4)) < 0) {
+        pa_log("bind() failed: %s", pa_cstrerror(errno));
+        goto fail;
+#ifdef HAVE_IPV6
+    } else if (af == AF_INET6 && bind(sap_fd, (struct sockaddr*) &src_sap_sa6, sizeof(src_sap_sa6)) < 0) {
+        pa_log("bind() failed: %s", pa_cstrerror(errno));
+        goto fail;
+#endif
+    }
+
     if (af == AF_INET && connect(sap_fd, (struct sockaddr*) &dst_sap_sa4, sizeof(dst_sap_sa4)) < 0) {
         pa_log("connect() failed: %s", pa_cstrerror(errno));
         goto fail;
@@ -320,6 +361,7 @@ int pa__init(pa_module*m) {
 
     pa_source_output_new_data_init(&data);
     pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, "RTP Monitor Stream");
+    pa_proplist_sets(data.proplist, "rtp.source", src_addr);
     pa_proplist_sets(data.proplist, "rtp.destination", dst_addr);
     pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu);
     pa_proplist_setf(data.proplist, "rtp.port", "%lu", (unsigned long) port);
@@ -387,7 +429,7 @@ int pa__init(pa_module*m) {
     pa_rtp_context_init_send(&u->rtp_context, fd, m->core->cookie, payload, pa_frame_size(&ss));
     pa_sap_context_init_send(&u->sap_context, sap_fd, p);
 
-    pa_log_info("RTP stream initialized with mtu %u on %s:%u ttl=%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dst_addr, port, ttl, u->rtp_context.ssrc, payload, u->rtp_context.sequence);
+    pa_log_info("RTP stream initialized with mtu %u on %s:%u from %s ttl=%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dst_addr, port, src_addr, ttl, u->rtp_context.ssrc, payload, u->rtp_context.sequence);
     pa_log_info("SDP-Data:\n%s\nEOF", p);
 
     pa_sap_send(&u->sap_context, 0);