Bug 1430948. P1 - add fuzzy mode to MediaTimer.
We will resolve the timer promise even if it is fired slightly before
the scheduled target. This is used by MDSM which doesn't require high-res
timers.
MozReview-Commit-ID: 1IAsG5gG9D7
--- a/dom/media/MediaTimer.cpp
+++ b/dom/media/MediaTimer.cpp
@@ -13,21 +13,22 @@
#include "nsThreadUtils.h"
#include <math.h>
namespace mozilla {
NS_IMPL_ADDREF(MediaTimer)
NS_IMPL_RELEASE_WITH_DESTROY(MediaTimer, DispatchDestroy())
-MediaTimer::MediaTimer()
+MediaTimer::MediaTimer(bool aFuzzy)
: mMonitor("MediaTimer Monitor")
, mTimer(NS_NewTimer())
, mCreationTimeStamp(TimeStamp::Now())
, mUpdateScheduled(false)
+ , mFuzzy(aFuzzy)
{
TIMER_LOG("MediaTimer::MediaTimer");
// Use the SharedThreadPool to create an nsIThreadPool with a maximum of one
// thread, which is equivalent to an nsIThread for our purposes.
RefPtr<SharedThreadPool> threadPool(
SharedThreadPool::Get(NS_LITERAL_CSTRING("MediaTimer"), 1));
mThread = threadPool.get();
@@ -109,28 +110,41 @@ MediaTimer::ScheduleUpdate()
void
MediaTimer::Update()
{
MonitorAutoLock mon(mMonitor);
UpdateLocked();
}
+bool
+MediaTimer::IsExpired(const TimeStamp& aTarget, const TimeStamp& aNow)
+{
+ MOZ_ASSERT(OnMediaTimerThread());
+ mMonitor.AssertCurrentThreadOwns();
+ // Treat this timer as expired in fuzzy mode even if it is fired
+ // slightly (< 1ms) before the schedule target. So we don't need to schedule a
+ // timer with very small timeout again when the client doesn't need a high-res
+ // timer.
+ TimeStamp t = mFuzzy ? aTarget - TimeDuration::FromMilliseconds(1) : aTarget;
+ return t <= aNow;
+}
+
void
MediaTimer::UpdateLocked()
{
MOZ_ASSERT(OnMediaTimerThread());
mMonitor.AssertCurrentThreadOwns();
mUpdateScheduled = false;
TIMER_LOG("MediaTimer::UpdateLocked");
// Resolve all the promises whose time is up.
TimeStamp now = TimeStamp::Now();
- while (!mEntries.empty() && mEntries.top().mTimeStamp <= now) {
+ while (!mEntries.empty() && IsExpired(mEntries.top().mTimeStamp, now)) {
mEntries.top().mPromise->Resolve(true, __func__);
DebugOnly<TimeStamp> poppedTimeStamp = mEntries.top().mTimeStamp;
mEntries.pop();
MOZ_ASSERT_IF(!mEntries.empty(), *&poppedTimeStamp <= mEntries.top().mTimeStamp);
}
// If we've got no more entries, cancel any pending timer and bail out.
if (mEntries.empty()) {
--- a/dom/media/MediaTimer.h
+++ b/dom/media/MediaTimer.h
@@ -31,17 +31,17 @@ typedef MozPromise<bool, bool, /* IsExcl
// Timers only know how to fire at a given thread, which creates an impedence
// mismatch with code that operates with TaskQueues. This class solves
// that mismatch with a dedicated (but shared) thread and a nice MozPromise-y
// interface.
class MediaTimer
{
public:
- MediaTimer();
+ explicit MediaTimer(bool aFuzzy = false);
// We use a release with a custom Destroy().
NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
NS_IMETHOD_(MozExternalRefCountType) Release(void);
RefPtr<MediaTimerPromise> WaitUntil(const TimeStamp& aTimeStamp, const char* aCallSite);
private:
@@ -49,16 +49,17 @@ private:
void DispatchDestroy(); // Invoked by Release on an arbitrary thread.
void Destroy(); // Runs on the timer thread.
bool OnMediaTimerThread();
void ScheduleUpdate();
void Update();
void UpdateLocked();
+ bool IsExpired(const TimeStamp& aTarget, const TimeStamp& aNow);
static void TimerCallback(nsITimer* aTimer, void* aClosure);
void TimerFired();
void ArmTimer(const TimeStamp& aTarget, const TimeStamp& aNow);
bool TimerIsArmed()
{
return !mCurrentTimerTarget.IsNull();
@@ -106,23 +107,24 @@ private:
// logging purposes.
TimeStamp mCreationTimeStamp;
int64_t RelativeMicroseconds(const TimeStamp& aTimeStamp)
{
return (int64_t) (aTimeStamp - mCreationTimeStamp).ToMicroseconds();
}
bool mUpdateScheduled;
+ const bool mFuzzy;
};
// Class for managing delayed dispatches on target thread.
class DelayedScheduler {
public:
- explicit DelayedScheduler(AbstractThread* aTargetThread)
- : mTargetThread(aTargetThread), mMediaTimer(new MediaTimer())
+ explicit DelayedScheduler(AbstractThread* aTargetThread, bool aFuzzy = false)
+ : mTargetThread(aTargetThread), mMediaTimer(new MediaTimer(aFuzzy))
{
MOZ_ASSERT(mTargetThread);
}
bool IsScheduled() const { return !mTarget.IsNull(); }
void Reset()
{