blob: c5a7ff0d185d1d8cb67164c70d5e0b5f259470b0 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_CAST_LOGGING_STATS_EVENT_SUBSCRIBER_H_
#define MEDIA_CAST_LOGGING_STATS_EVENT_SUBSCRIBER_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <utility>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "base/values.h"
#include "media/cast/logging/logging_defines.h"
#include "media/cast/logging/raw_event_subscriber.h"
#include "media/cast/logging/receiver_time_offset_estimator.h"
namespace media {
namespace cast {
class StatsEventSubscriberTest;
// A RawEventSubscriber implementation that subscribes to events,
// and aggregates them into stats.
class StatsEventSubscriber final : public RawEventSubscriber {
public:
StatsEventSubscriber(EventMediaType event_media_type,
const base::TickClock* clock,
ReceiverTimeOffsetEstimator* offset_estimator);
StatsEventSubscriber(const StatsEventSubscriber&) = delete;
StatsEventSubscriber& operator=(const StatsEventSubscriber&) = delete;
~StatsEventSubscriber() final;
// RawReventSubscriber implementations.
void OnReceiveFrameEvent(const FrameEvent& frame_event) final;
void OnReceivePacketEvent(const PacketEvent& packet_event) final;
// Returns stats as a DictionaryValue. The dictionary contains one entry -
// "audio" or "video" pointing to an inner dictionary.
// The inner dictionary consists of string - double entries, where the string
// describes the name of the stat, and the double describes
// the value of the stat. See CastStat and StatsMap below.
base::Value::Dict GetStats() const;
// Resets stats in this object.
void Reset();
static constexpr char kAudioStatsDictKey[] = "audio";
static constexpr char kVideoStatsDictKey[] = "video";
private:
// TODO(b/268543775): Replace friend class declarations with public getters
// for tests.
friend class StatsEventSubscriberTest;
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, EmptyStats);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, CaptureEncode);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Encode);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Decode);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, PlayoutDelay);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, E2ELatency);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Packets);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Histograms);
static const size_t kMaxFrameInfoMapSize = 100;
// Generic statistics given the raw data. More specific data (e.g. frame rate
// and bit rate) can be computed given the basic metrics.
// Some of the metrics will only be set when applicable, e.g. delay and size.
struct FrameLogStats {
FrameLogStats();
~FrameLogStats();
int event_counter;
size_t sum_size;
base::TimeDelta sum_delay;
};
struct PacketLogStats {
PacketLogStats();
~PacketLogStats();
int event_counter;
size_t sum_size;
};
class SimpleHistogram {
public:
// This will create N+2 buckets where N = (max - min) / width:
// Underflow bucket: < min
// Bucket 0: [min, min + width - 1]
// Bucket 1: [min + width, min + 2 * width - 1]
// ...
// Bucket N-1: [max - width, max - 1]
// Overflow bucket: >= max
// |min| must be less than |max|.
// |width| must divide |max - min| evenly.
SimpleHistogram(int64_t min, int64_t max, int64_t width);
~SimpleHistogram();
void Add(int64_t sample);
void Reset();
base::Value::List GetHistogram() const;
private:
int64_t min_;
int64_t max_;
int64_t width_;
std::vector<int> buckets_;
};
enum CastStat {
// Capture frame rate.
CAPTURE_FPS,
// Encode frame rate.
ENCODE_FPS,
// Decode frame rate.
DECODE_FPS,
// Average capture latency in milliseconds.
AVG_CAPTURE_LATENCY_MS,
// Average encode duration in milliseconds.
AVG_ENCODE_TIME_MS,
// Duration from when a frame is encoded to when the packet is first
// sent.
AVG_QUEUEING_LATENCY_MS,
// Duration from when a packet is transmitted to when it is received.
// This measures latency from sender to receiver.
AVG_NETWORK_LATENCY_MS,
// Duration from when a frame is encoded to when the packet is first
// received.
AVG_PACKET_LATENCY_MS,
// Average latency between frame encoded and the moment when the frame
// is fully received.
AVG_FRAME_LATENCY_MS,
// Duration from when a frame is captured to when it should be played out.
AVG_E2E_LATENCY_MS,
// Encode bitrate in kbps.
ENCODE_KBPS,
// Packet transmission bitrate in kbps.
TRANSMISSION_KBPS,
// Packet retransmission bitrate in kbps.
RETRANSMISSION_KBPS,
// Duration in milliseconds since last receiver response.
MS_SINCE_LAST_RECEIVER_RESPONSE,
// Number of frames captured.
NUM_FRAMES_CAPTURED,
// Number of frames dropped by encoder.
NUM_FRAMES_DROPPED_BY_ENCODER,
// Number of late frames.
NUM_FRAMES_LATE,
// Number of packets that were sent (not retransmitted).
NUM_PACKETS_SENT,
// Number of packets that were retransmitted.
NUM_PACKETS_RETRANSMITTED,
// Number of packets that were received by receiver.
NUM_PACKETS_RECEIVED,
// Number of packets that had their retransmission cancelled.
NUM_PACKETS_RTX_REJECTED,
// Unix time in milliseconds of first event since reset.
FIRST_EVENT_TIME_MS,
// Unix time in milliseconds of last event since reset.
LAST_EVENT_TIME_MS,
// Histograms
CAPTURE_LATENCY_MS_HISTO,
ENCODE_TIME_MS_HISTO,
QUEUEING_LATENCY_MS_HISTO,
NETWORK_LATENCY_MS_HISTO,
PACKET_LATENCY_MS_HISTO,
FRAME_LATENCY_MS_HISTO,
E2E_LATENCY_MS_HISTO,
LATE_FRAME_MS_HISTO
};
struct FrameInfo {
FrameInfo();
~FrameInfo();
base::TimeTicks capture_time;
base::TimeTicks capture_end_time;
base::TimeTicks encode_end_time;
bool encoded;
};
typedef std::map<CastStat, double> StatsMap;
typedef std::map<CastStat, std::unique_ptr<SimpleHistogram>> HistogramMap;
typedef std::map<RtpTimeTicks, FrameInfo> FrameInfoMap;
typedef std::map<std::pair<RtpTimeTicks, uint16_t>,
std::pair<base::TimeTicks, CastLoggingEvent>>
PacketEventTimeMap;
typedef std::map<CastLoggingEvent, FrameLogStats> FrameStatsMap;
typedef std::map<CastLoggingEvent, PacketLogStats> PacketStatsMap;
static const char* CastStatToString(CastStat stat);
void InitHistograms();
// Assigns |stats_map| with stats data. Used for testing.
void GetStatsInternal(StatsMap* stats_map) const;
// Return a histogram of the type specified.
SimpleHistogram* GetHistogramForTesting(CastStat stats) const;
void UpdateFirstLastEventTime(base::TimeTicks timestamp,
bool is_receiver_event);
bool GetReceiverOffset(base::TimeDelta* offset);
void MaybeInsertFrameInfo(RtpTimeTicks rtp_timestamp,
const FrameInfo& frame_info);
void RecordFrameCaptureTime(const FrameEvent& frame_event);
void RecordCaptureLatency(const FrameEvent& frame_event);
void RecordEncodeLatency(const FrameEvent& frame_event);
void RecordFrameTxLatency(const FrameEvent& frame_event);
void RecordE2ELatency(const FrameEvent& frame_event);
void RecordPacketSentTime(const PacketEvent& packet_event);
void ErasePacketSentTime(const PacketEvent& packet_event);
void RecordPacketRelatedLatencies(const PacketEvent& packet_event);
void UpdateLastResponseTime(base::TimeTicks receiver_time);
void PopulateFpsStat(base::TimeTicks now,
CastLoggingEvent event,
CastStat stat,
StatsMap* stats_map) const;
void PopulateFrameCountStat(CastLoggingEvent event,
CastStat stat,
StatsMap* stats_map) const;
void PopulatePacketCountStat(CastLoggingEvent event,
CastStat stat,
StatsMap* stats_map) const;
void PopulateFrameBitrateStat(base::TimeTicks now, StatsMap* stats_map) const;
void PopulatePacketBitrateStat(base::TimeTicks now,
CastLoggingEvent event,
CastStat stat,
StatsMap* stats_map) const;
const EventMediaType event_media_type_;
// Not owned by this class.
const raw_ptr<const base::TickClock> clock_;
// Not owned by this class.
const raw_ptr<ReceiverTimeOffsetEstimator> offset_estimator_;
FrameStatsMap frame_stats_;
PacketStatsMap packet_stats_;
base::TimeDelta total_capture_latency_;
int capture_latency_datapoints_;
base::TimeDelta total_encode_time_;
int encode_time_datapoints_;
base::TimeDelta total_queueing_latency_;
int queueing_latency_datapoints_;
base::TimeDelta total_network_latency_;
int network_latency_datapoints_;
base::TimeDelta total_packet_latency_;
int packet_latency_datapoints_;
base::TimeDelta total_frame_latency_;
int frame_latency_datapoints_;
base::TimeDelta total_e2e_latency_;
int e2e_latency_datapoints_;
base::TimeTicks last_response_received_time_;
int num_frames_dropped_by_encoder_;
int num_frames_late_;
// Fixed size map to record when recent frames were captured and other info.
FrameInfoMap recent_frame_infos_;
// Fixed size map to record when recent packets were sent.
PacketEventTimeMap packet_sent_times_;
// Sender time assigned on creation and |Reset()|.
base::TimeTicks start_time_;
base::TimeTicks first_event_time_;
base::TimeTicks last_event_time_;
HistogramMap histograms_;
base::ThreadChecker thread_checker_;
};
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_LOGGING_STATS_EVENT_SUBSCRIBER_H_