Change FakePeriodicVideoCapturer to use a TaskQueue instead of Thread.

This changes callbacks to OnFrame methods to occur on a task queue which
is in line with how it's called in production.

The change is essentially around inheriting from FakeVideoCapturerWithTaskQueue
instead of FakeVideoCapturer, but also removes the dependency on rtc::MessageHandler.

Along the way I'm also updating an ortc test that uses FakePeriodicVideoCapturer
and had a bug that was masked by the fact that FakePeriodicVideoCapturer
previously used rtc::Thread::Current internally, but was being called
by the wrong thread (and there were no checks for it).
As a result, I'm also adding a bunch of checks to help with correct usage.

Bug: webrtc:8841, webrtc:8848
Change-Id: I21b710873b508ebc55f8d2e4545d862766656871
Reviewed-on: https://webrtc-review.googlesource.com/49400
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21951}
This commit is contained in:
Tommi 2018-02-07 21:09:11 +01:00 committed by Commit Bot
parent 7ff6ca5844
commit 8b0ebb9484
3 changed files with 68 additions and 42 deletions

View File

@ -77,6 +77,7 @@ class OrtcFactoryIntegrationTest : public testing::Test {
// Sockets are bound to the ANY address, so this is needed to tell the
// virtual network which address to use in this case.
virtual_socket_server_.SetDefaultRoute(kIPv4LocalHostAddress);
network_thread_.SetName("TestNetworkThread", this);
network_thread_.Start();
// Need to create after network thread is started.
ortc_factory1_ =
@ -220,7 +221,7 @@ class OrtcFactoryIntegrationTest : public testing::Test {
rtc::scoped_refptr<webrtc::VideoTrackInterface>
CreateLocalVideoTrackAndFakeCapturer(const std::string& id,
OrtcFactoryInterface* ortc_factory) {
cricket::FakeVideoCapturer* fake_capturer =
webrtc::FakePeriodicVideoCapturer* fake_capturer =
new webrtc::FakePeriodicVideoCapturer();
fake_video_capturers_.push_back(fake_capturer);
rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source =
@ -350,7 +351,7 @@ class OrtcFactoryIntegrationTest : public testing::Test {
std::unique_ptr<OrtcFactoryInterface> ortc_factory1_;
std::unique_ptr<OrtcFactoryInterface> ortc_factory2_;
// Actually owned by video tracks.
std::vector<cricket::FakeVideoCapturer*> fake_video_capturers_;
std::vector<webrtc::FakePeriodicVideoCapturer*> fake_video_capturers_;
int received_audio_frames1_ = 0;
int received_audio_frames2_ = 0;
int rendered_video_frames1_ = 0;
@ -462,7 +463,7 @@ TEST_F(OrtcFactoryIntegrationTest, SetTrackWhileSending) {
// Stop the old capturer, set a new track, and verify new frames are received
// from the new track. Stopping the old capturer ensures that we aren't
// actually still getting frames from it.
fake_video_capturers_[0]->Stop();
fake_video_capturers_[0]->StopFrameDelivery();
int prev_num_frames = fake_renderer.num_rendered_frames();
error = sender->SetTrack(
CreateLocalVideoTrackAndFakeCapturer("video_2", ortc_factory1_.get()));

View File

@ -368,6 +368,7 @@ if (rtc_include_tests) {
"../rtc_base:rtc_base",
"../rtc_base:rtc_base_approved",
"../rtc_base:rtc_base_tests_utils",
"../rtc_base:rtc_task_queue_api",
"../test:test_support",
]

View File

@ -14,59 +14,83 @@
#ifndef PC_TEST_FAKEPERIODICVIDEOCAPTURER_H_
#define PC_TEST_FAKEPERIODICVIDEOCAPTURER_H_
#include <memory>
#include <vector>
#include "media/base/fakevideocapturer.h"
#include "rtc_base/thread.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/thread_checker.h"
namespace webrtc {
class FakePeriodicVideoCapturer : public cricket::FakeVideoCapturer,
public rtc::MessageHandler {
class FakePeriodicVideoCapturer
: public cricket::FakeVideoCapturerWithTaskQueue {
public:
FakePeriodicVideoCapturer() {
std::vector<cricket::VideoFormat> formats;
formats.push_back(cricket::VideoFormat(1280, 720,
cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
formats.push_back(cricket::VideoFormat(640, 480,
cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
formats.push_back(cricket::VideoFormat(640, 360,
cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
formats.push_back(cricket::VideoFormat(320, 240,
cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
formats.push_back(cricket::VideoFormat(160, 120,
cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
ResetSupportedFormats(formats);
worker_thread_checker_.DetachFromThread();
using cricket::VideoFormat;
static const VideoFormat formats[] = {
{1280, 720, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420},
{640, 480, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420},
{640, 360, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420},
{320, 240, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420},
{160, 120, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420},
};
ResetSupportedFormats({&formats[0], &formats[arraysize(formats)]});
}
virtual cricket::CaptureState Start(const cricket::VideoFormat& format) {
cricket::CaptureState state = FakeVideoCapturer::Start(format);
if (state != cricket::CS_FAILED) {
rtc::Thread::Current()->Post(RTC_FROM_HERE, this, MSG_CREATEFRAME);
}
return state;
~FakePeriodicVideoCapturer() override {
RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
}
virtual void Stop() {
rtc::Thread::Current()->Clear(this);
}
// Inherited from MesageHandler.
virtual void OnMessage(rtc::Message* msg) {
if (msg->message_id == MSG_CREATEFRAME) {
if (IsRunning()) {
CaptureFrame();
rtc::Thread::Current()->PostDelayed(
RTC_FROM_HERE, static_cast<int>(GetCaptureFormat()->interval /
rtc::kNumNanosecsPerMillisec),
this, MSG_CREATEFRAME);
}
}
// Workaround method for tests to allow stopping frame delivery directly.
// The |Start()| method expects to be called from the "worker thread" that
// is owned by the factory (think OrtcFactoryInterface or
// PeerConnectionFactoryInterface). That thread is not directly exposed,
// which can make it tricky for tests to inject calls on.
// So, in order to allow tests to stop frame delivery directly from the
// test thread, we expose this method publicly.
void StopFrameDelivery() {
RunSynchronouslyOnTaskQueue([this]() {
RTC_DCHECK_RUN_ON(&task_queue_);
deliver_frames_ = false;
});
}
private:
enum {
// Offset 0xFF to make sure this don't collide with base class messages.
MSG_CREATEFRAME = 0xFF
};
cricket::CaptureState Start(const cricket::VideoFormat& format) override {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
cricket::CaptureState state = FakeVideoCapturer::Start(format);
if (state != cricket::CS_FAILED) {
task_queue_.PostTask([this]() {
RTC_DCHECK_RUN_ON(&task_queue_);
deliver_frames_ = true;
DeliverFrame();
});
}
return state;
}
void Stop() override {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
StopFrameDelivery();
}
void DeliverFrame() {
RTC_DCHECK_RUN_ON(&task_queue_);
if (IsRunning() && deliver_frames_) {
CaptureFrame();
task_queue_.PostDelayedTask(
[this]() { DeliverFrame(); },
static_cast<int>(GetCaptureFormat()->interval /
rtc::kNumNanosecsPerMillisec));
}
}
rtc::ThreadChecker main_thread_checker_;
rtc::ThreadChecker worker_thread_checker_;
bool deliver_frames_ RTC_GUARDED_BY(task_queue_) = false;
};
} // namespace webrtc