diff --git a/src/bouquet.c b/src/bouquet.c index daa7384d..a47db199 100644 --- a/src/bouquet.c +++ b/src/bouquet.c @@ -112,12 +112,17 @@ void bouquet_destroy_by_service(service_t *t) { bouquet_t *bq; + service_lcn_t *sl; lock_assert(&global_lock); RB_FOREACH(bq, &bouquets, bq_link) if (idnode_set_exists(bq->bq_services, &t->s_id)) idnode_set_remove(bq->bq_services, &t->s_id); + while ((sl = LIST_FIRST(&t->s_lcns)) != NULL) { + LIST_REMOVE(sl, sl_link); + free(sl); + } } /** @@ -150,8 +155,14 @@ bouquet_find_by_source(const char *name, const char *src, int create) bqs.bq_src = (char *)src; bq = RB_FIND(&bouquets, &bqs, bq_link, _bq_cmp); - if (bq) + if (bq) { + if (name && *name && strcmp(name, bq->bq_name)) { + tvhwarn("bouquet", "bouquet name '%s' changed to '%s'", bq->bq_name ?: "", name); + free(bq->bq_name); + bq->bq_name = strdup(name); + } return bq; + } if (create && name) return bouquet_create(NULL, NULL, name, src); return NULL; @@ -227,13 +238,30 @@ bouquet_map_channel(bouquet_t *bq, service_t *t) * */ void -bouquet_add_service(bouquet_t *bq, service_t *s) +bouquet_add_service(bouquet_t *bq, service_t *s, uint32_t lcn) { + service_lcn_t *tl; + lock_assert(&global_lock); if (!idnode_set_exists(bq->bq_services, &s->s_id)) { tvhtrace("bouquet", "add service %s to %s", s->s_nicename, bq->bq_name ?: ""); idnode_set_add(bq->bq_services, &s->s_id, NULL); + + LIST_FOREACH(tl, &s->s_lcns, sl_link) + if (tl->sl_bouquet == bq) { + tl->sl_lcn = lcn; + break; + } + + if (!tl) { + tl = calloc(1, sizeof(*tl)); + tl->sl_bouquet = bq; + tl->sl_lcn = lcn; + LIST_INSERT_HEAD(&s->s_lcns, tl, sl_link); + } + tl->sl_seen = 1; + bq->bq_saveflag = 1; if (bq->bq_enabled && bq->bq_maptoch) bouquet_map_channel(bq, s); @@ -281,11 +309,17 @@ void bouquet_completed(bouquet_t *bq) { idnode_set_t *remove; + service_t *s; + service_lcn_t *lcn, *lcn_next; size_t z; + if (!bq) + return; + tvhtrace("bouquet", "completed: active=%zi old=%zi", bq->bq_active_services->is_count, bq->bq_services->is_count); + /* Add/Remove services */ remove = idnode_set_create(); for (z = 0; z < bq->bq_services->is_count; z++) if (!idnode_set_exists(bq->bq_active_services, bq->bq_services->is_array[z])) @@ -294,8 +328,27 @@ bouquet_completed(bouquet_t *bq) bouquet_remove_service(bq, (service_t *)remove->is_array[z]); idnode_set_free(remove); + /* Remove no longer used LCNs */ + for (z = 0; z < bq->bq_services->is_count; z++) { + s = (service_t *)bq->bq_services->is_array[z]; + for (lcn = LIST_FIRST(&s->s_lcns); lcn; lcn = lcn_next) { + lcn_next = LIST_NEXT(lcn, sl_link); + if (lcn->sl_bouquet != bq) continue; + if (!lcn->sl_seen) { + LIST_REMOVE(lcn, sl_link); + free(lcn); + } else { + lcn->sl_seen = 0; + } + } + } + + idnode_set_free(bq->bq_active_services); bq->bq_active_services = idnode_set_create(); + + if (bq->bq_saveflag) + bouquet_save(bq, 1); } /* @@ -335,6 +388,20 @@ bouquet_notify_channels(bouquet_t *bq) } } +/* + * + */ +uint64_t +bouquet_get_channel_number(bouquet_t *bq, service_t *t) +{ + service_lcn_t *tl; + + LIST_FOREACH(tl, &t->s_lcns, sl_link) + if (tl->sl_bouquet == bq) + return (int64_t)tl->sl_lcn * CHANNEL_SPLIT; + return 0; +} + /** * */ @@ -524,15 +591,19 @@ bouquet_class_chtag_ref_set ( void *obj, const void *p ) static const void * bouquet_class_services_get ( void *obj ) { - htsmsg_t *l = htsmsg_create_list(); + htsmsg_t *m = htsmsg_create_map(); bouquet_t *bq = obj; + service_t *t; size_t z; /* Add all */ - for (z = 0; z < bq->bq_services->is_count; z++) - htsmsg_add_str(l, NULL, idnode_uuid_as_str(bq->bq_services->is_array[z])); + for (z = 0; z < bq->bq_services->is_count; z++) { + t = (service_t *)bq->bq_services->is_array[z]; + htsmsg_add_u32(m, idnode_uuid_as_str(&t->s_id), + bouquet_get_channel_number(bq, t)); + } - return l; + return m; } static char * @@ -696,7 +767,7 @@ bouquet_service_resolve(void) bouquet_t *bq; htsmsg_field_t *f; service_t *s; - const char *str; + uint32_t lcn; int saveflag; lock_assert(&global_lock); @@ -706,11 +777,10 @@ bouquet_service_resolve(void) continue; saveflag = bq->bq_saveflag; HTSMSG_FOREACH(f, bq->bq_services_waiting) { - if ((str = htsmsg_field_get_str(f))) { - s = service_find_by_identifier(str); - if (s) - bouquet_add_service(bq, s); - } + 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; diff --git a/src/bouquet.h b/src/bouquet.h index fe34571f..293a97d6 100644 --- a/src/bouquet.h +++ b/src/bouquet.h @@ -76,9 +76,11 @@ 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); +void bouquet_add_service(bouquet_t *bq, service_t *s, uint32_t lcn); void bouquet_completed(bouquet_t *bq); +uint64_t bouquet_get_channel_number(bouquet_t *bq, service_t *t); + void bouquet_save(bouquet_t *bq, int notify); /** diff --git a/src/channels.c b/src/channels.c index 227bdfba..2d29c1d4 100644 --- a/src/channels.c +++ b/src/channels.c @@ -569,9 +569,13 @@ channel_get_number ( channel_t *ch ) if (ch->ch_number) { n = ch->ch_number; } else { - LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) + LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) { + if (ch->ch_bouquet && + (n = bouquet_get_channel_number(ch->ch_bouquet, csm->csm_svc))) + break; if ((n = service_get_channel_number(csm->csm_svc))) break; + } } if (n) { if (ch->ch_bouquet) @@ -661,6 +665,7 @@ channel_get_icon ( channel_t *ch ) ch->ch_icon = strdup(icn); channel_save(ch); idnode_notify_simple(&ch->ch_id); + break; } } } diff --git a/src/input/mpegts.h b/src/input/mpegts.h index bdc9114a..c898a1a5 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -111,7 +111,6 @@ typedef struct mpegts_table_state int version; int complete; uint32_t sections[8]; - void *bouquet; RB_ENTRY(mpegts_table_state) link; } mpegts_table_state_t; @@ -172,6 +171,7 @@ struct mpegts_table char *mt_name; void *mt_opaque; + void *mt_bat; mpegts_table_callback_t mt_callback; RB_HEAD(,mpegts_table_state) mt_state; diff --git a/src/input/mpegts/dvb.h b/src/input/mpegts/dvb.h index fc52004f..e2aeecbb 100644 --- a/src/input/mpegts/dvb.h +++ b/src/input/mpegts/dvb.h @@ -131,6 +131,9 @@ struct mpegts_mux; #define DVB_DESC_AAC 0x7C #define DVB_DESC_LOCAL_CHAN 0x83 +#define DVB_DESC_FREESAT_LCN 0xD3 +#define DVB_DESC_FREESAT_REGIONS 0xD4 + /* Service type lookup */ int dvb_servicetype_lookup ( int t ); @@ -202,7 +205,9 @@ int dvb_table_begin int tableid, uint64_t extraid, int minlen, struct mpegts_table_state **st, int *sect, int *last, int *ver); void dvb_table_reset - (struct mpegts_table *mt ); + (struct mpegts_table *mt); +void dvb_bat_destroy + (struct mpegts_table *mt); int dvb_pat_callback (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid); diff --git a/src/input/mpegts/dvb_psi.c b/src/input/mpegts/dvb_psi.c index 5431c3c1..79dcebf6 100644 --- a/src/input/mpegts/dvb_psi.c +++ b/src/input/mpegts/dvb_psi.c @@ -33,6 +33,45 @@ #include #include +typedef struct dvb_freesat_svc { + TAILQ_ENTRY(dvb_freesat_svc) link; + TAILQ_ENTRY(dvb_freesat_svc) region_link; + uint16_t sid; + uint16_t regionid; + uint16_t lcn; + mpegts_service_t *svc; +} dvb_freesat_svc_t; + +typedef struct dvb_freesat_region { + LIST_ENTRY(dvb_freesat_region) link; + TAILQ_HEAD(,dvb_freesat_svc) services; + uint16_t regionid; + char name[32]; + bouquet_t *bouquet; +} dvb_freesat_region_t; + +typedef struct dvb_bat_svc { + TAILQ_ENTRY(dvb_bat_svc) link; + mpegts_service_t *svc; + dvb_freesat_svc_t *fallback; +} dvb_bat_svc_t; + +typedef struct dvb_bat_id { + LIST_ENTRY(dvb_bat_id) link; + uint32_t complete:1; + uint32_t freesat:1; + uint16_t nbid; + char name[32]; + TAILQ_HEAD(,dvb_bat_svc) services; +} dvb_bat_id_t; + +typedef struct dvb_bat { + int complete; + LIST_HEAD(,dvb_bat_id) bats; + LIST_HEAD(,dvb_freesat_region) fregions; + TAILQ_HEAD(,dvb_freesat_svc) fservices; +} dvb_bat_t; + SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state); static int @@ -323,10 +362,11 @@ dvb_desc_service static int dvb_desc_service_list - ( const char *dstr, const uint8_t *ptr, int len, mpegts_mux_t *mm, bouquet_t *bq ) + ( const char *dstr, const uint8_t *ptr, int len, mpegts_mux_t *mm, dvb_bat_id_t *bi ) { uint16_t stype, sid; int i; + dvb_bat_svc_t *bs; mpegts_service_t *s; for (i = 0; i < len; i += 3) { sid = (ptr[i] << 8) | ptr[i+1]; @@ -335,8 +375,11 @@ dvb_desc_service_list if (mm) { int save = 0; s = mpegts_service_find(mm, sid, 0, 1, &save); - if (bq) - bouquet_add_service(bq, (service_t *)s); + if (bi) { + bs = calloc(1, sizeof(*bs)); + bs->svc = s; + TAILQ_INSERT_TAIL(&bi->services, bs, link); + } if (save) s->s_config_save((service_t*)s); } @@ -371,7 +414,150 @@ dvb_desc_local_channel return 0; } +/* + * UK FreeSat + */ +static void +dvb_freesat_local_channels + ( dvb_bat_t *b, const char *dstr, const uint8_t *ptr, int len, uint16_t nbid ) +{ + uint16_t sid, unk, lcn, regionid; + dvb_freesat_svc_t *fs; + int len2; + + while (len > 4) { + sid = (ptr[0] << 8) | ptr[1]; + unk = (ptr[2] << 8) | ptr[3]; + len2 = ptr[4]; + ptr += 5; + len -= 5; + if (len2 > len) + break; + tvhtrace(dstr, " sid %04X (%d) uknown %04X (%d)\n", sid, sid, unk, unk); + while (len2 > 3) { + lcn = ((ptr[0] & 0x0f) << 8) | ptr[1]; + regionid = (ptr[2] << 8) | ptr[3]; + tvhtrace(dstr, " lcn %d region %d\n", lcn, regionid); + + TAILQ_FOREACH(fs, &b->fservices, link) + if (fs->sid == sid && fs->regionid == regionid) + break; + if (!fs) { + fs = calloc(1, sizeof(*fs)); + fs->sid = sid; + fs->regionid = regionid; + fs->lcn = lcn; + TAILQ_INSERT_TAIL(&b->fservices, fs, link); + } + ptr += 4; + len -= 4; + len2 -= 4; + } + } +} + +static void +dvb_freesat_regions + ( dvb_bat_t *b, const char *dstr, const uint8_t *ptr, int len, uint16_t nbid ) +{ + uint16_t id; + char name[32]; + dvb_freesat_region_t *fr; + int r; + + while (len > 5) { + id = (ptr[0] << 8) | ptr[1]; + /* language: ptr[2-4]: 'eng' */ + if ((r = dvb_get_string_with_len(name, sizeof(name), ptr + 5, len - 5, NULL, NULL)) < 0) + break; + tvhtrace(dstr, " region %u - '%s'\n", id, name); + + LIST_FOREACH(fr, &b->fregions, link) + if (fr->regionid == id) + break; + if (!fr) { + fr = calloc(1, sizeof(*fr)); + fr->regionid = id; + strncpy(fr->name, name, sizeof(fr->name)-1); + fr->name[sizeof(fr->name)-1] = '\0'; + TAILQ_INIT(&fr->services); + LIST_INSERT_HEAD(&b->fregions, fr, link); + } + + ptr += 5 + r; + len -= 5 + r; + } +} + +static void +dvb_freesat_add_service + ( dvb_bat_id_t *bi, dvb_freesat_region_t *fr, mpegts_service_t *s, uint32_t lcn ) +{ + char name[64], src[64]; + if (!fr->bouquet) { + snprintf(name, sizeof(name), "%s: %s", bi->name, fr->name); + snprintf(src, sizeof(src), "dvb-freesat://28.2E,%04X,%u", bi->nbid, fr->regionid); + fr->bouquet = bouquet_find_by_source(name, src, 1); + } + bouquet_add_service(fr->bouquet, (service_t *)s, lcn); +} + +static void +dvb_freesat_completed + ( dvb_bat_t *b, dvb_bat_id_t *bi, const char *dstr, int nbid ) +{ + dvb_bat_svc_t *bs; + dvb_freesat_svc_t *fs; + dvb_freesat_region_t *fr; + uint16_t sid; + + /* Find all "fallback" services and region specific */ + TAILQ_FOREACH(bs, &bi->services, link) { + sid = bs->svc->s_dvb_service_id; + TAILQ_FOREACH(fs, &b->fservices, link) + if (fs->sid == sid) { + fs->svc = bs->svc; + if ((fs->regionid == 0 && !bs->fallback) || fs->regionid == 65535) { + bs->fallback = fs; + continue; + } + LIST_FOREACH(fr, &b->fregions, link) + if (fr->regionid == fs->regionid) + break; + if (!fr) + tvhtrace(dstr, "cannot find freesat region id %u", fs->regionid); + else + TAILQ_INSERT_TAIL(&fr->services, fs, region_link); + } + } + + /* create bouquets, one per region */ + LIST_FOREACH(fr, &b->fregions, link) { + if (TAILQ_EMPTY(&fr->services)) continue; + TAILQ_FOREACH(fs, &fr->services, region_link) + dvb_freesat_add_service(bi, fr, fs->svc, fs->lcn); + TAILQ_FOREACH(bs, &bi->services, link) + if ((fs = bs->fallback) != NULL) + dvb_freesat_add_service(bi, fr, bs->svc, fs->lcn); + else + dvb_freesat_add_service(bi, fr, bs->svc, 0); + } + + /* Remove all services associated to region, notify the completed status */ + LIST_FOREACH(fr, &b->fregions, link) { + while ((fs = TAILQ_FIRST(&fr->services)) != NULL) + TAILQ_REMOVE(&fr->services, fs, region_link); + if (fr->bouquet) { + bouquet_completed(fr->bouquet); + fr->bouquet = NULL; + } + } + + /* Clear all "fallback/default" services */ + TAILQ_FOREACH(bs, &bi->services, link) + bs->fallback = NULL; +} /* ************************************************************************** * Tables @@ -711,12 +897,105 @@ dvb_pmt_callback /* * NIT/BAT processing (because its near identical) */ + +static void +dvb_bat_destroy_lists( mpegts_table_t *mt ) +{ + dvb_bat_t *b = mt->mt_bat; + dvb_bat_id_t *bi; + dvb_bat_svc_t *bs; + dvb_freesat_region_t *fr; + dvb_freesat_svc_t *fs; + + while ((bi = LIST_FIRST(&b->bats)) != NULL) { + while ((bs = TAILQ_FIRST(&bi->services)) != NULL) { + TAILQ_REMOVE(&bi->services, bs, link); + free(bs); + } + LIST_REMOVE(bi, link); + free(bi); + } + while ((fr = LIST_FIRST(&b->fregions)) != NULL) { + LIST_REMOVE(fr, link); + free(fr); + } + while ((fs = TAILQ_FIRST(&b->fservices)) != NULL) { + TAILQ_REMOVE(&b->fservices, fs, link); + free(fs); + } +} + +void +dvb_bat_destroy( mpegts_table_t *mt ) +{ + dvb_bat_destroy_lists(mt); + free(mt->mt_bat); + mt->mt_bat = NULL; +} + +static void +dvb_bat_completed + ( dvb_bat_t *b, const char *dstr, int tableid, int nbid, mpegts_mux_t *mux ) +{ + dvb_bat_id_t *bi; + dvb_bat_svc_t *bs; + char src[64]; + bouquet_t *bq; + + b->complete = 1; + + LIST_FOREACH(bi, &b->bats, link) { + + if (bi->nbid != nbid) { + if (!bi->complete) + b->complete = 0; + continue; + } + + if (bi->freesat) { + dvb_freesat_completed(b, bi, dstr, nbid); + goto complete; + } + + bq = NULL; + +#if ENABLE_MPEGTS_DVB + if (tableid == 0x4A /* BAT */) { + if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbs_class)) { + dvb_mux_conf_t *mc = &((dvb_mux_t *)mux)->lm_tuning; + if (mc->u.dmc_fe_qpsk.orbital_dir) { + char buf[16]; + dvb_sat_position_to_str(dvb_sat_position(mc), buf, sizeof(buf)); + snprintf(src, sizeof(src), "dvb-bouquet://dvbs,%s,%04X", buf, bi->nbid); + } + } else if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbt_class)) { + snprintf(src, sizeof(src), "dvb-bouquet://dvbt,%04X", bi->nbid); + } else if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbc_class)) { + snprintf(src, sizeof(src), "dvb-bouquet://dvbc,%04X", bi->nbid); + } + if (src[0]) + bq = bouquet_find_by_source(bi->name, src, !TAILQ_EMPTY(&bi->services)); + } +#endif + + if (!bq) continue; + + TAILQ_FOREACH(bs, &bi->services, link) + bouquet_add_service(bq, (service_t *)bs->svc, 0); + + bouquet_completed(bq); + +complete: + bi->complete = 1; + } +} + int dvb_nit_callback (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid) { int save = 0; - int r, sect, last, ver; + int r, sect, last, ver, fsat = 0; uint8_t dtag; int llen, dllen, dlen; const uint8_t *lptr, *dlptr, *dptr; @@ -726,26 +1005,33 @@ dvb_nit_callback char name[256], dauth[256]; mpegts_table_state_t *st = NULL; bouquet_t *bq = NULL; + dvb_bat_t *b = NULL; + dvb_bat_id_t *bi = NULL; const char *charset; /* Net/Bat ID */ nbid = (ptr[0] << 8) | ptr[1]; /* Begin */ - if (tableid != 0x40 && tableid != 0x41 && tableid != 0x4A && tableid != 0xBC) + if (tableid != 0x40 && tableid != 0x41 && tableid != 0x4A && + tableid != DVB_FASTSCAN_NIT_BASE) return -1; + r = dvb_table_begin(mt, ptr, len, tableid, nbid, 7, &st, §, &last, &ver); if (r == 0) { - if (tableid != 0xBC /* fastscan */) { - RB_FOREACH(st, &mt->mt_state, link) - if (st->bouquet) - bouquet_completed((bouquet_t *)st->bouquet); + if (tableid == 0x4A) { + if ((b = mt->mt_bat) != NULL) { + if (!b->complete) + dvb_bat_completed(b, mt->mt_name, tableid, nbid, mm); + if (b->complete) + dvb_bat_destroy_lists(mt); + } } } if (r != 1) return r; /* NIT */ - if (tableid != 0x4A && tableid != 0xBC /* fastscan */) { + if (tableid != 0x4A && tableid != DVB_FASTSCAN_NIT_BASE) { /* Specific NID */ if (mn->mn_nid) { @@ -759,6 +1045,24 @@ dvb_nit_callback } } + /* BAT ID lookup */ + if (tableid == 0x4A) { + if ((b = mt->mt_bat) == NULL) { + b = calloc(1, sizeof(*b)); + TAILQ_INIT(&b->fservices); + mt->mt_bat = b; + } + LIST_FOREACH(bi, &b->bats, link) + if (bi->nbid == nbid) + break; + if (!bi) { + bi = calloc(1, sizeof(*bi)); + bi->nbid = nbid; + TAILQ_INIT(&bi->services); + LIST_INSERT_HEAD(&b->bats, bi, link); + } + } + /* Network Descriptors */ *name = 0; charset = dvb_charset_find(mn, NULL, NULL); @@ -774,17 +1078,29 @@ dvb_nit_callback case DVB_DESC_MULTI_NETWORK_NAME: // TODO: implement this? break; + case DVB_DESC_PRIVATE_DATA: + if (tableid == 0x4A && dlen == 4 && !memcmp(dptr, "FSAT", 4)) + fsat = 1; + break; + case DVB_DESC_FREESAT_REGIONS: + if (fsat) + dvb_freesat_regions(b, mt->mt_name, dptr, dlen, nbid); + break; } } /* Fastscan */ - if (tableid == 0xBC) { + if (tableid == DVB_FASTSCAN_NIT_BASE) { tvhdebug(mt->mt_name, "fastscan %04X (%d) [%s]", nbid, nbid, name); bq = mt->mt_opaque; /* BAT */ } else if (tableid == 0x4A) { tvhdebug(mt->mt_name, "bouquet %04X (%d) [%s]", nbid, nbid, name); + if (bi && *name) { + strncpy(bi->name, name, sizeof(bi->name)-1); + bi->name[sizeof(bi->name)-1] = '\0'; + } /* NIT */ } else { @@ -805,30 +1121,6 @@ dvb_nit_callback break; charset = dvb_charset_find(mn, mux, NULL); -#if ENABLE_MPEGTS_DVB - dauth[0] = 0; - if (!bq && *name && tableid == 0x4A /* BAT */) { - if (idnode_is_instance(&mm->mm_id, &dvb_mux_dvbs_class)) { - dvb_mux_conf_t *mc = &((dvb_mux_t *)mm)->lm_tuning; - if (mc->u.dmc_fe_qpsk.orbital_dir) { - char buf[16]; - dvb_sat_position_to_str(dvb_sat_position(mc), buf, sizeof(buf)); - snprintf(dauth, sizeof(dauth), "dvb-bouquet://dvbs,%s/%s", buf, name); - } - } else if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbt_class)) { - snprintf(dauth, sizeof(dauth), "dvb-bouquet://dvbt/%s", name); - } else if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbc_class)) { - snprintf(dauth, sizeof(dauth), "dvb-bouquet://dvbc/%s", name); - } - } - if (dauth[0]) { - bouquet_t *bq2 = bouquet_find_by_source(name, dauth, 1); - if (bq2 != bq && bq && bq->bq_saveflag) - bouquet_save(bq, 1); - bq = bq2; - st->bouquet = bq; - } -#endif tvhdebug(mt->mt_name, " onid %04X (%d) tsid %04X (%d) mux %p bq %p", onid, onid, tsid, tsid, mux, bq); @@ -887,9 +1179,19 @@ dvb_nit_callback return -1; break; case DVB_DESC_SERVICE_LIST: - if (dvb_desc_service_list(mt->mt_name, dptr, dlen, mux, bq)) + if (dvb_desc_service_list(mt->mt_name, dptr, dlen, mux, bi)) return -1; break; + case DVB_DESC_PRIVATE_DATA: + if (dlen == 4 && !memcmp(dptr, "FSAT", 4)) + fsat = 1; + break; + case DVB_DESC_FREESAT_LCN: + if (tableid == 0x4A && fsat) { + dvb_freesat_local_channels(b, mt->mt_name, dptr, dlen, nbid); + bi->freesat = 1; + } + break; } } } @@ -1163,7 +1465,7 @@ dvb_fs_sdt_callback mpegts_mux_t *mm = mt->mt_mux, *mux; mpegts_network_t *mn = mm->mm_network; mpegts_table_state_t *st = NULL; - bouquet_t *bq = mt->mt_opaque; + bouquet_t *bq = mt->mt_bat; /* Fastscan ID */ nbid = (ptr[0] << 8) | ptr[1]; @@ -1203,7 +1505,7 @@ dvb_fs_sdt_callback s = mpegts_service_find(mm, service_id, 0, 1, &save); charset = dvb_charset_find(mn, mm, s); if (bq && s) - bouquet_add_service(bq, (service_t *)s); + bouquet_add_service(bq, (service_t *)s, 0); /* Descriptor loop */ DVB_DESC_EACH(lptr, llen, dtag, dlen, dptr) { diff --git a/src/input/mpegts/mpegts_table.c b/src/input/mpegts/mpegts_table.c index 3628dfe7..3da63d12 100644 --- a/src/input/mpegts/mpegts_table.c +++ b/src/input/mpegts/mpegts_table.c @@ -142,6 +142,8 @@ mpegts_table_release_ ( mpegts_table_t *mt ) tvhtrace("mpegts", "table: mux %p free %s %02X/%02X (%d) pid %04X (%d)", mt->mt_mux, mt->mt_name, mt->mt_table, mt->mt_mask, mt->mt_table, mt->mt_pid, mt->mt_pid); + if (mt->mt_bat) + dvb_bat_destroy(mt); if (mt->mt_destroy) mt->mt_destroy(mt); free(mt->mt_name); diff --git a/src/prop.c b/src/prop.c index 723ae410..c568fb3a 100644 --- a/src/prop.c +++ b/src/prop.c @@ -107,7 +107,9 @@ prop_write_values /* List */ if (p->islist) - new = htsmsg_field_get_list(f); + new = (f->hmf_type == HMF_MAP) ? + htsmsg_field_get_map(f) : + htsmsg_field_get_list(f); /* Singular */ else { diff --git a/src/service.h b/src/service.h index 3097cb30..dd8faab7 100644 --- a/src/service.h +++ b/src/service.h @@ -180,6 +180,17 @@ void service_instance_destroy void service_instance_list_clear(service_instance_list_t *sil); +/** + * + */ +typedef struct service_lcn { + LIST_ENTRY(service_lcn) sl_link; + void *sl_bouquet; + uint32_t sl_lcn; + uint8_t sl_seen; +} service_lcn_t; + + /** * */ @@ -443,6 +454,11 @@ typedef struct service { int64_t s_current_pts; + /* + * Local channel numbers per bouquet + */ + LIST_HEAD(,service_lcn) s_lcns; + } service_t;