blob: 348f7534932f92ec8705ca983dc1d72cf3a8fc6d [file] [log] [blame]
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_AUDIO_PROCESSING_AGC_CLIPPING_PREDICTOR_EVALUATOR_H_
#define MODULES_AUDIO_PROCESSING_AGC_CLIPPING_PREDICTOR_EVALUATOR_H_
#include <vector>
#include "absl/types/optional.h"
namespace webrtc {
// Clipping prediction counters.
struct ClippingPredictionCounters {
int true_positives; // TP.
int true_negatives; // TN.
int false_positives; // FP.
int false_negatives; // FN.
};
// Counts true/false positives/negatives while observing sequences of flag pairs
// that indicate whether clipping has been detected and/or if clipping is
// predicted. When a true positive is found measures the time interval between
// prediction and detection events.
// After a prediction is observed and for a period equal to
// `history_size` calls to `Observe()`, one or more detections are expected. If
// the expectation is met, a true positive is added and the time interval
// between the earliest prediction and the detection is recorded; otherwise,
// when the deadline is reached, a false positive is added. Note that one
// detection matches all the expected detections that have not expired - i.e.,
// one detection counts as multiple true positives.
// If a detection is observed, but no prediction has been observed over the past
// `history_size` calls to `Observe()`, then a false negative is added;
// otherwise, a true negative is added.
class ClippingPredictorEvaluator {
public:
// Ctor. `history_size` indicates how long to wait for a call to `Observe()`
// having `clipping_detected` set to true from the time clipping is predicted.
explicit ClippingPredictorEvaluator(int history_size);
ClippingPredictorEvaluator(const ClippingPredictorEvaluator&) = delete;
ClippingPredictorEvaluator& operator=(const ClippingPredictorEvaluator&) =
delete;
~ClippingPredictorEvaluator();
// Observes whether clipping has been detected and/or if clipping is
// predicted. When predicted one or more detections are expected in the next
// `history_size_` calls of `Observe()`. When true positives are found returns
// the prediction interval between the earliest prediction and the detection.
absl::optional<int> Observe(bool clipping_detected, bool clipping_predicted);
// Removes any expectation recently set after a call to `Observe()` having
// `clipping_predicted` set to true. Counters won't be reset.
void RemoveExpectations();
// Resets counters and removes any expectation (see `RemoveExpectations()`).
void Reset();
ClippingPredictionCounters counters() const { return counters_; }
private:
const int history_size_;
// State of a detection expected to be observed after a prediction.
struct ExpectedDetection {
// Time to live (TTL); remaining number of `Observe()` calls to match a call
// having `clipping_detected` set to true.
int ttl;
// True if an `Observe()` call having `clipping_detected` set to true has
// been observed.
bool detected;
};
// Ring buffer of expected detections.
const int ring_buffer_capacity_;
std::vector<ExpectedDetection> ring_buffer_;
int ring_buffer_tail_;
int ring_buffer_size_;
// Pushes `expected_detection` into `expected_matches_ring_buffer_`.
void Push(ExpectedDetection expected_detection);
// Decreased the TTLs in `expected_matches_ring_buffer_` and removes expired
// items.
void DecreaseTimesToLive();
// Returns the prediction interval for the earliest unexpired expected
// detection if any.
absl::optional<int> FindEarliestPredictionInterval() const;
// Marks all the items in `expected_matches_ring_buffer_` as `detected` and
// returns the number of updated items.
int MarkExpectedDetectionAsDetected();
// Returns true if `expected_matches_ring_buffer_` has an item having `ttl`
// equal to 0 (expired) and `detected` equal to false (unmatched).
bool HasExpiredUnmatchedExpectedDetection() const;
// Counters.
ClippingPredictionCounters counters_;
};
// Clipping prediction metrics derived from the clipping prediction counters.
struct ClippingPredictionMetrics {
// Precision (P) is defined as TP / (TP + FP).
float precision;
// Recall (R) is defined as TP / (TP + FN).
float recall;
// The F1 score is defined as 2 * P * R / (P + R).
float f1_score;
};
// Derives clipping prediction metrics from the true/false positives/negatives
// `counters`. Returns an unspecified value if one or more metrics are not
// defined.
absl::optional<ClippingPredictionMetrics> ComputeClippingPredictionMetrics(
const ClippingPredictionCounters& counters);
} // namespace webrtc
#endif // MODULES_AUDIO_PROCESSING_AGC_CLIPPING_PREDICTOR_EVALUATOR_H_