chiark / gitweb /
lib/uaudio-rtp.c: Always allow clients to request unicast RTP streams.
[disorder] / lib / uaudio-rtp.c
index 8313054fbc3e43101e9afc858b28a0239fb3d907..8559bb228dbaa7c97c15e9bb50c84ca250189111 100644 (file)
 /** @brief RTP payload type */
 static int rtp_payload;
 
-/** @brief RTP output socket */
-static int rtp_fd;
+/** @brief RTP broadcast/multicast output socket */
+static int rtp_fd = -1;
 
-/** @brief RTP output socket (IPv6) */
-static int rtp_fd6;
+/** @brief RTP unicast output socket (IPv4) */
+static int rtp_fd4 = -1;
+
+/** @brief RTP unicast output socket (IPv6) */
+static int rtp_fd6 = -1;
 
 /** @brief RTP SSRC */
 static uint32_t rtp_id;
@@ -206,23 +209,23 @@ static size_t rtp_play(void *buffer, size_t nsamples, unsigned flags) {
     uaudio_schedule_sent(nsamples);
     return nsamples;
   }
-  if(rtp_mode == RTP_REQUEST) {
-    struct rtp_recipient *r;
-    struct msghdr m;
-    memset(&m, 0, sizeof m);
-    m.msg_iov = vec;
-    m.msg_iovlen = 2;
-    pthread_mutex_lock(&rtp_lock);
-    for(r = rtp_recipient_list; r; r = r->next) {
-      m.msg_name = &r->sa;
-      m.msg_namelen = r->sa.ss_family == AF_INET ? 
-        sizeof(struct sockaddr_in) : sizeof (struct sockaddr_in6);
-      sendmsg(r->sa.ss_family == AF_INET ? rtp_fd : rtp_fd6,
-              &m, MSG_DONTWAIT|MSG_NOSIGNAL);
-      // TODO similar error handling to other case?
-    }
-    pthread_mutex_unlock(&rtp_lock);
-  } else {
+  /* Send stuff to explicitly registerd unicast addresses unconditionally */
+  struct rtp_recipient *r;
+  struct msghdr m;
+  memset(&m, 0, sizeof m);
+  m.msg_iov = vec;
+  m.msg_iovlen = 2;
+  pthread_mutex_lock(&rtp_lock);
+  for(r = rtp_recipient_list; r; r = r->next) {
+    m.msg_name = &r->sa;
+    m.msg_namelen = r->sa.ss_family == AF_INET ? 
+      sizeof(struct sockaddr_in) : sizeof (struct sockaddr_in6);
+    sendmsg(r->sa.ss_family == AF_INET ? rtp_fd4 : rtp_fd6,
+            &m, MSG_DONTWAIT|MSG_NOSIGNAL);
+    // TODO similar error handling to other case?
+  }
+  pthread_mutex_unlock(&rtp_lock);
+  if(rtp_mode != RTP_REQUEST) {
     int written_bytes;
     do {
       written_bytes = writev(rtp_fd, vec, 2);
@@ -242,11 +245,29 @@ static size_t rtp_play(void *buffer, size_t nsamples, unsigned flags) {
   return nsamples;
 }
 
+static void hack_send_buffer_size(int fd, const char *what) {
+  int sndbuf, target_sndbuf = 131072;
+  socklen_t len = sizeof sndbuf;
+
+  if(getsockopt(fd, SOL_SOCKET, SO_SNDBUF,
+                &sndbuf, &len) < 0)
+    disorder_fatal(errno, "error getting SO_SNDBUF on %s socket", what);
+  if(target_sndbuf > sndbuf) {
+    if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
+                  &target_sndbuf, sizeof target_sndbuf) < 0)
+      disorder_error(errno, "error setting SO_SNDBUF on %s socket to %d",
+                     what, target_sndbuf);
+    else
+      disorder_info("changed socket send buffer size on %socket from %d to %d",
+                    what, sndbuf, target_sndbuf);
+  } else
+    disorder_info("default socket send buffer on %s socket is %d",
+                  what, sndbuf);
+}
+
 static void rtp_open(void) {
   struct addrinfo *dres, *sres;
   static const int one = 1;
-  int sndbuf, target_sndbuf = 131072;
-  socklen_t len;
   struct netaddress dst[1], src[1];
   const char *mode;
   
@@ -305,22 +326,17 @@ static void rtp_open(void) {
         rtp_mode = RTP_UNICAST;
     }
   }
-  /* Create the socket */
+  /* Create the sockets */
   if(rtp_mode != RTP_REQUEST) {
     if((rtp_fd = socket(dres->ai_family,
                         dres->ai_socktype,
                         dres->ai_protocol)) < 0)
       disorder_fatal(errno, "error creating RTP transmission socket");
-  } else {                              /* request mode slightly different */
-    if((rtp_fd = socket(AF_INET,
-                        SOCK_DGRAM,
-                        IPPROTO_UDP)) < 0)
-      disorder_fatal(errno, "error creating v4 RTP transmission socket");
-    if((rtp_fd6 = socket(AF_INET6,
-                         SOCK_DGRAM,
-                         IPPROTO_UDP)) < 0)
-      disorder_fatal(errno, "error creating v6 RTP transmission socket");
   }
+  if((rtp_fd4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+    disorder_fatal(errno, "error creating v4 RTP transmission socket");
+  if((rtp_fd6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+    disorder_fatal(errno, "error creating v6 RTP transmission socket");
   /* Configure the socket according to the desired mode */
   switch(rtp_mode) {
   case RTP_MULTICAST: {
@@ -369,20 +385,10 @@ static void rtp_open(void) {
     break;
   }
   }
-  /* Enlarge the socket buffer */
-  len = sizeof sndbuf;
-  if(getsockopt(rtp_fd, SOL_SOCKET, SO_SNDBUF,
-                &sndbuf, &len) < 0)
-    disorder_fatal(errno, "error getting SO_SNDBUF");
-  if(target_sndbuf > sndbuf) {
-    if(setsockopt(rtp_fd, SOL_SOCKET, SO_SNDBUF,
-                  &target_sndbuf, sizeof target_sndbuf) < 0)
-      disorder_error(errno, "error setting SO_SNDBUF to %d", target_sndbuf);
-    else
-      disorder_info("changed socket send buffer size from %d to %d",
-                    sndbuf, target_sndbuf);
-  } else
-    disorder_info("default socket send buffer is %d", sndbuf);
+  /* Enlarge the socket buffers */
+  if (rtp_fd != -1) hack_send_buffer_size(rtp_fd, "master socket");
+  hack_send_buffer_size(rtp_fd4, "IPv4 on-demand socket");
+  hack_send_buffer_size(rtp_fd6, "IPv6 on-demand socket");
   /* We might well want to set additional broadcast- or multicast-related
    * options here */
   if(rtp_mode != RTP_REQUEST) {
@@ -440,12 +446,9 @@ static void rtp_start(uaudio_callback *callback,
 
 static void rtp_stop(void) {
   uaudio_thread_stop();
-  close(rtp_fd);
-  rtp_fd = -1;
-  if(rtp_fd6 >= 0) {
-    close(rtp_fd6);
-    rtp_fd6 = -1;
-  }
+  if(rtp_fd >= 0) { close(rtp_fd); rtp_fd = -1; }
+  if(rtp_fd4 >= 0) { close(rtp_fd4); rtp_fd4 = -1; }
+  if(rtp_fd6 >= 0) { close(rtp_fd6); rtp_fd6 = -1; }
 }
 
 static void rtp_configure(void) {