Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
IPTV: add rtsp:// and rtsps:// support
  • Loading branch information
perexg committed May 1, 2015
1 parent 4d7d61e commit 1c10cd6
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 6 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/http.c
Expand Up @@ -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 },
Expand Down
1 change: 1 addition & 0 deletions src/http.h
Expand Up @@ -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,
Expand Down
24 changes: 24 additions & 0 deletions src/input/mpegts/iptv/iptv.c
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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));
Expand Down
11 changes: 10 additions & 1 deletion src/input/mpegts/iptv/iptv_http.c
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
7 changes: 6 additions & 1 deletion src/input/mpegts/iptv/iptv_private.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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__ */

Expand Down
221 changes: 221 additions & 0 deletions src/input/mpegts/iptv/iptv_rtsp.c
@@ -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);
}
15 changes: 11 additions & 4 deletions src/input/mpegts/iptv/iptv_udp.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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
*/
Expand All @@ -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);
Expand Down

0 comments on commit 1c10cd6

Please sign in to comment.