blob: bfb22ac52053605685e4c0b538643a056a5dec36 [file] [log] [blame]
// Copyright 2022 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_MIRRORING_SERVICE_OPENSCREEN_SESSION_HOST_H_
#define COMPONENTS_MIRRORING_SERVICE_OPENSCREEN_SESSION_HOST_H_
#include "base/component_export.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "components/mirroring/mojom/cast_message_channel.mojom.h"
#include "components/mirroring/mojom/resource_provider.mojom.h"
#include "components/mirroring/mojom/session_observer.mojom.h"
#include "components/mirroring/mojom/session_parameters.mojom.h"
#include "components/mirroring/service/media_remoter.h"
#include "components/mirroring/service/message_dispatcher.h"
#include "components/mirroring/service/mirror_settings.h"
#include "components/mirroring/service/openscreen_message_port.h"
#include "components/mirroring/service/openscreen_rpc_dispatcher.h"
#include "components/mirroring/service/rtp_stream.h"
#include "components/openscreen_platform/event_trace_logging_platform.h"
#include "components/openscreen_platform/task_runner.h"
#include "gpu/config/gpu_info.h"
#include "media/capture/video/video_capture_feedback.h"
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/mojo/mojom/video_encode_accelerator.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "third_party/openscreen/src/cast/streaming/sender_session.h"
using openscreen::cast::capture_recommendations::Recommendations;
namespace base {
class OneShotTimer;
}
namespace media {
class AudioInputDevice;
} // namespace media
namespace viz {
class Gpu;
} // namespace viz
namespace mirroring {
class VideoCaptureClient;
// Minimum required bitrate used for calculating bandwidth.
constexpr int kMinRequiredBitrate = 384 << 10; // 384 kbps
// Default bitrate used before we have a calculation.
constexpr int kDefaultBitrate = kMinRequiredBitrate * 2; // 768 kbps
// Hosts a streaming session by hosting an `openscreen::cast::SenderSession` and
// doing all of the necessary interfacing for audio and video capture, switching
// between mirroring and remoting, and setting up audio and video streams to
// encode and send captured content.
//
// On construction, an Open Screen SenderSession is immediately created and
// negotiation of a streaming session is started. The session host will stay
// in a good state until either the mirroring service notices a disconnection
// and tears down this streaming session, or a fatal error occurs.
//
// NOTE: most methods should be called on the same sequence as construction.
// This class also uses additional task runners, such as the IO task runner of
// this utility process for accessing the GPU, and dedicated video and audio
// encoder threads. Finally, some methods such as
// AudioCapturingCallback::Capture may be called on the audio thread.
class COMPONENT_EXPORT(MIRRORING_SERVICE) OpenscreenSessionHost final
: public RtpStreamClient,
public openscreen::cast::SenderSession::Client,
public MediaRemoter::Client {
public:
// NOTE: some notes on constructor arguments:
// `session_params`: connection information for the receiver.
// `max_resolution`: width and height that should never be exceeded.
// `resource_provider`: interface to ask the browser for resources.
// `outbound_channel`: used to send cast messages to the receiver.
// `inbound_channel`: used to receiver cast messages from the receiver.
// `io_task_runner`: used to interact with the GPU through Viz. This arg
// must be passed to enable hardware encoding.
OpenscreenSessionHost(
mojom::SessionParametersPtr session_params,
const gfx::Size& max_resolution,
mojo::PendingRemote<mojom::SessionObserver> observer,
mojo::PendingRemote<mojom::ResourceProvider> resource_provider,
mojo::PendingRemote<mojom::CastMessageChannel> outbound_channel,
mojo::PendingReceiver<mojom::CastMessageChannel> inbound_channel,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
~OpenscreenSessionHost() override;
// Initializes some of the asynchronous components of the session host, such
// as access to the GPU. Must be called before negotiation of a session
// can begin.
using AsyncInitializedCallback = base::OnceCallback<void()>;
void AsyncInitialize(AsyncInitializedCallback done_cb = {});
// SenderSession::Client overrides.
void OnNegotiated(const openscreen::cast::SenderSession* session,
openscreen::cast::SenderSession::ConfiguredSenders senders,
Recommendations capture_recommendations) override;
void OnCapabilitiesDetermined(
const openscreen::cast::SenderSession* session,
openscreen::cast::RemotingCapabilities capabilities) override;
void OnError(const openscreen::cast::SenderSession* session,
openscreen::Error error) override;
// RtpStreamClient overrides.
void OnError(const std::string& message) override;
void RequestRefreshFrame() override;
void CreateVideoEncodeAccelerator(
media::cast::ReceiveVideoEncodeAcceleratorCallback callback) override;
// MediaRemoter::Client overrides.
void ConnectToRemotingSource(
mojo::PendingRemote<media::mojom::Remoter> remoter,
mojo::PendingReceiver<media::mojom::RemotingSource> source_receiver)
override;
void RequestRemotingStreaming() override;
void RestartMirroringStreaming() override;
void SwitchSourceTab();
// Callback by media::cast::VideoSender to set a new target playout delay.
void SetTargetPlayoutDelay(base::TimeDelta playout_delay);
private:
friend class OpenscreenSessionHostTest;
FRIEND_TEST_ALL_PREFIXES(OpenscreenSessionHostTest, ChangeTargetPlayoutDelay);
FRIEND_TEST_ALL_PREFIXES(OpenscreenSessionHostTest, UpdateBandwidthEstimate);
FRIEND_TEST_ALL_PREFIXES(OpenscreenSessionHostTest,
ShouldEnableHardwareVp8EncodingIfSupported);
FRIEND_TEST_ALL_PREFIXES(OpenscreenSessionHostTest,
ShouldEnableHardwareH264EncodingIfSupported);
class AudioCapturingCallback;
using SupportedProfiles = media::VideoEncodeAccelerator::SupportedProfiles;
// Called when the GPU is either set up or determined to be unavailable due
// to software rendering being used.
void OnAsyncInitialized(const SupportedProfiles& profiles);
// Notify `observer_` of a relevant logging message.
void LogInfoMessage(const std::string& message);
// Notify `observer_` that error occurred and close the session.
void ReportAndLogError(mojom::SessionError error, const std::string& message);
// Stops the current streaming session. If not called from StopSession(), a
// new streaming session will start later after exchanging OFFER/ANSWER
// messages with the receiver. This could happen any number of times before
// StopSession() shuts down everything permanently.
void StopStreaming();
// Shuts down the entire mirroring session.
void StopSession();
// Helper method for taking the recommendations given by the Open Screen
// library and applying them to the given audio and video configs.
void SetConstraints(
const Recommendations& recommendations,
absl::optional<media::cast::FrameSenderConfig>& audio_config,
absl::optional<media::cast::FrameSenderConfig>& video_config);
// Sends a request to create an audio input stream through the Audio Service,
// configured with the specified audio `params`. The `shared_memory_count`
// property indicates how many equal-lengthed segments exist in the shared
// memory buffer. Once the stream has been created, `client` is called.
void CreateAudioStream(
mojo::PendingRemote<mojom::AudioStreamCreatorClient> client,
const media::AudioParameters& params,
uint32_t shared_memory_count);
// Callback by Audio/VideoSender to indicate encoder status change.
void OnEncoderStatusChange(media::cast::OperationalStatus status);
// Callback by media::cast::VideoSender to report resource utilization.
void ProcessFeedback(const media::VideoCaptureFeedback& feedback);
// Called by OpenscreenFrameSender to determine bitrate.
int GetSuggestedVideoBitrate(int min_bitrate, int max_bitrate) const;
// Called periodically to update the `bandwidth_estimate_`.
void UpdateBandwidthEstimate();
// Create and send OFFER message.
void Negotiate();
void NegotiateMirroring();
void NegotiateRemoting();
// Initialize `media_remoter_` and `rpc_dispatcher_`.
void InitMediaRemoter(
const openscreen::cast::RemotingCapabilities& capabilities);
// Called 5 seconds after the `media_remoter_` is initialized for Remote
// Playabck sessions. It terminates the streaming session if remoting is not
// started when it's called.
void OnRemotingStartTimeout();
// Called to provide Open Screen with access to this host's network proxy.
network::mojom::NetworkContext* GetNetworkContext();
// Provided by client.
const mojom::SessionParameters session_params_;
// State transition:
// kInitializing
// |
// ↓
// kMirroring <-------> kRemoting
// | |
// `---> kStopped <----'
//
// NOTE: once a session has reached a kStopped state, it cannot be
// reinitialized or used.
enum class State {
// The session is initializing, and can't be used yet.
kInitializing,
// A mirroring streaming session is starting or started.
kMirroring,
// A remoting streaming session is starting or started.
kRemoting,
// The session is stopped due to a user request or a fatal error.
kStopped,
};
State state_ = State::kInitializing;
// Informed of changes to session state.
mojo::Remote<mojom::SessionObserver> observer_;
// Provides a variety of instances, such as the current network context.
mojo::Remote<mojom::ResourceProvider> resource_provider_;
// Implements an Open Screen message port and wraps inbound and outbound mojom
// channels.
OpenscreenMessagePort message_port_;
// Used to initialize video and audio capture clients.
MirrorSettings mirror_settings_;
// Used to wrap the current thread's sequenced task runner for use by Open
// Screen.
std::unique_ptr<openscreen_platform::TaskRunner> openscreen_task_runner_;
// Used to wrap the `openscreen_task_runner` as well as the clock and
// local endpoint for binding. Responsible for creating and binding a UDP
// socket.
std::unique_ptr<openscreen::cast::Environment> openscreen_environment_;
// Takes care of handling OFFER/ANSWER negotiations, as well as querying
// capabilities and creating openscreen::cast::Sender objects upon
// negotiation.
std::unique_ptr<openscreen::cast::SenderSession> session_;
// Used to provide access to UDP sockets and URL loading.
mojo::Remote<network::mojom::NetworkContext> network_context_;
bool set_network_context_proxy_ = false;
// Stored as part of generating an OFFER.
// NOTE: currently we only support Opus audio, but may provide a variety of
// video codec configurations.
absl::optional<media::cast::FrameSenderConfig> last_offered_audio_config_;
std::vector<media::cast::FrameSenderConfig> last_offered_video_configs_;
// Created after OFFER/ANSWER exchange succeeds.
std::unique_ptr<AudioRtpStream> audio_stream_;
std::unique_ptr<VideoRtpStream> video_stream_;
// Connects to the video capture host and launches the video capture device.
std::unique_ptr<VideoCaptureClient> video_capture_client_;
// Manages the clock and thread proxies for the audio sender, video sender,
// and media remoter.
scoped_refptr<media::cast::CastEnvironment> cast_environment_;
// Task runners used specifically for audio, video encoding.
scoped_refptr<base::SingleThreadTaskRunner> audio_encode_thread_;
scoped_refptr<base::SingleThreadTaskRunner> video_encode_thread_;
// Called when audio is successfully captured by `audio_input_device_`.
std::unique_ptr<AudioCapturingCallback> audio_capturing_callback_;
// Captures audio samples from the resourceprovider-created audio stream.
scoped_refptr<media::AudioInputDevice> audio_input_device_;
// Used as an interface for the media remoter to send RPC messages. Created
// when a successful capabilities response arrives.
std::unique_ptr<OpenscreenRpcDispatcher> rpc_dispatcher_;
// Manages remoting content to the Cast Receiver. Created when a successful
// capabilities response arrives.
std::unique_ptr<MediaRemoter> media_remoter_;
// GPU specific properties, used to indicate whether HW encoding should be
// used and to help initialize it if enabled.
std::unique_ptr<viz::Gpu> gpu_;
SupportedProfiles supported_profiles_;
mojo::Remote<media::mojom::VideoEncodeAcceleratorProvider> vea_provider_;
// Called when the session host has fully initialized.
AsyncInitializedCallback initialized_cb_;
// Used to periodically update the currently used bandwidth estimate.
base::RepeatingTimer bandwidth_update_timer_;
// Used to override getting the bandwidth from the session. Setting to a
// positive value causes the session's bandwidth estimation to not be called.
int forced_bandwidth_estimate_for_testing_ = 0;
// The portion of the bandwidth estimate that is currently available for use.
// Note that the actual bandwidth will be effectively capped at the sum of the
// current video and audio bitrates.
int usable_bandwidth_ = kDefaultBitrate;
// Indicate whether we're in the middle of switching tab sources.
bool switching_tab_source_ = false;
// This timer is used to stop the session in case Remoting is not started
// before timeout. The timer is stopped when Remoting session successfully
// starts.
base::OneShotTimer remote_playback_start_timer_;
// Records the time when the streaming session is started and `media_remoter_`
// is initialized.
absl::optional<base::Time> remote_playback_start_time_;
// Used in callbacks executed on task runners, such as by RtpStream.
// TODO(https://crbug.com/1363503): determine if weak pointers can be removed.
base::WeakPtrFactory<OpenscreenSessionHost> weak_factory_{this};
};
} // namespace mirroring
#endif // COMPONENTS_MIRRORING_SERVICE_OPENSCREEN_SESSION_HOST_H_