From 3400ee8603ff08d2af31ef69b05c2229ae80146b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Jul 2014 12:23:40 +0200 Subject: [PATCH 01/12] capmt: do not cache keys for the descrambler layer --- src/descrambler/capmt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 8f33ea7e..6da21a71 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -1043,6 +1043,7 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset) } else if (cmd == CA_SET_DESCR) { + static uint8_t empty[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int32_t index = sbuf_peek_s32(sb, offset + 4); int32_t parity = sbuf_peek_s32(sb, offset + 8); uint8_t *cw = sbuf_peek (sb, offset + 12); @@ -1056,10 +1057,10 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset) cai = &capmt->capmt_adapters[adapter].ca_info[index]; if (parity == 0) { memcpy(cai->even, cw, 8); // even key - capmt_process_key(capmt, adapter, cai->seq, cai->even, cai->odd, 1); + capmt_process_key(capmt, adapter, cai->seq, cai->even, empty, 1); } else if (parity == 1) { memcpy(cai->odd, cw, 8); // odd key - capmt_process_key(capmt, adapter, cai->seq, cai->even, cai->odd, 1); + capmt_process_key(capmt, adapter, cai->seq, empty, cai->odd, 1); } else tvhlog(LOG_ERR, "capmt", "Invalid parity %d in CA_SET_DESCR for adapter%d", parity, adapter); From 4d8aa37dbc835a3a6afb3ad5fb5ae1c8af2ee52a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Jul 2014 12:24:38 +0200 Subject: [PATCH 02/12] descrambler: add other odd/even key validity check based on the key update time --- src/descrambler.h | 1 + src/descrambler/descrambler.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/descrambler.h b/src/descrambler.h index 77e370d2..8c6bbff3 100755 --- a/src/descrambler.h +++ b/src/descrambler.h @@ -63,6 +63,7 @@ typedef struct th_descrambler_runtime { uint8_t dr_key_valid; uint8_t dr_ecm_valid; time_t dr_key_start; + time_t dr_key_timestamp[2]; time_t dr_ecm_start; time_t dr_ecm_key_time; sbuf_t dr_buf; diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index 50e6d8d6..2e02a7b7 100755 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -186,6 +186,7 @@ descrambler_keys ( th_descrambler_t *td, j++; tvhcsa_set_key_even(td->td_csa, even); dr->dr_key_valid |= 0x40; + dr->dr_key_timestamp[0] = dispatch_clock; break; } for (i = 0; i < 8; i++) @@ -193,6 +194,7 @@ descrambler_keys ( th_descrambler_t *td, j++; tvhcsa_set_key_odd(td->td_csa, odd); dr->dr_key_valid |= 0x80; + dr->dr_key_timestamp[1] = dispatch_clock; break; } @@ -260,10 +262,11 @@ descrambler_descramble ( service_t *t, const uint8_t *tsb ) { #define KEY_MASK(k) (((k) & 0x40) + 0x40) /* 0x40 (for even) or 0x80 (for odd) */ +#define KEY_IDX(k) (((k) & 0x40) >> 6) th_descrambler_t *td; th_descrambler_runtime_t *dr = t->s_descramble; int count, failed, off, size, flush_data = 0; - uint8_t *tsb2, ki; + uint8_t *tsb2, ki, kidx; lock_assert(&t->s_stream_mutex); @@ -292,7 +295,9 @@ descrambler_descramble ( service_t *t, tvhtrace("descrambler", "stream key changed to %s for service \"%s\"", (ki & 0x40) ? "odd" : "even", ((mpegts_service_t *)t)->s_dvb_svcname); - if (dr->dr_ecm_key_time + + kidx = KEY_IDX(ki); + if (dr->dr_key_timestamp[kidx] < dr->dr_key_timestamp[kidx^1] || + dr->dr_ecm_key_time + ((dr->dr_ecm_valid & KEY_MASK(ki)) ? 0 : 2) < dr->dr_key_start) { sbuf_cut(&dr->dr_buf, off); if (!td->td_ecm_reset(td)) { @@ -325,7 +330,9 @@ descrambler_descramble ( service_t *t, tvhtrace("descrambler", "stream key changed to %s for service \"%s\"", (ki & 0x40) ? "odd" : "even", ((mpegts_service_t *)t)->s_dvb_svcname); - if (dr->dr_ecm_key_time + + kidx = KEY_IDX(ki); + if (dr->dr_key_timestamp[kidx] < dr->dr_key_timestamp[kidx^1] || + dr->dr_ecm_key_time + ((dr->dr_ecm_valid & KEY_MASK(ki)) ? 0 : 2) < dr->dr_key_start) { tvhtrace("descrambler", "ECM late (%ld seconds) for service \"%s\"", dispatch_clock - dr->dr_ecm_key_time, From 4faa4418cd7dec249e34284db4089b9b86848a0c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Jul 2014 12:50:50 +0200 Subject: [PATCH 03/12] service_mapper: remove include "plumbing/tsfix.h" --- src/service_mapper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/service_mapper.c b/src/service_mapper.c index f8aeb6af..c8fb56bd 100644 --- a/src/service_mapper.c +++ b/src/service_mapper.c @@ -30,7 +30,6 @@ #include "service_mapper.h" #include "streaming.h" #include "service.h" -#include "plumbing/tsfix.h" #include "api.h" static service_mapper_status_t service_mapper_stat; From bb1a128cfd10c595aa724f9c3afbce81987b12d0 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Jul 2014 12:59:39 +0200 Subject: [PATCH 04/12] capmt: a slight optimization - remove the key data --- src/descrambler/capmt.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 6da21a71..e60ce7a4 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -125,8 +125,6 @@ static pthread_cond_t capmt_config_changed; */ typedef struct ca_info { uint16_t seq; // sequence / service id number - uint8_t even[8]; - uint8_t odd[8]; } ca_info_t; /** @@ -1056,11 +1054,9 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset) return; cai = &capmt->capmt_adapters[adapter].ca_info[index]; if (parity == 0) { - memcpy(cai->even, cw, 8); // even key - capmt_process_key(capmt, adapter, cai->seq, cai->even, empty, 1); + capmt_process_key(capmt, adapter, cai->seq, cw, empty, 1); } else if (parity == 1) { - memcpy(cai->odd, cw, 8); // odd key - capmt_process_key(capmt, adapter, cai->seq, empty, cai->odd, 1); + capmt_process_key(capmt, adapter, cai->seq, empty, cw, 1); } else tvhlog(LOG_ERR, "capmt", "Invalid parity %d in CA_SET_DESCR for adapter%d", parity, adapter); From 9a6940cec3d79609ac54c023c2a2bbc4e57c164a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Jul 2014 17:36:55 +0200 Subject: [PATCH 05/12] SAT>IP: finish the RTSP command to keep connection consistent --- src/input/mpegts/satip/satip_frontend.c | 38 +++++++++++++++++++------ 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index 218fadfb..85936856 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -927,15 +927,14 @@ satip_frontend_input_thread ( void *aux ) uint8_t rtcp[2048]; uint8_t *p; sbuf_t sb; - int pos, nfds, i, r; + int pos, nfds, i, r, tc; size_t c; - int tc; tvhpoll_event_t ev[4]; tvhpoll_t *efd; - int changing = 0, ms = -1, fatal = 0; + int changing = 0, ms = -1, fatal = 0, running = 1; uint32_t seq = -1, nseq; udp_multirecv_t um; - int play2 = 1, position, rtsp_flags = 0; + int play2 = 1, position, rtsp_flags = 0, reply; uint64_t u64; lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf)); @@ -1004,14 +1003,18 @@ satip_frontend_input_thread ( void *aux ) tvherror("satip", "%s - failed to tune", buf); goto done; } + reply = 1; udp_multirecv_init(&um, RTP_PKTS, RTP_PKT_SIZE); sbuf_init_fixed(&sb, RTP_PKTS * RTP_PKT_SIZE); - while (tvheadend_running && !fatal) { + while ((reply || running) && !fatal) { nfds = tvhpoll_wait(efd, ev, 1, ms); + if (!tvheadend_running) + running = 0; + if (nfds > 0 && ev[0].data.ptr == NULL) { c = read(lfe->sf_dvr_pipe.rd, rtcp, 1); if (c == 1 && rtcp[0] == 'c') { @@ -1020,13 +1023,15 @@ satip_frontend_input_thread ( void *aux ) continue; } tvhtrace("satip", "%s - input thread received shutdown", buf); - break; + running = 0; + continue; } if (changing && rtsp->hc_cmd == HTTP_CMD_NONE) { ms = -1; changing = 0; - satip_frontend_pid_changed(rtsp, lfe, buf); + if (satip_frontend_pid_changed(rtsp, lfe, buf) > 0) + reply = 1; continue; } @@ -1039,9 +1044,12 @@ satip_frontend_input_thread ( void *aux ) buf, r, strerror(-r), rtsp->hc_cmd, rtsp->hc_code); fatal = 1; } else if (r == HTTP_CON_DONE) { + reply = 0; switch (rtsp->hc_cmd) { case RTSP_CMD_OPTIONS: r = rtsp_options_decode(rtsp); + if (!running) + break; if (r < 0) { tvhlog(LOG_ERR, "satip", "%s - RTSP OPTIONS error %d (%s) [%i-%i]", buf, r, strerror(-r), rtsp->hc_cmd, rtsp->hc_code); @@ -1050,6 +1058,8 @@ satip_frontend_input_thread ( void *aux ) break; case RTSP_CMD_SETUP: r = rtsp_setup_decode(rtsp, 1); + if (!running) + break; if (r < 0 || rtsp->hc_rtp_port != lfe->sf_rtp_port || rtsp->hc_rtpc_port != lfe->sf_rtp_port + 1) { tvhlog(LOG_ERR, "satip", "%s - RTSP SETUP error %d (%s) [%i-%i]", @@ -1067,18 +1077,25 @@ satip_frontend_input_thread ( void *aux ) tvherror("satip", "%s - failed to tune2", buf); fatal = 1; } + reply = 1; continue; } else { - if (satip_frontend_pid_changed(rtsp, lfe, buf) > 0) + if (satip_frontend_pid_changed(rtsp, lfe, buf) > 0) { + reply = 1; continue; + } } } break; case RTSP_CMD_PLAY: + if (!running) + break; if (rtsp->hc_code == 200 && play2) { play2 = 0; - if (satip_frontend_pid_changed(rtsp, lfe, buf) > 0) + if (satip_frontend_pid_changed(rtsp, lfe, buf) > 0) { + reply = 1; continue; + } } /* fall thru */ default: @@ -1091,6 +1108,9 @@ satip_frontend_input_thread ( void *aux ) } rtsp->hc_cmd = HTTP_CMD_NONE; } + + if (!running) + continue; } /* We need to keep the session alive */ From 854327aabacb60818f8c2a91a135c92e684c3291 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 28 Jul 2014 18:31:38 +0200 Subject: [PATCH 06/12] SAT>IP: finish the RTSP OPTIONS command to keep connection consistent --- src/input/mpegts/satip/satip_frontend.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index 85936856..26386900 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -1115,8 +1115,10 @@ satip_frontend_input_thread ( void *aux ) /* We need to keep the session alive */ if (rtsp->hc_ping_time + rtsp->hc_rtp_timeout / 2 < dispatch_clock && - rtsp->hc_cmd == HTTP_CMD_NONE) + rtsp->hc_cmd == HTTP_CMD_NONE) { rtsp_options(rtsp); + reply = 1; + } if (ev[0].data.ptr == lfe->sf_rtcp) { c = recv(lfe->sf_rtcp->fd, rtcp, sizeof(rtcp), MSG_DONTWAIT); From 2141112aac1f5f31b221242721d4ec704a08fa46 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 29 Jul 2014 15:23:03 +0200 Subject: [PATCH 07/12] epggrab: ota - requeue skipped muxes (network check) - enhance trace - do not print delete problem? messages on shutdown --- src/epggrab/otamux.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index 0c7ac299..db728088 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -392,8 +392,11 @@ next_one: for (i = 0, net = NULL; i < networks_count; i++) { net = &networks[i]; if (net->net == mm->mm_network) { - if (net->failed) + if (net->failed) { + TAILQ_INSERT_TAIL(&epggrab_ota_pending, om, om_q_link); + om->om_q_type = EPGGRAB_OTA_MUX_PENDING; goto done; + } break; } } @@ -514,7 +517,7 @@ epggrab_ota_service_trace ( epggrab_ota_mux_t *ota, if (mm && svc) { mpegts_mux_nice_name(mm, buf, sizeof(buf)); tvhtrace("epggrab", "ota %s %s service %s", buf, op, svc->s_nicename); - } else + } else if (tvheadend_running) tvhtrace("epggrab", "ota %s, problem? (%p %p)", op, mm, svc); #endif } @@ -570,11 +573,13 @@ epggrab_ota_save ( epggrab_ota_mux_t *ota ) LIST_FOREACH(map, &ota->om_modules, om_link) { e = htsmsg_create_map(); htsmsg_add_str(e, "id", map->om_module->id); - l2 = htsmsg_create_list(); - RB_FOREACH(svcl, &map->om_svcs, link) - if (svcl->uuid) - htsmsg_add_str(l2, NULL, svcl->uuid); - htsmsg_add_msg(e, "services", l2); + if (RB_FIRST(&map->om_svcs)) { + l2 = htsmsg_create_list(); + RB_FOREACH(svcl, &map->om_svcs, link) + if (svcl->uuid) + htsmsg_add_str(l2, NULL, svcl->uuid); + htsmsg_add_msg(e, "services", l2); + } htsmsg_add_msg(l, NULL, e); } htsmsg_add_msg(c, "modules", l); @@ -599,6 +604,13 @@ epggrab_ota_load_one hts_settings_remove("epggrab/otamux/%s", uuid); return; } +#if ENABLE_TRACE + { + char name[256]; + mpegts_mux_nice_name(mm, name, sizeof(name)); + tvhtrace("epggrab", "loading config for %s", name); + } +#endif ota = calloc(1, sizeof(epggrab_ota_mux_t)); ota->om_mux_uuid = strdup(uuid); From 0df3819a17636b1446a7e93ad92d5b725812d51d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 29 Jul 2014 15:28:08 +0200 Subject: [PATCH 08/12] epggrab: ota - optimize the eit/opentv workflow Assume that the EPG grab is completed when: - no EIT data are present and opentv completed - EIT data are present but opentv data were not seen --- src/epggrab/module/opentv.c | 3 +++ src/epggrab/otamux.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index fddf3b41..f8ef183c 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -129,6 +129,7 @@ typedef struct opentv_event typedef struct opentv_status { opentv_module_t *os_mod; + epggrab_ota_map_t *os_map; int os_refcount; epggrab_ota_mux_t *os_ota; } opentv_status_t; @@ -453,6 +454,7 @@ opentv_table_callback /* Complete */ done: if (!r) { + sta->os_map->om_first = 0; /* valid data mark */ tvhtrace(mt->mt_name, "pid %d complete remain %d", mt->mt_pid, sta->os_refcount-1); @@ -564,6 +566,7 @@ static int _opentv_start if (!sta) { sta = calloc(1, sizeof(opentv_status_t)); sta->os_mod = mod; + sta->os_map = map; } mt = mpegts_table_add(mm, DVB_BAT_BASE, DVB_BAT_MASK, opentv_bat_callback, sta, diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index db728088..5ef1d7a8 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -309,9 +309,11 @@ epggrab_ota_complete LIST_FOREACH(map, &ota->om_modules, om_link) { if (map->om_module == mod) { map->om_complete = 1; - } else if (!map->om_complete) { + } else if (!map->om_complete && !map->om_first) { done = 0; } + tvhtrace("epggrab", "%s complete %i first %i", + map->om_module->id, map->om_complete, map->om_first); } if (!done) return; From edbc0771c5537d4fe486ef8f3670676c62b4e394 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 30 Jul 2014 12:06:51 +0200 Subject: [PATCH 09/12] epggrab: ota - improve save caching and add no data timeout - fix the complete flag load - improve the save request caching - mark as completed all timeout states (no data, EPG timeout) --- src/epggrab.h | 2 + src/epggrab/module/eit.c | 10 ++--- src/epggrab/otamux.c | 86 +++++++++++++++++++++++++++++++++------- 3 files changed, 79 insertions(+), 19 deletions(-) diff --git a/src/epggrab.h b/src/epggrab.h index ed4dbd5b..d507ba04 100644 --- a/src/epggrab.h +++ b/src/epggrab.h @@ -203,7 +203,9 @@ struct epggrab_ota_mux LIST_HEAD(,epggrab_ota_map) om_modules; ///< List of linked mods int om_complete; ///< Has completed a scan + int om_save; ///< something changed gtimer_t om_timer; ///< Per mux active timer + gtimer_t om_data_timer; ///< Any EPG data seen? char *om_force_modname;///< Force this module diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index 14825dce..12faaf9d 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -608,16 +608,16 @@ _eit_callback if(!mm) goto done; - if (map->om_first) { - map->om_tune_count++; - map->om_first = 0; - } - /* Get service */ svc = mpegts_mux_find_service(mm, sid); if (!svc) goto done; + if (map->om_first) { + map->om_tune_count++; + map->om_first = 0; + } + /* Register this */ if (ota) epggrab_ota_service_add(map, ota, idnode_uuid_as_str(&svc->s_id), 1); diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index 5ef1d7a8..12e7a8cf 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -36,7 +36,8 @@ #define EPGGRAB_OTA_DONE_COMPLETE 0 #define EPGGRAB_OTA_DONE_TIMEOUT 1 -#define EPGGRAB_OTA_DONE_STOLEN 2 +#define EPGGRAB_OTA_DONE_NO_DATA 2 +#define EPGGRAB_OTA_DONE_STOLEN 3 typedef TAILQ_HEAD(epggrab_ota_head,epggrab_ota_mux) epggrab_ota_head_t; @@ -60,6 +61,7 @@ SKEL_DECLARE(epggrab_ota_mux_skel, epggrab_ota_mux_t); SKEL_DECLARE(epggrab_svc_link_skel, epggrab_ota_svc_link_t); static void epggrab_ota_timeout_cb ( void *p ); +static void epggrab_ota_data_timeout_cb ( void *p ); static void epggrab_ota_kick_cb ( void *p ); static void epggrab_ota_save ( epggrab_ota_mux_t *ota ); @@ -129,17 +131,25 @@ epggrab_ota_kick ( int delay ) static void epggrab_ota_done ( epggrab_ota_mux_t *om, int reason ) { + static const char *reasons[] = { + [EPGGRAB_OTA_DONE_COMPLETE] = "complete", + [EPGGRAB_OTA_DONE_TIMEOUT] = "timeout", + [EPGGRAB_OTA_DONE_NO_DATA] = "no data", + [EPGGRAB_OTA_DONE_STOLEN] = "stolen" + }; char name[256]; mpegts_mux_t *mm; epggrab_ota_map_t *map; + if (om->om_save) + epggrab_ota_save(om); + mm = mpegts_mux_find(om->om_mux_uuid); mpegts_mux_nice_name(mm, name, sizeof(name)); - tvhdebug("epggrab", "grab done for %s (%s)", name, - reason == EPGGRAB_OTA_DONE_TIMEOUT ? "timeout" : - (reason == EPGGRAB_OTA_DONE_STOLEN ? "stolen" : "complete")); + tvhdebug("epggrab", "grab done for %s (%s)", name, reasons[reason]); gtimer_disarm(&om->om_timer); + gtimer_disarm(&om->om_data_timer); assert(om->om_q_type == EPGGRAB_OTA_MUX_ACTIVE); TAILQ_REMOVE(&epggrab_ota_active, om, om_q_link); @@ -161,6 +171,15 @@ epggrab_ota_done ( epggrab_ota_mux_t *om, int reason ) epggrab_ota_kick(1); } +static void +epggrab_ota_complete_mark ( epggrab_ota_mux_t *om ) +{ + if (!om->om_complete) { + om->om_complete = 1; + epggrab_ota_save(om); + } +} + static void epggrab_ota_start ( epggrab_ota_mux_t *om, mpegts_mux_t *mm ) { @@ -168,6 +187,7 @@ epggrab_ota_start ( epggrab_ota_mux_t *om, mpegts_mux_t *mm ) epggrab_ota_map_t *map; char *modname = om->om_force_modname; mpegts_mux_instance_t *mmi = mm->mm_active; + int grace; /* In pending queue? Remove.. */ if (om->om_q_type == EPGGRAB_OTA_MUX_PENDING) @@ -177,8 +197,11 @@ epggrab_ota_start ( epggrab_ota_mux_t *om, mpegts_mux_t *mm ) TAILQ_INSERT_TAIL(&epggrab_ota_active, om, om_q_link); om->om_q_type = EPGGRAB_OTA_MUX_ACTIVE; + grace = mpegts_input_grace(mmi->mmi_input, mm); gtimer_arm(&om->om_timer, epggrab_ota_timeout_cb, om, - epggrab_ota_timeout_get() + mpegts_input_grace(mmi->mmi_input, mm)); + epggrab_ota_timeout_get() + grace); + gtimer_arm(&om->om_data_timer, epggrab_ota_data_timeout_cb, om, + 30 + grace); /* 30 seconds to receive any EPG info */ if (modname) { LIST_FOREACH(m, &epggrab_modules, link) if (!strcmp(m->id, modname)) { @@ -299,11 +322,7 @@ epggrab_ota_complete lock_assert(&global_lock); tvhdebug(mod->id, "grab complete"); - /* Mark */ - if (!ota->om_complete) { - ota->om_complete = 1; - epggrab_ota_save(ota); - } + epggrab_ota_complete_mark(ota); /* Test for completion */ LIST_FOREACH(map, &ota->om_modules, om_link) { @@ -340,8 +359,36 @@ epggrab_ota_timeout_cb ( void *p ) if (!om) return; - /* Re-queue */ + /* Abort */ epggrab_ota_done(om, EPGGRAB_OTA_DONE_TIMEOUT); + /* Not completed, but no further data for a long period */ + /* wait for a manual mux tuning */ + epggrab_ota_complete_mark(om); +} + +static void +epggrab_ota_data_timeout_cb ( void *p ) +{ + epggrab_ota_mux_t *om = p; + epggrab_ota_map_t *map; + + lock_assert(&global_lock); + + if (!om) + return; + + /* Test for any valid data reception */ + LIST_FOREACH(map, &om->om_modules, om_link) { + if (!map->om_first) + break; + } + + if (map == NULL) { + /* Abort */ + epggrab_ota_done(om, EPGGRAB_OTA_DONE_NO_DATA); + /* Not completed, but no data - wait for a manual mux tuning */ + epggrab_ota_complete_mark(om); + } } static void @@ -461,6 +508,15 @@ done: goto next_one; if (kick) epggrab_ota_kick(64); /* a random number? */ + +#if ENABLE_TRACE + i = r = 0; + RB_FOREACH(om, &epggrab_ota_all, om_global_link) + i++; + TAILQ_FOREACH(om, &epggrab_ota_pending, om_q_link) + r++; + tvhtrace("epggrab", "mux stats - all %i pending %i", i, r); +#endif } /* @@ -539,8 +595,8 @@ epggrab_ota_service_add ( epggrab_ota_map_t *map, epggrab_ota_mux_t *ota, svcl = epggrab_svc_link_skel; SKEL_USED(epggrab_svc_link_skel); svcl->uuid = strdup(uuid); - if (save && ota->om_complete) - epggrab_ota_save(ota); + if (save) + ota->om_save = 1; epggrab_ota_service_trace(ota, svcl, "add new"); } } @@ -556,7 +612,7 @@ epggrab_ota_service_del ( epggrab_ota_map_t *map, epggrab_ota_mux_t *ota, free(svcl->uuid); free(svcl); if (save) - epggrab_ota_save(ota); + ota->om_save = 1; } /* ************************************************************************** @@ -570,6 +626,7 @@ epggrab_ota_save ( epggrab_ota_mux_t *ota ) epggrab_ota_svc_link_t *svcl; htsmsg_t *e, *l, *l2, *c = htsmsg_create_map(); + ota->om_save = 0; htsmsg_add_u32(c, "complete", ota->om_complete); l = htsmsg_create_list(); LIST_FOREACH(map, &ota->om_modules, om_link) { @@ -621,6 +678,7 @@ epggrab_ota_load_one free(ota); return; } + htsmsg_get_u32(c, "complete", (uint32_t *)&ota->om_complete); if (!(l = htsmsg_get_list(c, "modules"))) return; HTSMSG_FOREACH(f, l) { From b3ef0941286273a199799296cfc5af959e668cb7 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 30 Jul 2014 12:23:00 +0200 Subject: [PATCH 10/12] webui: Stream directly for TVHeadend/ http client, too --- src/webui/webui.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/webui/webui.c b/src/webui/webui.c index 8d91a21f..91b3ec42 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -1016,12 +1016,14 @@ static char * page_play_path_modify(http_connection_t *hc, const char *path, int *cut) { /* - * For curl and wget do not set the playlist, stream directly + * For curl, wget and TVHeadend do not send the playlist, stream directly */ const char *agent = http_arg_get(&hc->hc_args, "User-Agent"); if (strncasecmp(agent, "curl/", 5) == 0 || strncasecmp(agent, "wget/", 5) == 0) return strdup(path + 5); + if (strncasecmp(agent, "TVHeadend/", 10) == 0) + return strdup(path + 10); return NULL; } From 5c250565e17816fadfd59ae20dec33bdafad9d93 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 30 Jul 2014 12:30:26 +0200 Subject: [PATCH 11/12] webui: remove dead code (tvhlog_level) --- src/webui/extjs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 9b27431f..23960313 100755 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -1619,8 +1619,6 @@ extjs_tvhlog(http_connection_t *hc, const char *remain, void *opaque) const char *str; pthread_mutex_lock(&tvhlog_mutex); - if ((str = http_arg_get(&hc->hc_req_args, "tvhlog_level"))) - tvhlog_level = atoi(str); if ((str = http_arg_get(&hc->hc_req_args, "tvhlog_trace_on"))) tvhlog_level = LOG_TRACE; else From 166a9504f0946c4b0a0527a4c0a230f5fe65ed1c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 30 Jul 2014 12:39:31 +0200 Subject: [PATCH 12/12] webui: enable file logging when the log file is set through GUI --- src/webui/extjs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 23960313..bb177c25 100755 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -1636,6 +1636,8 @@ extjs_tvhlog(http_connection_t *hc, const char *remain, void *opaque) tvhlog_options |= TVHLOG_OPT_DBG_SYSLOG; else tvhlog_options &= ~TVHLOG_OPT_DBG_SYSLOG; + if (tvhlog_path && tvhlog_path[0] != '\0') + tvhlog_options |= TVHLOG_OPT_DBG_FILE; tvhlog_set_trace(http_arg_get(&hc->hc_req_args, "tvhlog_trace")); tvhlog_set_debug(http_arg_get(&hc->hc_req_args, "tvhlog_debug")); pthread_mutex_unlock(&tvhlog_mutex);