diff --git a/src/idnode.c b/src/idnode.c index 6c3b8481..b0b3ab8a 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -152,6 +152,10 @@ idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class) fprintf(stderr, "Id node collision\n"); abort(); } + + /* Fire event */ + idnode_notify(in, NULL, 0, 1); + return 0; } @@ -163,7 +167,7 @@ idnode_unlink(idnode_t *in) { lock_assert(&global_lock); RB_REMOVE(&idnodes, in, in_link); - idnode_updated(in); + idnode_notify(in, NULL, 0, 1); } /* ************************************************************************** @@ -590,7 +594,7 @@ idnode_write0 ( idnode_t *self, htsmsg_t *c, int optmask, int dosave ) } if (save && dosave) { if (savefn) savefn(self); - idnode_notify(self, NULL, 0); + idnode_notify(self, NULL, 0, 0); } return save; } @@ -715,12 +719,31 @@ idnode_serialize0(idnode_t *self, int optmask) * Notifcation * *************************************************************************/ +/** + * Update internal event pipes + */ +static void +idnode_notify_event ( idnode_t *in ) +{ + const idclass_t *ic = in->in_class; + const char *uuid = idnode_uuid_as_str(in); + while (ic) { + if (ic->ic_event) { + htsmsg_t *m = htsmsg_create_map(); + htsmsg_add_str(m, "uuid", uuid); + printf("event = %s\n", ic->ic_event); + notify_by_msg(ic->ic_event, m); + } + ic = ic->ic_super; + } +} + /** * Notify on a given channel */ void idnode_notify - (idnode_t *in, const char *chn, int force) + (idnode_t *in, const char *chn, int force, int event) { const char *uuid = idnode_uuid_as_str(in); @@ -739,12 +762,16 @@ idnode_notify pthread_cond_signal(&idnode_cond); pthread_mutex_unlock(&idnode_mutex); } + + /* Send event */ + if (event) + idnode_notify_event(in); } void idnode_notify_simple (void *in) { - idnode_notify(in, NULL, 0); + idnode_notify(in, NULL, 0, 0); } void @@ -754,6 +781,7 @@ idnode_notify_title_changed (void *in) htsmsg_add_str(m, "uuid", idnode_uuid_as_str(in)); htsmsg_add_str(m, "text", idnode_get_title(in)); notify_by_msg("idnodeUpdated", m); + idnode_notify_event(in); } /* diff --git a/src/idnode.h b/src/idnode.h index 27df9925..2eee4409 100644 --- a/src/idnode.h +++ b/src/idnode.h @@ -46,6 +46,7 @@ typedef struct idclass { const char *ic_class; /// Class name const char *ic_caption; /// Class description const property_t *ic_properties; /// Property list + const char *ic_event; /// Events to fire on add/delete/title /* Callbacks */ idnode_set_t *(*ic_get_childs)(idnode_t *self); @@ -116,9 +117,9 @@ int idnode_is_instance (idnode_t *in, const idclass_t *idc); void *idnode_find (const char *uuid, const idclass_t *idc); idnode_set_t *idnode_find_all(const idclass_t *idc); -#define idnode_updated(in) idnode_notify(in, NULL, 0) +#define idnode_updated(in) idnode_notify(in, NULL, 0, 0) void idnode_notify - (idnode_t *in, const char *chn, int force); + (idnode_t *in, const char *chn, int force, int event); void idnode_notify_simple (void *in); void idnode_notify_title_changed (void *in); diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 98ccac89..116c3af3 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -410,6 +410,7 @@ struct mpegts_input void (*mi_stopped_mux) (mpegts_input_t*,mpegts_mux_instance_t*); int (*mi_has_subscription) (mpegts_input_t*, mpegts_mux_t *mm); int (*mi_grace_period) (mpegts_input_t*, mpegts_mux_t *mm); + idnode_set_t *(*mi_network_list) (mpegts_input_t*); }; /* **************************************************************************** @@ -445,6 +446,8 @@ mpegts_input_t *mpegts_input_create0 mpegts_input_create0(calloc(1, sizeof(mpegts_input_t)),\ &mpegts_input_class, u, c) +#define mpegts_input_find(u) idnode_find(u, &mpegts_input_class); + void mpegts_input_set_network ( mpegts_input_t *mi, mpegts_network_t *mn ); void mpegts_input_open_service ( mpegts_input_t *mi, mpegts_service_t *s, int init ); diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index bc05fae5..b2f7dd3a 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -92,22 +92,15 @@ linuxdvb_frontend_class_network_set(void *o, const void *v) static htsmsg_t * linuxdvb_frontend_class_network_enum(void *o) { - extern const idclass_t linuxdvb_network_class; - int i; - linuxdvb_frontend_t *lfe = o; - linuxdvb_network_t *ln; - htsmsg_t *m = htsmsg_create_list(); - idnode_set_t *is = idnode_find_all(&linuxdvb_network_class); - for (i = 0; i < is->is_count; i++) { - ln = (linuxdvb_network_t*)is->is_array[i]; - if (ln->ln_type == lfe->lfe_info.type) { - htsmsg_t *e = htsmsg_create_map(); - htsmsg_add_str(e, "key", idnode_uuid_as_str(&ln->mn_id)); - htsmsg_add_str(e, "val", ln->mn_network_name); - htsmsg_add_msg(m, NULL, e); - } - } - idnode_set_free(is); + htsmsg_t *m = htsmsg_create_map(); + htsmsg_t *p = htsmsg_create_map(); + htsmsg_add_str(m, "type", "api"); + htsmsg_add_str(m, "uri", "mpegts/input"); + htsmsg_add_str(p, "op", "network_list"); + htsmsg_add_str(p, "uuid", idnode_uuid_as_str((idnode_t*)o)); + htsmsg_add_str(m, "event", "mpegts_network"); + htsmsg_add_msg(m, "params", p); + return m; } @@ -368,6 +361,30 @@ exit: mpegts_input_close_service(mi, s); } +static idnode_set_t * +linuxdvb_frontend_network_list ( mpegts_input_t *mi ) +{ + linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi; + const idclass_t *idc; + extern const idclass_t linuxdvb_network_dvbt_class; + extern const idclass_t linuxdvb_network_dvbc_class; + extern const idclass_t linuxdvb_network_dvbs_class; + extern const idclass_t linuxdvb_network_atsc_class; + + if (lfe->lfe_info.type == FE_OFDM) + idc = &linuxdvb_network_dvbt_class; + else if (lfe->lfe_info.type == FE_QAM) + idc = &linuxdvb_network_dvbc_class; + else if (lfe->lfe_info.type == FE_QPSK) + idc = &linuxdvb_network_dvbs_class; + else if (lfe->lfe_info.type == FE_ATSC) + idc = &linuxdvb_network_atsc_class; + else + return NULL; + + return idnode_find_all(idc); +} + /* ************************************************************************** * Data processing * *************************************************************************/ @@ -829,6 +846,7 @@ linuxdvb_frontend_create0 lfe->mi_stop_mux = linuxdvb_frontend_stop_mux; lfe->mi_open_service = linuxdvb_frontend_open_service; lfe->mi_close_service = linuxdvb_frontend_close_service; + lfe->mi_network_list = linuxdvb_frontend_network_list; lfe->lfe_open_pid = linuxdvb_frontend_open_pid; /* Adapter link */ diff --git a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c index 14d3282d..637d5115 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c @@ -564,9 +564,6 @@ linuxdvb_satconf_create0 if (!ls->ls_lnb) ls->ls_lnb = linuxdvb_lnb_create0(NULL, NULL, ls); - /* Notification */ - idnode_notify(&ls->mi_id, "linuxdvb_satconf", 0); - return ls; } diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c index 27ae9bda..47e9f054 100644 --- a/src/input/mpegts/mpegts_mux.c +++ b/src/input/mpegts/mpegts_mux.c @@ -163,6 +163,7 @@ const idclass_t mpegts_mux_class = { .ic_class = "mpegts_mux", .ic_caption = "MPEGTS Multiplex", + .ic_event = "mpegts_mux", .ic_save = mpegts_mux_class_save, .ic_properties = (const property_t[]){ { @@ -556,10 +557,6 @@ mpegts_mux_create0 mm->mm_display_name(mm, buf, sizeof(buf)); tvhtrace("mpegts", "%s - created", buf); - /* Notification */ - idnode_notify(&mm->mm_id, "mpegts_mux", 0); - idnode_updated(&mn->mn_id); - return mm; } diff --git a/src/input/mpegts/mpegts_network.c b/src/input/mpegts/mpegts_network.c index e49feb6c..d54da922 100644 --- a/src/input/mpegts/mpegts_network.c +++ b/src/input/mpegts/mpegts_network.c @@ -84,12 +84,14 @@ const idclass_t mpegts_network_class = .ic_class = "mpegts_network", .ic_caption = "MPEGTS Network", .ic_save = mpegts_network_class_save, + .ic_event = "mpegts_network", .ic_properties = (const property_t[]){ { .type = PT_STR, .id = "networkname", .name = "Network Name", .off = offsetof(mpegts_network_t, mn_network_name), + .notify = idnode_notify_title_changed, }, { .type = PT_U16, @@ -279,9 +281,6 @@ mpegts_network_create0 mn->mn_display_name(mn, buf, sizeof(buf)); tvhtrace("mpegts", "created network %s", buf); - /* Notification */ - idnode_notify(&mn->mn_id, "mpegts_network", 0); - return mn; } diff --git a/src/service.c b/src/service.c index 6c80ec35..0798351f 100644 --- a/src/service.c +++ b/src/service.c @@ -441,9 +441,6 @@ service_create0 if (conf) service_load(t, conf); - /* Notify */ - idnode_notify(&t->s_id, "service", 0); - return t; } diff --git a/src/webui/extjs_dvb.c b/src/webui/extjs_dvb.c index 4b0c0981..d1a1cc56 100644 --- a/src/webui/extjs_dvb.c +++ b/src/webui/extjs_dvb.c @@ -387,7 +387,7 @@ extjs_mpegts_input (http_connection_t *hc, const char *remain, void *opaque) { mpegts_input_t *mi; - //mpegts_network_t *mn; + mpegts_network_t *mn; htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out = htsmsg_create_map(); @@ -403,8 +403,32 @@ extjs_mpegts_input idnode_set_add(&ins, (idnode_t*)mi, &conf.filter); extjs_idnode_grid(&ins, &conf, out); } else if (!strcmp(op, "class")) { - htsmsg_t *list= idclass_serialize(&mpegts_input_class); + htsmsg_t *list = idclass_serialize(&mpegts_input_class); htsmsg_add_msg(out, "entries", list); + } else if (!strcmp(op, "network_list")) { + const char *uuid = http_arg_get(&hc->hc_req_args, "uuid"); + if (!uuid) return HTTP_STATUS_BAD_REQUEST; + pthread_mutex_lock(&global_lock); + mi = mpegts_input_find(uuid); + if (mi) { + int i; + idnode_set_t *is = mi->mi_network_list(mi); + if (is) { + htsmsg_t *l = htsmsg_create_list(); + for (i = 0; i < is->is_count; i++) { + char buf[256]; + htsmsg_t *e = htsmsg_create_map(); + mn = (mpegts_network_t*)is->is_array[i]; + htsmsg_add_str(e, "key", idnode_uuid_as_str(is->is_array[i])); + mn->mn_display_name(mn, buf, sizeof(buf)); + htsmsg_add_str(e, "val", buf); + htsmsg_add_msg(l, NULL, e); + } + htsmsg_add_msg(out, "entries", l); + idnode_set_free(is); + } + } + pthread_mutex_unlock(&global_lock); #if 0 } else if (!strcmp(op, "network_class")) { const char *uuid = http_arg_get(&hc->hc_req_args, "uuid"); diff --git a/src/webui/static/app/idnode.js b/src/webui/static/app/idnode.js index 7b56d24d..b2345f39 100644 --- a/src/webui/static/app/idnode.js +++ b/src/webui/static/app/idnode.js @@ -1,3 +1,41 @@ +/* + * Combobox stores + */ +tvheadend.idnode_enum_stores = {} + +tvheadend.idnode_get_enum = function ( conf ) +{ + /* Build key */ + key = conf.url; + if (conf.event) + key += conf.event; + if (conf.params) + key += Ext.util.JSON.encode(conf.params); + + /* Use cached */ + if (key in tvheadend.idnode_enum_stores) + return tvheadend.idnode_enum_stores[key]; + + /* Build combobox */ + var st = new Ext.data.JsonStore({ + root : conf.root || 'entries', + url : conf.url, + baseParams : conf.params || {}, + fields : conf.fields || [ 'key', 'val' ], + autoLoad : true, + }); + tvheadend.idnode_enum_stores[key] = st; + + /* Event to update */ + if (conf.event) { + tvheadend.comet.on(conf.event, function(){ + st.reload(); + }); + } + + return st; +} + json_decode = function(d) { if (d && d.responseText) { @@ -18,6 +56,16 @@ json_decode = function(d) tvheadend.idnode_enum_store = function(f) { var store = null; + + /* API fetch */ + if (f.enum.type == 'api') { + return tvheadend.idnode_get_enum({ + url : 'api/' + f.enum.uri, + params : f.enum.params, + event : f.enum.event + }); + } + switch (f.type) { case 'str': if (f.enum.length > 0 && f.enum[0] instanceof Object)