]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
SAT>IP server: implement DESCRIBE RTSP command
authorJaroslav Kysela <perex@perex.cz>
Wed, 11 Mar 2015 20:26:33 +0000 (21:26 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 11 Mar 2015 20:41:13 +0000 (21:41 +0100)
src/satip/rtp.c
src/satip/rtsp.c
src/satip/server.h

index 6571cb1f29f0cd2b2a9430fca2fd0ed5f95244fa..0397b90e36c5f58a0cf610c62088e074c1e8de2a 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <signal.h>
+#include <ctype.h>
 #include "tvheadend.h"
 #include "input.h"
 #include "streaming.h"
@@ -148,7 +149,9 @@ found:
 static void
 satip_rtp_signal_status(satip_rtp_session_t *rtp, signal_status_t *sig)
 {
+  pthread_mutex_lock(&rtp->lock);
   rtp->sig = *sig;
+  pthread_mutex_unlock(&rtp->lock);
 }
 
 static void *
@@ -304,12 +307,35 @@ void satip_rtp_close(void *id)
     pthread_join(rtp->tid, NULL);
     udp_multisend_free(&rtp->um);
     mpegts_pid_done(&rtp->pids);
+    pthread_mutex_destroy(&rtp->lock);
     free(rtp);
   } else {
     pthread_mutex_unlock(&satip_rtp_lock);
   }
 }
 
+/*
+ *
+ */
+static const char *
+satip_rtcp_pol(int pol)
+{
+  switch (pol) {
+  case DVB_POLARISATION_HORIZONTAL:
+    return "h";
+  case DVB_POLARISATION_VERTICAL:
+    return "v";
+  case DVB_POLARISATION_CIRCULAR_LEFT:
+    return "l";
+  case DVB_POLARISATION_CIRCULAR_RIGHT:
+    return "r";
+  case DVB_POLARISATION_OFF:
+    return "off";
+  default:
+    return "";
+  }
+}
+
 /*
  *
  */
@@ -332,19 +358,19 @@ satip_rtcp_fec(int fec)
     *p = *(p+1);
     p++;
   }
-  return s;
+  return buf;
 }
 
 /*
  *
  */
 static int
-satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
+satip_status_build(satip_rtp_session_t *rtp, char *buf, int len)
 {
-  char buf[1500], pids[1400];
+  char pids[1400];
   const char *delsys, *msys, *pilot, *rolloff;
   const char *bw, *tmode, *gi, *plp, *t2id, *sm, *c2tft, *ds, *specinv;
-  int i, len, len2, level = 0, lock = 0, quality = 0;
+  int i, j, r, level = 0, lock = 0, quality = 0;
 
   if (rtp->sig.snr > 0)
     lock = 1;
@@ -370,10 +396,10 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
   }
 
   pids[0] = 0;
