Cleanup, fixes and improvements of linuxdvb frontend statistics code,

including webui improvements and fixes.
This commit is contained in:
Kai Sommerfeld 2014-07-20 12:16:10 +02:00 committed by Jaroslav Kysela
parent bcb8373f8b
commit 1858323412
8 changed files with 389 additions and 113 deletions

View file

@ -2798,9 +2798,9 @@ htsp_subscription_signal_status(htsp_subscription_t *hs, signal_status_t *sig)
htsmsg_add_str(m, "method", "signalStatus");
htsmsg_add_u32(m, "subscriptionId", hs->hs_sid);
htsmsg_add_str(m, "feStatus", sig->status_text);
if(sig->snr != -2)
if((sig->snr != -2) && (sig->snr_scale == SIGNAL_STATUS_SCALE_RELATIVE))
htsmsg_add_u32(m, "feSNR", sig->snr);
if(sig->signal != -2)
if((sig->signal != -2) && (sig->signal_scale == SIGNAL_STATUS_SCALE_RELATIVE))
htsmsg_add_u32(m, "feSignal", sig->signal);
if(sig->ber != -2)
htsmsg_add_u32(m, "feBER", sig->ber);

View file

@ -80,12 +80,18 @@ tvh_input_stream_create_msg
htsmsg_add_u32(m, "subs", st->subs_count);
htsmsg_add_u32(m, "weight", st->max_weight);
htsmsg_add_u32(m, "signal", st->stats.signal);
htsmsg_add_u32(m, "signal_scale", st->stats.signal_scale);
htsmsg_add_u32(m, "ber", st->stats.ber);
htsmsg_add_u32(m, "snr", st->stats.snr);
htsmsg_add_u32(m, "snr_scale", st->stats.snr_scale);
htsmsg_add_u32(m, "unc", st->stats.unc);
htsmsg_add_u32(m, "bps", st->stats.bps);
htsmsg_add_u32(m, "te", st->stats.te);
htsmsg_add_u32(m, "cc", st->stats.cc);
htsmsg_add_u32(m, "ec_bit", st->stats.ec_bit);
htsmsg_add_u32(m, "tc_bit", st->stats.tc_bit);
htsmsg_add_u32(m, "ec_block", st->stats.ec_block);
htsmsg_add_u32(m, "tc_block", st->stats.tc_block);
return m;
}

View file

