Commit 199c6b4e authored by Henrik Boström's avatar Henrik Boström Committed by Commit Bot

Delete WebRtcRtpBrowserTest.

Tests that can be expressed as LayoutTests (preferreably Web Platform
Tests) rather than browser tests should. Browser tests are slow to run
and a maintenance burden.

The WebRtcRtpBrowserTests are mainly testing behaviors of adding and
removing tracks/streams and asserting that the expected outcomes.

- The essentials of these tests are already covered in
  external/wpt/webrtc/ which we are actively maintaining and updating in
  preparation for Unified Plan and RTCRtpTransceiver support. Almost all
  of it is overlapping.
- The WebRtcRtpBrowserTests were not written to test behaviors, but
  functions. Each test is asserting a lot of unrelated behaviors.
- When running with Unified Plan/RTCRtpTransceiver (WIP CL:
  https://chromium-review.googlesource.com/c/chromium/src/+/1025771)
  these tests start failing. I started updating these tests but the
  failures were due to Plan B assumptions (problems in the tests, not in
  the implementation).
- Debugging this part of the code is slow and cumbersome.
- I won't miss any of these tests.

Conclusion: Nuke it.

Bug: 773472, 777617
Change-Id: I099992f1783914d4fb1d5c2d952ff977ec4cc513
Reviewed-on: https://chromium-review.googlesource.com/1100891Reviewed-by: default avatarPatrik Höglund <phoglund@chromium.org>
Commit-Queue: Henrik Boström <hbos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567283}
parent be8344a8
......@@ -154,13 +154,6 @@ std::vector<std::string> JsonArrayToVectorOfStrings(
} // namespace
WebRtcTestBase::TrackEvent::TrackEvent(const std::string& track_id)
: track_id(track_id) {}
WebRtcTestBase::TrackEvent::TrackEvent(const TrackEvent&) = default;
WebRtcTestBase::TrackEvent::~TrackEvent() = default;
WebRtcTestBase::WebRtcTestBase(): detect_errors_in_javascript_(false) {
// The handler gets set for each test method, but that's fine since this
// set operation is idempotent.
......@@ -607,151 +600,6 @@ void WebRtcTestBase::EnableOpusDtx(content::WebContents* tab) const {
EXPECT_EQ("ok-forced", ExecuteJavascript("forceOpusDtx()", tab));
}
void WebRtcTestBase::CreateAndAddStreams(content::WebContents* tab,
size_t count) const {
EXPECT_EQ(
"ok-streams-created-and-added",
ExecuteJavascript(
"createAndAddStreams(" + base::NumberToString(count) + ")", tab));
}
void WebRtcTestBase::VerifyRtpSenders(
content::WebContents* tab,
base::Optional<size_t> expected_num_tracks) const {
std::string javascript =
expected_num_tracks ? "verifyRtpSenders(" +
base::NumberToString(*expected_num_tracks) + ")"
: "verifyRtpSenders()";
EXPECT_EQ("ok-senders-verified", ExecuteJavascript(javascript, tab));
}
void WebRtcTestBase::VerifyRtpReceivers(
content::WebContents* tab,
base::Optional<size_t> expected_num_tracks) const {
std::string javascript =
expected_num_tracks ? "verifyRtpReceivers(" +
base::NumberToString(*expected_num_tracks) + ")"
: "verifyRtpReceivers()";
EXPECT_EQ("ok-receivers-verified", ExecuteJavascript(javascript, tab));
}
std::vector<std::string> WebRtcTestBase::CreateAndAddAudioAndVideoTrack(
content::WebContents* tab,
StreamArgumentType stream_argument_type) const {
const char* string_argument_type_str = nullptr;
switch (stream_argument_type) {
case StreamArgumentType::NO_STREAM:
string_argument_type_str = "'no-stream'";
break;
case StreamArgumentType::SHARED_STREAM:
string_argument_type_str = "'shared-stream'";
break;
case StreamArgumentType::INDIVIDUAL_STREAMS:
string_argument_type_str = "'individual-streams'";
break;
}
std::string result =
ExecuteJavascript(base::StringPrintf("createAndAddAudioAndVideoTrack(%s)",
string_argument_type_str),
tab);
EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE));
std::vector<std::string> ids = base::SplitString(
result.substr(3), " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
EXPECT_EQ(4u, ids.size());
return ids;
}
void WebRtcTestBase::RemoveTrack(content::WebContents* tab,
const std::string& track_id) const {
EXPECT_EQ(
"ok-sender-removed",
ExecuteJavascript(
base::StringPrintf("removeTrack('%s')", track_id.c_str()), tab));
}
bool WebRtcTestBase::HasLocalStreamWithTrack(
content::WebContents* tab,
const std::string& stream_id,
const std::string& track_id) const {
return HasStreamWithTrack(tab, "hasLocalStreamWithTrack", stream_id,
track_id);
}
bool WebRtcTestBase::HasRemoteStreamWithTrack(
content::WebContents* tab,
const std::string& stream_id,
const std::string& track_id) const {
return HasStreamWithTrack(tab, "hasRemoteStreamWithTrack", stream_id,
track_id);
}
bool WebRtcTestBase::HasStreamWithTrack(content::WebContents* tab,
const char* function_name,
std::string stream_id,
std::string track_id) const {
if (stream_id != kUndefined)
stream_id = "'" + stream_id + "'";
std::string javascript = base::StringPrintf(
"%s(%s, '%s')", function_name, stream_id.c_str(), track_id.c_str());
std::string result = ExecuteJavascript(javascript, tab);
EXPECT_TRUE(result == "ok-stream-with-track-found" ||
result == "ok-stream-with-track-not-found");
return result == "ok-stream-with-track-found";
}
bool WebRtcTestBase::HasSenderWithTrack(content::WebContents* tab,
std::string track_id) const {
std::string javascript =
base::StringPrintf("hasSenderWithTrack('%s')", track_id.c_str());
std::string result = ExecuteJavascript(javascript, tab);
EXPECT_TRUE(result == "ok-sender-with-track-found" ||
result == "ok-sender-with-track-not-found");
return result == "ok-sender-with-track-found";
}
bool WebRtcTestBase::HasReceiverWithTrack(content::WebContents* tab,
std::string track_id) const {
std::string javascript =
base::StringPrintf("hasReceiverWithTrack('%s')", track_id.c_str());
std::string result = ExecuteJavascript(javascript, tab);
EXPECT_TRUE(result == "ok-receiver-with-track-found" ||
result == "ok-receiver-with-track-not-found");
return result == "ok-receiver-with-track-found";
}
size_t WebRtcTestBase::GetNegotiationNeededCount(
content::WebContents* tab) const {
std::string result = ExecuteJavascript("getNegotiationNeededCount()", tab);
EXPECT_TRUE(base::StartsWith(result, "ok-negotiation-count-is-",
base::CompareCase::SENSITIVE));
size_t count = 0;
EXPECT_TRUE(base::StringToSizeT(result.substr(24), &count));
return count;
}
std::vector<WebRtcTestBase::TrackEvent> WebRtcTestBase::GetTrackEvents(
content::WebContents* tab) const {
std::string result = ExecuteJavascript("getTrackEvents()", tab);
EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE));
std::vector<std::string> tokens = base::SplitString(
result.substr(3), " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
std::vector<TrackEvent> events;
for (size_t i = 0; i < tokens.size(); ++i) {
if (tokens[i] == "RTCTrackEvent") {
DCHECK_LT(i + 1, tokens.size());
events.push_back(TrackEvent(tokens[++i]));
} else {
DCHECK(!events.empty());
events[events.size() - 1].stream_ids.push_back(tokens[i]);
}
}
return events;
}
void WebRtcTestBase::CollectGarbage(content::WebContents* tab) const {
EXPECT_EQ("ok-gc", ExecuteJavascript("collectGarbage()", tab));
}
std::string WebRtcTestBase::GetDesktopMediaStream(content::WebContents* tab) {
DCHECK(static_cast<bool>(LoadDesktopCaptureExtension()));
......
......@@ -58,15 +58,6 @@ class WebRtcTestBase : public InProcessBrowserTest {
INDIVIDUAL_STREAMS
};
struct TrackEvent {
explicit TrackEvent(const std::string& track_id);
TrackEvent(const TrackEvent&);
~TrackEvent();
std::string track_id;
std::vector<std::string> stream_ids;
};
protected:
WebRtcTestBase();
~WebRtcTestBase() override;
......@@ -223,33 +214,6 @@ class WebRtcTestBase : public InProcessBrowserTest {
// Add 'usedtx=1' to the offer SDP.
void EnableOpusDtx(content::WebContents* tab) const;
void CreateAndAddStreams(content::WebContents* tab, size_t count) const;
void VerifyRtpSenders(content::WebContents* tab,
base::Optional<size_t> expected_num_tracks =
base::Optional<size_t>()) const;
void VerifyRtpReceivers(content::WebContents* tab,
base::Optional<size_t> expected_num_tracks =
base::Optional<size_t>()) const;
std::vector<std::string> CreateAndAddAudioAndVideoTrack(
content::WebContents* tab,
StreamArgumentType stream_argument_type) const;
void RemoveTrack(content::WebContents* tab,
const std::string& track_id) const;
bool HasLocalStreamWithTrack(content::WebContents* tab,
const std::string& stream_id,
const std::string& track_id) const;
bool HasRemoteStreamWithTrack(content::WebContents* tab,
const std::string& stream_id,
const std::string& track_id) const;
bool HasSenderWithTrack(content::WebContents* tab,
std::string track_id) const;
bool HasReceiverWithTrack(content::WebContents* tab,
std::string track_id) const;
size_t GetNegotiationNeededCount(content::WebContents* tab) const;
std::vector<TrackEvent> GetTrackEvents(content::WebContents* tab) const;
// Performs garbage collection with "gc()". Requires command line switch
// |kJavaScriptFlags| with "--expose-gc".
void CollectGarbage(content::WebContents* tab) const;
// Try to open a dekstop media stream, and return the stream id.
// On failure, will return empty string.
std::string GetDesktopMediaStream(content::WebContents* tab);
......
// Copyright 2017 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 <string>
#include <vector>
#include "base/command_line.h"
#include "chrome/browser/media/webrtc/webrtc_browsertest_base.h"
#include "content/public/common/content_switches.h"
#include "media/base/media_switches.h"
static const char kMainWebrtcTestHtmlPage[] = "/webrtc/webrtc_jsep01_test.html";
class WebRtcRtpBrowserTest : public WebRtcTestBase {
public:
WebRtcRtpBrowserTest() : left_tab_(nullptr), right_tab_(nullptr) {}
void SetUpInProcessBrowserTestFixture() override {
DetectErrorsInJavaScript();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
"RTCRtpSenderReplaceTrack");
// Required by |CollectGarbage|.
command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
}
protected:
void StartServer() { ASSERT_TRUE(embedded_test_server()->Start()); }
void OpenTab(content::WebContents** tab) {
// TODO(hbos): Just open the tab, don't "AndGetUserMediaInNewTab".
*tab = OpenTestPageAndGetUserMediaInNewTab(kMainWebrtcTestHtmlPage);
}
void StartServerAndOpenTabs() {
StartServer();
OpenTab(&left_tab_);
OpenTab(&right_tab_);
}
const TrackEvent* FindTrackEvent(const std::vector<TrackEvent>& track_events,
const std::string& track_id) {
auto event_it = std::find_if(track_events.begin(), track_events.end(),
[&track_id](const TrackEvent& event) {
return event.track_id == track_id;
});
return event_it != track_events.end() ? &(*event_it) : nullptr;
}
content::WebContents* left_tab_;
content::WebContents* right_tab_;
};
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, GetSenders) {
StartServerAndOpenTabs();
SetupPeerconnectionWithoutLocalStream(left_tab_);
CreateAndAddStreams(left_tab_, 3);
SetupPeerconnectionWithoutLocalStream(right_tab_);
CreateAndAddStreams(right_tab_, 1);
NegotiateCall(left_tab_, right_tab_);
VerifyRtpSenders(left_tab_, 6);
VerifyRtpSenders(right_tab_, 2);
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, GetReceivers) {
StartServerAndOpenTabs();
SetupPeerconnectionWithoutLocalStream(left_tab_);
CreateAndAddStreams(left_tab_, 3);
SetupPeerconnectionWithoutLocalStream(right_tab_);
CreateAndAddStreams(right_tab_, 1);
NegotiateCall(left_tab_, right_tab_);
VerifyRtpReceivers(left_tab_, 2);
VerifyRtpReceivers(right_tab_, 6);
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, AddAndRemoveTracksWithoutStream) {
StartServerAndOpenTabs();
SetupPeerconnectionWithoutLocalStream(left_tab_);
SetupPeerconnectionWithoutLocalStream(right_tab_);
// TODO(hbos): Here and in other "AddAndRemoveTracks" tests: when ontrack and
// ended events are supported, verify that these are fired on the remote side
// when tracks are added and removed. https://crbug.com/webrtc/7933
// Add two tracks.
EXPECT_EQ(0u, GetNegotiationNeededCount(left_tab_));
std::vector<std::string> ids =
CreateAndAddAudioAndVideoTrack(left_tab_, StreamArgumentType::NO_STREAM);
// TODO(hbos): Should only fire once (if the "negotiationneeded" bit changes
// from false to true), not once per track added. https://crbug.com/740501
EXPECT_EQ(2u, GetNegotiationNeededCount(left_tab_));
std::string audio_stream_id = ids[0];
std::string audio_track_id = ids[1];
std::string video_stream_id = ids[2];
std::string video_track_id = ids[3];
EXPECT_EQ("null", audio_stream_id);
EXPECT_NE("null", audio_track_id);
EXPECT_EQ("null", video_stream_id);
EXPECT_NE("null", video_track_id);
CollectGarbage(left_tab_);
EXPECT_FALSE(HasLocalStreamWithTrack(left_tab_, kUndefined, audio_track_id));
EXPECT_FALSE(HasLocalStreamWithTrack(left_tab_, kUndefined, video_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 2);
// Negotiate call, sets remote description.
NegotiateCall(left_tab_, right_tab_);
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 2);
// TODO(hbos): When |addTrack| without streams results in SDP that does not
// signal a remote stream to be added we should expect |stream_ids| to be
// empty and |HasRemoteStreamWithTrack| to be false.
// https://crbug.com/webrtc/7933
std::vector<TrackEvent> track_events = GetTrackEvents(right_tab_);
EXPECT_EQ(2u, track_events.size());
const TrackEvent* audio_track_event =
FindTrackEvent(track_events, audio_track_id);
ASSERT_TRUE(audio_track_event);
EXPECT_EQ(1u, audio_track_event->stream_ids.size());
std::string remote_audio_stream_id = audio_track_event->stream_ids[0];
EXPECT_TRUE(HasRemoteStreamWithTrack(right_tab_, remote_audio_stream_id,
audio_track_id));
const TrackEvent* video_track_event =
FindTrackEvent(track_events, video_track_id);
ASSERT_TRUE(video_track_event);
EXPECT_EQ(1u, video_track_event->stream_ids.size());
std::string remote_video_stream_id = video_track_event->stream_ids[0];
EXPECT_TRUE(HasRemoteStreamWithTrack(right_tab_, remote_video_stream_id,
video_track_id));
// Remove first track.
RemoveTrack(left_tab_, audio_track_id);
CollectGarbage(left_tab_);
EXPECT_EQ(3u, GetNegotiationNeededCount(left_tab_));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 1);
// Re-negotiate call, sets remote description again.
NegotiateCall(left_tab_, right_tab_);
CollectGarbage(right_tab_);
// No additional track events should have fired.
EXPECT_EQ(2u, GetTrackEvents(right_tab_).size());
EXPECT_FALSE(HasRemoteStreamWithTrack(right_tab_, remote_audio_stream_id,
audio_track_id));
EXPECT_TRUE(HasRemoteStreamWithTrack(right_tab_, remote_video_stream_id,
video_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 1);
// Remove second track.
RemoveTrack(left_tab_, video_track_id);
CollectGarbage(left_tab_);
EXPECT_EQ(4u, GetNegotiationNeededCount(left_tab_));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 0);
// Re-negotiate call, sets remote description again.
NegotiateCall(left_tab_, right_tab_);
CollectGarbage(right_tab_);
// No additional track events should have fired.
EXPECT_EQ(2u, GetTrackEvents(right_tab_).size());
EXPECT_FALSE(HasRemoteStreamWithTrack(right_tab_, remote_audio_stream_id,
audio_track_id));
EXPECT_FALSE(HasRemoteStreamWithTrack(right_tab_, remote_video_stream_id,
video_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 0);
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
AddAndRemoveTracksWithSharedStream) {
StartServerAndOpenTabs();
SetupPeerconnectionWithoutLocalStream(left_tab_);
SetupPeerconnectionWithoutLocalStream(right_tab_);
// Add two tracks.
EXPECT_EQ(0u, GetNegotiationNeededCount(left_tab_));
std::vector<std::string> ids = CreateAndAddAudioAndVideoTrack(
left_tab_, StreamArgumentType::SHARED_STREAM);
// TODO(hbos): Should only fire once (if the "negotiationneeded" bit changes
// from false to true), not once per track added. https://crbug.com/740501
EXPECT_EQ(2u, GetNegotiationNeededCount(left_tab_));
std::string audio_stream_id = ids[0];
std::string audio_track_id = ids[1];
std::string video_stream_id = ids[2];
std::string video_track_id = ids[3];
EXPECT_NE("null", audio_stream_id);
EXPECT_NE("null", audio_track_id);
EXPECT_NE("null", video_stream_id);
EXPECT_NE("null", video_track_id);
EXPECT_EQ(audio_stream_id, video_stream_id);
CollectGarbage(left_tab_);
// TODO(hbos): When |getLocalStreams| is updated to return the streams of all
// senders, not just |addStream|-streams, then this will be EXPECT_TRUE.
// https://crbug.com/738918
EXPECT_FALSE(
HasLocalStreamWithTrack(left_tab_, audio_stream_id, audio_track_id));
EXPECT_FALSE(
HasLocalStreamWithTrack(left_tab_, video_stream_id, video_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 2);
// Negotiate call, sets remote description.
NegotiateCall(left_tab_, right_tab_);
EXPECT_TRUE(
HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
EXPECT_TRUE(
HasRemoteStreamWithTrack(right_tab_, video_stream_id, video_track_id));
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 2);
std::vector<TrackEvent> track_events = GetTrackEvents(right_tab_);
EXPECT_EQ(2u, track_events.size());
const TrackEvent* audio_track_event =
FindTrackEvent(track_events, audio_track_id);
ASSERT_TRUE(audio_track_event);
ASSERT_EQ(1u, audio_track_event->stream_ids.size());
EXPECT_EQ(audio_stream_id, audio_track_event->stream_ids[0]);
const TrackEvent* video_track_event =
FindTrackEvent(track_events, video_track_id);
ASSERT_TRUE(video_track_event);
ASSERT_EQ(1u, video_track_event->stream_ids.size());
EXPECT_EQ(video_stream_id, video_track_event->stream_ids[0]);
// Remove first track.
RemoveTrack(left_tab_, audio_track_id);
CollectGarbage(left_tab_);
EXPECT_EQ(3u, GetNegotiationNeededCount(left_tab_));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 1);
// Re-negotiate call, sets remote description again.
NegotiateCall(left_tab_, right_tab_);
CollectGarbage(right_tab_);
// No additional track events should have fired.
EXPECT_EQ(2u, GetTrackEvents(right_tab_).size());
EXPECT_FALSE(
HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
EXPECT_TRUE(
HasRemoteStreamWithTrack(right_tab_, video_stream_id, video_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 1);
// Remove second track.
RemoveTrack(left_tab_, video_track_id);
CollectGarbage(left_tab_);
EXPECT_EQ(4u, GetNegotiationNeededCount(left_tab_));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 0);
// Re-negotiate call, sets remote description again.
NegotiateCall(left_tab_, right_tab_);
CollectGarbage(right_tab_);
// No additional track events should have fired.
EXPECT_EQ(2u, GetTrackEvents(right_tab_).size());
EXPECT_FALSE(
HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
EXPECT_FALSE(
HasRemoteStreamWithTrack(right_tab_, video_stream_id, video_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 0);
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
AddAndRemoveTracksWithIndividualStreams) {
StartServerAndOpenTabs();
SetupPeerconnectionWithoutLocalStream(left_tab_);
SetupPeerconnectionWithoutLocalStream(right_tab_);
// Add two tracks.
EXPECT_EQ(0u, GetNegotiationNeededCount(left_tab_));
std::vector<std::string> ids = CreateAndAddAudioAndVideoTrack(
left_tab_, StreamArgumentType::INDIVIDUAL_STREAMS);
// TODO(hbos): Should only fire once (if the "negotiationneeded" bit changes
// from false to true), not once per track added. https://crbug.com/740501
EXPECT_EQ(2u, GetNegotiationNeededCount(left_tab_));
std::string audio_stream_id = ids[0];
std::string audio_track_id = ids[1];
std::string video_stream_id = ids[2];
std::string video_track_id = ids[3];
EXPECT_NE("null", audio_stream_id);
EXPECT_NE("null", audio_track_id);
EXPECT_NE("null", video_stream_id);
EXPECT_NE("null", video_track_id);
EXPECT_NE(audio_stream_id, video_stream_id);
CollectGarbage(left_tab_);
// TODO(hbos): When |getLocalStreams| is updated to return the streams of all
// senders, not just |addStream|-streams, then this will be EXPECT_TRUE.
// https://crbug.com/738918
EXPECT_FALSE(
HasLocalStreamWithTrack(left_tab_, audio_stream_id, audio_track_id));
EXPECT_FALSE(
HasLocalStreamWithTrack(left_tab_, video_stream_id, video_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 2);
// Negotiate call, sets remote description.
NegotiateCall(left_tab_, right_tab_);
EXPECT_TRUE(
HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
EXPECT_TRUE(
HasRemoteStreamWithTrack(right_tab_, video_stream_id, video_track_id));
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 2);
std::vector<TrackEvent> track_events = GetTrackEvents(right_tab_);
EXPECT_EQ(2u, track_events.size());
const TrackEvent* audio_track_event =
FindTrackEvent(track_events, audio_track_id);
ASSERT_TRUE(audio_track_event);
ASSERT_EQ(1u, audio_track_event->stream_ids.size());
EXPECT_EQ(audio_stream_id, audio_track_event->stream_ids[0]);
const TrackEvent* video_track_event =
FindTrackEvent(track_events, video_track_id);
ASSERT_TRUE(video_track_event);
ASSERT_EQ(1u, video_track_event->stream_ids.size());
EXPECT_EQ(video_stream_id, video_track_event->stream_ids[0]);
// Remove first track.
RemoveTrack(left_tab_, audio_track_id);
CollectGarbage(left_tab_);
EXPECT_EQ(3u, GetNegotiationNeededCount(left_tab_));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_TRUE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 1);
// Re-negotiate call, sets remote description again.
NegotiateCall(left_tab_, right_tab_);
CollectGarbage(right_tab_);
// No additional track events should have fired.
EXPECT_EQ(2u, GetTrackEvents(right_tab_).size());
EXPECT_FALSE(
HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
EXPECT_TRUE(
HasRemoteStreamWithTrack(right_tab_, video_stream_id, video_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_TRUE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 1);
// Remove second track.
RemoveTrack(left_tab_, video_track_id);
CollectGarbage(left_tab_);
EXPECT_EQ(4u, GetNegotiationNeededCount(left_tab_));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, audio_track_id));
EXPECT_FALSE(HasSenderWithTrack(left_tab_, video_track_id));
VerifyRtpSenders(left_tab_, 0);
// Re-negotiate call, sets remote description again.
NegotiateCall(left_tab_, right_tab_);
CollectGarbage(right_tab_);
// No additional track events should have fired.
EXPECT_EQ(2u, GetTrackEvents(right_tab_).size());
EXPECT_FALSE(
HasRemoteStreamWithTrack(right_tab_, audio_stream_id, audio_track_id));
EXPECT_FALSE(
HasRemoteStreamWithTrack(right_tab_, video_stream_id, video_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, audio_track_id));
EXPECT_FALSE(HasReceiverWithTrack(right_tab_, video_track_id));
VerifyRtpReceivers(right_tab_, 0);
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, GetReceiversSetRemoteDescription) {
StartServerAndOpenTabs();
EXPECT_EQ("ok", ExecuteJavascript("createReceiverWithSetRemoteDescription()",
left_tab_));
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, SwitchRemoteStreamAndBackAgain) {
StartServerAndOpenTabs();
EXPECT_EQ("ok",
ExecuteJavascript("switchRemoteStreamAndBackAgain()", left_tab_));
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
SwitchRemoteStreamWithoutWaitingForPromisesToResolve) {
StartServerAndOpenTabs();
EXPECT_EQ("ok", ExecuteJavascript(
"switchRemoteStreamWithoutWaitingForPromisesToResolve()",
left_tab_));
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest, TrackSwitchingStream) {
StartServerAndOpenTabs();
EXPECT_EQ("ok", ExecuteJavascript("trackSwitchingStream()", left_tab_));
}
IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
RTCRtpSenderReplaceTrackSendsNewVideoTrack) {
StartServer();
OpenTab(&left_tab_);
EXPECT_EQ("test-passed",
ExecuteJavascript(
"testRTCRtpSenderReplaceTrackSendsNewVideoTrack()", left_tab_));
}
......@@ -594,7 +594,6 @@ test("browser_tests") {
"../browser/media/webrtc/webrtc_getmediadevices_browsertest.cc",
"../browser/media/webrtc/webrtc_internals_integration_browsertest.cc",
"../browser/media/webrtc/webrtc_internals_perf_browsertest.cc",
"../browser/media/webrtc/webrtc_rtp_browsertest.cc",
"../browser/media/webrtc/webrtc_simulcast_browsertest.cc",
"../browser/media/webrtc/webrtc_stats_perf_browsertest.cc",
"../browser/media/webrtc/webrtc_video_display_perf_browsertest.cc",
......
/**
* Copyright 2017 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.
*/
// Public interface to tests. These are expected to be called with
// ExecuteJavascript invocations from the browser tests and will return answers
// through the DOM automation controller.
/**
* Adds |count| streams to the peer connection, with one audio and one video
* track per stream.
*
* Returns "ok-streams-created-and-added" on success.
*/
function createAndAddStreams(count) {
if (count > 0) {
navigator.getUserMedia({ audio: true, video: true },
function(stream) {
peerConnection_().addStream(stream);
createAndAddStreams(count - 1);
},
function(error) {
throw failTest('getUserMedia failed: ' + error);
});
} else {
returnToTest('ok-streams-created-and-added');
}
}
/**
* Verifies that the peer connection's getSenders() returns one sender per local
* track, that there are no duplicates and that object identity is preserved.
*
* Returns "ok-senders-verified" on success.
*/
function verifyRtpSenders(expectedNumTracks = null) {
if (expectedNumTracks != null &&
peerConnection_().getSenders().length != expectedNumTracks) {
throw failTest('getSenders().length != expectedNumTracks');
}
if (!arrayEquals_(peerConnection_().getSenders(),
peerConnection_().getSenders())) {
throw failTest('One getSenders() call is not equal to the next.');
}
let senders = new Set();
let senderTracks = new Set();
peerConnection_().getSenders().forEach(function(sender) {
if (sender == null)
throw failTest('sender is null or undefined.');
if (sender.track == null)
throw failTest('sender.track is null or undefined.');
senders.add(sender);
senderTracks.add(sender.track);
});
if (senderTracks.size != senders.size)
throw failTest('senderTracks.size != senders.size');
returnToTest('ok-senders-verified');
}
/**
* Verifies that the peer connection's getReceivers() returns one receiver per
* remote track, that there are no duplicates and that object identity is
* preserved.
*
* Returns "ok-receivers-verified" on success.
*/
function verifyRtpReceivers(expectedNumTracks = null) {
if (peerConnection_().getReceivers() == null)
throw failTest('getReceivers() returns null or undefined.');
if (expectedNumTracks != null &&
peerConnection_().getReceivers().length != expectedNumTracks) {
throw failTest('getReceivers().length != expectedNumTracks');
}
if (!arrayEquals_(peerConnection_().getReceivers(),
peerConnection_().getReceivers())) {
throw failTest('One getReceivers() call is not equal to the next.');
}
let receivers = new Set();
let receiverTracks = new Set();
peerConnection_().getReceivers().forEach(function(receiver) {
if (receiver == null)
throw failTest('receiver is null or undefined.');
if (receiver.track == null)
throw failTest('receiver.track is null or undefined.');
if (receiver.getContributingSources().length != 0)
throw failTest('receiver.getContributingSources() is not empty.');
receivers.add(receiver);
receiverTracks.add(receiver.track);
});
if (receiverTracks.size != receivers.size)
throw failTest('receiverTracks.size != receivers.size');
returnToTest('ok-receivers-verified');
}
/**
* Creates an audio and video track and adds them to the peer connection using
* |addTrack|. They are added with or without a stream in accordance with
* |streamArgumentType|.
*
* Returns
* "ok-<audio stream id> <audio track id> <video stream id> <video track id>" on
* success. If no stream is backing up the track, <stream id> is "null".
*
* @param {string} streamArgumentType Must be one of the following values:
* 'no-stream' - The tracks are added without an associated stream.
* 'shared-stream' - The tracks are added with the same associated stream.
* 'individual-streams' - A stream is created for each track.
*/
function createAndAddAudioAndVideoTrack(streamArgumentType) {
if (streamArgumentType !== 'no-stream' &&
streamArgumentType !== 'shared-stream' &&
streamArgumentType !== 'individual-streams')
throw failTest('Unsupported streamArgumentType.');
navigator.getUserMedia({ audio: true, video: true },
function(stream) {
let audioStream = undefined;
if (streamArgumentType !== 'no-stream')
audioStream = new MediaStream();
let audioTrack = stream.getAudioTracks()[0];
let audioSender =
audioStream ? peerConnection_().addTrack(audioTrack, audioStream)
: peerConnection_().addTrack(audioTrack);
if (!audioSender || audioSender.track != audioTrack)
throw failTest('addTrack did not return a sender with the track.');
let videoStream = undefined;
if (streamArgumentType === 'shared-stream') {
videoStream = audioStream;
} else if (streamArgumentType === 'individual-streams') {
videoStream = new MediaStream();
}
let videoTrack = stream.getVideoTracks()[0];
let videoSender =
videoStream ? peerConnection_().addTrack(videoTrack, videoStream)
: peerConnection_().addTrack(videoTrack);
if (!videoSender || videoSender.track != videoTrack)
throw failTest('addTrack did not return a sender with the track.');
let audioStreamId = audioStream ? audioStream.id : 'null';
let videoStreamId = videoStream ? videoStream.id : 'null';
returnToTest('ok-' + audioStreamId + ' ' + audioTrack.id
+ ' ' + videoStreamId + ' ' + videoTrack.id);
},
function(error) {
throw failTest('getUserMedia failed: ' + error);
});
}
/**
* Calls |removeTrack| with the first sender that has the track with |trackId|
* and verifies the SDP is updated accordingly.
*
* Returns "ok-sender-removed" on success.
*/
function removeTrack(trackId) {
let sender = null;
let otherSenderHasTrack = false;
peerConnection_().getSenders().forEach(function(s) {
if (s.track && s.track.id == trackId) {
if (!sender)
sender = s;
else
otherSenderHasTrack = true;
}
});
if (!sender)
throw failTest('There is no sender for track ' + trackId);
peerConnection_().removeTrack(sender);
if (sender.track)
throw failTest('sender.track was not nulled by removeTrack.');
returnToTest('ok-sender-removed');
}
/**
* Returns "ok-stream-with-track-found" or "ok-stream-with-track-not-found".
* If |streamId| is null then any stream having a track with |trackId| will do.
*/
function hasLocalStreamWithTrack(streamId, trackId) {
if (hasStreamWithTrack(
peerConnection_().getLocalStreams(), streamId, trackId)) {
returnToTest('ok-stream-with-track-found');
return;
}
returnToTest('ok-stream-with-track-not-found');
}
/**
* Returns "ok-stream-with-track-found" or "ok-stream-with-track-not-found".
* If |streamId| is null then any stream having a track with |trackId| will do.
*/
function hasRemoteStreamWithTrack(streamId, trackId) {
if (hasStreamWithTrack(
peerConnection_().getRemoteStreams(), streamId, trackId)) {
returnToTest('ok-stream-with-track-found');
return;
}
returnToTest('ok-stream-with-track-not-found');
}
/**
* Returns "ok-sender-with-track-found" or "ok-sender-with-track-not-found".
*/
function hasSenderWithTrack(trackId) {
if (hasSenderOrReceiverWithTrack(peerConnection_().getSenders(), trackId)) {
returnToTest('ok-sender-with-track-found');
return;
}
returnToTest('ok-sender-with-track-not-found');
}
/**
* Returns "ok-receiver-with-track-found" or "ok-receiver-with-track-not-found".
*/
function hasReceiverWithTrack(trackId) {
if (hasSenderOrReceiverWithTrack(peerConnection_().getReceivers(), trackId)) {
returnToTest('ok-receiver-with-track-found');
return;
}
returnToTest('ok-receiver-with-track-not-found');
}
// TODO(hbos): Make this a web platform test instead. https://crbug.com/773472
function createReceiverWithSetRemoteDescription() {
var pc = new RTCPeerConnection();
var receivers = null;
pc.setRemoteDescription(createOffer([msid('stream', 'track1')]))
.then(() => {
receivers = pc.getReceivers();
if (receivers.length != 1)
throw failTest('getReceivers() should return 1 receiver: ' +
receivers.length)
if (!receivers[0].track)
throw failTest('getReceivers()[0].track should have a value')
returnToTest('ok');
});
receivers = pc.getReceivers();
if (receivers.length != 0)
throw failTest('getReceivers() should return 0 receivers: ' +
receivers.length)
}
// TODO(hbos): Make this a web platform test instead. https://crbug.com/773472
function switchRemoteStreamAndBackAgain() {
let pc1 = new RTCPeerConnection();
let firstStream0 = null;
let firstTrack0 = null;
pc1.setRemoteDescription(createOffer([msid('stream0', 'track0')]))
.then(() => {
firstStream0 = pc1.getRemoteStreams()[0];
firstTrack0 = firstStream0.getTracks()[0];
if (firstStream0.id != 'stream0')
throw failTest('Unexpected firstStream0.id: ' + firstStream0.id);
if (firstTrack0.id != 'track0')
throw failTest('Unexpected firstTrack0.id: ' + firstTrack0.id);
return pc1.setRemoteDescription(
createOffer([msid('stream1', 'track1')]));
}).then(() => {
return pc1.setRemoteDescription(
createOffer([msid('stream0', 'track0')]));
}).then(() => {
let secondStream0 = pc1.getRemoteStreams()[0];
let secondTrack0 = secondStream0.getTracks()[0];
if (secondStream0.id != 'stream0')
throw failTest('Unexpected secondStream0.id: ' + secondStream0.id);
if (secondTrack0.id != 'track0')
throw failTest('Unexpected secondTrack0.id: ' + secondTrack0.id);
if (secondTrack0 == firstTrack0)
throw failTest('Expected a new track object with the same id');
if (secondStream0 == firstStream0)
throw failTest('Expected a new stream object with the same id');
returnToTest('ok');
});
}
// TODO(hbos): Make this a web platform test instead. https://crbug.com/773472
function switchRemoteStreamWithoutWaitingForPromisesToResolve() {
let pc = new RTCPeerConnection();
let trackEventsFired = 0;
let streamEventsFired = 0;
pc.ontrack = (e) => {
++trackEventsFired;
if (trackEventsFired == 1) {
if (e.track.id != 'track0')
throw failTest('Unexpected track id in first track event.');
if (e.receiver.track != e.track)
throw failTest('Unexpected receiver.track in first track event.');
if (e.streams[0].id != 'stream0')
throw failTest('Unexpected stream id in first track event.');
// Because we did not wait for promises to resolve before calling
// |setRemoteDescription| a second time, it may or may not have had an
// effect here. This is inherently racey and we have to check if the
// stream contains the track.
if (e.streams[0].getTracks().length != 0) {
if (e.streams[0].getTracks()[0] != e.track)
throw failTest('Unexpected track in stream in first track event.');
}
} else if (trackEventsFired == 2) {
if (e.track.id != 'track1')
throw failTest('Unexpected track id in second track event.');
if (e.receiver.track != e.track)
throw failTest('Unexpected receiver.track in second track event.');
if (e.streams[0].id != 'stream1')
throw failTest('Unexpected stream id in second track event.');
if (e.streams[0].getTracks()[0] != e.track)
throw failTest('The track should belong to the stream in the second ' +
'track event.');
if (streamEventsFired != trackEventsFired)
throw failTest('All stream events should already have fired.');
returnToTest('ok');
}
};
pc.onaddstream = (e) => {
++streamEventsFired;
if (streamEventsFired == 1) {
if (e.stream.id != 'stream0')
throw failTest('Unexpected stream id in first stream event.');
// Because we did not wait for promises to resolve before calling
// |setRemoteDescription| a second time, it may or may not have had an
// effect here. This is inherently racey and we have to check if the
// stream contains the track.
if (e.stream.getTracks().length != 0) {
if (e.stream.getTracks()[0].id != 'track0')
throw failTest('Unexpected track id in first stream event.');
}
} else if (streamEventsFired == 2) {
if (e.stream.id != 'stream1')
throw failTest('Unexpected stream id in second stream event.');
if (e.stream.getTracks()[0].id != 'track1')
throw failTest('Unexpected track id in second stream event.');
}
};
pc.setRemoteDescription(createOffer([msid('stream0', 'track0')]));
pc.setRemoteDescription(createOffer([msid('stream1', 'track1')]));
}
// TODO(hbos): Make this a web platform test instead. https://crbug.com/773472
function trackSwitchingStream() {
let pc = new RTCPeerConnection();
let track = null;
let stream1 = null;
let stream2 = null;
pc.setRemoteDescription(createOffer([msid('stream1', 'track1')]));
pc.ontrack = (e) => {
track = e.track;
stream1 = e.streams[0];
if (stream1.getTracks()[0] != track)
throw failTest('stream1 does not contain track.');
// This should update the associated set of streams for the existing
// receiver for track.
pc.setRemoteDescription(createOffer([msid('stream2', 'track')]));
pc.ontrack = (e) => {
let originalTrack = track;
track = e.track;
stream2 = e.streams[0];
// TODO(hbos): A new track should not be created, track should simply
// move. Fix this and update assertion. https://crbug.com/webrtc/8377
if (track == originalTrack)
throw failTest('A new track was not created.');
if (stream1.getTracks().length != 0)
throw failTest('stream1 is not empty.')
if (!originalTrack.muted)
throw failTest('Original track is not muted.');
if (track.muted)
throw failTest('New track is muted.');
if (stream2.getTracks()[0] != track)
throw failTest('stream2 does not contain track.');
returnToTest('ok');
};
};
}
// TODO(hbos): Add a test that verifies a track that is added to two streams can
// be removed from just one of them. https://crbug.com/webrtc/8377
/**
* Invokes the GC and returns "ok-gc".
*/
function collectGarbage() {
gc();
returnToTest('ok-gc');
}
// Internals.
function msid(stream, track) {
return {
stream: stream,
track: track
};
}
function createOffer(msids) {
let msidLines = '';
for (let i = 0; i < msids.length; ++i) {
msidLines += 'a=msid:' + msids[i].stream + ' ' + msids[i].track + '\n';
}
return {
type: 'offer',
sdp: 'v=0\n' +
'o=TestSDP 1337 0 IN IP4 0.0.0.0\n' +
's=-\n' +
't=0 0\n' +
'a=fingerprint:sha-256 7A:69:A9:2B:ED:09:B8:88:D5:44:D6:9A:3F:B2:48:' +
'6D:93:80:D1:39:AE:0C:3A:D5:89:EC:D8:39:95:62:9A:04\n' +
'a=ice-options:trickle\n' +
'a=msid-semantic:WMS *\n' +
'm=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8 101\n' +
'c=IN IP4 0.0.0.0\n' +
'a=sendrecv\n' +
'a=extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level\n' +
'a=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\n' +
'a=fmtp:101 0-15\n' +
'a=ice-pwd:bcda8c8d9061b19b86f7798e262c60b5\n' +
'a=ice-ufrag:4aeff5db\n' +
'a=rtcp-mux\n' +
'a=rtpmap:109 opus/48000/2\n' +
'a=rtpmap:9 G722/8000/1\n' +
'a=rtpmap:0 PCMU/8000\n' +
'a=rtpmap:8 PCMA/8000\n' +
'a=rtpmap:101 telephone-event/8000/1\n' +
'a=setup:actpass\n' +
'a=ssrc:1104456328 cname:{65ad23a5-22cd-2045-9154-0a745d951ccf}\n' +
// These are all audio tracks because they're placed under the
// "m=audio" section.
msidLines
};
}
/** @private */
function hasStreamWithTrack(streams, streamId, trackId) {
for (let i = 0; i < streams.length; ++i) {
let stream = streams[i];
if (streamId && stream.id !== streamId)
continue;
let tracks = stream.getTracks();
for (let j = 0; j < tracks.length; ++j) {
let track = tracks[j];
if (track.id == trackId) {
return true;
}
}
}
return false;
}
/** @private */
function hasSenderOrReceiverWithTrack(sendersOrReceivers, trackId) {
for (let i = 0; i < sendersOrReceivers.length; ++i) {
if (sendersOrReceivers[i].track &&
sendersOrReceivers[i].track.id === trackId) {
return true;
}
}
return false;
}
/** @private */
function arrayEquals_(a, b) {
if (a == null)
return b == null;
if (a.length != b.length)
return false;
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i])
return false;
}
return true;
}
/** @private */
function setEquals_(a, b) {
if (a == null)
return b == null;
if (a.size != b.size)
return false;
a.forEach(function(value) {
if (!b.has(value))
return false;
});
return true;
}
......@@ -10,7 +10,6 @@
<script type="text/javascript" src="media_devices.js"></script>
<script type="text/javascript" src="indexeddb.js"></script>
<script type="text/javascript" src="peerconnection_getstats.js"></script>
<script type="text/javascript" src="peerconnection_rtp.js"></script>
<script type="text/javascript" src="peerconnection_replacetrack.js"></script>
</head>
<body>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment