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