]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
SAT>IP client: add RTSP/TCP support, fixes #3092
authorJaroslav Kysela <perex@perex.cz>
Wed, 7 Oct 2015 13:37:59 +0000 (15:37 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 7 Oct 2015 15:30:08 +0000 (17:30 +0200)
src/http.h
src/httpc.c
src/input/mpegts.h
src/input/mpegts/satip/satip.c
src/input/mpegts/satip/satip_frontend.c
src/input/mpegts/satip/satip_private.h
src/input/mpegts/satip/satip_rtsp.c
src/rtsp.c

index e494ab9f4f82d303ed55a40816cd884cabfaa511..2759f6d75b91cae0d64fe102e8c65d4f0cfa8f5c 100644 (file)
@@ -302,6 +302,7 @@ struct http_client {
   int          hc_reconnected:1;
   int          hc_keepalive:1;
   int          hc_in_data:1;
+  int          hc_in_rtp_data:1;
   int          hc_chunked:1;
   int          hc_chunk_trails:1;
   int          hc_running:1;
@@ -319,6 +320,8 @@ struct http_client {
   char        *hc_rtp_dest;
   int          hc_rtp_port;
   int          hc_rtpc_port;
+  int          hc_rtp_tcp;
+  int          hc_rtcp_tcp;
   int          hc_rtcp_server_port;
   int          hc_rtp_multicast:1;
   long         hc_rtsp_stream_id;
@@ -334,6 +337,8 @@ struct http_client {
   int     (*hc_hdr_received) (http_client_t *hc);
   int     (*hc_data_received)(http_client_t *hc, void *buf, size_t len);
   int     (*hc_data_complete)(http_client_t *hc);
+  int     (*hc_rtp_data_received)(http_client_t *hc, void *buf, size_t len);
+  int     (*hc_rtp_data_complete)(http_client_t *hc);
   void    (*hc_conn_closed)  (http_client_t *hc, int err);
 };
 
index f9dd15a397d30d89763ab23d52d36a78c70dc5da..594bb2b6ac762febf4456a54ca64099105206765 100644 (file)
@@ -209,6 +209,7 @@ http_client_flush( http_client_t *hc, int result )
   if (result < 0)
     http_client_shutdown(hc, 0, 0);
   hc->hc_in_data      = 0;
+  hc->hc_in_rtp_data  = 0;
   hc->hc_hsize        = 0;
   hc->hc_csize        = 0;
   hc->hc_rpos         = 0;
@@ -642,7 +643,11 @@ http_client_finish( http_client_t *hc )
     tvhtrace("httpc", "%04X: received %s data", shortid(hc), http_ver2str(hc->hc_version));
     tvhlog_hexdump("httpc", hc->hc_data, hc->hc_csize);
   }
-  if (hc->hc_data_complete) {
+  if (hc->hc_in_rtp_data && hc->hc_rtp_data_complete) {
+    res = hc->hc_rtp_data_complete(hc);
+    if (res < 0)
+      return http_client_flush(hc, res);
+  } else if (hc->hc_data_complete) {
     res = hc->hc_data_complete(hc);
     if (res < 0)
       return http_client_flush(hc, res);
@@ -863,7 +868,7 @@ http_client_run( http_client_t *hc )
   char *buf, *saveptr, *argv[3], *d, *p;
   int ver, res, delimsize = 4;
   ssize_t r;
-  size_t len;
+  size_t len, limit;
 
   if (hc == NULL)
     return 0;
@@ -891,9 +896,10 @@ http_client_run( http_client_t *hc )
   }
 
   buf = alloca(hc->hc_io_size);
-
-  if (!hc->hc_in_data && hc->hc_rpos > 3) {
-    if ((d = strstr(hc->hc_rbuf, "\r\n\r\n")) != NULL)
+  if (!hc->hc_in_data && !hc->hc_in_rtp_data && hc->hc_rpos > 3) {
+    if (hc->hc_version == RTSP_VERSION_1_0 && hc->hc_rbuf[0] == '$')
+      goto rtsp_data;
+    else if ((d = strstr(hc->hc_rbuf, "\r\n\r\n")) != NULL)
       goto header;
     if ((d = strstr(hc->hc_rbuf, "\n\n")) != NULL) {
       delimsize = 2;
@@ -906,7 +912,6 @@ retry:
     r = http_client_ssl_recv(hc, buf, hc->hc_io_size);
   else
     r = recv(hc->hc_fd, buf, hc->hc_io_size, MSG_DONTWAIT);
-  tvhtrace("httpc", "%04X: recv %zi", shortid(hc), r);
   if (r == 0) {
     if (hc->hc_in_data && !hc->hc_keepalive)
       return http_client_finish(hc);
@@ -920,11 +925,12 @@ retry:
     return http_client_flush(hc, -errno);
   }
   if (r > 0 && tvhtrace_enabled()) {
-    tvhtrace("httpc", "%04X: received %s answer", shortid(hc), http_ver2str(hc->hc_version));
-    tvhlog_hexdump("httpc", buf, r);
+    tvhtrace("httpc", "%04X: received %s answer (len = %zd)", shortid(hc), http_ver2str(hc->hc_version), r);
+    tvhlog_hexdump("httpc", buf, MIN(64, r));
   }
 
-  if (hc->hc_in_data) {
+  limit = hc->hc_version == RTSP_VERSION_1_0 ? hc->hc_io_size * 2 : 16*1024;
+  if (hc->hc_in_data && !hc->hc_in_rtp_data) {
     res = http_client_data_received(hc, buf, r, 0);
     if (res < 0)
       return http_client_flush(hc, res);
@@ -936,7 +942,7 @@ retry:
   }
 
   if (hc->hc_rsize < r + hc->hc_rpos) {
-    if (hc->hc_rsize + r > 16*1024)
+    if (hc->hc_rsize + r > limit)
       return http_client_flush(hc, -EMSGSIZE);
     hc->hc_rsize += r;
     hc->hc_rbuf = realloc(hc->hc_rbuf, hc->hc_rsize + 1);
@@ -948,6 +954,8 @@ retry:
 next_header:
   if (hc->hc_rpos < 3)
     return HTTP_CON_RECEIVING;
+  if (hc->hc_version == RTSP_VERSION_1_0 && hc->hc_rbuf[0] == '$')
+    goto rtsp_data;
   if ((d = strstr(hc->hc_rbuf, "\r\n\r\n")) == NULL) {
     delimsize = 2;
     if ((d = strstr(hc->hc_rbuf, "\n\n")) == NULL)
@@ -983,6 +991,7 @@ header:
     if (res < 0)
       return http_client_flush(hc, -EINVAL);
   }
+  tvhtrace("httpc", "header parse1");
   p = http_arg_get(&hc->hc_args, "Content-Length");
   if (p) {
     hc->hc_csize = atoll(p);
@@ -1011,16 +1020,19 @@ header:
     if (res < 0)
       return http_client_flush(hc, res);
   }
-  hc->hc_rpos -= hc->hc_hsize;
-  len = hc->hc_rpos;
+  len = hc->hc_rpos - hc->hc_hsize;
+  hc->hc_rpos = 0;
   if (hc->hc_code == HTTP_STATUS_CONTINUE) {
     memmove(hc->hc_rbuf, hc->hc_rbuf + hc->hc_hsize, len);
+    hc->hc_rpos = len;
     goto next_header;
   }
-  hc->hc_rpos = 0;
   if (hc->hc_version == RTSP_VERSION_1_0 && !hc->hc_csize) {
     hc->hc_csize = -1;
     hc->hc_in_data = 0;
+    memmove(hc->hc_rbuf, hc->hc_rbuf + hc->hc_hsize, len);
+    hc->hc_rpos = len;
+    return http_client_finish(hc);
   } else {
     hc->hc_in_data = 1;
   }
@@ -1030,6 +1042,47 @@ header:
   if (res > 0)
     return http_client_finish(hc);
   goto retry;
+
+rtsp_data:
+  /* RTSP embedded data */
+  r = 0;
+  res = HTTP_CON_RECEIVING;
+  hc->hc_in_data = 0;
+  hc->hc_in_rtp_data = 0;
+  while (hc->hc_rpos > r + 3) {
+    hc->hc_csize = 4 + ((hc->hc_rbuf[r+2] << 8) | hc->hc_rbuf[r+3]);
+    hc->hc_chunked = 0;
+    if (r + hc->hc_csize > hc->hc_rpos) {
+      memmove(hc->hc_rbuf, hc->hc_rbuf + r, hc->hc_rpos - r);
+      hc->hc_rpos -= r;
+      hc->hc_in_rtp_data = 1;
+      if (r == 0)
+        goto retry;
+      return HTTP_CON_RECEIVING;
+    }
+    if (hc->hc_rtp_data_received) {
+      res = hc->hc_rtp_data_received(hc, hc->hc_rbuf + r, hc->hc_csize);
+      if (res < 0)
+        return res;
+    } else {
+      res = 0;
+    }
+    r += hc->hc_csize;
+    if (res < 0)
+      return http_client_flush(hc, res);
+    hc->hc_in_rtp_data = 1;
+    res = http_client_finish(hc);
+    hc->hc_in_rtp_data = 0;
+    if (res < 0)
+      return http_client_flush(hc, res);
+    res = HTTP_CON_RECEIVING;
+    if (hc->hc_rpos < r + 4 || hc->hc_rbuf[r] != '$') {
+      memcpy(hc->hc_rbuf, hc->hc_rbuf + r, hc->hc_rpos - r);
+      hc->hc_rpos -= r;
+      goto next_header;
+    }
+  }
+  return res;
 }
 
 /*
index 25ab51bfa312274ceb602e799cfab2b41fdfa901..f76bb8bb4870f1fde6b94ed0a19e95dcb8fc3ec2 100644 (file)
@@ -906,7 +906,7 @@ static inline void
 tsdebug_write(mpegts_mux_t *mm, uint8_t *buf, size_t len)
 {
 #if ENABLE_TSDEBUG
-  if (mm->mm_tsdebug_fd2 >= 0)
+  if (mm && mm->mm_tsdebug_fd2 >= 0)
     if (write(mm->mm_tsdebug_fd2, buf, len) != len)
       tvherror("tsdebug", "unable to write input data (%i)", errno);
 #endif
index b559ea0cd4c1aeafb56cea1e4920e4d3c5c54c46..a73577352cb04bcbb7dfcc34bc2f3483510c3816 100644 (file)
@@ -206,6 +206,13 @@ const idclass_t satip_device_class =
       .notify   = satip_device_class_tunercfg_notify,
       .def.s    = "Auto"
     },
+    {
+      .type     = PT_BOOL,
+      .id       = "tcp_mode",
+      .name     = N_("RTSP/TCP (embedded data)"),
+      .opts     = PO_ADVANCED,
+      .off      = offsetof(satip_device_t, sd_tcp_mode),
+    },
     {
       .type     = PT_BOOL,
       .id       = "fast_switch",
index 1e9ab88436e7cc1f1dbf528d0d284816a0c43465..8e8074dfe874bac3998a9c50edcd2226e2889d0e 100644 (file)
@@ -849,9 +849,9 @@ satip_frontend_extra_shutdown
 
   efd = tvhpoll_create(1);
   rtsp = http_client_connect(lfe, RTSP_VERSION_1_0, "rstp",
-                               lfe->sf_device->sd_info.addr,
-                               lfe->sf_device->sd_info.rtsp_port,
-                               satip_frontend_bindaddr(lfe));
+                             lfe->sf_device->sd_info.addr,
+                             lfe->sf_device->sd_info.rtsp_port,
+                             satip_frontend_bindaddr(lfe));
   if (rtsp == NULL)
     goto done;
 
@@ -968,6 +968,82 @@ satip_frontend_close_rtsp
   *rtsp = NULL;
 }
 
+static int
+satip_frontend_rtp_data_received( http_client_t *hc, void *buf, size_t len )
+{
+  int c, pos;
+  uint32_t nseq, unc;
+  uint8_t *b = buf, *p;
+  satip_frontend_t *lfe = hc->hc_aux;
+  mpegts_mux_instance_t *mmi;
+
+  if (len < 4)
+    return -EINVAL;
+
+  if (b[1] == 0) {
+
+    p = b   + 4;
+    c = len - 4;
+
+    /* Strip RTP header */
+    if (c < 12)
+      return 0;
+    if ((p[0] & 0xc0) != 0x80)
+      return 0;
+    if ((p[1] & 0x7f) != 33)
+      return 0;
+    pos = ((p[0] & 0x0f) * 4) + 12;
+    if (p[0] & 0x10) {
+      if (c < pos + 4)
+        return 0;
+      pos += (((p[pos+2] << 8) | p[pos+3]) + 1) * 4;
+    }
+    if (c <= pos || ((c - pos) % 188) != 0)
+      return 0;
+    /* Use uncorrectable value to notify RTP delivery issues */
+    nseq = (p[2] << 8) | p[3];
+    unc  = 0;
+    if (lfe->sf_seq == -1)
+      lfe->sf_seq = nseq;
+    else if (((lfe->sf_seq + 1) & 0xffff) != nseq) {
+      unc = ((c - pos) / 188) * (uint32_t)((uint16_t)nseq-(uint16_t)(lfe->sf_seq+1));
+      tvhtrace("satip", "TCP/RTP discontinuity (%i != %i)", lfe->sf_seq + 1, nseq);
+    }
+    lfe->sf_seq = nseq;
+
+    /* Process */
+    tsdebug_write((mpegts_mux_t *)lfe->sf_curmux, p + pos, c - pos);
+    sbuf_append(&lfe->sf_sbuf, p + pos, c - pos);
+
+    if (lfe->sf_sbuf.sb_ptr > 64 * 1024 ||
+        lfe->sf_last_data_tstamp != dispatch_clock) {
+      pthread_mutex_lock(&lfe->sf_dvr_lock);
+      if (lfe->sf_req == lfe->sf_req_thread) {
+        mmi = lfe->sf_req->sf_mmi;
+        mmi->tii_stats.unc += unc;
+        mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi,
+                                  &lfe->sf_sbuf, NULL, NULL);
+      }
+      pthread_mutex_unlock(&lfe->sf_dvr_lock);
+      lfe->sf_last_data_tstamp = dispatch_clock;
+    }
+
+  } else if (b[1] == 1) {
+
+    /* note: satip_frontend_decode_rtcp puts '\0' at the end (string termination) */
+    len -= 4;
+    memmove(b, b + 4, len);
+
+    pthread_mutex_lock(&lfe->sf_dvr_lock);
+    if (lfe->sf_req == lfe->sf_req_thread)
+      satip_frontend_decode_rtcp(lfe, lfe->sf_display_name,
+                                 lfe->sf_req->sf_mmi, b, len);
+    pthread_mutex_unlock(&lfe->sf_dvr_lock);
+
+  }
+  return 0;
+}
+
 static void *
 satip_frontend_input_thread ( void *aux )
 {
@@ -985,7 +1061,7 @@ satip_frontend_input_thread ( void *aux )
   struct iovec *iovec;
   uint8_t b[2048], session[32];
   uint8_t *p;
-  sbuf_t sb;
+  sbuf_t *sb;
   int pos, nfds, i, r, tc, rtp_port, start = 0;
   size_t c;
   tvhpoll_event_t ev[3];
@@ -1008,14 +1084,14 @@ satip_frontend_input_thread ( void *aux )
   rtsp = NULL;
 
   /* Setup buffers */
-  sbuf_init(&sb);
+  sbuf_init(sb = &lfe->sf_sbuf);
   udp_multirecv_init(&um, 0, 0);
 
   /*
    * New tune
    */
 new_tune:
-  sbuf_free(&sb);
+  sbuf_free(sb);
   udp_multirecv_free(&um);
   udp_close(rtcp);
   udp_close(rtp);
@@ -1025,6 +1101,9 @@ new_tune:
   if (rtsp && !lfe->sf_device->sd_fast_switch)
     satip_frontend_close_rtsp(lfe, efd, &rtsp);
 
+  if (rtsp)
+    rtsp->hc_rtp_data_received = NULL;
+
   memset(ev, 0, sizeof(ev));
   ev[0].events             = TVHPOLL_IN;
   ev[0].fd                 = lfe->sf_dvr_pipe.rd;
@@ -1032,6 +1111,7 @@ new_tune:
   tvhpoll_add(efd, ev, 1);
 
   lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf));
+  lfe->sf_display_name = buf;
 
   while (!start) {
 
@@ -1087,36 +1167,46 @@ new_tune:
   if (!lfe->sf_req_thread)
     goto new_tune;
 
-  mmi        = tr->sf_mmi;
-  changing   = 0;
-  ms         = 500;
-  fatal      = 0;
-  running    = 1;
-  seq        = -1;
-  play2      = 1;
-  rtsp_flags = 0;
-
-  if (udp_bind_double(&rtp, &rtcp,
-                      "satip", "rtp", "rtpc",
-                      satip_frontend_bindaddr(lfe), lfe->sf_udp_rtp_port,
-                      NULL, SATIP_BUF_SIZE, 16384, 4*1024, 4*1024) < 0) {
-    satip_frontend_tuning_error(lfe, tr);
-    goto done;
-  }
+  mmi         = tr->sf_mmi;
+  changing    = 0;
+  ms          = 500;
+  fatal       = 0;
+  running     = 1;
+  seq         = -1;
+  lfe->sf_seq = -1;
+  play2       = 1;
+  rtsp_flags  = lfe->sf_device->sd_tcp_mode ? SATIP_SETUP_TCP : 0;
+
+  if ((rtsp_flags & SATIP_SETUP_TCP) == 0) {
+    if (udp_bind_double(&rtp, &rtcp,
+                        "satip", "rtp", "rtpc",
+                        satip_frontend_bindaddr(lfe), lfe->sf_udp_rtp_port,
+                        NULL, SATIP_BUF_SIZE, 16384, 4*1024, 4*1024) < 0) {
+      satip_frontend_tuning_error(lfe, tr);
+      goto done;
+    }
 
-  rtp_port = ntohs(IP_PORT(rtp->ip));
+    rtp_port = ntohs(IP_PORT(rtp->ip));
 
-  tvhtrace("satip", "%s - local RTP port %i RTCP port %i",
-                    lfe->mi_name,
-                    ntohs(IP_PORT(rtp->ip)),
-                    ntohs(IP_PORT(rtcp->ip)));
+    tvhtrace("satip", "%s - local RTP port %i RTCP port %i",
+                      lfe->mi_name,
+                      ntohs(IP_PORT(rtp->ip)),
+                      ntohs(IP_PORT(rtcp->ip)));
 
-  if (rtp == NULL || rtcp == NULL || mmi == NULL) {
+    if (rtp == NULL || rtcp == NULL) {
+      satip_frontend_tuning_error(lfe, tr);
+      goto done;
+    }
+  } else {
+    rtp_port = -1;
+  }
+
+  if (mmi == NULL) {
     satip_frontend_tuning_error(lfe, tr);
     goto done;
   }
 
-  lm = (dvb_mux_t *)mmi->mmi_mux;
+  lfe->sf_curmux = lm = (dvb_mux_t *)mmi->mmi_mux;
 
   lfe_master = lfe;
   if (lfe->sf_master)
@@ -1204,18 +1294,27 @@ new_tune:
 
   /* Setup poll */
   memset(ev, 0, sizeof(ev));
-  ev[0].events             = TVHPOLL_IN;
-  ev[0].fd                 = rtp->fd;
-  ev[0].data.ptr           = rtp;
-  ev[1].events             = TVHPOLL_IN;
-  ev[1].fd                 = rtcp->fd;
-  ev[1].data.ptr           = rtcp;
+  nfds = 0;
+  if ((rtsp_flags & SATIP_SETUP_TCP) == 0) {
+    ev[nfds].events    = TVHPOLL_IN;
+    ev[nfds].fd        = rtp->fd;
+    ev[nfds].data.ptr  = rtp;
+    nfds++;
+    ev[nfds].events    = TVHPOLL_IN;
+    ev[nfds].fd        = rtcp->fd;
+    ev[nfds].data.ptr  = rtcp;
+    nfds++;
+  } else {
+    rtsp->hc_io_size           = 128 * 1024;
+    rtsp->hc_rtp_data_received = satip_frontend_rtp_data_received;
+  }
   if (i) {
-    ev[2].events           = TVHPOLL_IN;
-    ev[2].fd               = rtsp->hc_fd;
-    ev[2].data.ptr         = rtsp;
+    ev[nfds].events    = TVHPOLL_IN;
+    ev[nfds].fd        = rtsp->hc_fd;
+    ev[nfds].data.ptr  = rtsp;
+    nfds++;
   }
-  tvhpoll_add(efd, ev, i ? 3 : 2);
+  tvhpoll_add(efd, ev, nfds);
   rtsp->hc_efd = efd;
 
   position = lfe_master->sf_position;
@@ -1244,7 +1343,7 @@ new_tune:
   reply = 1;
 
   udp_multirecv_init(&um, RTP_PKTS, RTP_PKT_SIZE);
-  sbuf_init_fixed(&sb, RTP_PKTS * RTP_PKT_SIZE);
+  sbuf_init_fixed(sb, RTP_PKTS * RTP_PKT_SIZE);
   
   while ((reply || running) && !fatal) {
 
@@ -1322,8 +1421,11 @@ new_tune:
           r = rtsp_setup_decode(rtsp, 1);
           if (!running)
             break;
-          if (r < 0 || rtsp->hc_rtp_port != rtp_port ||
-                       rtsp->hc_rtpc_port != rtp_port + 1) {
+          if (r < 0 || ((rtsp_flags & SATIP_SETUP_TCP) == 0 &&
+                         (rtsp->hc_rtp_port  != rtp_port ||
+                          rtsp->hc_rtpc_port != rtp_port + 1)) ||
+                       ((rtsp_flags & SATIP_SETUP_TCP) != 0 &&
+                         (rtsp->hc_rtp_tcp < 0 || rtsp->hc_rtcp_tcp < 0))) {
             tvhlog(LOG_ERR, "satip", "%s - RTSP SETUP error %d (%s) [%i-%i]",
                    buf, r, strerror(-r), rtsp->hc_cmd, rtsp->hc_code);
             satip_frontend_tuning_error(lfe, tr);
@@ -1450,13 +1552,13 @@ new_tune:
       seq = nseq;
       /* Process */
       tsdebug_write((mpegts_mux_t *)lm, p + pos, c - pos);
-      sbuf_append(&sb, p + pos, c - pos);
+      sbuf_append(sb, p + pos, c - pos);
     }
     pthread_mutex_lock(&lfe->sf_dvr_lock);
     if (lfe->sf_req == lfe->sf_req_thread) {
       mmi->tii_stats.unc += unc;
       mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi,
-                                &sb, NULL, NULL);
+                                sb, NULL, NULL);
     } else
       fatal = 1;
     pthread_mutex_unlock(&lfe->sf_dvr_lock);
@@ -1465,19 +1567,26 @@ new_tune:
   /* Do not send the SMT_SIGNAL_STATUS packets - we are out of service */
   gtimer_disarm(&lfe->sf_monitor_timer);
 
-  sbuf_free(&sb);
+  sbuf_free(sb);
   udp_multirecv_free(&um);
-
-  ev[0].events             = TVHPOLL_IN;
-  ev[0].fd                 = rtp->fd;
-  ev[0].data.ptr           = rtp;
-  ev[1].events             = TVHPOLL_IN;
-  ev[1].fd                 = rtcp->fd;
-  ev[1].data.ptr           = rtcp;
-  ev[2].events             = TVHPOLL_IN;
-  ev[2].fd                 = lfe->sf_dvr_pipe.rd;
-  ev[2].data.ptr           = NULL;
-  tvhpoll_rem(efd, ev, 3);
+  lfe->sf_curmux = NULL;
+
+  nfds = 0;
+  if ((rtsp_flags & SATIP_SETUP_TCP) == 0) {
+    ev[nfds].events             = TVHPOLL_IN;
+    ev[nfds].fd                 = rtp->fd;
+    ev[nfds].data.ptr           = rtp;
+    nfds++;
+    ev[nfds].events             = TVHPOLL_IN;
+    ev[nfds].fd                 = rtcp->fd;
+    ev[nfds].data.ptr           = rtcp;
+    nfds++;
+  }
+  ev[nfds].events             = TVHPOLL_IN;
+  ev[nfds].fd                 = lfe->sf_dvr_pipe.rd;
+  ev[nfds].data.ptr           = NULL;
+  nfds++;
+  tvhpoll_rem(efd, ev, nfds);
 
   if (exit_flag) {
     satip_frontend_shutdown(rtsp, efd);
@@ -1512,6 +1621,8 @@ done:
     http_client_close(rtsp);
 
   tvhpoll_destroy(efd);
+  lfe->sf_display_name = NULL;
+  lfe->sf_curmux = NULL;
   return NULL;
 #undef PKTS
 }
index fc6b90523971b0308e74e5f245fdb3c0a74661ef..097f5728b8e71c3341cb916a637262675a6abc9f 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef __TVH_SATIP_PRIVATE_H__
 #define __TVH_SATIP_PRIVATE_H__
 
+#include "tvheadend.h"
 #include "input.h"
 #include "htsbuf.h"
 #include "udp.h"
@@ -79,6 +80,7 @@ struct satip_device
    * RTSP
    */
   char                      *sd_bindaddr;
+  int                        sd_tcp_mode;
   int                        sd_fast_switch;
   int                        sd_fullmux_ok;
   int                        sd_pids_max;
@@ -142,6 +144,11 @@ struct satip_frontend
   uint64_t                   sf_last_tune;
   satip_tune_req_t          *sf_req;
   satip_tune_req_t          *sf_req_thread;
+  sbuf_t                     sf_sbuf;
+  const char *               sf_display_name;
+  uint32_t                   sf_seq;
+  dvb_mux_t                 *sf_curmux;
+  time_t                     sf_last_data_tstamp;
  
   /*
    * Configuration
@@ -225,10 +232,11 @@ int satip_satconf_get_position
  * RTSP part
  */
 
-#define SATIP_SETUP_PLAY     (1<<0)
-#define SATIP_SETUP_PIDS0    (1<<1)
-#define SATIP_SETUP_PILOT_ON (1<<2)
-#define SATIP_SETUP_PIDS21   (1<<3)
+#define SATIP_SETUP_TCP      (1<<0)
+#define SATIP_SETUP_PLAY     (1<<1)
+#define SATIP_SETUP_PIDS0    (1<<2)
+#define SATIP_SETUP_PILOT_ON (1<<3)
+#define SATIP_SETUP_PIDS21   (1<<4)
 
 int
 satip_rtsp_setup( http_client_t *hc,
index a5ffef4ba673fd30968d0c36e297a53b4c9acd3c..10b99ff10eba4d554ef889fad9546a02661ffb09 100644 (file)
@@ -232,6 +232,8 @@ satip_rtsp_setup( http_client_t *hc, int src, int fe,
              hc->hc_rtsp_stream_id);
   if (flags & SATIP_SETUP_PLAY)
     return rtsp_play(hc, stream, buf);
+  if (flags & SATIP_SETUP_TCP)
+    return rtsp_setup(hc, stream, buf, NULL, 0, -1);
   return rtsp_setup(hc, stream, buf, NULL, udp_port, udp_port + 1);
 }
 
index 4f706f94bfeaaee61f3649e3aa30b2117b294a30..489afe9b287d618b404148e7b055f7879b7a5f61 100644 (file)
@@ -145,41 +145,67 @@ rtsp_setup_decode( http_client_t *hc, int satip )
   if (p == NULL)
     return -EIO;
   n = http_tokenize(p, argv, 32, ';');
-  if (n < 3)
+  if (n < 2)
     return -EIO;
-  if (strcasecmp(argv[0], "RTP/AVP"))
-    return -EIO;
-  hc->hc_rtp_multicast = strcasecmp(argv[1], "multicast") == 0;
-  if (strcasecmp(argv[1], "unicast") && !hc->hc_rtp_multicast)
-    return -EIO;
-  for (i = 2; i < n; i++) {
-    if (strncmp(argv[i], "destination=", 12) == 0)
-      hc->hc_rtp_dest = strdup(argv[i] + 12);
-    else if (strncmp(argv[i], "client_port=", 12) == 0) {
-      j = http_tokenize(argv[i] + 12, argv2, 2, '-');
-      if (j > 0) {
-        hc->hc_rtp_port = atoi(argv2[0]);
-        if (hc->hc_rtp_port <= 0)
-          return -EIO;
-        if (j > 1) {
-          hc->hc_rtpc_port = atoi(argv2[1]);
-          if (hc->hc_rtpc_port <= 0)
+  hc->hc_rtp_tcp = -1;
+  hc->hc_rtcp_tcp = -1;
+  hc->hc_rtp_port = -1;
+  hc->hc_rtpc_port = -1;
+  if (!strcasecmp(argv[0], "RTP/AVP/TCP")) {
+    for (i = 1; i < n; i++) {
+      if (strncmp(argv[i], "interleaved=", 12) == 0) {
+        j = http_tokenize(argv[i] + 12, argv2, 2, '-');
+        if (j > 0) {
+          hc->hc_rtp_tcp = atoi(argv2[0]);
+          if (hc->hc_rtp_tcp < 0)
             return -EIO;
+          if (j > 1) {
+            hc->hc_rtcp_tcp = atoi(argv2[1]);
+            if (hc->hc_rtcp_tcp < 0)
+              return -EIO;
+          }
+        } else {
+          return -EIO;
         }
-      } else {
-        return -EIO;
       }
     }
-    else if (strncmp(argv[i], "server_port=", 12) == 0) {
-      j = http_tokenize(argv[i] + 12, argv2, 2, '-');
-      if (j > 1) {
-        hc->hc_rtcp_server_port = atoi(argv2[1]);
-        if (hc->hc_rtcp_server_port <= 0)
+  } else if (!strcasecmp(argv[0], "RTP/AVP")) {
+    if (n < 3)
+      return -EIO;
+    hc->hc_rtp_multicast = strcasecmp(argv[1], "multicast") == 0;
+    if (strcasecmp(argv[1], "unicast") && !hc->hc_rtp_multicast)
+      return -EIO;
+    for (i = 2; i < n; i++) {
+      if (strncmp(argv[i], "destination=", 12) == 0)
+        hc->hc_rtp_dest = strdup(argv[i] + 12);
+      else if (strncmp(argv[i], "client_port=", 12) == 0) {
+        j = http_tokenize(argv[i] + 12, argv2, 2, '-');
+        if (j > 0) {
+          hc->hc_rtp_port = atoi(argv2[0]);
+          if (hc->hc_rtp_port <= 0)
+            return -EIO;
+          if (j > 1) {
+            hc->hc_rtpc_port = atoi(argv2[1]);
+            if (hc->hc_rtpc_port <= 0)
+              return -EIO;
+          }
+        } else {
           return -EIO;
-      } else {
-        return -EIO;
+        }
+      }
+      else if (strncmp(argv[i], "server_port=", 12) == 0) {
+        j = http_tokenize(argv[i] + 12, argv2, 2, '-');
+        if (j > 1) {
+          hc->hc_rtcp_server_port = atoi(argv2[1]);
+          if (hc->hc_rtcp_server_port <= 0)
+            return -EIO;
+        } else {
+          return -EIO;
+        }
       }
     }
+  } else {
+    return -EIO;
   }
   return HTTP_CON_OK;
 }
@@ -193,7 +219,10 @@ rtsp_setup( http_client_t *hc,
   http_arg_list_t h;
   char transport[256];
 
-  if (multicast_addr) {
+  if (rtpc_port < 0) {
+    snprintf(transport, sizeof(transport),
+      "RTP/AVP/TCP;interleaved=%d-%d", rtp_port, rtp_port + 1);
+  } else if (multicast_addr) {
     snprintf(transport, sizeof(transport),
       "RTP/AVP;multicast;destination=%s;ttl=1;client_port=%i-%i",
       multicast_addr, rtp_port, rtpc_port);