aboutsummaryrefslogtreecommitdiff
path: root/cast/streaming/receiver_session.cc
diff options
context:
space:
mode:
Diffstat (limited to 'cast/streaming/receiver_session.cc')
-rw-r--r--cast/streaming/receiver_session.cc175
1 files changed, 169 insertions, 6 deletions
diff --git a/cast/streaming/receiver_session.cc b/cast/streaming/receiver_session.cc
index 02c57e60..36a47bca 100644
--- a/cast/streaming/receiver_session.cc
+++ b/cast/streaming/receiver_session.cc
@@ -70,18 +70,104 @@ MediaCapability ToCapability(VideoCodec codec) {
}
}
+// Calculates whether any codecs present in |second| are not present in |first|.
+template <typename T>
+bool IsMissingCodecs(const std::vector<T>& first,
+ const std::vector<T>& second) {
+ if (second.size() > first.size()) {
+ return true;
+ }
+
+ for (auto codec : second) {
+ if (std::find(first.begin(), first.end(), codec) == first.end()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Calculates whether the limits defined by |first| are less restrictive than
+// those defined by |second|.
+// NOTE: These variables are intentionally passed by copy - the function will
+// mutate them.
+template <typename T>
+bool HasLessRestrictiveLimits(std::vector<T> first, std::vector<T> second) {
+ // Sort both vectors to allow for element-by-element comparison between the
+ // two. All elements with |applies_to_all_codecs| set are sorted to the front.
+ std::function<bool(const T&, const T&)> sorter = [](const T& first,
+ const T& second) {
+ if (first.applies_to_all_codecs != second.applies_to_all_codecs) {
+ return first.applies_to_all_codecs;
+ }
+ return static_cast<int>(first.codec) < static_cast<int>(second.codec);
+ };
+ std::sort(first.begin(), first.end(), sorter);
+ std::sort(second.begin(), second.end(), sorter);
+ auto first_it = first.begin();
+ auto second_it = second.begin();
+
+ // |applies_to_all_codecs| is a special case, so handle that first.
+ T fake_applies_to_all_codecs_struct;
+ fake_applies_to_all_codecs_struct.applies_to_all_codecs = true;
+ T* first_applies_to_all_codecs_struct =
+ !first.empty() && first.front().applies_to_all_codecs
+ ? &(*first_it++)
+ : &fake_applies_to_all_codecs_struct;
+ T* second_applies_to_all_codecs_struct =
+ !second.empty() && second.front().applies_to_all_codecs
+ ? &(*second_it++)
+ : &fake_applies_to_all_codecs_struct;
+ if (!first_applies_to_all_codecs_struct->IsSupersetOf(
+ *second_applies_to_all_codecs_struct)) {
+ return false;
+ }
+
+ // Now all elements of the vectors can be assumed to NOT have
+ // |applies_to_all_codecs| set. So iterate through all codecs set in either
+ // vector and check that the first has the less restrictive configuration set.
+ while (first_it != first.end() || second_it != second.end()) {
+ // Calculate the current codec to process, and whether each vector contains
+ // an instance of this codec.
+ decltype(T::codec) current_codec;
+ bool use_first_fake = false;
+ bool use_second_fake = false;
+ if (first_it == first.end()) {
+ current_codec = second_it->codec;
+ use_first_fake = true;
+ } else if (second_it == second.end()) {
+ current_codec = first_it->codec;
+ use_second_fake = true;
+ } else {
+ current_codec = std::min(first_it->codec, second_it->codec);
+ use_first_fake = first_it->codec != current_codec;
+ use_second_fake = second_it->codec != current_codec;
+ }
+
+ // Compare each vector's limit associated with this codec, or compare
+ // against the default limits if no such codec limits are set.
+ T fake_codecs_struct;
+ fake_codecs_struct.codec = current_codec;
+ T* first_codec_struct =
+ use_first_fake ? &fake_codecs_struct : &(*first_it++);
+ T* second_codec_struct =
+ use_second_fake ? &fake_codecs_struct : &(*second_it++);
+ OSP_DCHECK(!first_codec_struct->applies_to_all_codecs);
+ OSP_DCHECK(!second_codec_struct->applies_to_all_codecs);
+ if (!first_codec_struct->IsSupersetOf(*second_codec_struct)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // namespace
ReceiverSession::Client::~Client() = default;
using RemotingPreferences = ReceiverSession::RemotingPreferences;
-RemotingPreferences::RemotingPreferences() = default;
-RemotingPreferences::RemotingPreferences(RemotingPreferences&&) noexcept =
- default;
-RemotingPreferences& RemotingPreferences::operator=(
- RemotingPreferences&&) noexcept = default;
-
using Preferences = ReceiverSession::Preferences;
Preferences::Preferences() = default;
@@ -104,6 +190,24 @@ Preferences::Preferences(std::vector<VideoCodec> video_codecs,
Preferences::Preferences(Preferences&&) noexcept = default;
Preferences& Preferences::operator=(Preferences&&) noexcept = default;
+Preferences::Preferences(const Preferences& other) {
+ *this = other;
+}
+
+Preferences& Preferences::operator=(const Preferences& other) {
+ video_codecs = other.video_codecs;
+ audio_codecs = other.audio_codecs;
+ audio_limits = other.audio_limits;
+ video_limits = other.video_limits;
+ if (other.display_description) {
+ display_description = std::make_unique<Display>(*other.display_description);
+ }
+ if (other.remoting) {
+ remoting = std::make_unique<RemotingPreferences>(*other.remoting);
+ }
+ return *this;
+}
+
ReceiverSession::ReceiverSession(Client* const client,
Environment* environment,
MessagePort* message_port,
@@ -458,5 +562,64 @@ void ReceiverSession::SendErrorAnswerReply(int sequence_number,
}
}
+bool ReceiverSession::VideoLimits::IsSupersetOf(
+ const ReceiverSession::VideoLimits& second) const {
+ return (applies_to_all_codecs == second.applies_to_all_codecs) &&
+ (applies_to_all_codecs || codec == second.codec) &&
+ (max_pixels_per_second >= second.max_pixels_per_second) &&
+ (min_bit_rate <= second.min_bit_rate) &&
+ (max_bit_rate >= second.max_bit_rate) &&
+ (max_delay >= second.max_delay) &&
+ (max_dimensions.IsSupersetOf(second.max_dimensions));
+}
+
+bool ReceiverSession::AudioLimits::IsSupersetOf(
+ const ReceiverSession::AudioLimits& second) const {
+ return (applies_to_all_codecs == second.applies_to_all_codecs) &&
+ (applies_to_all_codecs || codec == second.codec) &&
+ (max_sample_rate >= second.max_sample_rate) &&
+ (max_channels >= second.max_channels) &&
+ (min_bit_rate <= second.min_bit_rate) &&
+ (max_bit_rate >= second.max_bit_rate) &&
+ (max_delay >= second.max_delay);
+}
+
+bool ReceiverSession::Display::IsSupersetOf(
+ const ReceiverSession::Display& other) const {
+ return dimensions.IsSupersetOf(other.dimensions) &&
+ (can_scale_content || !other.can_scale_content);
+}
+
+bool ReceiverSession::RemotingPreferences::IsSupersetOf(
+ const ReceiverSession::RemotingPreferences& other) const {
+ return (supports_chrome_audio_codecs ||
+ !other.supports_chrome_audio_codecs) &&
+ (supports_4k || !other.supports_4k);
+}
+
+bool ReceiverSession::Preferences::IsSupersetOf(
+ const ReceiverSession::Preferences& other) const {
+ // Check simple cases first.
+ if ((!!display_description != !!other.display_description) ||
+ (display_description &&
+ !display_description->IsSupersetOf(*other.display_description))) {
+ return false;
+ } else if (other.remoting &&
+ (!remoting || !remoting->IsSupersetOf(*other.remoting))) {
+ return false;
+ }
+
+ // Then check set codecs.
+ if (IsMissingCodecs(video_codecs, other.video_codecs) ||
+ IsMissingCodecs(audio_codecs, other.audio_codecs)) {
+ return false;
+ }
+
+ // Then check limits. Do this last because it's the most resource intensive to
+ // check.
+ return HasLessRestrictiveLimits(video_limits, other.video_limits) &&
+ HasLessRestrictiveLimits(audio_limits, other.audio_limits);
+}
+
} // namespace cast
} // namespace openscreen