From 655e5480afbd232c73a1ea33b23dddc40eb12f01 Mon Sep 17 00:00:00 2001 From: Ryan Keane Date: Wed, 5 May 2021 17:20:41 -0700 Subject: Create Base Class for Receiver This class defines a base class for the //cast/streaming/receiver class. It is necessary to allow for unit testing of classes which require a Receiver type. Change-Id: I7a462ec64d83b41beb6e4a6d31098dc85f521fa2 Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/2876289 Reviewed-by: Jordan Bayles Commit-Queue: Ryan Keane --- cast/streaming/BUILD.gn | 2 + cast/streaming/receiver.cc | 12 ++++- cast/streaming/receiver.h | 78 +++++++---------------------- cast/streaming/receiver_base.cc | 17 +++++++ cast/streaming/receiver_base.h | 108 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 63 deletions(-) create mode 100644 cast/streaming/receiver_base.cc create mode 100644 cast/streaming/receiver_base.h (limited to 'cast') diff --git a/cast/streaming/BUILD.gn b/cast/streaming/BUILD.gn index 013073cc..85867a95 100644 --- a/cast/streaming/BUILD.gn +++ b/cast/streaming/BUILD.gn @@ -111,6 +111,8 @@ source_set("receiver") { "packet_receive_stats_tracker.h", "receiver.cc", "receiver.h", + "receiver_base.cc", + "receiver_base.h", "receiver_packet_router.cc", "receiver_packet_router.h", "receiver_session.cc", diff --git a/cast/streaming/receiver.cc b/cast/streaming/receiver.cc index 271904f5..ee2b0bc5 100644 --- a/cast/streaming/receiver.cc +++ b/cast/streaming/receiver.cc @@ -61,6 +61,16 @@ Receiver::~Receiver() { packet_router_->OnReceiverDestroyed(rtcp_session_.sender_ssrc()); } +const SessionConfig& Receiver::config() const { + return config_; +} +int Receiver::rtp_timebase() const { + return rtp_timebase_; +} +Ssrc Receiver::ssrc() const { + return rtcp_session_.receiver_ssrc(); +} + void Receiver::SetConsumer(Consumer* consumer) { consumer_ = consumer; ScheduleFrameReadyCheck(); @@ -465,8 +475,6 @@ void Receiver::ScheduleFrameReadyCheck(Clock::time_point when) { when); } -Receiver::Consumer::~Consumer() = default; - Receiver::PendingFrame::PendingFrame() = default; Receiver::PendingFrame::~PendingFrame() = default; diff --git a/cast/streaming/receiver.h b/cast/streaming/receiver.h index 66edb7d5..d7fd1c80 100644 --- a/cast/streaming/receiver.h +++ b/cast/streaming/receiver.h @@ -21,6 +21,7 @@ #include "cast/streaming/frame_collector.h" #include "cast/streaming/frame_id.h" #include "cast/streaming/packet_receive_stats_tracker.h" +#include "cast/streaming/receiver_base.h" #include "cast/streaming/rtcp_common.h" #include "cast/streaming/rtcp_session.h" #include "cast/streaming/rtp_packet_parser.h" @@ -103,20 +104,9 @@ class ReceiverPacketRouter; // 3. Last Frame Consumed: The FrameId of last frame consumed (see // ConsumeNextFrame()). Once a frame is consumed, all internal resources // related to the frame can be freed and/or re-used for later frames. -class Receiver { +class Receiver : public ReceiverBase { public: - class Consumer { - public: - virtual ~Consumer(); - - // Called whenever one or more frames have become ready for consumption. The - // |next_frame_buffer_size| argument is identical to the result of calling - // AdvanceToNextFrame(), and so the Consumer only needs to prepare a buffer - // and call ConsumeNextFrame(). It may then call AdvanceToNextFrame() to - // check whether there are any more frames ready, but this is not mandatory. - // See usage example in class-level comments. - virtual void OnFramesReady(int next_frame_buffer_size) = 0; - }; + using ReceiverBase::Consumer; // Constructs a Receiver that attaches to the given |environment| and // |packet_router|. The config contains the settings that were @@ -126,52 +116,17 @@ class Receiver { Receiver(Environment* environment, ReceiverPacketRouter* packet_router, SessionConfig config); - ~Receiver(); - - const SessionConfig& config() const { return config_; } - int rtp_timebase() const { return rtp_timebase_; } - Ssrc ssrc() const { return rtcp_session_.receiver_ssrc(); } - - // Set the Consumer receiving notifications when new frames are ready for - // consumption. Frames received before this method is called will remain in - // the queue indefinitely. - void SetConsumer(Consumer* consumer); - - // Sets how much time the consumer will need to decode/buffer/render/etc., and - // otherwise fully process a frame for on-time playback. This information is - // used by the Receiver to decide whether to skip past frames that have - // arrived too late. This method can be called repeatedly to make adjustments - // based on changing environmental conditions. - // - // Default setting: kDefaultPlayerProcessingTime - void SetPlayerProcessingTime(Clock::duration needed_time); - - // Propagates a "picture loss indicator" notification to the Sender, - // requesting a key frame so that decode/playout can recover. It is safe to - // call this redundantly. The Receiver will clear the picture loss condition - // automatically, once a key frame is received (i.e., before - // ConsumeNextFrame() is called to access it). - void RequestKeyFrame(); - - // Advances to the next frame ready for consumption. This may skip-over - // incomplete frames that will not play out on-time; but only if there are - // completed frames further down the queue that have no dependency - // relationship with them (e.g., key frames). - // - // This method returns kNoFramesReady if there is not currently a frame ready - // for consumption. The caller should wait for a Consumer::OnFramesReady() - // notification before trying again. Otherwise, the number of bytes of encoded - // data is returned, and the caller should use this to ensure the buffer it - // passes to ConsumeNextFrame() is large enough. - int AdvanceToNextFrame(); - - // Returns the next frame, both metadata and payload data. The Consumer calls - // this method after being notified via OnFramesReady(), and it can also call - // this whenever AdvanceToNextFrame() indicates another frame is ready. - // |buffer| must point to a sufficiently-sized buffer that will be populated - // with the frame's payload data. Upon return |frame->data| will be set to the - // portion of the buffer that was populated. - EncodedFrame ConsumeNextFrame(absl::Span buffer); + ~Receiver() override; + + // ReceiverBase overrides. + const SessionConfig& config() const override; + int rtp_timebase() const override; + Ssrc ssrc() const override; + void SetConsumer(Consumer* consumer) override; + void SetPlayerProcessingTime(Clock::duration needed_time) override; + void RequestKeyFrame() override; + int AdvanceToNextFrame() override; + EncodedFrame ConsumeNextFrame(absl::Span buffer) override; // Allows setting picture loss indication for testing. In production, this // should be done using the config. @@ -180,11 +135,12 @@ class Receiver { } // The default "player processing time" amount. See SetPlayerProcessingTime(). - static constexpr std::chrono::milliseconds kDefaultPlayerProcessingTime{5}; + static constexpr std::chrono::milliseconds kDefaultPlayerProcessingTime = + ReceiverBase::kDefaultPlayerProcessingTime; // Returned by AdvanceToNextFrame() when there are no frames currently ready // for consumption. - static constexpr int kNoFramesReady = -1; + static constexpr int kNoFramesReady = ReceiverBase::kNoFramesReady; protected: friend class ReceiverPacketRouter; diff --git a/cast/streaming/receiver_base.cc b/cast/streaming/receiver_base.cc new file mode 100644 index 00000000..dd0067df --- /dev/null +++ b/cast/streaming/receiver_base.cc @@ -0,0 +1,17 @@ +// Copyright 2021 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. + +#include "cast/streaming/receiver_base.h" + +namespace openscreen { +namespace cast { + +ReceiverBase::Consumer::~Consumer() = default; + +ReceiverBase::ReceiverBase() = default; + +ReceiverBase::~ReceiverBase() = default; + +} // namespace cast +} // namespace openscreen diff --git a/cast/streaming/receiver_base.h b/cast/streaming/receiver_base.h new file mode 100644 index 00000000..0ad3ff86 --- /dev/null +++ b/cast/streaming/receiver_base.h @@ -0,0 +1,108 @@ +// Copyright 2021 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_RECEIVER_BASE_H_ +#define CAST_STREAMING_RECEIVER_BASE_H_ + +#include + +#include "absl/types/span.h" +#include "cast/streaming/encoded_frame.h" +#include "cast/streaming/session_config.h" +#include "cast/streaming/ssrc.h" +#include "platform/api/time.h" + +namespace openscreen { +namespace cast { + +// The Cast Streaming Receiver, a peer corresponding to some Cast Streaming +// Sender at the other end of a network link. +// +// Cast Streaming is a transport protocol which divides up the frames for one +// media stream (e.g., audio or video) into multiple RTP packets containing an +// encrypted payload. The Receiver is the peer responsible for collecting the +// RTP packets, decrypting the payload, and re-assembling a frame that can be +// passed to a decoder and played out. +// +// A Sender ↔ Receiver pair is used to transport each media stream. Typically, +// there are two pairs in a normal system, one for the audio stream and one for +// video stream. A local player is responsible for synchronizing the playout of +// the frames of each stream to achieve lip-sync. See the discussion in +// encoded_frame.h for how the |reference_time| and |rtp_timestamp| of the +// EncodedFrames are used to achieve this. +class ReceiverBase { + public: + class Consumer { + public: + virtual ~Consumer(); + + // Called whenever one or more frames have become ready for consumption. The + // |next_frame_buffer_size| argument is identical to the result of calling + // AdvanceToNextFrame(), and so the Consumer only needs to prepare a buffer + // and call ConsumeNextFrame(). It may then call AdvanceToNextFrame() to + // check whether there are any more frames ready, but this is not mandatory. + // See usage example in class-level comments. + virtual void OnFramesReady(int next_frame_buffer_size) = 0; + }; + + ReceiverBase(); + virtual ~ReceiverBase(); + + virtual const SessionConfig& config() const = 0; + virtual int rtp_timebase() const = 0; + virtual Ssrc ssrc() const = 0; + + // Set the Consumer receiving notifications when new frames are ready for + // consumption. Frames received before this method is called will remain in + // the queue indefinitely. + virtual void SetConsumer(Consumer* consumer) = 0; + + // Sets how much time the consumer will need to decode/buffer/render/etc., and + // otherwise fully process a frame for on-time playback. This information is + // used by the Receiver to decide whether to skip past frames that have + // arrived too late. This method can be called repeatedly to make adjustments + // based on changing environmental conditions. + // + // Default setting: kDefaultPlayerProcessingTime + virtual void SetPlayerProcessingTime(Clock::duration needed_time) = 0; + + // Propagates a "picture loss indicator" notification to the Sender, + // requesting a key frame so that decode/playout can recover. It is safe to + // call this redundantly. The Receiver will clear the picture loss condition + // automatically, once a key frame is received (i.e., before + // ConsumeNextFrame() is called to access it). + virtual void RequestKeyFrame() = 0; + + // Advances to the next frame ready for consumption. This may skip-over + // incomplete frames that will not play out on-time; but only if there are + // completed frames further down the queue that have no dependency + // relationship with them (e.g., key frames). + // + // This method returns kNoFramesReady if there is not currently a frame ready + // for consumption. The caller should wait for a Consumer::OnFramesReady() + // notification before trying again. Otherwise, the number of bytes of encoded + // data is returned, and the caller should use this to ensure the buffer it + // passes to ConsumeNextFrame() is large enough. + virtual int AdvanceToNextFrame() = 0; + + // Returns the next frame, both metadata and payload data. The Consumer calls + // this method after being notified via OnFramesReady(), and it can also call + // this whenever AdvanceToNextFrame() indicates another frame is ready. + // |buffer| must point to a sufficiently-sized buffer that will be populated + // with the frame's payload data. Upon return |frame->data| will be set to the + // portion of the buffer that was populated. + virtual EncodedFrame ConsumeNextFrame(absl::Span buffer) = 0; + + // The default "player processing time" amount. See SetPlayerProcessingTime(). + static constexpr std::chrono::milliseconds kDefaultPlayerProcessingTime{5}; + + // Returned by AdvanceToNextFrame() when there are no frames currently ready + // for consumption. + static constexpr int kNoFramesReady = -1; +}; + +#endif // CAST_STREAMING_RECEIVER_BASE_H_ + +} // namespace cast +} // namespace openscreen -- cgit v1.2.3