-  for (i = len = 0; i < rtp->pids.count; i++)
-    len += snprintf(pids + len, sizeof(pids) - len, "%d,", rtp->pids.pids[i]);
-  if (len && pids[len-1] == ',')
-    pids[len-1] = '\0';
+  for (i = j = 0; i < rtp->pids.count; i++)
+    j += snprintf(pids + j, sizeof(pids) - j, "%d,", rtp->pids.pids[i]);
+  if (j && pids[j-1] == ',')
+    pids[j-1] = '\0';
 
   switch (rtp->dmc.dmc_fe_delsys) {
   case DVB_SYS_DVBS:
@@ -398,11 +424,11 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
     /* ver=<major>.<minor>;src=<srcID>;tuner=<feID>,<level>,<lock>,<quality>,<frequency>,<polarisation>,\
      * <system>,<type>,<pilots>,<roll_off>,<symbol_rate>,<fec_inner>;pids=<pid0>,...,<pidn>
      */
-    snprintf(buf, sizeof(buf),
+    r = snprintf(buf, len,
       "ver=1.0;src=%d;tuner=%d,%d,%d,%d,%.f,%s,%s,%s,%s,%s,%.f,%s;pids=%s",
       rtp->source, rtp->frontend, level, lock, quality,
-      (float)rtp->dmc.dmc_fe_freq / 1000000.0,
-      dvb_pol2str(rtp->dmc.u.dmc_fe_qpsk.polarisation),
+      (float)rtp->dmc.dmc_fe_freq / 1000.0,
+      satip_rtcp_pol(rtp->dmc.u.dmc_fe_qpsk.polarisation),
       delsys, msys, pilot, rolloff,
       (float)rtp->dmc.u.dmc_fe_qpsk.symbol_rate / 1000.0,
       satip_rtcp_fec(rtp->dmc.u.dmc_fe_qpsk.fec_inner),
@@ -452,7 +478,7 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
     /* ver=1.1;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<tmode>,<mtype>,<gi>,\
      * <fec>,<plp>,<t2id>,<sm>;pids=<pid0>,...,<pidn>
      */
-    snprintf(buf, sizeof(buf),
+    r = snprintf(buf, len,
       "ver=1.1;tuner=%d,%d,%d,%d,%.f,%s,%s,%s,%s,%s,%s,%s,%s,%s;pids=%s",
       rtp->frontend, level, lock, quality,
       (float)rtp->dmc.dmc_fe_freq / 1000000.0,
@@ -478,7 +504,7 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
     /* ver=1.2;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<mtype>,<sr>,<c2tft>,<ds>,<plp>,
      * <specinv>;pids=<pid0>,...,<pidn>
      */
-    snprintf(buf, sizeof(buf),
+    r = snprintf(buf, len,
       "ver=1.1;tuner=%d,%d,%d,%d,%.f,%s,%s,%s,%.f,%s,%s,%s,%s;pids=%s",
       rtp->frontend, level, lock, quality,
       (float)rtp->dmc.dmc_fe_freq / 1000000.0,
@@ -490,7 +516,44 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
     return 0;
   }
 
-  len = len2 = MIN(strlen(buf), RTCP_PAYLOAD - 16);
+  return r;
+}
+
+/*
+ *
+ */
+int satip_rtp_status(void *id, char *buf, int len)
+{
+  satip_rtp_session_t *rtp;
+  int r = 0;
+
+  if (buf)
+    buf[0] = '\0';
+  pthread_mutex_lock(&satip_rtp_lock);
+  rtp = satip_rtp_find(id);
+  if (rtp) {
+    pthread_mutex_lock(&rtp->lock);
+    r = satip_status_build(rtp, buf, len);
+    pthread_mutex_unlock(&rtp->lock);
+  }
+  pthread_mutex_unlock(&satip_rtp_lock);
+  return r;
+}
+
+/*
+ *
+ */
+static int
+satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
+{
+  char buf[1500];
+  int len, len2;
+
+  pthread_mutex_lock(&rtp->lock);
+  len = satip_status_build(rtp, buf, sizeof(buf));
+  pthread_mutex_unlock(&rtp->lock);
+
+  len = len2 = MIN(len, RTCP_PAYLOAD - 16);
   if (len == 0)
     len++;
   while ((len % 4) != 0)
index 0ab2f24d1ebae03fd07fc5d4663b987997624169..3f0599aeb19a293e9f2e2824e630542bc9de21bb 100644 (file)
@@ -366,7 +366,8 @@ rtsp_process_options(http_connection_t *hc)
   }
   http_arg_init(&args);
   http_arg_set(&args, "Public", "OPTIONS,DESCRIBE,SETUP,PLAY,TEARDOWN");
-  http_arg_set(&args, "Session", hc->hc_session);
+  if (hc->hc_session)
+    http_arg_set(&args, "Session", hc->hc_session);
   http_send_header(hc, HTTP_STATUS_OK, NULL, 0, NULL, NULL, 0, NULL, NULL, &args);
   http_arg_flush(&args);
   return 0;
@@ -376,6 +377,129 @@ error:
   return 0;
 }
 
+/*
+ *
+ */
+static void
+rtsp_describe_header(session_t *rs, htsbuf_queue_t *q)
+{
+  unsigned long mono = getmonoclock();
+  int dvbt, dvbc;
+
+  htsbuf_qprintf(q, "v=0\r\n");
+  htsbuf_qprintf(q, "o=- %lu %lu IN %s %s\r\n",
+                 rs ? (unsigned long)rs->nsession : mono - 123,
+                 mono,
+                 strchr(rtsp_ip, ':') ? "IP6" : "IP4",
+                 rtsp_ip);
+
+  pthread_mutex_lock(&global_lock);
+  htsbuf_qprintf(q, "s=SatIPServer:1 %d",
+                 config_get_int("satip_dvbs", 0));
+  dvbt = config_get_int("satip_dvbt", 0);
+  dvbc = config_get_int("satip_dvbc", 0);
+  if (dvbc)
+    htsbuf_qprintf(q, " %d %d\r\n", dvbt, dvbc);
+  else if (dvbt)
+    htsbuf_qprintf(q, " %d\r\n", dvbt);
+  else
+    htsbuf_append(q, "\r\n", 1);
+  pthread_mutex_unlock(&global_lock);
+
+  htsbuf_qprintf(q, "t=0 0\r\n");
+  htsbuf_qprintf(q, "a=tool:tvheadend\r\n");
+}
+
+static void
+rtsp_describe_session(session_t *rs, htsbuf_queue_t *q)
+{
+  char buf[4096];
+
+  htsbuf_qprintf(q, "m=video 0 RTP/AVP 33\r\n");
+  if (strchr(rtsp_ip, ':'))
+    htsbuf_qprintf(q, "c=IN IP6 ::0\r\n");
+  else
+    htsbuf_qprintf(q, "c=IN IP4 0.0.0.0\r\n");
+  htsbuf_qprintf(q, "a=control:stream=%d\r\n", rs->stream);
+  if (rs->run) {
+    satip_rtp_status((void *)(intptr_t)rs->stream, buf, sizeof(buf));
+    htsbuf_qprintf(q, "a=fmtp:33 %s\r\n", buf);
+    htsbuf_qprintf(q, "a=sendonly\r\n");
+  } else {
+    htsbuf_qprintf(q, "a=inactive\r\n");
+  }
+}
+
+/*
+ *
+ */
+static int
+rtsp_process_describe(http_connection_t *hc)
+{
+  http_arg_list_t args;
+  const char *arg;
+  char *u = tvh_strdupa(hc->hc_url);
+  session_t *rs;
+  htsbuf_queue_t q;
+  char buf[96];
+  int stream;
+
+  htsbuf_queue_init(&q, 0);
+
+  arg = http_arg_get(&hc->hc_args, "Accept");
+  if (strcmp(arg, "application/sdp"))
+    goto error;
+
+  if ((u = rtsp_check_urlbase(u)) == NULL)
+    goto error;
+
+  stream = rtsp_parse_args(hc, u);
+
+  if (TAILQ_FIRST(&hc->hc_req_args))
+    goto error;
+
+  if (hc->hc_session) {
+    pthread_mutex_lock(&rtsp_lock);
+    TAILQ_FOREACH(rs, &rtsp_sessions, link)
+      if (rs->stream == stream)
+        break;
+    if (rs) {
+      rtsp_describe_header(rs, &q);
+      rtsp_describe_session(rs, &q);
+    }
+    pthread_mutex_unlock(&rtsp_lock);
+    if (rs == NULL) {
+      http_error(hc, HTTP_STATUS_BAD_SESSION);
+      return 0;
+    }
+  } else {
+    pthread_mutex_lock(&rtsp_lock);
+    rtsp_describe_header(NULL, &q);
+    TAILQ_FOREACH(rs, &rtsp_sessions, link)
+      rtsp_describe_session(rs, &q);
+    pthread_mutex_unlock(&rtsp_lock);
+  }
+  http_arg_init(&args);
+  if (hc->hc_session)
+    http_arg_set(&args, "Session", hc->hc_session);
+  if (stream > 0)
+    snprintf(buf, sizeof(buf), "rtsp://%s/stream=%i", rtsp_ip, stream);
+  else
+    snprintf(buf, sizeof(buf), "rtsp://%s", rtsp_ip);
+  http_arg_set(&args, "Content-Base", buf);
+  http_send_header(hc, HTTP_STATUS_OK, "application/sdp", q.hq_size,
+                   NULL, NULL, 0, NULL, NULL, &args);
+  tcp_write_queue(hc->hc_fd, &q);
+  http_arg_flush(&args);
+  htsbuf_queue_flush(&q);
+  return 0;
+
+error:
+  htsbuf_queue_flush(&q);
+  http_error(hc, HTTP_STATUS_BAD_REQUEST);
+  return 0;
+}
+
 /*
  *
  */
@@ -925,6 +1049,8 @@ rtsp_process_request(http_connection_t *hc, htsbuf_queue_t *spill)
   switch (hc->hc_cmd) {
   case RTSP_CMD_OPTIONS:
     return rtsp_process_options(hc);
+  case RTSP_CMD_DESCRIBE:
+    return rtsp_process_describe(hc);
   case RTSP_CMD_SETUP:
   case RTSP_CMD_PLAY:
     return rtsp_process_play(hc, hc->hc_cmd == RTSP_CMD_SETUP);
@@ -972,7 +1098,6 @@ static void
 rtsp_close_session(session_t *rs)
 {
   satip_rtp_close((void *)(intptr_t)rs->stream);
-  rs->stream = 0;
   rs->run = 0;
   udp_close(rs->udp_rtp);
   rs->udp_rtp = NULL;
index 38fcd049766de8bb7e34b18f335c3afd0e4246e7..68b1c7120594a1d0fa62e5d47d0e206f660e9604 100644 (file)
@@ -42,6 +42,7 @@ void satip_rtp_update(void *id, th_subscription_t *subs,
                       dvb_mux_conf_t *dmc,
                       mpegts_apids_t *pids);
 void satip_rtp_update_pids(void *id, mpegts_apids_t *pids);
+int satip_rtp_status(void *id, char *buf, int len);
 void satip_rtp_close(void *id);
 
 void satip_rtp_init(void);