]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
IPTV: add rtsp:// and rtsps:// support
authorJaroslav Kysela <perex@perex.cz>
Fri, 1 May 2015 14:58:04 +0000 (16:58 +0200)
committerJaroslav Kysela <perex@perex.cz>
Fri, 1 May 2015 14:58:39 +0000 (16:58 +0200)
Makefile
src/http.c
src/http.h
src/input/mpegts/iptv/iptv.c
src/input/mpegts/iptv/iptv_http.c
src/input/mpegts/iptv/iptv_private.h
src/input/mpegts/iptv/iptv_rtsp.c [new file with mode: 0644]
src/input/mpegts/iptv/iptv_udp.c

index 6d1126416c1032547c80e642280eb29d5268b241..98b84ee354fabba30bbbb4d456b699d06dbf7225 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -289,6 +289,7 @@ SRCS-${CONFIG_IPTV} += \
         src/input/mpegts/iptv/iptv_service.c \
         src/input/mpegts/iptv/iptv_http.c \
         src/input/mpegts/iptv/iptv_udp.c \
+        src/input/mpegts/iptv/iptv_rtsp.c \
         src/input/mpegts/iptv/iptv_pipe.c
 
 # TSfile
index c95ee00f7f251c1531ca14778af586de0de37a0d..70e912011804526325fab745a7b39953a601d66b 100644 (file)
@@ -42,6 +42,7 @@ void *http_server;
 static http_path_list_t http_paths;
 
 static struct strtab HTTP_cmdtab[] = {
+  { "NONE",       HTTP_CMD_NONE },
   { "GET",        HTTP_CMD_GET },
   { "HEAD",       HTTP_CMD_HEAD },
   { "POST",       HTTP_CMD_POST },
index 17638018ef25bcf94e164e39ab5503666f10e51a..d9241d262ccf621032ff6d1816bec84a7b778fce 100644 (file)
@@ -100,6 +100,7 @@ typedef enum http_state {
 } http_state_t;
 
 typedef enum http_cmd {
+  HTTP_CMD_NONE,
   HTTP_CMD_GET,
   HTTP_CMD_HEAD,
   HTTP_CMD_POST,
index 87ca500d2303b45b3aa6297f1bdc7b5014a300fa..407c92cf945e9bd7e06eee89b1066923b7ac1161 100644 (file)
@@ -271,6 +271,13 @@ iptv_input_stop_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
     im->mm_iptv_fd = -1;
   }
 
+  /* Close file2 */
+  if (im->mm_iptv_fd2 > 0) {
+    udp_close(im->mm_iptv_connection2); // removes from poll
+    im->mm_iptv_connection2 = NULL;
+    im->mm_iptv_fd2 = -1;
+  }
+
   /* Free memory */
   sbuf_free(&im->mm_iptv_buffer);
 
@@ -379,6 +386,22 @@ iptv_input_fd_started ( iptv_mux_t *im )
       return -1;
     }
   }
+
+  /* Setup poll2 */
+  if (im->mm_iptv_fd2 > 0) {
+    ev.fd       = im->mm_iptv_fd2;
+    ev.events   = TVHPOLL_IN;
+    ev.data.ptr = im;
+
+    /* Error? */
+    if (tvhpoll_add(iptv_poll, &ev, 1) == -1) {
+      mpegts_mux_nice_name((mpegts_mux_t*)im, buf, sizeof(buf));
+      tvherror("iptv", "%s - failed to add to poll q (2)", buf);
+      close(im->mm_iptv_fd2);
+      im->mm_iptv_fd2 = -1;
+      return -1;
+    }
+  }
   return 0;
 }
 
@@ -581,6 +604,7 @@ void iptv_init ( void )
   /* Register handlers */
   iptv_http_init();
   iptv_udp_init();
+  iptv_rtsp_init();
   iptv_pipe_init();
 
   iptv_input = calloc(1, sizeof(iptv_input_t));
