*/
#include <signal.h>
+#include <ctype.h>
#include "tvheadend.h"
#include "input.h"
#include "streaming.h"
static void
satip_rtp_signal_status(satip_rtp_session_t *rtp, signal_status_t *sig)
{
+ pthread_mutex_lock(&rtp->lock);
rtp->sig = *sig;
+ pthread_mutex_unlock(&rtp->lock);
}
static void *
pthread_join(rtp->tid, NULL);
udp_multisend_free(&rtp->um);
mpegts_pid_done(&rtp->pids);
+ pthread_mutex_destroy(&rtp->lock);
free(rtp);
} else {
pthread_mutex_unlock(&satip_rtp_lock);
}
}
+/*
+ *
+ */
+static const char *
+satip_rtcp_pol(int pol)
+{
+ switch (pol) {
+ case DVB_POLARISATION_HORIZONTAL:
+ return "h";
+ case DVB_POLARISATION_VERTICAL:
+ return "v";
+ case DVB_POLARISATION_CIRCULAR_LEFT:
+ return "l";
+ case DVB_POLARISATION_CIRCULAR_RIGHT:
+ return "r";
+ case DVB_POLARISATION_OFF:
+ return "off";
+ default:
+ return "";
+ }
+}
+
/*
*
*/
*p = *(p+1);
p++;
}
- return s;
+ return buf;
}
/*
*
*/
static int
-satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
+satip_status_build(satip_rtp_session_t *rtp, char *buf, int len)
{
- char buf[1500], pids[1400];
+ char pids[1400];
const char *delsys, *msys, *pilot, *rolloff;
const char *bw, *tmode, *gi, *plp, *t2id, *sm, *c2tft, *ds, *specinv;
- int i, len, len2, level = 0, lock = 0, quality = 0;
+ int i, j, r, level = 0, lock = 0, quality = 0;
if (rtp->sig.snr > 0)
lock = 1;
}
pids[0] = 0;
- for (i = len = 0; i < rtp->pids.count; i++)
- len += snprintf(pids + len, sizeof(pids) - len, "%d,", rtp->pids.pids[i]);
- if (len && pids[len-1] == ',')
- pids[len-1] = '\0';
+ for (i = j = 0; i < rtp->pids.count; i++)
+ j += snprintf(pids + j, sizeof(pids) - j, "%d,", rtp->pids.pids[i]);
+ if (j && pids[j-1] == ',')
+ pids[j-1] = '\0';
switch (rtp->dmc.dmc_fe_delsys) {
case DVB_SYS_DVBS:
/* ver=<major>.<minor>;src=<srcID>;tuner=<feID>,<level>,<lock>,<quality>,<frequency>,<polarisation>,\
* <system>,<type>,<pilots>,<roll_off>,<symbol_rate>,<fec_inner>;pids=<pid0>,...,<pidn>
*/
- snprintf(buf, sizeof(buf),
+ r = snprintf(buf, len,
"ver=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 / 1000000.0,
- dvb_pol2str(rtp->dmc.u.dmc_fe_qpsk.polarisation),
+ (float)rtp->dmc.dmc_fe_freq / 1000.0,
+ satip_rtcp_pol(rtp->dmc.u.dmc_fe_qpsk.polarisation),
delsys, msys, pilot, rolloff,
(float)rtp->dmc.u.dmc_fe_qpsk.symbol_rate / 1000.0,
satip_rtcp_fec(rtp->dmc.u.dmc_fe_qpsk.fec_inner),
/* ver=1.1;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<tmode>,<mtype>,<gi>,\
* <fec>,<plp>,<t2id>,<sm>;pids=<pid0>,...,<pidn>
*/
- snprintf(buf, sizeof(buf),
+ r = snprintf(buf, len,
"ver=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 / 1000000.0,
/* ver=1.2;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<mtype>,<sr>,<c2tft>,<ds>,<plp>,
* <specinv>;pids=<pid0>,...,<pidn>
*/
- snprintf(buf, sizeof(buf),
+ r = snprintf(buf, len,
"ver=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 / 1000000.0,
return 0;
}
- len = len2 = MIN(strlen(buf), RTCP_PAYLOAD - 16);
+ return r;
+}
+
+/*
+ *
+ */
+int satip_rtp_status(void *id, char *buf, int len)
+{
+ satip_rtp_session_t *rtp;
+ int r = 0;
+
+ if (buf)
+ buf[0] = '\0';
+ pthread_mutex_lock(&satip_rtp_lock);
+ rtp = satip_rtp_find(id);
+ if (rtp) {
+ pthread_mutex_lock(&rtp->lock);
+ r = satip_status_build(rtp, buf, len);
+ pthread_mutex_unlock(&rtp->lock);
+ }
+ pthread_mutex_unlock(&satip_rtp_lock);
+ return r;
+}
+
+/*
+ *
+ */
+static int
+satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
+{
+ char buf[1500];
+ int len, len2;
+
+ pthread_mutex_lock(&rtp->lock);
+ len = satip_status_build(rtp, buf, sizeof(buf));
+ pthread_mutex_unlock(&rtp->lock);
+
+ len = len2 = MIN(len, RTCP_PAYLOAD - 16);
if (len == 0)
len++;
while ((len % 4) != 0)
}
http_arg_init(&args);
http_arg_set(&args, "Public", "OPTIONS,DESCRIBE,SETUP,PLAY,TEARDOWN");
- http_arg_set(&args, "Session", hc->hc_session);
+ if (hc->hc_session)
+ http_arg_set(&args, "Session", hc->hc_session);
http_send_header(hc, HTTP_STATUS_OK, NULL, 0, NULL, NULL, 0, NULL, NULL, &args);
http_arg_flush(&args);
return 0;
return 0;
}
+/*
+ *
+ */
+static void
+rtsp_describe_header(session_t *rs, htsbuf_queue_t *q)
+{
+ unsigned long mono = getmonoclock();
+ int dvbt, dvbc;
+
+ htsbuf_qprintf(q, "v=0\r\n");
+ htsbuf_qprintf(q, "o=- %lu %lu IN %s %s\r\n",
+ rs ? (unsigned long)rs->nsession : mono - 123,
+ mono,
+ strchr(rtsp_ip, ':') ? "IP6" : "IP4",
+ rtsp_ip);
+
+ pthread_mutex_lock(&global_lock);
+ htsbuf_qprintf(q, "s=SatIPServer:1 %d",
+ config_get_int("satip_dvbs", 0));
+ dvbt = config_get_int("satip_dvbt", 0);
+ dvbc = config_get_int("satip_dvbc", 0);
+ if (dvbc)
+ htsbuf_qprintf(q, " %d %d\r\n", dvbt, dvbc);
+ else if (dvbt)
+ htsbuf_qprintf(q, " %d\r\n", dvbt);
+ else
+ htsbuf_append(q, "\r\n", 1);
+ pthread_mutex_unlock(&global_lock);
+
+ htsbuf_qprintf(q, "t=0 0\r\n");
+ htsbuf_qprintf(q, "a=tool:tvheadend\r\n");
+}
+
+static void
+rtsp_describe_session(session_t *rs, htsbuf_queue_t *q)
+{
+ char buf[4096];
+
+ htsbuf_qprintf(q, "m=video 0 RTP/AVP 33\r\n");
+ if (strchr(rtsp_ip, ':'))
+ htsbuf_qprintf(q, "c=IN IP6 ::0\r\n");
+ else
+ htsbuf_qprintf(q, "c=IN IP4 0.0.0.0\r\n");
+ htsbuf_qprintf(q, "a=control:stream=%d\r\n", rs->stream);
+ if (rs->run) {
+ satip_rtp_status((void *)(intptr_t)rs->stream, buf, sizeof(buf));
+ htsbuf_qprintf(q, "a=fmtp:33 %s\r\n", buf);
+ htsbuf_qprintf(q, "a=sendonly\r\n");
+ } else {
+ htsbuf_qprintf(q, "a=inactive\r\n");
+ }
+}
+
+/*
+ *
+ */
+static int
+rtsp_process_describe(http_connection_t *hc)
+{
+ http_arg_list_t args;
+ const char *arg;
+ char *u = tvh_strdupa(hc->hc_url);
+ session_t *rs;
+ htsbuf_queue_t q;
+ char buf[96];
+ int stream;
+
+ htsbuf_queue_init(&q, 0);
+
+ arg = http_arg_get(&hc->hc_args, "Accept");
+ if (strcmp(arg, "application/sdp"))
+ goto error;
+
+ if ((u = rtsp_check_urlbase(u)) == NULL)
+ goto error;
+
+ stream = rtsp_parse_args(hc, u);
+
+ if (TAILQ_FIRST(&hc->hc_req_args))
+ goto error;
+
+ if (hc->hc_session) {
+ pthread_mutex_lock(&rtsp_lock);
+ TAILQ_FOREACH(rs, &rtsp_sessions, link)
+ if (rs->stream == stream)
+ break;
+ if (rs) {
+ rtsp_describe_header(rs, &q);
+ rtsp_describe_session(rs, &q);
+ }
+ pthread_mutex_unlock(&rtsp_lock);
+ if (rs == NULL) {
+ http_error(hc, HTTP_STATUS_BAD_SESSION);
+ return 0;
+ }
+ } else {
+ pthread_mutex_lock(&rtsp_lock);
+ rtsp_describe_header(NULL, &q);
+ TAILQ_FOREACH(rs, &rtsp_sessions, link)
+ rtsp_describe_session(rs, &q);
+ pthread_mutex_unlock(&rtsp_lock);
+ }
+ http_arg_init(&args);
+ if (hc->hc_session)
+ http_arg_set(&args, "Session", hc->hc_session);
+ if (stream > 0)
+ snprintf(buf, sizeof(buf), "rtsp://%s/stream=%i", rtsp_ip, stream);
+ else
+ snprintf(buf, sizeof(buf), "rtsp://%s", rtsp_ip);
+ http_arg_set(&args, "Content-Base", buf);
+ http_send_header(hc, HTTP_STATUS_OK, "application/sdp", q.hq_size,
+ NULL, NULL, 0, NULL, NULL, &args);
+ tcp_write_queue(hc->hc_fd, &q);
+ http_arg_flush(&args);
+ htsbuf_queue_flush(&q);
+ return 0;
+
+error:
+ htsbuf_queue_flush(&q);
+ http_error(hc, HTTP_STATUS_BAD_REQUEST);
+ return 0;
+}
+
/*
*
*/
switch (hc->hc_cmd) {
case RTSP_CMD_OPTIONS:
return rtsp_process_options(hc);
+ case RTSP_CMD_DESCRIBE:
+ return rtsp_process_describe(hc);
case RTSP_CMD_SETUP:
case RTSP_CMD_PLAY:
return rtsp_process_play(hc, hc->hc_cmd == RTSP_CMD_SETUP);
rtsp_close_session(session_t *rs)
{
satip_rtp_close((void *)(intptr_t)rs->stream);
- rs->stream = 0;
rs->run = 0;
udp_close(rs->udp_rtp);
rs->udp_rtp = NULL;