1 // Copyright (c) 2011 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.
5 #include "content/browser/media/media_internals.h"
8 #include "base/bind_helpers.h"
9 #include "base/json/json_reader.h"
10 #include "base/run_loop.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "media/audio/audio_parameters.h"
15 #include "media/base/channel_layout.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/gfx/geometry/size.h"
20 const int kTestComponentID
= 0;
21 const char kTestDeviceID
[] = "test-device-id";
23 // This class encapsulates a MediaInternals reference. It also has some useful
24 // methods to receive a callback, deserialize its associated data and expect
25 // integer/string values.
26 class MediaInternalsTestBase
{
28 MediaInternalsTestBase()
29 : media_internals_(content::MediaInternals::GetInstance()) {
31 virtual ~MediaInternalsTestBase() {}
34 // Extracts and deserializes the JSON update data; merges into |update_data_|.
35 void UpdateCallbackImpl(const base::string16
& update
) {
36 // Each update string looks like "<JavaScript Function Name>({<JSON>});"
37 // or for video capabilities: "<JavaScript Function Name>([{<JSON>}]);".
38 // In the second case we will be able to extract the dictionary if it is the
39 // only member of the list.
40 // To use the JSON reader we need to strip out the JS function name and ().
41 std::string utf8_update
= base::UTF16ToUTF8(update
);
42 const std::string::size_type first_brace
= utf8_update
.find('{');
43 const std::string::size_type last_brace
= utf8_update
.rfind('}');
44 scoped_ptr
<base::Value
> output_value
= base::JSONReader::Read(
45 utf8_update
.substr(first_brace
, last_brace
- first_brace
+ 1));
48 base::DictionaryValue
* output_dict
= NULL
;
49 CHECK(output_value
->GetAsDictionary(&output_dict
));
50 update_data_
.MergeDictionary(output_dict
);
53 void ExpectInt(const std::string
& key
, int expected_value
) const {
55 ASSERT_TRUE(update_data_
.GetInteger(key
, &actual_value
));
56 EXPECT_EQ(expected_value
, actual_value
);
59 void ExpectString(const std::string
& key
,
60 const std::string
& expected_value
) const {
61 std::string actual_value
;
62 ASSERT_TRUE(update_data_
.GetString(key
, &actual_value
));
63 EXPECT_EQ(expected_value
, actual_value
);
66 void ExpectStatus(const std::string
& expected_value
) const {
67 ExpectString("status", expected_value
);
70 void ExpectListOfStrings(const std::string
& key
,
71 const base::ListValue
& expected_list
) const {
72 const base::ListValue
* actual_list
;
73 ASSERT_TRUE(update_data_
.GetList(key
, &actual_list
));
74 const size_t expected_size
= expected_list
.GetSize();
75 const size_t actual_size
= actual_list
->GetSize();
76 ASSERT_EQ(expected_size
, actual_size
);
77 for (size_t i
= 0; i
< expected_size
; ++i
) {
78 std::string expected_value
, actual_value
;
79 ASSERT_TRUE(expected_list
.GetString(i
, &expected_value
));
80 ASSERT_TRUE(actual_list
->GetString(i
, &actual_value
));
81 EXPECT_EQ(expected_value
, actual_value
);
85 const content::TestBrowserThreadBundle thread_bundle_
;
86 base::DictionaryValue update_data_
;
87 content::MediaInternals
* const media_internals_
;
94 class MediaInternalsVideoCaptureDeviceTest
: public testing::Test
,
95 public MediaInternalsTestBase
{
97 MediaInternalsVideoCaptureDeviceTest()
98 : update_cb_(base::Bind(
99 &MediaInternalsVideoCaptureDeviceTest::UpdateCallbackImpl
,
100 base::Unretained(this))) {
101 media_internals_
->AddUpdateCallback(update_cb_
);
104 ~MediaInternalsVideoCaptureDeviceTest() override
{
105 media_internals_
->RemoveUpdateCallback(update_cb_
);
109 MediaInternals::UpdateCallback update_cb_
;
112 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
114 TEST_F(MediaInternalsVideoCaptureDeviceTest
,
115 AllCaptureApiTypesHaveProperStringRepresentation
) {
116 typedef media::VideoCaptureDevice::Name VideoCaptureDeviceName
;
117 typedef std::map
<VideoCaptureDeviceName::CaptureApiType
, std::string
>
118 CaptureApiTypeStringMap
;
119 CaptureApiTypeStringMap m
;
120 #if defined(OS_LINUX)
121 m
[VideoCaptureDeviceName::V4L2_SINGLE_PLANE
] = "V4L2 SPLANE";
122 m
[VideoCaptureDeviceName::V4L2_MULTI_PLANE
] = "V4L2 MPLANE";
123 #elif defined(OS_WIN)
124 m
[VideoCaptureDeviceName::MEDIA_FOUNDATION
] = "Media Foundation";
125 m
[VideoCaptureDeviceName::DIRECT_SHOW
] = "Direct Show";
126 #elif defined(OS_MACOSX)
127 m
[VideoCaptureDeviceName::AVFOUNDATION
] = "AV Foundation";
128 m
[VideoCaptureDeviceName::QTKIT
] = "QTKit";
129 m
[VideoCaptureDeviceName::DECKLINK
] = "DeckLink";
130 #elif defined(OS_ANDROID)
131 m
[VideoCaptureDeviceName::API1
] = "Camera API1";
132 m
[VideoCaptureDeviceName::API2_LEGACY
] = "Camera API2 Legacy";
133 m
[VideoCaptureDeviceName::API2_FULL
] = "Camera API2 Full";
134 m
[VideoCaptureDeviceName::API2_LIMITED
] = "Camera API2 Limited";
135 m
[VideoCaptureDeviceName::TANGO
] = "Tango API";
137 EXPECT_EQ(media::VideoCaptureDevice::Name::API_TYPE_UNKNOWN
, m
.size());
138 for (CaptureApiTypeStringMap::iterator it
= m
.begin(); it
!= m
.end(); ++it
) {
139 const VideoCaptureDeviceName
device_name("dummy", "dummy", it
->first
);
140 EXPECT_EQ(it
->second
, device_name
.GetCaptureApiTypeString());
145 TEST_F(MediaInternalsVideoCaptureDeviceTest
,
146 VideoCaptureFormatStringIsInExpectedFormat
) {
147 // Since media internals will send video capture capabilities to JavaScript in
148 // an expected format and there are no public methods for accessing the
149 // resolutions, frame rates or pixel formats, this test checks that the format
150 // has not changed. If the test fails because of the changed format, it should
151 // be updated at the same time as the media internals JS files.
152 const float kFrameRate
= 30.0f
;
153 const gfx::Size
kFrameSize(1280, 720);
154 const media::VideoCapturePixelFormat kPixelFormat
=
155 media::VIDEO_CAPTURE_PIXEL_FORMAT_I420
;
156 const media::VideoPixelStorage kPixelStorage
= media::PIXEL_STORAGE_CPU
;
157 const media::VideoCaptureFormat
capture_format(kFrameSize
, kFrameRate
,
158 kPixelFormat
, kPixelStorage
);
159 const std::string expected_string
= base::StringPrintf(
160 "(%s)@%.3ffps, pixel format: %s storage: %s.",
161 kFrameSize
.ToString().c_str(), kFrameRate
,
162 media::VideoCaptureFormat::PixelFormatToString(kPixelFormat
).c_str(),
163 media::VideoCaptureFormat::PixelStorageToString(kPixelStorage
).c_str());
164 EXPECT_EQ(expected_string
,
165 media::VideoCaptureFormat::ToString(capture_format
));
168 TEST_F(MediaInternalsVideoCaptureDeviceTest
,
169 NotifyVideoCaptureDeviceCapabilitiesEnumerated
) {
170 const int kWidth
= 1280;
171 const int kHeight
= 720;
172 const float kFrameRate
= 30.0f
;
173 const media::VideoCapturePixelFormat kPixelFormat
=
174 media::VIDEO_CAPTURE_PIXEL_FORMAT_I420
;
175 const media::VideoCaptureFormat
format_hd({kWidth
, kHeight
},
176 kFrameRate
, kPixelFormat
);
177 media::VideoCaptureFormats formats
{};
178 formats
.push_back(format_hd
);
179 const media::VideoCaptureDeviceInfo
device_info(
180 #if defined(OS_MACOSX)
181 media::VideoCaptureDevice::Name("dummy", "dummy",
182 media::VideoCaptureDevice::Name::QTKIT
),
183 #elif defined(OS_WIN)
184 media::VideoCaptureDevice::Name("dummy", "dummy",
185 media::VideoCaptureDevice::Name::DIRECT_SHOW
),
186 #elif defined(OS_LINUX)
187 media::VideoCaptureDevice::Name(
188 "dummy", "/dev/dummy",
189 media::VideoCaptureDevice::Name::V4L2_SINGLE_PLANE
),
190 #elif defined(OS_ANDROID)
191 media::VideoCaptureDevice::Name("dummy", "dummy",
192 media::VideoCaptureDevice::Name::API2_LEGACY
),
194 media::VideoCaptureDevice::Name("dummy", "dummy"),
197 media::VideoCaptureDeviceInfos device_infos
{};
198 device_infos
.push_back(device_info
);
200 // When updating video capture capabilities, the update will serialize
201 // a JSON array of objects to string. So here, the |UpdateCallbackImpl| will
202 // deserialize the first object in the array. This means we have to have
203 // exactly one device_info in the |device_infos|.
204 media_internals_
->UpdateVideoCaptureDeviceCapabilities(device_infos
);
206 #if defined(OS_LINUX)
207 ExpectString("id", "/dev/dummy");
209 ExpectString("id", "dummy");
211 ExpectString("name", "dummy");
212 base::ListValue expected_list
;
213 expected_list
.AppendString(media::VideoCaptureFormat::ToString(format_hd
));
214 ExpectListOfStrings("formats", expected_list
);
215 #if defined(OS_LINUX)
216 ExpectString("captureApi", "V4L2 SPLANE");
217 #elif defined(OS_WIN)
218 ExpectString("captureApi", "Direct Show");
219 #elif defined(OS_MACOSX)
220 ExpectString("captureApi", "QTKit");
221 #elif defined(OS_ANDROID)
222 ExpectString("captureApi", "Camera API2 Legacy");
226 class MediaInternalsAudioLogTest
227 : public MediaInternalsTestBase
,
228 public testing::TestWithParam
<media::AudioLogFactory::AudioComponent
> {
230 MediaInternalsAudioLogTest() :
231 update_cb_(base::Bind(&MediaInternalsAudioLogTest::UpdateCallbackImpl
,
232 base::Unretained(this))),
233 test_params_(media::AudioParameters::AUDIO_PCM_LINEAR
,
234 media::CHANNEL_LAYOUT_MONO
,
238 media::AudioParameters::ECHO_CANCELLER
|
239 media::AudioParameters::DUCKING
),
240 test_component_(GetParam()),
241 audio_log_(media_internals_
->CreateAudioLog(test_component_
)) {
242 media_internals_
->AddUpdateCallback(update_cb_
);
245 virtual ~MediaInternalsAudioLogTest() {
246 media_internals_
->RemoveUpdateCallback(update_cb_
);
250 MediaInternals::UpdateCallback update_cb_
;
251 const media::AudioParameters test_params_
;
252 const media::AudioLogFactory::AudioComponent test_component_
;
253 scoped_ptr
<media::AudioLog
> audio_log_
;
256 TEST_P(MediaInternalsAudioLogTest
, AudioLogCreateStartStopErrorClose
) {
257 audio_log_
->OnCreated(kTestComponentID
, test_params_
, kTestDeviceID
);
258 base::RunLoop().RunUntilIdle();
260 ExpectString("channel_layout",
261 media::ChannelLayoutToString(test_params_
.channel_layout()));
262 ExpectInt("sample_rate", test_params_
.sample_rate());
263 ExpectInt("frames_per_buffer", test_params_
.frames_per_buffer());
264 ExpectInt("channels", test_params_
.channels());
265 ExpectString("effects", "ECHO_CANCELLER | DUCKING");
266 ExpectString("device_id", kTestDeviceID
);
267 ExpectInt("component_id", kTestComponentID
);
268 ExpectInt("component_type", test_component_
);
269 ExpectStatus("created");
271 // Verify OnStarted().
272 audio_log_
->OnStarted(kTestComponentID
);
273 base::RunLoop().RunUntilIdle();
274 ExpectStatus("started");
276 // Verify OnStopped().
277 audio_log_
->OnStopped(kTestComponentID
);
278 base::RunLoop().RunUntilIdle();
279 ExpectStatus("stopped");
282 const char kErrorKey
[] = "error_occurred";
283 std::string no_value
;
284 ASSERT_FALSE(update_data_
.GetString(kErrorKey
, &no_value
));
285 audio_log_
->OnError(kTestComponentID
);
286 base::RunLoop().RunUntilIdle();
287 ExpectString(kErrorKey
, "true");
289 // Verify OnClosed().
290 audio_log_
->OnClosed(kTestComponentID
);
291 base::RunLoop().RunUntilIdle();
292 ExpectStatus("closed");
295 TEST_P(MediaInternalsAudioLogTest
, AudioLogCreateClose
) {
296 audio_log_
->OnCreated(kTestComponentID
, test_params_
, kTestDeviceID
);
297 base::RunLoop().RunUntilIdle();
298 ExpectStatus("created");
300 audio_log_
->OnClosed(kTestComponentID
);
301 base::RunLoop().RunUntilIdle();
302 ExpectStatus("closed");
305 INSTANTIATE_TEST_CASE_P(
306 MediaInternalsAudioLogTest
, MediaInternalsAudioLogTest
, testing::Values(
307 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER
,
308 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER
,
309 media::AudioLogFactory::AUDIO_OUTPUT_STREAM
));
311 } // namespace content