Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / media / webrtc / track_observer.cc
blobc8ef2d3c52f64a6e5565f274eec5ff1cbf4cb252
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/media/webrtc/track_observer.h"
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/threading/thread_checker.h"
11 namespace content {
13 class CONTENT_EXPORT TrackObserver::TrackObserverImpl
14 : public base::RefCountedThreadSafe<TrackObserver::TrackObserverImpl>,
15 NON_EXPORTED_BASE(public webrtc::ObserverInterface) {
16 public:
17 TrackObserverImpl(
18 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
19 const scoped_refptr<webrtc::MediaStreamTrackInterface>& track)
20 : main_thread_(main_thread), track_(track) {
21 // We're on the signaling thread.
22 track->RegisterObserver(this);
25 const scoped_refptr<webrtc::MediaStreamTrackInterface>& track() const {
26 return track_;
29 const scoped_refptr<base::SingleThreadTaskRunner> main_thread() const {
30 return main_thread_;
33 protected:
34 friend class TrackObserver;
35 void SetCallback(const OnChangedCallback& callback) {
36 DCHECK(main_thread_->BelongsToCurrentThread());
37 DCHECK(callback_.is_null());
38 DCHECK(!callback.is_null());
39 callback_ = callback;
42 // This needs to be called by the owner of the observer instance before
43 // the owner releases its reference.
44 // The reason for this is to avoid a potential race when unregistration is
45 // done from the main thread while an event is being delivered on the
46 // signaling thread. If, on the main thread, we're releasing the last
47 // reference to the observer and attempt to unregister from the observer's
48 // dtor, and at the same time receive an OnChanged event on the signaling
49 // thread, we will attempt to increment the refcount in the callback
50 // from 0 to 1 while the object is being freed. Not good.
51 void Unregister() {
52 DCHECK(main_thread_->BelongsToCurrentThread());
53 callback_.Reset();
54 track_->UnregisterObserver(this);
55 // At this point we're guaranteed to not get further callbacks, so it's
56 // OK to reset the pointer.
57 track_ = nullptr;
60 private:
61 friend class base::RefCountedThreadSafe<TrackObserverImpl>;
62 ~TrackObserverImpl() override {
63 DCHECK(!track_.get()) << "must have been unregistered before deleting";
66 // webrtc::ObserverInterface implementation.
67 void OnChanged() override {
68 DCHECK(signaling_thread_.CalledOnValidThread());
69 webrtc::MediaStreamTrackInterface::TrackState state = track_->state();
70 main_thread_->PostTask(FROM_HERE,
71 base::Bind(&TrackObserverImpl::OnChangedOnMainThread, this, state));
74 void OnChangedOnMainThread(
75 webrtc::MediaStreamTrackInterface::TrackState state) {
76 DCHECK(main_thread_->BelongsToCurrentThread());
77 if (!callback_.is_null())
78 callback_.Run(state);
81 const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
82 scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
83 OnChangedCallback callback_; // Only touched on the main thread.
84 base::ThreadChecker signaling_thread_;
87 TrackObserver::TrackObserver(
88 const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
89 const scoped_refptr<webrtc::MediaStreamTrackInterface>& track)
90 : observer_(new TrackObserverImpl(main_thread, track)) {
93 TrackObserver::~TrackObserver() {
94 // Explicitly unregister before releasing our reference.
95 // We do this to avoid a race that could happen if we try to unregister
96 // inside the dtor of the observer and then receive an event that causes
97 // the ref count to go up while being destroyed.
98 observer_->Unregister();
101 void TrackObserver::SetCallback(const OnChangedCallback& callback) {
102 DCHECK(observer_->main_thread()->BelongsToCurrentThread());
103 observer_->SetCallback(callback);
106 const scoped_refptr<webrtc::MediaStreamTrackInterface>&
107 TrackObserver::track() const {
108 return observer_->track();
111 } // namespace content