|  | /* | 
|  | *  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_ |