1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/streaming/sender_session.h"
6
7 #include <openssl/rand.h>
8 #include <stdint.h>
9
10 #include <algorithm>
11 #include <iterator>
12 #include <string>
13 #include <utility>
14
15 #include "absl/strings/match.h"
16 #include "absl/strings/numbers.h"
17 #include "cast/streaming/capture_recommendations.h"
18 #include "cast/streaming/environment.h"
19 #include "cast/streaming/message_fields.h"
20 #include "cast/streaming/offer_messages.h"
21 #include "cast/streaming/sender.h"
22 #include "cast/streaming/sender_message.h"
23 #include "util/crypto/random_bytes.h"
24 #include "util/json/json_helpers.h"
25 #include "util/json/json_serialization.h"
26 #include "util/osp_logging.h"
27 #include "util/stringprintf.h"
28
29 namespace openscreen {
30 namespace cast {
31
32 namespace {
33
CreateStream(int index,const AudioCaptureConfig & config,bool use_android_rtp_hack)34 AudioStream CreateStream(int index,
35 const AudioCaptureConfig& config,
36 bool use_android_rtp_hack) {
37 return AudioStream{Stream{index,
38 Stream::Type::kAudioSource,
39 config.channels,
40 GetPayloadType(config.codec, use_android_rtp_hack),
41 GenerateSsrc(true /*high_priority*/),
42 config.target_playout_delay,
43 GenerateRandomBytes16(),
44 GenerateRandomBytes16(),
45 false /* receiver_rtcp_event_log */,
46 {} /* receiver_rtcp_dscp */,
47 config.sample_rate,
48 config.codec_parameter},
49 config.codec,
50 std::max(config.bit_rate, kDefaultAudioMinBitRate)};
51 }
52
CreateStream(int index,const VideoCaptureConfig & config,bool use_android_rtp_hack)53 VideoStream CreateStream(int index,
54 const VideoCaptureConfig& config,
55 bool use_android_rtp_hack) {
56 constexpr int kVideoStreamChannelCount = 1;
57 return VideoStream{
58 Stream{index,
59 Stream::Type::kVideoSource,
60 kVideoStreamChannelCount,
61 GetPayloadType(config.codec, use_android_rtp_hack),
62 GenerateSsrc(false /*high_priority*/),
63 config.target_playout_delay,
64 GenerateRandomBytes16(),
65 GenerateRandomBytes16(),
66 false /* receiver_rtcp_event_log */,
67 {} /* receiver_rtcp_dscp */,
68 kRtpVideoTimebase,
69 config.codec_parameter},
70 config.codec,
71 config.max_frame_rate,
72 (config.max_bit_rate >= kDefaultVideoMinBitRate)
73 ? config.max_bit_rate
74 : kDefaultVideoMaxBitRate,
75 {}, // protection
76 {}, // profile
77 {}, // protection
78 config.resolutions,
79 {} /* error_recovery mode, always "castv2" */
80 };
81 }
82
83 template <typename S, typename C>
CreateStreamList(int offset_index,const std::vector<C> & configs,bool use_android_rtp_hack,std::vector<S> * out)84 void CreateStreamList(int offset_index,
85 const std::vector<C>& configs,
86 bool use_android_rtp_hack,
87 std::vector<S>* out) {
88 out->reserve(configs.size());
89 for (size_t i = 0; i < configs.size(); ++i) {
90 out->emplace_back(
91 CreateStream(i + offset_index, configs[i], use_android_rtp_hack));
92 }
93 }
94
CreateMirroringOffer(const std::vector<AudioCaptureConfig> & audio_configs,const std::vector<VideoCaptureConfig> & video_configs,bool use_android_rtp_hack)95 Offer CreateMirroringOffer(const std::vector<AudioCaptureConfig>& audio_configs,
96 const std::vector<VideoCaptureConfig>& video_configs,
97 bool use_android_rtp_hack) {
98 Offer offer;
99 offer.cast_mode = CastMode::kMirroring;
100
101 // NOTE here: IDs will always follow the pattern:
102 // [0.. audio streams... N - 1][N.. video streams.. K]
103 CreateStreamList(0, audio_configs, use_android_rtp_hack,
104 &offer.audio_streams);
105 CreateStreamList(audio_configs.size(), video_configs, use_android_rtp_hack,
106 &offer.video_streams);
107
108 return offer;
109 }
110
CreateRemotingOffer(const AudioCaptureConfig & audio_config,const VideoCaptureConfig & video_config,bool use_android_rtp_hack)111 Offer CreateRemotingOffer(const AudioCaptureConfig& audio_config,
112 const VideoCaptureConfig& video_config,
113 bool use_android_rtp_hack) {
114 Offer offer;
115 offer.cast_mode = CastMode::kRemoting;
116
117 AudioStream audio_stream =
118 CreateStream(0, audio_config, use_android_rtp_hack);
119 audio_stream.codec = AudioCodec::kNotSpecified;
120 audio_stream.stream.rtp_payload_type =
121 GetPayloadType(AudioCodec::kNotSpecified, use_android_rtp_hack);
122 offer.audio_streams.push_back(std::move(audio_stream));
123
124 VideoStream video_stream =
125 CreateStream(1, video_config, use_android_rtp_hack);
126 video_stream.codec = VideoCodec::kNotSpecified;
127 video_stream.stream.rtp_payload_type =
128 GetPayloadType(VideoCodec::kNotSpecified, use_android_rtp_hack);
129 offer.video_streams.push_back(std::move(video_stream));
130
131 return offer;
132 }
133
IsValidAudioCaptureConfig(const AudioCaptureConfig & config)134 bool IsValidAudioCaptureConfig(const AudioCaptureConfig& config) {
135 return config.channels >= 1 && config.bit_rate >= 0;
136 }
137
138 // We don't support resolutions below our minimums.
IsSupportedResolution(const Resolution & resolution)139 bool IsSupportedResolution(const Resolution& resolution) {
140 return resolution.width > kMinVideoWidth &&
141 resolution.height > kMinVideoHeight;
142 }
143
IsValidVideoCaptureConfig(const VideoCaptureConfig & config)144 bool IsValidVideoCaptureConfig(const VideoCaptureConfig& config) {
145 return config.max_frame_rate.is_positive() &&
146 ((config.max_bit_rate == 0) ||
147 (config.max_bit_rate >= kDefaultVideoMinBitRate)) &&
148 !config.resolutions.empty() &&
149 std::all_of(config.resolutions.begin(), config.resolutions.end(),
150 IsSupportedResolution);
151 }
152
AreAllValid(const std::vector<AudioCaptureConfig> & audio_configs,const std::vector<VideoCaptureConfig> & video_configs)153 bool AreAllValid(const std::vector<AudioCaptureConfig>& audio_configs,
154 const std::vector<VideoCaptureConfig>& video_configs) {
155 return std::all_of(audio_configs.begin(), audio_configs.end(),
156 IsValidAudioCaptureConfig) &&
157 std::all_of(video_configs.begin(), video_configs.end(),
158 IsValidVideoCaptureConfig);
159 }
160
ToCapabilities(const ReceiverCapability & capability)161 RemotingCapabilities ToCapabilities(const ReceiverCapability& capability) {
162 RemotingCapabilities out;
163 for (MediaCapability c : capability.media_capabilities) {
164 switch (c) {
165 case MediaCapability::kAudio:
166 out.audio.push_back(AudioCapability::kBaselineSet);
167 break;
168 case MediaCapability::kAac:
169 out.audio.push_back(AudioCapability::kAac);
170 break;
171 case MediaCapability::kOpus:
172 out.audio.push_back(AudioCapability::kOpus);
173 break;
174 case MediaCapability::k4k:
175 out.video.push_back(VideoCapability::kSupports4k);
176 break;
177 case MediaCapability::kH264:
178 out.video.push_back(VideoCapability::kH264);
179 break;
180 case MediaCapability::kVp8:
181 out.video.push_back(VideoCapability::kVp8);
182 break;
183 case MediaCapability::kVp9:
184 out.video.push_back(VideoCapability::kVp9);
185 break;
186 case MediaCapability::kHevc:
187 out.video.push_back(VideoCapability::kHevc);
188 break;
189 case MediaCapability::kAv1:
190 out.video.push_back(VideoCapability::kAv1);
191 break;
192 case MediaCapability::kVideo:
193 // noop, as "video" is ignored by Chrome remoting.
194 break;
195
196 default:
197 OSP_NOTREACHED();
198 }
199 }
200 return out;
201 }
202
203 } // namespace
204
205 SenderSession::Client::~Client() = default;
206
SenderSession(Configuration config)207 SenderSession::SenderSession(Configuration config)
208 : config_(config),
209 messenger_(
210 config_.message_port,
211 config_.message_source_id,
212 config_.message_destination_id,
213 [this](Error error) {
214 OSP_DLOG_WARN << "SenderSession message port error: " << error;
215 config_.client->OnError(this, error);
216 },
217 config_.environment->task_runner()),
__anon1c56a2130302(std::vector<uint8_t> message) 218 rpc_messenger_([this](std::vector<uint8_t> message) {
219 SendRpcMessage(std::move(message));
220 }),
221 packet_router_(config_.environment) {
222 OSP_DCHECK(config_.client);
223 OSP_DCHECK(config_.environment);
224
225 // We may or may not do remoting this session, however our RPC handler
226 // is not negotiation-specific and registering on construction here allows us
227 // to record any unexpected RPC messages.
228 messenger_.SetHandler(ReceiverMessage::Type::kRpc,
__anon1c56a2130402(ReceiverMessage message) 229 [this](ReceiverMessage message) {
230 this->OnRpcMessage(std::move(message));
231 });
232 }
233
234 SenderSession::~SenderSession() = default;
235
Negotiate(std::vector<AudioCaptureConfig> audio_configs,std::vector<VideoCaptureConfig> video_configs)236 Error SenderSession::Negotiate(std::vector<AudioCaptureConfig> audio_configs,
237 std::vector<VideoCaptureConfig> video_configs) {
238 // Negotiating with no streams doesn't make any sense.
239 if (audio_configs.empty() && video_configs.empty()) {
240 return Error(Error::Code::kParameterInvalid,
241 "Need at least one audio or video config to negotiate.");
242 }
243 if (!AreAllValid(audio_configs, video_configs)) {
244 return Error(Error::Code::kParameterInvalid, "Invalid configs provided.");
245 }
246
247 Offer offer = CreateMirroringOffer(audio_configs, video_configs,
248 config_.use_android_rtp_hack);
249 return StartNegotiation(std::move(audio_configs), std::move(video_configs),
250 std::move(offer));
251 }
252
NegotiateRemoting(AudioCaptureConfig audio_config,VideoCaptureConfig video_config)253 Error SenderSession::NegotiateRemoting(AudioCaptureConfig audio_config,
254 VideoCaptureConfig video_config) {
255 // Remoting requires both an audio and a video configuration.
256 if (!IsValidAudioCaptureConfig(audio_config) ||
257 !IsValidVideoCaptureConfig(video_config)) {
258 return Error(Error::Code::kParameterInvalid,
259 "Passed invalid audio or video config.");
260 }
261
262 Offer offer = CreateRemotingOffer(audio_config, video_config,
263 config_.use_android_rtp_hack);
264 return StartNegotiation({audio_config}, {video_config}, std::move(offer));
265 }
266
GetEstimatedNetworkBandwidth() const267 int SenderSession::GetEstimatedNetworkBandwidth() const {
268 return packet_router_.ComputeNetworkBandwidth();
269 }
270
ResetState()271 void SenderSession::ResetState() {
272 state_ = State::kIdle;
273 current_negotiation_.reset();
274 current_audio_sender_.reset();
275 current_video_sender_.reset();
276 }
277
StartNegotiation(std::vector<AudioCaptureConfig> audio_configs,std::vector<VideoCaptureConfig> video_configs,Offer offer)278 Error SenderSession::StartNegotiation(
279 std::vector<AudioCaptureConfig> audio_configs,
280 std::vector<VideoCaptureConfig> video_configs,
281 Offer offer) {
282 current_negotiation_ =
283 std::unique_ptr<InProcessNegotiation>(new InProcessNegotiation{
284 offer, std::move(audio_configs), std::move(video_configs)});
285
286 return messenger_.SendRequest(
287 SenderMessage{SenderMessage::Type::kOffer, ++current_sequence_number_,
288 true, std::move(offer)},
289 ReceiverMessage::Type::kAnswer,
290 [this](ReceiverMessage message) { OnAnswer(message); });
291 }
292
OnAnswer(ReceiverMessage message)293 void SenderSession::OnAnswer(ReceiverMessage message) {
294 if (!message.valid) {
295 HandleErrorMessage(message, "Invalid answer response message");
296 return;
297 }
298
299 // There isn't an obvious way to tell from the Answer whether it is mirroring
300 // or remoting specific--the only clues are in the original offer message.
301 const Answer& answer = absl::get<Answer>(message.body);
302 if (current_negotiation_->offer.cast_mode == CastMode::kMirroring) {
303 ConfiguredSenders senders = SpawnSenders(answer);
304 // If we didn't select any senders, the negotiation was unsuccessful.
305 if (senders.audio_sender == nullptr && senders.video_sender == nullptr) {
306 return;
307 }
308
309 state_ = State::kStreaming;
310 config_.client->OnNegotiated(
311 this, std::move(senders),
312 capture_recommendations::GetRecommendations(answer));
313 } else {
314 state_ = State::kRemoting;
315
316 // We don't want to spawn senders yet, since we don't know what the
317 // receiver's capabilities are. So, we cache the Answer until the
318 // capabilites request is completed.
319 current_negotiation_->answer = answer;
320 const Error result = messenger_.SendRequest(
321 SenderMessage{SenderMessage::Type::kGetCapabilities,
322 ++current_sequence_number_, true},
323 ReceiverMessage::Type::kCapabilitiesResponse,
324 [this](ReceiverMessage message) { OnCapabilitiesResponse(message); });
325 if (!result.ok()) {
326 config_.client->OnError(
327 this, Error(Error::Code::kNegotiationFailure,
328 "Failed to set a GET_CAPABILITIES request"));
329 }
330 }
331 }
332
OnCapabilitiesResponse(ReceiverMessage message)333 void SenderSession::OnCapabilitiesResponse(ReceiverMessage message) {
334 if (!current_negotiation_ || !current_negotiation_->answer.IsValid()) {
335 OSP_LOG_INFO
336 << "Received a capabilities response, but not negotiating anything.";
337 return;
338 }
339
340 if (!message.valid) {
341 HandleErrorMessage(
342 message,
343 "Bad CAPABILITIES_RESPONSE, assuming remoting is not supported");
344 return;
345 }
346
347 const ReceiverCapability& caps = absl::get<ReceiverCapability>(message.body);
348 int remoting_version = caps.remoting_version;
349 // If not set, we assume it is version 1.
350 if (remoting_version == ReceiverCapability::kRemotingVersionUnknown) {
351 remoting_version = 1;
352 }
353
354 if (remoting_version > kSupportedRemotingVersion) {
355 std::string message = StringPrintf(
356 "Receiver is using too new of a version for remoting (%d > %d)",
357 remoting_version, kSupportedRemotingVersion);
358 config_.client->OnError(
359 this, Error(Error::Code::kRemotingNotSupported, std::move(message)));
360 return;
361 }
362
363 ConfiguredSenders senders = SpawnSenders(current_negotiation_->answer);
364 // If we didn't select any senders, the negotiation was unsuccessful.
365 if (senders.audio_sender == nullptr && senders.video_sender == nullptr) {
366 config_.client->OnError(this,
367 Error(Error::Code::kNegotiationFailure,
368 "Failed to negotiate a remoting session."));
369 return;
370 }
371
372 config_.client->OnRemotingNegotiated(
373 this, RemotingNegotiation{std::move(senders), ToCapabilities(caps)});
374 }
375
OnRpcMessage(ReceiverMessage message)376 void SenderSession::OnRpcMessage(ReceiverMessage message) {
377 if (!message.valid) {
378 HandleErrorMessage(
379 message,
380 "Bad RPC message. This may or may not represent a serious problem");
381 return;
382 }
383
384 const auto& body = absl::get<std::vector<uint8_t>>(message.body);
385 rpc_messenger_.ProcessMessageFromRemote(body.data(), body.size());
386 }
387
HandleErrorMessage(ReceiverMessage message,const std::string & text)388 void SenderSession::HandleErrorMessage(ReceiverMessage message,
389 const std::string& text) {
390 OSP_DCHECK(!message.valid);
391 if (absl::holds_alternative<ReceiverError>(message.body)) {
392 const ReceiverError& error = absl::get<ReceiverError>(message.body);
393 std::string error_text =
394 StringPrintf("%s. Error code: %d, description: %s", text.c_str(),
395 error.code, error.description.c_str());
396 config_.client->OnError(
397 this, Error(Error::Code::kParameterInvalid, std::move(error_text)));
398 } else {
399 config_.client->OnError(this, Error(Error::Code::kJsonParseError, text));
400 }
401 }
402
CreateSender(Ssrc receiver_ssrc,const Stream & stream,RtpPayloadType type)403 std::unique_ptr<Sender> SenderSession::CreateSender(Ssrc receiver_ssrc,
404 const Stream& stream,
405 RtpPayloadType type) {
406 // Session config is currently only for mirroring.
407 SessionConfig config{stream.ssrc,
408 receiver_ssrc,
409 stream.rtp_timebase,
410 stream.channels,
411 stream.target_delay,
412 stream.aes_key,
413 stream.aes_iv_mask,
414 /* is_pli_enabled*/ true};
415
416 return std::make_unique<Sender>(config_.environment, &packet_router_,
417 std::move(config), type);
418 }
419
SpawnAudioSender(ConfiguredSenders * senders,Ssrc receiver_ssrc,int send_index,int config_index)420 void SenderSession::SpawnAudioSender(ConfiguredSenders* senders,
421 Ssrc receiver_ssrc,
422 int send_index,
423 int config_index) {
424 const AudioCaptureConfig& config =
425 current_negotiation_->audio_configs[config_index];
426 const RtpPayloadType payload_type =
427 GetPayloadType(config.codec, config_.use_android_rtp_hack);
428 for (const AudioStream& stream : current_negotiation_->offer.audio_streams) {
429 if (stream.stream.index == send_index) {
430 current_audio_sender_ =
431 CreateSender(receiver_ssrc, stream.stream, payload_type);
432 senders->audio_sender = current_audio_sender_.get();
433 senders->audio_config = config;
434 break;
435 }
436 }
437 }
438
SpawnVideoSender(ConfiguredSenders * senders,Ssrc receiver_ssrc,int send_index,int config_index)439 void SenderSession::SpawnVideoSender(ConfiguredSenders* senders,
440 Ssrc receiver_ssrc,
441 int send_index,
442 int config_index) {
443 const VideoCaptureConfig& config =
444 current_negotiation_->video_configs[config_index];
445 const RtpPayloadType payload_type =
446 GetPayloadType(config.codec, config_.use_android_rtp_hack);
447 for (const VideoStream& stream : current_negotiation_->offer.video_streams) {
448 if (stream.stream.index == send_index) {
449 current_video_sender_ =
450 CreateSender(receiver_ssrc, stream.stream, payload_type);
451 senders->video_sender = current_video_sender_.get();
452 senders->video_config = config;
453 break;
454 }
455 }
456 }
457
SpawnSenders(const Answer & answer)458 SenderSession::ConfiguredSenders SenderSession::SpawnSenders(
459 const Answer& answer) {
460 OSP_DCHECK(current_negotiation_);
461
462 // Although we already have a message port set up with the TLS
463 // address of the receiver, we don't know where to send the separate UDP
464 // stream until we get the ANSWER message here.
465 config_.environment->set_remote_endpoint(IPEndpoint{
466 config_.remote_address, static_cast<uint16_t>(answer.udp_port)});
467 OSP_LOG_INFO << "Streaming to " << config_.environment->remote_endpoint()
468 << "...";
469
470 ConfiguredSenders senders;
471 for (size_t i = 0; i < answer.send_indexes.size(); ++i) {
472 const Ssrc receiver_ssrc = answer.ssrcs[i];
473 const size_t send_index = static_cast<size_t>(answer.send_indexes[i]);
474
475 const auto audio_size = current_negotiation_->audio_configs.size();
476 const auto video_size = current_negotiation_->video_configs.size();
477 if (send_index < audio_size) {
478 SpawnAudioSender(&senders, receiver_ssrc, send_index, send_index);
479 } else if (send_index < (audio_size + video_size)) {
480 SpawnVideoSender(&senders, receiver_ssrc, send_index,
481 send_index - audio_size);
482 }
483 }
484 return senders;
485 }
486
SendRpcMessage(std::vector<uint8_t> message_body)487 void SenderSession::SendRpcMessage(std::vector<uint8_t> message_body) {
488 Error error = this->messenger_.SendOutboundMessage(SenderMessage{
489 SenderMessage::Type::kRpc, ++(this->current_sequence_number_), true,
490 std::move(message_body)});
491
492 if (!error.ok()) {
493 OSP_LOG_WARN << "Failed to send RPC message: " << error;
494 }
495 }
496
497 } // namespace cast
498 } // namespace openscreen
499