chromium/components/cast_receiver/browser/streaming_receiver_session_client.h

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_CAST_RECEIVER_BROWSER_STREAMING_RECEIVER_SESSION_CLIENT_H_
#define COMPONENTS_CAST_RECEIVER_BROWSER_STREAMING_RECEIVER_SESSION_CLIENT_H_

#include <memory>

#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "components/cast/message_port/message_port.h"
#include "components/cast_receiver/browser/public/streaming_config_manager.h"
#include "components/cast_streaming/browser/public/network_context_getter.h"
#include "components/cast_streaming/browser/public/receiver_session.h"
#include "services/network/public/mojom/network_context.mojom.h"

namespace base {
class SequencedTaskRunner;
}  // namespace base

namespace gfx {
class Rect;
}  // namespace gfx

namespace content {
class WebContents;
}  // namespace content

namespace media {
class AudioDecoderConfig;
class VideoDecoderConfig;
struct VideoTransformation;
}  // namespace media

namespace cast_receiver {

class StreamingController;

// This class wraps all //components/cast_streaming functionality, only
// expecting the caller to supply a MessagePortFactory. Internally, it
// manages the lifetimes of cast streaming objects, and informs the caller
// of important events. Methods in this class may not be called in parallel.
class StreamingReceiverSessionClient
    : public cast_receiver::StreamingConfigManager::ConfigObserver,
      public cast_streaming::ReceiverSession::Client {
 public:
  class Handler {
   public:
    virtual ~Handler();

    //.Called when the streaming session as successfully been initialized,
    // following navigation of the observed CastWebContents to a cast-supporting
    // URL.
    virtual void OnStreamingSessionStarted() = 0;

    // Called when a nonrecoverable error occurs. Following this call, the
    // associated StreamingReceiverSessionClient instance will be placed in an
    // undefined state.
    virtual void OnError() = 0;

    // Called when the resolution as reported to the media pipeline changes.
    virtual void OnResolutionChanged(
        const gfx::Rect& size,
        const ::media::VideoTransformation& transformation) = 0;
  };

  // Max time for which streaming may wait for AV Settings receipt before being
  // treated as a failure.
  static constexpr base::TimeDelta kMaxAVSettingsWaitTime = base::Seconds(5);

  // Creates a new instance of this class. |handler| must persist for the
  // lifetime of this instance.
  StreamingReceiverSessionClient(
      scoped_refptr<base::SequencedTaskRunner> task_runner,
      network::NetworkContextGetter network_context_getter,
      std::unique_ptr<cast_api_bindings::MessagePort> message_port,
      content::WebContents* web_contents,
      Handler* handler,
      cast_receiver::StreamingConfigManager* config_manager,
      bool supports_audio,
      bool supports_video);

  ~StreamingReceiverSessionClient() override;

  // Schedules starting the Streaming Receiver owned by this instance. May only
  // be called once. At time of calling, this instance will be set as the
  // observer of |web_contents|, for which streaming will be started following
  // the latter of:
  // - Navigation to an associated URL by |cast_web_contents| as provided in the
  //   ctor.
  // - Receipt of supported AV Settings.
  // Following this call, the supported AV Settings are expected to remain
  // constant. If valid AV Settings have not been received within
  // |kMaxAVSettingsWaitTime| of this function call, it will be treated as an
  // unrecoverable error, and this instance will be placed in an undefined
  // state.
  void LaunchStreamingReceiverAsync();

  bool has_streaming_launched() const {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    return streaming_state_ == LaunchState::kLaunched;
  }

  bool is_streaming_launch_pending() const {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    return streaming_state_ & LaunchState::kLaunchCalled;
  }

  bool has_received_av_settings() const {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    return streaming_state_ & LaunchState::kAVSettingsReceived;
  }

  bool is_healthy() const {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    return !(streaming_state_ & LaunchState::kError);
  }

 private:
  friend class StreamingReceiverSessionClientTest;

  enum LaunchState : int32_t {
    kStopped = 0x00,

    // The two conditions which must be met for streaming to run.
    kLaunchCalled = 0x01 << 0,
    kAVSettingsReceived = 0x01 << 1,

    // Signifies that the above conditions have all been met.
    kReady = kAVSettingsReceived | kLaunchCalled,

    // Signifies that streaming has started.
    kLaunched = 0xFF,

    // Error state set after a Handler::OnError() call.
    kError = 0x100
  };

  // This second ctor is required for Unit Testing.
  StreamingReceiverSessionClient(
      scoped_refptr<base::SequencedTaskRunner> task_runner,
      network::NetworkContextGetter network_context_getter,
      std::unique_ptr<StreamingController> streaming_controller,
      Handler* handler,
      cast_receiver::StreamingConfigManager* config_manager,
      bool supports_audio,
      bool supports_video);

  friend inline LaunchState operator&(LaunchState first, LaunchState second) {
    return static_cast<LaunchState>(static_cast<int32_t>(first) &
                                    static_cast<int32_t>(second));
  }

  friend inline LaunchState operator|(LaunchState first, LaunchState second) {
    return static_cast<LaunchState>(static_cast<int32_t>(first) |
                                    static_cast<int32_t>(second));
  }

  friend inline LaunchState& operator|=(LaunchState& first,
                                        LaunchState second) {
    return first = first | second;
  }

  friend inline LaunchState& operator&=(LaunchState& first,
                                        LaunchState second) {
    return first = first & second;
  }

  void TriggerError();

  // cast_streaming::ReceiverSession::Client overrides.
  void OnAudioConfigUpdated(
      const ::media::AudioDecoderConfig& audio_config) override;
  void OnVideoConfigUpdated(
      const ::media::VideoDecoderConfig& video_config) override;
  void OnStreamingSessionEnded() override;

  // cast_receiver::StreamingConfigManager::ConfigObserver overrides.
  void OnStreamingConfigSet(
      const cast_streaming::ReceiverConfig& config) override;

  void VerifyAVSettingsReceived();

  // Callback passed when calling StreamingController::StartPlayback().
  void OnPlaybackStarted();

  // Handler for callbacks associated with this class. May be empty.
  Handler* const handler_;

  // Task runner on which waiting for the result of an AV Settings query should
  // occur.
  scoped_refptr<base::SequencedTaskRunner> const task_runner_;
  SEQUENCE_CHECKER(sequence_checker_);

  // Responsible for initiating the streaming session and controlling its
  // playback state.
  std::unique_ptr<StreamingController> streaming_controller_;

  // Current state in initialization of |receiver_session_|.
  LaunchState streaming_state_ = LaunchState::kStopped;

  // Tracks if this session should be initiated as audio or video only.
  bool supports_audio_ = true;
  bool supports_video_ = true;

  base::WeakPtrFactory<StreamingReceiverSessionClient> weak_factory_;
};

}  // namespace cast_receiver

#endif  // COMPONENTS_CAST_RECEIVER_BROWSER_STREAMING_RECEIVER_SESSION_CLIENT_H_