xref: /aosp_15_r20/external/openscreen/cast/streaming/sender_session.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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