blob: 036cd20d28f4af37b613dcbab53bf45df1ab6e52 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CAST_STREAMING_IMPL_STATISTICS_ANALYZER_H_
#define CAST_STREAMING_IMPL_STATISTICS_ANALYZER_H_
#include <map>
#include <memory>
#include <optional>
#include <utility>
#include <vector>
#include "cast/streaming/impl/clock_offset_estimator.h"
#include "cast/streaming/impl/statistics_collector.h"
#include "cast/streaming/public/statistics.h"
#include "platform/api/time.h"
#include "util/alarm.h"
namespace openscreen::cast {
class StatisticsAnalyzer {
public:
StatisticsAnalyzer(SenderStatsClient* stats_client,
ClockNowFunctionPtr now,
TaskRunner& task_runner,
std::unique_ptr<ClockOffsetEstimator> offset_estimator);
~StatisticsAnalyzer();
void ScheduleAnalysis();
// Get the statistics collector managed by this analyzer.
StatisticsCollector* statistics_collector() {
return statistics_collector_.get();
}
private:
struct FrameStatsAggregate {
int event_counter;
uint32_t sum_size;
Clock::duration sum_delay;
};
struct PacketStatsAggregate {
int event_counter;
uint32_t sum_size;
};
struct LatencyStatsAggregate {
int data_point_counter;
Clock::duration sum_latency;
};
struct FrameInfo {
Clock::time_point capture_begin_time = Clock::time_point::min();
Clock::time_point capture_end_time = Clock::time_point::min();
Clock::time_point encode_end_time = Clock::time_point::min();
};
struct PacketInfo {
Clock::time_point timestamp;
StatisticsEvent::Type type;
};
struct SessionStats {
Clock::time_point first_event_time = Clock::time_point::max();
Clock::time_point last_event_time = Clock::time_point::min();
Clock::time_point last_response_received_time = Clock::time_point::min();
int late_frame_counter = 0;
};
// Named std::pair equivalent for audio + video classes.
template <typename T>
struct AVPair {
T audio;
T video;
const T& Get(StatisticsEvent::MediaType media_type) const {
if (media_type == StatisticsEvent::MediaType::kAudio) {
return audio;
}
OSP_CHECK(media_type == StatisticsEvent::MediaType::kVideo);
return video;
}
T& Get(StatisticsEvent::MediaType media_type) {
return const_cast<T&>(const_cast<const AVPair*>(this)->Get(media_type));
}
};
using FrameStatsMap = std::map<StatisticsEvent::Type, FrameStatsAggregate>;
using PacketStatsMap = std::map<StatisticsEvent::Type, PacketStatsAggregate>;
using LatencyStatsMap = std::map<StatisticType, LatencyStatsAggregate>;
using FrameInfoMap = std::map<RtpTimeTicks, FrameInfo>;
using PacketKey = std::pair<RtpTimeTicks, uint16_t>;
using PacketInfoMap = std::map<PacketKey, PacketInfo>;
// Initialize the stats histograms with the preferred min, max, and width.
void InitHistograms();
// Takes the Frame and Packet events from the `collector_`, and processes them
// into a form expected by `stats_client_`. Then sends the stats, and
// schedules a future analysis.
void AnalyzeStatistics();
// Constructs a stats list, and sends it to `stats_client_`;
void SendStatistics();
// Handles incoming stat events, and adds their infos to all of the proper
// stats maps / aggregates.
void ProcessFrameEvents(const std::vector<FrameEvent>& frame_events);
void ProcessPacketEvents(const std::vector<PacketEvent>& packet_events);
void RecordFrameLatencies(const FrameEvent& frame_event);
void RecordPacketLatencies(const PacketEvent& packet_event);
void RecordEventTimes(const StatisticsEvent& event);
void ErasePacketInfo(const PacketEvent& packet_event);
void AddToLatencyAggregrate(StatisticType latency_stat,
Clock::duration latency_delta,
StatisticsEvent::MediaType media_type);
void AddToHistogram(HistogramType histogram,
StatisticsEvent::MediaType media_type,
int64_t sample);
// Creates a stats list, and populates the entries based on stored stats info
// / aggregates for each stat field.
SenderStats::StatisticsList ConstructStatisticsList(
Clock::time_point end_time,
StatisticsEvent::MediaType media_type);
void PopulatePacketCountStat(StatisticsEvent::Type event,
StatisticType stat,
StatisticsEvent::MediaType media_type,
SenderStats::StatisticsList& stats_list);
void PopulateFrameCountStat(StatisticsEvent::Type event,
StatisticType stat,
StatisticsEvent::MediaType media_type,
SenderStats::StatisticsList& stats_list);
void PopulateFpsStat(StatisticsEvent::Type event,
StatisticType stat,
StatisticsEvent::MediaType media_type,
Clock::time_point end_time,
SenderStats::StatisticsList& stats_list);
void PopulateAvgLatencyStat(StatisticType stat,
StatisticsEvent::MediaType media_type,
SenderStats::StatisticsList& stats_list);
void PopulateFrameBitrateStat(StatisticsEvent::Type event,
StatisticType stat,
StatisticsEvent::MediaType media_type,
Clock::time_point end_time,
SenderStats::StatisticsList& stats_list);
void PopulatePacketBitrateStat(StatisticsEvent::Type event,
StatisticType stat,
StatisticsEvent::MediaType media_type,
Clock::time_point end_time,
SenderStats::StatisticsList& stats_list);
void PopulateSessionStats(StatisticsEvent::MediaType media_type,
Clock::time_point end_time,
SenderStats::StatisticsList& stats_list);
// Calculates the offset between the sender and receiver clocks and returns
// the sender-side version of this receiver timestamp, if possible.
std::optional<Clock::time_point> ToSenderTimestamp(
Clock::time_point receiver_timestamp,
StatisticsEvent::MediaType media_type) const;
// The statistics client to which we report analyzed statistics.
SenderStatsClient* const stats_client_;
// The statistics collector from which we take the un-analyzed stats packets.
std::unique_ptr<StatisticsCollector> statistics_collector_;
// Keeps track of the best-guess clock offset between the sender and receiver.
std::unique_ptr<ClockOffsetEstimator> offset_estimator_;
// Keep track of time and events for this analyzer.
ClockNowFunctionPtr now_;
Alarm alarm_;
Clock::time_point start_time_;
// Maps of frame / packet infos used for stats that rely on seeing multiple
// events. For example, network latency is the calculated time difference
// between went a packet is sent, and when it is received.
AVPair<FrameInfoMap> recent_frame_infos_;
AVPair<PacketInfoMap> recent_packet_infos_;
// Aggregate statistics.
AVPair<FrameStatsMap> frame_stats_;
AVPair<PacketStatsMap> packet_stats_;
AVPair<LatencyStatsMap> latency_stats_;
// Stats that relate to the entirety of the session. For example, total late
// frames, or time of last event.
AVPair<SessionStats> session_stats_;
// Histograms.
AVPair<SenderStats::HistogramsList> histograms_;
};
} // namespace openscreen::cast
#endif // CAST_STREAMING_IMPL_STATISTICS_ANALYZER_H_