blob: 4a5d05b413ab3f2975f3c9617c9c470d89529b6e [file] [log] [blame]
// Copyright (c) 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 "content/renderer/media/webrtc/rtc_rtp_receiver.h"
#include <memory>
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.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 "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/test/webrtc_stats_report_obtainer.h"
#include "content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_rtc_stats.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_heap.h"
#include "third_party/webrtc/api/stats/rtc_stats_report.h"
#include "third_party/webrtc/api/stats/rtcstats_objects.h"
#include "third_party/webrtc/api/test/mock_rtpreceiver.h"
namespace content {
class RTCRtpReceiverTest : public ::testing::Test {
public:
void SetUp() override {
dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
main_thread_ = blink::scheduler::GetSingleThreadTaskRunnerForTesting();
track_map_ = new WebRtcMediaStreamTrackAdapterMap(dependency_factory_.get(),
main_thread_);
peer_connection_ = new rtc::RefCountedObject<MockPeerConnectionImpl>(
dependency_factory_.get(), nullptr);
}
void TearDown() override {
receiver_.reset();
// 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's 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();
}
std::unique_ptr<RTCRtpReceiver> CreateReceiver(
scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track) {
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref;
base::RunLoop run_loop;
dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE,
base::BindOnce(&RTCRtpReceiverTest::CreateReceiverOnSignalingThread,
base::Unretained(this), std::move(webrtc_track),
base::Unretained(&track_ref),
base::Unretained(&run_loop)));
run_loop.Run();
DCHECK(mock_webrtc_receiver_);
DCHECK(track_ref);
RtpReceiverState state(
main_thread_, dependency_factory_->GetWebRtcSignalingThread(),
mock_webrtc_receiver_.get(), std::move(track_ref), {});
state.Initialize();
return std::make_unique<RTCRtpReceiver>(peer_connection_.get(),
std::move(state));
}
scoped_refptr<WebRTCStatsReportObtainer> GetStats() {
scoped_refptr<WebRTCStatsReportObtainer> obtainer =
new WebRTCStatsReportObtainer();
receiver_->GetStats(obtainer->GetStatsCallbackWrapper(),
blink::RTCStatsFilter::kIncludeOnlyStandardMembers);
return obtainer;
}
protected:
void CreateReceiverOnSignalingThread(
scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track,
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>* track_ref,
base::RunLoop* run_loop) {
mock_webrtc_receiver_ =
new rtc::RefCountedObject<webrtc::MockRtpReceiver>();
*track_ref = track_map_->GetOrCreateRemoteTrackAdapter(webrtc_track);
run_loop->Quit();
}
// Code under test expects to be run in a process with an initialized
// ChildProcess, which requires TaskScheduler, and a main-thread MessageLoop,
// which the ScopedTaskEnvironment also provides.
base::test::ScopedTaskEnvironment task_environment_;
ChildProcess child_process_;
std::unique_ptr<MockPeerConnectionDependencyFactory> dependency_factory_;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
scoped_refptr<WebRtcMediaStreamTrackAdapterMap> track_map_;
rtc::scoped_refptr<MockPeerConnectionImpl> peer_connection_;
rtc::scoped_refptr<webrtc::MockRtpReceiver> mock_webrtc_receiver_;
std::unique_ptr<RTCRtpReceiver> receiver_;
};
TEST_F(RTCRtpReceiverTest, CreateReceiver) {
scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
MockWebRtcAudioTrack::Create("webrtc_track");
receiver_ = CreateReceiver(webrtc_track);
EXPECT_FALSE(receiver_->Track().IsNull());
EXPECT_EQ(receiver_->Track().Id().Utf8(), webrtc_track->id());
EXPECT_EQ(receiver_->state().track_ref()->webrtc_track(), webrtc_track);
}
TEST_F(RTCRtpReceiverTest, ShallowCopy) {
scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
MockWebRtcAudioTrack::Create("webrtc_track");
receiver_ = CreateReceiver(webrtc_track);
auto copy = std::make_unique<RTCRtpReceiver>(*receiver_);
EXPECT_EQ(receiver_->state().track_ref()->webrtc_track(), webrtc_track);
const auto& webrtc_receiver = receiver_->state().webrtc_receiver();
auto web_track_unique_id = receiver_->Track().UniqueId();
// Copy is identical to original.
EXPECT_EQ(copy->state().webrtc_receiver(), webrtc_receiver);
EXPECT_EQ(copy->state().track_ref()->webrtc_track(), webrtc_track);
EXPECT_EQ(copy->Track().UniqueId(), web_track_unique_id);
// Copy keeps the internal state alive.
receiver_.reset();
EXPECT_EQ(copy->state().webrtc_receiver(), webrtc_receiver);
EXPECT_EQ(copy->state().track_ref()->webrtc_track(), webrtc_track);
EXPECT_EQ(copy->Track().UniqueId(), web_track_unique_id);
}
TEST_F(RTCRtpReceiverTest, GetStats) {
scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
MockWebRtcAudioTrack::Create("webrtc_track");
receiver_ = CreateReceiver(webrtc_track);
// Make the mock return a blink version of the |webtc_report|. The mock does
// not perform any stats filtering, we just set it to a dummy value.
rtc::scoped_refptr<webrtc::RTCStatsReport> webrtc_report =
webrtc::RTCStatsReport::Create(0u);
webrtc_report->AddStats(
std::make_unique<webrtc::RTCInboundRTPStreamStats>("stats-id", 1234u));
peer_connection_->SetGetStatsReport(webrtc_report);
auto obtainer = GetStats();
// Make sure the operation is async.
EXPECT_FALSE(obtainer->report());
// Wait for the report, this performs the necessary run-loop.
auto* report = obtainer->WaitForReport();
EXPECT_TRUE(report);
// Verify dummy value.
EXPECT_EQ(report->Size(), 1u);
auto stats = report->GetStats(blink::WebString::FromUTF8("stats-id"));
EXPECT_TRUE(stats);
EXPECT_EQ(stats->Timestamp(), 1.234);
}
} // namespace content