122 lines
5.4 KiB
C++
122 lines
5.4 KiB
C++
// Copyright 2019 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 CAST_STREAMING_COMPOUND_RTCP_PARSER_H_
|
|
#define CAST_STREAMING_COMPOUND_RTCP_PARSER_H_
|
|
|
|
#include <chrono>
|
|
#include <vector>
|
|
|
|
#include "absl/types/optional.h"
|
|
#include "absl/types/span.h"
|
|
#include "cast/streaming/frame_id.h"
|
|
#include "cast/streaming/rtcp_common.h"
|
|
#include "cast/streaming/rtp_defines.h"
|
|
|
|
namespace openscreen {
|
|
namespace cast {
|
|
|
|
class RtcpSession;
|
|
|
|
// Parses compound RTCP packets from a Receiver, invoking client callbacks when
|
|
// information of interest to a Sender (in the current process) is encountered.
|
|
class CompoundRtcpParser {
|
|
public:
|
|
// Callback interface used while parsing RTCP packets of interest to a Sender.
|
|
// The implementation must take into account:
|
|
//
|
|
// 1. Some/All of the data could be stale, as it only reflects the state of
|
|
// the Receiver at the time the packet was generated. A significant
|
|
// amount of time may have passed, depending on how long it took the
|
|
// packet to reach this local instance over the network.
|
|
// 2. The data shouldn't necessarily be trusted blindly: Some may be
|
|
// inconsistent (e.g., the same frame being ACKed and NACKed; or a frame
|
|
// that has not been sent yet is being NACKed). While that would indicate
|
|
// a badly-behaving Receiver, the Sender should be robust to such things.
|
|
class Client {
|
|
public:
|
|
Client();
|
|
virtual ~Client();
|
|
|
|
// Called when a Receiver Reference Time Report has been parsed.
|
|
virtual void OnReceiverReferenceTimeAdvanced(
|
|
Clock::time_point reference_time);
|
|
|
|
// Called when a Receiver Report with a Report Block has been parsed.
|
|
virtual void OnReceiverReport(const RtcpReportBlock& receiver_report);
|
|
|
|
// Called when the Receiver has encountered an unrecoverable error in
|
|
// decoding the data. The Sender should provide a key frame as soon as
|
|
// possible.
|
|
virtual void OnReceiverIndicatesPictureLoss();
|
|
|
|
// Called when the Receiver indicates that all of the packets for all frames
|
|
// up to and including |frame_id| have been successfully received (or
|
|
// otherwise do not need to be re-transmitted). The |playout_delay| is the
|
|
// Receiver's current end-to-end target playout delay setting, which should
|
|
// reflect any changes the Sender has made by using the "Cast Adaptive
|
|
// Latency Extension" in RTP packets.
|
|
virtual void OnReceiverCheckpoint(FrameId frame_id,
|
|
std::chrono::milliseconds playout_delay);
|
|
|
|
// Called to indicate the Receiver has successfully received all of the
|
|
// packets for each of the given |acks|. The argument's elements are in
|
|
// monotonically increasing order.
|
|
virtual void OnReceiverHasFrames(std::vector<FrameId> acks);
|
|
|
|
// Called to indicate the Receiver is missing certain specific packets for
|
|
// certain specific frames. Any elements where the packet_id is
|
|
// kAllPacketsLost indicates that all the packets are missing for a frame.
|
|
// The argument's elements are in monotonically increasing order.
|
|
virtual void OnReceiverIsMissingPackets(std::vector<PacketNack> nacks);
|
|
};
|
|
|
|
// |session| and |client| must be non-null and must outlive the
|
|
// CompoundRtcpParser instance.
|
|
CompoundRtcpParser(RtcpSession* session, Client* client);
|
|
~CompoundRtcpParser();
|
|
|
|
// Parses the packet, invoking the Client callback methods when appropriate.
|
|
// Returns true if the |packet| was well-formed, or false if it was corrupt.
|
|
// Note that none of the Client callback methods will be invoked until a
|
|
// packet is known to be well-formed.
|
|
//
|
|
// |max_feedback_frame_id| is the maximum-valued FrameId that could possibly
|
|
// be ACKnowledged by the Receiver, if there is Cast Feedback in the |packet|.
|
|
// This is needed for expanding truncated frame IDs correctly.
|
|
bool Parse(absl::Span<const uint8_t> packet, FrameId max_feedback_frame_id);
|
|
|
|
private:
|
|
// These return true if the input was well-formed, and false if it was
|
|
// invalid/corrupt. The true/false value does NOT indicate whether the data
|
|
// contained within was ignored. Output arguments are only modified if the
|
|
// input contained the relevant field(s).
|
|
bool ParseReceiverReport(absl::Span<const uint8_t> in,
|
|
int num_report_blocks,
|
|
absl::optional<RtcpReportBlock>* receiver_report);
|
|
bool ParseFeedback(absl::Span<const uint8_t> in,
|
|
FrameId max_feedback_frame_id,
|
|
FrameId* checkpoint_frame_id,
|
|
std::chrono::milliseconds* target_playout_delay,
|
|
std::vector<FrameId>* received_frames,
|
|
std::vector<PacketNack>* packet_nacks);
|
|
bool ParseExtendedReports(absl::Span<const uint8_t> in,
|
|
Clock::time_point* receiver_reference_time);
|
|
bool ParsePictureLossIndicator(absl::Span<const uint8_t> in,
|
|
bool* picture_loss_indicator);
|
|
|
|
RtcpSession* const session_;
|
|
Client* const client_;
|
|
|
|
// Tracks the latest timestamp seen from any Receiver Reference Time Report,
|
|
// and uses this to ignore stale RTCP packets that arrived out-of-order and/or
|
|
// late from the network.
|
|
Clock::time_point latest_receiver_timestamp_;
|
|
};
|
|
|
|
} // namespace cast
|
|
} // namespace openscreen
|
|
|
|
#endif // CAST_STREAMING_COMPOUND_RTCP_PARSER_H_
|