blob: 0a018d19ac5dbe3b0276f58ccd8a853499ed41f7 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cast/sender/cast_app_availability_tracker.h"
#include "util/osp_logging.h"
namespace openscreen {
namespace cast {
CastAppAvailabilityTracker::CastAppAvailabilityTracker() = default;
CastAppAvailabilityTracker::~CastAppAvailabilityTracker() = default;
std::vector<std::string> CastAppAvailabilityTracker::RegisterSource(
const CastMediaSource& source) {
if (registered_sources_.find(source.source_id()) !=
registered_sources_.end()) {
return {};
}
registered_sources_.emplace(source.source_id(), source);
std::vector<std::string> new_app_ids;
for (const std::string& app_id : source.app_ids()) {
if (++registration_count_by_app_id_[app_id] == 1) {
new_app_ids.push_back(app_id);
}
}
return new_app_ids;
}
void CastAppAvailabilityTracker::UnregisterSource(
const CastMediaSource& source) {
UnregisterSource(source.source_id());
}
void CastAppAvailabilityTracker::UnregisterSource(
const std::string& source_id) {
auto it = registered_sources_.find(source_id);
if (it == registered_sources_.end()) {
return;
}
for (const std::string& app_id : it->second.app_ids()) {
auto count_it = registration_count_by_app_id_.find(app_id);
OSP_DCHECK(count_it != registration_count_by_app_id_.end());
if (--(count_it->second) == 0) {
registration_count_by_app_id_.erase(count_it);
}
}
registered_sources_.erase(it);
}
std::vector<CastMediaSource> CastAppAvailabilityTracker::UpdateAppAvailability(
const std::string& device_id,
const std::string& app_id,
AppAvailability availability) {
auto& availabilities = app_availabilities_[device_id];
auto it = availabilities.find(app_id);
AppAvailabilityResult old_availability = it == availabilities.end()
? AppAvailabilityResult::kUnknown
: it->second.availability;
AppAvailabilityResult new_availability = availability.availability;
// Updated if status changes from/to kAvailable.
bool updated = (old_availability == AppAvailabilityResult::kAvailable ||
new_availability == AppAvailabilityResult::kAvailable) &&
old_availability != new_availability;
availabilities[app_id] = availability;
if (!updated) {
return {};
}
std::vector<CastMediaSource> affected_sources;
for (const auto& source : registered_sources_) {
if (source.second.ContainsAppId(app_id)) {
affected_sources.push_back(source.second);
}
}
return affected_sources;
}
std::vector<CastMediaSource> CastAppAvailabilityTracker::RemoveResultsForDevice(
const std::string& device_id) {
auto affected_sources = GetSupportedSources(device_id);
app_availabilities_.erase(device_id);
return affected_sources;
}
std::vector<CastMediaSource> CastAppAvailabilityTracker::GetSupportedSources(
const std::string& device_id) const {
auto it = app_availabilities_.find(device_id);
if (it == app_availabilities_.end()) {
return std::vector<CastMediaSource>();
}
// Find all app IDs that are available on the device.
std::vector<std::string> supported_app_ids;
for (const auto& availability : it->second) {
if (availability.second.availability == AppAvailabilityResult::kAvailable) {
supported_app_ids.push_back(availability.first);
}
}
// Find all registered sources whose query results contain the device ID.
std::vector<CastMediaSource> sources;
for (const auto& source : registered_sources_) {
if (source.second.ContainsAnyAppIdFrom(supported_app_ids)) {
sources.push_back(source.second);
}
}
return sources;
}
CastAppAvailabilityTracker::AppAvailability
CastAppAvailabilityTracker::GetAvailability(const std::string& device_id,
const std::string& app_id) const {
auto availabilities_it = app_availabilities_.find(device_id);
if (availabilities_it == app_availabilities_.end()) {
return {AppAvailabilityResult::kUnknown, Clock::time_point{}};
}
const auto& availability_map = availabilities_it->second;
auto availability_it = availability_map.find(app_id);
if (availability_it == availability_map.end()) {
return {AppAvailabilityResult::kUnknown, Clock::time_point{}};
}
return availability_it->second;
}
std::vector<std::string> CastAppAvailabilityTracker::GetRegisteredApps() const {
std::vector<std::string> registered_apps;
for (const auto& app_ids_and_count : registration_count_by_app_id_) {
registered_apps.push_back(app_ids_and_count.first);
}
return registered_apps;
}
std::vector<std::string> CastAppAvailabilityTracker::GetAvailableDevices(
const CastMediaSource& source) const {
std::vector<std::string> device_ids;
// For each device, check if there is at least one available app in |source|.
for (const auto& availabilities : app_availabilities_) {
for (const std::string& app_id : source.app_ids()) {
const auto& availabilities_map = availabilities.second;
auto availability_it = availabilities_map.find(app_id);
if (availability_it != availabilities_map.end() &&
availability_it->second.availability ==
AppAvailabilityResult::kAvailable) {
device_ids.push_back(availabilities.first);
break;
}
}
}
return device_ids;
}
} // namespace cast
} // namespace openscreen