Reland of Change VideoTrack implementation to invoke VideoTrackSourceInterface::AddOrUpdateSink on wt

Added documentation of thread expectations for video tracks and sources to the API.

Originally landed as patchset #2 id:20001 of https://codereview.webrtc.org/2964863002/.

Patchset 1 is the originall cl.
Patschet 2 is modified so that VideoTrackInterface::AddSink and RemoveSink have a default implementation.

BUG=none

Review-Url: https://codereview.webrtc.org/2989113002
Cr-Commit-Position: refs/heads/master@{#19195}
This commit is contained in:
perkj 2017-07-31 23:22:01 -07:00 committed by Commit Bot
parent 36344a0c9b
commit 773be36bd6
13 changed files with 61 additions and 29 deletions

View File

@ -111,6 +111,11 @@ class MediaStreamTrackInterface : public rtc::RefCountInterface,
// VideoTrackSourceInterface is a reference counted source used for // VideoTrackSourceInterface is a reference counted source used for
// VideoTracks. The same source can be used by multiple VideoTracks. // VideoTracks. The same source can be used by multiple VideoTracks.
// VideoTrackSourceInterface is designed to be invoked on the signaling thread
// except for rtc::VideoSourceInterface<VideoFrame> methods that will be invoked
// on the worker thread via a VideoTrack. A custom implementation of a source
// can inherit AdaptedVideoTrackSource instead of directly implementing this
// interface.
class VideoTrackSourceInterface class VideoTrackSourceInterface
: public MediaSourceInterface, : public MediaSourceInterface,
public rtc::VideoSourceInterface<VideoFrame> { public rtc::VideoSourceInterface<VideoFrame> {
@ -145,6 +150,12 @@ class VideoTrackSourceInterface
virtual ~VideoTrackSourceInterface() {} virtual ~VideoTrackSourceInterface() {}
}; };
// VideoTrackInterface is designed to be invoked on the signaling thread except
// for rtc::VideoSourceInterface<VideoFrame> methods that must be invoked
// on the worker thread.
// PeerConnectionFactory::CreateVideoTrack can be used for creating a VideoTrack
// that ensures thread safety and that all methods are called on the right
// thread.
class VideoTrackInterface class VideoTrackInterface
: public MediaStreamTrackInterface, : public MediaStreamTrackInterface,
public rtc::VideoSourceInterface<VideoFrame> { public rtc::VideoSourceInterface<VideoFrame> {

View File

@ -479,7 +479,8 @@ rtc::scoped_refptr<VideoTrackInterface> OrtcFactory::CreateVideoTrack(
const std::string& id, const std::string& id,
VideoTrackSourceInterface* source) { VideoTrackSourceInterface* source) {
RTC_DCHECK_RUN_ON(signaling_thread_); RTC_DCHECK_RUN_ON(signaling_thread_);
rtc::scoped_refptr<VideoTrackInterface> track(VideoTrack::Create(id, source)); rtc::scoped_refptr<VideoTrackInterface> track(
VideoTrack::Create(id, source, worker_thread_.get()));
return VideoTrackProxy::Create(signaling_thread_, worker_thread_.get(), return VideoTrackProxy::Create(signaling_thread_, worker_thread_.get(),
track); track);
} }

View File

@ -56,8 +56,8 @@ class MediaStreamTest: public testing::Test {
stream_ = MediaStream::Create(kStreamLabel1); stream_ = MediaStream::Create(kStreamLabel1);
ASSERT_TRUE(stream_.get() != NULL); ASSERT_TRUE(stream_.get() != NULL);
video_track_ = video_track_ = VideoTrack::Create(
VideoTrack::Create(kVideoTrackId, FakeVideoTrackSource::Create()); kVideoTrackId, FakeVideoTrackSource::Create(), rtc::Thread::Current());
ASSERT_TRUE(video_track_.get() != NULL); ASSERT_TRUE(video_track_.get() != NULL);
EXPECT_EQ(MediaStreamTrackInterface::kLive, video_track_->state()); EXPECT_EQ(MediaStreamTrackInterface::kLive, video_track_->state());

View File

@ -292,7 +292,7 @@ rtc::scoped_refptr<VideoTrackInterface> PeerConnectionFactory::CreateVideoTrack(
VideoTrackSourceInterface* source) { VideoTrackSourceInterface* source) {
RTC_DCHECK(signaling_thread_->IsCurrent()); RTC_DCHECK(signaling_thread_->IsCurrent());
rtc::scoped_refptr<VideoTrackInterface> track( rtc::scoped_refptr<VideoTrackInterface> track(
VideoTrack::Create(id, source)); VideoTrack::Create(id, source, worker_thread_));
return VideoTrackProxy::Create(signaling_thread_, worker_thread_, track); return VideoTrackProxy::Create(signaling_thread_, worker_thread_, track);
} }

View File

@ -460,7 +460,8 @@ rtc::scoped_refptr<StreamCollection> CreateStreamCollection(
// Add a local video track. // Add a local video track.
rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track( rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
webrtc::VideoTrack::Create(kVideoTracks[i * tracks_per_stream + j], webrtc::VideoTrack::Create(kVideoTracks[i * tracks_per_stream + j],
webrtc::FakeVideoTrackSource::Create())); webrtc::FakeVideoTrackSource::Create(),
rtc::Thread::Current()));
stream->AddTrack(video_track); stream->AddTrack(video_track);
} }
@ -1150,7 +1151,8 @@ class PeerConnectionInterfaceTest : public testing::Test {
MediaStreamInterface* stream) { MediaStreamInterface* stream) {
rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track( rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
webrtc::VideoTrack::Create(track_id, webrtc::VideoTrack::Create(track_id,
webrtc::FakeVideoTrackSource::Create())); webrtc::FakeVideoTrackSource::Create(),
rtc::Thread::Current()));
ASSERT_TRUE(stream->AddTrack(video_track)); ASSERT_TRUE(stream->AddTrack(video_track));
} }

View File

@ -218,6 +218,11 @@ class FakeVideoTrackForStats
std::string kind() const override { std::string kind() const override {
return MediaStreamTrackInterface::kVideoKind; return MediaStreamTrackInterface::kVideoKind;
} }
void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
const rtc::VideoSinkWants& wants) override{};
void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override{};
VideoTrackSourceInterface* GetSource() const override { return nullptr; } VideoTrackSourceInterface* GetSource() const override { return nullptr; }
}; };

View File

@ -155,7 +155,8 @@ VideoRtpReceiver::VideoRtpReceiver(const std::string& track_id,
track_id, track_id,
VideoTrackSourceProxy::Create(rtc::Thread::Current(), VideoTrackSourceProxy::Create(rtc::Thread::Current(),
worker_thread, worker_thread,
source_)))) { source_),
worker_thread))) {
source_->SetState(MediaSourceInterface::kLive); source_->SetState(MediaSourceInterface::kLive);
if (!channel_) { if (!channel_) {
LOG(LS_ERROR) LOG(LS_ERROR)

View File

@ -124,7 +124,8 @@ class RtpSenderReceiverTest : public testing::Test,
void AddVideoTrack(bool is_screencast) { void AddVideoTrack(bool is_screencast) {
rtc::scoped_refptr<VideoTrackSourceInterface> source( rtc::scoped_refptr<VideoTrackSourceInterface> source(
FakeVideoTrackSource::Create(is_screencast)); FakeVideoTrackSource::Create(is_screencast));
video_track_ = VideoTrack::Create(kVideoTrackId, source); video_track_ =
VideoTrack::Create(kVideoTrackId, source, rtc::Thread::Current());
EXPECT_TRUE(local_stream_->AddTrack(video_track_)); EXPECT_TRUE(local_stream_->AddTrack(video_track_));
} }

View File

@ -545,7 +545,8 @@ class StatsCollectorTest : public testing::Test {
void AddOutgoingVideoTrackStats() { void AddOutgoingVideoTrackStats() {
stream_ = webrtc::MediaStream::Create("streamlabel"); stream_ = webrtc::MediaStream::Create("streamlabel");
track_ = webrtc::VideoTrack::Create(kLocalTrackId, track_ = webrtc::VideoTrack::Create(kLocalTrackId,
webrtc::FakeVideoTrackSource::Create()); webrtc::FakeVideoTrackSource::Create(),
rtc::Thread::Current());
stream_->AddTrack(track_); stream_->AddTrack(track_);
EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _)) EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(kLocalTrackId), Return(true))); .WillRepeatedly(DoAll(SetArgPointee<1>(kLocalTrackId), Return(true)));
@ -555,7 +556,8 @@ class StatsCollectorTest : public testing::Test {
void AddIncomingVideoTrackStats() { void AddIncomingVideoTrackStats() {
stream_ = webrtc::MediaStream::Create("streamlabel"); stream_ = webrtc::MediaStream::Create("streamlabel");
track_ = webrtc::VideoTrack::Create(kRemoteTrackId, track_ = webrtc::VideoTrack::Create(kRemoteTrackId,
webrtc::FakeVideoTrackSource::Create()); webrtc::FakeVideoTrackSource::Create(),
rtc::Thread::Current());
stream_->AddTrack(track_); stream_->AddTrack(track_);
EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _)) EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true))); .WillRepeatedly(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true)));

View File

@ -85,10 +85,12 @@ class TrackMediaInfoMapTest : public testing::Test {
remote_audio_track_(AudioTrack::Create("RemoteAudioTrack", nullptr)), remote_audio_track_(AudioTrack::Create("RemoteAudioTrack", nullptr)),
local_video_track_( local_video_track_(
VideoTrack::Create("LocalVideoTrack", VideoTrack::Create("LocalVideoTrack",
FakeVideoTrackSource::Create(false))), FakeVideoTrackSource::Create(false),
rtc::Thread::Current())),
remote_video_track_( remote_video_track_(
VideoTrack::Create("RemoteVideoTrack", VideoTrack::Create("RemoteVideoTrack",
FakeVideoTrackSource::Create(false))) {} FakeVideoTrackSource::Create(false),
rtc::Thread::Current())) {}
~TrackMediaInfoMapTest() { ~TrackMediaInfoMapTest() {
// If we have a map the ownership has been passed to the map, only delete if // If we have a map the ownership has been passed to the map, only delete if

View File

@ -15,11 +15,12 @@
namespace webrtc { namespace webrtc {
VideoTrack::VideoTrack(const std::string& label, VideoTrack::VideoTrack(const std::string& label,
VideoTrackSourceInterface* video_source) VideoTrackSourceInterface* video_source,
rtc::Thread* worker_thread)
: MediaStreamTrack<VideoTrackInterface>(label), : MediaStreamTrack<VideoTrackInterface>(label),
worker_thread_(worker_thread),
video_source_(video_source), video_source_(video_source),
content_hint_(ContentHint::kNone) { content_hint_(ContentHint::kNone) {
worker_thread_checker_.DetachFromThread();
video_source_->RegisterObserver(this); video_source_->RegisterObserver(this);
} }
@ -35,7 +36,7 @@ std::string VideoTrack::kind() const {
// thread. // thread.
void VideoTrack::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, void VideoTrack::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
const rtc::VideoSinkWants& wants) { const rtc::VideoSinkWants& wants) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_->IsCurrent());
VideoSourceBase::AddOrUpdateSink(sink, wants); VideoSourceBase::AddOrUpdateSink(sink, wants);
rtc::VideoSinkWants modified_wants = wants; rtc::VideoSinkWants modified_wants = wants;
modified_wants.black_frames = !enabled(); modified_wants.black_frames = !enabled();
@ -43,7 +44,7 @@ void VideoTrack::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
} }
void VideoTrack::RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) { void VideoTrack::RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_->IsCurrent());
VideoSourceBase::RemoveSink(sink); VideoSourceBase::RemoveSink(sink);
video_source_->RemoveSink(sink); video_source_->RemoveSink(sink);
} }
@ -63,13 +64,14 @@ void VideoTrack::set_content_hint(ContentHint hint) {
bool VideoTrack::set_enabled(bool enable) { bool VideoTrack::set_enabled(bool enable) {
RTC_DCHECK(signaling_thread_checker_.CalledOnValidThread()); RTC_DCHECK(signaling_thread_checker_.CalledOnValidThread());
for (auto& sink_pair : sink_pairs()) { worker_thread_->Invoke<void>(RTC_FROM_HERE, [enable, this] {
rtc::VideoSinkWants modified_wants = sink_pair.wants; RTC_DCHECK(worker_thread_->IsCurrent());
modified_wants.black_frames = !enable; for (auto& sink_pair : sink_pairs()) {
// video_source_ is a proxy object, marshalling the call to the rtc::VideoSinkWants modified_wants = sink_pair.wants;
// worker thread. modified_wants.black_frames = !enable;
video_source_->AddOrUpdateSink(sink_pair.sink, modified_wants); video_source_->AddOrUpdateSink(sink_pair.sink, modified_wants);
} }
});
return MediaStreamTrack<VideoTrackInterface>::set_enabled(enable); return MediaStreamTrack<VideoTrackInterface>::set_enabled(enable);
} }
@ -84,9 +86,10 @@ void VideoTrack::OnChanged() {
rtc::scoped_refptr<VideoTrack> VideoTrack::Create( rtc::scoped_refptr<VideoTrack> VideoTrack::Create(
const std::string& id, const std::string& id,
VideoTrackSourceInterface* source) { VideoTrackSourceInterface* source,
rtc::Thread* worker_thread) {
rtc::RefCountedObject<VideoTrack>* track = rtc::RefCountedObject<VideoTrack>* track =
new rtc::RefCountedObject<VideoTrack>(id, source); new rtc::RefCountedObject<VideoTrack>(id, source, worker_thread);
return track; return track;
} }

View File

@ -27,7 +27,8 @@ class VideoTrack : public MediaStreamTrack<VideoTrackInterface>,
public: public:
static rtc::scoped_refptr<VideoTrack> Create( static rtc::scoped_refptr<VideoTrack> Create(
const std::string& label, const std::string& label,
VideoTrackSourceInterface* source); VideoTrackSourceInterface* source,
rtc::Thread* worker_thread);
void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
const rtc::VideoSinkWants& wants) override; const rtc::VideoSinkWants& wants) override;
@ -42,15 +43,17 @@ class VideoTrack : public MediaStreamTrack<VideoTrackInterface>,
std::string kind() const override; std::string kind() const override;
protected: protected:
VideoTrack(const std::string& id, VideoTrackSourceInterface* video_source); VideoTrack(const std::string& id,
VideoTrackSourceInterface* video_source,
rtc::Thread* worker_thread);
~VideoTrack(); ~VideoTrack();
private: private:
// Implements ObserverInterface. Observes |video_source_| state. // Implements ObserverInterface. Observes |video_source_| state.
void OnChanged() override; void OnChanged() override;
rtc::Thread* const worker_thread_;
rtc::ThreadChecker signaling_thread_checker_; rtc::ThreadChecker signaling_thread_checker_;
rtc::ThreadChecker worker_thread_checker_;
rtc::scoped_refptr<VideoTrackSourceInterface> video_source_; rtc::scoped_refptr<VideoTrackSourceInterface> video_source_;
ContentHint content_hint_ GUARDED_BY(signaling_thread_checker_); ContentHint content_hint_ GUARDED_BY(signaling_thread_checker_);
}; };

View File

@ -31,7 +31,8 @@ class VideoTrackTest : public testing::Test {
static const char kVideoTrackId[] = "track_id"; static const char kVideoTrackId[] = "track_id";
video_track_source_ = new rtc::RefCountedObject<VideoTrackSource>( video_track_source_ = new rtc::RefCountedObject<VideoTrackSource>(
&capturer_, true /* remote */); &capturer_, true /* remote */);
video_track_ = VideoTrack::Create(kVideoTrackId, video_track_source_); video_track_ = VideoTrack::Create(kVideoTrackId, video_track_source_,
rtc::Thread::Current());
capturer_.Start( capturer_.Start(
cricket::VideoFormat(640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::VideoFormat(640, 480, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420)); cricket::FOURCC_I420));