blob: e0b3e89567dc29bc6b316d6d0cb8c5d198003624 [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/webrtc_media_stream_track_adapter.h"
#include <memory>
#include "base/bind.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/stream/media_stream_video_track.h"
#include "content/renderer/media/stream/mock_media_stream_video_sink.h"
#include "content/renderer/media/stream/mock_media_stream_video_source.h"
#include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.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_media_stream_track.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_heap.h"
namespace content {
class WebRtcMediaStreamTrackAdapterTest : public ::testing::Test {
public:
void SetUp() override {
dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
main_thread_ = blink::scheduler::GetSingleThreadTaskRunnerForTesting();
}
void TearDown() override {
if (track_adapter_) {
EXPECT_TRUE(track_adapter_->is_initialized());
track_adapter_->Dispose();
track_adapter_ = nullptr;
RunMessageLoopsUntilIdle();
}
blink::WebHeap::CollectAllGarbageForTesting();
}
blink::WebMediaStreamTrack CreateLocalAudioTrack() {
blink::WebMediaStreamSource web_source;
web_source.Initialize(blink::WebString::FromUTF8("local_audio_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;
}
blink::WebMediaStreamTrack CreateLocalVideoTrack() {
blink::WebMediaStreamSource web_source;
web_source.Initialize(blink::WebString::FromUTF8("local_video_id"),
blink::WebMediaStreamSource::kTypeVideo,
blink::WebString::FromUTF8("local_video_track"),
false);
MockMediaStreamVideoSource* video_source = new MockMediaStreamVideoSource();
// Takes ownership of |video_source|.
web_source.SetPlatformSource(base::WrapUnique(video_source));
return MediaStreamVideoTrack::CreateVideoTrack(
video_source, MediaStreamVideoSource::ConstraintsCallback(), true);
}
void CreateRemoteTrackAdapter(
webrtc::MediaStreamTrackInterface* webrtc_track) {
track_adapter_ = WebRtcMediaStreamTrackAdapter::CreateRemoteTrackAdapter(
dependency_factory_.get(), main_thread_, webrtc_track);
}
void HoldOntoAdapterReference(
base::WaitableEvent* waitable_event,
scoped_refptr<WebRtcMediaStreamTrackAdapter> adapter) {
waitable_event->Wait();
}
// Runs message loops on the webrtc signaling thread and optionally the main
// thread until idle.
void RunMessageLoopsUntilIdle(bool run_loop_on_main_thread = true) {
base::WaitableEvent waitable_event(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE, base::BindOnce(&WebRtcMediaStreamTrackAdapterTest::
RunMessageLoopUntilIdleOnSignalingThread,
base::Unretained(this), &waitable_event));
waitable_event.Wait();
if (run_loop_on_main_thread)
base::RunLoop().RunUntilIdle();
}
void RunMessageLoopUntilIdleOnSignalingThread(
base::WaitableEvent* waitable_event) {
DCHECK(dependency_factory_->GetWebRtcSignalingThread()
->BelongsToCurrentThread());
base::RunLoop().RunUntilIdle();
waitable_event->Signal();
}
protected:
// The ScopedTaskEnvironment prevents the ChildProcess from leaking a
// TaskScheduler.
base::test::ScopedTaskEnvironment scoped_task_environment_;
ChildProcess child_process_;
std::unique_ptr<MockPeerConnectionDependencyFactory> dependency_factory_;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
scoped_refptr<WebRtcMediaStreamTrackAdapter> track_adapter_;
};
TEST_F(WebRtcMediaStreamTrackAdapterTest, LocalAudioTrack) {
track_adapter_ = WebRtcMediaStreamTrackAdapter::CreateLocalTrackAdapter(
dependency_factory_.get(), main_thread_, CreateLocalAudioTrack());
EXPECT_TRUE(track_adapter_->is_initialized());
EXPECT_TRUE(!track_adapter_->web_track().IsNull());
EXPECT_EQ(track_adapter_->web_track().Source().GetType(),
blink::WebMediaStreamSource::kTypeAudio);
EXPECT_TRUE(track_adapter_->webrtc_track());
EXPECT_EQ(track_adapter_->webrtc_track()->kind(),
webrtc::MediaStreamTrackInterface::kAudioKind);
EXPECT_EQ(track_adapter_->webrtc_track()->id().c_str(),
track_adapter_->web_track().Id());
EXPECT_TRUE(track_adapter_->GetLocalTrackAudioSinkForTesting());
EXPECT_EQ(
track_adapter_->GetLocalTrackAudioSinkForTesting()->webrtc_audio_track(),
track_adapter_->webrtc_track());
}
TEST_F(WebRtcMediaStreamTrackAdapterTest, LocalVideoTrack) {
track_adapter_ = WebRtcMediaStreamTrackAdapter::CreateLocalTrackAdapter(
dependency_factory_.get(), main_thread_, CreateLocalVideoTrack());
EXPECT_TRUE(track_adapter_->is_initialized());
EXPECT_TRUE(!track_adapter_->web_track().IsNull());
EXPECT_EQ(track_adapter_->web_track().Source().GetType(),
blink::WebMediaStreamSource::kTypeVideo);
EXPECT_TRUE(track_adapter_->webrtc_track());
EXPECT_EQ(track_adapter_->webrtc_track()->kind(),
webrtc::MediaStreamTrackInterface::kVideoKind);
EXPECT_EQ(track_adapter_->webrtc_track()->id().c_str(),
track_adapter_->web_track().Id());
EXPECT_TRUE(track_adapter_->GetLocalTrackVideoSinkForTesting());
EXPECT_EQ(
track_adapter_->GetLocalTrackVideoSinkForTesting()->webrtc_video_track(),
track_adapter_->webrtc_track());
}
TEST_F(WebRtcMediaStreamTrackAdapterTest, RemoteAudioTrack) {
scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
MockWebRtcAudioTrack::Create("remote_audio_track");
dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE,
base::BindOnce(
&WebRtcMediaStreamTrackAdapterTest::CreateRemoteTrackAdapter,
base::Unretained(this), base::Unretained(webrtc_track.get())));
// The adapter is initialized implicitly in a PostTask, allow it to run.
RunMessageLoopsUntilIdle();
DCHECK(track_adapter_);
EXPECT_TRUE(track_adapter_->is_initialized());
EXPECT_TRUE(!track_adapter_->web_track().IsNull());
EXPECT_EQ(track_adapter_->web_track().Source().GetType(),
blink::WebMediaStreamSource::kTypeAudio);
EXPECT_TRUE(track_adapter_->webrtc_track());
EXPECT_EQ(track_adapter_->webrtc_track()->kind(),
webrtc::MediaStreamTrackInterface::kAudioKind);
EXPECT_EQ(track_adapter_->webrtc_track()->id().c_str(),
track_adapter_->web_track().Id());
EXPECT_TRUE(track_adapter_->GetRemoteAudioTrackAdapterForTesting());
EXPECT_TRUE(
track_adapter_->GetRemoteAudioTrackAdapterForTesting()->initialized());
}
TEST_F(WebRtcMediaStreamTrackAdapterTest, RemoteVideoTrack) {
scoped_refptr<MockWebRtcVideoTrack> webrtc_track =
MockWebRtcVideoTrack::Create("remote_video_track");
dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE,
base::BindOnce(
&WebRtcMediaStreamTrackAdapterTest::CreateRemoteTrackAdapter,
base::Unretained(this), base::Unretained(webrtc_track.get())));
// The adapter is initialized implicitly in a PostTask, allow it to run.
RunMessageLoopsUntilIdle();
DCHECK(track_adapter_);
EXPECT_TRUE(track_adapter_->is_initialized());
EXPECT_TRUE(!track_adapter_->web_track().IsNull());
EXPECT_EQ(track_adapter_->web_track().Source().GetType(),
blink::WebMediaStreamSource::kTypeVideo);
EXPECT_TRUE(track_adapter_->webrtc_track());
EXPECT_EQ(track_adapter_->webrtc_track()->kind(),
webrtc::MediaStreamTrackInterface::kVideoKind);
EXPECT_EQ(track_adapter_->webrtc_track()->id().c_str(),
track_adapter_->web_track().Id());
EXPECT_TRUE(track_adapter_->GetRemoteVideoTrackAdapterForTesting());
EXPECT_TRUE(
track_adapter_->GetRemoteVideoTrackAdapterForTesting()->initialized());
}
TEST_F(WebRtcMediaStreamTrackAdapterTest, RemoteTrackExplicitlyInitialized) {
scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
MockWebRtcAudioTrack::Create("remote_audio_track");
dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE,
base::BindOnce(
&WebRtcMediaStreamTrackAdapterTest::CreateRemoteTrackAdapter,
base::Unretained(this), base::Unretained(webrtc_track.get())));
// Wait for the CreateRemoteTrackAdapter() call, but don't run the main thread
// loop that would have implicitly initialized the adapter.
RunMessageLoopsUntilIdle(false);
DCHECK(track_adapter_);
EXPECT_FALSE(track_adapter_->is_initialized());
// Explicitly initialize before the main thread loop has a chance to run.
track_adapter_->InitializeOnMainThread();
EXPECT_TRUE(track_adapter_->is_initialized());
EXPECT_TRUE(!track_adapter_->web_track().IsNull());
EXPECT_EQ(track_adapter_->web_track().Source().GetType(),
blink::WebMediaStreamSource::kTypeAudio);
EXPECT_TRUE(track_adapter_->webrtc_track());
EXPECT_EQ(track_adapter_->webrtc_track()->kind(),
webrtc::MediaStreamTrackInterface::kAudioKind);
EXPECT_EQ(track_adapter_->webrtc_track()->id().c_str(),
track_adapter_->web_track().Id());
EXPECT_TRUE(track_adapter_->GetRemoteAudioTrackAdapterForTesting());
EXPECT_TRUE(
track_adapter_->GetRemoteAudioTrackAdapterForTesting()->initialized());
}
TEST_F(WebRtcMediaStreamTrackAdapterTest, LastReferenceOnSignalingThread) {
scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
MockWebRtcAudioTrack::Create("remote_audio_track");
dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE,
base::BindOnce(
&WebRtcMediaStreamTrackAdapterTest::CreateRemoteTrackAdapter,
base::Unretained(this), base::Unretained(webrtc_track.get())));
// The adapter is initialized implicitly in a PostTask, allow it to run.
RunMessageLoopsUntilIdle();
DCHECK(track_adapter_);
EXPECT_TRUE(track_adapter_->is_initialized());
base::WaitableEvent waitable_event(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
dependency_factory_->GetWebRtcSignalingThread()->PostTask(
FROM_HERE,
base::BindOnce(
&WebRtcMediaStreamTrackAdapterTest::HoldOntoAdapterReference,
base::Unretained(this), base::Unretained(&waitable_event),
track_adapter_));
// Clear last reference on main thread.
track_adapter_->Dispose();
track_adapter_ = nullptr;
waitable_event.Signal();
RunMessageLoopsUntilIdle();
}
} // namespace content