android13/external/openscreen/cast/streaming/sender_session.h

272 lines
11 KiB
C++

// Copyright 2020 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_SENDER_SESSION_H_
#define CAST_STREAMING_SENDER_SESSION_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "cast/common/public/message_port.h"
#include "cast/streaming/answer_messages.h"
#include "cast/streaming/capture_configs.h"
#include "cast/streaming/capture_recommendations.h"
#include "cast/streaming/offer_messages.h"
#include "cast/streaming/remoting_capabilities.h"
#include "cast/streaming/rpc_messenger.h"
#include "cast/streaming/sender.h"
#include "cast/streaming/sender_packet_router.h"
#include "cast/streaming/session_config.h"
#include "cast/streaming/session_messenger.h"
#include "json/value.h"
#include "util/json/json_serialization.h"
namespace openscreen {
namespace cast {
class Environment;
class Sender;
class SenderSession final {
public:
// Upon successful negotiation, a set of configured senders is constructed
// for handling audio and video. Note that either sender may be null.
struct ConfiguredSenders {
// In practice, we may have 0, 1, or 2 senders configured, depending
// on if the device supports audio and video, and if we were able to
// successfully negotiate a sender configuration.
// If the sender is audio- or video-only, either of the senders
// may be nullptr. However, in the majority of cases they will be populated.
Sender* audio_sender = nullptr;
AudioCaptureConfig audio_config;
Sender* video_sender = nullptr;
VideoCaptureConfig video_config;
};
// This struct contains all of the information necessary to begin remoting
// after we receive the capabilities from the receiver.
struct RemotingNegotiation {
ConfiguredSenders senders;
// The capabilities reported by the connected receiver. NOTE: SenderSession
// reports the capabilities as-is from the Receiver, so clients concerned
// about legacy devices, such as pre-1.27 Earth receivers should do
// a version check when using these capabilities to offer remoting.
RemotingCapabilities capabilities;
};
// The embedder should provide a client for handling negotiation events.
// The client is required to implement a mirorring handler, and may choose
// to provide a remoting negotiation if it supports remoting.
// When the negotiation is complete, the appropriate |On*Negotiated| handler
// is called.
class Client {
public:
// Called when a new set of senders has been negotiated. This may be
// called multiple times during a session, once for every time Negotiate()
// is called on the SenderSession object. The negotiation call also includes
// capture recommendations that can be used by the sender to provide
// an optimal video stream for the receiver.
virtual void OnNegotiated(
const SenderSession* session,
ConfiguredSenders senders,
capture_recommendations::Recommendations capture_recommendations) = 0;
// Called when a new set of remoting senders has been negotiated. Since
// remoting is an optional feature, the default behavior here is to leave
// this method unhandled.
virtual void OnRemotingNegotiated(const SenderSession* session,
RemotingNegotiation negotiation) {}
// Called whenever an error occurs. Ends the ongoing session, and the caller
// must call Negotiate() again if they wish to re-establish streaming.
virtual void OnError(const SenderSession* session, Error error) = 0;
protected:
virtual ~Client();
};
// The configuration information required to set up the session.
struct Configuration {
// The remote address of the receiver to connect to. NOTE: we do eventually
// set the remote endpoint on the |environment| object, but only after
// getting the port information from a successful ANSWER message.
IPAddress remote_address;
// The client for notifying of successful negotiations and errors. Required.
Client* const client;
// The cast environment used to access operating system resources, such
// as the UDP socket for RTP/RTCP messaging. Required.
Environment* environment;
// The message port used to send streaming control protocol messages.
MessagePort* message_port;
// The message source identifier (e.g. this sender).
std::string message_source_id;
// The message destination identifier (e.g. the receiver we are connected
// to).
std::string message_destination_id;
// Whether or not the android RTP value hack should be used (for legacy
// android devices). For more information, see https://crbug.com/631828.
bool use_android_rtp_hack = true;
};
// The SenderSession assumes that the passed in client, environment, and
// message port persist for at least the lifetime of the SenderSession. If
// one of these classes needs to be reset, a new SenderSession should be
// created.
//
// |message_source_id| and |message_destination_id| are the local and remote
// ID, respectively, to use when sending or receiving control messages (e.g.,
// OFFERs or ANSWERs) over the |message_port|. |message_port|'s SetClient()
// method will be called.
explicit SenderSession(Configuration config);
SenderSession(const SenderSession&) = delete;
SenderSession(SenderSession&&) noexcept = delete;
SenderSession& operator=(const SenderSession&) = delete;
SenderSession& operator=(SenderSession&&) = delete;
~SenderSession();
// Starts a mirroring OFFER/ANSWER exchange with the already configured
// receiver over the message port. The caller should assume any configured
// senders become invalid when calling this method.
Error Negotiate(std::vector<AudioCaptureConfig> audio_configs,
std::vector<VideoCaptureConfig> video_configs);
// Remoting negotiation is actually very similar to mirroring negotiation--
// an OFFER/ANSWER exchange still occurs, however only one audio and video
// codec should be presented based on the encoding of the media element that
// should be remoted. Note: the codec fields in |audio_config| and
// |video_config| are ignored in favor of |kRemote|.
Error NegotiateRemoting(AudioCaptureConfig audio_config,
VideoCaptureConfig video_config);
// Get the current network usage (in bits per second). This includes all
// senders managed by this session, and is a best guess based on receiver
// feedback. Embedders may use this information to throttle capture devices.
int GetEstimatedNetworkBandwidth() const;
// The RPC messenger for this session. NOTE: RPC messages may come at
// any time from the receiver, so subscriptions to RPC remoting messages
// should be done before calling |NegotiateRemoting|.
RpcMessenger* rpc_messenger() { return &rpc_messenger_; }
private:
// We store the current negotiation, so that when we get an answer from the
// receiver we can line up the selected streams with the original
// configuration.
struct InProcessNegotiation {
// The offer, which should always be valid if we have an in process
// negotiation.
Offer offer;
// The configs used to derive the offer.
std::vector<AudioCaptureConfig> audio_configs;
std::vector<VideoCaptureConfig> video_configs;
// The answer message for this negotiation, which may be invalid if we
// haven't received an answer yet.
Answer answer;
};
// The state of the session.
enum class State {
// Not sending content--may be in the middle of negotiation, or just
// waiting.
kIdle,
// Currently mirroring content to a receiver.
kStreaming,
// Currently remoting content to a receiver.
kRemoting
};
// Reset the state and tear down the current negotiation/negotiated mirroring
// or remoting session. After reset, the SenderSession is still connected to
// the same |remote_address_|, and the |packet_router_| and sequence number
// will be unchanged.
void ResetState();
// Uses the passed in configs and offer to send an OFFER/ANSWER negotiation
// and cache the new InProcessNavigation.
Error StartNegotiation(std::vector<AudioCaptureConfig> audio_configs,
std::vector<VideoCaptureConfig> video_configs,
Offer offer);
// Specific message type handler methods.
void OnAnswer(ReceiverMessage message);
void OnCapabilitiesResponse(ReceiverMessage message);
void OnRpcMessage(ReceiverMessage message);
void HandleErrorMessage(ReceiverMessage message, const std::string& text);
// Used by SpawnSenders to generate a sender for a specific stream.
std::unique_ptr<Sender> CreateSender(Ssrc receiver_ssrc,
const Stream& stream,
RtpPayloadType type);
// Helper methods for spawning specific senders from the Answer message.
void SpawnAudioSender(ConfiguredSenders* senders,
Ssrc receiver_ssrc,
int send_index,
int config_index);
void SpawnVideoSender(ConfiguredSenders* senders,
Ssrc receiver_ssrc,
int send_index,
int config_index);
// Spawn a set of configured senders from the currently stored negotiation.
ConfiguredSenders SpawnSenders(const Answer& answer);
// Used by the RPC messenger to send outbound messages.
void SendRpcMessage(std::vector<uint8_t> message_body);
// This session's configuration.
Configuration config_;
// The session messenger, which uses the message port for sending control
// messages. For message formats, see
// cast/protocol/castv2/streaming_schema.json.
SenderSessionMessenger messenger_;
// The RPC messenger, which uses the session messager for sending RPC messages
// and handles subscriptions to RPC messages.
RpcMessenger rpc_messenger_;
// The packet router used for RTP/RTCP messaging across all senders.
SenderPacketRouter packet_router_;
// Each negotiation has its own sequence number, and the receiver replies
// with the same sequence number that we send. Each message to the receiver
// advances our current sequence number.
int current_sequence_number_ = 0;
// The current negotiation. If present, we are expected an ANSWER from
// the receiver. If not present, any provided ANSWERS are rejected.
std::unique_ptr<InProcessNegotiation> current_negotiation_;
// The current state of the session. Note that the state is intentionally
// limited. |kStreaming| or |kRemoting| means that we are either starting
// a negotiation or actively sending to a receiver.
State state_ = State::kIdle;
// If the negotiation has succeeded, we store the current audio and video
// senders used for this session. Either or both may be nullptr.
std::unique_ptr<Sender> current_audio_sender_;
std::unique_ptr<Sender> current_video_sender_;
}; // namespace cast
} // namespace cast
} // namespace openscreen
#endif // CAST_STREAMING_SENDER_SESSION_H_