#include "channels.h"
#include "service_mapper.h"
#include "download.h"
+#include "input.h"
typedef struct bouquet_download {
bouquet_t *bq;
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;
}
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:
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,
uint16_t mn_satip_source;
int mn_autodiscovery;
int mn_skipinitscan;
+ int mn_bouquet;
char *mn_charset;
int mn_idlescan;
int mn_ignore_chnum;
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 );
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;
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);
}
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));
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;
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:
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;
#include "settings.h"
#include "htsstr.h"
#include "channels.h"
-#include "bouquet.h"
#include "packet.h"
#include <sys/socket.h>
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
* *************************************************************************/
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 )
{
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);
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)
{
.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",
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;
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;
}
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);
#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;
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;
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 );
( 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,
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;
}
#include "channels.h"
#include "access.h"
#include "dvb_charset.h"
+#include "bouquet.h"
#include <assert.h>
+static bouquet_t * mpegts_network_bouquet_get (mpegts_network_t *, int);
+
/* ****************************************************************************
* Class definition
* ***************************************************************************/
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)
.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",
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 )
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);
/* 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;
{
int r;
char buf[256];
+ mpegts_network_t *mn = mm->mm_network;
time_t dispatch_clock = gclk();
/* defaults for older version */
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);
*
*/
#if ENABLE_MPEGTS
-#include "input/mpegts.h"
th_subscription_t *
subscription_create_from_mux(profile_chain_t *prch,
tvh_input_t *ti,