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