diff options
Diffstat (limited to 'chromium/content/browser/media/webrtc_getusermedia_browsertest.cc')
-rw-r--r-- | chromium/content/browser/media/webrtc_getusermedia_browsertest.cc | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc b/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc new file mode 100644 index 00000000000..c7e1b4214e5 --- /dev/null +++ b/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc @@ -0,0 +1,607 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "base/debug/trace_event_impl.h" +#include "base/json/json_reader.h" +#include "base/strings/stringprintf.h" +#include "base/test/trace_event_analyzer.h" +#include "base/values.h" +#include "content/browser/media/webrtc_internals.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test_utils.h" +#include "content/public/test/test_utils.h" +#include "content/shell/browser/shell.h" +#include "content/test/webrtc_content_browsertest_base.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/perf/perf_test.h" + +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#endif + +using trace_analyzer::TraceAnalyzer; +using trace_analyzer::Query; +using trace_analyzer::TraceEventVector; + +namespace { + +static const char kGetUserMediaAndStop[] = "getUserMediaAndStop"; +static const char kGetUserMediaAndGetStreamUp[] = "getUserMediaAndGetStreamUp"; +static const char kGetUserMediaAndAnalyseAndStop[] = + "getUserMediaAndAnalyseAndStop"; +static const char kGetUserMediaAndExpectFailure[] = + "getUserMediaAndExpectFailure"; +static const char kRenderSameTrackMediastreamAndStop[] = + "renderSameTrackMediastreamAndStop"; +static const char kRenderClonedMediastreamAndStop[] = + "renderClonedMediastreamAndStop"; +static const char kRenderClonedTrackMediastreamAndStop[] = + "renderClonedTrackMediastreamAndStop"; +static const char kRenderDuplicatedMediastreamAndStop[] = + "renderDuplicatedMediastreamAndStop"; + +// Results returned by JS. +static const char kOK[] = "OK"; + +std::string GenerateGetUserMediaWithMandatorySourceID( + const std::string& function_name, + const std::string& audio_source_id, + const std::string& video_source_id) { + const std::string audio_constraint = + "audio: {mandatory: { sourceId:\"" + audio_source_id + "\"}}, "; + + const std::string video_constraint = + "video: {mandatory: { sourceId:\"" + video_source_id + "\"}}"; + return function_name + "({" + audio_constraint + video_constraint + "});"; +} + +std::string GenerateGetUserMediaWithOptionalSourceID( + const std::string& function_name, + const std::string& audio_source_id, + const std::string& video_source_id) { + const std::string audio_constraint = + "audio: {optional: [{sourceId:\"" + audio_source_id + "\"}]}, "; + + const std::string video_constraint = + "video: {optional: [{ sourceId:\"" + video_source_id + "\"}]}"; + return function_name + "({" + audio_constraint + video_constraint + "});"; +} + +} // namespace + +namespace content { + +class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest, + public testing::WithParamInterface<bool> { + public: + WebRtcGetUserMediaBrowserTest() : trace_log_(NULL) {} + virtual ~WebRtcGetUserMediaBrowserTest() {} + + virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { + WebRtcContentBrowserTest::SetUpCommandLine(command_line); + + bool enable_audio_track_processing = GetParam(); + if (!enable_audio_track_processing) + command_line->AppendSwitch(switches::kDisableAudioTrackProcessing); + } + + void StartTracing() { + CHECK(trace_log_ == NULL) << "Can only can start tracing once"; + trace_log_ = base::debug::TraceLog::GetInstance(); + trace_log_->SetEnabled(base::debug::CategoryFilter("video"), + base::debug::TraceLog::RECORDING_MODE, + base::debug::TraceLog::ENABLE_SAMPLING); + // Check that we are indeed recording. + EXPECT_EQ(trace_log_->GetNumTracesRecorded(), 1); + } + + void StopTracing() { + CHECK(message_loop_runner_ == NULL) << "Calling StopTracing more than once"; + trace_log_->SetDisabled(); + message_loop_runner_ = new MessageLoopRunner; + trace_log_->Flush(base::Bind( + &WebRtcGetUserMediaBrowserTest::OnTraceDataCollected, + base::Unretained(this))); + message_loop_runner_->Run(); + } + + void OnTraceDataCollected( + const scoped_refptr<base::RefCountedString>& events_str_ptr, + bool has_more_events) { + CHECK(!has_more_events); + recorded_trace_data_ = events_str_ptr; + message_loop_runner_->Quit(); + } + + TraceAnalyzer* CreateTraceAnalyzer() { + return TraceAnalyzer::Create("[" + recorded_trace_data_->data() + "]"); + } + + void RunGetUserMediaAndCollectMeasures(const int time_to_sample_secs, + const std::string& measure_filter, + const std::string& graph_name) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + // Put getUserMedia to work and let it run for a couple of seconds. + DCHECK(time_to_sample_secs); + ExecuteJavascriptAndWaitForOk( + base::StringPrintf("%s({video: true});", + kGetUserMediaAndGetStreamUp)); + + // Now the stream is up and running, start collecting traces. + StartTracing(); + + // Let the stream run for a while in javascript. + ExecuteJavascriptAndWaitForOk( + base::StringPrintf("waitAndStopVideoTrack(%d);", time_to_sample_secs)); + + // Wait until the page title changes to "OK". Do not sleep() here since that + // would stop both this code and the browser underneath. + StopTracing(); + + scoped_ptr<TraceAnalyzer> analyzer(CreateTraceAnalyzer()); + analyzer->AssociateBeginEndEvents(); + trace_analyzer::TraceEventVector events; + DCHECK(measure_filter.size()); + analyzer->FindEvents( + Query::EventNameIs(measure_filter), + &events); + ASSERT_GT(events.size(), 0u) + << "Could not collect any samples during test, this is bad"; + + std::string duration_us; + std::string interarrival_us; + for (size_t i = 0; i != events.size(); ++i) { + duration_us.append( + base::StringPrintf("%d,", static_cast<int>(events[i]->duration))); + } + + for (size_t i = 1; i < events.size(); ++i) { + // The event |timestamp| comes in ns, divide to get us like |duration|. + interarrival_us.append(base::StringPrintf("%d,", + static_cast<int>((events[i]->timestamp - events[i - 1]->timestamp) / + base::Time::kNanosecondsPerMicrosecond))); + } + + perf_test::PrintResultList( + graph_name, "", "sample_duration", duration_us, "us", true); + + perf_test::PrintResultList( + graph_name, "", "interarrival_time", interarrival_us, "us", true); + } + + void RunTwoGetTwoGetUserMediaWithDifferentContraints( + const std::string& constraints1, + const std::string& constraints2, + const std::string& expected_result) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + std::string command = "twoGetUserMedia(" + constraints1 + ',' + + constraints2 + ')'; + + EXPECT_EQ(expected_result, ExecuteJavascriptAndReturnResult(command)); + } + + void GetInputDevices(std::vector<std::string>* audio_ids, + std::vector<std::string>* video_ids) { + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + std::string devices_as_json = ExecuteJavascriptAndReturnResult( + "getSources()"); + EXPECT_FALSE(devices_as_json.empty()); + + int error_code; + std::string error_message; + scoped_ptr<base::Value> value( + base::JSONReader::ReadAndReturnError(devices_as_json, + base::JSON_ALLOW_TRAILING_COMMAS, + &error_code, + &error_message)); + + ASSERT_TRUE(value.get() != NULL) << error_message; + EXPECT_EQ(value->GetType(), base::Value::TYPE_LIST); + + base::ListValue* values; + ASSERT_TRUE(value->GetAsList(&values)); + + for (base::ListValue::iterator it = values->begin(); + it != values->end(); ++it) { + const base::DictionaryValue* dict; + std::string kind; + std::string device_id; + ASSERT_TRUE((*it)->GetAsDictionary(&dict)); + ASSERT_TRUE(dict->GetString("kind", &kind)); + ASSERT_TRUE(dict->GetString("id", &device_id)); + ASSERT_FALSE(device_id.empty()); + EXPECT_TRUE(kind == "audio" || kind == "video"); + if (kind == "audio") { + audio_ids->push_back(device_id); + } else if (kind == "video") { + video_ids->push_back(device_id); + } + } + ASSERT_FALSE(audio_ids->empty()); + ASSERT_FALSE(video_ids->empty()); + } + + private: + base::debug::TraceLog* trace_log_; + scoped_refptr<base::RefCountedString> recorded_trace_data_; + scoped_refptr<MessageLoopRunner> message_loop_runner_; +}; + +static const bool kRunTestsWithFlag[] = { false, true }; +INSTANTIATE_TEST_CASE_P(WebRtcGetUserMediaBrowserTests, + WebRtcGetUserMediaBrowserTest, + testing::ValuesIn(kRunTestsWithFlag)); + +// These tests will all make a getUserMedia call with different constraints and +// see that the success callback is called. If the error callback is called or +// none of the callbacks are called the tests will simply time out and fail. +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + ExecuteJavascriptAndWaitForOk( + base::StringPrintf("%s({video: true});", kGetUserMediaAndStop)); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + RenderSameTrackMediastreamAndStop) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + ExecuteJavascriptAndWaitForOk( + base::StringPrintf("%s({video: true});", + kRenderSameTrackMediastreamAndStop)); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + RenderClonedMediastreamAndStop) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + + ExecuteJavascriptAndWaitForOk( + base::StringPrintf("%s({video: true});", + kRenderClonedMediastreamAndStop)); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + kRenderClonedTrackMediastreamAndStop) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + ExecuteJavascriptAndWaitForOk( + base::StringPrintf("%s({video: true});", + kRenderClonedTrackMediastreamAndStop)); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + kRenderDuplicatedMediastreamAndStop) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + ExecuteJavascriptAndWaitForOk( + base::StringPrintf("%s({video: true});", + kRenderDuplicatedMediastreamAndStop)); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + GetAudioAndVideoStreamAndStop) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + ExecuteJavascriptAndWaitForOk(base::StringPrintf( + "%s({video: true, audio: true});", kGetUserMediaAndStop)); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + GetAudioAndVideoStreamAndClone) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + ExecuteJavascriptAndWaitForOk("getUserMediaAndClone();"); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + RenderVideoTrackInMultipleTagsAndPause) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + ExecuteJavascriptAndWaitForOk("getUserMediaAndRenderInSeveralVideoTags();"); +} + + + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + GetUserMediaWithMandatorySourceID) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + std::vector<std::string> audio_ids; + std::vector<std::string> video_ids; + GetInputDevices(&audio_ids, &video_ids); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + // Test all combinations of mandatory sourceID; + for (std::vector<std::string>::const_iterator video_it = video_ids.begin(); + video_it != video_ids.end(); ++video_it) { + for (std::vector<std::string>::const_iterator audio_it = audio_ids.begin(); + audio_it != audio_ids.end(); ++audio_it) { + NavigateToURL(shell(), url); + EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult( + GenerateGetUserMediaWithMandatorySourceID( + kGetUserMediaAndStop, + *audio_it, + *video_it))); + } + } +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + GetUserMediaWithInvalidMandatorySourceID) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + std::vector<std::string> audio_ids; + std::vector<std::string> video_ids; + GetInputDevices(&audio_ids, &video_ids); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + // Test with invalid mandatory audio sourceID. + NavigateToURL(shell(), url); + EXPECT_EQ("DevicesNotFoundError", ExecuteJavascriptAndReturnResult( + GenerateGetUserMediaWithMandatorySourceID( + kGetUserMediaAndExpectFailure, + "something invalid", + video_ids[0]))); + + // Test with invalid mandatory video sourceID. + EXPECT_EQ("DevicesNotFoundError", ExecuteJavascriptAndReturnResult( + GenerateGetUserMediaWithMandatorySourceID( + kGetUserMediaAndExpectFailure, + audio_ids[0], + "something invalid"))); + + // Test with empty mandatory audio sourceID. + EXPECT_EQ("DevicesNotFoundError", ExecuteJavascriptAndReturnResult( + GenerateGetUserMediaWithMandatorySourceID( + kGetUserMediaAndExpectFailure, + "", + video_ids[0]))); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + GetUserMediaWithInvalidOptionalSourceID) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + std::vector<std::string> audio_ids; + std::vector<std::string> video_ids; + GetInputDevices(&audio_ids, &video_ids); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + // Test with invalid optional audio sourceID. + NavigateToURL(shell(), url); + EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult( + GenerateGetUserMediaWithOptionalSourceID( + kGetUserMediaAndStop, + "something invalid", + video_ids[0]))); + + // Test with invalid optional video sourceID. + EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult( + GenerateGetUserMediaWithOptionalSourceID( + kGetUserMediaAndStop, + audio_ids[0], + "something invalid"))); + + // Test with empty optional audio sourceID. + EXPECT_EQ(kOK, ExecuteJavascriptAndReturnResult( + GenerateGetUserMediaWithOptionalSourceID( + kGetUserMediaAndStop, + "", + video_ids[0]))); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, TwoGetUserMediaAndStop) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + NavigateToURL(shell(), url); + + ExecuteJavascriptAndWaitForOk( + "twoGetUserMediaAndStop({video: true, audio: true});"); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + TwoGetUserMediaWithEqualConstraints) { + std::string constraints1 = "{video: true, audio: true}"; + const std::string& constraints2 = constraints1; + std::string expected_result = "w=640:h=480-w=640:h=480"; + + RunTwoGetTwoGetUserMediaWithDifferentContraints(constraints1, constraints2, + expected_result); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + TwoGetUserMediaWithSecondVideoCropped) { + std::string constraints1 = "{video: true}"; + std::string constraints2 = "{video: {mandatory: {maxHeight: 360}}}"; + std::string expected_result = "w=640:h=480-w=640:h=360"; + RunTwoGetTwoGetUserMediaWithDifferentContraints(constraints1, constraints2, + expected_result); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + TwoGetUserMediaWithFirstHdSecondVga) { + std::string constraints1 = + "{video: {mandatory: {minWidth:1280 , minHeight: 720}}}"; + std::string constraints2 = + "{video: {mandatory: {maxWidth:640 , maxHeight: 480}}}"; + std::string expected_result = "w=1280:h=720-w=640:h=480"; + RunTwoGetTwoGetUserMediaWithDifferentContraints(constraints1, constraints2, + expected_result); +} + +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + GetUserMediaWithTooHighVideoConstraintsValues) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + int large_value = 99999; + std::string call = GenerateGetUserMediaCall(kGetUserMediaAndExpectFailure, + large_value, + large_value, + large_value, + large_value, + large_value, + large_value); + NavigateToURL(shell(), url); + + // TODO(perkj): A proper error code should be returned by gUM. + EXPECT_EQ("TrackStartError", ExecuteJavascriptAndReturnResult(call)); +} + +// This test will make a simple getUserMedia page, verify that video is playing +// in a simple local <video>, and for a couple of seconds, collect some +// performance traces from VideoCaptureController colorspace conversion and +// potential resizing. +IN_PROC_BROWSER_TEST_P( + WebRtcGetUserMediaBrowserTest, + TraceVideoCaptureControllerPerformanceDuringGetUserMedia) { + RunGetUserMediaAndCollectMeasures( + 10, + "VideoCaptureController::OnIncomingCapturedData", + "VideoCaptureController"); +} + +// This test calls getUserMedia and checks for aspect ratio behavior. +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + TestGetUserMediaAspectRatio4To3) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + std::string constraints_4_3 = GenerateGetUserMediaCall( + kGetUserMediaAndAnalyseAndStop, 640, 640, 480, 480, 10, 30); + + NavigateToURL(shell(), url); + ASSERT_EQ("w=640:h=480", + ExecuteJavascriptAndReturnResult(constraints_4_3)); +} + +// This test calls getUserMedia and checks for aspect ratio behavior. +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + TestGetUserMediaAspectRatio16To9) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + std::string constraints_16_9 = GenerateGetUserMediaCall( + kGetUserMediaAndAnalyseAndStop, 640, 640, 360, 360, 10, 30); + + NavigateToURL(shell(), url); + ASSERT_EQ("w=640:h=360", + ExecuteJavascriptAndReturnResult(constraints_16_9)); +} + +// This test calls getUserMedia and checks for aspect ratio behavior. +IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, + TestGetUserMediaAspectRatio1To1) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + std::string constraints_1_1 = GenerateGetUserMediaCall( + kGetUserMediaAndAnalyseAndStop, 320, 320, 320, 320, 10, 30); + + NavigateToURL(shell(), url); + ASSERT_EQ("w=320:h=320", + ExecuteJavascriptAndReturnResult(constraints_1_1)); +} + +namespace { + +struct UserMediaSizes { + int min_width; + int max_width; + int min_height; + int max_height; + int min_frame_rate; + int max_frame_rate; +}; + +} // namespace + +class WebRtcConstraintsBrowserTest + : public WebRtcContentBrowserTest, + public testing::WithParamInterface<UserMediaSizes> { + public: + WebRtcConstraintsBrowserTest() : user_media_(GetParam()) {} + const UserMediaSizes& user_media() const { return user_media_; } + + private: + UserMediaSizes user_media_; +}; + +// This test calls getUserMedia in sequence with different constraints. +IN_PROC_BROWSER_TEST_P(WebRtcConstraintsBrowserTest, GetUserMediaConstraints) { + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html")); + + std::string call = GenerateGetUserMediaCall(kGetUserMediaAndStop, + user_media().min_width, + user_media().max_width, + user_media().min_height, + user_media().max_height, + user_media().min_frame_rate, + user_media().max_frame_rate); + DVLOG(1) << "Calling getUserMedia: " << call; + NavigateToURL(shell(), url); + ExecuteJavascriptAndWaitForOk(call); +} + +static const UserMediaSizes kAllUserMediaSizes[] = { + {320, 320, 180, 180, 10, 30}, + {320, 320, 240, 240, 10, 30}, + {640, 640, 360, 360, 10, 30}, + {640, 640, 480, 480, 10, 30}, + {960, 960, 720, 720, 10, 30}, + {1280, 1280, 720, 720, 10, 30}}; + +INSTANTIATE_TEST_CASE_P(UserMedia, + WebRtcConstraintsBrowserTest, + testing::ValuesIn(kAllUserMediaSizes)); + +} // namespace content |