1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/webrtc/track_observer.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/task/single_thread_task_runner.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
namespace blink {
class TrackObserver::TrackObserverImpl
: public WTF::ThreadSafeRefCounted<TrackObserver::TrackObserverImpl>,
public webrtc::ObserverInterface {
public:
TrackObserverImpl(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
const scoped_refptr<webrtc::MediaStreamTrackInterface>& track)
: main_thread_(main_thread), track_(track) {
// We're on the signaling thread.
DCHECK(!main_thread_->BelongsToCurrentThread());
track->RegisterObserver(this);
}
const scoped_refptr<webrtc::MediaStreamTrackInterface>& track() const {
return track_;
}
const scoped_refptr<base::SingleThreadTaskRunner> main_thread() const {
return main_thread_;
}
protected:
friend class TrackObserver;
void SetCallback(const OnChangedCallback& callback) {
DCHECK(main_thread_->BelongsToCurrentThread());
DCHECK(callback_.is_null());
DCHECK(!callback.is_null());
callback_ = callback;
}
// This needs to be called by the owner of the observer instance before
// the owner releases its reference.
// The reason for this is to avoid a potential race when unregistration is
// done from the main thread while an event is being delivered on the
// signaling thread. If, on the main thread, we're releasing the last
// reference to the observer and attempt to unregister from the observer's
// dtor, and at the same time receive an OnChanged event on the signaling
// thread, we will attempt to increment the refcount in the callback
// from 0 to 1 while the object is being freed. Not good.
void Unregister() {
DCHECK(main_thread_->BelongsToCurrentThread());
callback_.Reset();
track_->UnregisterObserver(this);
// At this point we're guaranteed to not get further callbacks, so it's
// OK to reset the pointer.
track_ = nullptr;
}
private:
friend class WTF::ThreadSafeRefCounted<TrackObserverImpl>;
~TrackObserverImpl() override {
DCHECK(!track_.get()) << "must have been unregistered before deleting";
}
// webrtc::ObserverInterface implementation.
void OnChanged() override {
DCHECK(!main_thread_->BelongsToCurrentThread());
webrtc::MediaStreamTrackInterface::TrackState state = track_->state();
PostCrossThreadTask(
*main_thread_.get(), FROM_HERE,
CrossThreadBindOnce(&TrackObserverImpl::OnChangedOnMainThread,
WrapRefCounted(this), state));
}
void OnChangedOnMainThread(
webrtc::MediaStreamTrackInterface::TrackState state) {
DCHECK(main_thread_->BelongsToCurrentThread());
if (!callback_.is_null())
callback_.Run(state);
}
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
OnChangedCallback callback_; // Only touched on the main thread.
};
TrackObserver::TrackObserver(
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
const scoped_refptr<webrtc::MediaStreamTrackInterface>& track)
: observer_(base::MakeRefCounted<TrackObserverImpl>(main_thread, track)) {}
TrackObserver::~TrackObserver() {
// Explicitly unregister before releasing our reference.
// We do this to avoid a race that could happen if we try to unregister
// inside the dtor of the observer and then receive an event that causes
// the ref count to go up while being destroyed.
observer_->Unregister();
}
void TrackObserver::SetCallback(const OnChangedCallback& callback) {
DCHECK(observer_->main_thread()->BelongsToCurrentThread());
observer_->SetCallback(callback);
}
const scoped_refptr<webrtc::MediaStreamTrackInterface>& TrackObserver::track()
const {
return observer_->track();
}
} // namespace blink
|