index 17dbabf250bdde88837830f98b638f50647288c1..1f136f4384d5d083b6fee710c0a830aeaae055f2 100644 (file)
@@ -27,6 +27,9 @@
 static int
 iptv_http_header ( http_client_t *hc )
 {
+  if (hc->hc_aux == NULL)
+    return 0;
+
   /* multiple headers for redirections */
   if (hc->hc_code == HTTP_STATUS_OK) {
     pthread_mutex_lock(&global_lock);
@@ -45,6 +48,9 @@ iptv_http_data
 {
   iptv_mux_t *im = hc->hc_aux;
 
+  if (im == NULL)
+    return 0;
+
   pthread_mutex_lock(&iptv_lock);
 
   tsdebug_write((mpegts_mux_t *)im, buf, len);
@@ -93,8 +99,11 @@ static void
 iptv_http_stop
   ( iptv_mux_t *im )
 {
+  http_client_t *hc = im->im_data;
+
+  hc->hc_aux = NULL;
   pthread_mutex_unlock(&iptv_lock);
-  http_client_close(im->im_data);
+  http_client_close(hc);
   pthread_mutex_lock(&iptv_lock);
 }
 
index d7f1af3adbc08fe2115e359223e06af878cf73e1..688e25fd9190d35ac8d35edf6a82d951bd55e906 100644 (file)
@@ -83,6 +83,8 @@ struct iptv_mux
   int                   mm_iptv_streaming_priority;
   int                   mm_iptv_fd;
   udp_connection_t     *mm_iptv_connection;
+  int                   mm_iptv_fd2;
+  udp_connection_t     *mm_iptv_connection2;
   char                 *mm_iptv_url;
   char                 *mm_iptv_url_sane;
   char                 *mm_iptv_interface;
@@ -123,7 +125,10 @@ void iptv_mux_load_all ( void );
 
 void iptv_http_init    ( void );
 void iptv_udp_init     ( void );
-void iptv_pipe_init     ( void );
+void iptv_rtsp_init    ( void );
+void iptv_pipe_init    ( void );
+
+ssize_t iptv_rtp_read ( iptv_mux_t *im, udp_multirecv_t *um );
 
 #endif /* __IPTV_PRIVATE_H__ */
 
diff --git a/src/input/mpegts/iptv/iptv_rtsp.c b/src/input/mpegts/iptv/iptv_rtsp.c
new file mode 100644 (file)
index 0000000..360e116
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ *  IPTV - RTSP/RTSPS handler
+ *
+ *  Copyright (C) 2015 Jaroslav Kysela
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tvheadend.h"
+#include "iptv_private.h"
+#include "http.h"
+#include "udp.h"
+
+typedef struct {
+  http_client_t *hc;
+  udp_multirecv_t um;
+  char *url;
+  gtimer_t alive_timer;
+} rtsp_priv_t;
+
+/*
+ * Alive timeout
+ */
+static void
+iptv_rtsp_alive_cb ( void *aux )
+{
+  iptv_mux_t *im = aux;
+  rtsp_priv_t *rp = im->im_data;
+
+  rtsp_options(rp->hc);
+  gtimer_arm(&rp->alive_timer, iptv_rtsp_alive_cb, im, rp->hc->hc_rtp_timeout / 2);
+}
+
+/*
+ * Connected
+ */
+static int
+iptv_rtsp_header ( http_client_t *hc )
+{
+  iptv_mux_t *im = hc->hc_aux;
+  rtsp_priv_t *rp = im->im_data;
+  int r;
+
+  if (im == NULL)
+    return 0;
+
+  if (hc->hc_code != HTTP_STATUS_OK) {
+    tvherror("iptv", "invalid error code %d for '%s'", hc->hc_code, im->mm_iptv_url);
+    return 0;
+  }
+
+  switch (hc->hc_cmd) {
+  case RTSP_CMD_SETUP:
+    r = rtsp_setup_decode(hc, 0);
+    if (r >= 0)
+      rtsp_play(hc, rp->url, "");
+    break;
+  case RTSP_CMD_PLAY:
+    hc->hc_cmd = HTTP_CMD_NONE;
+    pthread_mutex_lock(&global_lock);
+    iptv_input_mux_started(hc->hc_aux);
+    gtimer_arm(&rp->alive_timer, iptv_rtsp_alive_cb, im, hc->hc_rtp_timeout / 2);
+    pthread_mutex_unlock(&global_lock);
+    break;
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+/*
+ * Receive data
+ */
+static int
+iptv_rtsp_data
+  ( http_client_t *hc, void *buf, size_t len )
+{
+  iptv_mux_t *im = hc->hc_aux;
+
+  if (im == NULL)
+    return 0;
+
+  if (len > 0)
+    tvherror("iptv", "unknown data %zd received for '%s'", len, im->mm_iptv_url);
+
+  return 0;
+}
+
+/*
+ * Setup RTSP(S) connection
+ */
+static int
+iptv_rtsp_start
+  ( iptv_mux_t *im, const char *raw, const url_t *u )
+{
+  rtsp_priv_t *rp;
+  http_client_t *hc;
+  udp_connection_t *rtp, *rtpc;
+  int r;
+
+  if (!(hc = http_client_connect(im, RTSP_VERSION_1_0, u->scheme,
+                                 u->host, u->port, NULL)))
+    return SM_CODE_TUNING_FAILED;
+
+  if (udp_bind_double(&rtp, &rtpc,
+                      "IPTV", "rtp", "rtcp",
+                      NULL, 0, NULL,
+                      128*1024, 16384, 4*1024, 4*1024) < 0) {
+    http_client_close(hc);
+    return SM_CODE_TUNING_FAILED;
+  }
+
+  hc->hc_hdr_received    = iptv_rtsp_header;
+  hc->hc_data_received   = iptv_rtsp_data;
+  hc->hc_handle_location = 1;        /* allow redirects */
+  http_client_register(hc);          /* register to the HTTP thread */
+  r = rtsp_setup(hc, u->path, u->query, NULL,
+                 ntohs(IP_PORT(rtp->ip)),
+                 ntohs(IP_PORT(rtpc->ip)));
+  if (r < 0) {
+    udp_close(rtpc);
+    udp_close(rtp);
+    http_client_close(hc);
+    return SM_CODE_TUNING_FAILED;
+  }
+
+  rp = calloc(1, sizeof(*rp));
+  rp->hc = hc;
+  udp_multirecv_init(&rp->um, IPTV_PKTS, IPTV_PKT_PAYLOAD);
+  rp->url = strdup(u->raw);
+
+  im->im_data = rp;
+  im->mm_iptv_fd = rtp->fd;
+  im->mm_iptv_connection = rtp;
+  im->mm_iptv_fd2 = rtpc->fd;
+  im->mm_iptv_connection2 = rtpc;
+
+  return 0;
+}
+
+/*
+ * Stop connection
+ */
+static void
+iptv_rtsp_stop
+  ( iptv_mux_t *im )
+{
+  rtsp_priv_t *rp = im->im_data;
+
+  lock_assert(&global_lock);
+
+  if (rp == NULL)
+    return;
+  im->im_data = NULL;
+  rp->hc->hc_aux = NULL;
+  pthread_mutex_unlock(&iptv_lock);
+  gtimer_disarm(&rp->alive_timer);
+  udp_multirecv_free(&rp->um);
+  http_client_close(rp->hc);
+  free(rp->url);
+  free(rp);
+  pthread_mutex_lock(&iptv_lock);
+}
+
+/*
+ * Read data
+ */
+static ssize_t
+iptv_rtsp_read ( iptv_mux_t *im )
+{
+  rtsp_priv_t *rp = im->im_data;
+  udp_multirecv_t *um = &rp->um;
+  ssize_t r;
+  uint8_t buf[1500];
+
+  /* RTPC - ignore all incoming packets for now */
+  do {
+    r = recv(im->mm_iptv_fd2, buf, sizeof(buf), MSG_DONTWAIT);
+  } while (r > 0);
+
+  r = iptv_rtp_read(im, um);
+  if (r < 0 && ERRNO_AGAIN(errno))
+    r = 0;
+  return r;
+}
+
+/*
+ * Initialise RTSP handler
+ */
+
+void
+iptv_rtsp_init ( void )
+{
+  static iptv_handler_t ih[] = {
+    {
+      .scheme = "rtsp",
+      .start  = iptv_rtsp_start,
+      .stop   = iptv_rtsp_stop,
+      .read   = iptv_rtsp_read,
+    },
+    {
+      .scheme  = "rtsps",
+      .start  = iptv_rtsp_start,
+      .stop   = iptv_rtsp_stop,
+      .read   = iptv_rtsp_read,
+    }
+  };
+  iptv_handler_register(ih, 2);
+}
index 3989cc1d032c5a322b492452f4917c5354207001..e561c375ad7fe811a04871fdbf34d8304bcd2792 100644 (file)
@@ -92,14 +92,13 @@ iptv_udp_read ( iptv_mux_t *im )
   return res;
 }
 
-static ssize_t
-iptv_rtp_read ( iptv_mux_t *im )
+ssize_t
+iptv_rtp_read ( iptv_mux_t *im, udp_multirecv_t *um )
 {
   ssize_t len, hlen;
   uint8_t *rtp;
   int i, n;
   struct iovec *iovec;
-  udp_multirecv_t *um = im->im_data;
   ssize_t res = 0;
 
   n = udp_multirecv_read(um, im->mm_iptv_fd, IPTV_PKTS, &iovec);
@@ -145,6 +144,14 @@ iptv_rtp_read ( iptv_mux_t *im )
   return res;
 }
 
+static ssize_t
+iptv_udp_rtp_read ( iptv_mux_t *im )
+{
+  udp_multirecv_t *um = im->im_data;
+
+  return iptv_rtp_read(im, um);
+}
+
 /*
  * Initialise UDP handler
  */
@@ -163,7 +170,7 @@ iptv_udp_init ( void )
       .scheme = "rtp",
       .start  = iptv_udp_start,
       .stop   = iptv_udp_stop,
-      .read   = iptv_rtp_read,
+      .read   = iptv_udp_rtp_read,
     }
   };
   iptv_handler_register(ih, 2);