From bda5d8ce255bd0ce44d3b181eb1cbebc342ab44e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 17 Apr 2015 11:11:00 +0200 Subject: [PATCH] stream status: add possibility to clear statistics, introduce tvh_input_instance_t --- src/api/api_status.c | 40 +++++++++ src/input.c | 25 ++++++ src/input.h | 22 +++++ src/input/mpegts.h | 11 +-- src/input/mpegts/linuxdvb/linuxdvb_frontend.c | 84 +++++++++---------- src/input/mpegts/mpegts_input.c | 36 ++++---- src/input/mpegts/mpegts_mux.c | 18 ++-- src/input/mpegts/satip/satip_frontend.c | 56 ++++++------- src/input/mpegts/tsfile/tsfile_mux.c | 8 +- .../mpegts/tvhdhomerun/tvhdhomerun_frontend.c | 18 ++-- src/webui/static/app/status.js | 31 ++++++- 11 files changed, 232 insertions(+), 117 deletions(-) diff --git a/src/api/api_status.c b/src/api/api_status.c index 0057109f..0f7cfef5 100644 --- a/src/api/api_status.c +++ b/src/api/api_status.c @@ -37,8 +37,10 @@ api_status_inputs tvh_input_stream_t *st; tvh_input_stream_list_t stl = { 0 }; + pthread_mutex_lock(&global_lock); TVH_INPUT_FOREACH(ti) ti->ti_get_streams(ti, &stl); + pthread_mutex_unlock(&global_lock); l = htsmsg_create_list(); while ((st = LIST_FIRST(&stl))) { @@ -67,11 +69,13 @@ api_status_subscriptions l = htsmsg_create_list(); c = 0; + pthread_mutex_lock(&global_lock); LIST_FOREACH(ths, &subscriptions, ths_global_link) { e = subscription_create_msg(ths); htsmsg_add_msg(l, NULL, e); c++; } + pthread_mutex_unlock(&global_lock); *resp = htsmsg_create_map(); htsmsg_add_msg(*resp, "entries", l); @@ -120,12 +124,48 @@ api_connections_cancel return 0; } +static void +input_clear_stats(const char *uuid) +{ + tvh_input_instance_t *tii; + + pthread_mutex_lock(&global_lock); + if ((tii = tvh_input_instance_find_by_uuid(uuid)) != NULL) + if (tii->tii_clear_stats) + tii->tii_clear_stats(tii); + pthread_mutex_unlock(&global_lock); +} + +static int +api_status_input_clear_stats + ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) +{ + htsmsg_field_t *f; + htsmsg_t *ids; + const char *uuid; + + if (!(f = htsmsg_field_find(args, "uuid"))) + return EINVAL; + if (!(ids = htsmsg_field_get_list(f))) { + if ((uuid = htsmsg_field_get_str(f)) == NULL) + return EINVAL; + input_clear_stats(uuid); + } else { + HTSMSG_FOREACH(f, ids) { + if ((uuid = htsmsg_field_get_str(f)) == NULL) continue; + input_clear_stats(uuid); + } + } + return 0; +} + void api_status_init ( void ) { static api_hook_t ah[] = { { "status/connections", ACCESS_ADMIN, api_status_connections, NULL }, { "status/subscriptions", ACCESS_ADMIN, api_status_subscriptions, NULL }, { "status/inputs", ACCESS_ADMIN, api_status_inputs, NULL }, + { "status/inputclrstats", ACCESS_ADMIN, api_status_input_clear_stats, NULL }, { "connections/cancel", ACCESS_ADMIN, api_connections_cancel, NULL }, { NULL }, }; diff --git a/src/input.c b/src/input.c index cdac24f9..c346dee6 100644 --- a/src/input.c +++ b/src/input.c @@ -18,10 +18,18 @@ #include "input.h" #include "notify.h" +#include "access.h" tvh_input_list_t tvh_inputs; tvh_hardware_list_t tvh_hardware; +const idclass_t tvh_input_instance_class = +{ + .ic_class = "tvh_input_instance", + .ic_caption = "Input Instance", + .ic_perm_def = ACCESS_ADMIN +}; + /* * Create entry */ @@ -59,6 +67,23 @@ tvh_hardware_delete ( tvh_hardware_t *th ) idnode_unlink(&th->th_id); } +/* + * + */ + +void +tvh_input_instance_clear_stats ( tvh_input_instance_t *tii ) +{ + tvh_input_stream_stats_t *s = &tii->tii_stats; + + atomic_exchange(&s->ber, 0); + atomic_exchange(&s->unc, 0); + atomic_exchange(&s->cc, 0); + atomic_exchange(&s->te, 0); + atomic_exchange(&s->ec_block, 0); + atomic_exchange(&s->tc_block, 0); +} + /* * Input status handling */ diff --git a/src/input.h b/src/input.h index 68254b68..7b023a1c 100644 --- a/src/input.h +++ b/src/input.h @@ -27,6 +27,7 @@ */ typedef struct tvh_hardware tvh_hardware_t; typedef struct tvh_input tvh_input_t; +typedef struct tvh_input_instance tvh_input_instance_t; typedef struct tvh_input_stream tvh_input_stream_t; typedef struct tvh_input_stream_stats tvh_input_stream_stats_t; @@ -87,6 +88,20 @@ struct tvh_input { void (*ti_get_streams) (struct tvh_input *, tvh_input_stream_list_t*); }; +/* + * Generic input instance super-class + */ +struct tvh_input_instance { + idnode_t tii_id; + + LIST_ENTRY(tvh_input_instance) tii_input_link; + + tvh_input_stream_stats_t tii_stats; + + void (*tii_delete) (tvh_input_instance_t *tii); + void (*tii_clear_stats) (tvh_input_instance_t *tii); +}; + /* * Generic hardware super-class */ @@ -103,6 +118,7 @@ void tvh_hardware_delete ( tvh_hardware_t *th ); * Class and Global list defs */ extern const idclass_t tvh_input_class; +extern const idclass_t tvh_input_instance_class; tvh_input_list_t tvh_inputs; tvh_hardware_list_t tvh_hardware; @@ -120,6 +136,12 @@ htsmsg_t * tvh_input_stream_create_msg ( tvh_input_stream_t *st ); void tvh_input_stream_destroy ( tvh_input_stream_t *st ); +static inline tvh_input_instance_t * +tvh_input_instance_find_by_uuid(const char *uuid) + { return (tvh_input_instance_t*)idnode_find(uuid, &tvh_input_instance_class, NULL); } + +void tvh_input_instance_clear_stats ( tvh_input_instance_t *tii ); + /* * Input subsystem includes */ diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 66eda6d0..58c21b3d 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -548,10 +548,9 @@ struct mpegts_service /* Physical mux instance */ struct mpegts_mux_instance { - idnode_t mmi_id; + tvh_input_instance_t; LIST_ENTRY(mpegts_mux_instance) mmi_mux_link; - LIST_ENTRY(mpegts_mux_instance) mmi_input_link; LIST_ENTRY(mpegts_mux_instance) mmi_active_link; streaming_pad_t mmi_streaming_pad; @@ -559,11 +558,7 @@ struct mpegts_mux_instance mpegts_mux_t *mmi_mux; mpegts_input_t *mmi_input; - tvh_input_stream_stats_t mmi_stats; - int mmi_tune_failed; - - void (*mmi_delete) (mpegts_mux_instance_t *mmi); }; struct mpegts_mux_sub @@ -598,7 +593,7 @@ struct mpegts_input mpegts_network_link_list_t mi_networks; - LIST_HEAD(,mpegts_mux_instance) mi_mux_instances; + LIST_HEAD(,tvh_input_instance) mi_mux_instances; /* @@ -795,7 +790,7 @@ mpegts_service_t *mpegts_mux_find_service(mpegts_mux_t *ms, uint16_t sid); &type##_class, uuid,\ mi, mm); -void mpegts_mux_instance_delete ( mpegts_mux_instance_t *mmi ); +void mpegts_mux_instance_delete ( tvh_input_instance_t *tii ); int mpegts_mux_instance_start ( mpegts_mux_instance_t **mmiptr ); diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index 59fc77d9..8daedbbf 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -662,18 +662,18 @@ linuxdvb_frontend_monitor ( void *aux ) gotprop = 0; if(ioctl_check(lfe, 1) && fe_properties[0].u.st.len > 0) { if(fe_properties[0].u.st.stat[0].scale == FE_SCALE_RELATIVE) { - mmi->mmi_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; - mmi->mmi_stats.signal = fe_properties[0].u.st.stat[0].uvalue; + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; + mmi->tii_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 = SIGNAL_STATUS_SCALE_DECIBEL; - mmi->mmi_stats.signal = fe_properties[0].u.st.stat[0].svalue; + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_DECIBEL; + mmi->tii_stats.signal = fe_properties[0].u.st.stat[0].svalue; gotprop = 1; } else { ioctl_bad(lfe, 1); - mmi->mmi_stats.signal_scale = SIGNAL_STATUS_SCALE_UNKNOWN; + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_UNKNOWN; if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unhandled signal scale: %d", fe_properties[0].u.st.stat[0].scale); @@ -682,12 +682,12 @@ linuxdvb_frontend_monitor ( void *aux ) if(!gotprop && ioctl_check(lfe, 2)) { /* try old API */ if (!ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16)) { - mmi->mmi_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; - mmi->mmi_stats.signal = u16; + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; + mmi->tii_stats.signal = u16; } else { ioctl_bad(lfe, 2); - mmi->mmi_stats.signal_scale = SIGNAL_STATUS_SCALE_UNKNOWN; + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_UNKNOWN; if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide signal strength value."); } @@ -697,7 +697,7 @@ linuxdvb_frontend_monitor ( void *aux ) gotprop = 0; if(ioctl_check(lfe, 3) && fe_properties[1].u.st.len > 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; + mmi->tii_stats.ec_bit = fe_properties[1].u.st.stat[0].uvalue; gotprop = 1; } else { @@ -711,12 +711,12 @@ linuxdvb_frontend_monitor ( void *aux ) if(gotprop && (fe_properties[2].u.st.len > 0)) { gotprop = 0; if(ioctl_check(lfe, 4) && fe_properties[2].u.st.stat[0].scale == FE_SCALE_COUNTER) { - mmi->mmi_stats.tc_bit = fe_properties[2].u.st.stat[0].uvalue; + mmi->tii_stats.tc_bit = fe_properties[2].u.st.stat[0].uvalue; gotprop = 1; } else { ioctl_bad(lfe, 4); - mmi->mmi_stats.ec_bit = 0; /* both values or none */ + mmi->tii_stats.ec_bit = 0; /* both values or none */ if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unhandled TOTAL_BIT_COUNT scale: %d", fe_properties[2].u.st.stat[0].scale); @@ -725,7 +725,7 @@ linuxdvb_frontend_monitor ( void *aux ) if(!gotprop && ioctl_check(lfe, 5)) { /* try old API */ if (!ioctl(lfe->lfe_fe_fd, FE_READ_BER, &u32)) - mmi->mmi_stats.ber = u32; + mmi->tii_stats.ber = u32; else { ioctl_bad(lfe, 5); if (logit) @@ -737,18 +737,18 @@ linuxdvb_frontend_monitor ( void *aux ) gotprop = 0; if(ioctl_check(lfe, 6) && fe_properties[3].u.st.len > 0) { if(fe_properties[3].u.st.stat[0].scale == FE_SCALE_RELATIVE) { - mmi->mmi_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; - mmi->mmi_stats.snr = fe_properties[3].u.st.stat[0].uvalue; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; + mmi->tii_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 = SIGNAL_STATUS_SCALE_DECIBEL; - mmi->mmi_stats.snr = fe_properties[3].u.st.stat[0].svalue; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_DECIBEL; + mmi->tii_stats.snr = fe_properties[3].u.st.stat[0].svalue; gotprop = 1; } else { ioctl_bad(lfe, 6); - mmi->mmi_stats.snr_scale = SIGNAL_STATUS_SCALE_UNKNOWN; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_UNKNOWN; if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unhandled SNR scale: %d", fe_properties[3].u.st.stat[0].scale); @@ -757,12 +757,12 @@ linuxdvb_frontend_monitor ( void *aux ) if(!gotprop && ioctl_check(lfe, 7)) { /* try old API */ if (!ioctl(lfe->lfe_fe_fd, FE_READ_SNR, &u16)) { - mmi->mmi_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; - mmi->mmi_stats.snr = u16; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; + mmi->tii_stats.snr = u16; } else { ioctl_bad(lfe, 7); - mmi->mmi_stats.snr_scale = SIGNAL_STATUS_SCALE_UNKNOWN; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_UNKNOWN; if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide SNR value."); } @@ -772,7 +772,7 @@ linuxdvb_frontend_monitor ( void *aux ) gotprop = 0; if(ioctl_check(lfe, 8) && 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; + mmi->tii_stats.unc = mmi->tii_stats.ec_block = fe_properties[4].u.st.stat[0].uvalue; gotprop = 1; } else { @@ -787,12 +787,12 @@ linuxdvb_frontend_monitor ( void *aux ) if(gotprop && (fe_properties[5].u.st.len > 0)) { gotprop = 0; if(ioctl_check(lfe, 9) && fe_properties[5].u.st.stat[0].scale == FE_SCALE_COUNTER) { - mmi->mmi_stats.tc_block = fe_properties[5].u.st.stat[0].uvalue; + mmi->tii_stats.tc_block = fe_properties[5].u.st.stat[0].uvalue; gotprop = 1; } else { ioctl_bad(lfe, 9); - mmi->mmi_stats.ec_block = mmi->mmi_stats.unc = 0; /* both values or none */ + mmi->tii_stats.ec_block = mmi->tii_stats.unc = 0; /* both values or none */ if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unhandled TOTAL_BLOCK_COUNT scale: %d", fe_properties[5].u.st.stat[0].scale); @@ -801,7 +801,7 @@ linuxdvb_frontend_monitor ( void *aux ) if(!gotprop && ioctl_check(lfe, 10)) { /* try old API */ if (!ioctl(lfe->lfe_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &u32)) { - mmi->mmi_stats.unc = u32; + mmi->tii_stats.unc = u32; gotprop = 1; } else { @@ -816,34 +816,34 @@ linuxdvb_frontend_monitor ( void *aux ) { ioctl_bad(lfe, 0); if (ioctl_check(lfe, 1) && !ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16)) { - mmi->mmi_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; - mmi->mmi_stats.signal = u16; + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; + mmi->tii_stats.signal = u16; } else { ioctl_bad(lfe, 1); - mmi->mmi_stats.signal_scale = SIGNAL_STATUS_SCALE_UNKNOWN; + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_UNKNOWN; if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide signal strength value."); } if (ioctl_check(lfe, 2) && !ioctl(lfe->lfe_fe_fd, FE_READ_BER, &u32)) - mmi->mmi_stats.ber = u32; + mmi->tii_stats.ber = u32; else { ioctl_bad(lfe, 2); if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide BER value."); } if (ioctl_check(lfe, 3) && !ioctl(lfe->lfe_fe_fd, FE_READ_SNR, &u16)) { - mmi->mmi_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; - mmi->mmi_stats.snr = u16; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; + mmi->tii_stats.snr = u16; } else { ioctl_bad(lfe, 3); - mmi->mmi_stats.snr_scale = SIGNAL_STATUS_SCALE_UNKNOWN; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_UNKNOWN; if (logit) tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide SNR value."); } if (ioctl_check(lfe, 4) && !ioctl(lfe->lfe_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &u32)) - mmi->mmi_stats.unc = u32; + mmi->tii_stats.unc = u32; else { ioctl_bad(lfe, 4); if (logit) @@ -853,16 +853,16 @@ linuxdvb_frontend_monitor ( void *aux ) /* 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.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; + sigstat.snr = mmi->tii_stats.snr; + sigstat.signal = mmi->tii_stats.signal; + sigstat.ber = mmi->tii_stats.ber; + sigstat.unc = mmi->tii_stats.unc; + sigstat.signal_scale = mmi->tii_stats.signal_scale; + sigstat.snr_scale = mmi->tii_stats.snr_scale; + sigstat.ec_bit = mmi->tii_stats.ec_bit; + sigstat.tc_bit = mmi->tii_stats.tc_bit; + sigstat.ec_block = mmi->tii_stats.ec_block; + sigstat.tc_block = mmi->tii_stats.tc_block; sm.sm_type = SMT_SIGNAL_STATUS; sm.sm_data = &sigstat; LIST_FOREACH(s, &lfe->mi_transports, s_active_link) { diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index a3b0ad06..f27fdfe3 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -673,10 +673,10 @@ mpegts_input_create_mux_instance ( mpegts_input_t *mi, mpegts_mux_t *mm ) { extern const idclass_t mpegts_mux_instance_class; - mpegts_mux_instance_t *mmi; - LIST_FOREACH(mmi, &mi->mi_mux_instances, mmi_input_link) - if (mmi->mmi_mux == mm) break; - if (!mmi) + tvh_input_instance_t *tii; + LIST_FOREACH(tii, &mi->mi_mux_instances, tii_input_link) + if (((mpegts_mux_instance_t *)tii)->mmi_mux == mm) break; + if (!tii) (void)mpegts_mux_instance_create(mpegts_mux_instance, NULL, mi, mm); } @@ -871,7 +871,7 @@ mpegts_input_recv_packets /* Check for sync */ while ( (len >= MIN_TS_SYN) && ((len2 = ts_sync_count(tsb, len)) < MIN_TS_SYN) ) { - mmi->mmi_stats.unc++; + mmi->tii_stats.unc++; --len; ++tsb; ++off; @@ -1079,7 +1079,7 @@ mpegts_input_process /* Transport error */ if (pid & 0x8000) { if ((pid & 0x1FFF) != 0x1FFF) - ++mmi->mmi_stats.te; + ++mmi->tii_stats.te; } pid &= 0x1FFF; @@ -1102,7 +1102,7 @@ mpegts_input_process cc = tsb2[3] & 0x0f; if (cc2 != 0xff && cc2 != cc) { tvhtrace("mpegts", "pid %04X cc err %2d != %2d", pid, cc, cc2); - ++mmi->mmi_stats.cc; + ++mmi->tii_stats.cc; } cc2 = (cc + 1) & 0xF; } @@ -1214,7 +1214,7 @@ done: pthread_cond_signal(&mi->mi_table_cond); /* Bandwidth monitoring */ - atomic_add(&mmi->mmi_stats.bps, tsb - mpkt->mp_data); + atomic_add(&mmi->tii_stats.bps, tsb - mpkt->mp_data); } static void * @@ -1352,15 +1352,15 @@ mpegts_input_stream_status w = MAX(w, ths->ths_weight); } - st->uuid = strdup(idnode_uuid_as_str(&mmi->mmi_id)); + st->uuid = strdup(idnode_uuid_as_str(&mmi->tii_id)); mi->mi_display_name(mi, buf, sizeof(buf)); st->input_name = strdup(buf); mpegts_mux_nice_name(mm, buf, sizeof(buf)); 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; + st->stats = mmi->tii_stats; + st->stats.bps = atomic_exchange(&mmi->tii_stats.bps, 0) * 8; } static void @@ -1524,19 +1524,19 @@ void mpegts_input_delete ( mpegts_input_t *mi, int delconf ) { mpegts_network_link_t *mnl; - mpegts_mux_instance_t *mmi, *mmi_next; + tvh_input_instance_t *tii, *tii_next; /* Remove networks */ while ((mnl = LIST_FIRST(&mi->mi_networks))) mpegts_input_del_network(mnl); /* Remove mux instances assigned to this input */ - mmi = LIST_FIRST(&mi->mi_mux_instances); - while (mmi) { - mmi_next = LIST_NEXT(mmi, mmi_input_link); - if (mmi->mmi_input == mi) - mmi->mmi_delete(mmi); - mmi = mmi_next; + tii = LIST_FIRST(&mi->mi_mux_instances); + while (tii) { + tii_next = LIST_NEXT(tii, tii_input_link); + if (((mpegts_mux_instance_t *)tii)->mmi_input == mi) + tii->tii_delete(tii); + tii = tii_next; } /* Remove global refs */ diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c index 9a007ac6..1f9c6670 100644 --- a/src/input/mpegts/mpegts_mux.c +++ b/src/input/mpegts/mpegts_mux.c @@ -37,6 +37,7 @@ static void mpegts_mux_scan_timeout ( void *p ); const idclass_t mpegts_mux_instance_class = { + .ic_super = &tvh_input_instance_class, .ic_class = "mpegts_mux_instance", .ic_caption = "MPEGTS Multiplex Phy", .ic_perm_def = ACCESS_ADMIN @@ -44,11 +45,13 @@ const idclass_t mpegts_mux_instance_class = void mpegts_mux_instance_delete - ( mpegts_mux_instance_t *mmi ) + ( tvh_input_instance_t *tii ) { - idnode_unlink(&mmi->mmi_id); + mpegts_mux_instance_t *mmi = (mpegts_mux_instance_t *)tii; + + idnode_unlink(&tii->tii_id); LIST_REMOVE(mmi, mmi_mux_link); - LIST_REMOVE(mmi, mmi_input_link); + LIST_REMOVE(tii, tii_input_link); free(mmi); } @@ -58,7 +61,7 @@ mpegts_mux_instance_create0 mpegts_input_t *mi, mpegts_mux_t *mm ) { // TODO: does this need to be an idnode? - if (idnode_insert(&mmi->mmi_id, uuid, class, 0)) { + if (idnode_insert(&mmi->tii_id, uuid, class, 0)) { free(mmi); return NULL; } @@ -68,10 +71,11 @@ mpegts_mux_instance_create0 mmi->mmi_input = mi; /* Callbacks */ - mmi->mmi_delete = mpegts_mux_instance_delete; + mmi->tii_delete = mpegts_mux_instance_delete; + mmi->tii_clear_stats = tvh_input_instance_clear_stats; LIST_INSERT_HEAD(&mm->mm_instances, mmi, mmi_mux_link); - LIST_INSERT_HEAD(&mi->mi_mux_instances, mmi, mmi_input_link); + LIST_INSERT_HEAD(&mi->mi_mux_instances, (tvh_input_instance_t *)mmi, tii_input_link); return mmi; @@ -621,7 +625,7 @@ mpegts_mux_delete ( mpegts_mux_t *mm, int delconf ) /* Remove instances */ while ((mmi = LIST_FIRST(&mm->mm_instances))) { - mmi->mmi_delete(mmi); + mmi->tii_delete((tvh_input_instance_t *)mmi); } /* Remove raw subscribers */ diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index 23b7a2ed..f80590c2 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -76,16 +76,16 @@ satip_frontend_signal_cb( void *aux ) lfe->sf_tables = 1; } sigstat.status_text = signal2str(lfe->sf_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; + sigstat.snr = mmi->tii_stats.snr; + sigstat.signal = mmi->tii_stats.signal; + sigstat.ber = mmi->tii_stats.ber; + sigstat.unc = mmi->tii_stats.unc; + sigstat.signal_scale = mmi->tii_stats.signal_scale; + sigstat.snr_scale = mmi->tii_stats.snr_scale; + sigstat.ec_bit = mmi->tii_stats.ec_bit; + sigstat.tc_bit = mmi->tii_stats.tc_bit; + sigstat.ec_block = mmi->tii_stats.ec_block; + sigstat.tc_block = mmi->tii_stats.tc_block; sm.sm_type = SMT_SIGNAL_STATUS; sm.sm_data = &sigstat; LIST_FOREACH(svc, &lfe->mi_transports, s_active_link) { @@ -722,20 +722,20 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name, return; if (atoi(argv[0]) != lfe->sf_number) return; - mmi->mmi_stats.signal = + mmi->tii_stats.signal = atoi(argv[1]) * 0xffff / lfe->sf_device->sd_sig_scale; - mmi->mmi_stats.signal_scale = + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; if (atoi(argv[2]) > 0) status = SIGNAL_GOOD; - mmi->mmi_stats.snr = atoi(argv[3]) * 0xffff / 15; - mmi->mmi_stats.snr_scale = + mmi->tii_stats.snr = atoi(argv[3]) * 0xffff / 15; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; if (status == SIGNAL_GOOD && - mmi->mmi_stats.signal == 0 && mmi->mmi_stats.snr == 0) { + mmi->tii_stats.signal == 0 && mmi->tii_stats.snr == 0) { /* some values that we're tuned */ - mmi->mmi_stats.signal = 50 * 0xffff / 100; - mmi->mmi_stats.snr = 12 * 0xffff / 15; + mmi->tii_stats.signal = 50 * 0xffff / 100; + mmi->tii_stats.snr = 12 * 0xffff / 15; } goto ok; } else if (strncmp(s, "ver=1.0;", 8) == 0) { @@ -747,14 +747,14 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name, return; if (atoi(argv[0]) != lfe->sf_number) return; - mmi->mmi_stats.signal = + mmi->tii_stats.signal = atoi(argv[1]) * 0xffff / lfe->sf_device->sd_sig_scale; - mmi->mmi_stats.signal_scale = + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; if (atoi(argv[2]) > 0) status = SIGNAL_GOOD; - mmi->mmi_stats.snr = atoi(argv[3]) * 0xffff / 15; - mmi->mmi_stats.snr_scale = + mmi->tii_stats.snr = atoi(argv[3]) * 0xffff / 15; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; goto ok; } else if (strncmp(s, "ver=1.1;tuner=", 14) == 0) { @@ -763,14 +763,14 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name, return; if (atoi(argv[0]) != lfe->sf_number) return; - mmi->mmi_stats.signal = + mmi->tii_stats.signal = atoi(argv[1]) * 0xffff / lfe->sf_device->sd_sig_scale; - mmi->mmi_stats.signal_scale = + mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; if (atoi(argv[2]) > 0) status = SIGNAL_GOOD; - mmi->mmi_stats.snr = atoi(argv[3]) * 0xffff / 15; - mmi->mmi_stats.snr_scale = + mmi->tii_stats.snr = atoi(argv[3]) * 0xffff / 15; + mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; goto ok; } @@ -782,9 +782,9 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name, return; ok: - if (mmi->mmi_stats.snr < 2 && status == SIGNAL_GOOD) + if (mmi->tii_stats.snr < 2 && status == SIGNAL_GOOD) status = SIGNAL_BAD; - else if (mmi->mmi_stats.snr < 4 && status == SIGNAL_GOOD) + else if (mmi->tii_stats.snr < 4 && status == SIGNAL_GOOD) status = SIGNAL_FAINT; lfe->sf_status = status; } @@ -1503,7 +1503,7 @@ new_tune: } pthread_mutex_lock(&lfe->sf_dvr_lock); if (lfe->sf_req == lfe->sf_req_thread) { - mmi->mmi_stats.unc += unc; + mmi->tii_stats.unc += unc; mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi, &sb, NULL, NULL); } else diff --git a/src/input/mpegts/tsfile/tsfile_mux.c b/src/input/mpegts/tsfile/tsfile_mux.c index b5333fe4..a3fedbbe 100644 --- a/src/input/mpegts/tsfile/tsfile_mux.c +++ b/src/input/mpegts/tsfile/tsfile_mux.c @@ -23,12 +23,12 @@ extern const idclass_t mpegts_mux_class; extern const idclass_t mpegts_mux_instance_class; static void -tsfile_mux_instance_delete( mpegts_mux_instance_t *_mmi ) +tsfile_mux_instance_delete( tvh_input_instance_t *tii ) { - tsfile_mux_instance_t *mmi = (tsfile_mux_instance_t *)_mmi; + tsfile_mux_instance_t *mmi = (tsfile_mux_instance_t *)tii; free(mmi->mmi_tsfile_path); - mpegts_mux_instance_delete(_mmi); + mpegts_mux_instance_delete(tii); } tsfile_mux_instance_t * @@ -41,7 +41,7 @@ tsfile_mux_instance_create #undef tsfile_mux_instance_class mmi->mmi_tsfile_path = strdup(path); mmi->mmi_tsfile_pcr_pid = MPEGTS_PID_NONE; - mmi->mmi_delete = tsfile_mux_instance_delete; + mmi->tii_delete = tsfile_mux_instance_delete; tvhtrace("tsfile", "mmi created %p path %s", mmi, mmi->mmi_tsfile_path); return mmi; } diff --git a/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c b/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c index b8bd705a..5e277cb1 100644 --- a/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c +++ b/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c @@ -300,19 +300,19 @@ tvhdhomerun_frontend_monitor_cb( void *aux ) if(tuner_status.signal_present) { /* TODO: totaly stupid conversion from 0-100 scale to 0-655.35 */ - mmi->mmi_stats.snr = tuner_status.signal_to_noise_quality * 655.35; - mmi->mmi_stats.signal = tuner_status.signal_strength * 655.35; + mmi->tii_stats.snr = tuner_status.signal_to_noise_quality * 655.35; + mmi->tii_stats.signal = tuner_status.signal_strength * 655.35; } else { - mmi->mmi_stats.snr = 0; + mmi->tii_stats.snr = 0; } sigstat.status_text = signal2str(hfe->hf_status); - sigstat.snr = mmi->mmi_stats.snr; - sigstat.snr_scale = mmi->mmi_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; - sigstat.signal = mmi->mmi_stats.signal; - sigstat.signal_scale = mmi->mmi_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; - sigstat.ber = mmi->mmi_stats.ber; - sigstat.unc = mmi->mmi_stats.unc; + sigstat.snr = mmi->tii_stats.snr; + sigstat.snr_scale = mmi->tii_stats.snr_scale = SIGNAL_STATUS_SCALE_RELATIVE; + sigstat.signal = mmi->tii_stats.signal; + sigstat.signal_scale = mmi->tii_stats.signal_scale = SIGNAL_STATUS_SCALE_RELATIVE; + sigstat.ber = mmi->tii_stats.ber; + sigstat.unc = mmi->tii_stats.unc; sm.sm_type = SMT_SIGNAL_STATUS; sm.sm_data = &sigstat; diff --git a/src/webui/static/app/status.js b/src/webui/static/app/status.js index 819032f8..356cb337 100644 --- a/src/webui/static/app/status.js +++ b/src/webui/static/app/status.js @@ -231,6 +231,33 @@ tvheadend.status_streams = function(panel, index) if (grid) return; + var actions = new Ext.ux.grid.RowActions({ + header: '', + width: 10, + actions: [ + { + iconCls: 'undo', + qtip: 'Clear statistics', + cb: function(grid, rec, act, row) { + var uuid = grid.getStore().getAt(row).data.uuid; + Ext.MessageBox.confirm('Clear statistics', + 'Clear statistics for selected input?', + function(button) { + if (button === 'no') + return; + Ext.Ajax.request({ + url: 'api/status/inputclrstats', + params: { uuid: uuid } + }); + } + ); + } + }, + ], + destroy: function() { + } + }); + store = new Ext.data.JsonStore({ root: 'entries', totalProperty: 'totalCount', @@ -288,6 +315,7 @@ tvheadend.status_streams = function(panel, index) } var cm = new Ext.grid.ColumnModel([ + actions, { width: 120, header: "Input", @@ -402,7 +430,8 @@ tvheadend.status_streams = function(panel, index) flex: 1, viewConfig: { forceFit: true - } + }, + plugins: [actions] }); dpanel.add(grid);