Merge remote-tracking branch 'upstream/master' into freebsd

* upstream/master:
  webui: enable file logging when the log file is set through GUI
  webui: remove dead code (tvhlog_level)
  webui: Stream directly for TVHeadend/ http client, too
  epggrab: ota - improve save caching and add no data timeout
  epggrab: ota - optimize the eit/opentv workflow
  epggrab: ota - requeue skipped muxes (network check)
  SAT>IP: finish the RTSP OPTIONS command to keep connection consistent
  SAT>IP: finish the RTSP command to keep connection consistent
  capmt: a slight optimization - remove the key data
  service_mapper: remove include "plumbing/tsfix.h"
  descrambler: add other odd/even key validity check based on the key update time
  capmt: do not cache keys for the descrambler layer
This commit is contained in:
Dreamcat4 2014-07-30 15:47:05 +01:00
commit 156b24a00f
11 changed files with 155 additions and 50 deletions

View file

@ -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;

View file

@ -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;
/**
@ -1043,6 +1041,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);
@ -1055,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, cai->odd, 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, cai->even, 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);

View file

@ -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,

View file

@ -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

View file

@ -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);

View file

@ -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,

View file

@ -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,19 +322,17 @@ 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) {
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;
@ -338,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
@ -392,8 +441,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;
}
}
@ -456,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
}
/*
@ -514,7 +575,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
}
@ -534,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");
}
}
@ -551,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;
}
/* **************************************************************************
@ -565,16 +626,19 @@ 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) {
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 +663,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);
@ -607,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) {

View file

@ -932,15 +932,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));
@ -1009,14 +1008,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') {
@ -1025,13 +1028,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;
}
@ -1044,9 +1049,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);
@ -1055,6 +1063,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]",
@ -1072,18 +1082,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:
@ -1096,12 +1113,17 @@ satip_frontend_input_thread ( void *aux )
}
rtsp->hc_cmd = HTTP_CMD_NONE;
}
if (!running)
continue;
}
/* 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);

View file

@ -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;

View file

@ -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
@ -1638,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);

View file

@ -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;
}