@ -34,18 +34,42 @@ typedef LIST_HEAD(,tvh_hardware) tvh_hardware_list_t;
typedef LIST_HEAD(,tvh_input) tvh_input_list_t;
typedef LIST_HEAD(,tvh_input_stream) tvh_input_stream_list_t;
/*
* Scales for input stream statistics values
*/
typedef enum {
INPUT_STREAM_STATS_SCALE_UNKNOWN = 0,
INPUT_STREAM_STATS_SCALE_RELATIVE, // value is unsigned, where 0 means 0% and 65535 means 100%
INPUT_STREAM_STATS_SCALE_DECIBEL // value is measured in dB
} tvh_input_stream_stats_scale_t;
/*
* Input stream structure - used for getting statistics about active streams
*/
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)
int cc; ///< Continuity errors
int te; ///< Transport errors
int signal; ///< signal strength, value depending on signal_scale value:
///< - SCALE_RELATIVE : 0...65535 (which means 0%...100%)
///< - SCALE DECIBEL : 0.0001 dBm units. This value is generally negative.
int snr; ///< signal to noise ratio, value depending on snr_scale value:
///< - SCALE_RELATIVE : 0...65535 (which means 0%...100%)
///< - SCALE DECIBEL : 0.0001 dB units.
int ber; ///< bit error rate (driver/vendor specific value!)
int unc; ///< number of uncorrected blocks
int bps; ///< bandwidth (bps)
int cc; ///< number of continuity errors
int te; ///< number of transport errors
tvh_input_stream_stats_scale_t signal_scale;
tvh_input_stream_stats_scale_t snr_scale;
/* Note: if tc_bit > 0, BER = ec_bit / tc_bit (0...1) else BER = ber (driver specific value) */
int ec_bit; ///< ERROR_BIT_COUNT (same as unc?)
int tc_bit; ///< TOTAL_BIT_COUNT
/* Note: PER = ec_block / tc_block (0...1) */
int ec_block; ///< ERROR_BLOCK_COUNT
int tc_block; ///< TOTAL_BLOCK_COUNT
};
struct tvh_input_stream {

View file

@ -432,6 +432,7 @@ linuxdvb_frontend_monitor ( void *aux )
#if DVB_VER_ATLEAST(5,10)
struct dtv_property fe_properties[6];
struct dtv_properties dtv_prop;
int gotprop;
#endif
lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf));
@ -536,82 +537,194 @@ linuxdvb_frontend_monitor ( void *aux )
/* Statistics - New API */
#if DVB_VER_ATLEAST(5,10)
memset(&fe_properties, 0, sizeof(fe_properties));
/* Signal strength */
fe_properties[0].cmd = DTV_STAT_SIGNAL_STRENGTH;
/* BER */
fe_properties[1].cmd = DTV_STAT_PRE_ERROR_BIT_COUNT;
fe_properties[2].cmd = DTV_STAT_PRE_TOTAL_BIT_COUNT;
/* SNR */
fe_properties[3].cmd = DTV_STAT_CNR;
/* PER */
/* PER / UNC */
fe_properties[4].cmd = DTV_STAT_ERROR_BLOCK_COUNT;
fe_properties[5].cmd = DTV_STAT_TOTAL_BLOCK_COUNT;
dtv_prop.num = 6;
dtv_prop.props = fe_properties;
if(!ioctl(lfe->lfe_fe_fd, FE_GET_PROPERTY, &dtv_prop)) {
/* Signal strength */
gotprop = 0;
if(fe_properties[0].u.st.len > 0) {
if(fe_properties[0].u.st.stat[0].scale == FE_SCALE_RELATIVE)
mmi->mmi_stats.signal = (fe_properties[0].u.st.stat[0].uvalue * 100) / 0xffff;
/* TODO: handle other scales */
if(fe_properties[0].u.st.stat[0].scale == FE_SCALE_RELATIVE) {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.signal = fe_properties[0].u.st.stat[0].uvalue;
gotprop = 1;
}
else if(fe_properties[0].u.st.stat[0].scale == FE_SCALE_DECIBEL) {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_DECIBEL;
mmi->mmi_stats.signal = fe_properties[0].u.st.stat[0].svalue;
gotprop = 1;
}
else {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled signal scale: %d",
fe_properties[0].u.st.stat[0].scale);
}
}
if(!gotprop) {
/* try old API */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16)) {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.signal = u16;
}
else {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide signal strength value.");
}
}
/* Calculate BER from PRE_ERROR and TOTAL_BIT_COUNT */
/* ERROR_BIT_COUNT */
gotprop = 0;
if(fe_properties[1].u.st.len > 0) {
if(fe_properties[1].u.st.stat[0].scale == FE_SCALE_COUNTER)
u16 = fe_properties[1].u.st.stat[0].uvalue;
}
if(fe_properties[2].u.st.len > 0) {
if(fe_properties[2].u.st.stat[0].scale == FE_SCALE_COUNTER) {
if(fe_properties[2].u.st.stat[0].uvalue > 0 )
mmi->mmi_stats.ber = u16 / fe_properties[2].u.st.stat[0].uvalue;
else
mmi->mmi_stats.ber = 0;
if(fe_properties[1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
mmi->mmi_stats.ec_bit = fe_properties[1].u.st.stat[0].uvalue;
gotprop = 1;
}
else
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled ERROR_BIT_COUNT scale: %d",
fe_properties[1].u.st.stat[0].scale);
}
/* TOTAL_BIT_COUNT */
if(gotprop && (fe_properties[2].u.st.len > 0)) {
gotprop = 0;
if(fe_properties[2].u.st.stat[0].scale == FE_SCALE_COUNTER) {
mmi->mmi_stats.tc_bit = fe_properties[2].u.st.stat[0].uvalue;
gotprop = 1;
}
else {
mmi->mmi_stats.ec_bit = 0; /* both values or none */
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled TOTAL_BIT_COUNT scale: %d",
fe_properties[2].u.st.stat[0].scale);
}
}
if(!gotprop) {
/* try old API */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_BER, &u32))
mmi->mmi_stats.ber = u32;
else
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide BER value.");
}
/* SNR */
gotprop = 0;
if(fe_properties[3].u.st.len > 0) {
/* note that decibel scale means 1 = 0.0001 dB units here */
if(fe_properties[3].u.st.stat[0].scale == FE_SCALE_DECIBEL)
mmi->mmi_stats.snr = fe_properties[3].u.st.stat[0].svalue * 0.0001;
/* TODO: handle other scales */
}
/* Calculate PER from PRE_ERROR and TOTAL_BIT_COUNT */
if(fe_properties[4].u.st.len > 0) {
if(fe_properties[4].u.st.stat[0].scale == FE_SCALE_COUNTER)
u16 = fe_properties[4].u.st.stat[0].uvalue;
}
if(fe_properties[5].u.st.len > 0) {
if(fe_properties[5].u.st.stat[0].scale == FE_SCALE_COUNTER) {
if(fe_properties[5].u.st.stat[0].uvalue > 0 )
mmi->mmi_stats.unc = u16 / fe_properties[5].u.st.stat[0].uvalue;
else
mmi->mmi_stats.unc = 0;
if(fe_properties[3].u.st.stat[0].scale == FE_SCALE_RELATIVE) {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.snr = fe_properties[3].u.st.stat[0].uvalue;
gotprop = 1;
}
else if(fe_properties[3].u.st.stat[0].scale == FE_SCALE_DECIBEL) {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_DECIBEL;
mmi->mmi_stats.snr = fe_properties[3].u.st.stat[0].svalue;
gotprop = 1;
}
else {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled SNR scale: %d",
fe_properties[3].u.st.stat[0].scale);
}
}
if(!gotprop) {
/* try old API */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SNR, &u16)) {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.snr = u16;
}
else {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide SNR value.");
}
}
/* ERROR_BLOCK_COUNT == Uncorrected blocks (UNC) */
gotprop = 0;
if(fe_properties[4].u.st.len > 0) {
if(fe_properties[4].u.st.stat[0].scale == FE_SCALE_COUNTER) {
mmi->mmi_stats.unc = mmi->mmi_stats.ec_block = fe_properties[4].u.st.stat[0].uvalue;
gotprop = 1;
}
else
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled ERROR_BLOCK_COUNT scale: %d",
fe_properties[4].u.st.stat[0].scale);
}
/* TOTAL_BLOCK_COUNT */
if(gotprop && (fe_properties[5].u.st.len > 0)) {
gotprop = 0;
if(fe_properties[5].u.st.stat[0].scale == FE_SCALE_COUNTER) {
mmi->mmi_stats.tc_block = fe_properties[5].u.st.stat[0].uvalue;
gotprop = 1;
}
else {
mmi->mmi_stats.ec_block = mmi->mmi_stats.unc = 0; /* both values or none */
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled TOTAL_BLOCK_COUNT scale: %d",
fe_properties[5].u.st.stat[0].scale);
}
}
if(!gotprop) {
/* try old API */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &u32)) {
mmi->mmi_stats.unc = u32;
gotprop = 1;
}
else
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide UNC value.");
}
/* Older API */
} else
#endif
{
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16))
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16)) {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.signal = u16;
}
else {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide signal strength value.");
}
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))
else
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide BER value.");
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SNR, &u16)) {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.snr = u16;
}
else {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide SNR value.");
}
if (!ioctl(lfe->lfe_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &u32))
mmi->mmi_stats.unc = u32;
else
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide UNC value.");
}
/* Send message */
sigstat.status_text = signal2str(status);
sigstat.snr = mmi->mmi_stats.snr;
sigstat.signal = mmi->mmi_stats.signal;
sigstat.ber = mmi->mmi_stats.ber;
sigstat.unc = mmi->mmi_stats.unc;
sigstat.status_text = signal2str(status);
sigstat.snr = mmi->mmi_stats.snr;
sigstat.signal = mmi->mmi_stats.signal;
sigstat.ber = mmi->mmi_stats.ber;
sigstat.unc = mmi->mmi_stats.unc;
sigstat.signal_scale = mmi->mmi_stats.signal_scale;
sigstat.snr_scale = mmi->mmi_stats.snr_scale;
sigstat.ec_bit = mmi->mmi_stats.ec_bit;
sigstat.tc_bit = mmi->mmi_stats.tc_bit;
sigstat.ec_block = mmi->mmi_stats.ec_block;
sigstat.tc_block = mmi->mmi_stats.tc_block;
sm.sm_type = SMT_SIGNAL_STATUS;
sm.sm_data = &sigstat;
LIST_FOREACH(s, &lfe->mi_transports, s_active_link) {

View file

@ -712,15 +712,19 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name,
if (atoi(argv[0]) != lfe->sf_number)
return;
mmi->mmi_stats.signal =
(atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale;
((atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale) * 65535 / 100;
mmi->mmi_stats.signal_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
if (atoi(argv[2]) > 0)
status = SIGNAL_GOOD;
mmi->mmi_stats.snr = atoi(argv[3]);
mmi->mmi_stats.snr = atoi(argv[3]) * 65535 / 100;
mmi->mmi_stats.snr_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
if (status == SIGNAL_GOOD &&
mmi->mmi_stats.signal == 0 && mmi->mmi_stats.snr == 0) {
/* some values that we're tuned */
mmi->mmi_stats.signal = 50;
mmi->mmi_stats.snr = 12;
mmi->mmi_stats.signal = 50 * 65535 / 100;
mmi->mmi_stats.snr = 12 * 65535 / 100;
}
goto ok;
} else if (strncmp(s, "ver=1.0;", 8) == 0) {
@ -733,10 +737,14 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name,
if (atoi(argv[0]) != lfe->sf_number)
return;
mmi->mmi_stats.signal =
(atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale;
((atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale) * 65535 / 100;
mmi->mmi_stats.signal_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
if (atoi(argv[2]) > 0)
status = SIGNAL_GOOD;
mmi->mmi_stats.snr = atoi(argv[3]);
mmi->mmi_stats.snr = atoi(argv[3]) * 65535 / 100;
mmi->mmi_stats.snr_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
goto ok;
} else if (strncmp(s, "ver=1.1;tuner=", 14) == 0) {
n = http_tokenize(s + 14, argv, 4, ',');
@ -745,10 +753,14 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name,
if (atoi(argv[0]) != lfe->sf_number)
return;
mmi->mmi_stats.signal =
(atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale;
((atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale) * 65535 / 100;
mmi->mmi_stats.signal_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
if (atoi(argv[2]) > 0)
status = SIGNAL_GOOD;
mmi->mmi_stats.snr = atoi(argv[3]);
mmi->mmi_stats.snr = atoi(argv[3]) * 65535 / 100;
mmi->mmi_stats.snr_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
goto ok;
}
}
@ -1260,6 +1272,12 @@ satip_frontend_signal_cb( void *aux )
sigstat.signal = mmi->mmi_stats.signal;
sigstat.ber = mmi->mmi_stats.ber;
sigstat.unc = mmi->mmi_stats.unc;
sigstat.signal_scale = mmi->mmi_stats.signal_scale;
sigstat.snr_scale = mmi->mmi_stats.snr_scale;
sigstat.ec_bit = mmi->mmi_stats.ec_bit;
sigstat.tc_bit = mmi->mmi_stats.tc_bit;
sigstat.ec_block = mmi->mmi_stats.ec_block;
sigstat.tc_block = mmi->mmi_stats.tc_block;
sm.sm_type = SMT_SIGNAL_STATUS;
sm.sm_data = &sigstat;
LIST_FOREACH(svc, &lfe->mi_transports, s_active_link) {

View file

@ -237,15 +237,30 @@ typedef enum {
#define SCT_ISSUBTITLE(t) ((t) == SCT_TEXTSUB || (t) == SCT_DVBSUB)
/*
* Scales for signal status values
*/
typedef enum {
SIGNAL_STATUS_SCALE_UNKNOWN = 0,
SIGNAL_STATUS_SCALE_RELATIVE, // value is unsigned, where 0 means 0% and 65535 means 100%
SIGNAL_STATUS_SCALE_DECIBEL // value is measured in dB
} signal_status_scale_t;
/**
* The signal status of a tuner
*/
typedef struct signal_status {
const char *status_text; /* adapter status text */
int snr; /* signal/noise ratio */
signal_status_scale_t snr_scale;
int signal; /* signal strength */
signal_status_scale_t signal_scale;
int ber; /* bit error rate */
int unc; /* uncorrected blocks */
int ec_bit; /* error bit count */
int tc_bit; /* total bit count */
int ec_block; /* error block count */
int tc_block; /* total block count */
} signal_status_t;
/**

View file

@ -345,6 +345,9 @@ Ext.reg("multiselect", Ext.ux.Multiselect);
* License details: http://www.gnu.org/licenses/lgpl.html
*/
/**
* 22/07/2014: ceiling support backported from version 1.2, by Kai Sommerfeld
*/
Ext.namespace('Ext.ux.grid');
Ext.ux.grid.ProgressColumn = function(config) {
@ -355,6 +358,10 @@ Ext.ux.grid.ProgressColumn = function(config) {
};
Ext.extend(Ext.ux.grid.ProgressColumn, Ext.util.Observable, {
/**
* @cfg {Integer} upper limit for full progress indicator (defaults to 100)
*/
ceiling : 100,
/**
* @cfg {String} colored determines whether use special progression coloring
* or the standard Ext.ProgressBar coloring for the bar (defaults to
@ -397,27 +404,30 @@ Ext.extend(Ext.ux.grid.ProgressColumn, Ext.util.Observable, {
},
renderer: function(v, p, record) {
var style = '';
var textClass = (v < 55) ? 'x-progress-text-back' : 'x-progress-text-front' + (Ext.isIE6 ? '-ie6' : '');
var textClass = (v < (this.ceiling / 1.818)) ? 'x-progress-text-back' : 'x-progress-text-front' + (Ext.isIE6 ? '-ie6' : '');
var value = v / this.ceiling * 100;
value = value.toFixed(0);
//ugly hack to deal with IE6 issue
var text = String.format('</div><div class="x-progress-text {0}" style="width:100%;" id="{1}">{2}</div></div>',
textClass, Ext.id(), v + this.textPst
textClass, Ext.id(), value + this.textPst
);
text = (v < 96) ? text.substring(0, text.length - 6) : text.substr(6);
text = (v < (this.ceiling / 1.031)) ? text.substring(0, text.length - 6) : text.substr(6);
if (this.colored == true) {
if (v <= 100 && v > 66)
if (v <= this.ceiling && v > (this.ceiling * 0.66))
style = '-green';
if (v < 67 && v > 33)
if (v < (this.ceiling * 0.67) && v > (this.ceiling * 0.33))
style = '-orange';
if (v < 34)
if (v < (this.ceiling * 0.34))
style = '-red';
}
p.css += ' x-grid3-progresscol';
return String.format(
'<div class="x-progress-wrap"><div class="x-progress-inner"><div class="x-progress-bar{0}" style="width:{1}%;">{2}</div>' +
'</div>', style, v, text
'</div>', style, value, text
);
}
});

View file

@ -181,6 +181,18 @@ tvheadend.status_streams = function() {
name: 'cc'
}, {
name: 'te'
}, {
name: 'signal_scale'
}, {
name: 'snr_scale'
}, {
name: 'ec_bit'
}, {
name: 'tc_bit'
}, {
name: 'ec_block'
}, {
name: 'tc_block'
}
],
url: 'api/status/inputs',
@ -188,49 +200,32 @@ tvheadend.status_streams = function() {
id: 'uuid'
});
tvheadend.comet.on('input_status', function(m) {
if (m.reload != null)
tvheadend.streamStatusStore.reload();
if (m.update != null) {
var r = tvheadend.streamStatusStore.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;
r.data.cc = m.cc;
r.data.te = m.te;
tvheadend.streamStatusStore.afterEdit(r);
tvheadend.streamStatusStore.fireEvent('updated',
tvheadend.streamStatusStore,
r,
Ext.data.Record.COMMIT);
} else {
tvheadend.streamStatusStore.reload();
}
}
});
var signal = new Ext.ux.grid.ProgressColumn({
header: "Signal Strength",
dataIndex: 'signal',
width: 85,
textPst: '%',
colored: true
});
function renderBw(value, item, store) {
var txt = parseInt(value / 1024);
var href = "javascript:tvheadend.stream_bw_monitor('" + store.id + "');";
return '<a href="' + href + '">' + txt + '</a>';
}
function renderBer(value, item, store) {
if (store.data.tc_bit == 0)
return value; // fallback (driver/vendor dependent ber)
// ber = error_bit_count / total_bit_count
var ber = store.data.ec_bit / store.data.tc_bit;
return ber;
}
function renderPer(value, item, store) {
if (value == 0) // value: total_block_count
return '<span class="tvh-grid-unset">Unknown</span>';
// per = error_block_count / total_block_count
var per = store.data.ec_block / value;
return per;
}
var cm = new Ext.grid.ColumnModel([{
width: 100,
width: 120,
header: "Input",
dataIndex: 'input'
}, {
@ -253,31 +248,126 @@ tvheadend.status_streams = function() {
}, {
width: 50,
header: "BER",
dataIndex: 'ber'
dataIndex: 'ber',
renderer: renderBer
}, {
width: 50,
header: "Uncorrected BER",
header: "PER",
dataIndex: 'tc_block',
renderer: renderPer
}, {
width: 50,
header: "Uncorrected Blocks",
dataIndex: 'unc'
}, {
width: 50,
header: "Transport Error",
header: "Transport Errors",
dataIndex: 'te'
}, {
width: 50,
header: "Continuity Error",
header: "Continuity Errors",
dataIndex: 'cc'
}, {
width: 50,
header: "SNR",
dataIndex: 'snr',
renderer: function(value) {
if (value > 0) {
return value.toFixed(1) + " dB";
} else {
return '<span class="tvh-grid-unset">Unknown</span>';
}]);
var has_signal_rel = false;
var has_signal_dbm = false;
var has_snr_rel = false;
var has_snr_db = false;
tvheadend.comet.on('input_status', function(m) {
if (m.reload != null)
tvheadend.streamStatusStore.reload();
if (m.update != null) {
var r = tvheadend.streamStatusStore.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;
r.data.cc = m.cc;
r.data.te = m.te;
r.data.signal_scale = m.signal_scale;
r.data.snr_scale = m.snr_scale;
r.data.ec_bit = m.ec_bit;
r.data.tc_bit = m.tc_bit;
r.data.ec_block = m.ec_block;
r.data.tc_block = m.tc_block;
if (r.data.snr_scale == 1 /* scale_relative */) {
if (!has_snr_rel) {
cm.config.push(new Ext.ux.grid.ProgressColumn({
header: "SNR (%)",
dataIndex: 'snr',
width: 85,
colored: true,
ceiling: 65535
}));
has_snr_rel = true;
}
}
else if (r.data.snr_scale == 2 /* scale_decibel */) {
if (!has_snr_db) {
cm.config.push(new Ext.grid.Column({
width: 50,
header: "SNR (dB)",
dataIndex: 'snr',
renderer: function(value) {
if (value > 0) {
var snr = value * 0.0001;
return snr.toFixed(1) + " dB";
} else {
return '<span class="tvh-grid-unset">Unknown</span>';
}
}
}));
has_snr_db = true;
}
}
if (r.data.signal_scale == 1 /* scale_relative */) {
if (!has_signal_rel) {
cm.config.push(new Ext.ux.grid.ProgressColumn({
header: "Signal Strength (%)",
dataIndex: 'signal',
width: 85,
colored: true,
ceiling: 65535
}));
has_signal_rel = true;
}
}
else if (r.data.signal_scale == 2 /* scale_decibel */) {
if (!has_signal_dbm) {
cm.config.push(new Ext.grid.Column({
width: 50,
header: "Signal Strength (dBm)",
dataIndex: 'signal',
renderer: function(value) {
if (value > 0) {
var snr = value * 0.0001;
return snr.toFixed(1) + " dBm";
} else {
return '<span class="tvh-grid-unset">Unknown</span>';
}
}
}));
has_signal_dbm = true;
}
}
tvheadend.streamStatusStore.afterEdit(r);
tvheadend.streamStatusStore.fireEvent('updated',
tvheadend.streamStatusStore,
r,
Ext.data.Record.COMMIT);
} else {
tvheadend.streamStatusStore.reload();
}
}, signal]);
}
});
var panel = new Ext.grid.GridPanel({
border: false,