xref: /aosp_15_r20/external/openscreen/cast/sender/cast_app_availability_tracker.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/sender/cast_app_availability_tracker.h"
6 
7 #include "util/osp_logging.h"
8 
9 namespace openscreen {
10 namespace cast {
11 
12 CastAppAvailabilityTracker::CastAppAvailabilityTracker() = default;
13 CastAppAvailabilityTracker::~CastAppAvailabilityTracker() = default;
14 
RegisterSource(const CastMediaSource & source)15 std::vector<std::string> CastAppAvailabilityTracker::RegisterSource(
16     const CastMediaSource& source) {
17   if (registered_sources_.find(source.source_id()) !=
18       registered_sources_.end()) {
19     return {};
20   }
21 
22   registered_sources_.emplace(source.source_id(), source);
23 
24   std::vector<std::string> new_app_ids;
25   for (const std::string& app_id : source.app_ids()) {
26     if (++registration_count_by_app_id_[app_id] == 1) {
27       new_app_ids.push_back(app_id);
28     }
29   }
30   return new_app_ids;
31 }
32 
UnregisterSource(const CastMediaSource & source)33 void CastAppAvailabilityTracker::UnregisterSource(
34     const CastMediaSource& source) {
35   UnregisterSource(source.source_id());
36 }
37 
UnregisterSource(const std::string & source_id)38 void CastAppAvailabilityTracker::UnregisterSource(
39     const std::string& source_id) {
40   auto it = registered_sources_.find(source_id);
41   if (it == registered_sources_.end()) {
42     return;
43   }
44 
45   for (const std::string& app_id : it->second.app_ids()) {
46     auto count_it = registration_count_by_app_id_.find(app_id);
47     OSP_DCHECK(count_it != registration_count_by_app_id_.end());
48     if (--(count_it->second) == 0) {
49       registration_count_by_app_id_.erase(count_it);
50     }
51   }
52 
53   registered_sources_.erase(it);
54 }
55 
UpdateAppAvailability(const std::string & receiver_id,const std::string & app_id,AppAvailability availability)56 std::vector<CastMediaSource> CastAppAvailabilityTracker::UpdateAppAvailability(
57     const std::string& receiver_id,
58     const std::string& app_id,
59     AppAvailability availability) {
60   auto& availabilities = app_availabilities_[receiver_id];
61   auto it = availabilities.find(app_id);
62 
63   AppAvailabilityResult old_availability = it == availabilities.end()
64                                                ? AppAvailabilityResult::kUnknown
65                                                : it->second.availability;
66   AppAvailabilityResult new_availability = availability.availability;
67 
68   // Updated if status changes from/to kAvailable.
69   bool updated = (old_availability == AppAvailabilityResult::kAvailable ||
70                   new_availability == AppAvailabilityResult::kAvailable) &&
71                  old_availability != new_availability;
72   availabilities[app_id] = availability;
73 
74   if (!updated) {
75     return {};
76   }
77 
78   std::vector<CastMediaSource> affected_sources;
79   for (const auto& source : registered_sources_) {
80     if (source.second.ContainsAppId(app_id)) {
81       affected_sources.push_back(source.second);
82     }
83   }
84   return affected_sources;
85 }
86 
87 std::vector<CastMediaSource>
RemoveResultsForReceiver(const std::string & receiver_id)88 CastAppAvailabilityTracker::RemoveResultsForReceiver(
89     const std::string& receiver_id) {
90   auto affected_sources = GetSupportedSources(receiver_id);
91   app_availabilities_.erase(receiver_id);
92   return affected_sources;
93 }
94 
GetSupportedSources(const std::string & receiver_id) const95 std::vector<CastMediaSource> CastAppAvailabilityTracker::GetSupportedSources(
96     const std::string& receiver_id) const {
97   auto it = app_availabilities_.find(receiver_id);
98   if (it == app_availabilities_.end()) {
99     return std::vector<CastMediaSource>();
100   }
101 
102   // Find all app IDs that are available on the receiver.
103   std::vector<std::string> supported_app_ids;
104   for (const auto& availability : it->second) {
105     if (availability.second.availability == AppAvailabilityResult::kAvailable) {
106       supported_app_ids.push_back(availability.first);
107     }
108   }
109 
110   // Find all registered sources whose query results contain the receiver ID.
111   std::vector<CastMediaSource> sources;
112   for (const auto& source : registered_sources_) {
113     if (source.second.ContainsAnyAppIdFrom(supported_app_ids)) {
114       sources.push_back(source.second);
115     }
116   }
117   return sources;
118 }
119 
120 CastAppAvailabilityTracker::AppAvailability
GetAvailability(const std::string & receiver_id,const std::string & app_id) const121 CastAppAvailabilityTracker::GetAvailability(const std::string& receiver_id,
122                                             const std::string& app_id) const {
123   auto availabilities_it = app_availabilities_.find(receiver_id);
124   if (availabilities_it == app_availabilities_.end()) {
125     return {AppAvailabilityResult::kUnknown, Clock::time_point{}};
126   }
127 
128   const auto& availability_map = availabilities_it->second;
129   auto availability_it = availability_map.find(app_id);
130   if (availability_it == availability_map.end()) {
131     return {AppAvailabilityResult::kUnknown, Clock::time_point{}};
132   }
133 
134   return availability_it->second;
135 }
136 
GetRegisteredApps() const137 std::vector<std::string> CastAppAvailabilityTracker::GetRegisteredApps() const {
138   std::vector<std::string> registered_apps;
139   for (const auto& app_ids_and_count : registration_count_by_app_id_) {
140     registered_apps.push_back(app_ids_and_count.first);
141   }
142 
143   return registered_apps;
144 }
145 
GetAvailableReceivers(const CastMediaSource & source) const146 std::vector<std::string> CastAppAvailabilityTracker::GetAvailableReceivers(
147     const CastMediaSource& source) const {
148   std::vector<std::string> receiver_ids;
149   // For each receiver, check if there is at least one available app in
150   // |source|.
151   for (const auto& availabilities : app_availabilities_) {
152     for (const std::string& app_id : source.app_ids()) {
153       const auto& availabilities_map = availabilities.second;
154       auto availability_it = availabilities_map.find(app_id);
155       if (availability_it != availabilities_map.end() &&
156           availability_it->second.availability ==
157               AppAvailabilityResult::kAvailable) {
158         receiver_ids.push_back(availabilities.first);
159         break;
160       }
161     }
162   }
163   return receiver_ids;
164 }
165 
166 }  // namespace cast
167 }  // namespace openscreen
168