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"
8 #include "base/location.h"
9 #include "base/threading/thread_checker.h"
13 class CONTENT_EXPORT
TrackObserver::TrackObserverImpl
14 : public base::RefCountedThreadSafe
<TrackObserver::TrackObserverImpl
>,
15 NON_EXPORTED_BASE(public webrtc::ObserverInterface
) {
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 {
29 const scoped_refptr
<base::SingleThreadTaskRunner
> main_thread() const {
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());
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.
52 DCHECK(main_thread_
->BelongsToCurrentThread());
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.
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())
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