OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 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 "base/debug/trace_event_impl.h" |
| 6 #include "base/json/json_reader.h" |
| 7 #include "base/strings/stringprintf.h" |
| 8 #include "base/test/trace_event_analyzer.h" |
| 9 #include "base/values.h" |
| 10 #include "content/browser/media/webrtc_internals.h" |
| 11 #include "content/browser/web_contents/web_contents_impl.h" |
| 12 #include "content/public/test/browser_test_utils.h" |
| 13 #include "content/public/test/test_utils.h" |
| 14 #include "content/shell/browser/shell.h" |
| 15 #include "content/test/content_browser_test_utils.h" |
| 16 #include "content/test/webrtc_content_browsertest_base.h" |
| 17 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 18 #include "testing/perf/perf_test.h" |
| 19 |
| 20 #if defined(OS_WIN) |
| 21 #include "base/win/windows_version.h" |
| 22 #endif |
| 23 |
| 24 using trace_analyzer::TraceAnalyzer; |
| 25 using trace_analyzer::Query; |
| 26 using trace_analyzer::TraceEventVector; |
| 27 |
| 28 namespace { |
| 29 |
| 30 static const char kGetUserMediaAndStop[] = "getUserMediaAndStop"; |
| 31 static const char kGetUserMediaAndWaitAndStop[] = "getUserMediaAndWaitAndStop"; |
| 32 static const char kGetUserMediaAndAnalyseAndStop[] = |
| 33 "getUserMediaAndAnalyseAndStop"; |
| 34 |
| 35 // Results returned by JS. |
| 36 static const char kOK[] = "OK"; |
| 37 static const char kGetUserMediaFailed[] = |
| 38 "GetUserMedia call failed with code undefined"; |
| 39 |
| 40 std::string GenerateGetUserMediaWithMandatorySourceID( |
| 41 const std::string& function_name, |
| 42 const std::string& audio_source_id, |
| 43 const std::string& video_source_id) { |
| 44 const std::string audio_constraint = |
| 45 "audio: {mandatory: { sourceId:\"" + audio_source_id + "\"}}, "; |
| 46 |
| 47 const std::string video_constraint = |
| 48 "video: {mandatory: { sourceId:\"" + video_source_id + "\"}}"; |
| 49 return function_name + "({" + audio_constraint + video_constraint + "});"; |
| 50 } |
| 51 |
| 52 std::string GenerateGetUserMediaWithOptionalSourceID( |
| 53 const std::string& function_name, |
| 54 const std::string& audio_source_id, |
| 55 const std::string& video_source_id) { |
| 56 const std::string audio_constraint = |
| 57 "audio: {optional: [{sourceId:\"" + audio_source_id + "\"}]}, "; |
| 58 |
| 59 const std::string video_constraint = |
| 60 "video: {optional: [{ sourceId:\"" + video_source_id + "\"}]}"; |
| 61 return function_name + "({" + audio_constraint + video_constraint + "});"; |
| 62 } |
| 63 |
| 64 } // namespace |
| 65 |
| 66 namespace content { |
| 67 |
| 68 class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest { |
| 69 public: |
| 70 WebRtcGetUserMediaBrowserTest() : trace_log_(NULL) {} |
| 71 virtual ~WebRtcGetUserMediaBrowserTest() {} |
| 72 |
| 73 void StartTracing() { |
| 74 CHECK(trace_log_ == NULL) << "Can only can start tracing once"; |
| 75 trace_log_ = base::debug::TraceLog::GetInstance(); |
| 76 trace_log_->SetEnabled(base::debug::CategoryFilter("video"), |
| 77 base::debug::TraceLog::RECORDING_MODE, |
| 78 base::debug::TraceLog::ENABLE_SAMPLING); |
| 79 // Check that we are indeed recording. |
| 80 EXPECT_EQ(trace_log_->GetNumTracesRecorded(), 1); |
| 81 } |
| 82 |
| 83 void StopTracing() { |
| 84 CHECK(message_loop_runner_ == NULL) << "Calling StopTracing more than once"; |
| 85 trace_log_->SetDisabled(); |
| 86 message_loop_runner_ = new MessageLoopRunner; |
| 87 trace_log_->Flush(base::Bind( |
| 88 &WebRtcGetUserMediaBrowserTest::OnTraceDataCollected, |
| 89 base::Unretained(this))); |
| 90 message_loop_runner_->Run(); |
| 91 } |
| 92 |
| 93 void OnTraceDataCollected( |
| 94 const scoped_refptr<base::RefCountedString>& events_str_ptr, |
| 95 bool has_more_events) { |
| 96 CHECK(!has_more_events); |
| 97 recorded_trace_data_ = events_str_ptr; |
| 98 message_loop_runner_->Quit(); |
| 99 } |
| 100 |
| 101 TraceAnalyzer* CreateTraceAnalyzer() { |
| 102 return TraceAnalyzer::Create("[" + recorded_trace_data_->data() + "]"); |
| 103 } |
| 104 |
| 105 void GetSources(std::vector<std::string>* audio_ids, |
| 106 std::vector<std::string>* video_ids) { |
| 107 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 108 NavigateToURL(shell(), url); |
| 109 |
| 110 std::string sources_as_json = ExecuteJavascriptAndReturnResult( |
| 111 "getSources()"); |
| 112 EXPECT_FALSE(sources_as_json.empty()); |
| 113 |
| 114 int error_code; |
| 115 std::string error_message; |
| 116 scoped_ptr<base::Value> value( |
| 117 base::JSONReader::ReadAndReturnError(sources_as_json, |
| 118 base::JSON_ALLOW_TRAILING_COMMAS, |
| 119 &error_code, |
| 120 &error_message)); |
| 121 |
| 122 ASSERT_TRUE(value.get() != NULL) << error_message; |
| 123 EXPECT_EQ(value->GetType(), base::Value::TYPE_LIST); |
| 124 |
| 125 base::ListValue* values; |
| 126 ASSERT_TRUE(value->GetAsList(&values)); |
| 127 |
| 128 for (base::ListValue::iterator it = values->begin(); |
| 129 it != values->end(); ++it) { |
| 130 const base::DictionaryValue* dict; |
| 131 std::string kind; |
| 132 std::string id; |
| 133 ASSERT_TRUE((*it)->GetAsDictionary(&dict)); |
| 134 ASSERT_TRUE(dict->GetString("kind", &kind)); |
| 135 ASSERT_TRUE(dict->GetString("id", &id)); |
| 136 ASSERT_FALSE(id.empty()); |
| 137 EXPECT_TRUE(kind == "audio" || kind == "video"); |
| 138 if (kind == "audio") { |
| 139 audio_ids->push_back(id); |
| 140 } else if (kind == "video") { |
| 141 video_ids->push_back(id); |
| 142 } |
| 143 } |
| 144 ASSERT_FALSE(audio_ids->empty()); |
| 145 ASSERT_FALSE(video_ids->empty()); |
| 146 } |
| 147 |
| 148 private: |
| 149 base::debug::TraceLog* trace_log_; |
| 150 scoped_refptr<base::RefCountedString> recorded_trace_data_; |
| 151 scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 152 }; |
| 153 |
| 154 // These tests will all make a getUserMedia call with different constraints and |
| 155 // see that the success callback is called. If the error callback is called or |
| 156 // none of the callbacks are called the tests will simply time out and fail. |
| 157 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) { |
| 158 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 159 |
| 160 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 161 NavigateToURL(shell(), url); |
| 162 |
| 163 ASSERT_TRUE(ExecuteJavascript( |
| 164 base::StringPrintf("%s({video: true});", kGetUserMediaAndStop))); |
| 165 |
| 166 ExpectTitle("OK"); |
| 167 } |
| 168 |
| 169 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, |
| 170 GetAudioAndVideoStreamAndStop) { |
| 171 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 172 |
| 173 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 174 NavigateToURL(shell(), url); |
| 175 |
| 176 ASSERT_TRUE(ExecuteJavascript(base::StringPrintf( |
| 177 "%s({video: true, audio: true});", kGetUserMediaAndStop))); |
| 178 |
| 179 ExpectTitle("OK"); |
| 180 } |
| 181 |
| 182 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, |
| 183 GetAudioAndVideoStreamAndClone) { |
| 184 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 185 |
| 186 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 187 NavigateToURL(shell(), url); |
| 188 |
| 189 ASSERT_TRUE(ExecuteJavascript("getUserMediaAndClone();")); |
| 190 |
| 191 ExpectTitle("OK"); |
| 192 } |
| 193 |
| 194 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, |
| 195 GetUserMediaWithMandatorySourceID) { |
| 196 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 197 |
| 198 std::vector<std::string> audio_ids; |
| 199 std::vector<std::string> video_ids; |
| 200 GetSources(&audio_ids, &video_ids); |
| 201 |
| 202 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 203 |
| 204 // Test all combinations of mandatory sourceID; |
| 205 for (std::vector<std::string>::const_iterator video_it = video_ids.begin(); |
| 206 video_it != video_ids.end(); ++video_it) { |
| 207 for (std::vector<std::string>::const_iterator audio_it = audio_ids.begin(); |
| 208 audio_it != audio_ids.end(); ++audio_it) { |
| 209 NavigateToURL(shell(), url); |
| 210 EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult( |
| 211 GenerateGetUserMediaWithMandatorySourceID( |
| 212 kGetUserMediaAndStop, |
| 213 *audio_it, |
| 214 *video_it))); |
| 215 } |
| 216 } |
| 217 } |
| 218 |
| 219 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, |
| 220 GetUserMediaWithInvalidMandatorySourceID) { |
| 221 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 222 |
| 223 std::vector<std::string> audio_ids; |
| 224 std::vector<std::string> video_ids; |
| 225 GetSources(&audio_ids, &video_ids); |
| 226 |
| 227 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 228 |
| 229 // Test with invalid mandatory audio sourceID. |
| 230 NavigateToURL(shell(), url); |
| 231 EXPECT_EQ(kGetUserMediaFailed, ExecuteJavascriptAndReturnResult( |
| 232 GenerateGetUserMediaWithMandatorySourceID( |
| 233 kGetUserMediaAndStop, |
| 234 "something invalid", |
| 235 video_ids[0]))); |
| 236 |
| 237 // Test with invalid mandatory video sourceID. |
| 238 EXPECT_EQ(kGetUserMediaFailed, ExecuteJavascriptAndReturnResult( |
| 239 GenerateGetUserMediaWithMandatorySourceID( |
| 240 kGetUserMediaAndStop, |
| 241 audio_ids[0], |
| 242 "something invalid"))); |
| 243 |
| 244 // Test with empty mandatory audio sourceID. |
| 245 EXPECT_EQ(kGetUserMediaFailed, ExecuteJavascriptAndReturnResult( |
| 246 GenerateGetUserMediaWithMandatorySourceID( |
| 247 kGetUserMediaAndStop, |
| 248 "", |
| 249 video_ids[0]))); |
| 250 } |
| 251 |
| 252 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, |
| 253 GetUserMediaWithInvalidOptionalSourceID) { |
| 254 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 255 |
| 256 std::vector<std::string> audio_ids; |
| 257 std::vector<std::string> video_ids; |
| 258 GetSources(&audio_ids, &video_ids); |
| 259 |
| 260 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 261 |
| 262 // Test with invalid optional audio sourceID. |
| 263 NavigateToURL(shell(), url); |
| 264 EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult( |
| 265 GenerateGetUserMediaWithOptionalSourceID( |
| 266 kGetUserMediaAndStop, |
| 267 "something invalid", |
| 268 video_ids[0]))); |
| 269 |
| 270 // Test with invalid optional video sourceID. |
| 271 EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult( |
| 272 GenerateGetUserMediaWithOptionalSourceID( |
| 273 kGetUserMediaAndStop, |
| 274 audio_ids[0], |
| 275 "something invalid"))); |
| 276 |
| 277 // Test with empty optional audio sourceID. |
| 278 EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult( |
| 279 GenerateGetUserMediaWithOptionalSourceID( |
| 280 kGetUserMediaAndStop, |
| 281 "", |
| 282 video_ids[0]))); |
| 283 } |
| 284 |
| 285 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, TwoGetUserMediaAndStop) { |
| 286 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 287 |
| 288 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 289 NavigateToURL(shell(), url); |
| 290 |
| 291 ASSERT_TRUE(ExecuteJavascript( |
| 292 "twoGetUserMediaAndStop({video: true, audio: true});")); |
| 293 |
| 294 ExpectTitle("OK"); |
| 295 } |
| 296 |
| 297 // This test will make a simple getUserMedia page, verify that video is playing |
| 298 // in a simple local <video>, and for a couple of seconds, collect some |
| 299 // performance traces. |
| 300 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, |
| 301 TracePerformanceDuringGetUserMedia) { |
| 302 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 303 |
| 304 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 305 NavigateToURL(shell(), url); |
| 306 // Put getUserMedia to work and let it run for a couple of seconds. |
| 307 ASSERT_TRUE(ExecuteJavascript(base::StringPrintf( |
| 308 "%s({video: true}, 10);", kGetUserMediaAndWaitAndStop))); |
| 309 |
| 310 // Make sure the stream is up and running, then start collecting traces. |
| 311 ExpectTitle("Running..."); |
| 312 StartTracing(); |
| 313 |
| 314 // Wait until the page title changes to "OK". Do not sleep() here since that |
| 315 // would stop both this code and the browser underneath. |
| 316 ExpectTitle("OK"); |
| 317 StopTracing(); |
| 318 |
| 319 scoped_ptr<TraceAnalyzer> analyzer(CreateTraceAnalyzer()); |
| 320 analyzer->AssociateBeginEndEvents(); |
| 321 trace_analyzer::TraceEventVector events; |
| 322 analyzer->FindEvents( |
| 323 Query::EventNameIs("VideoCaptureController::OnIncomingCapturedFrame"), |
| 324 &events); |
| 325 ASSERT_GT(events.size(), 0u) |
| 326 << "Could not collect any samples during test, this is bad"; |
| 327 |
| 328 std::string duration_us; |
| 329 std::string interarrival_us; |
| 330 for (size_t i = 0; i != events.size(); ++i) { |
| 331 duration_us.append( |
| 332 base::StringPrintf("%d,", static_cast<int>(events[i]->duration))); |
| 333 } |
| 334 |
| 335 for (size_t i = 1; i < events.size(); ++i) { |
| 336 interarrival_us.append(base::StringPrintf( |
| 337 "%d,", |
| 338 static_cast<int>(events[i]->timestamp - events[i - 1]->timestamp))); |
| 339 } |
| 340 |
| 341 perf_test::PrintResultList( |
| 342 "video_capture", "", "sample_duration", duration_us, "us", true); |
| 343 |
| 344 perf_test::PrintResultList( |
| 345 "video_capture", "", "interarrival_time", interarrival_us, "us", true); |
| 346 } |
| 347 |
| 348 // This test calls getUserMedia and checks for aspect ratio behavior. |
| 349 IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, |
| 350 TestGetUserMediaAspectRatio) { |
| 351 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 352 |
| 353 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 354 |
| 355 std::string constraints_4_3 = GenerateGetUserMediaCall( |
| 356 kGetUserMediaAndAnalyseAndStop, 640, 640, 480, 480, 30, 30); |
| 357 std::string constraints_16_9 = GenerateGetUserMediaCall( |
| 358 kGetUserMediaAndAnalyseAndStop, 640, 640, 360, 360, 30, 30); |
| 359 |
| 360 // TODO(mcasas): add more aspect ratios, in particular 16:10 crbug.com/275594. |
| 361 |
| 362 NavigateToURL(shell(), url); |
| 363 ASSERT_TRUE(ExecuteJavascript(constraints_4_3)); |
| 364 ExpectTitle("4:3 letterbox"); |
| 365 |
| 366 NavigateToURL(shell(), url); |
| 367 ASSERT_TRUE(ExecuteJavascript(constraints_16_9)); |
| 368 ExpectTitle("16:9 letterbox"); |
| 369 } |
| 370 |
| 371 namespace { |
| 372 |
| 373 struct UserMediaSizes { |
| 374 int min_width; |
| 375 int max_width; |
| 376 int min_height; |
| 377 int max_height; |
| 378 int min_frame_rate; |
| 379 int max_frame_rate; |
| 380 }; |
| 381 |
| 382 } // namespace |
| 383 |
| 384 class WebRtcConstraintsBrowserTest |
| 385 : public WebRtcGetUserMediaBrowserTest, |
| 386 public testing::WithParamInterface<UserMediaSizes> { |
| 387 public: |
| 388 WebRtcConstraintsBrowserTest() : user_media_(GetParam()) {} |
| 389 const UserMediaSizes& user_media() const { return user_media_; } |
| 390 |
| 391 private: |
| 392 UserMediaSizes user_media_; |
| 393 }; |
| 394 |
| 395 // This test calls getUserMedia in sequence with different constraints. |
| 396 IN_PROC_BROWSER_TEST_P(WebRtcConstraintsBrowserTest, GetUserMediaConstraints) { |
| 397 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 398 |
| 399 GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); |
| 400 |
| 401 std::string call = GenerateGetUserMediaCall(kGetUserMediaAndStop, |
| 402 user_media().min_width, |
| 403 user_media().max_width, |
| 404 user_media().min_height, |
| 405 user_media().max_height, |
| 406 user_media().min_frame_rate, |
| 407 user_media().max_frame_rate); |
| 408 DVLOG(1) << "Calling getUserMedia: " << call; |
| 409 NavigateToURL(shell(), url); |
| 410 ASSERT_TRUE(ExecuteJavascript(call)); |
| 411 ExpectTitle("OK"); |
| 412 } |
| 413 |
| 414 static const UserMediaSizes kAllUserMediaSizes[] = { |
| 415 {320, 320, 180, 180, 30, 30}, |
| 416 {320, 320, 240, 240, 30, 30}, |
| 417 {640, 640, 360, 360, 30, 30}, |
| 418 {640, 640, 480, 480, 30, 30}, |
| 419 {960, 960, 720, 720, 30, 30}, |
| 420 {1280, 1280, 720, 720, 30, 30}, |
| 421 {1920, 1920, 1080, 1080, 30, 30}}; |
| 422 |
| 423 INSTANTIATE_TEST_CASE_P(UserMedia, |
| 424 WebRtcConstraintsBrowserTest, |
| 425 testing::ValuesIn(kAllUserMediaSizes)); |
| 426 |
| 427 } // namespace content |
OLD | NEW |