xref: /aosp_15_r20/external/openscreen/cast/streaming/receiver_session.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1 // Copyright 2019 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/receiver_session.h"
6 
7 #include <algorithm>
8 #include <chrono>
9 #include <string>
10 #include <utility>
11 
12 #include "absl/strings/match.h"
13 #include "absl/strings/numbers.h"
14 #include "cast/common/channel/message_util.h"
15 #include "cast/common/public/message_port.h"
16 #include "cast/streaming/answer_messages.h"
17 #include "cast/streaming/environment.h"
18 #include "cast/streaming/message_fields.h"
19 #include "cast/streaming/offer_messages.h"
20 #include "cast/streaming/receiver.h"
21 #include "cast/streaming/sender_message.h"
22 #include "util/json/json_helpers.h"
23 #include "util/osp_logging.h"
24 
25 namespace openscreen {
26 namespace cast {
27 namespace {
28 
29 template <typename Stream, typename Codec>
SelectStream(const std::vector<Codec> & preferred_codecs,ReceiverSession::Client * client,const std::vector<Stream> & offered_streams)30 std::unique_ptr<Stream> SelectStream(
31     const std::vector<Codec>& preferred_codecs,
32     ReceiverSession::Client* client,
33     const std::vector<Stream>& offered_streams) {
34   for (auto codec : preferred_codecs) {
35     for (const Stream& offered_stream : offered_streams) {
36       if (offered_stream.codec == codec &&
37           (offered_stream.stream.codec_parameter.empty() ||
38            client->SupportsCodecParameter(
39                offered_stream.stream.codec_parameter))) {
40         OSP_VLOG << "Selected " << CodecToString(codec)
41                  << " as codec for streaming";
42         return std::make_unique<Stream>(offered_stream);
43       }
44     }
45   }
46   return nullptr;
47 }
48 
ToCapability(AudioCodec codec)49 MediaCapability ToCapability(AudioCodec codec) {
50   switch (codec) {
51     case AudioCodec::kAac:
52       return MediaCapability::kAac;
53     case AudioCodec::kOpus:
54       return MediaCapability::kOpus;
55     default:
56       OSP_DLOG_FATAL << "Invalid audio codec: " << static_cast<int>(codec);
57       OSP_NOTREACHED();
58   }
59 }
60 
ToCapability(VideoCodec codec)61 MediaCapability ToCapability(VideoCodec codec) {
62   switch (codec) {
63     case VideoCodec::kVp8:
64       return MediaCapability::kVp8;
65     case VideoCodec::kVp9:
66       return MediaCapability::kVp9;
67     case VideoCodec::kH264:
68       return MediaCapability::kH264;
69     case VideoCodec::kHevc:
70       return MediaCapability::kHevc;
71     case VideoCodec::kAv1:
72       return MediaCapability::kAv1;
73     default:
74       OSP_DLOG_FATAL << "Invalid video codec: " << static_cast<int>(codec);
75       OSP_NOTREACHED();
76   }
77 }
78 
79 // Calculates whether any codecs present in |second| are not present in |first|.
80 template <typename T>
IsMissingCodecs(const std::vector<T> & first,const std::vector<T> & second)81 bool IsMissingCodecs(const std::vector<T>& first,
82                      const std::vector<T>& second) {
83   if (second.size() > first.size()) {
84     return true;
85   }
86 
87   for (auto codec : second) {
88     if (std::find(first.begin(), first.end(), codec) == first.end()) {
89       return true;
90     }
91   }
92 
93   return false;
94 }
95 
96 // Calculates whether the limits defined by |first| are less restrictive than
97 // those defined by |second|.
98 // NOTE: These variables are intentionally passed by copy - the function will
99 // mutate them.
100 template <typename T>
HasLessRestrictiveLimits(std::vector<T> first,std::vector<T> second)101 bool HasLessRestrictiveLimits(std::vector<T> first, std::vector<T> second) {
102   // Sort both vectors to allow for element-by-element comparison between the
103   // two. All elements with |applies_to_all_codecs| set are sorted to the front.
104   std::function<bool(const T&, const T&)> sorter = [](const T& first,
105                                                       const T& second) {
106     if (first.applies_to_all_codecs != second.applies_to_all_codecs) {
107       return first.applies_to_all_codecs;
108     }
109     return static_cast<int>(first.codec) < static_cast<int>(second.codec);
110   };
111   std::sort(first.begin(), first.end(), sorter);
112   std::sort(second.begin(), second.end(), sorter);
113   auto first_it = first.begin();
114   auto second_it = second.begin();
115 
116   // |applies_to_all_codecs| is a special case, so handle that first.
117   T fake_applies_to_all_codecs_struct;
118   fake_applies_to_all_codecs_struct.applies_to_all_codecs = true;
119   T* first_applies_to_all_codecs_struct =
120       !first.empty() && first.front().applies_to_all_codecs
121           ? &(*first_it++)
122           : &fake_applies_to_all_codecs_struct;
123   T* second_applies_to_all_codecs_struct =
124       !second.empty() && second.front().applies_to_all_codecs
125           ? &(*second_it++)
126           : &fake_applies_to_all_codecs_struct;
127   if (!first_applies_to_all_codecs_struct->IsSupersetOf(
128           *second_applies_to_all_codecs_struct)) {
129     return false;
130   }
131 
132   // Now all elements of the vectors can be assumed to NOT have
133   // |applies_to_all_codecs| set. So iterate through all codecs set in either
134   // vector and check that the first has the less restrictive configuration set.
135   while (first_it != first.end() || second_it != second.end()) {
136     // Calculate the current codec to process, and whether each vector contains
137     // an instance of this codec.
138     decltype(T::codec) current_codec;
139     bool use_first_fake = false;
140     bool use_second_fake = false;
141     if (first_it == first.end()) {
142       current_codec = second_it->codec;
143       use_first_fake = true;
144     } else if (second_it == second.end()) {
145       current_codec = first_it->codec;
146       use_second_fake = true;
147     } else {
148       current_codec = std::min(first_it->codec, second_it->codec);
149       use_first_fake = first_it->codec != current_codec;
150       use_second_fake = second_it->codec != current_codec;
151     }
152 
153     // Compare each vector's limit associated with this codec, or compare
154     // against the default limits if no such codec limits are set.
155     T fake_codecs_struct;
156     fake_codecs_struct.codec = current_codec;
157     T* first_codec_struct =
158         use_first_fake ? &fake_codecs_struct : &(*first_it++);
159     T* second_codec_struct =
160         use_second_fake ? &fake_codecs_struct : &(*second_it++);
161     OSP_DCHECK(!first_codec_struct->applies_to_all_codecs);
162     OSP_DCHECK(!second_codec_struct->applies_to_all_codecs);
163     if (!first_codec_struct->IsSupersetOf(*second_codec_struct)) {
164       return false;
165     }
166   }
167 
168   return true;
169 }
170 
171 }  // namespace
172 
173 ReceiverSession::Client::~Client() = default;
174 
175 using RemotingPreferences = ReceiverSession::RemotingPreferences;
176 
177 using Preferences = ReceiverSession::Preferences;
178 
179 Preferences::Preferences() = default;
Preferences(std::vector<VideoCodec> video_codecs,std::vector<AudioCodec> audio_codecs)180 Preferences::Preferences(std::vector<VideoCodec> video_codecs,
181                          std::vector<AudioCodec> audio_codecs)
182     : video_codecs(std::move(video_codecs)),
183       audio_codecs(std::move(audio_codecs)) {}
184 
Preferences(std::vector<VideoCodec> video_codecs,std::vector<AudioCodec> audio_codecs,std::vector<AudioLimits> audio_limits,std::vector<VideoLimits> video_limits,std::unique_ptr<Display> description)185 Preferences::Preferences(std::vector<VideoCodec> video_codecs,
186                          std::vector<AudioCodec> audio_codecs,
187                          std::vector<AudioLimits> audio_limits,
188                          std::vector<VideoLimits> video_limits,
189                          std::unique_ptr<Display> description)
190     : video_codecs(std::move(video_codecs)),
191       audio_codecs(std::move(audio_codecs)),
192       audio_limits(std::move(audio_limits)),
193       video_limits(std::move(video_limits)),
194       display_description(std::move(description)) {}
195 
196 Preferences::Preferences(Preferences&&) noexcept = default;
197 Preferences& Preferences::operator=(Preferences&&) noexcept = default;
198 
Preferences(const Preferences & other)199 Preferences::Preferences(const Preferences& other) {
200   *this = other;
201 }
202 
operator =(const Preferences & other)203 Preferences& Preferences::operator=(const Preferences& other) {
204   video_codecs = other.video_codecs;
205   audio_codecs = other.audio_codecs;
206   audio_limits = other.audio_limits;
207   video_limits = other.video_limits;
208   if (other.display_description) {
209     display_description = std::make_unique<Display>(*other.display_description);
210   }
211   if (other.remoting) {
212     remoting = std::make_unique<RemotingPreferences>(*other.remoting);
213   }
214   return *this;
215 }
216 
ReceiverSession(Client * const client,Environment * environment,MessagePort * message_port,Preferences preferences)217 ReceiverSession::ReceiverSession(Client* const client,
218                                  Environment* environment,
219                                  MessagePort* message_port,
220                                  Preferences preferences)
221     : client_(client),
222       environment_(environment),
223       preferences_(std::move(preferences)),
224       session_id_(MakeUniqueSessionId("streaming_receiver")),
225       messenger_(message_port,
226                  session_id_,
227                  [this](Error error) {
228                    OSP_DLOG_WARN << "Got a session messenger error: " << error;
229                    client_->OnError(this, error);
230                  }),
231       packet_router_(environment_) {
232   OSP_DCHECK(client_);
233   OSP_DCHECK(environment_);
234 
235   OSP_DCHECK(!std::any_of(
236       preferences_.video_codecs.begin(), preferences_.video_codecs.end(),
__anona65f6d470402(VideoCodec c) 237       [](VideoCodec c) { return c == VideoCodec::kNotSpecified; }));
238   OSP_DCHECK(!std::any_of(
239       preferences_.audio_codecs.begin(), preferences_.audio_codecs.end(),
__anona65f6d470502(AudioCodec c) 240       [](AudioCodec c) { return c == AudioCodec::kNotSpecified; }));
241 
242   messenger_.SetHandler(
243       SenderMessage::Type::kOffer,
__anona65f6d470602(SenderMessage message) 244       [this](SenderMessage message) { OnOffer(std::move(message)); });
245   messenger_.SetHandler(SenderMessage::Type::kGetCapabilities,
__anona65f6d470702(SenderMessage message) 246                         [this](SenderMessage message) {
247                           OnCapabilitiesRequest(std::move(message));
248                         });
249   messenger_.SetHandler(SenderMessage::Type::kRpc,
__anona65f6d470802(SenderMessage message) 250                         [this](SenderMessage message) {
251                           this->OnRpcMessage(std::move(message));
252                         });
253   environment_->SetSocketSubscriber(this);
254 }
255 
~ReceiverSession()256 ReceiverSession::~ReceiverSession() {
257   ResetReceivers(Client::kEndOfSession);
258 }
259 
OnSocketReady()260 void ReceiverSession::OnSocketReady() {
261   if (pending_session_) {
262     InitializeSession(*pending_session_);
263     pending_session_.reset();
264   }
265 }
266 
OnSocketInvalid(Error error)267 void ReceiverSession::OnSocketInvalid(Error error) {
268   if (pending_session_) {
269     SendErrorAnswerReply(pending_session_->sequence_number,
270                          "Failed to bind UDP socket");
271     pending_session_.reset();
272   }
273 
274   client_->OnError(this,
275                    Error(Error::Code::kSocketFailure,
276                          "The environment is invalid and should be replaced."));
277 }
278 
IsValid() const279 bool ReceiverSession::SessionProperties::IsValid() const {
280   return (selected_audio || selected_video) && sequence_number >= 0;
281 }
282 
OnOffer(SenderMessage message)283 void ReceiverSession::OnOffer(SenderMessage message) {
284   // We just drop offers we can't respond to. Note that libcast senders will
285   // always send a strictly positive sequence numbers, but zero is permitted
286   // by the spec.
287   if (message.sequence_number < 0) {
288     OSP_DLOG_WARN
289         << "Dropping offer with missing sequence number, can't respond";
290     return;
291   }
292 
293   if (!message.valid) {
294     SendErrorAnswerReply(message.sequence_number,
295                          "Failed to parse malformed OFFER");
296     client_->OnError(this, Error(Error::Code::kParameterInvalid,
297                                  "Received invalid OFFER message"));
298     return;
299   }
300 
301   auto properties = std::make_unique<SessionProperties>();
302   properties->sequence_number = message.sequence_number;
303 
304   const Offer& offer = absl::get<Offer>(message.body);
305   if (offer.cast_mode == CastMode::kRemoting) {
306     if (!preferences_.remoting) {
307       SendErrorAnswerReply(message.sequence_number,
308                            "This receiver does not have remoting enabled.");
309       return;
310     }
311   }
312 
313   properties->mode = offer.cast_mode;
314   SelectStreams(offer, properties.get());
315   if (!properties->IsValid()) {
316     SendErrorAnswerReply(message.sequence_number,
317                          "Failed to select any streams from OFFER");
318     return;
319   }
320 
321   switch (environment_->socket_state()) {
322     // If the environment is ready or in a bad state, we can respond
323     // immediately.
324     case Environment::SocketState::kInvalid:
325       SendErrorAnswerReply(message.sequence_number,
326                            "UDP socket is closed, likely due to a bind error.");
327       break;
328 
329     case Environment::SocketState::kReady:
330       InitializeSession(*properties);
331       break;
332 
333     // Else we need to store the properties we just created until we get a
334     // ready or error event.
335     case Environment::SocketState::kStarting:
336       pending_session_ = std::move(properties);
337       break;
338   }
339 }
340 
OnCapabilitiesRequest(SenderMessage message)341 void ReceiverSession::OnCapabilitiesRequest(SenderMessage message) {
342   if (message.sequence_number < 0) {
343     OSP_DLOG_WARN
344         << "Dropping offer with missing sequence number, can't respond";
345     return;
346   }
347 
348   ReceiverMessage response{
349       ReceiverMessage::Type::kCapabilitiesResponse, message.sequence_number,
350       true /* valid */
351   };
352   if (preferences_.remoting) {
353     response.body = CreateRemotingCapabilityV2();
354   } else {
355     response.valid = false;
356     response.body =
357         ReceiverError{static_cast<int>(Error::Code::kRemotingNotSupported),
358                       "Remoting is not supported"};
359   }
360 
361   const Error result = messenger_.SendMessage(std::move(response));
362   if (!result.ok()) {
363     client_->OnError(this, std::move(result));
364   }
365 }
366 
OnRpcMessage(SenderMessage message)367 void ReceiverSession::OnRpcMessage(SenderMessage message) {
368   if (!message.valid) {
369     OSP_DLOG_WARN
370         << "Bad RPC message. This may or may not represent a serious problem.";
371     return;
372   }
373 
374   const auto& body = absl::get<std::vector<uint8_t>>(message.body);
375   if (!rpc_messenger_) {
376     OSP_DLOG_INFO << "Received an RPC message without having a messenger.";
377     return;
378   }
379   rpc_messenger_->ProcessMessageFromRemote(body.data(), body.size());
380 }
381 
SelectStreams(const Offer & offer,SessionProperties * properties)382 void ReceiverSession::SelectStreams(const Offer& offer,
383                                     SessionProperties* properties) {
384   if (offer.cast_mode == CastMode::kMirroring) {
385     if (!offer.audio_streams.empty() && !preferences_.audio_codecs.empty()) {
386       properties->selected_audio =
387           SelectStream(preferences_.audio_codecs, client_, offer.audio_streams);
388     }
389     if (!offer.video_streams.empty() && !preferences_.video_codecs.empty()) {
390       properties->selected_video =
391           SelectStream(preferences_.video_codecs, client_, offer.video_streams);
392     }
393   } else {
394     OSP_DCHECK(offer.cast_mode == CastMode::kRemoting);
395 
396     if (offer.audio_streams.size() == 1) {
397       properties->selected_audio =
398           std::make_unique<AudioStream>(offer.audio_streams[0]);
399     }
400     if (offer.video_streams.size() == 1) {
401       properties->selected_video =
402           std::make_unique<VideoStream>(offer.video_streams[0]);
403     }
404   }
405 }
406 
InitializeSession(const SessionProperties & properties)407 void ReceiverSession::InitializeSession(const SessionProperties& properties) {
408   Answer answer = ConstructAnswer(properties);
409   if (!answer.IsValid()) {
410     // If the answer message is invalid, there is no point in setting up a
411     // negotiation because the sender won't be able to connect to it.
412     SendErrorAnswerReply(properties.sequence_number,
413                          "Failed to construct an ANSWER message");
414     return;
415   }
416 
417   // Only spawn receivers if we know we have a valid answer message.
418   ConfiguredReceivers receivers = SpawnReceivers(properties);
419   if (properties.mode == CastMode::kMirroring) {
420     client_->OnNegotiated(this, std::move(receivers));
421   } else {
422     // TODO(jophba): cleanup sequence number usage.
423     rpc_messenger_ = std::make_unique<RpcMessenger>([this](std::vector<uint8_t> message) {
424       Error error = this->messenger_.SendMessage(
425           ReceiverMessage{ReceiverMessage::Type::kRpc, -1, true /* valid */,
426                           std::move(message)});
427 
428       if (!error.ok()) {
429         OSP_LOG_WARN << "Failed to send RPC message: " << error;
430       }
431     });
432     client_->OnRemotingNegotiated(
433         this, RemotingNegotiation{std::move(receivers), rpc_messenger_.get()});
434   }
435   const Error result = messenger_.SendMessage(ReceiverMessage{
436       ReceiverMessage::Type::kAnswer, properties.sequence_number,
437       true /* valid */, std::move(answer)});
438   if (!result.ok()) {
439     client_->OnError(this, std::move(result));
440   }
441 }
442 
ConstructReceiver(const Stream & stream)443 std::unique_ptr<Receiver> ReceiverSession::ConstructReceiver(
444     const Stream& stream) {
445   // Session config is currently only for mirroring.
446   SessionConfig config = {stream.ssrc,         stream.ssrc + 1,
447                           stream.rtp_timebase, stream.channels,
448                           stream.target_delay, stream.aes_key,
449                           stream.aes_iv_mask,  /* is_pli_enabled */ true};
450   return std::make_unique<Receiver>(environment_, &packet_router_,
451                                     std::move(config));
452 }
453 
SpawnReceivers(const SessionProperties & properties)454 ReceiverSession::ConfiguredReceivers ReceiverSession::SpawnReceivers(
455     const SessionProperties& properties) {
456   OSP_DCHECK(properties.IsValid());
457   ResetReceivers(Client::kRenegotiated);
458 
459   AudioCaptureConfig audio_config;
460   if (properties.selected_audio) {
461     current_audio_receiver_ =
462         ConstructReceiver(properties.selected_audio->stream);
463     audio_config =
464         AudioCaptureConfig{properties.selected_audio->codec,
465                            properties.selected_audio->stream.channels,
466                            properties.selected_audio->bit_rate,
467                            properties.selected_audio->stream.rtp_timebase,
468                            properties.selected_audio->stream.target_delay,
469                            properties.selected_audio->stream.codec_parameter};
470   }
471 
472   VideoCaptureConfig video_config;
473   if (properties.selected_video) {
474     current_video_receiver_ =
475         ConstructReceiver(properties.selected_video->stream);
476     video_config =
477         VideoCaptureConfig{properties.selected_video->codec,
478                            properties.selected_video->max_frame_rate,
479                            properties.selected_video->max_bit_rate,
480                            properties.selected_video->resolutions,
481                            properties.selected_video->stream.target_delay,
482                            properties.selected_video->stream.codec_parameter};
483   }
484 
485   return ConfiguredReceivers{
486       current_audio_receiver_.get(), std::move(audio_config),
487       current_video_receiver_.get(), std::move(video_config)};
488 }
489 
ResetReceivers(Client::ReceiversDestroyingReason reason)490 void ReceiverSession::ResetReceivers(Client::ReceiversDestroyingReason reason) {
491   if (current_video_receiver_ || current_audio_receiver_) {
492     client_->OnReceiversDestroying(this, reason);
493     current_audio_receiver_.reset();
494     current_video_receiver_.reset();
495     rpc_messenger_.reset();
496   }
497 }
498 
ConstructAnswer(const SessionProperties & properties)499 Answer ReceiverSession::ConstructAnswer(const SessionProperties& properties) {
500   OSP_DCHECK(properties.IsValid());
501 
502   std::vector<int> stream_indexes;
503   std::vector<Ssrc> stream_ssrcs;
504   Constraints constraints;
505   if (properties.selected_audio) {
506     stream_indexes.push_back(properties.selected_audio->stream.index);
507     stream_ssrcs.push_back(properties.selected_audio->stream.ssrc + 1);
508 
509     for (const auto& limit : preferences_.audio_limits) {
510       if (limit.codec == properties.selected_audio->codec ||
511           limit.applies_to_all_codecs) {
512         constraints.audio = AudioConstraints{
513             limit.max_sample_rate, limit.max_channels, limit.min_bit_rate,
514             limit.max_bit_rate,    limit.max_delay,
515         };
516         break;
517       }
518     }
519   }
520 
521   if (properties.selected_video) {
522     stream_indexes.push_back(properties.selected_video->stream.index);
523     stream_ssrcs.push_back(properties.selected_video->stream.ssrc + 1);
524 
525     for (const auto& limit : preferences_.video_limits) {
526       if (limit.codec == properties.selected_video->codec ||
527           limit.applies_to_all_codecs) {
528         constraints.video = VideoConstraints{
529             limit.max_pixels_per_second, absl::nullopt, /* min dimensions */
530             limit.max_dimensions,        limit.min_bit_rate,
531             limit.max_bit_rate,          limit.max_delay,
532         };
533         break;
534       }
535     }
536   }
537 
538   absl::optional<DisplayDescription> display;
539   if (preferences_.display_description) {
540     const auto* d = preferences_.display_description.get();
541     display = DisplayDescription{d->dimensions, absl::nullopt,
542                                  d->can_scale_content
543                                      ? AspectRatioConstraint::kVariable
544                                      : AspectRatioConstraint::kFixed};
545   }
546 
547   // Only set the constraints in the answer if they are valid (meaning we
548   // successfully found limits above).
549   absl::optional<Constraints> answer_constraints;
550   if (constraints.IsValid()) {
551     answer_constraints = std::move(constraints);
552   }
553   return Answer{environment_->GetBoundLocalEndpoint().port,
554                 std::move(stream_indexes), std::move(stream_ssrcs),
555                 answer_constraints, std::move(display)};
556 }
557 
CreateRemotingCapabilityV2()558 ReceiverCapability ReceiverSession::CreateRemotingCapabilityV2() {
559   // If we don't support remoting, there is no reason to respond to
560   // capability requests--they are not used for mirroring.
561   OSP_DCHECK(preferences_.remoting);
562   ReceiverCapability capability;
563   capability.remoting_version = kSupportedRemotingVersion;
564 
565   for (const AudioCodec& codec : preferences_.audio_codecs) {
566     capability.media_capabilities.push_back(ToCapability(codec));
567   }
568   for (const VideoCodec& codec : preferences_.video_codecs) {
569     capability.media_capabilities.push_back(ToCapability(codec));
570   }
571 
572   if (preferences_.remoting->supports_chrome_audio_codecs) {
573     capability.media_capabilities.push_back(MediaCapability::kAudio);
574   }
575   if (preferences_.remoting->supports_4k) {
576     capability.media_capabilities.push_back(MediaCapability::k4k);
577   }
578   return capability;
579 }
580 
SendErrorAnswerReply(int sequence_number,const char * message)581 void ReceiverSession::SendErrorAnswerReply(int sequence_number,
582                                            const char* message) {
583   const Error error(Error::Code::kParseError, message);
584   OSP_DLOG_WARN << message;
585   const Error result = messenger_.SendMessage(ReceiverMessage{
586       ReceiverMessage::Type::kAnswer, sequence_number, false /* valid */,
587       ReceiverError{static_cast<int>(Error::Code::kParseError), message}});
588   if (!result.ok()) {
589     client_->OnError(this, std::move(result));
590   }
591 }
592 
IsSupersetOf(const ReceiverSession::VideoLimits & second) const593 bool ReceiverSession::VideoLimits::IsSupersetOf(
594     const ReceiverSession::VideoLimits& second) const {
595   return (applies_to_all_codecs == second.applies_to_all_codecs) &&
596          (applies_to_all_codecs || codec == second.codec) &&
597          (max_pixels_per_second >= second.max_pixels_per_second) &&
598          (min_bit_rate <= second.min_bit_rate) &&
599          (max_bit_rate >= second.max_bit_rate) &&
600          (max_delay >= second.max_delay) &&
601          (max_dimensions.IsSupersetOf(second.max_dimensions));
602 }
603 
IsSupersetOf(const ReceiverSession::AudioLimits & second) const604 bool ReceiverSession::AudioLimits::IsSupersetOf(
605     const ReceiverSession::AudioLimits& second) const {
606   return (applies_to_all_codecs == second.applies_to_all_codecs) &&
607          (applies_to_all_codecs || codec == second.codec) &&
608          (max_sample_rate >= second.max_sample_rate) &&
609          (max_channels >= second.max_channels) &&
610          (min_bit_rate <= second.min_bit_rate) &&
611          (max_bit_rate >= second.max_bit_rate) &&
612          (max_delay >= second.max_delay);
613 }
614 
IsSupersetOf(const ReceiverSession::Display & other) const615 bool ReceiverSession::Display::IsSupersetOf(
616     const ReceiverSession::Display& other) const {
617   return dimensions.IsSupersetOf(other.dimensions) &&
618          (can_scale_content || !other.can_scale_content);
619 }
620 
IsSupersetOf(const ReceiverSession::RemotingPreferences & other) const621 bool ReceiverSession::RemotingPreferences::IsSupersetOf(
622     const ReceiverSession::RemotingPreferences& other) const {
623   return (supports_chrome_audio_codecs ||
624           !other.supports_chrome_audio_codecs) &&
625          (supports_4k || !other.supports_4k);
626 }
627 
IsSupersetOf(const ReceiverSession::Preferences & other) const628 bool ReceiverSession::Preferences::IsSupersetOf(
629     const ReceiverSession::Preferences& other) const {
630   // Check simple cases first.
631   if ((!!display_description != !!other.display_description) ||
632       (display_description &&
633        !display_description->IsSupersetOf(*other.display_description))) {
634     return false;
635   } else if (other.remoting &&
636              (!remoting || !remoting->IsSupersetOf(*other.remoting))) {
637     return false;
638   }
639 
640   // Then check set codecs.
641   if (IsMissingCodecs(video_codecs, other.video_codecs) ||
642       IsMissingCodecs(audio_codecs, other.audio_codecs)) {
643     return false;
644   }
645 
646   // Then check limits. Do this last because it's the most resource intensive to
647   // check.
648   return HasLessRestrictiveLimits(video_limits, other.video_limits) &&
649          HasLessRestrictiveLimits(audio_limits, other.audio_limits);
650 }
651 
652 }  // namespace cast
653 }  // namespace openscreen
654