SAT>IP server: many fixes and additions, first "somewhat working" version
Tested only with another tvheadend as client with the DVB-T adapter.
This commit is contained in:
parent
ca0a703779
commit
7bb903a397
2 changed files with 338 additions and 145 deletions
117
src/satip/rtp.c
117
src/satip/rtp.c
|
@ -24,8 +24,8 @@
|
|||
#include "satip/server.h"
|
||||
|
||||
#define RTP_PACKETS 128
|
||||
#define RTP_PAYLOAD (1356-20-8)
|
||||
#define RTCP_PAYLOAD (1472-20-8)
|
||||
#define RTP_PAYLOAD (7*188+12)
|
||||
#define RTCP_PAYLOAD (1420)
|
||||
|
||||
typedef struct satip_rtp_session {
|
||||
TAILQ_ENTRY(satip_rtp_session) link;
|
||||
|
@ -47,6 +47,7 @@ typedef struct satip_rtp_session {
|
|||
int um_packet;
|
||||
uint16_t seq;
|
||||
signal_status_t sig;
|
||||
pthread_mutex_t lock;
|
||||
} satip_rtp_session_t;
|
||||
|
||||
static pthread_mutex_t satip_rtp_lock;
|
||||
|
@ -72,7 +73,7 @@ satip_rtp_header(satip_rtp_session_t *rtp)
|
|||
data[5] = (tstamp >> 16) & 0xff;
|
||||
data[6] = (tstamp >> 8) & 0xff;
|
||||
data[7] = tstamp & 0xff;
|
||||
memset(data + 8, 0xa5, 8);
|
||||
memset(data + 8, 0xa5, 4);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -83,11 +84,11 @@ satip_rtp_send(satip_rtp_session_t *rtp)
|
|||
if (v->iov_len == RTP_PAYLOAD) {
|
||||
packets = rtp->um_packet;
|
||||
v2 = v + packets;
|
||||
copy = 1;
|
||||
if (v2->iov_len == RTP_PAYLOAD) {
|
||||
packets++;
|
||||
copy = 0;
|
||||
} else
|
||||
copy = 1;
|
||||
}
|
||||
r = udp_multisend_send(&rtp->um, rtp->fd_rtp, packets);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -107,7 +108,7 @@ satip_rtp_send(satip_rtp_session_t *rtp)
|
|||
static int
|
||||
satip_rtp_loop(satip_rtp_session_t *rtp, uint8_t *data, int len)
|
||||
{
|
||||
int i, pid, last_pid = -1, r;
|
||||
int i, j, pid, last_pid = -1, r;
|
||||
int16_t *pids = rtp->pids;
|
||||
struct iovec *v = rtp->um_iovec + rtp->um_packet;
|
||||
|
||||
|
@ -115,21 +116,27 @@ satip_rtp_loop(satip_rtp_session_t *rtp, uint8_t *data, int len)
|
|||
for ( ; len >= 188 ; data += 188, len -= 188) {
|
||||
pid = ((data[1] & 0x1f) << 8) | data[2];
|
||||
if (pid != last_pid) {
|
||||
for (i = 0; i < RTSP_PIDS && pids[i] >= 0; i++)
|
||||
if (pids[i] == pid)
|
||||
break;
|
||||
if (i >= RTSP_PIDS) continue; /* skip PID */
|
||||
for (i = 0, j = -1; i < RTSP_PIDS && (j = pids[i]) >= 0; i++)
|
||||
if (j == pid) goto found;
|
||||
continue;
|
||||
found:
|
||||
last_pid = pid;
|
||||
}
|
||||
assert(v->iov_len + 188 <= RTP_PAYLOAD);
|
||||
memcpy(v->iov_base + v->iov_len, data, 188);
|
||||
v->iov_len += 188;
|
||||
if (v->iov_len >= RTP_PAYLOAD) {
|
||||
if (v->iov_len == RTP_PAYLOAD) {
|
||||
if ((rtp->um_packet + 1) == RTP_PACKETS) {
|
||||
r = satip_rtp_send(rtp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
} else {
|
||||
rtp->um_packet++;
|
||||
satip_rtp_header(rtp);
|
||||
}
|
||||
v = rtp->um_iovec + rtp->um_packet;
|
||||
} else {
|
||||
assert(v->iov_len < RTP_PAYLOAD);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -174,7 +181,9 @@ satip_rtp_thread(void *aux)
|
|||
case SMT_MPEGTS:
|
||||
pb = sm->sm_data;
|
||||
atomic_add(&subs->ths_bytes_out, pktbuf_len(pb));
|
||||
pthread_mutex_lock(&rtp->lock);
|
||||
r = satip_rtp_loop(rtp, pktbuf_ptr(pb), pktbuf_len(pb));
|
||||
pthread_mutex_unlock(&rtp->lock);
|
||||
if (r) fatal = 1;
|
||||
break;
|
||||
case SMT_SIGNAL_STATUS:
|
||||
|
@ -215,11 +224,9 @@ satip_rtp_find(void *id)
|
|||
{
|
||||
satip_rtp_session_t *rtp;
|
||||
|
||||
pthread_mutex_lock(&satip_rtp_lock);
|
||||
TAILQ_FOREACH(rtp, &satip_rtp_sessions, link)
|
||||
if (rtp == id)
|
||||
if (rtp->id == id)
|
||||
break;
|
||||
pthread_mutex_unlock(&satip_rtp_lock);
|
||||
return rtp;
|
||||
}
|
||||
|
||||
|
@ -241,7 +248,7 @@ void satip_rtp_queue(void *id, th_subscription_t *subs,
|
|||
rtp->id = id;
|
||||
rtp->peer = *peer;
|
||||
rtp->peer2 = *peer;
|
||||
IP_PORT_SET(rtp->peer2, port + 1);
|
||||
IP_PORT_SET(rtp->peer2, htons(port + 1));
|
||||
rtp->port = port;
|
||||
rtp->fd_rtp = fd_rtp;
|
||||
rtp->fd_rtcp = fd_rtcp;
|
||||
|
@ -253,6 +260,7 @@ void satip_rtp_queue(void *id, th_subscription_t *subs,
|
|||
rtp->frontend = frontend;
|
||||
rtp->dmc = *dmc;
|
||||
rtp->source = source;
|
||||
pthread_mutex_init(&rtp->lock, NULL);
|
||||
|
||||
pthread_mutex_lock(&satip_rtp_lock);
|
||||
TAILQ_INSERT_TAIL(&satip_rtp_sessions, rtp, link);
|
||||
|
@ -260,6 +268,20 @@ void satip_rtp_queue(void *id, th_subscription_t *subs,
|
|||
pthread_mutex_unlock(&satip_rtp_lock);
|
||||
}
|
||||
|
||||
void satip_rtp_update_pids(void *id, int16_t *pids)
|
||||
{
|
||||
satip_rtp_session_t *rtp;
|
||||
|
||||
pthread_mutex_lock(&satip_rtp_lock);
|
||||
rtp = satip_rtp_find(id);
|
||||
if (rtp) {
|
||||
pthread_mutex_lock(&rtp->lock);
|
||||
memcpy(rtp->pids, pids, sizeof(*pids)*RTSP_PIDS);
|
||||
pthread_mutex_unlock(&rtp->lock);
|
||||
}
|
||||
pthread_mutex_unlock(&satip_rtp_lock);
|
||||
}
|
||||
|
||||
void satip_rtp_close(void *id)
|
||||
{
|
||||
satip_rtp_session_t *rtp;
|
||||
|
@ -268,17 +290,19 @@ void satip_rtp_close(void *id)
|
|||
pthread_mutex_lock(&satip_rtp_lock);
|
||||
rtp = satip_rtp_find(id);
|
||||
if (rtp) {
|
||||
TAILQ_REMOVE(&satip_rtp_sessions, rtp, link);
|
||||
sq = rtp->sq;
|
||||
pthread_mutex_lock(&sq->sq_mutex);
|
||||
rtp->sq = NULL;
|
||||
pthread_cond_signal(&sq->sq_cond);
|
||||
pthread_mutex_unlock(&sq->sq_mutex);
|
||||
pthread_mutex_unlock(&satip_rtp_lock);
|
||||
pthread_join(rtp->tid, NULL);
|
||||
pthread_mutex_lock(&satip_rtp_lock);
|
||||
udp_multisend_free(&rtp->um);
|
||||
free(rtp);
|
||||
} else {
|
||||
pthread_mutex_unlock(&satip_rtp_lock);
|
||||
}
|
||||
pthread_mutex_unlock(&satip_rtp_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -288,8 +312,12 @@ static const char *
|
|||
satip_rtcp_fec(int fec)
|
||||
{
|
||||
static char buf[16];
|
||||
const char *s = dvb_fec2str(fec);
|
||||
char *p = buf;
|
||||
const char *s;
|
||||
|
||||
if (fec == DVB_FEC_AUTO || fec == DVB_FEC_NONE)
|
||||
return "";
|
||||
s = dvb_fec2str(fec);
|
||||
if (s == NULL)
|
||||
return "";
|
||||
strncpy(buf, s, sizeof(buf));
|
||||
|
@ -313,8 +341,31 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
|
|||
const char *bw, *tmode, *gi, *plp, *t2id, *sm, *c2tft, *ds, *specinv;
|
||||
int i, len, len2, level = 0, lock = 0, quality = 0;
|
||||
|
||||
if (rtp->sig.signal > 0)
|
||||
lock = 1;
|
||||
switch (rtp->sig.signal_scale) {
|
||||
case SIGNAL_STATUS_SCALE_RELATIVE:
|
||||
level = MIN(240, MAX(0, (rtp->sig.signal * 245) / 0xffff));
|
||||
break;
|
||||
case SIGNAL_STATUS_SCALE_DECIBEL:
|
||||
level = MIN(240, MAX(0, (rtp->sig.signal * 900000)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (rtp->sig.snr_scale) {
|
||||
case SIGNAL_STATUS_SCALE_RELATIVE:
|
||||
quality = MIN(15, MAX(0, (rtp->sig.signal * 16) / 0xffff));
|
||||
break;
|
||||
case SIGNAL_STATUS_SCALE_DECIBEL:
|
||||
quality = MIN(15, MAX(0, (rtp->sig.signal * 100000)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pids[0] = 0;
|
||||
for (i = len = 00; i < RTSP_PIDS && rtp->pids[i] >= 0; i++)
|
||||
for (i = len = 0; i < RTSP_PIDS && rtp->pids[i] >= 0; i++)
|
||||
len += snprintf(pids + len, sizeof(pids) - len, "%d,", rtp->pids[i]);
|
||||
if (len && pids[len-1] == ',')
|
||||
pids[len-1] = '\0';
|
||||
|
@ -345,7 +396,7 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
|
|||
snprintf(buf, sizeof(buf),
|
||||
"vers=1.0;src=%d;tuner=%d,%d,%d,%d,%.f,%s,%s,%s,%s,%s,%.f,%s;pids=%s",
|
||||
rtp->source, rtp->frontend, level, lock, quality,
|
||||
(float)rtp->dmc.dmc_fe_freq / 1000.0,
|
||||
(float)rtp->dmc.dmc_fe_freq / 1000000.0,
|
||||
dvb_pol2str(rtp->dmc.u.dmc_fe_qpsk.polarisation),
|
||||
delsys, msys, pilot, rolloff,
|
||||
(float)rtp->dmc.u.dmc_fe_qpsk.symbol_rate / 1000.0,
|
||||
|
@ -399,7 +450,7 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
|
|||
snprintf(buf, sizeof(buf),
|
||||
"vers=1.1;tuner=%d,%d,%d,%d,%.f,%s,%s,%s,%s,%s,%s,%s,%s,%s;pids=%s",
|
||||
rtp->frontend, level, lock, quality,
|
||||
(float)rtp->dmc.dmc_fe_freq / 1000.0,
|
||||
(float)rtp->dmc.dmc_fe_freq / 1000000.0,
|
||||
bw, delsys, tmode, msys, gi,
|
||||
satip_rtcp_fec(rtp->dmc.u.dmc_fe_ofdm.code_rate_HP),
|
||||
plp, t2id, sm, pids);
|
||||
|
@ -425,7 +476,7 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
|
|||
snprintf(buf, sizeof(buf),
|
||||
"vers=1.1;tuner=%d,%d,%d,%d,%.f,%s,%s,%s,%.f,%s,%s,%s,%s;pids=%s",
|
||||
rtp->frontend, level, lock, quality,
|
||||
(float)rtp->dmc.dmc_fe_freq / 1000.0,
|
||||
(float)rtp->dmc.dmc_fe_freq / 1000000.0,
|
||||
bw, delsys, msys,
|
||||
(float)rtp->dmc.u.dmc_fe_qam.symbol_rate / 1000.0,
|
||||
c2tft, ds, plp, specinv, pids);
|
||||
|
@ -434,7 +485,9 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
len = len2 = strlen(buf);
|
||||
len = len2 = MIN(strlen(buf), RTCP_PAYLOAD - 16);
|
||||
if (len == 0)
|
||||
len++;
|
||||
while ((len % 4) != 0)
|
||||
buf[len++] = 0;
|
||||
memcpy(msg + 16, buf, len);
|
||||
|
@ -442,8 +495,8 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
|
|||
len += 16;
|
||||
msg[0] = 0x80;
|
||||
msg[1] = 204;
|
||||
msg[2] = (len >> 8) & 0xff;
|
||||
msg[3] = len & 0xff;
|
||||
msg[2] = (((len - 1) / 4) >> 8) & 0xff;
|
||||
msg[3] = ((len - 1) / 4) & 0xff;
|
||||
msg[4] = 0;
|
||||
msg[5] = 0;
|
||||
msg[6] = 0;
|
||||
|
@ -457,7 +510,7 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
|
|||
msg[14] = (len2 >> 8) & 0xff;
|
||||
msg[15] = len2 & 0xff;
|
||||
|
||||
return len2;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -475,11 +528,11 @@ satip_rtcp_thread(void *aux)
|
|||
while (satip_rtcp_run) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 150000000;
|
||||
while (1) {
|
||||
nanosleep(&ts, &ts);
|
||||
if (satip_rtcp_run)
|
||||
do {
|
||||
r = nanosleep(&ts, &ts);
|
||||
if (!satip_rtcp_run)
|
||||
goto end;
|
||||
} while (ts.tv_nsec);
|
||||
} while (r && ts.tv_nsec);
|
||||
pthread_mutex_lock(&satip_rtp_lock);
|
||||
TAILQ_FOREACH(rtp, &satip_rtp_sessions, link) {
|
||||
if (rtp->sq == NULL) continue;
|
||||
|
@ -489,7 +542,7 @@ satip_rtcp_thread(void *aux)
|
|||
(struct sockaddr*)&rtp->peer2,
|
||||
rtp->peer2.ss_family == AF_INET6 ?
|
||||
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
|
||||
if (r) {
|
||||
if (r < 0) {
|
||||
err = errno;
|
||||
tcp_get_ip_str((struct sockaddr*)&rtp->peer2, addrbuf, sizeof(addrbuf));
|
||||
tvhwarn("satips", "RTCP send to error %s:%d : %s",
|
||||
|
|
366
src/satip/rtsp.c
366
src/satip/rtsp.c
|
@ -36,6 +36,7 @@ typedef struct session {
|
|||
int frontend;
|
||||
int findex;
|
||||
int src;
|
||||
int run;
|
||||
uint32_t nsession;
|
||||
char session[9];
|
||||
dvb_mux_conf_t dmc;
|
||||
|
@ -45,6 +46,7 @@ typedef struct session {
|
|||
int mux_created;
|
||||
profile_chain_t prch;
|
||||
th_subscription_t *subs;
|
||||
int rtp_peer_port;
|
||||
udp_connection_t *udp_rtp;
|
||||
udp_connection_t *udp_rtcp;
|
||||
} session_t;
|
||||
|
@ -104,6 +106,8 @@ static struct session *
|
|||
rtsp_new_session(int delsys, uint32_t nsession, int session)
|
||||
{
|
||||
struct session *rs = calloc(1, sizeof(*rs));
|
||||
int i;
|
||||
|
||||
if (rs == NULL)
|
||||
return NULL;
|
||||
rs->delsys = delsys;
|
||||
|
@ -114,6 +118,8 @@ rtsp_new_session(int delsys, uint32_t nsession, int session)
|
|||
if (session_number == 0)
|
||||
session_number += 9876;
|
||||
}
|
||||
for (i = 0; i < RTSP_PIDS; i++)
|
||||
rs->pids[i] = -1;
|
||||
TAILQ_INSERT_TAIL(&rtsp_sessions, rs, link);
|
||||
return rs;
|
||||
}
|
||||
|
@ -145,8 +151,7 @@ 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);
|
||||
}
|
||||
|
@ -154,7 +159,9 @@ rtsp_session_timer_cb(void *aux)
|
|||
static inline void
|
||||
rtsp_rearm_session_timer(session_t *rs)
|
||||
{
|
||||
pthread_mutex_lock(&global_lock);
|
||||
gtimer_arm(&rs->timer, rtsp_session_timer_cb, rs, RTSP_TIMEOUT);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -163,7 +170,7 @@ rtsp_rearm_session_timer(session_t *rs)
|
|||
static char *
|
||||
rtsp_check_urlbase(char *u)
|
||||
{
|
||||
char *p;
|
||||
char *p, *s;
|
||||
|
||||
/* expect string: rtsp://<myip>[:<myport>]/ */
|
||||
if (u[0] == '\0' || strncmp(u, "rtsp://", 7))
|
||||
|
@ -173,9 +180,9 @@ rtsp_check_urlbase(char *u)
|
|||
if (p == NULL)
|
||||
return NULL;
|
||||
*p = '\0';
|
||||
if ((p = strchr(u, ':')) != NULL) {
|
||||
*p = '\0';
|
||||
if (atoi(p + 1) != rtsp_port)
|
||||
if ((s = strchr(u, ':')) != NULL) {
|
||||
*s = '\0';
|
||||
if (atoi(s + 1) != rtsp_port)
|
||||
return NULL;
|
||||
} else {
|
||||
if (rtsp_port != 554)
|
||||
|
@ -183,7 +190,7 @@ rtsp_check_urlbase(char *u)
|
|||
}
|
||||
if (strcmp(u, rtsp_ip))
|
||||
return NULL;
|
||||
return p;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -197,7 +204,9 @@ rtsp_parse_args(http_connection_t *hc, char *u)
|
|||
|
||||
if (strncmp(u, "stream=", 7) == 0) {
|
||||
u += 7;
|
||||
for (s = 0; isdigit(*s); s++);
|
||||
for (s = u; isdigit(*s); s++);
|
||||
if (*s == '\0')
|
||||
return atoi(u);
|
||||
if (*s != '?')
|
||||
return -1;
|
||||
*s = '\0';
|
||||
|
@ -206,11 +215,24 @@ rtsp_parse_args(http_connection_t *hc, char *u)
|
|||
} else {
|
||||
if (*u != '?')
|
||||
return -1;
|
||||
u++;
|
||||
}
|
||||
http_parse_get_args(hc, u);
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
rtsp_clrpids(session_t *rs)
|
||||
{
|
||||
int16_t *pids = rs->pids;
|
||||
int i = RTSP_PIDS;
|
||||
while (*pids >= 0 && i-- > 0)
|
||||
*pids++ = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
@ -228,8 +250,12 @@ rtsp_addpids(session_t *rs, int16_t *pids)
|
|||
rs->pids[j] = rs->pids[j-1];
|
||||
rs->pids[i] = pid;
|
||||
break;
|
||||
} else if (rs->pids[i] == pid)
|
||||
} else if (rs->pids[i] == pid) {
|
||||
break;
|
||||
} else if (rs->pids[i] < 0) {
|
||||
rs->pids[i] = pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -270,71 +296,98 @@ rtsp_clean(session_t *rs)
|
|||
}
|
||||
if (rs->prch.prch_pro)
|
||||
profile_chain_close(&rs->prch);
|
||||
if (rs->mux && rs->mux_created) {
|
||||
if (rs->mux && rs->mux_created)
|
||||
rs->mux->mm_delete((mpegts_mux_t *)rs->mux, 1);
|
||||
rs->mux = NULL;
|
||||
rs->mux_created = 0;
|
||||
}
|
||||
rs->mux = NULL;
|
||||
rs->mux_created = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static int
|
||||
rtsp_start(http_connection_t *hc, session_t *rs, char *addrbuf)
|
||||
rtsp_start
|
||||
(http_connection_t *hc, session_t *rs, char *addrbuf, int newmux, int setup)
|
||||
{
|
||||
mpegts_network_t *mn;
|
||||
mpegts_network_t *mn, *mn2;
|
||||
dvb_network_t *ln;
|
||||
char buf[256];
|
||||
int res = HTTP_STATUS_SERVICE, qsize = 3000000;
|
||||
dvb_mux_t *mux;
|
||||
char buf[384];
|
||||
int res = HTTP_STATUS_SERVICE, qsize = 3000000, created = 0;
|
||||
|
||||
if (rs->mux)
|
||||
return 0;
|
||||
rs->mux_created = 0;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
|
||||
ln = (dvb_network_t *)mn;
|
||||
if (ln->ln_type == rs->dmc.dmc_fe_type &&
|
||||
mn->mn_satip_source == rs->src)
|
||||
break;
|
||||
}
|
||||
if (mn) {
|
||||
rs->mux = dvb_network_find_mux((dvb_network_t *)mn, &rs->dmc,
|
||||
if (newmux) {
|
||||
mux = NULL;
|
||||
mn2 = NULL;
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
|
||||
ln = (dvb_network_t *)mn;
|
||||
if (ln->ln_type == rs->dmc.dmc_fe_type &&
|
||||
mn->mn_satip_source == rs->src) {
|
||||
if (!mn2) mn2 = mn;
|
||||
mux = dvb_network_find_mux((dvb_network_t *)mn, &rs->dmc,
|
||||
MPEGTS_ONID_NONE, MPEGTS_TSID_NONE);
|
||||
if (rs->mux == NULL) {
|
||||
rs->mux = (dvb_mux_t *)
|
||||
mn->mn_create_mux(mn, (void *)(intptr_t)rs->nsession,
|
||||
if (mux) break;
|
||||
}
|
||||
}
|
||||
if (mux == NULL && mn2) {
|
||||
mux = (dvb_mux_t *)
|
||||
mn->mn_create_mux(mn2, (void *)(intptr_t)rs->nsession,
|
||||
MPEGTS_ONID_NONE, MPEGTS_TSID_NONE,
|
||||
&rs->dmc, 0);
|
||||
if (rs->mux)
|
||||
rs->mux_created = 1;
|
||||
if (mux)
|
||||
created = 1;
|
||||
}
|
||||
}
|
||||
if (rs->mux == NULL) {
|
||||
dvb_mux_conf_str(&rs->dmc, buf, sizeof(buf));
|
||||
tvhwarn("satips", "%i: unable to create mux %s", rs->frontend, buf);
|
||||
goto end;
|
||||
}
|
||||
if (profile_chain_raw_open(&rs->prch, (mpegts_mux_t *)rs->mux, qsize))
|
||||
goto endclean;
|
||||
rs->subs = subscription_create_from_mux(&rs->prch, NULL,
|
||||
if (mux == NULL) {
|
||||
dvb_mux_conf_str(&rs->dmc, buf, sizeof(buf));
|
||||
tvhwarn("satips", "%i: unable to create mux %s", rs->frontend, buf);
|
||||
goto endclean;
|
||||
}
|
||||
if (rs->mux == mux)
|
||||
goto pids;
|
||||
if (rs->run)
|
||||
satip_rtp_close((void *)(intptr_t)rs->stream);
|
||||
rtsp_clean(rs);
|
||||
rs->mux = mux;
|
||||
rs->mux_created = created;
|
||||
if (profile_chain_raw_open(&rs->prch, (mpegts_mux_t *)rs->mux, qsize))
|
||||
goto endclean;
|
||||
rs->subs = subscription_create_from_mux(&rs->prch, NULL,
|
||||
config_get_int("satip_weight", 100),
|
||||
"SAT>IP",
|
||||
SUBSCRIPTION_FULLMUX | SUBSCRIPTION_STREAMING,
|
||||
rs->prch.prch_flags |
|
||||
SUBSCRIPTION_FULLMUX |
|
||||
SUBSCRIPTION_STREAMING,
|
||||
addrbuf, hc->hc_username,
|
||||
http_arg_get(&hc->hc_args, "User-Agent"), NULL);
|
||||
if (!rs->subs)
|
||||
goto endclean;
|
||||
satip_rtp_queue((void *)(intptr_t)rs->nsession,
|
||||
rs->subs, &rs->prch.prch_sq,
|
||||
hc->hc_peer, ntohs(IP_PORT(rs->udp_rtp->ip)),
|
||||
rs->udp_rtp->fd, rs->udp_rtcp->fd,
|
||||
rs->frontend, rs->findex, &rs->mux->lm_tuning, rs->pids);
|
||||
if (!rs->subs)
|
||||
goto endrtp;
|
||||
if (rs->run) {
|
||||
/* restart streaming */
|
||||
setup = 0;
|
||||
rs->run = 0;
|
||||
}
|
||||
} else {
|
||||
pids:
|
||||
satip_rtp_update_pids((void *)(intptr_t)rs->stream, rs->pids);
|
||||
}
|
||||
if (!setup && !rs->run) {
|
||||
if (rs->mux == NULL)
|
||||
goto endrtp;
|
||||
satip_rtp_queue((void *)(intptr_t)rs->stream,
|
||||
rs->subs, &rs->prch.prch_sq,
|
||||
hc->hc_peer, rs->rtp_peer_port,
|
||||
rs->udp_rtp->fd, rs->udp_rtcp->fd,
|
||||
rs->frontend, rs->findex, &rs->mux->lm_tuning, rs->pids);
|
||||
rs->run = 1;
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 0;
|
||||
|
||||
endrtp:
|
||||
satip_rtp_close((void *)(intptr_t)rs->stream);
|
||||
rs->run = 0;
|
||||
endclean:
|
||||
rtsp_clean(rs);
|
||||
end:
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return res;
|
||||
}
|
||||
|
@ -417,6 +470,7 @@ static int
|
|||
fec_to_tvh(http_connection_t *hc)
|
||||
{
|
||||
switch (atoi(http_arg_get_remove(&hc->hc_req_args, "fec"))) {
|
||||
case 0: return DVB_FEC_AUTO;
|
||||
case 12: return DVB_FEC_1_2;
|
||||
case 13: return DVB_FEC_1_3;
|
||||
case 15: return DVB_FEC_1_5;
|
||||
|
@ -548,7 +602,7 @@ parse_pids(char *p, int16_t *pids)
|
|||
char *x, *saveptr;
|
||||
int i = 0;
|
||||
|
||||
if (p == '\0') {
|
||||
if (p == NULL || *p == '\0') {
|
||||
pids[0] = -1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -559,9 +613,12 @@ parse_pids(char *p, int16_t *pids)
|
|||
if (i >= RTSP_PIDS)
|
||||
return -1;
|
||||
pids[i] = atoi(x);
|
||||
if (pids[i] < 0 || pids[i] > 8191)
|
||||
if (pids[i] < 0 || pids[i] > 8191) {
|
||||
pids[i] = -1;
|
||||
return -1;
|
||||
}
|
||||
x = strtok_r(NULL, ",", &saveptr);
|
||||
i++;
|
||||
}
|
||||
if (i == 0)
|
||||
return -1;
|
||||
|
@ -569,6 +626,27 @@ parse_pids(char *p, int16_t *pids)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_transport(http_connection_t *hc)
|
||||
{
|
||||
const char *s = http_arg_get(&hc->hc_args, "Transport");
|
||||
const char *u;
|
||||
int a, b;
|
||||
if (!s || strncmp(s, "RTP/AVP;unicast;client_port=", 28))
|
||||
return -1;
|
||||
for (s += 28, u = s; isdigit(*u); u++);
|
||||
if (*u != '-')
|
||||
return -1;
|
||||
a = atoi(s);
|
||||
for (s = ++u; isdigit(*s); s++);
|
||||
if (*s != '\0' && *s != ';')
|
||||
return -1;
|
||||
b = atoi(u);
|
||||
if (a + 1 != b)
|
||||
return -1;
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
@ -580,12 +658,12 @@ rtsp_process_play(http_connection_t *hc, int setup)
|
|||
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];
|
||||
int16_t pids[RTSP_PIDS+1], addpids[RTSP_PIDS+1], delpids[RTSP_PIDS+1];
|
||||
dvb_mux_conf_t *dmc;
|
||||
char buf[256], addrbuf[50];
|
||||
http_arg_list_t args;
|
||||
|
||||
http_arg_init(&args);
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, sizeof(addrbuf));
|
||||
|
||||
u = tvh_strdupa(hc->hc_url);
|
||||
|
@ -594,15 +672,16 @@ rtsp_process_play(http_connection_t *hc, int setup)
|
|||
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;
|
||||
s = http_arg_get_remove(&hc->hc_req_args, "addpids");
|
||||
if (parse_pids(s, addpids)) goto error2;
|
||||
s = http_arg_get_remove(&hc->hc_req_args, "delpids");
|
||||
if (parse_pids(s, delpids)) goto error2;
|
||||
s = http_arg_get_remove(&hc->hc_req_args, "pids");
|
||||
if (parse_pids(s, pids)) goto error2;
|
||||
msys = msys_to_tvh(hc);
|
||||
if (msys < 0)
|
||||
goto error2;
|
||||
freq = atof(http_arg_get_remove(&hc->hc_req_args, "freq")) * 1000000;
|
||||
|
||||
if (addpids || delpids) {
|
||||
if (addpids[0] >= 0 || delpids[0] >= 0) {
|
||||
if (setup)
|
||||
goto error2;
|
||||
if (!stream)
|
||||
|
@ -620,34 +699,53 @@ rtsp_process_play(http_connection_t *hc, int setup)
|
|||
}
|
||||
|
||||
if (setup) {
|
||||
if (msys == DVB_SYS_NONE)
|
||||
goto error;
|
||||
if (delsys == DVB_SYS_NONE) goto error;
|
||||
if (msys == DVB_SYS_NONE) goto error;
|
||||
if (!fe) goto error;
|
||||
if (freq < 1000000) goto error;
|
||||
if (!rs)
|
||||
rs = rtsp_new_session(msys, 0, -1);
|
||||
else if (stream != rs->stream)
|
||||
rs = rtsp_new_session(msys, rs->nsession, stream);
|
||||
else
|
||||
rtsp_close_session(rs);
|
||||
r = parse_transport(hc);
|
||||
if (r < 0) {
|
||||
errcode = HTTP_STATUS_BAD_TRANSFER;
|
||||
goto error;
|
||||
}
|
||||
if (rs->run && rs->rtp_peer_port != r) {
|
||||
errcode = HTTP_STATUS_METHOD_INVALID;
|
||||
goto error;
|
||||
}
|
||||
rs->frontend = fe;
|
||||
rs->rtp_peer_port = r;
|
||||
dmc = &rs->dmc;
|
||||
} else {
|
||||
if (!rs || stream != rs->stream) {
|
||||
if (rs)
|
||||
errcode = HTTP_STATUS_NOT_FOUND;
|
||||
goto error;
|
||||
}
|
||||
dmc = &rs->dmc;
|
||||
if (rs->mux == NULL) goto error;
|
||||
if (!fe) {
|
||||
fe = rs->frontend;
|
||||
findex = rs->findex;
|
||||
}
|
||||
if (rs->frontend != fe)
|
||||
goto error;
|
||||
if (freq >= 1000000) {
|
||||
if (delsys == DVB_SYS_NONE) goto error;
|
||||
if (msys == DVB_SYS_NONE) goto error;
|
||||
} else {
|
||||
if (!TAILQ_EMPTY(&hc->hc_req_args)) goto error;
|
||||
goto play;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
rs->findex = findex;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -688,10 +786,14 @@ rtsp_process_play(http_connection_t *hc, int setup)
|
|||
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;
|
||||
s = http_arg_get_remove(&hc->hc_req_args, "plp");
|
||||
if (s[0]) {
|
||||
plp = atoi(s);
|
||||
if (plp < 0 || plp > 255) goto error;
|
||||
} else {
|
||||
plp = DVB_NO_STREAM_ID_FILTER;
|
||||
}
|
||||
t2id = atoi(http_arg_get_remove(&hc->hc_req_args, "t2id"));
|
||||
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;
|
||||
|
@ -739,66 +841,89 @@ rtsp_process_play(http_connection_t *hc, int setup)
|
|||
|
||||
}
|
||||
|
||||
dvb_mux_conf_str(dmc, buf, sizeof(buf));
|
||||
tvhdebug("satips", "%i/%s/%d: setup %s", rs->frontend, rs->session, rs->stream, buf);
|
||||
|
||||
dmc->dmc_fe_freq = freq;
|
||||
dmc->dmc_fe_modulation = mtype;
|
||||
rs->delsys = delsys;
|
||||
rs->frontend = fe;
|
||||
rs->findex = findex;
|
||||
|
||||
stream_id++;
|
||||
if (stream_id == 0)
|
||||
if (setup) {
|
||||
stream_id++;
|
||||
rs->stream = stream_id % 0x7fff;
|
||||
if (stream_id == 0)
|
||||
stream_id++;
|
||||
rs->stream = stream_id % 0x7fff;
|
||||
}
|
||||
rs->src = src;
|
||||
|
||||
memset(&rs->udp_rtp, 0, sizeof(rs->udp_rtp));
|
||||
memset(&rs->udp_rtcp, 0, sizeof(rs->udp_rtcp));
|
||||
if (udp_bind_double(&rs->udp_rtp, &rs->udp_rtcp,
|
||||
"satips", "rtsp", "rtcp",
|
||||
addrbuf, 0, NULL,
|
||||
rtsp_ip, 0, NULL,
|
||||
4*1024, 4*1024,
|
||||
RTP_BUFSIZE, RTCP_BUFSIZE)) {
|
||||
errcode = HTTP_STATUS_INTERNAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (setup) {
|
||||
if (pids)
|
||||
rtsp_addpids(rs, _pids);
|
||||
goto end;
|
||||
if (udp_connect(rs->udp_rtp, "RTP", addrbuf, rs->rtp_peer_port) ||
|
||||
udp_connect(rs->udp_rtcp, "RTCP", addrbuf, rs->rtp_peer_port + 1)) {
|
||||
errcode = HTTP_STATUS_INTERNAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
play:
|
||||
if (delpids)
|
||||
rtsp_delpids(rs, _delpids);
|
||||
if (addpids)
|
||||
rtsp_addpids(rs, _addpids);
|
||||
if ((r = rtsp_start(hc, rs, addrbuf)) < 0) {
|
||||
if (pids[0] >= 0) {
|
||||
rtsp_clrpids(rs);
|
||||
rtsp_addpids(rs, pids);
|
||||
}
|
||||
if (delpids[0] >= 0)
|
||||
rtsp_delpids(rs, delpids);
|
||||
if (addpids[0] >= 0)
|
||||
rtsp_addpids(rs, addpids);
|
||||
if ((r = rtsp_start(hc, rs, addrbuf, freq >= 10000000, setup)) < 0) {
|
||||
errcode = r;
|
||||
goto error;
|
||||
}
|
||||
tvhdebug("satips", "%i/%s/%d: play", rs->frontend, rs->session, rs->stream);
|
||||
|
||||
end:
|
||||
if (setup)
|
||||
tvhdebug("satips", "setup from %s:%d, RTP: %d, RTCP: %d",
|
||||
addrbuf, IP_PORT(*hc->hc_peer),
|
||||
rs->rtp_peer_port, rs->rtp_peer_port + 1);
|
||||
dvb_mux_conf_str(dmc, buf, sizeof(buf));
|
||||
s = buf + strlen(buf);
|
||||
for (r = 0; r < RTSP_PIDS; r++) {
|
||||
if (rs->pids[r] < 0) break;
|
||||
s += snprintf(s, sizeof(buf) - (s - buf), "%s%i",
|
||||
r > 0 ? "," : " pids ", rs->pids[r]);
|
||||
}
|
||||
tvhdebug("satips", "%i/%s/%d: %s %s",
|
||||
rs->frontend, rs->session, rs->stream,
|
||||
setup ? "setup" : "play", buf);
|
||||
|
||||
http_arg_init(&args);
|
||||
snprintf(buf, sizeof(buf), "%s;timeout=%d", rs->session, RTSP_TIMEOUT);
|
||||
http_arg_set(&args, "Session", buf);
|
||||
r = IP_PORT(rs->udp_rtp->ip);
|
||||
snprintf(buf, sizeof(buf), "RTP/AVP;unicast;client_port=%d-%d", r, r+1);
|
||||
http_arg_set(&args, "Transport", buf);
|
||||
snprintf(buf, sizeof(buf), "%d", rs->stream);
|
||||
http_arg_set(&args, "com.ses.streamID", buf);
|
||||
if (setup) {
|
||||
snprintf(buf, sizeof(buf), "%s;timeout=%d", rs->session, RTSP_TIMEOUT);
|
||||
http_arg_set(&args, "Session", buf);
|
||||
r = rs->rtp_peer_port;
|
||||
snprintf(buf, sizeof(buf), "RTP/AVP;unicast;client_port=%d-%d", r, r+1);
|
||||
http_arg_set(&args, "Transport", buf);
|
||||
snprintf(buf, sizeof(buf), "%d", rs->stream);
|
||||
http_arg_set(&args, "com.ses.streamID", buf);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "url=rtsp://%s/stream=%d", rtsp_ip, rs->stream);
|
||||
http_arg_set(&args, "RTP-Info", buf);
|
||||
}
|
||||
http_send_header(hc, HTTP_STATUS_OK, NULL, 0, NULL, NULL, 0, NULL, NULL, &args);
|
||||
http_arg_flush(&args);
|
||||
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
|
||||
http_arg_flush(&args);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
error2:
|
||||
http_error(hc, errcode);
|
||||
http_arg_flush(&args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -811,14 +936,20 @@ rtsp_process_teardown(http_connection_t *hc)
|
|||
char *u = tvh_strdupa(hc->hc_url);
|
||||
struct session *rs = NULL;
|
||||
http_arg_list_t args;
|
||||
char addrbuf[50];
|
||||
int stream;
|
||||
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, sizeof(addrbuf));
|
||||
|
||||
if ((u = rtsp_check_urlbase(u)) == NULL ||
|
||||
(stream = rtsp_parse_args(hc, u)) < 0) {
|
||||
http_error(hc, HTTP_STATUS_BAD_REQUEST);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tvhdebug("satips", "teardown from %s:%d for stream %d",
|
||||
addrbuf, IP_PORT(*hc->hc_peer), stream);
|
||||
|
||||
pthread_mutex_lock(&rtsp_lock);
|
||||
rs = rtsp_find_session(hc, stream);
|
||||
if (!rs || stream != rs->stream) {
|
||||
|
@ -891,7 +1022,9 @@ rtsp_serve(int fd, void **opaque, struct sockaddr_storage *peer,
|
|||
static void
|
||||
rtsp_close_session(session_t *rs)
|
||||
{
|
||||
satip_rtp_close((void *)(intptr_t)rs->nsession);
|
||||
satip_rtp_close((void *)(intptr_t)rs->stream);
|
||||
rs->stream = 0;
|
||||
rs->run =0;
|
||||
udp_close(rs->udp_rtp);
|
||||
udp_close(rs->udp_rtcp);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
@ -906,8 +1039,8 @@ rtsp_close_session(session_t *rs)
|
|||
static void
|
||||
rtsp_free_session(session_t *rs)
|
||||
{
|
||||
gtimer_disarm(&rs->timer);
|
||||
TAILQ_REMOVE(&rtsp_sessions, rs, link);
|
||||
gtimer_disarm(&rs->timer);
|
||||
free(rs);
|
||||
}
|
||||
|
||||
|
@ -918,10 +1051,15 @@ static void
|
|||
rtsp_close_sessions(void)
|
||||
{
|
||||
session_t *rs;
|
||||
while ((rs = TAILQ_FIRST(&rtsp_sessions)) != NULL) {
|
||||
rtsp_close_session(rs);
|
||||
rtsp_free_session(rs);
|
||||
}
|
||||
do {
|
||||
pthread_mutex_lock(&rtsp_lock);
|
||||
rs = TAILQ_FIRST(&rtsp_sessions);
|
||||
if (rs) {
|
||||
rtsp_close_session(rs);
|
||||
rtsp_free_session(rs);
|
||||
}
|
||||
pthread_mutex_unlock(&rtsp_lock);
|
||||
} while (rs != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -966,9 +1104,11 @@ void satip_server_rtsp_register(void)
|
|||
void satip_server_rtsp_done(void)
|
||||
{
|
||||
pthread_mutex_lock(&global_lock);
|
||||
rtsp_close_sessions();
|
||||
if (rtsp_server)
|
||||
tcp_server_delete(rtsp_server);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
rtsp_close_sessions();
|
||||
pthread_mutex_lock(&global_lock);
|
||||
rtsp_server = NULL;
|
||||
rtsp_port = -1;
|
||||
free(rtsp_ip);
|
||||
|
|
Loading…
Add table
Reference in a new issue