char *mn_charset;
int mn_idlescan;
int mn_ignore_chnum;
+ int mn_autoclean_svc;
+ int mn_autoclean_mux;
};
typedef enum mpegts_mux_scan_state
uint16_t mm_onid;
uint16_t mm_tsid;
+ /*
+ * Versioning
+ */
+ int64_t mm_created;
+ int64_t mm_updated;
+
/*
* Services
*/
int s_dvb_prefcapid_lock;
uint16_t s_dvb_forcecaid;
+ /*
+ * History
+ */
+ int64_t s_dvb_created;
+ int64_t s_dvb_updated;
+
/*
* EIT/EPG control
*/
/* Multiplex */
tvhdebug("pat", "tsid %04X (%d)", tsid, tsid);
mpegts_mux_set_tsid(mm, tsid, 1);
+ mm->mm_updated = dispatch_clock;
/* Process each programme */
ptr += 5;
tvhdebug("pat", " sid %04X (%d) on pid %04X (%d)", sid, sid, pid, pid);
int save = 0;
if ((s = mpegts_service_find(mm, sid, pid, 1, &save))) {
+ s->s_dvb_updated = dispatch_clock;
mpegts_table_add(mm, DVB_PMT_BASE, DVB_PMT_MASK, dvb_pmt_callback,
NULL, "pmt", MT_CRC | MT_QUICKREQ | MT_SCANSUBS,
pid);
sid = ptr[0] << 8 | ptr[1];
r = dvb_table_begin(mt, ptr, len, tableid, sid, 9, &st, §, &last, &ver);
if (r != 1) return r;
+ mm->mm_updated = dispatch_clock;
/* Find service */
LIST_FOREACH(s, &mm->mm_services, s_dvb_mux_link)
if (s->s_dvb_service_id == sid) break;
if (!s) return -1;
+ s->s_dvb_updated = dispatch_clock;
/* Process */
tvhdebug("pmt", "sid %04X (%d)", sid, sid);
#endif
break;
}
+
+ /* Update */
+ if (mux)
+ mm->mm_updated = dispatch_clock;
}
}
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link)
if (mm->mm_onid == onid && mm->mm_tsid == tsid)
break;
- goto done;
+ if (!mm) goto done;
}
+ mm->mm_updated = dispatch_clock;
/* Service loop */
len -= 8;
s = mpegts_service_find(mm, service_id, 0, 1, &save);
charset = dvb_charset_find(mn, mm, s);
+ /* Update time and version */
+ s->s_dvb_updated = dispatch_clock;
+
/* Descriptor loop */
DVB_DESC_EACH(lptr, llen, dtag, dlen, dptr) {
tvhtrace("sdt", " dtag %02X dlen %d", dtag, dlen);
/* Done */
done:
- return dvb_table_end(mt, st, sect);
+ r = dvb_table_end(mt, st, sect);
+ return r;
}
/*
&st, §, &last, &ver);
if (r != 1) return r;
tvhdebug("vct", "tsid %04X (%d)", tsid, tsid);
+ mm->mm_updated = dispatch_clock;
/* # channels */
count = ptr[6];
/* Find the service */
if (!(s = mpegts_service_find(mm, sid, 0, 1, &save)))
goto next;
+ s->s_dvb_updated = dispatch_clock;
/* Update */
if (strcmp(s->s_dvb_svcname ?: "", chname)) {
.off = offsetof(mpegts_mux_t, mm_pmt_06_ac3),
.opts = PO_ADVANCED,
},
- {}
+ {
+ .type = PT_S64,
+ .id = "created",
+ .name = "Created",
+ .off = offsetof(mpegts_mux_t, mm_created),
+ .opts = PO_ADVANCED | PO_RDONLY,
+ .istime = "%F %T",
+ },
+ {
+ .type = PT_S64,
+ .id = "updated",
+ .name = "Updated",
+ .off = offsetof(mpegts_mux_t, mm_updated),
+ .opts = PO_ADVANCED | PO_RDONLY,
+ .istime = "%F %T",
+ },
+ {},
}
};
char buf[256];
mpegts_mux_nice_name(mm, buf, sizeof(buf));
- tvhinfo("mpegts", "%s (%p) - deleting", buf, mm);
+ if (delconf)
+ tvhinfo("mpegts", "%s (%p) - deleting", buf, mm);
+ else
+ tvhtrace("mpegts", "%s (%p) - deleting", buf, mm);
/* Stop */
mm->mm_stop(mm, 1);
* Scanning
* *************************************************************************/
+#define MPEGTS_AUTOCLEAN_PERIOD (86400L * 7) // 1 week
+
+static void
+mpegts_mux_clean_services ( const char *mname, mpegts_mux_t *mm )
+{
+ mpegts_service_t *s, *n;
+ for (s = LIST_FIRST(&mm->mm_services); s != NULL; s = n) {
+ n = LIST_NEXT(s, s_dvb_mux_link);
+ if (dispatch_clock < (s->s_dvb_updated + MPEGTS_AUTOCLEAN_PERIOD))
+ continue;
+ tvhinfo("mpegts", "%s - autoclean svc %s", mname, s->s_nicename);
+ service_destroy((service_t*)s, 1);
+ }
+}
+
void
mpegts_mux_scan_done ( mpegts_mux_t *mm, const char *buf, int res )
{
}
pthread_mutex_unlock(&mm->mm_tables_lock);
+ /* Check for out of date services */
+ if (mm->mm_network->mn_autoclean_svc)
+ mpegts_mux_clean_services(buf, mm);
+
if (res)
mpegts_network_scan_mux_done(mm);
else
tvhinfo("mpegts", "%s - scan no data, failed", buf);
mpegts_mux_scan_done(mm, buf, 0);
+ /* Mark disabled */
+ if (mm->mm_network->mn_autoclean_mux) {
+ if (dispatch_clock > (mm->mm_updated + MPEGTS_AUTOCLEAN_PERIOD)) {
+ tvhinfo("mpegts", "%s - autoclean mux", buf);
+ mm->mm_delete(mm, 1);
+ return;
+ }
+ }
+
/* Pending tables (another 20s or 30s - bit arbitrary) */
} else if (q) {
tvhinfo("mpegts", "%s - scan needs more time", buf);
return NULL;
}
+ /* Set time */
+ mm->mm_created = dispatch_clock;
+
/* Enabled by default */
mm->mm_enabled = 1;
mm->mm_epg = 1;
{
.type = PT_BOOL,
.id = "autodiscovery",
- .name = "Network Discovery",
+ .name = "Autodiscover Muxes",
.off = offsetof(mpegts_network_t, mn_autodiscovery),
.def.i = 1
},
- {
- .type = PT_BOOL,
- .id = "skipinitscan",
- .name = "Skip Initial Scan",
- .off = offsetof(mpegts_network_t, mn_skipinitscan),
- .def.i = 1
- },
{
.type = PT_BOOL,
.id = "idlescan",
- .name = "Idle Scan Muxes",
+ .name = "Autoscan Muxes",
.off = offsetof(mpegts_network_t, mn_idlescan),
.def.i = 0,
.notify = mpegts_network_class_idlescan_notify,
.off = offsetof(mpegts_network_t, mn_ignore_chnum),
.def.i = 0,
},
+ {
+ .type = PT_BOOL,
+ .id = "autoclean_svc`",
+ .name = "Autoclean Services",
+ .off = offsetof(mpegts_network_t, mn_autoclean_svc),
+ .def.i = 1,
+ },
+ {
+ .type = PT_BOOL,
+ .id = "autoclean_mux",
+ .name = "Autoclean Muxes",
+ .off = offsetof(mpegts_network_t, mn_autoclean_mux),
+ .def.i = 1,
+ },
+ {
+ .type = PT_BOOL,
+ .id = "skipinitscan",
+ .name = "Skip Initial Scan",
+ .off = offsetof(mpegts_network_t, mn_skipinitscan),
+ .def.i = 1
+ },
{
.type = PT_STR,
.id = "charset",
.off = offsetof(mpegts_service_t, s_dvb_forcecaid),
.opts = PO_ADVANCED | PO_HEXA,
},
+ {
+ .type = PT_S64,
+ .id = "created",
+ .name = "Created",
+ .off = offsetof(mpegts_service_t, s_dvb_created),
+ .opts = PO_ADVANCED | PO_RDONLY,
+ .istime = "%F %T",
+ },
+ {
+ .type = PT_S64,
+ .id = "updated",
+ .name = "Updated",
+ .off = offsetof(mpegts_service_t, s_dvb_updated),
+ .opts = PO_ADVANCED | PO_RDONLY,
+ .istime = "%F %T",
+ },
{},
}
};
if (service_create0((service_t*)s, class, uuid, S_MPEG_TS, conf) == NULL)
return NULL;
-
+ s->s_dvb_created = dispatch_clock;
+
/* Create */
sbuf_init(&s->s_tsbuf);
if (!conf) {