From c66213c745bcd26478208fda2cf4bfda254eb660 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 11 Mar 2015 21:26:33 +0100 Subject: [PATCH] SAT>IP server: implement DESCRIBE RTSP command --- src/satip/rtp.c | 91 +++++++++++++++++++++++++++----- src/satip/rtsp.c | 129 ++++++++++++++++++++++++++++++++++++++++++++- src/satip/server.h | 1 + 3 files changed, 205 insertions(+), 16 deletions(-) diff --git a/src/satip/rtp.c b/src/satip/rtp.c index 6571cb1f..0397b90e 100644 --- a/src/satip/rtp.c +++ b/src/satip/rtp.c @@ -18,6 +18,7 @@ */ #include +#include #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=.;src=;tuner=,,,,,,\ * ,,,,,;pids=,..., */ - 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=,,,,,,,,,,\ * ,,,;pids=,..., */ - 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=,,,,,,,,,,,, * ;pids=,..., */ - 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) diff --git a/src/satip/rtsp.c b/src/satip/rtsp.c index 0ab2f24d..3f0599ae 100644 --- a/src/satip/rtsp.c +++ b/src/satip/rtsp.c @@ -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; diff --git a/src/satip/server.h b/src/satip/server.h index 38fcd049..68b1c712 100644 --- a/src/satip/server.h +++ b/src/satip/server.h @@ -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);