diff options
| author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-10-29 15:35:13 +0100 | 
|---|---|---|
| committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-10-29 15:35:13 +0100 | 
| commit | bf82967d4c04946ae6e0490ea28e160a856fc81b (patch) | |
| tree | e6eaffeed8741ea6203a0323826153179a3d91df | |
| parent | 234420f5c8a37acd94a41ddd1dc33979bc843e76 (diff) | |
| download | dabmux-bf82967d4c04946ae6e0490ea28e160a856fc81b.tar.gz dabmux-bf82967d4c04946ae6e0490ea28e160a856fc81b.tar.bz2 dabmux-bf82967d4c04946ae6e0490ea28e160a856fc81b.zip | |
Rework inputstat to use absolute timestamps internally
| -rw-r--r-- | src/ManagementServer.cpp | 145 | ||||
| -rw-r--r-- | src/ManagementServer.h | 28 | 
2 files changed, 93 insertions, 80 deletions
| diff --git a/src/ManagementServer.cpp b/src/ManagementServer.cpp index 5741e38..201fc7b 100644 --- a/src/ManagementServer.cpp +++ b/src/ManagementServer.cpp @@ -355,21 +355,10 @@ void ManagementServer::update_ptree(const boost::property_tree::ptree& pt)  /************************************************/ -InputStat::InputStat(const std::string& name) -    : m_name(name) +InputStat::InputStat(const std::string& name) : +    m_name(name), +    m_time_last_event(std::chrono::steady_clock::now())  { -    /* Statistics */ -    m_num_underruns = 0; -    m_num_overruns = 0; - -    /* State handling */ -    m_time_last_event = std::chrono::steady_clock::now(); -    m_glitch_counter = 0; -    m_silence_counter = 0; - -    m_buffer_fill_stats.clear(); -    m_peaks_left.clear(); -    m_peaks_right.clear();  }  InputStat::~InputStat() @@ -386,61 +375,65 @@ void InputStat::notifyBuffer(long bufsize)  {      unique_lock<mutex> lock(m_mutex); -    m_buffer_fill_stats.push_front(bufsize); -      using namespace std::chrono;      const auto time_now = steady_clock::now(); -    if (m_buffer_fill_stats.size() > 1) { -        auto insertion_interval = time_now - m_time_last_buffer_notify; -        auto total_length = insertion_interval * m_buffer_fill_stats.size(); +    m_buffer_fill_stats.push_front({time_now, bufsize}); -        if (total_length > BUFFER_STATS_KEEP_DURATION) { -            m_buffer_fill_stats.pop_back(); -        } -    } -    m_time_last_buffer_notify = time_now; +    // Keep only stats whose timestamp are more recent than +    // BUFFER_STATS_KEEP_DURATION ago +    m_buffer_fill_stats.erase(remove_if( +                m_buffer_fill_stats.begin(), m_buffer_fill_stats.end(), +                [&](const fill_stat_t& fs) { +                    return fs.timestamp + BUFFER_STATS_KEEP_DURATION < time_now; +                }), +                m_buffer_fill_stats.end());  }  void InputStat::notifyPeakLevels(int peak_left, int peak_right)  {      unique_lock<mutex> lock(m_mutex); -    m_peaks_left.push_front(peak_left); -    m_peaks_right.push_front(peak_right); -      using namespace std::chrono; -      const auto time_now = steady_clock::now(); -    if (m_peaks_left.size() < 2) { -        m_time_last_peak_notify = time_now; -    } -    else { -        const auto insertion_interval = time_now - m_time_last_peak_notify; -        const auto peaks_total_length = insertion_interval * m_peaks_left.size(); - -        if (peaks_total_length > PEAK_STATS_KEEP_DURATION) { -            m_peaks_left.pop_back(); -            m_peaks_right.pop_back(); -        } +    m_peak_stats.push_front({time_now, peak_left, peak_right}); -        m_time_last_peak_notify = time_now; +    // Keep only stats whose timestamp are more recent than +    // BUFFER_STATS_KEEP_DURATION ago +    m_peak_stats.erase(remove_if( +                m_peak_stats.begin(), m_peak_stats.end(), +                [&](const peak_stat_t& ps) { +                    return ps.timestamp + PEAK_STATS_KEEP_DURATION < time_now; +                }), +                m_peak_stats.end()); +    if (m_peak_stats.size() >= 2) {          // Calculate the peak over the short window -        m_short_window_length = PEAK_STATS_SHORT_WINDOW / insertion_interval; -        const size_t short_window = std::min( -                m_peaks_left.size(), m_short_window_length); -        const auto max_left = *max_element(m_peaks_left.begin(), -                m_peaks_left.begin() + short_window); -        const auto max_right = *max_element(m_peaks_right.begin(), -                m_peaks_right.begin() + short_window); - -        // State - -        // using the lower of the two channels allows us to detect if only one +        vector<peak_stat_t> short_peaks; +        copy_if(m_peak_stats.begin(), m_peak_stats.end(), +                back_inserter(short_peaks), +                [&](const peak_stat_t& ps) { +                    return ps.timestamp + PEAK_STATS_SHORT_WINDOW >= time_now; +                }); + +        const auto& short_left_peak_max = max_element( +                short_peaks.begin(), short_peaks.end(), +                [](const peak_stat_t& lhs, const peak_stat_t& rhs) { +                    return lhs.peak_left < rhs.peak_left; +                }); + +        const auto& short_right_peak_max = max_element( +                short_peaks.begin(), short_peaks.end(), +                [](const peak_stat_t& lhs, const peak_stat_t& rhs) { +                    return lhs.peak_right < rhs.peak_right; +                }); + +        // Using the lower of the two channels allows us to detect if only one          // channel is silent. -        const int lower_peak = max_left < max_right ? max_left : max_right; +        const int lower_peak = min( +                short_left_peak_max->peak_left, short_right_peak_max->peak_right); +        // State          const int16_t int16_max = std::numeric_limits<int16_t>::max();          int peak_dB = lower_peak ?              round(20*log10((double)lower_peak / int16_max)) : @@ -474,8 +467,7 @@ void InputStat::notifyUnderrun(void)      else {          // As we don't receive level notifications anymore, clear the          // audio level information -        m_peaks_left.clear(); -        m_peaks_right.clear(); +        m_peak_stats.clear();      }  } @@ -506,16 +498,28 @@ std::string InputStat::encodeValuesJSON()      int peak_left = 0;      int peak_right = 0; -    if (not m_peaks_left.empty() and not m_peaks_right.empty()) { -        peak_left = *max_element(m_peaks_left.begin(), m_peaks_left.end()); -        peak_right = *max_element(m_peaks_right.begin(), m_peaks_right.end()); - -        if (m_peaks_left.size() >= m_short_window_length and -            m_peaks_right.size() >= m_short_window_length) { -            peak_left_short = *max_element(m_peaks_left.begin(), -                    m_peaks_left.begin() + m_short_window_length); -            peak_right_short = *max_element(m_peaks_right.begin(), -                    m_peaks_right.begin() + m_short_window_length); +    if (not m_peak_stats.empty()) { +        peak_left = max_element(m_peak_stats.begin(), m_peak_stats.end(), +                [](const peak_stat_t& lhs, const peak_stat_t& rhs) { +                    return lhs.peak_left < rhs.peak_left; +                })->peak_left; +        peak_right = max_element(m_peak_stats.begin(), m_peak_stats.end(), +                [](const peak_stat_t& lhs, const peak_stat_t& rhs) { +                    return lhs.peak_right < rhs.peak_right; +                })->peak_right; + +        if (m_peak_stats.size() > m_short_window_length) { +            peak_left_short = max_element(m_peak_stats.begin(), +                    m_peak_stats.begin() + m_short_window_length, +                [](const peak_stat_t& lhs, const peak_stat_t& rhs) { +                    return lhs.peak_left < rhs.peak_left; +                })->peak_left; + +            peak_right_short = max_element(m_peak_stats.begin(), +                    m_peak_stats.begin() + m_short_window_length, +                [](const peak_stat_t& lhs, const peak_stat_t& rhs) { +                    return lhs.peak_right < rhs.peak_right; +                })->peak_right;          }          else {              peak_left_short = peak_left; @@ -526,10 +530,13 @@ std::string InputStat::encodeValuesJSON()      long min_fill_buffer = MIN_FILL_BUFFER_UNDEF;      long max_fill_buffer = 0;      if (not m_buffer_fill_stats.empty()) { -        auto buffer_min_max_fill = minmax_element(m_buffer_fill_stats.begin(), -                m_buffer_fill_stats.end()); -        min_fill_buffer = *buffer_min_max_fill.first; -        max_fill_buffer = *buffer_min_max_fill.second; +        const auto& buffer_min_max_fill = minmax_element( +                m_buffer_fill_stats.begin(), m_buffer_fill_stats.end(), +                [](const fill_stat_t& lhs, const fill_stat_t& rhs) { +                    return lhs.bufsize < rhs.bufsize; +                }); +        min_fill_buffer = buffer_min_max_fill.first->bufsize; +        max_fill_buffer = buffer_min_max_fill.second->bufsize;      }      /* convert to dB */ @@ -596,7 +603,7 @@ input_state_t InputStat::determineState()       */      if (std::all_of(                  m_buffer_fill_stats.begin(), m_buffer_fill_stats.end(), -                [](long fill) { return fill == 0; }) ) { +                [](const fill_stat_t& fs) { return fs.bufsize == 0; }) ) {          state = input_state_t::NoData;      }      /* Otherwise, the state depends on the glitch counter */ diff --git a/src/ManagementServer.h b/src/ManagementServer.h index 17b8bda..18af48c 100644 --- a/src/ManagementServer.h +++ b/src/ManagementServer.h @@ -107,28 +107,34 @@ class InputStat          std::string m_name;          /************ STATISTICS ***********/ -        // Calculate minimum and maximum buffer fill from -        // a FIFO of values from the last few seconds -        std::deque<long> m_buffer_fill_stats; -        std::chrono::time_point<std::chrono::steady_clock> m_time_last_buffer_notify; +        // Keep track of buffer fill with timestamps, so that we +        // can calculate the correct state from it. +        struct fill_stat_t { +            std::chrono::time_point<std::chrono::steady_clock> timestamp; +            long bufsize; +        }; +        std::deque<fill_stat_t> m_buffer_fill_stats;          // counter of number of overruns and underruns since startup -        uint32_t m_num_underruns; -        uint32_t m_num_overruns; +        uint32_t m_num_underruns = 0; +        uint32_t m_num_overruns = 0;          // Peak audio levels (linear 16-bit PCM) for the two channels.          // Keep a FIFO of values from the last minutes, apply          // a short window to also see short-term fluctuations. -        std::deque<int> m_peaks_left; -        std::deque<int> m_peaks_right; -        std::chrono::time_point<std::chrono::steady_clock> m_time_last_peak_notify; +        struct peak_stat_t { +            std::chrono::time_point<std::chrono::steady_clock> timestamp; +            int peak_left; +            int peak_right; +        }; +        std::deque<peak_stat_t> m_peak_stats;          size_t m_short_window_length = 0;          /************* STATE ***************/          /* Variables used for determining the input state */ -        int m_glitch_counter; // saturating counter -        int m_silence_counter; // saturating counter +        int m_glitch_counter = 0; // saturating counter +        int m_silence_counter = 0; // saturating counter          std::chrono::time_point<std::chrono::steady_clock> m_time_last_event;          // The mutex that has to be held during all notify and readout | 
