#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;
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;
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
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;
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;
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;
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:
{
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;
}
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;
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);
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;
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);
}
/*
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));
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';
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,
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);
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);
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);
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;
msg[14] = (len2 >> 8) & 0xff;
msg[15] = len2 & 0xff;
- return len2;
+ return len;
}
/*
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;
(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",
int frontend;
int findex;
int src;
+ int run;
uint32_t nsession;
char session[9];
dvb_mux_conf_t dmc;
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;
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;
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;
}
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)
{
+ pthread_mutex_lock(&global_lock);
gtimer_arm(&rs->timer, rtsp_session_timer_cb, rs, RTSP_TIMEOUT);
+ pthread_mutex_unlock(&global_lock);
}
/*
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))
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)
}
if (strcmp(u, rtsp_ip))
return NULL;
- return p;
+ return p + 1;
}
/*
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';
} 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;
+}
+
/*
*
*/
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;
}
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;
}
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;
char *x, *saveptr;
int i = 0;
- if (p == '\0') {
+ if (p == NULL || *p == '\0') {
pids[0] = -1;
return 0;
}
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;
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;
+}
+
/*
*
*/
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);
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)
}
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;
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;
}
- 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;
}
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) {
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);
static void
rtsp_free_session(session_t *rs)
{
- gtimer_disarm(&rs->timer);
TAILQ_REMOVE(&rtsp_sessions, rs, link);
+ gtimer_disarm(&rs->timer);
free(rs);
}
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);
}
/*
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);