From 8ac1b3d7ed11de9025364ef7c5cf19b846f13bd0 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 6 Sep 2013 22:49:22 +0100 Subject: [PATCH] status: added back in basic status info It will now show subscriptions and streams (tuners/muxes combined). --- Makefile | 2 + src/api.c | 1 + src/api.h | 3 +- src/api/api_input.c | 71 ++++++++++++++ src/descrambler/capmt.c | 4 +- src/input.h | 57 ++++++++++- src/input/mpegts.h | 17 +++- src/input/mpegts/linuxdvb/linuxdvb_adapter.c | 8 +- src/input/mpegts/linuxdvb/linuxdvb_device.c | 10 +- src/input/mpegts/linuxdvb/linuxdvb_frontend.c | 47 +++------- src/input/mpegts/linuxdvb/linuxdvb_hardware.c | 2 +- src/input/mpegts/linuxdvb/linuxdvb_satconf.c | 6 +- src/input/mpegts/mpegts_input.c | 76 ++++++++++++++- src/webui/static/app/status.js | 94 ++++++++++++++----- 14 files changed, 314 insertions(+), 84 deletions(-) create mode 100644 src/api/api_input.c diff --git a/Makefile b/Makefile index aaaad9da..a80ecbcd 100644 --- a/Makefile +++ b/Makefile @@ -109,10 +109,12 @@ SRCS = src/version.c \ src/tvhtime.c \ src/descrambler/descrambler.c \ src/service_mapper.c \ + src/input.c \ SRCS += \ src/api.c \ src/api/api_idnode.c \ + src/api/api_input.c \ src/api/api_channel.c \ src/api/api_service.c \ src/api/api_mpegts.c \ diff --git a/src/api.c b/src/api.c index 2a0b4b67..16895d9c 100644 --- a/src/api.c +++ b/src/api.c @@ -116,6 +116,7 @@ void api_init ( void ) /* Subsystems */ api_idnode_init(); + api_input_init(); api_mpegts_init(); api_service_init(); api_channel_init(); diff --git a/src/api.h b/src/api.h index ca4be19e..a3897540 100644 --- a/src/api.h +++ b/src/api.h @@ -57,9 +57,10 @@ int api_exec ( const char *subsystem, htsmsg_t *args, htsmsg_t **resp ); */ void api_init ( void ); void api_idnode_init ( void ); -void api_mpegts_init ( void ); +void api_input_init ( void ); void api_service_init ( void ); void api_channel_init ( void ); +void api_mpegts_init ( void ); /* * IDnode diff --git a/src/api/api_input.c b/src/api/api_input.c new file mode 100644 index 00000000..f6cef7db --- /dev/null +++ b/src/api/api_input.c @@ -0,0 +1,71 @@ +/* + * API - channel related calls + * + * Copyright (C) 2013 Adam Sutton + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TVH_API_INPUT_H__ +#define __TVH_API_INPUT_H__ + +#include "tvheadend.h" +#include "idnode.h" +#include "input.h" +#include "access.h" +#include "api.h" + +static int +api_input_status + ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) +{ + int c = 0; + htsmsg_t *l, *e; + tvh_input_t *ti; + tvh_input_stream_t *st; + tvh_input_stream_list_t stl = { 0 }; + + TVH_INPUT_FOREACH(ti) + ti->ti_get_streams(ti, &stl); + + l = htsmsg_create_list(); + while ((st = LIST_FIRST(&stl))) { + e = tvh_input_stream_create_msg(st); + htsmsg_add_msg(l, NULL, e); + tvh_input_stream_destroy(st); + LIST_REMOVE(st, link); + free(st); + c++; + } + + *resp = htsmsg_create_map(); + htsmsg_add_msg(*resp, "entries", l); + htsmsg_add_u32(*resp, "totalCount", c); + + return 0; +} + +void api_input_init ( void ) +{ + static api_hook_t ah[] = { + { "input/status", ACCESS_ANONYMOUS, api_input_status, NULL }, +// { "input/tree", ACCESS_ANONYMOUS, NULL, NULL }, + { NULL }, + }; + + api_register_all(ah); +} + + +#endif /* __TVH_API_INPUT_H__ */ diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 0b4b5656..98237940 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -654,7 +654,7 @@ capmt_table_input(struct th_descrambler *td, struct service *s, return; if (!t->s_dvb_active_input) return; lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input; - if (!idnode_is_instance(&lfe->mi_id, &linuxdvb_frontend_class)) + if (!idnode_is_instance(&lfe->ti_id, &linuxdvb_frontend_class)) return; adapter_num = ((linuxdvb_adapter_t*)lfe->lh_parent)->la_number; @@ -893,7 +893,7 @@ capmt_service_start(service_t *s) return; if (!t->s_dvb_active_input) return; lfe = (linuxdvb_frontend_t*)t->s_dvb_active_input; - if (!idnode_is_instance(&lfe->mi_id, &linuxdvb_frontend_class)) + if (!idnode_is_instance(&lfe->ti_id, &linuxdvb_frontend_class)) return; tuner = ((linuxdvb_adapter_t*)lfe->lh_parent)->la_number; diff --git a/src/input.h b/src/input.h index a377d7bc..7bd63ba2 100644 --- a/src/input.h +++ b/src/input.h @@ -19,6 +19,61 @@ #ifndef __TVH_INPUT_H__ #define __TVH_INPUT_H__ +#include "idnode.h" +#include "queue.h" + +/* + * Input stream structure - used for getting statistics about active streams + */ +typedef struct tvh_input_stream_stats +{ + int signal; ///< Signal level (0-100) + int ber; ///< Bit error rate (0-100?) + int unc; ///< Uncorrectable errors + int snr; ///< Signal 2 Noise (dB) + int bps; ///< Bandwidth (bps) +} tvh_input_stream_stats_t; + +typedef struct tvh_input_stream { + + LIST_ENTRY(tvh_input_stream) link; + + char *uuid; ///< Unique ID of the entry (used for updates) + char *input_name; ///< Name of the parent input + char *stream_name; ///< Name for this stream + int subs_count; ///< Number of subcscriptions + int max_weight; ///< Current max weight + + tvh_input_stream_stats_t stats; + +} tvh_input_stream_t; + +typedef LIST_HEAD(,tvh_input_stream) tvh_input_stream_list_t; + +/* + * Generic input super-class + */ +typedef struct tvh_input { + idnode_t ti_id; + + LIST_ENTRY(tvh_input) ti_link; + + void (*ti_get_streams) (struct tvh_input *, tvh_input_stream_list_t*); + +} tvh_input_t; + +typedef LIST_HEAD(,tvh_input) tvh_input_list_t; +tvh_input_list_t tvh_inputs; + +#define TVH_INPUT_FOREACH(x) LIST_FOREACH(x, &tvh_inputs, ti_link) + +void input_init ( void ); + +htsmsg_t * tvh_input_stream_create_msg ( tvh_input_stream_t *st ); + +void tvh_input_stream_destroy ( tvh_input_stream_t *st ); + + #if ENABLE_MPEGPS #include "input/mpegps.h" #endif @@ -36,6 +91,4 @@ #endif #endif -void input_init ( void ); - #endif /* __TVH_INPUT_H__ */ diff --git a/src/input/mpegts.h b/src/input/mpegts.h index cb71fb66..95e7f9dd 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -20,6 +20,7 @@ #ifndef __TVH_MPEGTS_H__ #define __TVH_MPEGTS_H__ +#include "input.h" #include "service.h" #include "mpegts/dvb.h" @@ -374,8 +375,9 @@ struct mpegts_mux_instance LIST_HEAD(,th_subscription) mmi_subs; - // TODO: remove this - int mmi_tune_failed; // this is really DVB + tvh_input_stream_stats_t mmi_stats; + + int mmi_tune_failed; void (*mmi_delete) (mpegts_mux_instance_t *mmi); }; @@ -390,7 +392,7 @@ struct mpegts_mux_sub /* Input source */ struct mpegts_input { - idnode_t mi_id; + tvh_input_t; int mi_enabled; @@ -407,6 +409,11 @@ struct mpegts_input LIST_HEAD(,mpegts_mux_instance) mi_mux_instances; + /* + * Status + */ + gtimer_t mi_status_timer; + /* * Input processing */ @@ -416,8 +423,6 @@ struct mpegts_input LIST_HEAD(,service) mi_transports; - int mi_bytes; - struct mpegts_table_feed_queue mi_table_feed; pthread_cond_t mi_table_feed_cond; // Bound to mi_delivery_mutex @@ -484,6 +489,8 @@ 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 ); void mpegts_input_close_service ( mpegts_input_t *mi, mpegts_service_t *s ); +void mpegts_input_status_timer ( void *p ); + void mpegts_network_register_builder ( const idclass_t *idc, mpegts_network_t *(*build)(const idclass_t *idc, htsmsg_t *conf) ); diff --git a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c index c4407c3b..b2fadf60 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c @@ -71,7 +71,7 @@ linuxdvb_adapter_save ( linuxdvb_adapter_t *la, htsmsg_t *m ) htsmsg_t *l; linuxdvb_hardware_t *lh; - idnode_save(&la->mi_id, m); + idnode_save(&la->ti_id, m); htsmsg_add_u32(m, "number", la->la_number); if (la->la_rootpath) htsmsg_add_str(m, "rootpath", la->la_rootpath); @@ -81,7 +81,7 @@ linuxdvb_adapter_save ( linuxdvb_adapter_t *la, htsmsg_t *m ) LIST_FOREACH(lh, &la->lh_children, lh_parent_link) { htsmsg_t *e = htsmsg_create_map(); linuxdvb_frontend_save((linuxdvb_frontend_t*)lh, e); - htsmsg_add_msg(l, idnode_uuid_as_str(&lh->mi_id), e); + htsmsg_add_msg(l, idnode_uuid_as_str(&lh->ti_id), e); } htsmsg_add_msg(m, "frontends", l); } @@ -118,7 +118,7 @@ linuxdvb_adapter_create0 linuxdvb_adapter_t *la; la = calloc(1, sizeof(linuxdvb_adapter_t)); - if (idnode_insert(&la->mi_id, uuid, &linuxdvb_adapter_class)) { + if (idnode_insert(&la->ti_id, uuid, &linuxdvb_adapter_class)) { free(la); return NULL; } @@ -131,7 +131,7 @@ linuxdvb_adapter_create0 if (!conf) return la; - idnode_load(&la->mi_id, conf); + idnode_load(&la->ti_id, conf); if (!htsmsg_get_u32(conf, "number", &u32)) la->la_number = u32; if ((str = htsmsg_get_str(conf, "rootpath"))) diff --git a/src/input/mpegts/linuxdvb/linuxdvb_device.c b/src/input/mpegts/linuxdvb/linuxdvb_device.c index 37b4b0e8..9e288f0d 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_device.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_device.c @@ -175,20 +175,20 @@ void linuxdvb_device_save ( linuxdvb_device_t *ld ) m = htsmsg_create_map(); - idnode_save(&ld->mi_id, m); + idnode_save(&ld->ti_id, m); /* Adapters */ l = htsmsg_create_map(); LIST_FOREACH(lh, &ld->lh_children, lh_parent_link) { e = htsmsg_create_map(); linuxdvb_adapter_save((linuxdvb_adapter_t*)lh, e); - htsmsg_add_msg(l, idnode_uuid_as_str(&lh->mi_id), e); + htsmsg_add_msg(l, idnode_uuid_as_str(&lh->ti_id), e); } htsmsg_add_msg(m, "adapters", l); /* Save */ hts_settings_save(m, "input/linuxdvb/devices/%s", - idnode_uuid_as_str(&ld->mi_id)); + idnode_uuid_as_str(&ld->ti_id)); } const idclass_t linuxdvb_device_class = @@ -226,7 +226,7 @@ linuxdvb_device_create0 ( const char *uuid, htsmsg_t *conf ) /* Create */ ld = calloc(1, sizeof(linuxdvb_device_t)); - if (idnode_insert(&ld->mi_id, uuid, &linuxdvb_device_class)) { + if (idnode_insert(&ld->ti_id, uuid, &linuxdvb_device_class)) { free(ld); return NULL; } @@ -240,7 +240,7 @@ linuxdvb_device_create0 ( const char *uuid, htsmsg_t *conf ) return ld; /* Load config */ - idnode_load(&ld->mi_id, conf); + idnode_load(&ld->ti_id, conf); get_min_dvb_adapter(&ld->ld_devid); /* Adapters */ diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index e4de3eff..7dc76866 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -1,5 +1,4 @@ /* -rk_class * Tvheadend - Linux DVB frontend * * Copyright (C) 2013 Adam Sutton @@ -461,42 +460,11 @@ linuxdvb_frontend_open_all } } -static void -linuxdvb_frontend_monitor_stats ( linuxdvb_frontend_t *lfe, const char *name ) -{ - int bw; - htsmsg_t *m, *l, *e; - mpegts_mux_instance_t *mmi; - - /* Send message */ - m = htsmsg_create_map(); - htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&lfe->mi_id)); - htsmsg_add_str(m, "name", name); - htsmsg_add_str(m, "type", "linuxdvb"); - - /* Mux list */ - if ((mmi = LIST_FIRST(&lfe->mi_mux_active))) { - char buf[256]; - l = htsmsg_create_list(); - e = htsmsg_create_map(); - mmi->mmi_mux->mm_display_name(mmi->mmi_mux, buf, sizeof(buf)); - htsmsg_add_str(e, "name", buf); - htsmsg_add_u32(e, "bytes", 0); // TODO - // TODO: signal info - htsmsg_add_msg(l, NULL, e); - htsmsg_add_msg(m, "muxes", l); - } - - /* Total data */ - bw = atomic_exchange(&lfe->mi_bytes, 0); - htsmsg_add_u32(m, "bytes", bw); - - notify_by_msg("input", m); -} - static void linuxdvb_frontend_monitor ( void *aux ) { + uint16_t u16; + uint32_t u32; char buf[256]; linuxdvb_frontend_t *lfe = aux; mpegts_mux_instance_t *mmi = LIST_FIRST(&lfe->mi_mux_active); @@ -573,8 +541,15 @@ linuxdvb_frontend_monitor ( void *aux ) } } - /* Monitor stats */ - linuxdvb_frontend_monitor_stats(lfe, buf); + /* Statistics */ + if (!ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16)) + mmi->mmi_stats.signal = u16; + if (!ioctl(lfe->lfe_fe_fd, FE_READ_BER, &u32)) + mmi->mmi_stats.ber = u32; + if (!ioctl(lfe->lfe_fe_fd, FE_READ_SNR, &u16)) + mmi->mmi_stats.snr = u16; + if (!ioctl(lfe->lfe_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &u32)) + mmi->mmi_stats.unc = u32; } static void * diff --git a/src/input/mpegts/linuxdvb/linuxdvb_hardware.c b/src/input/mpegts/linuxdvb/linuxdvb_hardware.c index 79df2c5a..6150f279 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_hardware.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_hardware.c @@ -35,7 +35,7 @@ linuxdvb_hardware_enumerate ( linuxdvb_hardware_list_t *list ) linuxdvb_hardware_t *lh; idnode_set_t *set = idnode_set_create(); LIST_FOREACH(lh, list, lh_parent_link) - idnode_set_add(set, &lh->mi_id, NULL); + idnode_set_add(set, &lh->ti_id, NULL); return set; } diff --git a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c index eee864dc..b9a95637 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c @@ -91,7 +91,7 @@ linuxdvb_satconf_class_frontend_get ( void *o ) static const char *s; linuxdvb_satconf_t *ls = o; if (ls->ls_frontend) - s = idnode_uuid_as_str(&ls->ls_frontend->mi_id); + s = idnode_uuid_as_str(&ls->ls_frontend->ti_id); else s = NULL; return &s; @@ -123,7 +123,7 @@ linuxdvb_satconf_class_frontend_enum (void *o) for (i = 0; i < is->is_count; i++) { mpegts_input_t *mi = (mpegts_input_t*)is->is_array[i]; htsmsg_t *e = htsmsg_create_map(); - htsmsg_add_str(e, "key", idnode_uuid_as_str(&mi->mi_id)); + htsmsg_add_str(e, "key", idnode_uuid_as_str(&mi->ti_id)); *buf = 0; mi->mi_display_name(mi, buf, sizeof(buf)); htsmsg_add_str(e, "val", buf); @@ -585,7 +585,7 @@ linuxdvb_diseqc_class_save ( idnode_t *o ) { linuxdvb_diseqc_t *ld = (linuxdvb_diseqc_t*)o; if (ld->ld_satconf) - linuxdvb_satconf_class_save(&ld->ld_satconf->mi_id); + linuxdvb_satconf_class_save(&ld->ld_satconf->ti_id); } const idclass_t linuxdvb_diseqc_class = diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 429d80a1..090de1f8 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -22,6 +22,7 @@ #include "streaming.h" #include "subscriptions.h" #include "atomic.h" +#include "notify.h" #include #include @@ -164,8 +165,15 @@ static void mpegts_input_started_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi ) { + /* Arm timer */ + if (LIST_FIRST(&mi->mi_mux_active) == NULL) + gtimer_arm(&mi->mi_status_timer, mpegts_input_status_timer, + mi, 1); + + /* Update */ mmi->mmi_mux->mm_active = mmi; LIST_INSERT_HEAD(&mi->mi_mux_active, mmi, mmi_active_link); + notify_reload("input_status"); } static void @@ -177,6 +185,10 @@ mpegts_input_stopped_mux mmi->mmi_mux->mm_active = NULL; LIST_REMOVE(mmi, mmi_active_link); + /* Disarm timer */ + if (LIST_FIRST(&mi->mi_mux_active) == NULL) + gtimer_disarm(&mi->mi_status_timer); + mi->mi_display_name(mi, buf, sizeof(buf)); tvhtrace("mpegts", "%s - flush subscribers", buf); s = LIST_FIRST(&mi->mi_transports); @@ -185,6 +197,7 @@ mpegts_input_stopped_mux service_remove_subscriber(s, NULL, SM_CODE_SUBSCRIPTION_OVERRIDDEN); s = LIST_NEXT(s, s_active_link); } + notify_reload("input_status"); } static int @@ -290,7 +303,7 @@ mpegts_input_recv_packets pthread_mutex_unlock(&mi->mi_delivery_mutex); /* Bandwidth monitoring */ - atomic_add(&mi->mi_bytes, i); + atomic_add(&mmi->mmi_stats.bps, i); /* Reset buffer */ if (len) memmove(tsb, tsb+i, len); @@ -371,6 +384,59 @@ mpegts_input_flush_mux pthread_mutex_unlock(&mi->mi_delivery_mutex); } +static void +mpegts_input_stream_status + ( mpegts_mux_instance_t *mmi, tvh_input_stream_t *st ) +{ + int s = 0, w = 0; + char buf[512]; + mmi->mmi_mux->mm_display_name(mmi->mmi_mux, buf, sizeof(buf)); + st->uuid = strdup(idnode_uuid_as_str(&mmi->mmi_id)); + st->input_name = strdup(mmi->mmi_input->mi_displayname?:""); + st->stream_name = strdup(buf); + st->subs_count = s; + st->max_weight = w; + st->stats = mmi->mmi_stats; + st->stats.bps = atomic_exchange(&mmi->mmi_stats.bps, 0) * 8; +} + +static void +mpegts_input_get_streams + ( tvh_input_t *i, tvh_input_stream_list_t *isl ) +{ + tvh_input_stream_t *st; + mpegts_input_t *mi = (mpegts_input_t*)i; + mpegts_mux_instance_t *mmi; + + LIST_FOREACH(mmi, &mi->mi_mux_active, mmi_active_link) { + st = calloc(1, sizeof(tvh_input_stream_t)); + mpegts_input_stream_status(mmi, st); + LIST_INSERT_HEAD(isl, st, link); + } +} + +/* ************************************************************************** + * Status monitoring + * *************************************************************************/ + +void +mpegts_input_status_timer ( void *p ) +{ + tvh_input_stream_t st; + mpegts_input_t *mi = p; + mpegts_mux_instance_t *mmi; + htsmsg_t *e; + LIST_FOREACH(mmi, &mi->mi_mux_active, mmi_active_link) { + memset(&st, 0, sizeof(st)); + mpegts_input_stream_status(mmi, &st); + e = tvh_input_stream_create_msg(&st); + htsmsg_add_u32(e, "update", 1); + notify_by_msg("input_status", e); + tvh_input_stream_destroy(&st); + } + gtimer_arm(&mi->mi_status_timer, mpegts_input_status_timer, mi, 1); +} + /* ************************************************************************** * Creation/Config * *************************************************************************/ @@ -383,7 +449,8 @@ mpegts_input_create0 ( mpegts_input_t *mi, const idclass_t *class, const char *uuid, htsmsg_t *c ) { - idnode_insert(&mi->mi_id, uuid, class); + idnode_insert(&mi->ti_id, uuid, class); + LIST_INSERT_HEAD(&tvh_inputs, (tvh_input_t*)mi, ti_link); /* Defaults */ mi->mi_is_enabled = mpegts_input_is_enabled; @@ -398,6 +465,7 @@ mpegts_input_create0 mi->mi_started_mux = mpegts_input_started_mux; mi->mi_stopped_mux = mpegts_input_stopped_mux; mi->mi_has_subscription = mpegts_input_has_subscription; + mi->ti_get_streams = mpegts_input_get_streams; /* Index */ mi->mi_instance = ++mpegts_input_idx; @@ -417,7 +485,7 @@ mpegts_input_create0 /* Load config */ if (c) - idnode_load(&mi->mi_id, c); + idnode_load(&mi->ti_id, c); return mi; } @@ -425,7 +493,7 @@ mpegts_input_create0 void mpegts_input_save ( mpegts_input_t *mi, htsmsg_t *m ) { - idnode_save(&mi->mi_id, m); + idnode_save(&mi->ti_id, m); } void diff --git a/src/webui/static/app/status.js b/src/webui/static/app/status.js index 2caa8fb7..32aa9c74 100644 --- a/src/webui/static/app/status.js +++ b/src/webui/static/app/status.js @@ -136,9 +136,61 @@ tvheadend.status_subs = function() { /** - * + * Streams */ -tvheadend.status_adapters = function() { +tvheadend.status_streams = function() { + + var stream_store = new Ext.data.JsonStore({ + root : 'entries', + totalProperty : 'totalCount', + fields : [ { + name : 'uuid' + }, { + name : 'input' + }, { + name : 'username' + }, { + name : 'stream' + }, { + name : 'subs' + }, { + name : 'weight' + }, { + name : 'signal' + }, { + name : 'ber' + }, { + name : 'unc' + }, { + name : 'snr' + }, { + name : 'bps' + }, + ], + url : 'api/input/status', + autoLoad : true, + id : 'uuid' + }); + + tvheadend.comet.on('input_status', function(m){ + if (m.reload != null) stream_store.reload(); + if (m.update != null) { + var r = stream_store.getById(m.uuid); + if (r) { + r.data.subs = m.subs; + r.data.weight = m.weight; + r.data.signal = m.signal; + r.data.ber = m.ber; + r.data.unc = m.unc; + r.data.snr = m.snr; + r.data.bps = m.bps; + stream_store.afterEdit(r); + stream_store.fireEvent('updated', stream_store, r, Ext.data.Record.COMMIT); + } else { + stream_store.reload(); + } + } + }); var signal = new Ext.ux.grid.ProgressColumn({ header : "Signal Strength", @@ -149,30 +201,30 @@ tvheadend.status_adapters = function() { }); function renderBw(value) { - return parseInt(value / 125); + return parseInt(value / 1024); } var cm = new Ext.grid.ColumnModel([{ - width : 50, - header : "Name", - dataIndex : 'name' - },{ - width : 50, - header : "Hardware device", - dataIndex : 'path' + width : 100, + header : "Input", + dataIndex : 'input' },{ width : 100, - header : "Currently tuned to", - dataIndex : 'currentMux' + header : "Stream", + dataIndex : 'stream' + },{ + width : 50, + header : "Subs #", + dataIndex : 'subs' + },{ + width : 50, + header : "Weight", + dataIndex : 'weight' },{ width : 100, header : "Bandwidth (kb/s)", - dataIndex : 'bw', + dataIndex : 'bps', renderer: renderBw - },{ - width : 50, - header : "Used for", - dataIndex : 'reason' },{ width : 50, header : "Bit error rate", @@ -180,7 +232,7 @@ tvheadend.status_adapters = function() { },{ width : 50, header : "Uncorrected bit error rate", - dataIndex : 'uncavg' + dataIndex : 'unc' },{ width : 50, header : "SNR", @@ -199,9 +251,9 @@ tvheadend.status_adapters = function() { loadMask : true, stripeRows : true, disableSelection : true, - title : 'Adapters', + title : 'Stream', iconCls : 'hardware', - store : tvheadend.tvAdapterStore, + store : stream_store, cm : cm, flex: 1, viewConfig : { @@ -218,7 +270,7 @@ tvheadend.status = function() { layout : 'vbox', title : 'Status', iconCls : 'eye', - items : [ new tvheadend.status_subs, new tvheadend.status_adapters ] + items : [ new tvheadend.status_subs, new tvheadend.status_streams ] }); return panel;