Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration
Some checks failed
dev release / build (push) Failing after 12s
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.
This commit is contained in:
parent
887c29002f
commit
8c745d18e0
283 changed files with 36788 additions and 0 deletions
208
breadcast-caststream-sys/vendor/openscreen/cast/streaming/impl/statistics_analyzer.h
vendored
Normal file
208
breadcast-caststream-sys/vendor/openscreen/cast/streaming/impl/statistics_analyzer.h
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
// 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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue