Some checks failed
dev release / build (push) Failing after 12s
Builds out the full v1 scope: a vendored+patched openscreen subset for low-latency Cast Streaming (Mirroring receiver 0F5096E8) alongside the existing Cast V2/HLS and new DLNA/AVTransport casting paths, breadcastd's Idle/Casting state machine with a private IPC socket, the breadcast GTK4 popup as a thin IPC client, and bread.cast.*/bread.command.cast.* breadd integration (device discovery, start/stop, mirroring lifecycle events). Also adds bakery/systemd/Forgejo CI packaging. Validated end-to-end against a real Chromecast/Google TV: negotiated Cast Streaming session, live pipeline playback, and daemon+GUI click-to-cast/ stop through the actual popup.
208 lines
7.6 KiB
C++
208 lines
7.6 KiB
C++
// 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"
|
|
#include "util/raw_ptr.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.
|
|
const raw_ptr<SenderStatsClient> 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_
|