From: Jaroslav Kysela Date: Wed, 7 Oct 2015 13:37:59 +0000 (+0200) Subject: SAT>IP client: add RTSP/TCP support, fixes #3092 X-Git-Tag: v4.2.1~1967 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=443c2871092c735dd945b85b9453c34ea91092c1;p=thirdparty%2Ftvheadend.git SAT>IP client: add RTSP/TCP support, fixes #3092 --- diff --git a/src/http.h b/src/http.h index e494ab9f4..2759f6d75 100644 --- a/src/http.h +++ b/src/http.h @@ -302,6 +302,7 @@ struct http_client { int hc_reconnected:1; int hc_keepalive:1; int hc_in_data:1; + int hc_in_rtp_data:1; int hc_chunked:1; int hc_chunk_trails:1; int hc_running:1; @@ -319,6 +320,8 @@ struct http_client { char *hc_rtp_dest; int hc_rtp_port; int hc_rtpc_port; + int hc_rtp_tcp; + int hc_rtcp_tcp; int hc_rtcp_server_port; int hc_rtp_multicast:1; long hc_rtsp_stream_id; @@ -334,6 +337,8 @@ struct http_client { int (*hc_hdr_received) (http_client_t *hc); int (*hc_data_received)(http_client_t *hc, void *buf, size_t len); int (*hc_data_complete)(http_client_t *hc); + int (*hc_rtp_data_received)(http_client_t *hc, void *buf, size_t len); + int (*hc_rtp_data_complete)(http_client_t *hc); void (*hc_conn_closed) (http_client_t *hc, int err); }; diff --git a/src/httpc.c b/src/httpc.c index f9dd15a39..594bb2b6a 100644 --- a/src/httpc.c +++ b/src/httpc.c @@ -209,6 +209,7 @@ http_client_flush( http_client_t *hc, int result ) if (result < 0) http_client_shutdown(hc, 0, 0); hc->hc_in_data = 0; + hc->hc_in_rtp_data = 0; hc->hc_hsize = 0; hc->hc_csize = 0; hc->hc_rpos = 0; @@ -642,7 +643,11 @@ http_client_finish( http_client_t *hc ) tvhtrace("httpc", "%04X: received %s data", shortid(hc), http_ver2str(hc->hc_version)); tvhlog_hexdump("httpc", hc->hc_data, hc->hc_csize); } - if (hc->hc_data_complete) { + if (hc->hc_in_rtp_data && hc->hc_rtp_data_complete) { + res = hc->hc_rtp_data_complete(hc); + if (res < 0) + return http_client_flush(hc, res); + } else if (hc->hc_data_complete) { res = hc->hc_data_complete(hc); if (res < 0) return http_client_flush(hc, res); @@ -863,7 +868,7 @@ http_client_run( http_client_t *hc ) char *buf, *saveptr, *argv[3], *d, *p; int ver, res, delimsize = 4; ssize_t r; - size_t len; + size_t len, limit; if (hc == NULL) return 0; @@ -891,9 +896,10 @@ http_client_run( http_client_t *hc ) } buf = alloca(hc->hc_io_size); - - if (!hc->hc_in_data && hc->hc_rpos > 3) { - if ((d = strstr(hc->hc_rbuf, "\r\n\r\n")) != NULL) + if (!hc->hc_in_data && !hc->hc_in_rtp_data && hc->hc_rpos > 3) { + if (hc->hc_version == RTSP_VERSION_1_0 && hc->hc_rbuf[0] == '$') + goto rtsp_data; + else if ((d = strstr(hc->hc_rbuf, "\r\n\r\n")) != NULL) goto header; if ((d = strstr(hc->hc_rbuf, "\n\n")) != NULL) { delimsize = 2; @@ -906,7 +912,6 @@ retry: r = http_client_ssl_recv(hc, buf, hc->hc_io_size); else r = recv(hc->hc_fd, buf, hc->hc_io_size, MSG_DONTWAIT); - tvhtrace("httpc", "%04X: recv %zi", shortid(hc), r); if (r == 0) { if (hc->hc_in_data && !hc->hc_keepalive) return http_client_finish(hc); @@ -920,11 +925,12 @@ retry: return http_client_flush(hc, -errno); } if (r > 0 && tvhtrace_enabled()) { - tvhtrace("httpc", "%04X: received %s answer", shortid(hc), http_ver2str(hc->hc_version)); - tvhlog_hexdump("httpc", buf, r); + tvhtrace("httpc", "%04X: received %s answer (len = %zd)", shortid(hc), http_ver2str(hc->hc_version), r); + tvhlog_hexdump("httpc", buf, MIN(64, r)); } - if (hc->hc_in_data) { + limit = hc->hc_version == RTSP_VERSION_1_0 ? hc->hc_io_size * 2 : 16*1024; + if (hc->hc_in_data && !hc->hc_in_rtp_data) { res = http_client_data_received(hc, buf, r, 0); if (res < 0) return http_client_flush(hc, res); @@ -936,7 +942,7 @@ retry: } if (hc->hc_rsize < r + hc->hc_rpos) { - if (hc->hc_rsize + r > 16*1024) + if (hc->hc_rsize + r > limit) return http_client_flush(hc, -EMSGSIZE); hc->hc_rsize += r; hc->hc_rbuf = realloc(hc->hc_rbuf, hc->hc_rsize + 1); @@ -948,6 +954,8 @@ retry: next_header: if (hc->hc_rpos < 3) return HTTP_CON_RECEIVING; + if (hc->hc_version == RTSP_VERSION_1_0 && hc->hc_rbuf[0] == '$') + goto rtsp_data; if ((d = strstr(hc->hc_rbuf, "\r\n\r\n")) == NULL) { delimsize = 2; if ((d = strstr(hc->hc_rbuf, "\n\n")) == NULL) @@ -983,6 +991,7 @@ header: if (res < 0) return http_client_flush(hc, -EINVAL); } + tvhtrace("httpc", "header parse1"); p = http_arg_get(&hc->hc_args, "Content-Length"); if (p) { hc->hc_csize = atoll(p); @@ -1011,16 +1020,19 @@ header: if (res < 0) return http_client_flush(hc, res); } - hc->hc_rpos -= hc->hc_hsize; - len = hc->hc_rpos; + len = hc->hc_rpos - hc->hc_hsize; + hc->hc_rpos = 0; if (hc->hc_code == HTTP_STATUS_CONTINUE) { memmove(hc->hc_rbuf, hc->hc_rbuf + hc->hc_hsize, len); + hc->hc_rpos = len; goto next_header; } - hc->hc_rpos = 0; if (hc->hc_version == RTSP_VERSION_1_0 && !hc->hc_csize) { hc->hc_csize = -1; hc->hc_in_data = 0; + memmove(hc->hc_rbuf, hc->hc_rbuf + hc->hc_hsize, len); + hc->hc_rpos = len; + return http_client_finish(hc); } else { hc->hc_in_data = 1; } @@ -1030,6 +1042,47 @@ header: if (res > 0) return http_client_finish(hc); goto retry; + +rtsp_data: + /* RTSP embedded data */ + r = 0; + res = HTTP_CON_RECEIVING; + hc->hc_in_data = 0; + hc->hc_in_rtp_data = 0; + while (hc->hc_rpos > r + 3) { + hc->hc_csize = 4 + ((hc->hc_rbuf[r+2] << 8) | hc->hc_rbuf[r+3]); + hc->hc_chunked = 0; + if (r + hc->hc_csize > hc->hc_rpos) { + memmove(hc->hc_rbuf, hc->hc_rbuf + r, hc->hc_rpos - r); + hc->hc_rpos -= r; + hc->hc_in_rtp_data = 1; + if (r == 0) + goto retry; + return HTTP_CON_RECEIVING; + } + if (hc->hc_rtp_data_received) { + res = hc->hc_rtp_data_received(hc, hc->hc_rbuf + r, hc->hc_csize); + if (res < 0) + return res; + } else { + res = 0; + } + r += hc->hc_csize; + if (res < 0) + return http_client_flush(hc, res); + hc->hc_in_rtp_data = 1; + res = http_client_finish(hc); + hc->hc_in_rtp_data = 0; + if (res < 0) + return http_client_flush(hc, res); + res = HTTP_CON_RECEIVING; + if (hc->hc_rpos < r + 4 || hc->hc_rbuf[r] != '$') { + memcpy(hc->hc_rbuf, hc->hc_rbuf + r, hc->hc_rpos - r); + hc->hc_rpos -= r; + goto next_header; + } + } + return res; } /* diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 25ab51bfa..f76bb8bb4 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -906,7 +906,7 @@ static inline void tsdebug_write(mpegts_mux_t *mm, uint8_t *buf, size_t len) { #if ENABLE_TSDEBUG - if (mm->mm_tsdebug_fd2 >= 0) + if (mm && mm->mm_tsdebug_fd2 >= 0) if (write(mm->mm_tsdebug_fd2, buf, len) != len) tvherror("tsdebug", "unable to write input data (%i)", errno); #endif diff --git a/src/input/mpegts/satip/satip.c b/src/input/mpegts/satip/satip.c index b559ea0cd..a73577352 100644 --- a/src/input/mpegts/satip/satip.c +++ b/src/input/mpegts/satip/satip.c @@ -206,6 +206,13 @@ const idclass_t satip_device_class = .notify = satip_device_class_tunercfg_notify, .def.s = "Auto" }, + { + .type = PT_BOOL, + .id = "tcp_mode", + .name = N_("RTSP/TCP (embedded data)"), + .opts = PO_ADVANCED, + .off = offsetof(satip_device_t, sd_tcp_mode), + }, { .type = PT_BOOL, .id = "fast_switch", diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index 1e9ab8843..8e8074dfe 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -849,9 +849,9 @@ satip_frontend_extra_shutdown efd = tvhpoll_create(1); rtsp = http_client_connect(lfe, RTSP_VERSION_1_0, "rstp", - lfe->sf_device->sd_info.addr, - lfe->sf_device->sd_info.rtsp_port, - satip_frontend_bindaddr(lfe)); + lfe->sf_device->sd_info.addr, + lfe->sf_device->sd_info.rtsp_port, + satip_frontend_bindaddr(lfe)); if (rtsp == NULL) goto done; @@ -968,6 +968,82 @@ satip_frontend_close_rtsp *rtsp = NULL; } +static int +satip_frontend_rtp_data_received( http_client_t *hc, void *buf, size_t len ) +{ + int c, pos; + uint32_t nseq, unc; + uint8_t *b = buf, *p; + satip_frontend_t *lfe = hc->hc_aux; + mpegts_mux_instance_t *mmi; + + if (len < 4) + return -EINVAL; + + if (b[1] == 0) { + + p = b + 4; + c = len - 4; + + /* Strip RTP header */ + if (c < 12) + return 0; + if ((p[0] & 0xc0) != 0x80) + return 0; + if ((p[1] & 0x7f) != 33) + return 0; + pos = ((p[0] & 0x0f) * 4) + 12; + if (p[0] & 0x10) { + if (c < pos + 4) + return 0; + pos += (((p[pos+2] << 8) | p[pos+3]) + 1) * 4; + } + if (c <= pos || ((c - pos) % 188) != 0) + return 0; + /* Use uncorrectable value to notify RTP delivery issues */ + nseq = (p[2] << 8) | p[3]; + unc = 0; + if (lfe->sf_seq == -1) + lfe->sf_seq = nseq; + else if (((lfe->sf_seq + 1) & 0xffff) != nseq) { + unc = ((c - pos) / 188) * (uint32_t)((uint16_t)nseq-(uint16_t)(lfe->sf_seq+1)); + tvhtrace("satip", "TCP/RTP discontinuity (%i != %i)", lfe->sf_seq + 1, nseq); + } + lfe->sf_seq = nseq; + + /* Process */ + tsdebug_write((mpegts_mux_t *)lfe->sf_curmux, p + pos, c - pos); + sbuf_append(&lfe->sf_sbuf, p + pos, c - pos); + + if (lfe->sf_sbuf.sb_ptr > 64 * 1024 || + lfe->sf_last_data_tstamp != dispatch_clock) { + pthread_mutex_lock(&lfe->sf_dvr_lock); + if (lfe->sf_req == lfe->sf_req_thread) { + mmi = lfe->sf_req->sf_mmi; + mmi->tii_stats.unc += unc; + mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi, + &lfe->sf_sbuf, NULL, NULL); + } + pthread_mutex_unlock(&lfe->sf_dvr_lock); + lfe->sf_last_data_tstamp = dispatch_clock; + } + + } else if (b[1] == 1) { + + /* note: satip_frontend_decode_rtcp puts '\0' at the end (string termination) */ + len -= 4; + memmove(b, b + 4, len); + + pthread_mutex_lock(&lfe->sf_dvr_lock); + if (lfe->sf_req == lfe->sf_req_thread) + satip_frontend_decode_rtcp(lfe, lfe->sf_display_name, + lfe->sf_req->sf_mmi, b, len); + pthread_mutex_unlock(&lfe->sf_dvr_lock); + + } + return 0; +} + static void * satip_frontend_input_thread ( void *aux ) { @@ -985,7 +1061,7 @@ satip_frontend_input_thread ( void *aux ) struct iovec *iovec; uint8_t b[2048], session[32]; uint8_t *p; - sbuf_t sb; + sbuf_t *sb; int pos, nfds, i, r, tc, rtp_port, start = 0; size_t c; tvhpoll_event_t ev[3]; @@ -1008,14 +1084,14 @@ satip_frontend_input_thread ( void *aux ) rtsp = NULL; /* Setup buffers */ - sbuf_init(&sb); + sbuf_init(sb = &lfe->sf_sbuf); udp_multirecv_init(&um, 0, 0); /* * New tune */ new_tune: - sbuf_free(&sb); + sbuf_free(sb); udp_multirecv_free(&um); udp_close(rtcp); udp_close(rtp); @@ -1025,6 +1101,9 @@ new_tune: if (rtsp && !lfe->sf_device->sd_fast_switch) satip_frontend_close_rtsp(lfe, efd, &rtsp); + if (rtsp) + rtsp->hc_rtp_data_received = NULL; + memset(ev, 0, sizeof(ev)); ev[0].events = TVHPOLL_IN; ev[0].fd = lfe->sf_dvr_pipe.rd; @@ -1032,6 +1111,7 @@ new_tune: tvhpoll_add(efd, ev, 1); lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf)); + lfe->sf_display_name = buf; while (!start) { @@ -1087,36 +1167,46 @@ new_tune: if (!lfe->sf_req_thread) goto new_tune; - mmi = tr->sf_mmi; - changing = 0; - ms = 500; - fatal = 0; - running = 1; - seq = -1; - play2 = 1; - rtsp_flags = 0; - - if (udp_bind_double(&rtp, &rtcp, - "satip", "rtp", "rtpc", - satip_frontend_bindaddr(lfe), lfe->sf_udp_rtp_port, - NULL, SATIP_BUF_SIZE, 16384, 4*1024, 4*1024) < 0) { - satip_frontend_tuning_error(lfe, tr); - goto done; - } + mmi = tr->sf_mmi; + changing = 0; + ms = 500; + fatal = 0; + running = 1; + seq = -1; + lfe->sf_seq = -1; + play2 = 1; + rtsp_flags = lfe->sf_device->sd_tcp_mode ? SATIP_SETUP_TCP : 0; + + if ((rtsp_flags & SATIP_SETUP_TCP) == 0) { + if (udp_bind_double(&rtp, &rtcp, + "satip", "rtp", "rtpc", + satip_frontend_bindaddr(lfe), lfe->sf_udp_rtp_port, + NULL, SATIP_BUF_SIZE, 16384, 4*1024, 4*1024) < 0) { + satip_frontend_tuning_error(lfe, tr); + goto done; + } - rtp_port = ntohs(IP_PORT(rtp->ip)); + rtp_port = ntohs(IP_PORT(rtp->ip)); - tvhtrace("satip", "%s - local RTP port %i RTCP port %i", - lfe->mi_name, - ntohs(IP_PORT(rtp->ip)), - ntohs(IP_PORT(rtcp->ip))); + tvhtrace("satip", "%s - local RTP port %i RTCP port %i", + lfe->mi_name, + ntohs(IP_PORT(rtp->ip)), + ntohs(IP_PORT(rtcp->ip))); - if (rtp == NULL || rtcp == NULL || mmi == NULL) { + if (rtp == NULL || rtcp == NULL) { + satip_frontend_tuning_error(lfe, tr); + goto done; + } + } else { + rtp_port = -1; + } + + if (mmi == NULL) { satip_frontend_tuning_error(lfe, tr); goto done; } - lm = (dvb_mux_t *)mmi->mmi_mux; + lfe->sf_curmux = lm = (dvb_mux_t *)mmi->mmi_mux; lfe_master = lfe; if (lfe->sf_master) @@ -1204,18 +1294,27 @@ new_tune: /* Setup poll */ memset(ev, 0, sizeof(ev)); - ev[0].events = TVHPOLL_IN; - ev[0].fd = rtp->fd; - ev[0].data.ptr = rtp; - ev[1].events = TVHPOLL_IN; - ev[1].fd = rtcp->fd; - ev[1].data.ptr = rtcp; + nfds = 0; + if ((rtsp_flags & SATIP_SETUP_TCP) == 0) { + ev[nfds].events = TVHPOLL_IN; + ev[nfds].fd = rtp->fd; + ev[nfds].data.ptr = rtp; + nfds++; + ev[nfds].events = TVHPOLL_IN; + ev[nfds].fd = rtcp->fd; + ev[nfds].data.ptr = rtcp; + nfds++; + } else { + rtsp->hc_io_size = 128 * 1024; + rtsp->hc_rtp_data_received = satip_frontend_rtp_data_received; + } if (i) { - ev[2].events = TVHPOLL_IN; - ev[2].fd = rtsp->hc_fd; - ev[2].data.ptr = rtsp; + ev[nfds].events = TVHPOLL_IN; + ev[nfds].fd = rtsp->hc_fd; + ev[nfds].data.ptr = rtsp; + nfds++; } - tvhpoll_add(efd, ev, i ? 3 : 2); + tvhpoll_add(efd, ev, nfds); rtsp->hc_efd = efd; position = lfe_master->sf_position; @@ -1244,7 +1343,7 @@ new_tune: reply = 1; udp_multirecv_init(&um, RTP_PKTS, RTP_PKT_SIZE); - sbuf_init_fixed(&sb, RTP_PKTS * RTP_PKT_SIZE); + sbuf_init_fixed(sb, RTP_PKTS * RTP_PKT_SIZE); while ((reply || running) && !fatal) { @@ -1322,8 +1421,11 @@ new_tune: r = rtsp_setup_decode(rtsp, 1); if (!running) break; - if (r < 0 || rtsp->hc_rtp_port != rtp_port || - rtsp->hc_rtpc_port != rtp_port + 1) { + if (r < 0 || ((rtsp_flags & SATIP_SETUP_TCP) == 0 && + (rtsp->hc_rtp_port != rtp_port || + rtsp->hc_rtpc_port != rtp_port + 1)) || + ((rtsp_flags & SATIP_SETUP_TCP) != 0 && + (rtsp->hc_rtp_tcp < 0 || rtsp->hc_rtcp_tcp < 0))) { tvhlog(LOG_ERR, "satip", "%s - RTSP SETUP error %d (%s) [%i-%i]", buf, r, strerror(-r), rtsp->hc_cmd, rtsp->hc_code); satip_frontend_tuning_error(lfe, tr); @@ -1450,13 +1552,13 @@ new_tune: seq = nseq; /* Process */ tsdebug_write((mpegts_mux_t *)lm, p + pos, c - pos); - sbuf_append(&sb, p + pos, c - pos); + sbuf_append(sb, p + pos, c - pos); } pthread_mutex_lock(&lfe->sf_dvr_lock); if (lfe->sf_req == lfe->sf_req_thread) { mmi->tii_stats.unc += unc; mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi, - &sb, NULL, NULL); + sb, NULL, NULL); } else fatal = 1; pthread_mutex_unlock(&lfe->sf_dvr_lock); @@ -1465,19 +1567,26 @@ new_tune: /* Do not send the SMT_SIGNAL_STATUS packets - we are out of service */ gtimer_disarm(&lfe->sf_monitor_timer); - sbuf_free(&sb); + sbuf_free(sb); udp_multirecv_free(&um); - - ev[0].events = TVHPOLL_IN; - ev[0].fd = rtp->fd; - ev[0].data.ptr = rtp; - ev[1].events = TVHPOLL_IN; - ev[1].fd = rtcp->fd; - ev[1].data.ptr = rtcp; - ev[2].events = TVHPOLL_IN; - ev[2].fd = lfe->sf_dvr_pipe.rd; - ev[2].data.ptr = NULL; - tvhpoll_rem(efd, ev, 3); + lfe->sf_curmux = NULL; + + nfds = 0; + if ((rtsp_flags & SATIP_SETUP_TCP) == 0) { + ev[nfds].events = TVHPOLL_IN; + ev[nfds].fd = rtp->fd; + ev[nfds].data.ptr = rtp; + nfds++; + ev[nfds].events = TVHPOLL_IN; + ev[nfds].fd = rtcp->fd; + ev[nfds].data.ptr = rtcp; + nfds++; + } + ev[nfds].events = TVHPOLL_IN; + ev[nfds].fd = lfe->sf_dvr_pipe.rd; + ev[nfds].data.ptr = NULL; + nfds++; + tvhpoll_rem(efd, ev, nfds); if (exit_flag) { satip_frontend_shutdown(rtsp, efd); @@ -1512,6 +1621,8 @@ done: http_client_close(rtsp); tvhpoll_destroy(efd); + lfe->sf_display_name = NULL; + lfe->sf_curmux = NULL; return NULL; #undef PKTS } diff --git a/src/input/mpegts/satip/satip_private.h b/src/input/mpegts/satip/satip_private.h index fc6b90523..097f5728b 100644 --- a/src/input/mpegts/satip/satip_private.h +++ b/src/input/mpegts/satip/satip_private.h @@ -20,6 +20,7 @@ #ifndef __TVH_SATIP_PRIVATE_H__ #define __TVH_SATIP_PRIVATE_H__ +#include "tvheadend.h" #include "input.h" #include "htsbuf.h" #include "udp.h" @@ -79,6 +80,7 @@ struct satip_device * RTSP */ char *sd_bindaddr; + int sd_tcp_mode; int sd_fast_switch; int sd_fullmux_ok; int sd_pids_max; @@ -142,6 +144,11 @@ struct satip_frontend uint64_t sf_last_tune; satip_tune_req_t *sf_req; satip_tune_req_t *sf_req_thread; + sbuf_t sf_sbuf; + const char * sf_display_name; + uint32_t sf_seq; + dvb_mux_t *sf_curmux; + time_t sf_last_data_tstamp; /* * Configuration @@ -225,10 +232,11 @@ int satip_satconf_get_position * RTSP part */ -#define SATIP_SETUP_PLAY (1<<0) -#define SATIP_SETUP_PIDS0 (1<<1) -#define SATIP_SETUP_PILOT_ON (1<<2) -#define SATIP_SETUP_PIDS21 (1<<3) +#define SATIP_SETUP_TCP (1<<0) +#define SATIP_SETUP_PLAY (1<<1) +#define SATIP_SETUP_PIDS0 (1<<2) +#define SATIP_SETUP_PILOT_ON (1<<3) +#define SATIP_SETUP_PIDS21 (1<<4) int satip_rtsp_setup( http_client_t *hc, diff --git a/src/input/mpegts/satip/satip_rtsp.c b/src/input/mpegts/satip/satip_rtsp.c index a5ffef4ba..10b99ff10 100644 --- a/src/input/mpegts/satip/satip_rtsp.c +++ b/src/input/mpegts/satip/satip_rtsp.c @@ -232,6 +232,8 @@ satip_rtsp_setup( http_client_t *hc, int src, int fe, hc->hc_rtsp_stream_id); if (flags & SATIP_SETUP_PLAY) return rtsp_play(hc, stream, buf); + if (flags & SATIP_SETUP_TCP) + return rtsp_setup(hc, stream, buf, NULL, 0, -1); return rtsp_setup(hc, stream, buf, NULL, udp_port, udp_port + 1); } diff --git a/src/rtsp.c b/src/rtsp.c index 4f706f94b..489afe9b2 100644 --- a/src/rtsp.c +++ b/src/rtsp.c @@ -145,41 +145,67 @@ rtsp_setup_decode( http_client_t *hc, int satip ) if (p == NULL) return -EIO; n = http_tokenize(p, argv, 32, ';'); - if (n < 3) + if (n < 2) return -EIO; - if (strcasecmp(argv[0], "RTP/AVP")) - return -EIO; - hc->hc_rtp_multicast = strcasecmp(argv[1], "multicast") == 0; - if (strcasecmp(argv[1], "unicast") && !hc->hc_rtp_multicast) - return -EIO; - for (i = 2; i < n; i++) { - if (strncmp(argv[i], "destination=", 12) == 0) - hc->hc_rtp_dest = strdup(argv[i] + 12); - else if (strncmp(argv[i], "client_port=", 12) == 0) { - j = http_tokenize(argv[i] + 12, argv2, 2, '-'); - if (j > 0) { - hc->hc_rtp_port = atoi(argv2[0]); - if (hc->hc_rtp_port <= 0) - return -EIO; - if (j > 1) { - hc->hc_rtpc_port = atoi(argv2[1]); - if (hc->hc_rtpc_port <= 0) + hc->hc_rtp_tcp = -1; + hc->hc_rtcp_tcp = -1; + hc->hc_rtp_port = -1; + hc->hc_rtpc_port = -1; + if (!strcasecmp(argv[0], "RTP/AVP/TCP")) { + for (i = 1; i < n; i++) { + if (strncmp(argv[i], "interleaved=", 12) == 0) { + j = http_tokenize(argv[i] + 12, argv2, 2, '-'); + if (j > 0) { + hc->hc_rtp_tcp = atoi(argv2[0]); + if (hc->hc_rtp_tcp < 0) return -EIO; + if (j > 1) { + hc->hc_rtcp_tcp = atoi(argv2[1]); + if (hc->hc_rtcp_tcp < 0) + return -EIO; + } + } else { + return -EIO; } - } else { - return -EIO; } } - else if (strncmp(argv[i], "server_port=", 12) == 0) { - j = http_tokenize(argv[i] + 12, argv2, 2, '-'); - if (j > 1) { - hc->hc_rtcp_server_port = atoi(argv2[1]); - if (hc->hc_rtcp_server_port <= 0) + } else if (!strcasecmp(argv[0], "RTP/AVP")) { + if (n < 3) + return -EIO; + hc->hc_rtp_multicast = strcasecmp(argv[1], "multicast") == 0; + if (strcasecmp(argv[1], "unicast") && !hc->hc_rtp_multicast) + return -EIO; + for (i = 2; i < n; i++) { + if (strncmp(argv[i], "destination=", 12) == 0) + hc->hc_rtp_dest = strdup(argv[i] + 12); + else if (strncmp(argv[i], "client_port=", 12) == 0) { + j = http_tokenize(argv[i] + 12, argv2, 2, '-'); + if (j > 0) { + hc->hc_rtp_port = atoi(argv2[0]); + if (hc->hc_rtp_port <= 0) + return -EIO; + if (j > 1) { + hc->hc_rtpc_port = atoi(argv2[1]); + if (hc->hc_rtpc_port <= 0) + return -EIO; + } + } else { return -EIO; - } else { - return -EIO; + } + } + else if (strncmp(argv[i], "server_port=", 12) == 0) { + j = http_tokenize(argv[i] + 12, argv2, 2, '-'); + if (j > 1) { + hc->hc_rtcp_server_port = atoi(argv2[1]); + if (hc->hc_rtcp_server_port <= 0) + return -EIO; + } else { + return -EIO; + } } } + } else { + return -EIO; } return HTTP_CON_OK; } @@ -193,7 +219,10 @@ rtsp_setup( http_client_t *hc, http_arg_list_t h; char transport[256]; - if (multicast_addr) { + if (rtpc_port < 0) { + snprintf(transport, sizeof(transport), + "RTP/AVP/TCP;interleaved=%d-%d", rtp_port, rtp_port + 1); + } else if (multicast_addr) { snprintf(transport, sizeof(transport), "RTP/AVP;multicast;destination=%s;ttl=1;client_port=%i-%i", multicast_addr, rtp_port, rtpc_port);