1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
|
// 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_
|