From c4adde611fe82368bf3aef4c01edb71cb0631b8d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 13 Mar 2015 23:59:31 +0100 Subject: [PATCH] SAT>IP Server: fixed issues for the Elgato SAT>IP Android app --- src/http.c | 19 ++++++---- src/satip/rtp.c | 8 +++-- src/satip/rtsp.c | 89 +++++++++++++++++++++++++++------------------- src/satip/server.c | 40 +++++++++++---------- 4 files changed, 92 insertions(+), 64 deletions(-) diff --git a/src/http.c b/src/http.c index 9f1f8cca..ec0bbecd 100644 --- a/src/http.c +++ b/src/http.c @@ -949,6 +949,8 @@ http_parse_get_args(http_connection_t *hc, char *args) { char *k, *v; + if (args && *args == '&') + args++; while(args) { k = args; if((args = strchr(args, '=')) == NULL) @@ -1008,13 +1010,18 @@ http_serve_requests(http_connection_t *hc) goto error; if(!*hdrline) - break; /* header complete */ + break; /* header complete */ - if((n = http_tokenize(hdrline, argv, 2, -1)) < 2) - continue; - - if((c = strrchr(argv[0], ':')) == NULL) - goto error; + if((n = http_tokenize(hdrline, argv, 2, -1)) < 2) { + if ((c = strchr(hdrline, ':')) != NULL) { + *c = '\0'; + argv[0] = hdrline; + argv[1] = c + 1; + } else { + continue; + } + } else if((c = strrchr(argv[0], ':')) == NULL) + goto error; *c = 0; http_arg_set(&hc->hc_args, argv[0], argv[1]); diff --git a/src/satip/rtp.c b/src/satip/rtp.c index ef372578..d1c39fd2 100644 --- a/src/satip/rtp.c +++ b/src/satip/rtp.c @@ -48,6 +48,7 @@ typedef struct satip_rtp_session { int um_packet; uint16_t seq; signal_status_t sig; + int sig_lock; pthread_mutex_t lock; } satip_rtp_session_t; @@ -114,6 +115,8 @@ satip_rtp_loop(satip_rtp_session_t *rtp, uint8_t *data, int len) struct iovec *v = rtp->um_iovec + rtp->um_packet; assert((len % 188) == 0); + if (len > 0) + rtp->sig_lock = 1; for ( ; len >= 188 ; data += 188, len -= 188) { pid = ((data[1] & 0x1f) << 8) | data[2]; if (pid != last_pid && !rtp->pids.all) { @@ -372,8 +375,7 @@ satip_status_build(satip_rtp_session_t *rtp, char *buf, int len) const char *bw, *tmode, *gi, *plp, *t2id, *sm, *c2tft, *ds, *specinv; int i, j, r, level = 0, lock = 0, quality = 0; - if (rtp->sig.snr > 0) - lock = 1; + lock = rtp->sig_lock; switch (rtp->sig.signal_scale) { case SIGNAL_STATUS_SCALE_RELATIVE: level = MIN(240, MAX(0, (rtp->sig.signal * 245) / 0xffff)); @@ -382,6 +384,7 @@ satip_status_build(satip_rtp_session_t *rtp, char *buf, int len) level = MIN(240, MAX(0, (rtp->sig.signal + 90000) / 375)); break; default: + level = lock ? 10 : 0; break; } switch (rtp->sig.snr_scale) { @@ -392,6 +395,7 @@ satip_status_build(satip_rtp_session_t *rtp, char *buf, int len) quality = MIN(15, MAX(0, (rtp->sig.snr / 2000))); break; default: + quality = lock ? 1 : 0; break; } diff --git a/src/satip/rtsp.c b/src/satip/rtsp.c index 390b0773..f57df44d 100644 --- a/src/satip/rtsp.c +++ b/src/satip/rtsp.c @@ -300,6 +300,10 @@ rtsp_clean(session_t *rs) { slave_subscription_t *sub; + if (rs->run) { + satip_rtp_close((void *)(intptr_t)rs->stream); + rs->run = 0; + } if (rs->subs) { while ((sub = LIST_FIRST(&rs->slaves)) != NULL) rtsp_slave_remove(rs, (mpegts_service_t *)rs->subs->ths_service, @@ -321,6 +325,7 @@ rtsp_clean(session_t *rs) static int rtsp_validate_service(mpegts_service_t *s) { + int av = 0, enc = 0; elementary_stream_t *st; pthread_mutex_lock(&s->s_stream_mutex); @@ -328,12 +333,15 @@ rtsp_validate_service(mpegts_service_t *s) pthread_mutex_unlock(&s->s_stream_mutex); return 0; } - TAILQ_FOREACH(st, &s->s_components, es_link) + TAILQ_FOREACH(st, &s->s_components, es_link) { + if (st->es_type == SCT_CA) + enc = 1; if (st->es_pid > 0 && (SCT_ISVIDEO(st->es_type) || SCT_ISAUDIO(st->es_type))) - break; + av = 1; + } pthread_mutex_unlock(&s->s_stream_mutex); - return st != NULL; + return enc && av; } /* @@ -398,7 +406,8 @@ end: */ static int rtsp_start - (http_connection_t *hc, session_t *rs, char *addrbuf, int newmux, int setup) + (http_connection_t *hc, session_t *rs, char *addrbuf, + int newmux, int setup, int oldrun) { mpegts_network_t *mn, *mn2; dvb_network_t *ln; @@ -422,22 +431,24 @@ rtsp_start } } if (mux == NULL && mn2) { + dvb_mux_conf_str(&rs->dmc, buf, sizeof(buf)); + tvhwarn("satips", "%i/%s/%i: create mux %s", + rs->frontend, rs->session, rs->stream, buf); mux = (dvb_mux_t *) mn2->mn_create_mux(mn2, (void *)(intptr_t)rs->nsession, MPEGTS_ONID_NONE, MPEGTS_TSID_NONE, - &rs->dmc, 0); + &rs->dmc, 1); if (mux) created = 1; } if (mux == NULL) { dvb_mux_conf_str(&rs->dmc, buf, sizeof(buf)); - tvhwarn("satips", "%i: unable to create mux %s", rs->frontend, buf); + tvhwarn("satips", "%i/%s/%i: unable to create mux %s", + rs->frontend, rs->session, rs->stream, 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; @@ -452,9 +463,9 @@ rtsp_start http_arg_get(&hc->hc_args, "User-Agent"), NULL); if (!rs->subs) - goto endrtp; - if (rs->run) { - /* restart streaming */ + goto endclean; + /* retrigger play when new setup arrived */ + if (oldrun) { setup = 0; rs->run = 0; } @@ -466,7 +477,7 @@ pids: } if (!setup && !rs->run) { if (rs->mux == NULL) - goto endrtp; + goto endclean; satip_rtp_queue((void *)(intptr_t)rs->stream, rs->subs, &rs->prch.prch_sq, hc->hc_peer, rs->rtp_peer_port, @@ -481,9 +492,6 @@ pids: pthread_mutex_unlock(&global_lock); return 0; -endrtp: - satip_rtp_close((void *)(intptr_t)rs->stream); - rs->run = 0; endclean: rtsp_clean(rs); pthread_mutex_unlock(&global_lock); @@ -598,7 +606,7 @@ rtsp_process_describe(http_connection_t *hc) session_t *rs; htsbuf_queue_t q; char buf[96]; - int stream; + int stream, first = 1; htsbuf_queue_init(&q, 0); @@ -614,27 +622,30 @@ rtsp_process_describe(http_connection_t *hc) 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_lock(&rtsp_lock); + TAILQ_FOREACH(rs, &rtsp_sessions, link) { + if (hc->hc_session) { + if (strcmp(hc->hc_session, rs->session)) + continue; + if (stream > 0 && rs->stream != stream) + continue; } - pthread_mutex_unlock(&rtsp_lock); - if (rs == NULL) { + if (first) { + rtsp_describe_header(hc->hc_session ? rs : NULL, &q); + first = 0; + } + rtsp_describe_session(rs, &q); + } + pthread_mutex_unlock(&rtsp_lock); + + if (first) { + if (hc->hc_session) { 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); @@ -875,7 +886,7 @@ static int rtsp_process_play(http_connection_t *hc, int setup) { session_t *rs; - int errcode = HTTP_STATUS_BAD_REQUEST, r, findex = 0, valid; + int errcode = HTTP_STATUS_BAD_REQUEST, r, findex = 0, valid, oldrun = 0; 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; @@ -922,19 +933,22 @@ rtsp_process_play(http_connection_t *hc, int setup) delsys = rtsp_delsys(fe, &findex); if (delsys == DVB_SYS_NONE) goto error; + } else { + delsys = msys; } if (setup) { if (delsys == DVB_SYS_NONE) goto error; if (msys == DVB_SYS_NONE) goto error; - if (!fe) goto error; if (!valid) 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 + else { + oldrun = rs->run; rtsp_close_session(rs); + } r = parse_transport(hc); if (r < 0) { errcode = HTTP_STATUS_BAD_TRANSFER; @@ -944,7 +958,7 @@ rtsp_process_play(http_connection_t *hc, int setup) errcode = HTTP_STATUS_METHOD_INVALID; goto error; } - rs->frontend = fe; + rs->frontend = fe > 0 ? fe : 1; rs->rtp_peer_port = r; dmc = &rs->dmc; } else { @@ -953,6 +967,7 @@ rtsp_process_play(http_connection_t *hc, int setup) errcode = HTTP_STATUS_NOT_FOUND; goto error; } + oldrun = rs->run; dmc = &rs->dmc; if (rs->mux == NULL) goto error; if (!fe) { @@ -1106,13 +1121,13 @@ play: mpegts_pid_del_group(&rs->pids, &delpids); if (addpids.count > 0) mpegts_pid_add_group(&rs->pids, &addpids); - if ((r = rtsp_start(hc, rs, addrbuf, valid, setup)) < 0) { + if ((r = rtsp_start(hc, rs, addrbuf, valid, setup, oldrun)) < 0) { errcode = r; goto error; } if (setup) - tvhdebug("satips", "%i/%s/%d: setup from %s:%d, RTP: %d, RTCP: %d, pids ", + tvhdebug("satips", "%i/%s/%d: setup from %s:%d, RTP: %d, RTCP: %d", rs->frontend, rs->session, rs->stream, addrbuf, IP_PORT(*hc->hc_peer), rs->rtp_peer_port, rs->rtp_peer_port + 1); diff --git a/src/satip/server.c b/src/satip/server.c index 24d96bed..150c11bc 100644 --- a/src/satip/server.c +++ b/src/satip/server.c @@ -60,11 +60,10 @@ satip_server_http_xml(http_connection_t *hc) http://tvheadend.org\n\ TVHeadend %s\n\ TVHeadend SAT>IP\n\ -1\n\ -http://tvheadend.org\n\ +1.0\n\ +\n\ 123456\n\ uuid:%s\n\ -TVHeadend %s\n\ \n\ \n\ image/png\n\ @@ -74,7 +73,7 @@ satip_server_http_xml(http_connection_t *hc) http://%s:%d/static/satip-icon40.png\n\ \n\ \n\ -image/jpg\n\ +image/jpeg\n\ 40\n\ 40\n\ 16\n\ @@ -88,7 +87,7 @@ satip_server_http_xml(http_connection_t *hc) http://%s:%d/static/satip-icon120.png\n\ \n\ \n\ -image/jpg\n\ +image/jpeg\n\ 120\n\ 120\n\ 16\n\ @@ -100,7 +99,7 @@ satip_server_http_xml(http_connection_t *hc) \n\ \n" - char buf[sizeof(MSG) + 1024], buf2[16]; + char buf[sizeof(MSG) + 1024], buf2[64]; char *devicelist = NULL; htsbuf_queue_t q; mpegts_network_t *mn; @@ -122,18 +121,18 @@ satip_server_http_xml(http_connection_t *hc) } else if (idnode_is_instance(&mn->mn_id, &dvb_network_dvbc_class)) dvbc++; } - if (dvbt && (i = config_get_int("satip_dvbt", 0)) > 0) { - htsbuf_qprintf(&q, "DVBT-%d", i); - delim++; - } else { - dvbt = 0; - } if (dvbs && (i = config_get_int("satip_dvbs", 0)) > 0) { htsbuf_qprintf(&q, "%sDVBS2-%d", delim ? "," : "", i); delim++; } else { dvbs = 0; } + if (dvbt && (i = config_get_int("satip_dvbt", 0)) > 0) { + htsbuf_qprintf(&q, "%sDVBT-%d", delim ? "," : "", i); + delim++; + } else { + dvbt = 0; + } if (dvbc && (i = config_get_int("satip_dvbc", 0)) > 0) { htsbuf_qprintf(&q, "%sDVBC-%d", delim ? "," : "", i); delim++; @@ -153,13 +152,14 @@ satip_server_http_xml(http_connection_t *hc) buf, dvbt + dvbs + dvbc ? "tuner settings - global config" : "network assignment"); } - buf2[0] = '\0'; if (satip_server_rtsp_port != 554) - snprintf(buf2, sizeof(buf2), ":%d", satip_server_rtsp_port); + snprintf(buf2, sizeof(buf2), ":%d %s", satip_server_rtsp_port, satip_server_uuid + 26); + else + snprintf(buf2, sizeof(buf2), " %s", satip_server_uuid + 26); snprintf(buf, sizeof(buf), MSG, buf2, tvheadend_version, - satip_server_uuid, tvheadend_version, + satip_server_uuid, http_server_ip, http_server_port, http_server_ip, http_server_port, http_server_ip, http_server_port, @@ -170,8 +170,10 @@ satip_server_http_xml(http_connection_t *hc) free(devicelist); http_arg_init(&args); - snprintf(buf2, sizeof(buf2), "%d", satip_server_rtsp_port); - http_arg_set(&args, "X-SATIP-RTSP-Port", buf2); + if (satip_server_rtsp_port != 554) { + snprintf(buf2, sizeof(buf2), "%d", satip_server_rtsp_port); + http_arg_set(&args, "X-SATIP-RTSP-Port", buf2); + } if (srcs) { snprintf(buf2, sizeof(buf2), "%d", srcs); http_arg_set(&args, "X-SATIP-Sources", buf2); @@ -405,9 +407,9 @@ satips_upnp_discovery_received if (http_tokenize(ptr, argv, 2, ':') == 2) { if (strcmp(argv[0], "ST") == 0) st = argv[1]; - else if (strcmp(argv[0], "HOST") == 0) + else if (strcasecmp(argv[0], "HOST") == 0) host = argv[1]; - else if (strcmp(argv[0], "MAN") == 0) + else if (strcasecmp(argv[0], "MAN") == 0) man = argv[1]; else if (strcmp(argv[0], "DEVICEID.SES.COM") == 0) deviceid = argv[1];