blob: accdeb9587fe6814f2dddcad1649f834e6f29875 [file] [log] [blame]
// Copyright 2018 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 "content/renderer/media/webrtc/rtc_rtp_transceiver.h"
#include <memory>
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "content/child/child_process.h"
#include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
#include "content/renderer/media/webrtc/mock_peer_connection_impl.h"
#include "content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h"
#include "content/renderer/media/webrtc/webrtc_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/modules/mediastream/media_stream_audio_source.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_media_stream_source.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/webrtc/api/test/mock_rtpreceiver.h"
#include "third_party/webrtc/api/test/mock_rtpsender.h"
namespace content {
class RTCRtpTransceiverTest : public ::testing::Test {
public:
void SetUp() override {
dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
main_task_runner_ = blink::scheduler::GetSingleThreadTaskRunnerForTesting();
track_map_ = new WebRtcMediaStreamTrackAdapterMap(dependency_factory_.get(),
main_task_runner_);
peer_connection_ = new rtc::RefCountedObject<MockPeerConnectionImpl>(
dependency_factory_.get(), nullptr);
}
void TearDown() override {
// Syncing up with the signaling thread ensures any pending operations on
// that thread are executed. If they post back to the main thread, such as
// the sender or receiver destructor traits, this is allowed to execute
// before the test shuts down the threads.
SyncWithSignalingThread();
blink::WebHeap::CollectAllGarbageForTesting();
}
// Wait for the signaling thread to perform any queued tasks, executing tasks
// posted to the current thread in the meantime while waiting.
void SyncWithSignalingThread() const {
base::RunLoop run_loop;
dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE, run_loop.QuitClosure());
run_loop.Run();
}
scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner() const {
return dependency_factory_->GetWebRtcSignalingThread();
}
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>
CreateLocalTrackAndAdapter(const std::string& id) {
return track_map_->GetOrCreateLocalTrackAdapter(CreateBlinkLocalTrack(id));
}
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>
CreateRemoteTrackAndAdapter(const std::string& id) {
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track =
MockWebRtcAudioTrack::Create(id).get();
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref;
base::RunLoop run_loop;
signaling_task_runner()->PostTask(
FROM_HERE,
base::BindOnce(
&RTCRtpTransceiverTest::CreateRemoteTrackAdapterOnSignalingThread,
base::Unretained(this), std::move(webrtc_track),
base::Unretained(&track_ref), base::Unretained(&run_loop)));
run_loop.Run();
DCHECK(track_ref);
return track_ref;
}
rtc::scoped_refptr<FakeRtpSender> CreateWebRtcSender(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
const std::string& stream_id) {
return new rtc::RefCountedObject<FakeRtpSender>(
std::move(track), std::vector<std::string>({stream_id}));
}
rtc::scoped_refptr<FakeRtpReceiver> CreateWebRtcReceiver(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
const std::string& stream_id) {
rtc::scoped_refptr<webrtc::MediaStreamInterface> remote_stream(
new rtc::RefCountedObject<MockMediaStream>(stream_id));
return new rtc::RefCountedObject<FakeRtpReceiver>(
track.get(),
std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>(
{remote_stream}));
}
rtc::scoped_refptr<FakeRtpTransceiver> CreateWebRtcTransceiver(
rtc::scoped_refptr<FakeRtpSender> sender,
rtc::scoped_refptr<FakeRtpReceiver> receiver,
base::Optional<std::string> mid,
bool stopped,
webrtc::RtpTransceiverDirection direction,
base::Optional<webrtc::RtpTransceiverDirection> current_direction) {
DCHECK(!sender->track() ||
sender->track()->kind() == receiver->track()->kind());
return new rtc::RefCountedObject<FakeRtpTransceiver>(
receiver->track()->kind() ==
webrtc::MediaStreamTrackInterface::kAudioKind
? cricket::MEDIA_TYPE_AUDIO
: cricket::MEDIA_TYPE_VIDEO,
std::move(sender), std::move(receiver), std::move(mid), stopped,
direction, std::move(current_direction));
}
RtpTransceiverState CreateTransceiverState(
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> webrtc_transceiver,
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>
sender_track_ref,
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>
receiver_track_ref) {
std::vector<std::string> receiver_stream_ids;
for (const auto& stream : webrtc_transceiver->receiver()->streams()) {
receiver_stream_ids.push_back(stream->id());
}
return RtpTransceiverState(
main_task_runner_, signaling_task_runner(), webrtc_transceiver.get(),
RtpSenderState(main_task_runner_, signaling_task_runner(),
webrtc_transceiver->sender().get(),
std::move(sender_track_ref),
webrtc_transceiver->sender()->stream_ids()),
RtpReceiverState(main_task_runner_, signaling_task_runner(),
webrtc_transceiver->receiver().get(),
std::move(receiver_track_ref),
std::move(receiver_stream_ids)),
ToBaseOptional(webrtc_transceiver->mid()),
webrtc_transceiver->stopped(), webrtc_transceiver->direction(),
ToBaseOptional(webrtc_transceiver->current_direction()),
ToBaseOptional(webrtc_transceiver->fired_direction()));
}
protected:
blink::WebMediaStreamTrack CreateBlinkLocalTrack(const std::string& id) {
blink::WebMediaStreamSource web_source;
web_source.Initialize(
blink::WebString::FromUTF8(id), blink::WebMediaStreamSource::kTypeAudio,
blink::WebString::FromUTF8("local_audio_track"), false);
blink::MediaStreamAudioSource* audio_source =
new blink::MediaStreamAudioSource(true);
// Takes ownership of |audio_source|.
web_source.SetPlatformSource(base::WrapUnique(audio_source));
blink::WebMediaStreamTrack web_track;
web_track.Initialize(web_source.Id(), web_source);
audio_source->ConnectToTrack(web_track);
return web_track;
}
void CreateRemoteTrackAdapterOnSignalingThread(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track,
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>* track_ref,
base::RunLoop* run_loop) {
*track_ref = track_map_->GetOrCreateRemoteTrackAdapter(webrtc_track.get());
run_loop->Quit();
}
private:
base::test::ScopedTaskEnvironment task_environment_;
protected:
std::unique_ptr<MockPeerConnectionDependencyFactory> dependency_factory_;
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<WebRtcMediaStreamTrackAdapterMap> track_map_;
rtc::scoped_refptr<MockPeerConnectionImpl> peer_connection_;
};
TEST_F(RTCRtpTransceiverTest, InitializeTransceiverState) {
auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
auto webrtc_transceiver = CreateWebRtcTransceiver(
CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream"),
CreateWebRtcReceiver(remote_track_adapter->webrtc_track(),
"remote_stream"),
base::nullopt, false, webrtc::RtpTransceiverDirection::kSendRecv,
base::nullopt);
RtpTransceiverState transceiver_state =
CreateTransceiverState(webrtc_transceiver, std::move(local_track_adapter),
std::move(remote_track_adapter));
EXPECT_FALSE(transceiver_state.is_initialized());
transceiver_state.Initialize();
EXPECT_TRUE(transceiver_state.is_initialized());
// Inspect sender states.
const auto& sender_state = transceiver_state.sender_state();
EXPECT_TRUE(sender_state);
EXPECT_TRUE(sender_state->is_initialized());
const auto& webrtc_sender = webrtc_transceiver->sender();
EXPECT_EQ(sender_state->webrtc_sender().get(), webrtc_sender.get());
EXPECT_TRUE(sender_state->track_ref()->is_initialized());
EXPECT_EQ(sender_state->track_ref()->webrtc_track(),
webrtc_sender->track().get());
EXPECT_EQ(sender_state->stream_ids(), webrtc_sender->stream_ids());
// Inspect receiver states.
const auto& receiver_state = transceiver_state.receiver_state();
EXPECT_TRUE(receiver_state);
EXPECT_TRUE(receiver_state->is_initialized());
const auto& webrtc_receiver = webrtc_transceiver->receiver();
EXPECT_EQ(receiver_state->webrtc_receiver().get(), webrtc_receiver.get());
EXPECT_TRUE(receiver_state->track_ref()->is_initialized());
EXPECT_EQ(receiver_state->track_ref()->webrtc_track(),
webrtc_receiver->track().get());
std::vector<std::string> receiver_stream_ids;
for (const auto& stream : webrtc_receiver->streams()) {
receiver_stream_ids.push_back(stream->id());
}
EXPECT_EQ(receiver_state->stream_ids(), receiver_stream_ids);
// Inspect transceiver states.
EXPECT_TRUE(
OptionalEquals(transceiver_state.mid(), webrtc_transceiver->mid()));
EXPECT_EQ(transceiver_state.stopped(), webrtc_transceiver->stopped());
EXPECT_TRUE(transceiver_state.direction() == webrtc_transceiver->direction());
EXPECT_TRUE(OptionalEquals(transceiver_state.current_direction(),
webrtc_transceiver->current_direction()));
EXPECT_TRUE(OptionalEquals(transceiver_state.fired_direction(),
webrtc_transceiver->fired_direction()));
}
TEST_F(RTCRtpTransceiverTest, CreateTranceiver) {
auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
auto webrtc_transceiver = CreateWebRtcTransceiver(
CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream"),
CreateWebRtcReceiver(remote_track_adapter->webrtc_track(),
"remote_stream"),
base::nullopt, false, webrtc::RtpTransceiverDirection::kSendRecv,
base::nullopt);
RtpTransceiverState transceiver_state =
CreateTransceiverState(webrtc_transceiver, std::move(local_track_adapter),
std::move(remote_track_adapter));
EXPECT_FALSE(transceiver_state.is_initialized());
transceiver_state.Initialize();
RTCRtpTransceiver transceiver(peer_connection_.get(), track_map_,
std::move(transceiver_state));
EXPECT_TRUE(transceiver.Mid().IsNull());
EXPECT_TRUE(transceiver.Sender());
EXPECT_TRUE(transceiver.Receiver());
EXPECT_FALSE(transceiver.Stopped());
EXPECT_EQ(transceiver.Direction(),
webrtc::RtpTransceiverDirection::kSendRecv);
EXPECT_FALSE(transceiver.CurrentDirection());
EXPECT_FALSE(transceiver.FiredDirection());
}
TEST_F(RTCRtpTransceiverTest, ModifyTransceiver) {
auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
auto webrtc_sender =
CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream");
auto webrtc_receiver = CreateWebRtcReceiver(
remote_track_adapter->webrtc_track(), "remote_stream");
auto webrtc_transceiver = CreateWebRtcTransceiver(
webrtc_sender, webrtc_receiver, base::nullopt, false,
webrtc::RtpTransceiverDirection::kSendRecv, base::nullopt);
// Create initial state.
RtpTransceiverState initial_transceiver_state =
CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
remote_track_adapter->Copy());
EXPECT_FALSE(initial_transceiver_state.is_initialized());
initial_transceiver_state.Initialize();
// Modify the webrtc transceiver and create a new state object for the
// modified state.
*webrtc_transceiver =
*CreateWebRtcTransceiver(webrtc_sender, webrtc_receiver, "MidyMacMidface",
true, webrtc::RtpTransceiverDirection::kInactive,
webrtc::RtpTransceiverDirection::kSendRecv);
RtpTransceiverState modified_transceiver_state =
CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
remote_track_adapter->Copy());
EXPECT_FALSE(modified_transceiver_state.is_initialized());
modified_transceiver_state.Initialize();
// Modifying the webrtc transceiver after the initial state was created should
// not have affected the transceiver state.
RTCRtpTransceiver transceiver(peer_connection_.get(), track_map_,
std::move(initial_transceiver_state));
EXPECT_TRUE(transceiver.Mid().IsNull());
EXPECT_TRUE(transceiver.Sender());
EXPECT_TRUE(transceiver.Receiver());
EXPECT_FALSE(transceiver.Stopped());
EXPECT_EQ(transceiver.Direction(),
webrtc::RtpTransceiverDirection::kSendRecv);
EXPECT_FALSE(transceiver.CurrentDirection());
EXPECT_FALSE(transceiver.FiredDirection());
// Setting the state should make the transceiver state up-to-date.
transceiver.set_state(std::move(modified_transceiver_state));
EXPECT_EQ(transceiver.Mid(), "MidyMacMidface");
EXPECT_TRUE(transceiver.Sender());
EXPECT_TRUE(transceiver.Receiver());
EXPECT_TRUE(transceiver.Stopped());
EXPECT_EQ(transceiver.Direction(),
webrtc::RtpTransceiverDirection::kInactive);
EXPECT_TRUE(transceiver.CurrentDirection() ==
webrtc::RtpTransceiverDirection::kSendRecv);
EXPECT_FALSE(transceiver.FiredDirection());
}
TEST_F(RTCRtpTransceiverTest, ShallowCopy) {
auto local_track_adapter = CreateLocalTrackAndAdapter("local_track");
auto remote_track_adapter = CreateRemoteTrackAndAdapter("remote_track");
auto webrtc_sender =
CreateWebRtcSender(local_track_adapter->webrtc_track(), "local_stream");
auto webrtc_receiver = CreateWebRtcReceiver(
remote_track_adapter->webrtc_track(), "remote_stream");
auto webrtc_transceiver = CreateWebRtcTransceiver(
webrtc_sender, webrtc_receiver, base::nullopt, false /* stopped */,
webrtc::RtpTransceiverDirection::kSendRecv, base::nullopt);
std::unique_ptr<RTCRtpTransceiver> transceiver;
// Create transceiver.
{
RtpTransceiverState transceiver_state =
CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
remote_track_adapter->Copy());
EXPECT_FALSE(transceiver_state.is_initialized());
transceiver_state.Initialize();
transceiver.reset(new RTCRtpTransceiver(peer_connection_.get(), track_map_,
std::move(transceiver_state)));
}
DCHECK(transceiver);
EXPECT_FALSE(transceiver->Stopped());
std::unique_ptr<RTCRtpTransceiver> shallow_copy = transceiver->ShallowCopy();
// Modifying the shallow copy should modify the original too since they have a
// shared internal state.
{
// Modify webrtc transceiver to be stopped.
*webrtc_transceiver = *CreateWebRtcTransceiver(
webrtc_sender, webrtc_receiver, base::nullopt, true /* stopped */,
webrtc::RtpTransceiverDirection::kSendRecv, base::nullopt);
RtpTransceiverState transceiver_state =
CreateTransceiverState(webrtc_transceiver, local_track_adapter->Copy(),
remote_track_adapter->Copy());
EXPECT_FALSE(transceiver_state.is_initialized());
transceiver_state.Initialize();
// Set the state of the shallow copy.
shallow_copy->set_state(std::move(transceiver_state));
}
EXPECT_TRUE(shallow_copy->Stopped());
EXPECT_TRUE(transceiver->Stopped());
}
} // namespace content