1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/global_media_controls/media_notification_device_monitor.h"
#include <algorithm>
#include <iterator>
#include "base/functional/bind.h"
#include "base/hash/hash.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/ui/global_media_controls/media_notification_device_provider.h"
// MediaNotificationDeviceMonitor
MediaNotificationDeviceMonitor::~MediaNotificationDeviceMonitor() = default;
std::unique_ptr<MediaNotificationDeviceMonitor>
MediaNotificationDeviceMonitor::Create(
MediaNotificationDeviceProvider* device_provider) {
// The device monitor implementation on linux does not reliably detect
// connection changes for some devices. In this case we fall back to polling the
// device provider. See crbug.com/1112480 for more information.
#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(USE_UDEV)
return std::make_unique<PollingDeviceMonitorImpl>(device_provider);
#else
return std::make_unique<SystemMonitorDeviceMonitorImpl>();
#endif
}
void MediaNotificationDeviceMonitor::AddDevicesChangedObserver(
DevicesChangedObserver* obs) {
observers_.AddObserver(obs);
}
void MediaNotificationDeviceMonitor::RemoveDevicesChangedObserver(
DevicesChangedObserver* obs) {
observers_.RemoveObserver(obs);
}
MediaNotificationDeviceMonitor::MediaNotificationDeviceMonitor() = default;
#if !((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(USE_UDEV))
// SystemMonitorDeviceMonitorImpl
SystemMonitorDeviceMonitorImpl::SystemMonitorDeviceMonitorImpl() {
base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
}
SystemMonitorDeviceMonitorImpl::~SystemMonitorDeviceMonitorImpl() {
base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
}
void SystemMonitorDeviceMonitorImpl::StartMonitoring() {
is_monitoring_ = true;
}
void SystemMonitorDeviceMonitorImpl::StopMonitoring() {
is_monitoring_ = false;
}
void SystemMonitorDeviceMonitorImpl::OnDevicesChanged(
base::SystemMonitor::DeviceType device_type) {
if (!is_monitoring_) {
return;
}
// TODO(noahrose): Get an issue number for this TODO. Only notify observers in
// changes of audio output devices as opposed to audio devices in general.
if (device_type != base::SystemMonitor::DEVTYPE_AUDIO) {
return;
}
for (auto& observer : observers_) {
observer.OnDevicesChanged();
}
}
#else
namespace {
constexpr int kPollingIntervalSeconds = 10;
} // anonymous namespace
// PollingDeviceMonitorImpl
PollingDeviceMonitorImpl::PollingDeviceMonitorImpl(
MediaNotificationDeviceProvider* device_provider)
: device_provider_(device_provider),
task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {}
void PollingDeviceMonitorImpl::StartMonitoring() {
if (is_monitoring_) {
return;
}
is_monitoring_ = true;
if (!is_task_posted_) {
is_task_posted_ = true;
task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&PollingDeviceMonitorImpl::PollDeviceProvider,
weak_ptr_factory_.GetWeakPtr()),
base::Seconds(kPollingIntervalSeconds));
}
}
void PollingDeviceMonitorImpl::StopMonitoring() {
is_monitoring_ = false;
}
// static
int PollingDeviceMonitorImpl::get_polling_interval_for_testing() {
return kPollingIntervalSeconds;
}
PollingDeviceMonitorImpl::~PollingDeviceMonitorImpl() = default;
void PollingDeviceMonitorImpl::PollDeviceProvider() {
is_task_posted_ = false;
if (!is_monitoring_) {
return;
}
device_provider_->GetOutputDeviceDescriptions(
base::BindOnce(&PollingDeviceMonitorImpl::OnDeviceDescriptionsRecieved,
weak_ptr_factory_.GetWeakPtr()));
}
void PollingDeviceMonitorImpl::OnDeviceDescriptionsRecieved(
media::AudioDeviceDescriptions descriptions) {
if (!is_monitoring_) {
return;
}
if (!std::ranges::equal(descriptions, device_ids_, std::equal_to<>(),
&media::AudioDeviceDescription::unique_id)) {
device_ids_.clear();
std::ranges::transform(
descriptions, std::back_inserter(device_ids_),
[](auto& description) { return std::move(description.unique_id); });
NotifyObservers();
}
is_task_posted_ = true;
task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&PollingDeviceMonitorImpl::PollDeviceProvider,
weak_ptr_factory_.GetWeakPtr()),
base::Seconds(kPollingIntervalSeconds));
}
void PollingDeviceMonitorImpl::NotifyObservers() {
for (auto& observer : observers_) {
observer.OnDevicesChanged();
}
}
#endif
|