From e76171c573492fe52d56bba25c768db901e017f7 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 12 May 2017 16:31:52 +0200 Subject: [PATCH] mpegts network: create network bouquet for all mpegts networks, fixes #4366 --- src/bouquet.c | 21 ++++-- src/epggrab/module/opentv.c | 1 + src/input/mpegts.h | 8 +++ src/input/mpegts/dvb_psi.c | 12 ++-- src/input/mpegts/iptv/iptv.c | 97 +++++++--------------------- src/input/mpegts/iptv/iptv_auto.c | 2 +- src/input/mpegts/iptv/iptv_mux.c | 2 +- src/input/mpegts/iptv/iptv_private.h | 5 -- src/input/mpegts/iptv/iptv_service.c | 4 -- src/input/mpegts/mpegts_network.c | 92 ++++++++++++++++++++++++++ src/input/mpegts/mpegts_service.c | 4 ++ src/subscriptions.c | 1 - 12 files changed, 153 insertions(+), 96 deletions(-) diff --git a/src/bouquet.c b/src/bouquet.c index c6eb56bd5..9e63a34f4 100644 --- a/src/bouquet.c +++ b/src/bouquet.c @@ -24,6 +24,7 @@ #include "channels.h" #include "service_mapper.h" #include "download.h" +#include "input.h" typedef struct bouquet_download { bouquet_t *bq; @@ -599,13 +600,23 @@ void bouquet_scan ( bouquet_t *bq ) { void mpegts_mux_bouquet_rescan ( const char *src, const char *extra ); - void iptv_bouquet_trigger_by_uuid( const char *uuid ); + char *mpegts_network_uuid = NULL; + if (bq->bq_src) { #if ENABLE_IPTV - if (bq->bq_src && strncmp(bq->bq_src, "iptv-network://", 15) == 0) - return iptv_bouquet_trigger_by_uuid(bq->bq_src + 15); + if (strncmp(bq->bq_src, "iptv-network://", 15) == 0) + mpegts_network_uuid = bq->bq_src + 15; #endif - if (bq->bq_src && strncmp(bq->bq_src, "exturl://", 9) == 0) - return bouquet_download_trigger(bq); + if (strncmp(bq->bq_src, "mpegts-network://", 17) == 0) + mpegts_network_uuid = bq->bq_src + 17; + else if (strncmp(bq->bq_src, "exturl://", 9) == 0) + return bouquet_download_trigger(bq); + + if (mpegts_network_uuid) { + mpegts_network_t *mn = mpegts_network_find(mpegts_network_uuid); + if (mn) + return mpegts_network_bouquet_trigger(mn, 0); + } + } mpegts_mux_bouquet_rescan(bq->bq_src, bq->bq_comment); bq->bq_rescan = 0; } diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index 6abf06f51..8674bae23 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -541,6 +541,7 @@ opentv_desc_channels tvhtrace(LS_OPENTV, "%s: cnum changed (%i != %i)", mt->mt_name, cnum, (int)svc->s_dvb_opentv_chnum); svc->s_dvb_opentv_chnum = cnum; svc->s_dvb_opentv_id = unk; + mpegts_network_bouquet_trigger(mm->mm_network, 0); service_request_save((service_t *)svc, 0); } skip_chnum: diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 6d0158510..f3fa5858a 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -330,12 +330,15 @@ struct mpegts_network mpegts_mux_queue_t mn_scan_pend; // Pending muxes mpegts_mux_queue_t mn_scan_active; // Active muxes mtimer_t mn_scan_timer; // Timer for activity + mtimer_t mn_bouquet_timer; /* * Functions */ void (*mn_delete) (mpegts_network_t*, int delconf); void (*mn_display_name) (mpegts_network_t*, char *buf, size_t len); + int (*mn_bouquet_source) (mpegts_network_t*, char *buf, size_t len); + int (*mn_bouquet_comment) (mpegts_network_t*, char *buf, size_t len); htsmsg_t * (*mn_config_save) (mpegts_network_t*, char *filename, size_t fsize); mpegts_mux_t* (*mn_create_mux) (mpegts_network_t*, void *origin, uint16_t onid, uint16_t tsid, @@ -352,6 +355,7 @@ struct mpegts_network uint16_t mn_satip_source; int mn_autodiscovery; int mn_skipinitscan; + int mn_bouquet; char *mn_charset; int mn_idlescan; int mn_ignore_chnum; @@ -866,6 +870,10 @@ int mpegts_network_set_network_name ( mpegts_network_t *mn, const char *name ); void mpegts_network_scan ( mpegts_network_t *mn ); void mpegts_network_get_type_str( mpegts_network_t *mn, char *buf, size_t buflen ); +void mpegts_network_bouquet_trigger0(mpegts_network_t *mn, int timeout); +static inline void mpegts_network_bouquet_trigger(mpegts_network_t *mn, int timeout) +{ if (mn->mn_bouquet) mpegts_network_bouquet_trigger0(mn, timeout); } + htsmsg_t * mpegts_network_wizard_get ( mpegts_input_t *mi, const idclass_t *idc, mpegts_network_t *mn, const char *lang ); void mpegts_network_wizard_create ( const char *clazz, htsmsg_t **nlist, const char *lang ); diff --git a/src/input/mpegts/dvb_psi.c b/src/input/mpegts/dvb_psi.c index d01fb944a..6deb1761e 100644 --- a/src/input/mpegts/dvb_psi.c +++ b/src/input/mpegts/dvb_psi.c @@ -481,7 +481,7 @@ dvb_desc_service_list static int dvb_desc_local_channel - ( mpegts_table_t *mt, const uint8_t *ptr, int len, + ( mpegts_table_t *mt, mpegts_network_t *mn, const uint8_t *ptr, int len, uint8_t dtag, mpegts_mux_t *mm, dvb_bat_id_t *bi, int prefer ) { int save = 0; @@ -505,6 +505,7 @@ dvb_desc_local_channel s->s_dvb_channel_num != lcn) { s->s_dvb_channel_dtag = dtag; s->s_dvb_channel_num = lcn; + mpegts_network_bouquet_trigger(mn, 0); idnode_changed(&s->s_id); service_refresh_channel((service_t*)s); } @@ -1192,12 +1193,14 @@ dvb_nit_mux int dllen, dlen; const uint8_t *dlptr, *dptr, *lptr_orig = lptr; const char *charset; + mpegts_network_t *mn; char buf[128], dauth[256]; if (mux && mux->mm_enabled != MM_ENABLE) bi = NULL; - charset = dvb_charset_find(mux ? mux->mm_network : mm->mm_network, mux, NULL); + mn = mux ? mux->mm_network : mm->mm_network; + charset = dvb_charset_find(mn, mux, NULL); if (mux) mpegts_mux_nice_name(mux, buf, sizeof(buf)); @@ -1297,7 +1300,7 @@ dvb_nit_mux case 0x88: if (priv == 0x28) { /* HD simulcast */ - if (dvb_desc_local_channel(mt, dptr, dlen, dtag, mux, bi, 1)) + if (dvb_desc_local_channel(mt, mn, dptr, dlen, dtag, mux, bi, 1)) return -1; } break; @@ -1305,7 +1308,7 @@ dvb_nit_mux if (priv == 0 || priv == 0x362275) /* fall thru */ lcn: - if (dvb_desc_local_channel(mt, dptr, dlen, dtag, mux, bi, 0)) + if (dvb_desc_local_channel(mt, mn, dptr, dlen, dtag, mux, bi, 0)) return -1; break; case DVB_DESC_FREESAT_LCN: @@ -1809,6 +1812,7 @@ atsc_vct_callback save = 1; } if (s->s_dvb_channel_num != maj || s->s_dvb_channel_minor != min) { + mpegts_network_bouquet_trigger(mn, 0); s->s_dvb_channel_num = maj; s->s_dvb_channel_minor = min; save = 1; diff --git a/src/input/mpegts/iptv/iptv.c b/src/input/mpegts/iptv/iptv.c index 7d822042d..597c40d0c 100644 --- a/src/input/mpegts/iptv/iptv.c +++ b/src/input/mpegts/iptv/iptv.c @@ -23,7 +23,6 @@ #include "settings.h" #include "htsstr.h" #include "channels.h" -#include "bouquet.h" #include "packet.h" #include @@ -83,51 +82,6 @@ iptv_handler_find ( const char *scheme ) return RB_FIND(&iptv_handlers, &ih, link, ih_cmp); } -/* ************************************************************************** - * IPTV bouquet - * *************************************************************************/ - -static bouquet_t * -iptv_bouquet_get (iptv_network_t *in, int create) -{ - char buf[128], ubuf[UUID_HEX_SIZE]; - snprintf(buf, sizeof(buf), "iptv-network://%s", idnode_uuid_as_str(&in->mn_id, ubuf)); - return bouquet_find_by_source(in->mn_network_name, buf, create); -} - -static void -iptv_bouquet_update(void *aux) -{ - iptv_network_t *in = aux; - mpegts_mux_t *mm; - mpegts_service_t *ms; - bouquet_t *bq = in->in_bouquet ? iptv_bouquet_get(in, 1) : NULL; - uint32_t seen = 0; - if (bq == NULL) - return; - bouquet_change_comment(bq, in->in_url, 1); - LIST_FOREACH(mm, &in->mn_muxes, mm_network_link) - LIST_FOREACH(ms, &mm->mm_services, s_dvb_mux_link) { - bouquet_add_service(bq, (service_t *)ms, ((iptv_mux_t *)mm)->mm_iptv_chnum, NULL); - seen++; - } - bouquet_completed(bq, seen); -} - -void -iptv_bouquet_trigger(iptv_network_t *in, int timeout) -{ - mtimer_arm_rel(&in->in_bouquet_timer, iptv_bouquet_update, in, sec2mono(timeout)); -} - -void -iptv_bouquet_trigger_by_uuid(const char *uuid) -{ - iptv_network_t *in = (iptv_network_t *)idnode_find(uuid, &iptv_network_class, NULL); - iptv_bouquet_trigger(in, 0); -} - - /* ************************************************************************** * IPTV input * *************************************************************************/ @@ -672,6 +626,25 @@ iptv_input_mux_started ( iptv_mux_t *im ) im->mm_iptv_atsc ? DVB_SYS_ATSC_ALL : DVB_SYS_DVBT); } +static int +iptv_network_bouquet_source (mpegts_network_t *mn, char *source, size_t len) +{ + iptv_network_t *in = (mpegts_network_t *)mn; + char ubuf[UUID_HEX_SIZE]; + snprintf(source, len, "iptv-network://%s", idnode_uuid_as_str(&in->mn_id, ubuf)); + return 0; +} + +static int +iptv_network_bouquet_comment (mpegts_network_t *mn, char *comment, size_t len) +{ + iptv_network_t *in = (mpegts_network_t *)mn; + if (in->in_url == NULL || in->in_url[0] == '\0') + return -1; + snprintf(comment, len, "%s", in->in_url); + return 0; +} + static void iptv_network_delete ( mpegts_network_t *mn, int delconf ) { @@ -684,17 +657,13 @@ iptv_network_delete ( mpegts_network_t *mn, int delconf ) idnode_save_check(&mn->mn_id, delconf); - mtimer_disarm(&in->in_bouquet_timer); - if (in->mn_id.in_class == &iptv_auto_network_class) iptv_auto_network_done(in); /* Remove config */ - if (delconf) { + if (delconf) hts_settings_remove("input/iptv/networks/%s", idnode_uuid_as_str(&in->mn_id, ubuf)); - bouquet_delete(iptv_bouquet_get(in, 0)); - } /* delete */ free(in->in_remove_args); @@ -844,22 +813,6 @@ iptv_auto_network_class_notify_url( void *in, const char *lang ) iptv_auto_network_trigger(in); } -static void -iptv_auto_network_class_notify_bouquet( void *in, const char *lang ) -{ - iptv_network_t *mn = in; - bouquet_t *bq; - if (mn->in_bouquet) { - iptv_bouquet_trigger(mn, 0); - } else { - if (mn->in_bouquet) { - bq = iptv_bouquet_get(mn, 0); - if (bq) - bouquet_delete(bq); - } - } -} - static htsmsg_t * iptv_auto_network_class_charset_list(void *o, const char *lang) { @@ -884,14 +837,6 @@ const idclass_t iptv_auto_network_class = { .notify = iptv_auto_network_class_notify_url, .opts = PO_MULTILINE }, - { - .type = PT_BOOL, - .id = "bouquet", - .name = N_("Create bouquet"), - .desc = N_("Create a bouquet from the playlist."), - .off = offsetof(iptv_network_t, in_bouquet), - .notify = iptv_auto_network_class_notify_bouquet, - }, { .type = PT_STR, .id = "ctx_charset", @@ -999,6 +944,8 @@ iptv_network_create0 free(in); return NULL; } + in->mn_bouquet_source = iptv_network_bouquet_source; + in->mn_bouquet_comment= iptv_network_bouquet_comment; in->mn_delete = iptv_network_delete; in->mn_create_service = iptv_network_create_service; in->mn_mux_class = iptv_network_mux_class; diff --git a/src/input/mpegts/iptv/iptv_auto.c b/src/input/mpegts/iptv/iptv_auto.c index f17ca0a3d..74607f6d8 100644 --- a/src/input/mpegts/iptv/iptv_auto.c +++ b/src/input/mpegts/iptv/iptv_auto.c @@ -215,7 +215,7 @@ skip_url: change = 1; } if (im->mm_iptv_chnum != chnum) { - iptv_bouquet_trigger(in, 0); /* propagate LCN change */ + mpegts_network_bouquet_trigger((mpegts_network_t *)in, 0); /* propagate LCN change */ im->mm_iptv_chnum = chnum; change = 1; } diff --git a/src/input/mpegts/iptv/iptv_mux.c b/src/input/mpegts/iptv/iptv_mux.c index eadbe6133..10f474b99 100644 --- a/src/input/mpegts/iptv/iptv_mux.c +++ b/src/input/mpegts/iptv/iptv_mux.c @@ -373,7 +373,7 @@ iptv_mux_create0 ( iptv_network_t *in, const char *uuid, htsmsg_t *conf ) ms->s_pmt_pid = SERVICE_PMT_AUTO; htsmsg_destroy(conf); if (ms) - iptv_bouquet_trigger(in, 0); + mpegts_network_bouquet_trigger((mpegts_network_t *)in, 0); } htsmsg_destroy(c2); diff --git a/src/input/mpegts/iptv/iptv_private.h b/src/input/mpegts/iptv/iptv_private.h index c13bf9052..3b108bacc 100644 --- a/src/input/mpegts/iptv/iptv_private.h +++ b/src/input/mpegts/iptv/iptv_private.h @@ -36,8 +36,6 @@ #define IPTV_KILL_USR1 4 #define IPTV_KILL_USR2 5 -struct bouquet; - extern pthread_mutex_t iptv_lock; typedef struct iptv_input iptv_input_t; @@ -93,8 +91,6 @@ struct iptv_network char *in_url; char *in_url_sane; - int in_bouquet; - mtimer_t in_bouquet_timer; char *in_ctx_charset; int64_t in_channel_number; uint32_t in_refetch_period; @@ -182,7 +178,6 @@ extern iptv_input_t *iptv_input; extern iptv_network_t *iptv_network; -void iptv_bouquet_trigger(iptv_network_t *in, int timeout); int iptv_url_set ( char **url, char **sane_url, const char *str, int allow_file, int allow_pipe ); void iptv_mux_load_all ( void ); diff --git a/src/input/mpegts/iptv/iptv_service.c b/src/input/mpegts/iptv/iptv_service.c index 554e35b71..8cf9e4389 100644 --- a/src/input/mpegts/iptv/iptv_service.c +++ b/src/input/mpegts/iptv/iptv_service.c @@ -119,7 +119,6 @@ iptv_service_create0 ( iptv_mux_t *im, uint16_t sid, uint16_t pmt, const char *uuid, htsmsg_t *conf ) { - iptv_network_t *in = (iptv_network_t *)im->mm_network; iptv_service_t *is = (iptv_service_t*) mpegts_service_create0(calloc(1, sizeof(mpegts_service_t)), &mpegts_service_class, uuid, @@ -138,8 +137,5 @@ iptv_service_create0 if (im->mm_iptv_svcname) is->s_dvb_svcname = strdup(im->mm_iptv_svcname); - if (in->in_bouquet) - iptv_bouquet_trigger(in, 1); - return is; } diff --git a/src/input/mpegts/mpegts_network.c b/src/input/mpegts/mpegts_network.c index ec0a949d3..161ccdb93 100644 --- a/src/input/mpegts/mpegts_network.c +++ b/src/input/mpegts/mpegts_network.c @@ -21,9 +21,12 @@ #include "channels.h" #include "access.h" #include "dvb_charset.h" +#include "bouquet.h" #include +static bouquet_t * mpegts_network_bouquet_get (mpegts_network_t *, int); + /* **************************************************************************** * Class definition * ***************************************************************************/ @@ -140,6 +143,20 @@ mpegts_network_discovery_enum ( void *o, const char *lang ) return strtab2htsmsg(tab, 1, lang); } +static void +mpegts_network_class_notify_bouquet( void *in, const char *lang ) +{ + mpegts_network_t *mn = in; + bouquet_t *bq; + if (mn->mn_bouquet) { + mpegts_network_bouquet_trigger(mn, 0); + } else { + bq = mpegts_network_bouquet_get(mn, 0); + if (bq) + bouquet_delete(bq); + } +} + CLASS_DOC(mpegts_network) PROP_DOC(network_discovery) @@ -189,6 +206,15 @@ const idclass_t mpegts_network_class = .opts = PO_ADVANCED | PO_DOC_NLIST, .def.i = MN_DISCOVERY_NEW }, + { + .type = PT_BOOL, + .id = "bouquet", + .name = N_("Create bouquet"), + .desc = N_("Create a bouquet with all services in the network."), + .off = offsetof(mpegts_network_t, mn_bouquet), + .notify = mpegts_network_class_notify_bouquet, + }, + { .type = PT_BOOL, .id = "skipinitscan", @@ -320,6 +346,65 @@ mpegts_network_display_name strncpy(buf, mn->mn_network_name ?: "unknown", len); } +static bouquet_t * +mpegts_network_bouquet_get (mpegts_network_t *mn, int create) +{ + char buf[128]; + if (mn->mn_bouquet_source(mn, buf, sizeof(buf))) + return NULL; + return bouquet_find_by_source(mn->mn_network_name, buf, create); +} + +static void +mpegts_network_bouquet_update(void *aux) +{ + mpegts_network_t *mn = aux; + mpegts_mux_t *mm; + mpegts_service_t *ms; + int64_t chnum; + char buf[128]; + uint32_t seen = 0; + bouquet_t *bq = mn->mn_bouquet ? mpegts_network_bouquet_get(mn, 1) : NULL; + if (bq == NULL) + return; + if (!mn->mn_bouquet_comment(mn, buf, sizeof(buf))) + bouquet_change_comment(bq, buf, 1); + LIST_FOREACH(mm, &mn->mn_muxes, mm_network_link) + LIST_FOREACH(ms, &mm->mm_services, s_dvb_mux_link) { + chnum = ms->s_channel_number((service_t *)ms); + bouquet_add_service(bq, (service_t *)ms, chnum, NULL); + seen++; + } + bouquet_completed(bq, seen); +} + +void +mpegts_network_bouquet_trigger0(mpegts_network_t *mn, int timeout) +{ + mtimer_arm_rel(&mn->mn_bouquet_timer, mpegts_network_bouquet_update, + mn, sec2mono(timeout)); +} + +static int +mpegts_network_bouquet_source + ( mpegts_network_t *mn, char *source, size_t len) +{ + char ubuf[UUID_HEX_SIZE]; + snprintf(source, len, "mpegts-network://%s", + idnode_uuid_as_str(&mn->mn_id, ubuf)); + return 0; +} + +static int +mpegts_network_bouquet_comment + ( mpegts_network_t *mn, char *comment, size_t len) +{ + if (!mn->mn_provider_network_name || mn->mn_provider_network_name[0] == '\0') + return -1; + snprintf(comment, len, "%s", mn->mn_provider_network_name); + return 0; +} + static htsmsg_t * mpegts_network_config_save ( mpegts_network_t *mn, char *filename, size_t size ) @@ -376,6 +461,11 @@ mpegts_network_delete idnode_save_check(&mn->mn_id, delconf); + /* Bouquet */ + mtimer_disarm(&mn->mn_bouquet_timer); + if (delconf) + bouquet_delete(mpegts_network_bouquet_get(mn, 0)); + /* Remove from global list */ LIST_REMOVE(mn, mn_global_link); @@ -422,6 +512,8 @@ mpegts_network_create0 /* Default callbacks */ mn->mn_display_name = mpegts_network_display_name; + mn->mn_bouquet_source = mpegts_network_bouquet_source; + mn->mn_bouquet_comment= mpegts_network_bouquet_comment; mn->mn_config_save = mpegts_network_config_save; mn->mn_create_mux = mpegts_network_create_mux; mn->mn_create_service = mpegts_network_create_service; diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c index f4f9153b5..5f8532732 100644 --- a/src/input/mpegts/mpegts_service.c +++ b/src/input/mpegts/mpegts_service.c @@ -768,6 +768,7 @@ mpegts_service_create0 { int r; char buf[256]; + mpegts_network_t *mn = mm->mm_network; time_t dispatch_clock = gclk(); /* defaults for older version */ @@ -817,6 +818,9 @@ mpegts_service_create0 mpegts_mux_nice_name(mm, buf, sizeof(buf)); tvhdebug(LS_MPEGTS, "%s - add service %04X %s", buf, s->s_dvb_service_id, s->s_dvb_svcname); + /* Bouquet */ + mpegts_network_bouquet_trigger(mn, 1); + /* Notification */ idnode_notify_changed(&mm->mm_id); idnode_notify_changed(&mm->mm_network->mn_id); diff --git a/src/subscriptions.c b/src/subscriptions.c index a54a69217..e4e3037a7 100644 --- a/src/subscriptions.c +++ b/src/subscriptions.c @@ -936,7 +936,6 @@ subscription_create_from_service(profile_chain_t *prch, * */ #if ENABLE_MPEGTS -#include "input/mpegts.h" th_subscription_t * subscription_create_from_mux(profile_chain_t *prch, tvh_input_t *ti, -- 2.47.3