SAT>IP server: initial RTSP code
This commit is contained in:
parent
1c3f608194
commit
fd1bc1c5f7
6 changed files with 930 additions and 40 deletions
3
Makefile
3
Makefile
|
@ -161,7 +161,8 @@ SRCS-${CONFIG_UPNP} += \
|
|||
|
||||
# SATIP Server
|
||||
SRCS-${CONFIG_SATIP_SERVER} += \
|
||||
src/satip/server.c
|
||||
src/satip/server.c \
|
||||
src/satip/rtsp.c
|
||||
|
||||
SRCS += \
|
||||
src/api.c \
|
||||
|
|
105
src/http.c
105
src/http.c
|
@ -61,8 +61,6 @@ static struct strtab HTTP_versiontab[] = {
|
|||
{ "RTSP/1.0", RTSP_VERSION_1_0 },
|
||||
};
|
||||
|
||||
static void http_parse_get_args(http_connection_t *hc, char *args);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -185,13 +183,16 @@ http_rc2str(int code)
|
|||
switch(code) {
|
||||
case HTTP_STATUS_OK: return "OK";
|
||||
case HTTP_STATUS_PARTIAL_CONTENT: return "Partial Content";
|
||||
case HTTP_STATUS_NOT_FOUND: return "Not found";
|
||||
case HTTP_STATUS_UNAUTHORIZED: return "Unauthorized";
|
||||
case HTTP_STATUS_BAD_REQUEST: return "Bad request";
|
||||
case HTTP_STATUS_FOUND: return "Found";
|
||||
case HTTP_STATUS_HTTP_VERSION: return "HTTP Version Not Supported";
|
||||
case HTTP_STATUS_BAD_REQUEST: return "Bad Request";
|
||||
case HTTP_STATUS_UNAUTHORIZED: return "Unauthorized";
|
||||
case HTTP_STATUS_NOT_FOUND: return "Not Found";
|
||||
case HTTP_STATUS_UNSUPPORTED: return "Unsupported Media Type";
|
||||
case HTTP_STATUS_BANDWIDTH: return "Not Enough Bandwidth";
|
||||
case HTTP_STATUS_BAD_SESSION: return "Session Not Found";
|
||||
case HTTP_STATUS_HTTP_VERSION: return "HTTP/RTSP Version Not Supported";
|
||||
default:
|
||||
return "Unknown returncode";
|
||||
return "Unknown Code";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -213,10 +214,12 @@ http_send_header(http_connection_t *hc, int rc, const char *content,
|
|||
int64_t contentlen,
|
||||
const char *encoding, const char *location,
|
||||
int maxage, const char *range,
|
||||
const char *disposition)
|
||||
const char *disposition,
|
||||
http_arg_list_t *args)
|
||||
{
|
||||
struct tm tm0, *tm;
|
||||
htsbuf_queue_t hdrs;
|
||||
http_arg_t *ra;
|
||||
time_t t;
|
||||
|
||||
htsbuf_queue_init(&hdrs, 0);
|
||||
|
@ -229,7 +232,8 @@ http_send_header(http_connection_t *hc, int rc, const char *content,
|
|||
htsbuf_qprintf(&hdrs, "Server: HTS/tvheadend\r\n");
|
||||
|
||||
if(maxage == 0) {
|
||||
htsbuf_qprintf(&hdrs, "Cache-Control: no-cache\r\n");
|
||||
if (hc->hc_version != RTSP_VERSION_1_0)
|
||||
htsbuf_qprintf(&hdrs, "Cache-Control: no-cache\r\n");
|
||||
} else {
|
||||
time(&t);
|
||||
|
||||
|
@ -289,6 +293,13 @@ http_send_header(http_connection_t *hc, int rc, const char *content,
|
|||
if (++hc->hc_cseq == 0)
|
||||
hc->hc_cseq = 1;
|
||||
}
|
||||
if(hc->hc_session)
|
||||
htsbuf_qprintf(&hdrs, "Session: %s\r\n", hc->hc_session);
|
||||
|
||||
if (args) {
|
||||
TAILQ_FOREACH(ra, args, link)
|
||||
htsbuf_qprintf(&hdrs, "%s: %s\r\n", ra->key, ra->val);
|
||||
}
|
||||
|
||||
htsbuf_qprintf(&hdrs, "\r\n");
|
||||
|
||||
|
@ -305,7 +316,7 @@ http_send_reply(http_connection_t *hc, int rc, const char *content,
|
|||
const char *encoding, const char *location, int maxage)
|
||||
{
|
||||
http_send_header(hc, rc, content, hc->hc_reply.hq_size,
|
||||
encoding, location, maxage, 0, NULL);
|
||||
encoding, location, maxage, 0, NULL, NULL);
|
||||
|
||||
if(hc->hc_no_output)
|
||||
return;
|
||||
|
@ -328,25 +339,29 @@ http_error(http_connection_t *hc, int error)
|
|||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50);
|
||||
|
||||
if (error != HTTP_STATUS_FOUND && error != HTTP_STATUS_MOVED)
|
||||
tvhlog(error < 400 ? LOG_INFO : LOG_ERR, "HTTP", "%s: %s -- %d",
|
||||
tvhlog(error < 400 ? LOG_INFO : LOG_ERR, "http", "%s: %s -- %d",
|
||||
addrstr, hc->hc_url, error);
|
||||
|
||||
htsbuf_queue_flush(&hc->hc_reply);
|
||||
if (hc->hc_version != RTSP_VERSION_1_0) {
|
||||
htsbuf_queue_flush(&hc->hc_reply);
|
||||
|
||||
htsbuf_qprintf(&hc->hc_reply,
|
||||
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
|
||||
"<HTML><HEAD>\r\n"
|
||||
"<TITLE>%d %s</TITLE>\r\n"
|
||||
"</HEAD><BODY>\r\n"
|
||||
"<H1>%d %s</H1>\r\n",
|
||||
error, errtxt, error, errtxt);
|
||||
htsbuf_qprintf(&hc->hc_reply,
|
||||
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
|
||||
"<HTML><HEAD>\r\n"
|
||||
"<TITLE>%d %s</TITLE>\r\n"
|
||||
"</HEAD><BODY>\r\n"
|
||||
"<H1>%d %s</H1>\r\n",
|
||||
error, errtxt, error, errtxt);
|
||||
|
||||
if (error == HTTP_STATUS_UNAUTHORIZED)
|
||||
htsbuf_qprintf(&hc->hc_reply, "<P><A HREF=\"/\">Default Login</A></P>");
|
||||
if (error == HTTP_STATUS_UNAUTHORIZED)
|
||||
htsbuf_qprintf(&hc->hc_reply, "<P><A HREF=\"/\">Default Login</A></P>");
|
||||
|
||||
htsbuf_qprintf(&hc->hc_reply, "</BODY></HTML>\r\n");
|
||||
htsbuf_qprintf(&hc->hc_reply, "</BODY></HTML>\r\n");
|
||||
|
||||
http_send_reply(hc, error, "text/html", NULL, NULL, 0);
|
||||
http_send_reply(hc, error, "text/html", NULL, NULL, 0);
|
||||
} else {
|
||||
http_send_reply(hc, error, NULL, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -430,7 +445,7 @@ http_access_verify_ticket(http_connection_t *hc)
|
|||
return;
|
||||
char addrstr[50];
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50);
|
||||
tvhlog(LOG_INFO, "HTTP", "%s: using ticket %s for %s",
|
||||
tvhlog(LOG_INFO, "http", "%s: using ticket %s for %s",
|
||||
addrstr, ticket_id, hc->hc_url);
|
||||
}
|
||||
|
||||
|
@ -666,6 +681,20 @@ process_request(http_connection_t *hc, htsbuf_queue_t *spill)
|
|||
switch(hc->hc_version) {
|
||||
case RTSP_VERSION_1_0:
|
||||
hc->hc_keep_alive = 1;
|
||||
/* Extract CSeq */
|
||||
if((v = http_arg_get(&hc->hc_args, "CSeq")) != NULL)
|
||||
hc->hc_cseq = strtoll(v, NULL, 10);
|
||||
else
|
||||
hc->hc_cseq = 0;
|
||||
free(hc->hc_session);
|
||||
if ((v = http_arg_get(&hc->hc_args, "Session")) != NULL)
|
||||
hc->hc_session = strdup(v);
|
||||
else
|
||||
hc->hc_session = NULL;
|
||||
if(hc->hc_cseq == 0) {
|
||||
http_error(hc, HTTP_STATUS_BAD_REQUEST);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case HTTP_VERSION_1_0:
|
||||
|
@ -707,7 +736,7 @@ process_request(http_connection_t *hc, htsbuf_queue_t *spill)
|
|||
if (hc->hc_cseq)
|
||||
rval = hc->hc_process(hc, spill);
|
||||
else
|
||||
rval = -1;
|
||||
http_error(hc, HTTP_STATUS_HTTP_VERSION);
|
||||
break;
|
||||
|
||||
case HTTP_VERSION_1_0:
|
||||
|
@ -719,6 +748,7 @@ process_request(http_connection_t *hc, htsbuf_queue_t *spill)
|
|||
break;
|
||||
}
|
||||
free(hc->hc_representative);
|
||||
free(hc->hc_session);
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
@ -753,6 +783,25 @@ http_arg_get(struct http_arg_list *list, const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an argument associated with a connection and remove it
|
||||
*/
|
||||
char *
|
||||
http_arg_get_remove(struct http_arg_list *list, const char *name)
|
||||
{
|
||||
static char __thread buf[128];
|
||||
http_arg_t *ra;
|
||||
TAILQ_FOREACH(ra, list, link)
|
||||
if(!strcasecmp(ra->key, name)) {
|
||||
TAILQ_REMOVE(list, ra, link);
|
||||
strncpy(buf, ra->val, sizeof(buf)-1);
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
buf[0] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set an argument associated with a connection
|
||||
|
@ -887,7 +936,7 @@ http_deescape(char *s)
|
|||
/**
|
||||
* Parse arguments of a HTTP GET url, not perfect, but works for us
|
||||
*/
|
||||
static void
|
||||
void
|
||||
http_parse_get_args(http_connection_t *hc, char *args)
|
||||
{
|
||||
char *k, *v;
|
||||
|
@ -1011,7 +1060,7 @@ http_serve(int fd, void **opaque, struct sockaddr_storage *peer,
|
|||
{
|
||||
http_connection_t hc;
|
||||
|
||||
// Note: global_lock held on entry */
|
||||
/* Note: global_lock held on entry */
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
memset(&hc, 0, sizeof(http_connection_t));
|
||||
*opaque = &hc;
|
||||
|
@ -1031,7 +1080,7 @@ http_serve(int fd, void **opaque, struct sockaddr_storage *peer,
|
|||
*opaque = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
http_cancel( void *opaque )
|
||||
{
|
||||
http_connection_t *hc = opaque;
|
||||
|
|
13
src/http.h
13
src/http.h
|
@ -22,7 +22,7 @@
|
|||
#include "htsbuf.h"
|
||||
#include "url.h"
|
||||
#include "tvhpoll.h"
|
||||
#include "access.h"
|
||||
#include "access.h"
|
||||
|
||||
struct channel;
|
||||
struct http_path;
|
||||
|
@ -74,12 +74,15 @@ typedef struct http_arg {
|
|||
#define HTTP_STATUS_UNSUPPORTED 415
|
||||
#define HTTP_STATUS_BAD_RANGE 417
|
||||
#define HTTP_STATUS_EXPECTATION 418
|
||||
#define HTTP_STATUS_BANDWIDTH 453
|
||||
#define HTTP_STATUS_BAD_SESSION 454
|
||||
#define HTTP_STATUS_INTERNAL 500
|
||||
#define HTTP_STATUS_NOT_IMPLEMENTED 501
|
||||
#define HTTP_STATUS_BAD_GATEWAY 502
|
||||
#define HTTP_STATUS_SERVICE 503
|
||||
#define HTTP_STATUS_GATEWAY_TIMEOUT 504
|
||||
#define HTTP_STATUS_HTTP_VERSION 505
|
||||
#define HTTP_STATUS_OP_NOT_SUPPRT 551
|
||||
|
||||
typedef enum http_state {
|
||||
HTTP_CON_WAIT_REQUEST,
|
||||
|
@ -145,6 +148,7 @@ typedef struct http_connection {
|
|||
int hc_logout_cookie;
|
||||
int hc_shutdown;
|
||||
uint64_t hc_cseq;
|
||||
char *hc_session;
|
||||
|
||||
/* Support for HTTP POST */
|
||||
|
||||
|
@ -168,6 +172,7 @@ static inline void http_arg_init(struct http_arg_list *list)
|
|||
void http_arg_flush(struct http_arg_list *list);
|
||||
|
||||
char *http_arg_get(struct http_arg_list *list, const char *name);
|
||||
char *http_arg_get_remove(struct http_arg_list *list, const char *name);
|
||||
|
||||
void http_arg_set(struct http_arg_list *list, const char *key, const char *val);
|
||||
|
||||
|
@ -185,10 +190,12 @@ void http_redirect(http_connection_t *hc, const char *location,
|
|||
void http_send_header(http_connection_t *hc, int rc, const char *content,
|
||||
int64_t contentlen, const char *encoding,
|
||||
const char *location, int maxage, const char *range,
|
||||
const char *disposition);
|
||||
const char *disposition, http_arg_list_t *args);
|
||||
|
||||
void http_serve_requests(http_connection_t *hc);
|
||||
|
||||
void http_cancel(void *opaque);
|
||||
|
||||
typedef int (http_callback_t)(http_connection_t *hc,
|
||||
const char *remain, void *opaque);
|
||||
|
||||
|
@ -223,6 +230,8 @@ int http_access_verify_channel(http_connection_t *hc, int mask,
|
|||
|
||||
void http_deescape(char *s);
|
||||
|
||||
void http_parse_get_args(http_connection_t *hc, char *args);
|
||||
|
||||
/*
|
||||
* HTTP/RTSP Client
|
||||
*/
|
||||
|
|
821
src/satip/rtsp.c
Normal file
821
src/satip/rtsp.c
Normal file
|
@ -0,0 +1,821 @@
|
|||
/*
|
||||
* Tvheadend - SAT-IP server - RTSP part
|
||||
*
|
||||
* 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 "input.h"
|
||||
#include "htsbuf.h"
|
||||
#include "htsmsg_xml.h"
|
||||
#include "upnp.h"
|
||||
#include "http.h"
|
||||
#include "settings.h"
|
||||
#include "config.h"
|
||||
#include "satip/server.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#if defined(PLATFORM_FREEBSD) || ENABLE_ANDROID
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#define RTSP_TIMEOUT 30
|
||||
#define RTSP_PIDS 128
|
||||
|
||||
typedef struct session {
|
||||
TAILQ_ENTRY(session) link;
|
||||
int delsys;
|
||||
int stream;
|
||||
int frontend;
|
||||
char session[9];
|
||||
dvb_mux_conf_t dmc;
|
||||
int16_t pids[RTSP_PIDS];
|
||||
gtimer_t timer;
|
||||
} session_t;
|
||||
|
||||
static uint32_t session_number;
|
||||
static char *rtsp_ip = NULL;
|
||||
static int rtsp_port = -1;
|
||||
static void *rtsp_server = NULL;
|
||||
static TAILQ_HEAD(,session) rtsp_sessions;
|
||||
static pthread_mutex_t rtsp_lock;
|
||||
|
||||
static void rtsp_close_session(session_t *rs);
|
||||
static void rtsp_free_session(session_t *rs);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_delsys(int fe)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (fe < 1)
|
||||
return DVB_SYS_NONE;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
i = config_get_int("satip_dvbt", 0);
|
||||
if (fe <= i)
|
||||
return DVB_SYS_DVBT;
|
||||
fe -= i;
|
||||
i = config_get_int("satip_dvbs", 0);
|
||||
if (fe <= i)
|
||||
return DVB_SYS_DVBS;
|
||||
fe -= i;
|
||||
i = config_get_int("satip_dvbc", 0);
|
||||
if (fe <= i)
|
||||
return DVB_SYS_DVBC_ANNEX_A;
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return DVB_SYS_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static struct session *
|
||||
rtsp_new_session(int delsys)
|
||||
{
|
||||
struct session *rs = calloc(1, sizeof(*rs));
|
||||
if (rs == NULL)
|
||||
return NULL;
|
||||
rs->delsys = delsys;
|
||||
snprintf(rs->session, sizeof(rs->session), "%08X", session_number);
|
||||
session_number += 9876;
|
||||
return rs;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static struct session *
|
||||
rtsp_find_session(http_connection_t *hc)
|
||||
{
|
||||
struct session *rs;
|
||||
|
||||
if (hc->hc_session == NULL)
|
||||
return NULL;
|
||||
TAILQ_FOREACH(rs, &rtsp_sessions, link)
|
||||
if (!strcmp(rs->session, hc->hc_session))
|
||||
return rs;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
rtsp_session_timer_cb(void *aux)
|
||||
{
|
||||
session_t *rs = aux;
|
||||
|
||||
rtsp_close_session(rs);
|
||||
rtsp_free_session(rs);
|
||||
tvhwarn("satips", "session %s closed (timeout)", rs->session);
|
||||
}
|
||||
|
||||
static inline void
|
||||
rtsp_rearm_session_timer(session_t *rs)
|
||||
{
|
||||
gtimer_arm(&rs->timer, rtsp_session_timer_cb, rs, RTSP_TIMEOUT);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static char *
|
||||
rtsp_check_urlbase(char *u)
|
||||
{
|
||||
char *p;
|
||||
|
||||
/* expect string: rtsp://<myip>[:<myport>]/ */
|
||||
if (u[0] == '\0' || strncmp(u, "rtsp://", 7))
|
||||
return NULL;
|
||||
u += 7;
|
||||
p = strchr(u, '/');
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
*p = '\0';
|
||||
if ((p = strchr(u, ':')) != NULL) {
|
||||
*p = '\0';
|
||||
if (atoi(p + 1) != rtsp_port)
|
||||
return NULL;
|
||||
} else {
|
||||
if (rtsp_port != 554)
|
||||
return NULL;
|
||||
}
|
||||
if (strcmp(u, rtsp_ip))
|
||||
return NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_parse_args(http_connection_t *hc, char *u)
|
||||
{
|
||||
char *s;
|
||||
int stream = 0;
|
||||
|
||||
if (strncmp(u, "stream=", 7) == 0) {
|
||||
u += 7;
|
||||
for (s = 0; isdigit(*s); s++);
|
||||
if (*s != '?')
|
||||
return -1;
|
||||
*s = '\0';
|
||||
stream = atoi(u);
|
||||
u = s + 1;
|
||||
} else {
|
||||
if (*u != '?')
|
||||
return -1;
|
||||
}
|
||||
http_parse_get_args(hc, u);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_addpids(session_t *rs, int16_t *pids)
|
||||
{
|
||||
int pid, i, j;
|
||||
|
||||
while ((pid = *pids++) >= 0) {
|
||||
for (i = 0; i < RTSP_PIDS; i++) {
|
||||
if (rs->pids[i] > pid) {
|
||||
if (rs->pids[RTSP_PIDS-1] >= 0)
|
||||
return -1;
|
||||
for (j = RTSP_PIDS-1; j != i; j--)
|
||||
rs->pids[j] = rs->pids[j-1];
|
||||
rs->pids[i] = pid;
|
||||
break;
|
||||
} else if (rs->pids[i] == pid)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_delpids(session_t *rs, int16_t *pids)
|
||||
{
|
||||
int pid, i, j;
|
||||
|
||||
while ((pid = *pids++) >= 0) {
|
||||
for (i = 0; i < RTSP_PIDS; i++) {
|
||||
if (rs->pids[i] > pid)
|
||||
break;
|
||||
else if (rs->pids[i] == pid) {
|
||||
for (j = i; rs->pids[j] >= 0 && j + 1 < RTSP_PIDS; j++)
|
||||
rs->pids[j] = rs->pids[j+1];
|
||||
rs->pids[RTSP_PIDS-1] = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_start(session_t *rs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_process_options(http_connection_t *hc)
|
||||
{
|
||||
http_arg_list_t args;
|
||||
char *u = tvh_strdupa(hc->hc_url);
|
||||
session_t *rs;
|
||||
|
||||
if ((u = rtsp_check_urlbase(u)) == NULL)
|
||||
goto error;
|
||||
if (*u)
|
||||
goto error;
|
||||
|
||||
pthread_mutex_lock(&rtsp_lock);
|
||||
rs = rtsp_find_session(hc);
|
||||
if (rs)
|
||||
rtsp_rearm_session_timer(rs);
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
http_arg_init(&args);
|
||||
http_arg_set(&args, "Public", "OPTIONS,DESCRIBE,SETUP,PLAY,TEARDOWN");
|
||||
http_send_header(hc, HTTP_STATUS_OK, NULL, 0, NULL, NULL, 0, NULL, NULL, &args);
|
||||
http_arg_flush(&args);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
http_error(hc, HTTP_STATUS_BAD_REQUEST);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static inline int
|
||||
msys_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
static struct strtab tab[] = {
|
||||
{ "dvbs", DVB_SYS_DVBS },
|
||||
{ "dvbs2", DVB_SYS_DVBS2 },
|
||||
{ "dvbt", DVB_SYS_DVBT },
|
||||
{ "dvbt2", DVB_SYS_DVBT2 },
|
||||
{ "dvbc", DVB_SYS_DVBC_ANNEX_A },
|
||||
{ "dvbc2", DVB_SYS_DVBC_ANNEX_C },
|
||||
};
|
||||
const char *s = http_arg_get_remove(&hc->hc_req_args, "msys");
|
||||
return s[0] ? str2val(s, tab) : DVB_SYS_NONE;
|
||||
}
|
||||
|
||||
static inline int
|
||||
pol_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
static struct strtab tab[] = {
|
||||
{ "h", DVB_POLARISATION_HORIZONTAL },
|
||||
{ "v", DVB_POLARISATION_VERTICAL },
|
||||
{ "l", DVB_POLARISATION_CIRCULAR_LEFT },
|
||||
{ "r", DVB_POLARISATION_CIRCULAR_RIGHT },
|
||||
};
|
||||
const char *s = http_arg_get_remove(&hc->hc_req_args, "pol");
|
||||
return s[0] ? str2val(s, tab) : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
fec_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
switch (atoi(http_arg_get_remove(&hc->hc_req_args, "fec"))) {
|
||||
case 12: return DVB_FEC_1_2;
|
||||
case 13: return DVB_FEC_1_3;
|
||||
case 15: return DVB_FEC_1_5;
|
||||
case 23: return DVB_FEC_2_3;
|
||||
case 25: return DVB_FEC_2_5;
|
||||
case 29: return DVB_FEC_2_9;
|
||||
case 34: return DVB_FEC_3_4;
|
||||
case 35: return DVB_FEC_3_5;
|
||||
case 45: return DVB_FEC_4_5;
|
||||
case 415: return DVB_FEC_4_15;
|
||||
case 56: return DVB_FEC_5_6;
|
||||
case 59: return DVB_FEC_5_9;
|
||||
case 67: return DVB_FEC_6_7;
|
||||
case 78: return DVB_FEC_7_8;
|
||||
case 79: return DVB_FEC_7_9;
|
||||
case 715: return DVB_FEC_7_15;
|
||||
case 89: return DVB_FEC_8_9;
|
||||
case 815: return DVB_FEC_8_15;
|
||||
case 910: return DVB_FEC_9_10;
|
||||
case 920: return DVB_FEC_9_20;
|
||||
default: return DVB_FEC_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bw_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
int bw = atof(http_arg_get_remove(&hc->hc_req_args, "bw")) * 1000;
|
||||
switch (bw) {
|
||||
case DVB_BANDWIDTH_1_712_MHZ:
|
||||
case DVB_BANDWIDTH_5_MHZ:
|
||||
case DVB_BANDWIDTH_6_MHZ:
|
||||
case DVB_BANDWIDTH_7_MHZ:
|
||||
case DVB_BANDWIDTH_8_MHZ:
|
||||
case DVB_BANDWIDTH_10_MHZ:
|
||||
return bw;
|
||||
default:
|
||||
return DVB_BANDWIDTH_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rolloff_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
int ro = atof(http_arg_get_remove(&hc->hc_req_args, "ro")) * 1000;
|
||||
switch (ro) {
|
||||
case 0:
|
||||
return DVB_ROLLOFF_35;
|
||||
case DVB_ROLLOFF_20:
|
||||
case DVB_ROLLOFF_25:
|
||||
case DVB_ROLLOFF_35:
|
||||
return ro;
|
||||
default:
|
||||
return DVB_ROLLOFF_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pilot_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
const char *s = http_arg_get_remove(&hc->hc_req_args, "plts");
|
||||
if (strcmp(s, "on") == 0)
|
||||
return DVB_PILOT_ON;
|
||||
if (strcmp(s, "off") == 0)
|
||||
return DVB_PILOT_OFF;
|
||||
if (s[0] == '\0')
|
||||
return DVB_PILOT_AUTO;
|
||||
return DVB_ROLLOFF_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
tmode_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
static struct strtab tab[] = {
|
||||
{ "1k", DVB_TRANSMISSION_MODE_1K },
|
||||
{ "2k", DVB_TRANSMISSION_MODE_2K },
|
||||
{ "4k", DVB_TRANSMISSION_MODE_4K },
|
||||
{ "8k", DVB_TRANSMISSION_MODE_8K },
|
||||
{ "16k", DVB_TRANSMISSION_MODE_16K },
|
||||
{ "32k", DVB_TRANSMISSION_MODE_32K },
|
||||
};
|
||||
const char *s = http_arg_get_remove(&hc->hc_req_args, "tmode");
|
||||
if (s[0]) {
|
||||
int v = str2val(s, tab);
|
||||
return v >= 0 ? v : DVB_TRANSMISSION_MODE_NONE;
|
||||
}
|
||||
return DVB_TRANSMISSION_MODE_AUTO;
|
||||
}
|
||||
|
||||
static int
|
||||
mtype_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
static struct strtab tab[] = {
|
||||
{ "qpsk", DVB_MOD_QPSK },
|
||||
{ "8psk", DVB_MOD_PSK_8 },
|
||||
{ "16qam", DVB_MOD_QAM_16 },
|
||||
{ "32qam", DVB_MOD_QAM_32 },
|
||||
{ "64qam", DVB_MOD_QAM_64 },
|
||||
{ "128qam", DVB_MOD_QAM_128 },
|
||||
{ "256qam", DVB_MOD_QAM_256 },
|
||||
};
|
||||
const char *s = http_arg_get_remove(&hc->hc_req_args, "mtype");
|
||||
if (s[0]) {
|
||||
int v = str2val(s, tab);
|
||||
return v >= 0 ? v : DVB_MOD_NONE;
|
||||
}
|
||||
return DVB_MOD_AUTO;
|
||||
}
|
||||
|
||||
static int
|
||||
gi_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
switch (atoi(http_arg_get_remove(&hc->hc_req_args, "gi"))) {
|
||||
case 0: return DVB_GUARD_INTERVAL_AUTO;
|
||||
case 14: return DVB_GUARD_INTERVAL_1_4;
|
||||
case 18: return DVB_GUARD_INTERVAL_1_8;
|
||||
case 116: return DVB_GUARD_INTERVAL_1_16;
|
||||
case 132: return DVB_GUARD_INTERVAL_1_32;
|
||||
case 1128: return DVB_GUARD_INTERVAL_1_128;
|
||||
case 19128: return DVB_GUARD_INTERVAL_19_128;
|
||||
case 19256: return DVB_GUARD_INTERVAL_19_256;
|
||||
default: return DVB_GUARD_INTERVAL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
parse_pids(char *p, int16_t *pids)
|
||||
{
|
||||
char *x, *saveptr;
|
||||
int i = 0;
|
||||
|
||||
if (p == '\0') {
|
||||
pids[0] = -1;
|
||||
return 0;
|
||||
}
|
||||
x = strtok_r(p, ",", &saveptr);
|
||||
while (1) {
|
||||
if (x == NULL)
|
||||
break;
|
||||
if (i >= RTSP_PIDS)
|
||||
return -1;
|
||||
pids[i] = atoi(x);
|
||||
if (pids[i] < 0 || pids[i] > 8191)
|
||||
return -1;
|
||||
x = strtok_r(NULL, ",", &saveptr);
|
||||
}
|
||||
if (i == 0)
|
||||
return -1;
|
||||
pids[i] = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_process_play(http_connection_t *hc, int setup)
|
||||
{
|
||||
session_t *rs;
|
||||
int errcode = HTTP_STATUS_BAD_REQUEST;
|
||||
int stream, delsys = DVB_SYS_NONE, msys, fe, src, freq, pol, sr;
|
||||
int fec, ro, plts, bw, tmode, mtype, gi, plp, t2id, sm, c2tft, ds, specinv;
|
||||
char *u, *s;
|
||||
char *pids, *addpids, *delpids;
|
||||
int16_t _pids[RTSP_PIDS+1], _addpids[RTSP_PIDS+1], _delpids[RTSP_PIDS+1];
|
||||
dvb_mux_conf_t *dmc;
|
||||
|
||||
u = tvh_strdupa(hc->hc_url);
|
||||
if ((u = rtsp_check_urlbase(u)) == NULL ||
|
||||
(stream = rtsp_parse_args(hc, u)) < 0)
|
||||
goto error2;
|
||||
|
||||
fe = atoi(http_arg_get_remove(&hc->hc_req_args, "fe"));
|
||||
addpids = http_arg_get_remove(&hc->hc_req_args, "addpids");
|
||||
if (parse_pids(addpids, _addpids)) goto error2;
|
||||
delpids = http_arg_get_remove(&hc->hc_req_args, "delpids");
|
||||
if (parse_pids(delpids, _delpids)) goto error2;
|
||||
msys = msys_to_tvh(hc);
|
||||
if (msys < 0)
|
||||
goto error2;
|
||||
|
||||
if (addpids || delpids) {
|
||||
if (setup)
|
||||
goto error2;
|
||||
if (!stream)
|
||||
goto error2;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&rtsp_lock);
|
||||
|
||||
rs = rtsp_find_session(hc);
|
||||
|
||||
if (fe > 0) {
|
||||
delsys = rtsp_delsys(fe);
|
||||
if (delsys == DVB_SYS_NONE)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (setup) {
|
||||
if (msys == DVB_SYS_NONE)
|
||||
goto error;
|
||||
if (!rs)
|
||||
rs = rtsp_new_session(msys);
|
||||
else
|
||||
rtsp_close_session(rs);
|
||||
} else {
|
||||
if (!rs || stream != rs->stream) {
|
||||
if (rs)
|
||||
errcode = HTTP_STATUS_NOT_FOUND;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!setup && rs->frontend == fe && TAILQ_EMPTY(&hc->hc_req_args))
|
||||
goto play;
|
||||
|
||||
dmc = &rs->dmc;
|
||||
dvb_mux_conf_init(dmc, msys);
|
||||
rs->frontend = fe;
|
||||
|
||||
pids = http_arg_get_remove(&hc->hc_req_args, "pids");
|
||||
if (parse_pids(pids, _pids)) goto error;
|
||||
freq = atof(http_arg_get_remove(&hc->hc_req_args, "freq")) * 1000;
|
||||
if (freq < 1000) goto error;
|
||||
mtype = mtype_to_tvh(hc);
|
||||
if (mtype == DVB_MOD_NONE) goto error;
|
||||
|
||||
if (msys == DVB_SYS_DVBS || msys == DVB_SYS_DVBS2) {
|
||||
|
||||
src = atoi(http_arg_get_remove(&hc->hc_req_args, "src"));
|
||||
if (src < 1) goto error;
|
||||
pol = pol_to_tvh(hc);
|
||||
if (pol < 0) goto error;
|
||||
sr = atof(http_arg_get_remove(&hc->hc_req_args, "sr")) * 1000;
|
||||
if (sr < 1000) goto error;
|
||||
fec = fec_to_tvh(hc);
|
||||
if (fec == DVB_FEC_NONE) goto error;
|
||||
ro = rolloff_to_tvh(hc);
|
||||
if (ro == DVB_ROLLOFF_NONE ||
|
||||
(ro != DVB_ROLLOFF_35 && msys == DVB_SYS_DVBS)) goto error;
|
||||
plts = pilot_to_tvh(hc);
|
||||
if (plts == DVB_PILOT_NONE) goto error;
|
||||
|
||||
if (!TAILQ_EMPTY(&hc->hc_req_args))
|
||||
goto error;
|
||||
|
||||
dmc->dmc_fe_rolloff = ro;
|
||||
dmc->dmc_fe_pilot = plts;
|
||||
dmc->u.dmc_fe_qpsk.polarisation = pol;
|
||||
dmc->u.dmc_fe_qpsk.symbol_rate = sr;
|
||||
dmc->u.dmc_fe_qpsk.fec_inner = fec;
|
||||
|
||||
} else if (msys == DVB_SYS_DVBT || msys == DVB_SYS_DVBT2) {
|
||||
|
||||
bw = bw_to_tvh(hc);
|
||||
if (bw == DVB_BANDWIDTH_NONE) goto error;
|
||||
tmode = tmode_to_tvh(hc);
|
||||
if (tmode == DVB_TRANSMISSION_MODE_NONE) goto error;
|
||||
gi = gi_to_tvh(hc);
|
||||
if (gi == DVB_GUARD_INTERVAL_NONE) goto error;
|
||||
fec = fec_to_tvh(hc);
|
||||
if (fec == DVB_FEC_NONE) goto error;
|
||||
plp = atoi(http_arg_get_remove(&hc->hc_req_args, "plp"));
|
||||
if (plp < 0 || plp > 255) goto error;
|
||||
s = http_arg_get_remove(&hc->hc_req_args, "t2id");
|
||||
t2id = s[0] ? atoi(s) : DVB_NO_STREAM_ID_FILTER;
|
||||
if (t2id < 0 || t2id > 65535) goto error;
|
||||
sm = atoi(http_arg_get_remove(&hc->hc_req_args, "sm"));
|
||||
if (sm < 0 || sm > 1) goto error;
|
||||
|
||||
if (!TAILQ_EMPTY(&hc->hc_req_args))
|
||||
goto error;
|
||||
|
||||
dmc->u.dmc_fe_ofdm.bandwidth = bw;
|
||||
dmc->u.dmc_fe_ofdm.code_rate_HP = fec;
|
||||
dmc->u.dmc_fe_ofdm.code_rate_LP = DVB_FEC_NONE;
|
||||
dmc->u.dmc_fe_ofdm.transmission_mode = tmode;
|
||||
dmc->u.dmc_fe_ofdm.guard_interval = gi;
|
||||
dmc->u.dmc_fe_ofdm.hierarchy_information = DVB_HIERARCHY_AUTO;
|
||||
dmc->dmc_fe_stream_id = plp;
|
||||
dmc->dmc_fe_pls_code = t2id;
|
||||
dmc->dmc_fe_pls_mode = sm; /* check */
|
||||
|
||||
} else if (msys == DVB_SYS_DVBC_ANNEX_A || msys == DVB_SYS_DVBC_ANNEX_C) {
|
||||
|
||||
c2tft = atoi(http_arg_get_remove(&hc->hc_req_args, "c2tft"));
|
||||
if (c2tft < 0 || c2tft > 2) goto error;
|
||||
bw = bw_to_tvh(hc);
|
||||
if (bw == DVB_BANDWIDTH_NONE) goto error;
|
||||
sr = atof(http_arg_get_remove(&hc->hc_req_args, "sr")) * 1000;
|
||||
if (sr < 1000) goto error;
|
||||
ds = atoi(http_arg_get_remove(&hc->hc_req_args, "ds"));
|
||||
if (ds < 0 || ds > 255) goto error;
|
||||
plp = atoi(http_arg_get_remove(&hc->hc_req_args, "plp"));
|
||||
if (plp < 0 || plp > 255) goto error;
|
||||
specinv = atoi(http_arg_get_remove(&hc->hc_req_args, "specinv"));
|
||||
if (specinv < 0 || specinv > 1) goto error;
|
||||
|
||||
if (!TAILQ_EMPTY(&hc->hc_req_args))
|
||||
goto error;
|
||||
|
||||
dmc->u.dmc_fe_qpsk.symbol_rate = sr;
|
||||
dmc->u.dmc_fe_qpsk.fec_inner = DVB_FEC_NONE;
|
||||
dmc->dmc_fe_inversion = specinv;
|
||||
dmc->dmc_fe_stream_id = plp;
|
||||
dmc->dmc_fe_pls_code = ds; /* check */
|
||||
|
||||
} else {
|
||||
|
||||
goto error;
|
||||
|
||||
}
|
||||
|
||||
dmc->dmc_fe_freq = freq;
|
||||
dmc->dmc_fe_modulation = mtype;
|
||||
|
||||
if (setup) {
|
||||
if (pids)
|
||||
rtsp_addpids(rs, _pids);
|
||||
goto end;
|
||||
}
|
||||
|
||||
play:
|
||||
if (delpids)
|
||||
rtsp_delpids(rs, _delpids);
|
||||
if (addpids)
|
||||
rtsp_addpids(rs, _addpids);
|
||||
if (rtsp_start(rs) < 0) {
|
||||
errcode = HTTP_STATUS_SERVICE;;
|
||||
goto error;
|
||||
}
|
||||
|
||||
end:
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
error2:
|
||||
http_error(hc, errcode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_process_teardown(http_connection_t *hc)
|
||||
{
|
||||
char *u = tvh_strdupa(hc->hc_url);
|
||||
struct session *rs = NULL;
|
||||
int stream;
|
||||
|
||||
if ((u = rtsp_check_urlbase(u)) == NULL ||
|
||||
(stream = rtsp_parse_args(hc, u)) < 0) {
|
||||
http_error(hc, HTTP_STATUS_BAD_REQUEST);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&rtsp_lock);
|
||||
rs = rtsp_find_session(hc);
|
||||
if (!rs || stream != rs->stream) {
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
http_error(hc, !rs ? HTTP_STATUS_BAD_SESSION : HTTP_STATUS_NOT_FOUND);
|
||||
} else {
|
||||
rtsp_close_session(rs);
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
rtsp_free_session(rs);
|
||||
http_send_header(hc, HTTP_STATUS_OK, NULL, 0, NULL, NULL, 0, NULL, NULL, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a RTSP request
|
||||
*/
|
||||
static int
|
||||
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_SETUP:
|
||||
case RTSP_CMD_PLAY:
|
||||
return rtsp_process_play(hc, hc->hc_cmd == RTSP_CMD_SETUP);
|
||||
case RTSP_CMD_TEARDOWN:
|
||||
return rtsp_process_teardown(hc);
|
||||
default:
|
||||
http_error(hc, HTTP_STATUS_BAD_REQUEST);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
rtsp_serve(int fd, void **opaque, struct sockaddr_storage *peer,
|
||||
struct sockaddr_storage *self)
|
||||
{
|
||||
http_connection_t hc;
|
||||
|
||||
memset(&hc, 0, sizeof(http_connection_t));
|
||||
*opaque = &hc;
|
||||
/* Note: global_lock held on entry */
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
hc.hc_fd = fd;
|
||||
hc.hc_peer = peer;
|
||||
hc.hc_self = self;
|
||||
hc.hc_process = rtsp_process_request;
|
||||
hc.hc_cseq = 1;
|
||||
|
||||
http_serve_requests(&hc);
|
||||
|
||||
close(fd);
|
||||
|
||||
/* Note: leave global_lock held for parent */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
*opaque = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
rtsp_close_session(session_t *rs)
|
||||
{
|
||||
gtimer_disarm(&rs->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
rtsp_free_session(session_t *rs)
|
||||
{
|
||||
gtimer_disarm(&rs->timer);
|
||||
TAILQ_REMOVE(&rtsp_sessions, rs, link);
|
||||
free(rs);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
rtsp_close_sessions(void)
|
||||
{
|
||||
session_t *rs;
|
||||
while ((rs = TAILQ_FIRST(&rtsp_sessions)) != NULL) {
|
||||
rtsp_close_session(rs);
|
||||
rtsp_free_session(rs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void satip_server_rtsp_init(const char *bindaddr, int port)
|
||||
{
|
||||
static tcp_server_ops_t ops = {
|
||||
.start = rtsp_serve,
|
||||
.stop = NULL,
|
||||
.cancel = http_cancel
|
||||
};
|
||||
int reg = 0;
|
||||
uint8_t rnd[4];
|
||||
if (!rtsp_server) {
|
||||
uuid_random(rnd, sizeof(rnd));
|
||||
session_number = *(uint32_t *)rnd;
|
||||
TAILQ_INIT(&rtsp_sessions);
|
||||
pthread_mutex_init(&rtsp_lock, NULL);
|
||||
}
|
||||
if (rtsp_port != port && rtsp_server) {
|
||||
pthread_mutex_lock(&rtsp_lock);
|
||||
rtsp_close_sessions();
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
tcp_server_delete(rtsp_server);
|
||||
reg = 1;
|
||||
}
|
||||
free(rtsp_ip);
|
||||
rtsp_ip = strdup(bindaddr);
|
||||
rtsp_port = port;
|
||||
rtsp_server = tcp_server_create(bindaddr, port, &ops, NULL);
|
||||
if (reg)
|
||||
tcp_server_register(rtsp_server);
|
||||
}
|
||||
|
||||
void satip_server_rtsp_register(void)
|
||||
{
|
||||
tcp_server_register(rtsp_server);
|
||||
}
|
||||
|
||||
void satip_server_rtsp_done(void)
|
||||
{
|
||||
pthread_mutex_lock(&global_lock);
|
||||
rtsp_close_sessions();
|
||||
if (rtsp_server)
|
||||
tcp_server_delete(rtsp_server);
|
||||
rtsp_server = NULL;
|
||||
rtsp_port = -1;
|
||||
free(rtsp_ip);
|
||||
rtsp_ip = NULL;
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
|
@ -173,7 +173,7 @@ satip_server_http_xml(http_connection_t *hc)
|
|||
|
||||
free(devicelist);
|
||||
|
||||
http_send_header(hc, 200, "text/xml", strlen(buf), 0, NULL, 10, 0, NULL);
|
||||
http_send_header(hc, 200, "text/xml", strlen(buf), 0, NULL, 10, 0, NULL, NULL);
|
||||
tvh_write(hc->hc_fd, buf, strlen(buf));
|
||||
|
||||
return 0;
|
||||
|
@ -474,7 +474,8 @@ void satip_server_config_changed(void)
|
|||
if (!satip_server_rtsp_port_locked) {
|
||||
rtsp_port = config_get_int("satip_rtsp", 0);
|
||||
satip_server_rtsp_port = rtsp_port;
|
||||
if (rtsp_port <= 0) {
|
||||
if (rtsp_port > 0) {
|
||||
satip_server_rtsp_init(http_server_ip, rtsp_port);
|
||||
tvhinfo("satips", "SAT>IP Server reinitialized (HTTP %s:%d, RTSP %s:%d, DVB-T %d, DVB-S2 %d, DVB-C %d)",
|
||||
http_server_ip, http_server_port, http_server_ip, rtsp_port,
|
||||
config_get_int("satip_dvbt", 0),
|
||||
|
@ -483,6 +484,7 @@ void satip_server_config_changed(void)
|
|||
satips_upnp_send_announce();
|
||||
} else {
|
||||
tvhinfo("satips", "SAT>IP Server shutdown");
|
||||
satip_server_rtsp_done();
|
||||
satips_upnp_send_byebye();
|
||||
}
|
||||
}
|
||||
|
@ -519,8 +521,13 @@ void satip_server_init(int rtsp_port)
|
|||
if (rtsp_port <= 0)
|
||||
return;
|
||||
|
||||
tvhinfo("satips", "SAT>IP Server initialized (HTTP %s:%d, RTSP %s:%d)",
|
||||
http_server_ip, http_server_port, http_server_ip, rtsp_port);
|
||||
satip_server_rtsp_init(http_server_ip, rtsp_port);
|
||||
|
||||
tvhinfo("satips", "SAT>IP Server initialized (HTTP %s:%d, RTSP %s:%d, DVB-T %d, DVB-S2 %d, DVB-C %d)",
|
||||
http_server_ip, http_server_port, http_server_ip, rtsp_port,
|
||||
config_get_int("satip_dvbt", 0),
|
||||
config_get_int("satip_dvbs", 0),
|
||||
config_get_int("satip_dvbc", 0));
|
||||
}
|
||||
|
||||
void satip_server_register(void)
|
||||
|
@ -576,13 +583,16 @@ void satip_server_register(void)
|
|||
satips_upnp_discovery->us_destroy = satips_upnp_discovery_destroy;
|
||||
}
|
||||
|
||||
satip_server_rtsp_register();
|
||||
satips_upnp_send_announce();
|
||||
}
|
||||
|
||||
void satip_server_done(void)
|
||||
{
|
||||
satip_server_rtsp_done();
|
||||
if (satip_server_rtsp_port > 0)
|
||||
satips_upnp_send_byebye();
|
||||
satip_server_rtsp_port = 0;
|
||||
free(http_server_ip);
|
||||
http_server_ip = NULL;
|
||||
free(satip_server_uuid);
|
||||
|
|
|
@ -189,7 +189,7 @@ page_static_file(http_connection_t *hc, const char *remain, void *opaque)
|
|||
size = fb_size(fp);
|
||||
gzip = fb_gzipped(fp) ? "gzip" : NULL;
|
||||
|
||||
http_send_header(hc, 200, content, size, gzip, NULL, 10, 0, NULL);
|
||||
http_send_header(hc, 200, content, size, gzip, NULL, 10, 0, NULL, NULL);
|
||||
while (!fb_eof(fp)) {
|
||||
ssize_t c = fb_read(fp, buf, sizeof(buf));
|
||||
if (c < 0) {
|
||||
|
@ -1002,7 +1002,7 @@ page_xspf(http_connection_t *hc, const char *remain, void *opaque)
|
|||
image ? " <image>" : "", image ?: "", image ? "</image>\r\n" : "");
|
||||
|
||||
len = strlen(buf);
|
||||
http_send_header(hc, 200, "application/xspf+xml", len, 0, NULL, 10, 0, NULL);
|
||||
http_send_header(hc, 200, "application/xspf+xml", len, 0, NULL, 10, 0, NULL, NULL);
|
||||
tvh_write(hc->hc_fd, buf, len);
|
||||
|
||||
free(hostpath);
|
||||
|
@ -1034,7 +1034,7 @@ page_m3u(http_connection_t *hc, const char *remain, void *opaque)
|
|||
%s/%s%s%s\r\n", title, hostpath, remain, profile ? "?profile=" : "", profile ?: "");
|
||||
|
||||
len = strlen(buf);
|
||||
http_send_header(hc, 200, "audio/x-mpegurl", len, 0, NULL, 10, 0, NULL);
|
||||
http_send_header(hc, 200, "audio/x-mpegurl", len, 0, NULL, 10, 0, NULL, NULL);
|
||||
tvh_write(hc->hc_fd, buf, len);
|
||||
|
||||
free(hostpath);
|
||||
|
@ -1234,7 +1234,7 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque)
|
|||
http_send_header(hc, range ? HTTP_STATUS_PARTIAL_CONTENT : HTTP_STATUS_OK,
|
||||
content, content_len, NULL, NULL, 10,
|
||||
range ? range_buf : NULL,
|
||||
disposition[0] ? disposition : NULL);
|
||||
disposition[0] ? disposition : NULL, NULL);
|
||||
|
||||
ret = 0;
|
||||
if(!hc->hc_no_output) {
|
||||
|
@ -1313,7 +1313,7 @@ page_imagecache(http_connection_t *hc, const char *remain, void *opaque)
|
|||
return HTTP_STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
http_send_header(hc, 200, NULL, st.st_size, 0, NULL, 10, 0, NULL);
|
||||
http_send_header(hc, 200, NULL, st.st_size, 0, NULL, 10, 0, NULL, NULL);
|
||||
|
||||
while (1) {
|
||||
c = read(fd, buf, sizeof(buf));
|
||||
|
|
Loading…
Add table
Reference in a new issue