Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/MediaTimer.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=2 sw=2 sts=2 et cindent: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#if !defined(MediaTimer_h_)
8
#define MediaTimer_h_
9
10
#include "mozilla/AbstractThread.h"
11
#include "mozilla/IntegerPrintfMacros.h"
12
#include "mozilla/Monitor.h"
13
#include "mozilla/MozPromise.h"
14
#include "mozilla/RefPtr.h"
15
#include "mozilla/TimeStamp.h"
16
#include "mozilla/Unused.h"
17
#include "nsITimer.h"
18
#include <queue>
19
20
namespace mozilla {
21
22
extern LazyLogModule gMediaTimerLog;
23
24
#define TIMER_LOG(x, ...) \
25
0
  MOZ_ASSERT(gMediaTimerLog); \
26
0
  MOZ_LOG(gMediaTimerLog, LogLevel::Debug, ("[MediaTimer=%p relative_t=%" PRId64 "]" x, this, \
27
0
                                        RelativeMicroseconds(TimeStamp::Now()), ##__VA_ARGS__))
28
29
// This promise type is only exclusive because so far there isn't a reason for
30
// it not to be. Feel free to change that.
31
typedef MozPromise<bool, bool, /* IsExclusive = */ true> MediaTimerPromise;
32
33
// Timers only know how to fire at a given thread, which creates an impedence
34
// mismatch with code that operates with TaskQueues. This class solves
35
// that mismatch with a dedicated (but shared) thread and a nice MozPromise-y
36
// interface.
37
class MediaTimer
38
{
39
public:
40
  explicit MediaTimer(bool aFuzzy = false);
41
42
  // We use a release with a custom Destroy().
43
  NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
44
  NS_IMETHOD_(MozExternalRefCountType) Release(void);
45
46
  RefPtr<MediaTimerPromise> WaitFor(const TimeDuration& aDuration, const char* aCallSite);
47
  RefPtr<MediaTimerPromise> WaitUntil(const TimeStamp& aTimeStamp, const char* aCallSite);
48
  void Cancel(); // Cancel and reject any unresolved promises with false.
49
50
private:
51
0
  virtual ~MediaTimer() { MOZ_ASSERT(OnMediaTimerThread()); }
52
53
  void DispatchDestroy(); // Invoked by Release on an arbitrary thread.
54
  void Destroy(); // Runs on the timer thread.
55
56
  bool OnMediaTimerThread();
57
  void ScheduleUpdate();
58
  void Update();
59
  void UpdateLocked();
60
  bool IsExpired(const TimeStamp& aTarget, const TimeStamp& aNow);
61
  void Reject();
62
63
  static void TimerCallback(nsITimer* aTimer, void* aClosure);
64
  void TimerFired();
65
  void ArmTimer(const TimeStamp& aTarget, const TimeStamp& aNow);
66
67
  bool TimerIsArmed()
68
0
  {
69
0
    return !mCurrentTimerTarget.IsNull();
70
0
  }
71
72
  void CancelTimerIfArmed()
73
0
  {
74
0
    MOZ_ASSERT(OnMediaTimerThread());
75
0
    if (TimerIsArmed()) {
76
0
      TIMER_LOG("MediaTimer::CancelTimerIfArmed canceling timer");
77
0
      mTimer->Cancel();
78
0
      mCurrentTimerTarget = TimeStamp();
79
0
    }
80
0
  }
81
82
83
  struct Entry
84
  {
85
    TimeStamp mTimeStamp;
86
    RefPtr<MediaTimerPromise::Private> mPromise;
87
88
    explicit Entry(const TimeStamp& aTimeStamp, const char* aCallSite)
89
      : mTimeStamp(aTimeStamp)
90
      , mPromise(new MediaTimerPromise::Private(aCallSite))
91
0
    {}
92
93
    // Define a < overload that reverses ordering because std::priority_queue
94
    // provides access to the largest element, and we want the smallest
95
    // (i.e. the soonest).
96
    bool operator<(const Entry& aOther) const
97
0
    {
98
0
      return mTimeStamp > aOther.mTimeStamp;
99
0
    }
100
  };
101
102
  ThreadSafeAutoRefCnt mRefCnt;
103
  NS_DECL_OWNINGTHREAD
104
  nsCOMPtr<nsIEventTarget> mThread;
105
  std::priority_queue<Entry> mEntries;
106
  Monitor mMonitor;
107
  nsCOMPtr<nsITimer> mTimer;
108
  TimeStamp mCurrentTimerTarget;
109
110
  // Timestamps only have relative meaning, so we need a base timestamp for
111
  // logging purposes.
112
  TimeStamp mCreationTimeStamp;
113
  int64_t RelativeMicroseconds(const TimeStamp& aTimeStamp)
114
0
  {
115
0
    return (int64_t) (aTimeStamp - mCreationTimeStamp).ToMicroseconds();
116
0
  }
117
118
  bool mUpdateScheduled;
119
  const bool mFuzzy;
120
};
121
122
// Class for managing delayed dispatches on target thread.
123
class DelayedScheduler {
124
public:
125
  explicit DelayedScheduler(AbstractThread* aTargetThread, bool aFuzzy = false)
126
    : mTargetThread(aTargetThread), mMediaTimer(new MediaTimer(aFuzzy))
127
0
  {
128
0
    MOZ_ASSERT(mTargetThread);
129
0
  }
130
131
0
  bool IsScheduled() const { return !mTarget.IsNull(); }
132
133
  void Reset()
134
0
  {
135
0
    MOZ_ASSERT(mTargetThread->IsCurrentThreadIn(),
136
0
      "Must be on target thread to disconnect");
137
0
    if (IsScheduled()) {
138
0
      mRequest.Disconnect();
139
0
      mTarget = TimeStamp();
140
0
    }
141
0
  }
142
143
  template <typename ResolveFunc, typename RejectFunc>
144
  void Ensure(mozilla::TimeStamp& aTarget,
145
              ResolveFunc&& aResolver,
146
              RejectFunc&& aRejector)
147
0
  {
148
0
    MOZ_ASSERT(mTargetThread->IsCurrentThreadIn());
149
0
    if (IsScheduled() && mTarget <= aTarget) {
150
0
      return;
151
0
    }
152
0
    Reset();
153
0
    mTarget = aTarget;
154
0
    mMediaTimer->WaitUntil(mTarget, __func__)->Then(
155
0
      mTargetThread, __func__,
156
0
      std::forward<ResolveFunc>(aResolver),
157
0
      std::forward<RejectFunc>(aRejector))
158
0
    ->Track(mRequest);
159
0
  }
Unexecuted instantiation: void mozilla::DelayedScheduler::Ensure<mozilla::MediaDecoderStateMachine::DecodingState::StartDormantTimer()::{lambda()#1}, mozilla::MediaDecoderStateMachine::DecodingState::StartDormantTimer()::{lambda()#2}>(mozilla::TimeStamp&, mozilla::MediaDecoderStateMachine::DecodingState::StartDormantTimer()::{lambda()#1}&&, mozilla::MediaDecoderStateMachine::DecodingState::StartDormantTimer()::{lambda()#2}&&)
Unexecuted instantiation: Unified_cpp_dom_media5.cpp:void mozilla::DelayedScheduler::Ensure<mozilla::MediaDecoderStateMachine::SetVideoDecodeModeInternal(mozilla::VideoDecodeMode)::$_24, mozilla::MediaDecoderStateMachine::SetVideoDecodeModeInternal(mozilla::VideoDecodeMode)::$_25>(mozilla::TimeStamp&, mozilla::MediaDecoderStateMachine::SetVideoDecodeModeInternal(mozilla::VideoDecodeMode)::$_24&&, mozilla::MediaDecoderStateMachine::SetVideoDecodeModeInternal(mozilla::VideoDecodeMode)::$_25&&)
Unexecuted instantiation: Unified_cpp_dom_media5.cpp:void mozilla::DelayedScheduler::Ensure<mozilla::MediaDecoderStateMachine::ScheduleStateMachineIn(mozilla::media::TimeUnit const&)::$_34, mozilla::MediaDecoderStateMachine::ScheduleStateMachineIn(mozilla::media::TimeUnit const&)::$_35>(mozilla::TimeStamp&, mozilla::MediaDecoderStateMachine::ScheduleStateMachineIn(mozilla::media::TimeUnit const&)::$_34&&, mozilla::MediaDecoderStateMachine::ScheduleStateMachineIn(mozilla::media::TimeUnit const&)::$_35&&)
160
161
  void CompleteRequest()
162
0
  {
163
0
    MOZ_ASSERT(mTargetThread->IsCurrentThreadIn());
164
0
    mRequest.Complete();
165
0
    mTarget = TimeStamp();
166
0
  }
167
168
private:
169
  RefPtr<AbstractThread> mTargetThread;
170
  RefPtr<MediaTimer> mMediaTimer;
171
  MozPromiseRequestHolder<mozilla::MediaTimerPromise> mRequest;
172
  TimeStamp mTarget;
173
};
174
175
} // namespace mozilla
176
177
#endif