// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/tick_clock.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 base {
class DictionaryValue;
}
namespace media {
namespace cast {
class StatsEventSubscriberTest;
// A RawEventSubscriber implementation that subscribes to events,
// and aggregates them into stats.
class StatsEventSubscriber : public RawEventSubscriber {
public:
StatsEventSubscriber(EventMediaType event_media_type,
base::TickClock* clock,
ReceiverTimeOffsetEstimator* offset_estimator);
virtual ~StatsEventSubscriber();
// RawReventSubscriber implementations.
virtual void OnReceiveFrameEvent(const FrameEvent& frame_event) OVERRIDE;
virtual void OnReceivePacketEvent(const PacketEvent& packet_event) OVERRIDE;
// 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.
scoped_ptr<base::DictionaryValue> GetStats() const;
// Resets stats in this object.
void Reset();
private:
friend class StatsEventSubscriberTest;
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, EmptyStats);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Capture);
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);
// 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;
};
enum CastStat {
// Capture frame rate.
CAPTURE_FPS,
// Encode frame rate.
ENCODE_FPS,
// Decode frame rate.
DECODE_FPS,
// Average encode duration in milliseconds.
// TODO(imcheng): This stat is not populated yet because we do not have
// the time when encode started. Record it in FRAME_ENCODED event.
AVG_ENCODE_TIME_MS,
// Average playout delay in milliseconds, with target delay already
// accounted for. Ideally, every frame should have a playout delay of 0.
AVG_PLAYOUT_DELAY_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 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,
// Fraction of packet loss.
PACKET_LOSS_FRACTION,
// Duration in milliseconds since last receiver response.
MS_SINCE_LAST_RECEIVER_RESPONSE
};
typedef std::map<CastStat, double> StatsMap;
typedef std::map<RtpTimestamp, base::TimeTicks> FrameEventTimeMap;
typedef std::map<
std::pair<RtpTimestamp, uint16>,
std::pair<base::TimeTicks, CastLoggingEvent> >
PacketEventTimeMap;
typedef std::map<CastLoggingEvent, FrameLogStats> FrameStatsMap;
typedef std::map<CastLoggingEvent, PacketLogStats> PacketStatsMap;
static const char* CastStatToString(CastStat stat);
// Assigns |stats_map| with stats data. Used for testing.
void GetStatsInternal(StatsMap* stats_map) const;
bool GetReceiverOffset(base::TimeDelta* offset);
void RecordFrameCapturedTime(const FrameEvent& frame_event);
void RecordE2ELatency(const FrameEvent& frame_event);
void RecordPacketSentTime(const PacketEvent& packet_event);
void ErasePacketSentTime(const PacketEvent& packet_event);
void RecordNetworkLatency(const PacketEvent& packet_event);
void UpdateLastResponseTime(base::TimeTicks receiver_time);
void PopulateFpsStat(base::TimeTicks now,
CastLoggingEvent event,
CastStat stat,
StatsMap* stats_map) const;
void PopulatePlayoutDelayStat(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;
void PopulatePacketLossPercentageStat(StatsMap* stats_map) const;
const EventMediaType event_media_type_;
// Not owned by this class.
base::TickClock* const clock_;
// Not owned by this class.
ReceiverTimeOffsetEstimator* const offset_estimator_;
FrameStatsMap frame_stats_;
PacketStatsMap packet_stats_;
base::TimeDelta total_network_latency_;
int network_latency_datapoints_;
base::TimeDelta total_e2e_latency_;
int e2e_latency_datapoints_;
base::TimeTicks last_response_received_time_;
// Fixed size map to record when recent frames were captured.
FrameEventTimeMap frame_captured_times_;
// 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::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(StatsEventSubscriber);
};
} // namespace cast
} // namespace media
#endif // MEDIA_CAST_LOGGING_STATS_EVENT_SUBSCRIBER_H_