03493c09ef5285c4cb4356d9c8e6682940e62551
[platform/framework/web/crosswalk.git] / src / content / browser / media / webrtc_getusermedia_browsertest.cc
1 // Copyright 2014 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/command_line.h"
6 #include "base/debug/trace_event_impl.h"
7 #include "base/json/json_reader.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/test/trace_event_analyzer.h"
10 #include "base/values.h"
11 #include "content/browser/media/webrtc_internals.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/public/common/content_switches.h"
14 #include "content/public/test/browser_test_utils.h"
15 #include "content/public/test/content_browser_test_utils.h"
16 #include "content/public/test/test_utils.h"
17 #include "content/shell/browser/shell.h"
18 #include "content/test/webrtc_content_browsertest_base.h"
19 #include "net/test/embedded_test_server/embedded_test_server.h"
20 #include "testing/perf/perf_test.h"
21
22 #if defined(OS_WIN)
23 #include "base/win/windows_version.h"
24 #endif
25
26 using trace_analyzer::TraceAnalyzer;
27 using trace_analyzer::Query;
28 using trace_analyzer::TraceEventVector;
29
30 namespace {
31
32 static const char kGetUserMediaAndStop[] = "getUserMediaAndStop";
33 static const char kGetUserMediaAndGetStreamUp[] = "getUserMediaAndGetStreamUp";
34 static const char kGetUserMediaAndAnalyseAndStop[] =
35     "getUserMediaAndAnalyseAndStop";
36 static const char kGetUserMediaAndExpectFailure[] =
37     "getUserMediaAndExpectFailure";
38 static const char kRenderSameTrackMediastreamAndStop[] =
39     "renderSameTrackMediastreamAndStop";
40 static const char kRenderClonedMediastreamAndStop[] =
41     "renderClonedMediastreamAndStop";
42 static const char kRenderClonedTrackMediastreamAndStop[] =
43     "renderClonedTrackMediastreamAndStop";
44 static const char kRenderDuplicatedMediastreamAndStop[] =
45     "renderDuplicatedMediastreamAndStop";
46
47 // Results returned by JS.
48 static const char kOK[] = "OK";
49
50 std::string GenerateGetUserMediaWithMandatorySourceID(
51     const std::string& function_name,
52     const std::string& audio_source_id,
53     const std::string& video_source_id) {
54   const std::string audio_constraint =
55       "audio: {mandatory: { sourceId:\"" + audio_source_id + "\"}}, ";
56
57   const std::string video_constraint =
58       "video: {mandatory: { sourceId:\"" + video_source_id + "\"}}";
59   return function_name + "({" + audio_constraint + video_constraint + "});";
60 }
61
62 std::string GenerateGetUserMediaWithOptionalSourceID(
63     const std::string& function_name,
64     const std::string& audio_source_id,
65     const std::string& video_source_id) {
66   const std::string audio_constraint =
67       "audio: {optional: [{sourceId:\"" + audio_source_id + "\"}]}, ";
68
69   const std::string video_constraint =
70       "video: {optional: [{ sourceId:\"" + video_source_id + "\"}]}";
71   return function_name + "({" + audio_constraint + video_constraint + "});";
72 }
73
74 }  // namespace
75
76 namespace content {
77
78 class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest,
79                                      public testing::WithParamInterface<bool> {
80  public:
81   WebRtcGetUserMediaBrowserTest() : trace_log_(NULL) {}
82   virtual ~WebRtcGetUserMediaBrowserTest() {}
83
84   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
85     WebRtcContentBrowserTest::SetUpCommandLine(command_line);
86
87     bool enable_audio_track_processing = GetParam();
88     if (enable_audio_track_processing)
89       command_line->AppendSwitch(switches::kEnableAudioTrackProcessing);
90   }
91
92   void StartTracing() {
93     CHECK(trace_log_ == NULL) << "Can only can start tracing once";
94     trace_log_ = base::debug::TraceLog::GetInstance();
95     trace_log_->SetEnabled(base::debug::CategoryFilter("video"),
96                            base::debug::TraceLog::RECORDING_MODE,
97                            base::debug::TraceLog::ENABLE_SAMPLING);
98     // Check that we are indeed recording.
99     EXPECT_EQ(trace_log_->GetNumTracesRecorded(), 1);
100   }
101
102   void StopTracing() {
103     CHECK(message_loop_runner_ == NULL) << "Calling StopTracing more than once";
104     trace_log_->SetDisabled();
105     message_loop_runner_ = new MessageLoopRunner;
106     trace_log_->Flush(base::Bind(
107         &WebRtcGetUserMediaBrowserTest::OnTraceDataCollected,
108         base::Unretained(this)));
109     message_loop_runner_->Run();
110   }
111
112   void OnTraceDataCollected(
113       const scoped_refptr<base::RefCountedString>& events_str_ptr,
114       bool has_more_events) {
115     CHECK(!has_more_events);
116     recorded_trace_data_ = events_str_ptr;
117     message_loop_runner_->Quit();
118   }
119
120   TraceAnalyzer* CreateTraceAnalyzer() {
121     return TraceAnalyzer::Create("[" + recorded_trace_data_->data() + "]");
122   }
123
124   void RunGetUserMediaAndCollectMeasures(const int time_to_sample_secs,
125                                          const std::string& measure_filter,
126                                          const std::string& graph_name) {
127     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
128
129     GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
130     NavigateToURL(shell(), url);
131
132     // Put getUserMedia to work and let it run for a couple of seconds.
133     DCHECK(time_to_sample_secs);
134     ExecuteJavascriptAndWaitForOk(
135         base::StringPrintf("%s({video: true});",
136                            kGetUserMediaAndGetStreamUp));
137
138     // Now the stream is up and running, start collecting traces.
139     StartTracing();
140
141     // Let the stream run for a while in javascript.
142     ExecuteJavascriptAndWaitForOk(
143         base::StringPrintf("waitAndStopVideoTrack(%d);", time_to_sample_secs));
144
145     // Wait until the page title changes to "OK". Do not sleep() here since that
146     // would stop both this code and the browser underneath.
147     StopTracing();
148
149     scoped_ptr<TraceAnalyzer> analyzer(CreateTraceAnalyzer());
150     analyzer->AssociateBeginEndEvents();
151     trace_analyzer::TraceEventVector events;
152     DCHECK(measure_filter.size());
153     analyzer->FindEvents(
154         Query::EventNameIs(measure_filter),
155         &events);
156     ASSERT_GT(events.size(), 0u)
157         << "Could not collect any samples during test, this is bad";
158
159     std::string duration_us;
160     std::string interarrival_us;
161     for (size_t i = 0; i != events.size(); ++i) {
162       duration_us.append(
163           base::StringPrintf("%d,", static_cast<int>(events[i]->duration)));
164     }
165
166     for (size_t i = 1; i < events.size(); ++i) {
167       // The event |timestamp| comes in ns, divide to get us like |duration|.
168       interarrival_us.append(base::StringPrintf("%d,",
169           static_cast<int>((events[i]->timestamp - events[i - 1]->timestamp) /
170                            base::Time::kNanosecondsPerMicrosecond)));
171     }
172
173     perf_test::PrintResultList(
174         graph_name, "", "sample_duration", duration_us, "us", true);
175
176     perf_test::PrintResultList(
177         graph_name, "", "interarrival_time", interarrival_us, "us", true);
178   }
179
180   void GetSources(std::vector<std::string>* audio_ids,
181                   std::vector<std::string>* video_ids) {
182     GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
183     NavigateToURL(shell(), url);
184
185     std::string sources_as_json = ExecuteJavascriptAndReturnResult(
186         "getSources()");
187     EXPECT_FALSE(sources_as_json.empty());
188
189     int error_code;
190     std::string error_message;
191     scoped_ptr<base::Value> value(
192         base::JSONReader::ReadAndReturnError(sources_as_json,
193                                              base::JSON_ALLOW_TRAILING_COMMAS,
194                                              &error_code,
195                                              &error_message));
196
197     ASSERT_TRUE(value.get() != NULL) << error_message;
198     EXPECT_EQ(value->GetType(), base::Value::TYPE_LIST);
199
200     base::ListValue* values;
201     ASSERT_TRUE(value->GetAsList(&values));
202
203     for (base::ListValue::iterator it = values->begin();
204          it != values->end(); ++it) {
205       const base::DictionaryValue* dict;
206       std::string kind;
207       std::string id;
208       ASSERT_TRUE((*it)->GetAsDictionary(&dict));
209       ASSERT_TRUE(dict->GetString("kind", &kind));
210       ASSERT_TRUE(dict->GetString("id", &id));
211       ASSERT_FALSE(id.empty());
212       EXPECT_TRUE(kind == "audio" || kind == "video");
213       if (kind == "audio") {
214         audio_ids->push_back(id);
215       } else if (kind == "video") {
216         video_ids->push_back(id);
217       }
218     }
219     ASSERT_FALSE(audio_ids->empty());
220     ASSERT_FALSE(video_ids->empty());
221   }
222
223  private:
224   base::debug::TraceLog* trace_log_;
225   scoped_refptr<base::RefCountedString> recorded_trace_data_;
226   scoped_refptr<MessageLoopRunner> message_loop_runner_;
227 };
228
229 static const bool kRunTestsWithFlag[] = { false, true };
230 INSTANTIATE_TEST_CASE_P(WebRtcGetUserMediaBrowserTests,
231                         WebRtcGetUserMediaBrowserTest,
232                         testing::ValuesIn(kRunTestsWithFlag));
233
234 // These tests will all make a getUserMedia call with different constraints and
235 // see that the success callback is called. If the error callback is called or
236 // none of the callbacks are called the tests will simply time out and fail.
237 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) {
238   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
239
240   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
241   NavigateToURL(shell(), url);
242
243   ExecuteJavascriptAndWaitForOk(
244       base::StringPrintf("%s({video: true});", kGetUserMediaAndStop));
245 }
246
247 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
248                        RenderSameTrackMediastreamAndStop) {
249   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
250
251   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
252   NavigateToURL(shell(), url);
253
254   ExecuteJavascriptAndWaitForOk(
255       base::StringPrintf("%s({video: true});",
256                          kRenderSameTrackMediastreamAndStop));
257 }
258
259 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
260                        RenderClonedMediastreamAndStop) {
261   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
262
263   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
264   NavigateToURL(shell(), url);
265
266
267   ExecuteJavascriptAndWaitForOk(
268       base::StringPrintf("%s({video: true});",
269                          kRenderClonedMediastreamAndStop));
270 }
271
272 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
273                        kRenderClonedTrackMediastreamAndStop) {
274   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
275
276   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
277   NavigateToURL(shell(), url);
278
279   ExecuteJavascriptAndWaitForOk(
280       base::StringPrintf("%s({video: true});",
281                          kRenderClonedTrackMediastreamAndStop));
282 }
283
284 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
285                        kRenderDuplicatedMediastreamAndStop) {
286   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
287
288   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
289   NavigateToURL(shell(), url);
290
291   ExecuteJavascriptAndWaitForOk(
292       base::StringPrintf("%s({video: true});",
293                           kRenderDuplicatedMediastreamAndStop));
294 }
295
296 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
297                        GetAudioAndVideoStreamAndStop) {
298   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
299
300   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
301   NavigateToURL(shell(), url);
302
303   ExecuteJavascriptAndWaitForOk(base::StringPrintf(
304       "%s({video: true, audio: true});", kGetUserMediaAndStop));
305 }
306
307 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
308                        GetAudioAndVideoStreamAndClone) {
309   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
310
311   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
312   NavigateToURL(shell(), url);
313
314   ExecuteJavascriptAndWaitForOk("getUserMediaAndClone();");
315 }
316
317 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
318                        RenderVideoTrackInMultipleTagsAndPause) {
319   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
320
321   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
322   NavigateToURL(shell(), url);
323
324   ExecuteJavascriptAndWaitForOk("getUserMediaAndRenderInSeveralVideoTags();");
325 }
326
327
328
329 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
330                        GetUserMediaWithMandatorySourceID) {
331   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
332
333   std::vector<std::string> audio_ids;
334   std::vector<std::string> video_ids;
335   GetSources(&audio_ids, &video_ids);
336
337   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
338
339   // Test all combinations of mandatory sourceID;
340   for (std::vector<std::string>::const_iterator video_it = video_ids.begin();
341        video_it != video_ids.end(); ++video_it) {
342     for (std::vector<std::string>::const_iterator audio_it = audio_ids.begin();
343          audio_it != audio_ids.end(); ++audio_it) {
344       NavigateToURL(shell(), url);
345       EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult(
346           GenerateGetUserMediaWithMandatorySourceID(
347               kGetUserMediaAndStop,
348               *audio_it,
349               *video_it)));
350     }
351   }
352 }
353
354 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
355                        GetUserMediaWithInvalidMandatorySourceID) {
356   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
357
358   std::vector<std::string> audio_ids;
359   std::vector<std::string> video_ids;
360   GetSources(&audio_ids, &video_ids);
361
362   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
363
364   // Test with invalid mandatory audio sourceID.
365   NavigateToURL(shell(), url);
366   EXPECT_EQ("DevicesNotFoundError", ExecuteJavascriptAndReturnResult(
367       GenerateGetUserMediaWithMandatorySourceID(
368           kGetUserMediaAndExpectFailure,
369           "something invalid",
370           video_ids[0])));
371
372   // Test with invalid mandatory video sourceID.
373   EXPECT_EQ("DevicesNotFoundError", ExecuteJavascriptAndReturnResult(
374       GenerateGetUserMediaWithMandatorySourceID(
375           kGetUserMediaAndExpectFailure,
376           audio_ids[0],
377           "something invalid")));
378
379   // Test with empty mandatory audio sourceID.
380   EXPECT_EQ("DevicesNotFoundError", ExecuteJavascriptAndReturnResult(
381       GenerateGetUserMediaWithMandatorySourceID(
382           kGetUserMediaAndExpectFailure,
383           "",
384           video_ids[0])));
385 }
386
387 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
388                        GetUserMediaWithInvalidOptionalSourceID) {
389   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
390
391   std::vector<std::string> audio_ids;
392   std::vector<std::string> video_ids;
393   GetSources(&audio_ids, &video_ids);
394
395   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
396
397   // Test with invalid optional audio sourceID.
398   NavigateToURL(shell(), url);
399   EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult(
400       GenerateGetUserMediaWithOptionalSourceID(
401           kGetUserMediaAndStop,
402           "something invalid",
403           video_ids[0])));
404
405   // Test with invalid optional video sourceID.
406   EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult(
407       GenerateGetUserMediaWithOptionalSourceID(
408           kGetUserMediaAndStop,
409           audio_ids[0],
410           "something invalid")));
411
412   // Test with empty optional audio sourceID.
413   EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult(
414       GenerateGetUserMediaWithOptionalSourceID(
415           kGetUserMediaAndStop,
416           "",
417           video_ids[0])));
418 }
419
420 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, TwoGetUserMediaAndStop) {
421   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
422
423   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
424   NavigateToURL(shell(), url);
425
426   ExecuteJavascriptAndWaitForOk(
427       "twoGetUserMediaAndStop({video: true, audio: true});");
428 }
429
430 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
431                        GetUserMediaWithTooHighVideoConstraintsValues) {
432   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
433
434   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
435
436   int large_value = 99999;
437   std::string call = GenerateGetUserMediaCall(kGetUserMediaAndExpectFailure,
438                                               large_value,
439                                               large_value,
440                                               large_value,
441                                               large_value,
442                                               large_value,
443                                               large_value);
444   NavigateToURL(shell(), url);
445
446   // TODO(perkj): A proper error code should be returned by gUM.
447   EXPECT_EQ("TrackStartError", ExecuteJavascriptAndReturnResult(call));
448 }
449
450 // This test will make a simple getUserMedia page, verify that video is playing
451 // in a simple local <video>, and for a couple of seconds, collect some
452 // performance traces from VideoCaptureController colorspace conversion and
453 // potential resizing.
454 IN_PROC_BROWSER_TEST_P(
455     WebRtcGetUserMediaBrowserTest,
456     TraceVideoCaptureControllerPerformanceDuringGetUserMedia) {
457   RunGetUserMediaAndCollectMeasures(
458       10,
459       "VideoCaptureController::OnIncomingCapturedData",
460       "VideoCaptureController");
461 }
462
463 // This test calls getUserMedia and checks for aspect ratio behavior.
464 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
465                        TestGetUserMediaAspectRatio4To3) {
466   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
467
468   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
469
470   std::string constraints_4_3 = GenerateGetUserMediaCall(
471       kGetUserMediaAndAnalyseAndStop, 640, 640, 480, 480, 30, 30);
472
473   NavigateToURL(shell(), url);
474   ASSERT_EQ("w=640:h=480",
475             ExecuteJavascriptAndReturnResult(constraints_4_3));
476 }
477
478 // This test calls getUserMedia and checks for aspect ratio behavior.
479 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
480                        TestGetUserMediaAspectRatio16To9) {
481   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
482
483   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
484
485   std::string constraints_16_9 = GenerateGetUserMediaCall(
486       kGetUserMediaAndAnalyseAndStop, 640, 640, 360, 360, 30, 30);
487
488   NavigateToURL(shell(), url);
489   ASSERT_EQ("w=640:h=360",
490             ExecuteJavascriptAndReturnResult(constraints_16_9));
491 }
492
493 // This test calls getUserMedia and checks for aspect ratio behavior.
494 IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
495                        TestGetUserMediaAspectRatio1To1) {
496   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
497
498   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
499
500   std::string constraints_1_1 = GenerateGetUserMediaCall(
501       kGetUserMediaAndAnalyseAndStop, 320, 320, 320, 320, 30, 30);
502
503   NavigateToURL(shell(), url);
504   ASSERT_EQ("w=320:h=320",
505             ExecuteJavascriptAndReturnResult(constraints_1_1));
506 }
507
508 namespace {
509
510 struct UserMediaSizes {
511   int min_width;
512   int max_width;
513   int min_height;
514   int max_height;
515   int min_frame_rate;
516   int max_frame_rate;
517 };
518
519 }  // namespace
520
521 class WebRtcConstraintsBrowserTest
522     : public WebRtcContentBrowserTest,
523       public testing::WithParamInterface<UserMediaSizes> {
524  public:
525   WebRtcConstraintsBrowserTest() : user_media_(GetParam()) {}
526   const UserMediaSizes& user_media() const { return user_media_; }
527
528  private:
529   UserMediaSizes user_media_;
530 };
531
532 // This test calls getUserMedia in sequence with different constraints.
533 IN_PROC_BROWSER_TEST_P(WebRtcConstraintsBrowserTest, GetUserMediaConstraints) {
534   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
535
536   GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
537
538   std::string call = GenerateGetUserMediaCall(kGetUserMediaAndStop,
539                                               user_media().min_width,
540                                               user_media().max_width,
541                                               user_media().min_height,
542                                               user_media().max_height,
543                                               user_media().min_frame_rate,
544                                               user_media().max_frame_rate);
545   DVLOG(1) << "Calling getUserMedia: " << call;
546   NavigateToURL(shell(), url);
547   ExecuteJavascriptAndWaitForOk(call);
548 }
549
550 static const UserMediaSizes kAllUserMediaSizes[] = {
551     {320, 320, 180, 180, 30, 30},
552     {320, 320, 240, 240, 30, 30},
553     {640, 640, 360, 360, 30, 30},
554     {640, 640, 480, 480, 30, 30},
555     {960, 960, 720, 720, 30, 30},
556     {1280, 1280, 720, 720, 30, 30},
557     {1920, 1920, 1080, 1080, 30, 30}};
558
559 INSTANTIATE_TEST_CASE_P(UserMedia,
560                         WebRtcConstraintsBrowserTest,
561                         testing::ValuesIn(kAllUserMediaSizes));
562
563 }  // namespace content