SAT>IP server: implement DESCRIBE RTSP command

This commit is contained in:
Jaroslav Kysela 2015-03-11 21:26:33 +01:00
parent be3749f45c
commit c66213c745
3 changed files with 205 additions and 16 deletions

View file

@ -18,6 +18,7 @@
*/
#include <signal.h>
#include <ctype.h>
#include "tvheadend.h"
#include "input.h"
#include "streaming.h"
@ -148,7 +149,9 @@ found:
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 *
@ -304,12 +307,35 @@ void satip_rtp_close(void *id)
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 "";
}
}
/*
*
*/
@ -332,19 +358,19 @@ satip_rtcp_fec(int fec)
*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;
@ -370,10 +396,10 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
}
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:
@ -398,11 +424,11 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
/* 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),
@ -452,7 +478,7 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
/* 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,
@ -478,7 +504,7 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
/* 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,
@ -490,7 +516,44 @@ satip_rtcp_build(satip_rtp_session_t *rtp, uint8_t *msg)
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)

View file

@ -366,7 +366,8 @@ rtsp_process_options(http_connection_t *hc)
}
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;
@ -376,6 +377,129 @@ error:
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;
}
/*
*
*/
@ -925,6 +1049,8 @@ 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_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);
@ -972,7 +1098,6 @@ static void
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;

View file

@ -42,6 +42,7 @@ void satip_rtp_update(void *id, th_subscription_t *subs,
dvb_mux_conf_t *dmc,
mpegts_apids_t *pids);
void satip_rtp_update_pids(void *id, mpegts_apids_t *pids);
int satip_rtp_status(void *id, char *buf, int len);
void satip_rtp_close(void *id);
void satip_rtp_init(void);