blob: 246d46965ae20d3e617c4b2cebe8dcdca1fe0859 [file] [log] [blame]
Bryant Chandlerb214ba42024-02-28 22:27:421// Copyright 2024 The Chromium Authors
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 "components/media_effects/media_device_info.h"
6
ahmedmoussa354d0472024-03-06 18:36:067#include <optional>
8
Bryant Chandlerb214ba42024-02-28 22:27:429#include "base/system/system_monitor.h"
10#include "base/test/test_future.h"
11#include "components/media_effects/test/fake_audio_service.h"
12#include "components/media_effects/test/fake_video_capture_service.h"
13#include "content/public/browser/audio_service.h"
14#include "content/public/browser/video_capture_service.h"
15#include "content/public/test/browser_task_environment.h"
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace {
20
ahmedmoussa5b526e952024-03-16 16:15:2621using media_effects::GetRealAudioDeviceNames;
ahmedmoussa354d0472024-03-06 18:36:0622using media_effects::GetRealDefaultDeviceId;
ahmedmoussa5b526e952024-03-16 16:15:2623using media_effects::GetRealVideoDeviceNames;
ahmedmoussa354d0472024-03-06 18:36:0624
Bryant Chandlerb214ba42024-02-28 22:27:4225media::AudioDeviceDescription GetAudioDeviceDescription(size_t index) {
26 return media::AudioDeviceDescription{
27 /*device_name=*/base::StringPrintf("name_%zu", index),
28 /*unique_id=*/base::StringPrintf("id_%zu", index),
29 /*group_id=*/base::StringPrintf("group_%zu", index)};
30}
31
32media::VideoCaptureDeviceDescriptor GetVideoCaptureDeviceDescriptor(
33 size_t index) {
34 return media::VideoCaptureDeviceDescriptor{
35 /*display_name=*/base::StringPrintf("name_%zu", index),
36 /*device_id=*/base::StringPrintf("id_%zu", index)};
37}
38
39class MockDeviceChangeObserver
40 : public media_effects::MediaDeviceInfo::Observer {
41 public:
42 MOCK_METHOD(void,
43 OnAudioDevicesChanged,
44 (const std::optional<std::vector<media::AudioDeviceDescription>>&
45 device_infos));
46 MOCK_METHOD(void,
47 OnVideoDevicesChanged,
48 (const std::optional<std::vector<media::VideoCaptureDeviceInfo>>&
49 device_infos));
50};
51
52auto IsVideoDevice(size_t expected_index) {
53 return testing::Field(&media::VideoCaptureDeviceInfo::descriptor,
54 GetVideoCaptureDeviceDescriptor(expected_index));
55}
56
57} // namespace
58
59class MediaDeviceInfoTest : public testing::Test {
60 void SetUp() override {
61 auto_reset_audio_service_.emplace(
62 content::OverrideAudioServiceForTesting(&fake_audio_service_));
63 content::OverrideVideoCaptureServiceForTesting(
64 &fake_video_capture_service_);
65 auto_reset_media_device_info_override_.emplace(
66 media_effects::MediaDeviceInfo::OverrideInstanceForTesting());
67 }
68
69 void TearDown() override {
70 content::OverrideVideoCaptureServiceForTesting(nullptr);
71 }
72
73 protected:
74 media::AudioDeviceDescription AddFakeAudioDevice(size_t index) {
75 base::test::TestFuture<void> replied_audio_device_infos_future;
76 fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback(
77 replied_audio_device_infos_future.GetCallback());
78 auto device = GetAudioDeviceDescription(index);
79 fake_audio_service_.AddFakeInputDevice(device);
80 CHECK(replied_audio_device_infos_future.WaitAndClear());
81 return device;
82 }
83
84 media::VideoCaptureDeviceDescriptor AddFakeVideoDevice(size_t index) {
85 base::test::TestFuture<void> replied_video_device_infos_future;
86 fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback(
87 replied_video_device_infos_future.GetCallback());
88 auto device = GetVideoCaptureDeviceDescriptor(index);
89 fake_video_capture_service_.AddFakeCamera(device);
90 CHECK(replied_video_device_infos_future.WaitAndClear());
91 return device;
92 }
93
94 content::BrowserTaskEnvironment task_environment_;
95 base::SystemMonitor monitor_;
96 media_effects::FakeAudioService fake_audio_service_;
97 std::optional<base::AutoReset<audio::mojom::AudioService*>>
98 auto_reset_audio_service_;
99 media_effects::FakeVideoCaptureService fake_video_capture_service_;
100 // When `MediaDeviceInfo::OverrideInstanceForTesting()` is called it returns
101 // an `AutoReset` that removes the override when it's destructed.
102 // std::optional is used to hold it because we don't get the value until
103 // `SetUp()` and `AutoReset` doesn't have a default constructor.
104 std::optional<std::pair<std::unique_ptr<media_effects::MediaDeviceInfo>,
105 base::AutoReset<media_effects::MediaDeviceInfo*>>>
106 auto_reset_media_device_info_override_;
107};
108
109// Test that audio device infos are retrieved on construction and updated when
110// changes are observed from `SystemMonitor`.
111TEST_F(MediaDeviceInfoTest, GetAudioDeviceInfos) {
112 base::test::TestFuture<void> replied_audio_device_infos_future;
113 fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback(
114 replied_audio_device_infos_future.GetCallback());
115 EXPECT_FALSE(media_effects::MediaDeviceInfo::GetInstance()
116 ->GetAudioDeviceInfos()
117 .has_value());
118 ASSERT_TRUE(replied_audio_device_infos_future.WaitAndClear());
119 EXPECT_TRUE(media_effects::MediaDeviceInfo::GetInstance()
120 ->GetAudioDeviceInfos()
121 .has_value());
122
123 auto device_0 = AddFakeAudioDevice(0);
124 EXPECT_THAT(
125 media_effects::MediaDeviceInfo::GetInstance()->GetAudioDeviceInfos(),
126 testing::Optional(testing::ElementsAre(device_0)));
127 auto device_1 = AddFakeAudioDevice(1);
128 EXPECT_THAT(
129 media_effects::MediaDeviceInfo::GetInstance()->GetAudioDeviceInfos(),
130 testing::Optional(testing::ElementsAre(device_0, device_1)));
131}
132
133// Test that getting audio device info by ID returns the correct device or
134// nullopt if not found.
135TEST_F(MediaDeviceInfoTest, GetAudioDeviceInfoForId) {
136 auto device_0 = AddFakeAudioDevice(0);
137 auto device_1 = AddFakeAudioDevice(1);
138 auto device_2 = AddFakeAudioDevice(2);
139 EXPECT_EQ(device_1, media_effects::MediaDeviceInfo::GetInstance()
140 ->GetAudioDeviceInfoForId(device_1.unique_id));
141 EXPECT_EQ(std::nullopt, media_effects::MediaDeviceInfo::GetInstance()
142 ->GetAudioDeviceInfoForId("not_found_id"));
143}
144
145// Test that video device infos are retrieved on construction and updated when
146// changes are observed from `SystemMonitor`.
147TEST_F(MediaDeviceInfoTest, GetVideoDeviceInfos) {
148 base::test::TestFuture<void> replied_video_device_infos_future;
149 fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback(
150 replied_video_device_infos_future.GetCallback());
151 EXPECT_FALSE(media_effects::MediaDeviceInfo::GetInstance()
152 ->GetVideoDeviceInfos()
153 .has_value());
154 ASSERT_TRUE(replied_video_device_infos_future.WaitAndClear());
155 EXPECT_TRUE(media_effects::MediaDeviceInfo::GetInstance()
156 ->GetVideoDeviceInfos()
157 .has_value());
158
159 auto device_0 = AddFakeVideoDevice(0);
160 EXPECT_THAT(
161 media_effects::MediaDeviceInfo::GetInstance()->GetVideoDeviceInfos(),
162 testing::Optional(testing::ElementsAre(IsVideoDevice(0))));
163 auto device_1 = AddFakeVideoDevice(1);
164 EXPECT_THAT(
165 media_effects::MediaDeviceInfo::GetInstance()->GetVideoDeviceInfos(),
166 testing::Optional(
167 testing::ElementsAre(IsVideoDevice(0), IsVideoDevice(1))));
168}
169
170// Test that getting video device info by ID returns the correct device or
171// nullopt if not found.
172TEST_F(MediaDeviceInfoTest, GetVideoDeviceInfoForId) {
173 auto device_0 = AddFakeVideoDevice(0);
174 auto device_1 = AddFakeVideoDevice(1);
175 auto device_2 = AddFakeVideoDevice(2);
176 EXPECT_EQ(device_1, media_effects::MediaDeviceInfo::GetInstance()
177 ->GetVideoDeviceInfoForId(device_1.device_id)
178 ->descriptor);
179 EXPECT_EQ(std::nullopt, media_effects::MediaDeviceInfo::GetInstance()
180 ->GetVideoDeviceInfoForId("not_found_id"));
181}
182
183// Test that appropriate observer methods are called when device infos change.
184TEST_F(MediaDeviceInfoTest, Observers) {
185 MockDeviceChangeObserver observer;
186 media_effects::MediaDeviceInfo::GetInstance()->AddObserver(&observer);
187 base::test::TestFuture<void> replied_video_device_infos_future;
188 fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback(
189 replied_video_device_infos_future.GetCallback());
190 EXPECT_CALL(observer,
191 OnAudioDevicesChanged(testing::Optional(testing::IsEmpty())));
192 EXPECT_CALL(observer,
193 OnVideoDevicesChanged(testing::Optional(testing::IsEmpty())));
194 ASSERT_TRUE(replied_video_device_infos_future.WaitAndClear());
195
196 // Audio device changes
197 EXPECT_CALL(observer,
198 OnAudioDevicesChanged(testing::Optional(
199 testing::ElementsAre(GetAudioDeviceDescription(0)))));
200 AddFakeAudioDevice(0);
201
202 EXPECT_CALL(
203 observer,
204 OnAudioDevicesChanged(testing::Optional(testing::ElementsAre(
205 GetAudioDeviceDescription(0), GetAudioDeviceDescription(1)))));
206 AddFakeAudioDevice(1);
207
208 EXPECT_CALL(observer,
209 OnAudioDevicesChanged(testing::Optional(testing::ElementsAre(
210 GetAudioDeviceDescription(0), GetAudioDeviceDescription(1),
211 GetAudioDeviceDescription(2)))));
212 AddFakeAudioDevice(2);
213
214 // Video device changes
215 EXPECT_CALL(observer, OnVideoDevicesChanged(testing::Optional(
216 testing::ElementsAre(IsVideoDevice(0)))));
217 AddFakeVideoDevice(0);
218
219 EXPECT_CALL(observer,
220 OnVideoDevicesChanged(testing::Optional(
221 testing::ElementsAre(IsVideoDevice(0), IsVideoDevice(1)))));
222 auto device_1 = AddFakeVideoDevice(1);
223
224 EXPECT_CALL(observer,
225 OnVideoDevicesChanged(testing::Optional(testing::ElementsAre(
226 IsVideoDevice(0), IsVideoDevice(1), IsVideoDevice(2)))));
227 auto device_2 = AddFakeVideoDevice(2);
228
229 // Remove observer
230 EXPECT_CALL(observer, OnAudioDevicesChanged(testing::_)).Times(0);
231 EXPECT_CALL(observer, OnVideoDevicesChanged(testing::_)).Times(0);
232 media_effects::MediaDeviceInfo::GetInstance()->RemoveObserver(&observer);
233 AddFakeAudioDevice(3);
234 AddFakeVideoDevice(3);
235}
ahmedmoussa354d0472024-03-06 18:36:06236
237TEST(MediaDeviceInfoTestGeneral, DefaultAudioDeviceHandling) {
238 std::vector<media::AudioDeviceDescription> infos;
239 EXPECT_EQ(GetRealDefaultDeviceId(infos), std::nullopt);
ahmedmoussa5b526e952024-03-16 16:15:26240 EXPECT_EQ(GetRealAudioDeviceNames(infos).size(), 0u);
ahmedmoussa354d0472024-03-06 18:36:06241
242 infos.push_back(GetAudioDeviceDescription(0));
243 infos.push_back(GetAudioDeviceDescription(1));
244 infos.push_back(GetAudioDeviceDescription(2));
245 EXPECT_EQ(GetRealDefaultDeviceId(infos), std::nullopt);
ahmedmoussa5b526e952024-03-16 16:15:26246 EXPECT_THAT(GetRealAudioDeviceNames(infos),
247 testing::ElementsAre(infos[0].device_name, infos[1].device_name,
248 infos[2].device_name));
ahmedmoussa354d0472024-03-06 18:36:06249
250 infos.front().is_system_default = true;
251 EXPECT_EQ(GetRealDefaultDeviceId(infos), infos.front().unique_id);
ahmedmoussa5b526e952024-03-16 16:15:26252 EXPECT_THAT(GetRealAudioDeviceNames(infos),
253 testing::ElementsAre(infos[0].device_name, infos[1].device_name,
254 infos[2].device_name));
ahmedmoussa354d0472024-03-06 18:36:06255
256 infos.front().unique_id = media::AudioDeviceDescription::kDefaultDeviceId;
257 EXPECT_EQ(GetRealDefaultDeviceId(infos), std::nullopt);
ahmedmoussa5b526e952024-03-16 16:15:26258 EXPECT_THAT(GetRealAudioDeviceNames(infos),
259 testing::ElementsAre(infos[1].device_name, infos[2].device_name));
ahmedmoussa354d0472024-03-06 18:36:06260
261 infos[1].is_system_default = true;
262 EXPECT_EQ(GetRealDefaultDeviceId(infos), infos[1].unique_id);
ahmedmoussa5b526e952024-03-16 16:15:26263 EXPECT_THAT(GetRealAudioDeviceNames(infos),
264 testing::ElementsAre(infos[1].device_name, infos[2].device_name));
ahmedmoussa354d0472024-03-06 18:36:06265
266 infos[2].unique_id = media::AudioDeviceDescription::kCommunicationsDeviceId;
267 EXPECT_EQ(GetRealDefaultDeviceId(infos), infos[1].unique_id);
ahmedmoussa5b526e952024-03-16 16:15:26268 EXPECT_THAT(GetRealAudioDeviceNames(infos),
269 testing::ElementsAre(infos[1].device_name));
270}
271
272TEST(MediaDeviceInfoTestGeneral, GetVideoDeviceNames) {
273 std::vector<media::VideoCaptureDeviceInfo> infos;
274 EXPECT_EQ(GetRealVideoDeviceNames(infos).size(), 0u);
275
276 infos.emplace_back(GetVideoCaptureDeviceDescriptor(0));
277 infos.emplace_back(GetVideoCaptureDeviceDescriptor(1));
278 infos.emplace_back(GetVideoCaptureDeviceDescriptor(2));
279
280 EXPECT_THAT(GetRealVideoDeviceNames(infos),
281 testing::ElementsAre(infos[0].descriptor.GetNameAndModel(),
282 infos[1].descriptor.GetNameAndModel(),
283 infos[2].descriptor.GetNameAndModel()));
ahmedmoussa354d0472024-03-06 18:36:06284}