bouquet: do not keep services for not enabled bouquets, fix bouquet delete
This commit is contained in:
parent
bdaab51c30
commit
7e99756d3c
9 changed files with 221 additions and 23 deletions
|
@ -251,6 +251,9 @@ bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn)
|
|||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if (!bq->bq_enabled)
|
||||
return;
|
||||
|
||||
if (!idnode_set_exists(bq->bq_services, &s->s_id)) {
|
||||
tvhtrace("bouquet", "add service %s to %s", s->s_nicename, bq->bq_name ?: "<unknown>");
|
||||
idnode_set_add(bq->bq_services, &s->s_id, NULL);
|
||||
|
@ -317,7 +320,7 @@ bouquet_remove_service(bouquet_t *bq, service_t *s)
|
|||
*
|
||||
*/
|
||||
void
|
||||
bouquet_completed(bouquet_t *bq)
|
||||
bouquet_completed(bouquet_t *bq, uint32_t seen)
|
||||
{
|
||||
idnode_set_t *remove;
|
||||
service_t *s;
|
||||
|
@ -327,9 +330,17 @@ bouquet_completed(bouquet_t *bq)
|
|||
if (!bq)
|
||||
return;
|
||||
|
||||
tvhtrace("bouquet", "%s: completed: active=%zi old=%zi",
|
||||
bq->bq_name ?: "", bq->bq_active_services->is_count,
|
||||
bq->bq_services->is_count);
|
||||
if (seen != bq->bq_services_seen) {
|
||||
bq->bq_services_seen = seen;
|
||||
bq->bq_saveflag = 1;
|
||||
}
|
||||
|
||||
tvhtrace("bouquet", "%s: completed: enabled=%d active=%zi old=%zi seen=%u",
|
||||
bq->bq_name ?: "", bq->bq_enabled, bq->bq_active_services->is_count,
|
||||
bq->bq_services->is_count, seen);
|
||||
|
||||
if (!bq->bq_enabled)
|
||||
goto save;
|
||||
|
||||
/* Add/Remove services */
|
||||
remove = idnode_set_create(0);
|
||||
|
@ -359,6 +370,7 @@ bouquet_completed(bouquet_t *bq)
|
|||
idnode_set_free(bq->bq_active_services);
|
||||
bq->bq_active_services = idnode_set_create(1);
|
||||
|
||||
save:
|
||||
if (bq->bq_saveflag)
|
||||
bouquet_save(bq, 1);
|
||||
}
|
||||
|
@ -380,6 +392,18 @@ bouquet_map_to_channels(bouquet_t *bq)
|
|||
bouquet_unmap_channel(bq, t);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bq->bq_enabled) {
|
||||
if (bq->bq_services->is_count) {
|
||||
idnode_set_free(bq->bq_services);
|
||||
bq->bq_services = idnode_set_create(1);
|
||||
bq->bq_saveflag = 1;
|
||||
}
|
||||
if (bq->bq_active_services->is_count) {
|
||||
idnode_set_free(bq->bq_active_services);
|
||||
bq->bq_active_services = idnode_set_create(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -446,6 +470,8 @@ bouquet_class_delete(idnode_t *self)
|
|||
{
|
||||
bouquet_t *bq = (bouquet_t *)self;
|
||||
|
||||
bq->bq_enabled = 0;
|
||||
bouquet_map_to_channels(bq);
|
||||
if (!bq->bq_shield) {
|
||||
hts_settings_remove("bouquet/%s", idnode_uuid_as_str(&bq->bq_id));
|
||||
bouquet_destroy(bq);
|
||||
|
@ -477,10 +503,25 @@ bouquet_class_get_list(void *o)
|
|||
return m;
|
||||
}
|
||||
|
||||
static void
|
||||
bouquet_class_rescan_notify ( void *obj )
|
||||
{
|
||||
void mpegts_mux_bouquet_rescan ( const char *src, const char *extra );
|
||||
bouquet_t *bq = obj;
|
||||
|
||||
if (bq->bq_rescan)
|
||||
mpegts_mux_bouquet_rescan(bq->bq_src, bq->bq_comment);
|
||||
bq->bq_rescan = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bouquet_class_enabled_notify ( void *obj )
|
||||
{
|
||||
bouquet_map_to_channels((bouquet_t *)obj);
|
||||
bouquet_t *bq = obj;
|
||||
|
||||
if (bq->bq_enabled)
|
||||
bouquet_class_rescan_notify(obj);
|
||||
bouquet_map_to_channels(bq);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -687,6 +728,14 @@ const idclass_t bouquet_class = {
|
|||
.off = offsetof(bouquet_t, bq_enabled),
|
||||
.notify = bouquet_class_enabled_notify,
|
||||
},
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
.id = "rescan",
|
||||
.name = "Rescan",
|
||||
.off = offsetof(bouquet_t, bq_rescan),
|
||||
.notify = bouquet_class_rescan_notify,
|
||||
.opts = PO_NOSAVE,
|
||||
},
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
.id = "maptoch",
|
||||
|
@ -754,6 +803,13 @@ const idclass_t bouquet_class = {
|
|||
.rend = bouquet_class_services_rend,
|
||||
.opts = PO_RDONLY | PO_HIDDEN,
|
||||
},
|
||||
{
|
||||
.type = PT_U32,
|
||||
.id = "services_seen",
|
||||
.name = "# Seen Services",
|
||||
.off = offsetof(bouquet_t, bq_services_seen),
|
||||
.opts = PO_RDONLY,
|
||||
},
|
||||
{
|
||||
.type = PT_U32,
|
||||
.id = "services_count",
|
||||
|
@ -816,11 +872,13 @@ bouquet_service_resolve(void)
|
|||
if (!bq->bq_services_waiting)
|
||||
continue;
|
||||
saveflag = bq->bq_saveflag;
|
||||
HTSMSG_FOREACH(f, bq->bq_services_waiting) {
|
||||
if (htsmsg_field_get_u32(f, &lcn)) continue;
|
||||
s = service_find_by_identifier(f->hmf_name);
|
||||
if (s)
|
||||
bouquet_add_service(bq, s, lcn);
|
||||
if (bq->bq_enabled) {
|
||||
HTSMSG_FOREACH(f, bq->bq_services_waiting) {
|
||||
if (htsmsg_field_get_u32(f, &lcn)) continue;
|
||||
s = service_find_by_identifier(f->hmf_name);
|
||||
if (s)
|
||||
bouquet_add_service(bq, s, lcn);
|
||||
}
|
||||
}
|
||||
htsmsg_destroy(bq->bq_services_waiting);
|
||||
bq->bq_services_waiting = NULL;
|
||||
|
|
|
@ -34,6 +34,7 @@ typedef struct bouquet {
|
|||
|
||||
int bq_shield;
|
||||
int bq_enabled;
|
||||
int bq_rescan;
|
||||
int bq_maptoch;
|
||||
int bq_mapnolcn;
|
||||
int bq_mapnoname;
|
||||
|
@ -47,6 +48,8 @@ typedef struct bouquet {
|
|||
idnode_set_t *bq_services;
|
||||
idnode_set_t *bq_active_services;
|
||||
htsmsg_t *bq_services_waiting;
|
||||
uint32_t bq_services_seen;
|
||||
uint32_t bq_services_tmp; /* for fastscan tables */
|
||||
uint32_t bq_lcn_offset;
|
||||
|
||||
} bouquet_t;
|
||||
|
@ -78,7 +81,7 @@ bouquet_t * bouquet_find_by_source(const char *name, const char *src, int create
|
|||
void bouquet_map_to_channels(bouquet_t *bq);
|
||||
void bouquet_notify_channels(bouquet_t *bq);
|
||||
void bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn);
|
||||
void bouquet_completed(bouquet_t *bq);
|
||||
void bouquet_completed(bouquet_t *bq, uint32_t seen);
|
||||
|
||||
uint64_t bouquet_get_channel_number(bouquet_t *bq, service_t *t);
|
||||
|
||||
|
|
|
@ -752,8 +752,15 @@ void mpegts_mux_unsubscribe_by_name(mpegts_mux_t *mm, const char *name);
|
|||
|
||||
void mpegts_mux_scan_done ( mpegts_mux_t *mm, const char *buf, int res );
|
||||
|
||||
void mpegts_mux_bouquet_rescan ( const char *src, const char *extra );
|
||||
|
||||
void mpegts_mux_nice_name( mpegts_mux_t *mm, char *buf, size_t len );
|
||||
|
||||
int mpegts_mux_class_scan_state_set ( void *, const void * );
|
||||
|
||||
static inline int mpegts_mux_scan_state_set ( mpegts_mux_t *m, int state )
|
||||
{ return mpegts_mux_class_scan_state_set ( m, &state ); }
|
||||
|
||||
mpegts_pid_t *mpegts_mux_find_pid_(mpegts_mux_t *mm, int pid, int create);
|
||||
|
||||
static inline mpegts_pid_t *
|
||||
|
|
|
@ -505,6 +505,8 @@ int dvb_sat_position( const dvb_mux_conf_t *mc );
|
|||
|
||||
const char *dvb_sat_position_to_str( int position, char *buf, size_t buflen );
|
||||
|
||||
const int dvb_sat_position_from_str( const char *buf );
|
||||
|
||||
#endif /* ENABLE_MPEGTS_DVB */
|
||||
|
||||
void dvb_done ( void );
|
||||
|
|
|
@ -63,6 +63,7 @@ typedef struct dvb_bat_id {
|
|||
uint32_t freesat:1;
|
||||
uint32_t bskyb:1;
|
||||
uint16_t nbid;
|
||||
uint32_t services_count;
|
||||
char name[32];
|
||||
mpegts_mux_t *mm;
|
||||
TAILQ_HEAD(,dvb_bat_svc) services;
|
||||
|
@ -389,6 +390,8 @@ dvb_desc_service_list
|
|||
sid = (ptr[i] << 8) | ptr[i+1];
|
||||
stype = ptr[i+2];
|
||||
tvhdebug(dstr, " service %04X (%d) type %d", sid, sid, stype);
|
||||
if (bi)
|
||||
bi->services_count++;
|
||||
if (mm) {
|
||||
int save = 0;
|
||||
s = mpegts_service_find(mm, sid, 0, 1, &save);
|
||||
|
@ -524,7 +527,7 @@ dvb_freesat_add_service
|
|||
snprintf(name, sizeof(name), "%s: %s", bi->name, fr->name);
|
||||
fr->bouquet = bouquet_find_by_source(name, src, 1);
|
||||
}
|
||||
bouquet_add_service(fr->bouquet, (service_t *)s, lcn * CHANNEL_SPLIT);
|
||||
bouquet_add_service(fr->bouquet, (service_t *)s, (int64_t)lcn * CHANNEL_SPLIT);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -590,7 +593,7 @@ dvb_freesat_completed
|
|||
TAILQ_REMOVE(&fr->services, fs, region_link);
|
||||
if (fr->bouquet) {
|
||||
dvb_bouquet_comment(fr->bouquet, bi->mm);
|
||||
bouquet_completed(fr->bouquet);
|
||||
bouquet_completed(fr->bouquet, total);
|
||||
fr->bouquet = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -653,9 +656,9 @@ dvb_bskyb_local_channels
|
|||
if (len < 2)
|
||||
return;
|
||||
|
||||
regionid = ptr[1];
|
||||
regionid = (ptr[1] != 0xff) ? ptr[1] : 0xffff;
|
||||
|
||||
if (regionid != 0xff && regionid != 0 && regionid != 1) {
|
||||
if (regionid != 0xffff && regionid != 0 && regionid != 1) {
|
||||
if ((str = getenv("TVHEADEND_BSKYB_REGIONID")) != NULL) {
|
||||
if (regionid != atoi(str))
|
||||
return;
|
||||
|
@ -667,7 +670,7 @@ dvb_bskyb_local_channels
|
|||
len -= 2;
|
||||
ptr += 2;
|
||||
|
||||
tvhtrace(dstr, " region id %02X (%d) unknown %02X (%d)",
|
||||
tvhtrace(dstr, " region id %04X (%d) unknown %02X (%d)",
|
||||
regionid, regionid, ptr[0], ptr[0]);
|
||||
|
||||
while (len > 8) {
|
||||
|
@ -687,7 +690,7 @@ dvb_bskyb_local_channels
|
|||
if (!fs) {
|
||||
fs = calloc(1, sizeof(*fs));
|
||||
fs->sid = sid;
|
||||
fs->regionid = regionid != 0xff ? regionid : 0xffff;
|
||||
fs->regionid = regionid;
|
||||
fs->lcn = lcn != 0xffff ? lcn : 0;
|
||||
TAILQ_INSERT_TAIL(&b->fservices, fs, link);
|
||||
}
|
||||
|
@ -704,7 +707,7 @@ dvb_bskyb_local_channels
|
|||
}
|
||||
}
|
||||
|
||||
if (regionid && regionid != 0xff) {
|
||||
if (regionid && regionid != 0xffff) {
|
||||
LIST_FOREACH(fr, &b->fregions, link)
|
||||
if (fr->regionid == regionid)
|
||||
break;
|
||||
|
@ -1153,7 +1156,7 @@ dvb_bat_completed
|
|||
TAILQ_FOREACH(bs, &bi->services, link)
|
||||
bouquet_add_service(bq, (service_t *)bs->svc, 0);
|
||||
|
||||
bouquet_completed(bq);
|
||||
bouquet_completed(bq, bi->services_count);
|
||||
|
||||
complete:
|
||||
bi->complete = 1;
|
||||
|
@ -1678,7 +1681,7 @@ dvb_fs_sdt_callback
|
|||
if (r == 0) {
|
||||
mt->mt_working -= st->working;
|
||||
st->working = 0;
|
||||
bouquet_completed(bq);
|
||||
bouquet_completed(bq, bq->bq_services_tmp);
|
||||
}
|
||||
if (r != 1) return r;
|
||||
if (len < 5) return -1;
|
||||
|
@ -1730,6 +1733,7 @@ dvb_fs_sdt_callback
|
|||
tvhtrace(mt->mt_name, " dtag %02X dlen %d", dtag, dlen);
|
||||
switch (dtag) {
|
||||
case DVB_DESC_SERVICE:
|
||||
bq->bq_services_tmp++;
|
||||
if (dvb_desc_service(dptr, dlen, &stype, sprov,
|
||||
sizeof(sprov), sname, sizeof(sname), charset))
|
||||
return -1;
|
||||
|
@ -2301,6 +2305,7 @@ static void
|
|||
psi_tables_dvb_fastscan( void *aux, bouquet_t *bq, const char *name, int pid )
|
||||
{
|
||||
tvhtrace("fastscan", "adding table %04X (%i) for '%s'", pid, pid, name);
|
||||
bq->bq_services_tmp = 0;
|
||||
mpegts_table_add(aux, DVB_FASTSCAN_NIT_BASE, DVB_FASTSCAN_MASK,
|
||||
dvb_nit_callback, bq, "fs_nit", MT_CRC, pid);
|
||||
mpegts_table_add(aux, DVB_FASTSCAN_SDT_BASE, DVB_FASTSCAN_MASK,
|
||||
|
|
|
@ -868,6 +868,31 @@ dvb_sat_position_to_str(int position, char *buf, size_t buflen)
|
|||
return buf;
|
||||
}
|
||||
|
||||
const int
|
||||
dvb_sat_position_from_str( const char *buf )
|
||||
{
|
||||
const char *s = buf;
|
||||
int min, maj;
|
||||
char c;
|
||||
|
||||
if (!buf)
|
||||
return INT_MAX;
|
||||
maj = atoi(s);
|
||||
while (*s && *s != '.')
|
||||
s++;
|
||||
min = *s == '.' ? atoi(s + 1) : 0;
|
||||
do {
|
||||
c = *s++;
|
||||
} while (c && c != 'W' && c != 'E');
|
||||
if (!c)
|
||||
return INT_MAX;
|
||||
if (maj > 180 || maj < 0)
|
||||
return INT_MAX;
|
||||
if (min > 9 || min < 0)
|
||||
return INT_MAX;
|
||||
return (maj * 10 + min) * (c == 'W' ? -1 : 1);
|
||||
}
|
||||
|
||||
#endif /* ENABLE_MPEGTS_DVB */
|
||||
|
||||
/**
|
||||
|
|
|
@ -257,7 +257,7 @@ scan_result_tab[] = {
|
|||
{ "FAIL", MM_SCAN_FAIL },
|
||||
};
|
||||
|
||||
static int
|
||||
int
|
||||
mpegts_mux_class_scan_state_set ( void *o, const void *p )
|
||||
{
|
||||
mpegts_mux_t *mm = o;
|
||||
|
|
|
@ -213,6 +213,102 @@ mpegts_network_scan_queue_add ( mpegts_mux_t *mm, int weight )
|
|||
mpegts_network_scan_notify(mm);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Bouquet helper
|
||||
*****************************************************************************/
|
||||
|
||||
static ssize_t
|
||||
startswith( const char *str, const char *start )
|
||||
{
|
||||
size_t len = strlen(start);
|
||||
if (!strncmp(str, start, len))
|
||||
return len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
mpegts_mux_bouquet_rescan ( const char *src, const char *extra )
|
||||
{
|
||||
mpegts_network_t *mn;
|
||||
mpegts_mux_t *mm;
|
||||
ssize_t l;
|
||||
#if ENABLE_MPEGTS_DVB
|
||||
const idclass_t *ic;
|
||||
uint32_t freq;
|
||||
int satpos;
|
||||
#endif
|
||||
|
||||
if (!src)
|
||||
return;
|
||||
#if ENABLE_MPEGTS_DVB
|
||||
if ((l = startswith(src, "dvb-bouquet://dvbs,")) > 0) {
|
||||
uint32_t tsid, nbid;
|
||||
src += l;
|
||||
if ((satpos = dvb_sat_position_from_str(src)) == INT_MAX)
|
||||
return;
|
||||
while (*src && *src != ',')
|
||||
src++;
|
||||
if (sscanf(src, ",%x,%x", &tsid, &nbid) != 2)
|
||||
return;
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link)
|
||||
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link)
|
||||
if (idnode_is_instance(&mm->mm_id, &dvb_mux_dvbs_class) &&
|
||||
mm->mm_tsid == tsid &&
|
||||
dvb_sat_position(&((dvb_mux_t *)mm)->lm_tuning) == satpos)
|
||||
mpegts_mux_scan_state_set(mm, MM_SCAN_STATE_PEND);
|
||||
return;
|
||||
}
|
||||
if ((l = startswith(src, "dvb-bouquet://dvbt,")) > 0) {
|
||||
uint32_t tsid, nbid;
|
||||
if (sscanf(src, "%x,%x", &tsid, &nbid) != 2)
|
||||
return;
|
||||
ic = &dvb_mux_dvbt_class;
|
||||
goto tsid_lookup;
|
||||
}
|
||||
if ((l = startswith(src, "dvb-bouquet://dvbc,")) > 0) {
|
||||
uint32_t tsid, nbid;
|
||||
if (sscanf(src, "%x,%x", &tsid, &nbid) != 2)
|
||||
return;
|
||||
ic = &dvb_mux_dvbc_class;
|
||||
tsid_lookup:
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link)
|
||||
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link)
|
||||
if (idnode_is_instance(&mm->mm_id, ic) &&
|
||||
mm->mm_tsid == tsid)
|
||||
mpegts_mux_scan_state_set(mm, MM_SCAN_STATE_PEND);
|
||||
return;
|
||||
}
|
||||
if ((l = startswith(src, "dvb-bskyb://dvbs,")) > 0 ||
|
||||
(l = startswith(src, "dvb-freesat://dvbs,")) > 0) {
|
||||
if ((satpos = dvb_sat_position_from_str(src + l)) == INT_MAX)
|
||||
return;
|
||||
/* a bit tricky, but we don't have other info */
|
||||
if (!extra)
|
||||
return;
|
||||
freq = strtod(extra, NULL) * 1000;
|
||||
goto freq;
|
||||
}
|
||||
if ((l = startswith(src, "dvb-fastscan://dvbs,")) > 0) {
|
||||
uint32_t pid;
|
||||
src += l;
|
||||
if ((satpos = dvb_sat_position_from_str(src)) == INT_MAX)
|
||||
return;
|
||||
while (*src && *src != ',')
|
||||
src++;
|
||||
if (sscanf(src, ",%u,%u", &freq, &pid) != 2)
|
||||
return;
|
||||
freq:
|
||||
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link)
|
||||
LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link)
|
||||
if (idnode_is_instance(&mm->mm_id, &dvb_mux_dvbs_class) &&
|
||||
((dvb_mux_t *)mm)->lm_tuning.dmc_fe_freq == freq &&
|
||||
dvb_sat_position(&((dvb_mux_t *)mm)->lm_tuning) == satpos)
|
||||
mpegts_mux_scan_state_set(mm, MM_SCAN_STATE_PEND);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Subsystem setup / tear down
|
||||
*****************************************************************************/
|
||||
|
|
|
@ -32,8 +32,8 @@ tvheadend.cteditor = function(panel, index)
|
|||
*/
|
||||
tvheadend.bouquet = function(panel, index)
|
||||
{
|
||||
var list = 'enabled,name,maptoch,mapnolcn,lcn_off,mapnoname,mapradio,' +
|
||||
'chtag,source,services_count,comment';
|
||||
var list = 'enabled,rescan,name,maptoch,mapnolcn,lcn_off,mapnoname,mapradio,' +
|
||||
'chtag,source,services_count,services_seen,comment';
|
||||
|
||||
tvheadend.idnode_grid(panel, {
|
||||
url: 'api/bouquet',
|
||||
|
@ -43,6 +43,7 @@ tvheadend.bouquet = function(panel, index)
|
|||
tabIndex: index,
|
||||
columns: {
|
||||
enabled: { width: 50 },
|
||||
rescan: { width: 50 },
|
||||
name: { width: 200 },
|
||||
maptoch: { width: 100 },
|
||||
mapnolcn: { width: 100 },
|
||||
|
@ -52,6 +53,7 @@ tvheadend.bouquet = function(panel, index)
|
|||
chtag: { width: 100 },
|
||||
source: { width: 200 },
|
||||
services_count: { width: 100 },
|
||||
services_seen: { width: 100 },
|
||||
comment: { width: 200 },
|
||||
},
|
||||
list: list,
|
||||
|
|
Loading…
Add table
Reference in a new issue