]> git.sesse.net Git - nageru/commitdiff
Add support for bus audio level metrics, which includes support for removing metrics.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 13 Jun 2017 21:53:19 +0000 (23:53 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 13 Jun 2017 21:53:19 +0000 (23:53 +0200)
audio_mixer.cpp
audio_mixer.h
metrics.cpp
metrics.h

index 7da5b0bea3d84db6853ce5616b795382a5db12b9..468edd531859b75793750564bc6a29f433a1675b 100644 (file)
@@ -849,18 +849,22 @@ void AudioMixer::send_audio_level_callback()
        {
                lock_guard<mutex> lock(compressor_mutex);
                for (unsigned bus_index = 0; bus_index < bus_levels.size(); ++bus_index) {
-                       bus_levels[bus_index].current_level_dbfs[0] = to_db(peak_history[bus_index][0].current_level);
-                       bus_levels[bus_index].current_level_dbfs[1] = to_db(peak_history[bus_index][1].current_level);
-                       bus_levels[bus_index].peak_level_dbfs[0] = to_db(peak_history[bus_index][0].current_peak);
-                       bus_levels[bus_index].peak_level_dbfs[1] = to_db(peak_history[bus_index][1].current_peak);
-                       bus_levels[bus_index].historic_peak_dbfs = to_db(
+                       BusLevel &levels = bus_levels[bus_index];
+                       BusMetrics &metrics = bus_metrics[bus_index];
+
+                       levels.current_level_dbfs[0] = metrics.current_level_dbfs[0] = to_db(peak_history[bus_index][0].current_level);
+                       levels.current_level_dbfs[1] = metrics.current_level_dbfs[1] = to_db(peak_history[bus_index][1].current_level);
+                       levels.peak_level_dbfs[0] = metrics.peak_level_dbfs[0] = to_db(peak_history[bus_index][0].current_peak);
+                       levels.peak_level_dbfs[1] = metrics.peak_level_dbfs[1] = to_db(peak_history[bus_index][1].current_peak);
+                       levels.historic_peak_dbfs = metrics.historic_peak_dbfs = to_db(
                                max(peak_history[bus_index][0].historic_peak,
                                    peak_history[bus_index][1].historic_peak));
-                       bus_levels[bus_index].gain_staging_db = gain_staging_db[bus_index];
+                       levels.gain_staging_db = metrics.gain_staging_db = gain_staging_db[bus_index];
                        if (compressor_enabled[bus_index]) {
-                               bus_levels[bus_index].compressor_attenuation_db = -to_db(compressor[bus_index]->get_attenuation());
+                               levels.compressor_attenuation_db = metrics.compressor_attenuation_db = -to_db(compressor[bus_index]->get_attenuation());
                        } else {
-                               bus_levels[bus_index].compressor_attenuation_db = 0.0;
+                               levels.compressor_attenuation_db = 0.0;
+                               metrics.compressor_attenuation_db = 0.0 / 0.0;
                        }
                }
        }
@@ -983,6 +987,62 @@ void AudioMixer::set_input_mapping_lock_held(const InputMapping &new_input_mappi
                }
        }
 
+       // Kill all the old metrics, and set up new ones.
+       for (unsigned bus_index = 0; bus_index < input_mapping.buses.size(); ++bus_index) {
+               BusMetrics &metrics = bus_metrics[bus_index];
+
+               vector<pair<string, string>> labels_left = metrics.labels;
+               labels_left.emplace_back("channel", "left");
+               vector<pair<string, string>> labels_right = metrics.labels;
+               labels_right.emplace_back("channel", "right");
+
+               global_metrics.remove("bus_current_level_dbfs", labels_left);
+               global_metrics.remove("bus_current_level_dbfs", labels_right);
+               global_metrics.remove("bus_peak_level_dbfs", labels_left);
+               global_metrics.remove("bus_peak_level_dbfs", labels_right);
+               global_metrics.remove("bus_historic_peak_dbfs", metrics.labels);
+               global_metrics.remove("bus_gain_staging_db", metrics.labels);
+               global_metrics.remove("bus_compressor_attenuation_db", metrics.labels);
+       }
+       bus_metrics.reset(new BusMetrics[new_input_mapping.buses.size()]);
+       for (unsigned bus_index = 0; bus_index < new_input_mapping.buses.size(); ++bus_index) {
+               const InputMapping::Bus &bus = new_input_mapping.buses[bus_index];
+               BusMetrics &metrics = bus_metrics[bus_index];
+
+               char bus_index_str[16], source_index_str[16], source_channels_str[64];
+               snprintf(bus_index_str, sizeof(bus_index_str), "%u", bus_index);
+               snprintf(source_index_str, sizeof(source_index_str), "%u", bus.device.index);
+               snprintf(source_channels_str, sizeof(source_channels_str), "%d:%d", bus.source_channel[0], bus.source_channel[1]);
+
+               vector<pair<string, string>> labels;
+               metrics.labels.emplace_back("index", bus_index_str);
+               metrics.labels.emplace_back("name", bus.name);
+               if (bus.device.type == InputSourceType::SILENCE) {
+                       metrics.labels.emplace_back("source_type", "silence");
+               } else if (bus.device.type == InputSourceType::CAPTURE_CARD) {
+                       metrics.labels.emplace_back("source_type", "capture_card");
+               } else if (bus.device.type == InputSourceType::ALSA_INPUT) {
+                       metrics.labels.emplace_back("source_type", "alsa_input");
+               } else {
+                       assert(false);
+               }
+               metrics.labels.emplace_back("source_index", source_index_str);
+               metrics.labels.emplace_back("source_channels", source_channels_str);
+
+               vector<pair<string, string>> labels_left = metrics.labels;
+               labels_left.emplace_back("channel", "left");
+               vector<pair<string, string>> labels_right = metrics.labels;
+               labels_right.emplace_back("channel", "right");
+
+               global_metrics.add("bus_current_level_dbfs", labels_left, &metrics.current_level_dbfs[0], Metrics::TYPE_GAUGE);
+               global_metrics.add("bus_current_level_dbfs", labels_right, &metrics.current_level_dbfs[1], Metrics::TYPE_GAUGE);
+               global_metrics.add("bus_peak_level_dbfs", labels_left, &metrics.peak_level_dbfs[0], Metrics::TYPE_GAUGE);
+               global_metrics.add("bus_peak_level_dbfs", labels_right, &metrics.peak_level_dbfs[1], Metrics::TYPE_GAUGE);
+               global_metrics.add("bus_historic_peak_dbfs", metrics.labels, &metrics.historic_peak_dbfs, Metrics::TYPE_GAUGE);
+               global_metrics.add("bus_gain_staging_db", metrics.labels, &metrics.gain_staging_db, Metrics::TYPE_GAUGE);
+               global_metrics.add("bus_compressor_attenuation_db", metrics.labels, &metrics.compressor_attenuation_db, Metrics::TYPE_GAUGE);
+       }
+
        // Reset resamplers for all cards that don't have the exact same state as before.
        for (unsigned card_index = 0; card_index < MAX_VIDEO_CARDS; ++card_index) {
                const DeviceSpec device_spec{InputSourceType::CAPTURE_CARD, card_index};
index afebea471b7809cd7e51e11b583a413193159c2a..17f95280e28eba8a9a85756cb24c626a6f3f858c 100644 (file)
@@ -394,6 +394,19 @@ private:
        std::atomic<double> metric_audio_peak_dbfs{0.0 / 0.0};
        std::atomic<double> metric_audio_final_makeup_gain_db{0.0};
        std::atomic<double> metric_audio_correlation{0.0};
+
+       // These are all gauges corresponding to the elements of BusLevel.
+       // In a sense, they'd probably do better as histograms, but that's an
+       // awful lot of time series when you have many buses.
+       struct BusMetrics {
+               std::vector<std::pair<std::string, std::string>> labels;
+               std::atomic<double> current_level_dbfs[2]{{0.0/0.0},{0.0/0.0}};
+               std::atomic<double> peak_level_dbfs[2]{{0.0/0.0},{0.0/0.0}};
+               std::atomic<double> historic_peak_dbfs{0.0/0.0};
+               std::atomic<double> gain_staging_db{0.0/0.0};
+               std::atomic<double> compressor_attenuation_db{0.0/0.0};
+       };
+       std::unique_ptr<BusMetrics[]> bus_metrics;  // One for each bus in <input_mapping>.
 };
 
 extern AudioMixer *global_audio_mixer;
index 3fadb72907d9afdc5e2574269c57badd539eba6f..f44ced2c15a66715977b352736122442c9ba4541 100644 (file)
@@ -75,6 +75,22 @@ void Metrics::add(const string &name, const vector<pair<string, string>> &labels
        types[name] = TYPE_HISTOGRAM;
 }
 
+void Metrics::remove(const string &name, const vector<pair<string, string>> &labels)
+{
+       lock_guard<mutex> lock(mu);
+
+       auto it = metrics.find(MetricKey(name, labels));
+       assert(it != metrics.end());
+
+       // If this is the last metric with this name, remove the type as well.
+       if (!((it != metrics.begin() && prev(it)->first.name == name) ||
+             (it != metrics.end() && next(it)->first.name == name))) {
+               types.erase(name);
+       }
+
+       metrics.erase(it);
+}
+
 string Metrics::serialize() const
 {
        stringstream ss;
index 0371668bd2a1e25c1adaed613071ac8e3c6c0551..603abb09630623c163d155952346d0fdb6a6865f 100644 (file)
--- a/metrics.h
+++ b/metrics.h
@@ -48,6 +48,13 @@ public:
        void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, std::atomic<double> *location, Type type = TYPE_COUNTER);
        void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, Histogram *location);
 
+       void remove(const std::string &name)
+       {
+               remove(name, {});
+       }
+
+       void remove(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels);
+
        std::string serialize() const;
 
 private: