|  | /* | 
|  | *  Copyright 2011 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "pc/video_track.h" | 
|  |  | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "api/notifier.h" | 
|  | #include "api/sequence_checker.h" | 
|  | #include "rtc_base/checks.h" | 
|  | #include "rtc_base/location.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | VideoTrack::VideoTrack( | 
|  | absl::string_view label, | 
|  | rtc::scoped_refptr< | 
|  | VideoTrackSourceProxyWithInternal<VideoTrackSourceInterface>> source, | 
|  | rtc::Thread* worker_thread) | 
|  | : MediaStreamTrack<VideoTrackInterface>(label), | 
|  | worker_thread_(worker_thread), | 
|  | video_source_(std::move(source)), | 
|  | content_hint_(ContentHint::kNone) { | 
|  | RTC_DCHECK_RUN_ON(&signaling_thread_); | 
|  | // Detach the thread checker for VideoSourceBaseGuarded since we'll make calls | 
|  | // to VideoSourceBaseGuarded on the worker thread, but we're currently on the | 
|  | // signaling thread. | 
|  | source_sequence_.Detach(); | 
|  | video_source_->RegisterObserver(this); | 
|  | } | 
|  |  | 
|  | VideoTrack::~VideoTrack() { | 
|  | RTC_DCHECK_RUN_ON(&signaling_thread_); | 
|  | video_source_->UnregisterObserver(this); | 
|  | } | 
|  |  | 
|  | std::string VideoTrack::kind() const { | 
|  | return kVideoKind; | 
|  | } | 
|  |  | 
|  | // AddOrUpdateSink and RemoveSink should be called on the worker | 
|  | // thread. | 
|  | void VideoTrack::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, | 
|  | const rtc::VideoSinkWants& wants) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | VideoSourceBaseGuarded::AddOrUpdateSink(sink, wants); | 
|  | rtc::VideoSinkWants modified_wants = wants; | 
|  | modified_wants.black_frames = !enabled_w_; | 
|  | video_source_->internal()->AddOrUpdateSink(sink, modified_wants); | 
|  | } | 
|  |  | 
|  | void VideoTrack::RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | VideoSourceBaseGuarded::RemoveSink(sink); | 
|  | video_source_->internal()->RemoveSink(sink); | 
|  | } | 
|  |  | 
|  | void VideoTrack::RequestRefreshFrame() { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | video_source_->internal()->RequestRefreshFrame(); | 
|  | } | 
|  |  | 
|  | VideoTrackSourceInterface* VideoTrack::GetSource() const { | 
|  | // Callable from any thread. | 
|  | return video_source_.get(); | 
|  | } | 
|  |  | 
|  | VideoTrackSourceInterface* VideoTrack::GetSourceInternal() const { | 
|  | return video_source_->internal(); | 
|  | } | 
|  |  | 
|  | VideoTrackInterface::ContentHint VideoTrack::content_hint() const { | 
|  | RTC_DCHECK_RUN_ON(&signaling_thread_); | 
|  | return content_hint_; | 
|  | } | 
|  |  | 
|  | void VideoTrack::set_content_hint(ContentHint hint) { | 
|  | RTC_DCHECK_RUN_ON(&signaling_thread_); | 
|  | if (content_hint_ == hint) | 
|  | return; | 
|  | content_hint_ = hint; | 
|  | Notifier<VideoTrackInterface>::FireOnChanged(); | 
|  | } | 
|  |  | 
|  | bool VideoTrack::set_enabled(bool enable) { | 
|  | RTC_DCHECK_RUN_ON(&signaling_thread_); | 
|  |  | 
|  | bool ret = MediaStreamTrack<VideoTrackInterface>::set_enabled(enable); | 
|  |  | 
|  | worker_thread_->Invoke<void>(RTC_FROM_HERE, [&]() { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | enabled_w_ = enable; | 
|  | for (auto& sink_pair : sink_pairs()) { | 
|  | rtc::VideoSinkWants modified_wants = sink_pair.wants; | 
|  | modified_wants.black_frames = !enable; | 
|  | video_source_->AddOrUpdateSink(sink_pair.sink, modified_wants); | 
|  | } | 
|  | }); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | bool VideoTrack::enabled() const { | 
|  | if (worker_thread_->IsCurrent()) { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | return enabled_w_; | 
|  | } | 
|  | RTC_DCHECK_RUN_ON(&signaling_thread_); | 
|  | return MediaStreamTrack<VideoTrackInterface>::enabled(); | 
|  | } | 
|  |  | 
|  | MediaStreamTrackInterface::TrackState VideoTrack::state() const { | 
|  | RTC_DCHECK_RUN_ON(worker_thread_); | 
|  | return MediaStreamTrack<VideoTrackInterface>::state(); | 
|  | } | 
|  |  | 
|  | void VideoTrack::OnChanged() { | 
|  | RTC_DCHECK_RUN_ON(&signaling_thread_); | 
|  | rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls; | 
|  | MediaSourceInterface::SourceState state = video_source_->state(); | 
|  | set_state(state == MediaSourceInterface::kEnded ? kEnded : kLive); | 
|  | } | 
|  |  | 
|  | rtc::scoped_refptr<VideoTrack> VideoTrack::Create( | 
|  | absl::string_view id, | 
|  | rtc::scoped_refptr<VideoTrackSourceInterface> source, | 
|  | rtc::Thread* worker_thread) { | 
|  | rtc::scoped_refptr< | 
|  | VideoTrackSourceProxyWithInternal<VideoTrackSourceInterface>> | 
|  | source_proxy = VideoTrackSourceProxy::Create( | 
|  | rtc::Thread::Current(), worker_thread, std::move(source)); | 
|  |  | 
|  | return rtc::make_ref_counted<VideoTrack>(id, std::move(source_proxy), | 
|  | worker_thread); | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |