// 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_COMMON_H_ #define CAST_STREAMING_IMPL_STATISTICS_COMMON_H_ #include #include #include "cast/streaming/public/constants.h" #include "cast/streaming/public/frame_id.h" #include "cast/streaming/rtp_time.h" #include "platform/api/time.h" namespace openscreen::cast { struct StatisticsEvent { enum class Type : int { kUnknown = 0, // Sender side frame events. kFrameCaptureBegin = 1, kFrameCaptureEnd = 2, kFrameEncoded = 3, kFrameAckReceived = 4, // Receiver side frame events. kFrameAckSent = 5, kFrameDecoded = 6, kFramePlayedOut = 7, // Sender side packet events. kPacketSentToNetwork = 8, kPacketRetransmitted = 9, kPacketRtxRejected = 10, // Receiver side packet events. kPacketReceived = 11, kFrameDroppedByEncoder = 15, kNumOfEvents = kFrameDroppedByEncoder + 1 }; // Serialized values for the statistics events for use by the RTCP builder // and parser logic. *Do not modify existing values* since they are shared by // both libcast-based devices as well as a variety of legacy implementations. // // NOTE: Events 1 to 8 have been replaced with events 11 to 14 (e.g. // kAudioAckSent and kVideoAckSent merged into a single event kAckSent). // Events 9 and 10 (to log duplicated packets) have been fully removed. Future // events may reuse those values. enum class WireType : uint8_t { kUnknown = 0, // Legacy audio event types. kAudioAckSent = 1, kAudioPlayoutDelay = 2, kAudioFrameDecoded = 3, kAudioPacketReceived = 4, // Legacy video event types. kVideoAckSent = 5, kVideoRenderDelay = 6, kVideoFrameDecoded = 7, kVideoPacketReceived = 8, // New unified event types. kUnifiedAckSent = 11, kUnifiedRenderDelay = 12, kUnifiedFrameDecoded = 13, kUnifiedPacketReceived = 14, kNumOfEvents = kUnifiedPacketReceived + 1 }; enum class MediaType : int { kUnknown = 0, kAudio = 1, kVideo = 2 }; static Type FromWireType(WireType wire_type); static WireType ToWireType(Type type); static MediaType ToMediaType(StreamType type); constexpr StatisticsEvent(FrameId frame_id, Type type, MediaType media_type, RtpTimeTicks rtp_timestamp, uint32_t size, Clock::time_point timestamp, Clock::time_point received_timestamp) : frame_id(frame_id), type(type), media_type(media_type), rtp_timestamp(rtp_timestamp), size(size), timestamp(timestamp), received_timestamp(received_timestamp) {} constexpr StatisticsEvent() = default; StatisticsEvent(const StatisticsEvent& other); StatisticsEvent(StatisticsEvent&& other) noexcept; StatisticsEvent& operator=(const StatisticsEvent& other); StatisticsEvent& operator=(StatisticsEvent&& other); ~StatisticsEvent() = default; bool operator==(const StatisticsEvent& other) const; // The frame this event is associated with. FrameId frame_id; // The type of this frame event. Type type = Type::kUnknown; // Whether this was audio or video (or unknown). MediaType media_type = MediaType::kUnknown; // The RTP timestamp of the frame this event is associated with. RtpTimeTicks rtp_timestamp; // Size of this packet, or the frame it is associated with. // Note: we use uint32_t instead of size_t for byte count because this struct // is sent over IPC which could span 32 & 64 bit processes. uint32_t size = 0; // Time of event logged. Clock::time_point timestamp; // Time that the event was received by the sender. Only set for receiver-side // events. Clock::time_point received_timestamp; }; struct FrameEvent : public StatisticsEvent { constexpr FrameEvent(FrameId frame_id_in, Type type_in, MediaType media_type_in, RtpTimeTicks rtp_timestamp_in, uint32_t size_in, Clock::time_point timestamp_in, Clock::time_point received_timestamp_in, int width, int height, Clock::duration delay_delta, bool key_frame, int target_bitrate) : StatisticsEvent(frame_id_in, type_in, media_type_in, rtp_timestamp_in, size_in, timestamp_in, received_timestamp_in), width(width), height(height), delay_delta(delay_delta), key_frame(key_frame), target_bitrate(target_bitrate) {} constexpr FrameEvent() = default; FrameEvent(const FrameEvent& other); FrameEvent(FrameEvent&& other) noexcept; FrameEvent& operator=(const FrameEvent& other); FrameEvent& operator=(FrameEvent&& other); ~FrameEvent() = default; bool operator==(const FrameEvent& other) const; // Resolution of the frame. Only set for video FRAME_CAPTURE_END events. int width = 0; int height = 0; // Only set for FRAME_PLAYOUT events. // If this value is zero the frame is rendered on time. // If this value is positive it means the frame is rendered late. // If this value is negative it means the frame is rendered early. Clock::duration delay_delta{}; // Whether the frame is a key frame. Only set for video FRAME_ENCODED event. bool key_frame = false; // The requested target bitrate of the encoder at the time the frame is // encoded. Only set for video FRAME_ENCODED event. int target_bitrate = 0; }; struct PacketEvent : public StatisticsEvent { constexpr PacketEvent(FrameId frame_id_in, Type type_in, MediaType media_type_in, RtpTimeTicks rtp_timestamp_in, uint32_t size_in, Clock::time_point timestamp_in, Clock::time_point received_timestamp_in, uint16_t packet_id, uint16_t max_packet_id) : StatisticsEvent(frame_id_in, type_in, media_type_in, rtp_timestamp_in, size_in, timestamp_in, received_timestamp_in), packet_id(packet_id), max_packet_id(max_packet_id) {} constexpr PacketEvent() = default; PacketEvent(const PacketEvent& other); PacketEvent(PacketEvent&& other) noexcept; PacketEvent& operator=(const PacketEvent& other); PacketEvent& operator=(PacketEvent&& other); ~PacketEvent() = default; bool operator==(const PacketEvent& other) const; // The packet this event is associated with. uint16_t packet_id = 0; // The highest packet ID seen so far at time of event. uint16_t max_packet_id = 0; }; } // namespace openscreen::cast #endif // CAST_STREAMING_IMPL_STATISTICS_COMMON_H_