IPTV: add rtsp:// and rtsps:// support
This commit is contained in:
parent
4d7d61e39a
commit
1c10cd6fe9
8 changed files with 275 additions and 6 deletions
1
Makefile
1
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
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
||||
|
|
221
src/input/mpegts/iptv/iptv_rtsp.c
Normal file
221
src/input/mpegts/iptv/iptv_rtsp.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue