| Index: content/browser/media/webrtc_getusermedia_browsertest.cc
|
| diff --git a/content/browser/media/webrtc_getusermedia_browsertest.cc b/content/browser/media/webrtc_getusermedia_browsertest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..df7d8fa9ef76e58872abb08e5f25a3c025bbb8ab
|
| --- /dev/null
|
| +++ b/content/browser/media/webrtc_getusermedia_browsertest.cc
|
| @@ -0,0 +1,427 @@
|
| +// Copyright (c) 2012 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/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/test/browser_test_utils.h"
|
| +#include "content/public/test/test_utils.h"
|
| +#include "content/shell/browser/shell.h"
|
| +#include "content/test/content_browser_test_utils.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 kGetUserMediaAndWaitAndStop[] = "getUserMediaAndWaitAndStop";
|
| +static const char kGetUserMediaAndAnalyseAndStop[] =
|
| + "getUserMediaAndAnalyseAndStop";
|
| +
|
| +// Results returned by JS.
|
| +static const char kOK[] = "OK";
|
| +static const char kGetUserMediaFailed[] =
|
| + "GetUserMedia call failed with code undefined";
|
| +
|
| +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:
|
| + WebRtcGetUserMediaBrowserTest() : trace_log_(NULL) {}
|
| + virtual ~WebRtcGetUserMediaBrowserTest() {}
|
| +
|
| + 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 GetSources(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 sources_as_json = ExecuteJavascriptAndReturnResult(
|
| + "getSources()");
|
| + EXPECT_FALSE(sources_as_json.empty());
|
| +
|
| + int error_code;
|
| + std::string error_message;
|
| + scoped_ptr<base::Value> value(
|
| + base::JSONReader::ReadAndReturnError(sources_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 id;
|
| + ASSERT_TRUE((*it)->GetAsDictionary(&dict));
|
| + ASSERT_TRUE(dict->GetString("kind", &kind));
|
| + ASSERT_TRUE(dict->GetString("id", &id));
|
| + ASSERT_FALSE(id.empty());
|
| + EXPECT_TRUE(kind == "audio" || kind == "video");
|
| + if (kind == "audio") {
|
| + audio_ids->push_back(id);
|
| + } else if (kind == "video") {
|
| + video_ids->push_back(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_;
|
| +};
|
| +
|
| +// 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_F(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) {
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| +
|
| + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
|
| + NavigateToURL(shell(), url);
|
| +
|
| + ASSERT_TRUE(ExecuteJavascript(
|
| + base::StringPrintf("%s({video: true});", kGetUserMediaAndStop)));
|
| +
|
| + ExpectTitle("OK");
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
|
| + GetAudioAndVideoStreamAndStop) {
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| +
|
| + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
|
| + NavigateToURL(shell(), url);
|
| +
|
| + ASSERT_TRUE(ExecuteJavascript(base::StringPrintf(
|
| + "%s({video: true, audio: true});", kGetUserMediaAndStop)));
|
| +
|
| + ExpectTitle("OK");
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
|
| + GetAudioAndVideoStreamAndClone) {
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| +
|
| + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
|
| + NavigateToURL(shell(), url);
|
| +
|
| + ASSERT_TRUE(ExecuteJavascript("getUserMediaAndClone();"));
|
| +
|
| + ExpectTitle("OK");
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
|
| + GetUserMediaWithMandatorySourceID) {
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| +
|
| + std::vector<std::string> audio_ids;
|
| + std::vector<std::string> video_ids;
|
| + GetSources(&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_F(WebRtcGetUserMediaBrowserTest,
|
| + GetUserMediaWithInvalidMandatorySourceID) {
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| +
|
| + std::vector<std::string> audio_ids;
|
| + std::vector<std::string> video_ids;
|
| + GetSources(&audio_ids, &video_ids);
|
| +
|
| + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
|
| +
|
| + // Test with invalid mandatory audio sourceID.
|
| + NavigateToURL(shell(), url);
|
| + EXPECT_EQ(kGetUserMediaFailed, ExecuteJavascriptAndReturnResult(
|
| + GenerateGetUserMediaWithMandatorySourceID(
|
| + kGetUserMediaAndStop,
|
| + "something invalid",
|
| + video_ids[0])));
|
| +
|
| + // Test with invalid mandatory video sourceID.
|
| + EXPECT_EQ(kGetUserMediaFailed, ExecuteJavascriptAndReturnResult(
|
| + GenerateGetUserMediaWithMandatorySourceID(
|
| + kGetUserMediaAndStop,
|
| + audio_ids[0],
|
| + "something invalid")));
|
| +
|
| + // Test with empty mandatory audio sourceID.
|
| + EXPECT_EQ(kGetUserMediaFailed, ExecuteJavascriptAndReturnResult(
|
| + GenerateGetUserMediaWithMandatorySourceID(
|
| + kGetUserMediaAndStop,
|
| + "",
|
| + video_ids[0])));
|
| +}
|
| +
|
| +IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
|
| + GetUserMediaWithInvalidOptionalSourceID) {
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| +
|
| + std::vector<std::string> audio_ids;
|
| + std::vector<std::string> video_ids;
|
| + GetSources(&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_F(WebRtcGetUserMediaBrowserTest, TwoGetUserMediaAndStop) {
|
| + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
|
| +
|
| + GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
|
| + NavigateToURL(shell(), url);
|
| +
|
| + ASSERT_TRUE(ExecuteJavascript(
|
| + "twoGetUserMediaAndStop({video: true, audio: true});"));
|
| +
|
| + ExpectTitle("OK");
|
| +}
|
| +
|
| +// 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.
|
| +IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
|
| + TracePerformanceDuringGetUserMedia) {
|
| + 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.
|
| + ASSERT_TRUE(ExecuteJavascript(base::StringPrintf(
|
| + "%s({video: true}, 10);", kGetUserMediaAndWaitAndStop)));
|
| +
|
| + // Make sure the stream is up and running, then start collecting traces.
|
| + ExpectTitle("Running...");
|
| + StartTracing();
|
| +
|
| + // Wait until the page title changes to "OK". Do not sleep() here since that
|
| + // would stop both this code and the browser underneath.
|
| + ExpectTitle("OK");
|
| + StopTracing();
|
| +
|
| + scoped_ptr<TraceAnalyzer> analyzer(CreateTraceAnalyzer());
|
| + analyzer->AssociateBeginEndEvents();
|
| + trace_analyzer::TraceEventVector events;
|
| + analyzer->FindEvents(
|
| + Query::EventNameIs("VideoCaptureController::OnIncomingCapturedFrame"),
|
| + &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) {
|
| + interarrival_us.append(base::StringPrintf(
|
| + "%d,",
|
| + static_cast<int>(events[i]->timestamp - events[i - 1]->timestamp)));
|
| + }
|
| +
|
| + perf_test::PrintResultList(
|
| + "video_capture", "", "sample_duration", duration_us, "us", true);
|
| +
|
| + perf_test::PrintResultList(
|
| + "video_capture", "", "interarrival_time", interarrival_us, "us", true);
|
| +}
|
| +
|
| +// This test calls getUserMedia and checks for aspect ratio behavior.
|
| +IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
|
| + TestGetUserMediaAspectRatio) {
|
| + 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, 30, 30);
|
| + std::string constraints_16_9 = GenerateGetUserMediaCall(
|
| + kGetUserMediaAndAnalyseAndStop, 640, 640, 360, 360, 30, 30);
|
| +
|
| + // TODO(mcasas): add more aspect ratios, in particular 16:10 crbug.com/275594.
|
| +
|
| + NavigateToURL(shell(), url);
|
| + ASSERT_TRUE(ExecuteJavascript(constraints_4_3));
|
| + ExpectTitle("4:3 letterbox");
|
| +
|
| + NavigateToURL(shell(), url);
|
| + ASSERT_TRUE(ExecuteJavascript(constraints_16_9));
|
| + ExpectTitle("16:9 letterbox");
|
| +}
|
| +
|
| +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 WebRtcGetUserMediaBrowserTest,
|
| + 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);
|
| + ASSERT_TRUE(ExecuteJavascript(call));
|
| + ExpectTitle("OK");
|
| +}
|
| +
|
| +static const UserMediaSizes kAllUserMediaSizes[] = {
|
| + {320, 320, 180, 180, 30, 30},
|
| + {320, 320, 240, 240, 30, 30},
|
| + {640, 640, 360, 360, 30, 30},
|
| + {640, 640, 480, 480, 30, 30},
|
| + {960, 960, 720, 720, 30, 30},
|
| + {1280, 1280, 720, 720, 30, 30},
|
| + {1920, 1920, 1080, 1080, 30, 30}};
|
| +
|
| +INSTANTIATE_TEST_CASE_P(UserMedia,
|
| + WebRtcConstraintsBrowserTest,
|
| + testing::ValuesIn(kAllUserMediaSizes));
|
| +
|
| +} // namespace content
|
|
|