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
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146

media / audio / alive_checker.h [blame]

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_AUDIO_ALIVE_CHECKER_H_
#define MEDIA_AUDIO_ALIVE_CHECKER_H_

#include <memory>

#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "media/audio/power_observer_helper.h"
#include "media/base/media_export.h"

namespace media {

// A class that checks if a client that is expected to have regular activity
// is alive. For example, audio streams expect regular callbacks from the
// operating system. The client informs regularly that it's alive by calling
// NotifyAlive(). At a certain interval the AliveChecker checks that it has been
// notified within a timeout period. If not, it runs a callback to inform about
// detecting dead. The callback is run once and further checking is stopped at
// detection. Checking can be restarted if desired.
//
// The AliveChecker can pause checking when the machine is suspending, i.e.
// between suspend and resume notification from base::PowerMonitor. Checking
// during this period can cause false positives. Shorter timeout gives higher
// risk of false positives.
//
// It lives on the task runner it's created on; all functions except
// NotifyAlive() must be called on it. NotifyAlive() can be called on any task
// runner.
//
// It stops at the first NotifyAlive() call if
// |stop_at_first_alive_notification| is specified at construction time. This
// can be useful for example if the platform doesn't support suspend/resume
// notifications, as Linux.
class MEDIA_EXPORT AliveChecker {
 public:
  // Factory callback to create a PowerObserverHelper that can be injected. Can
  // be used by tests to provide a mock.
  using PowerObserverHelperFactoryCallback =
      base::OnceCallback<std::unique_ptr<PowerObserverHelper>(
          scoped_refptr<base::SequencedTaskRunner> task_runner,
          base::RepeatingClosure suspend_callback,
          base::RepeatingClosure resume_callback)>;

  // See class description for general explanation of parameters.
  // In addition the following must be true: |timeout| > |check_interval| > 0.
  // The first version creates a PowerObserverHelper internally, the second
  // version takes a factory callback to allow injecting a PowerObserverHelper,
  // typically a mock for testing. The callback is run in the constructor. The
  // second version doesn't have |pause_check_during_suspend|, since that's
  // implicitly true when providing a PowerObserverHelper.
  AliveChecker(base::RepeatingClosure dead_callback,
               base::TimeDelta check_interval,
               base::TimeDelta timeout,
               bool stop_at_first_alive_notification,
               bool pause_check_during_suspend);
  AliveChecker(base::RepeatingClosure dead_callback,
               base::TimeDelta check_interval,
               base::TimeDelta timeout,
               bool stop_at_first_alive_notification,
               PowerObserverHelperFactoryCallback
                   power_observer_helper_factory_callback);

  AliveChecker(const AliveChecker&) = delete;
  AliveChecker& operator=(const AliveChecker&) = delete;

  ~AliveChecker();

  // Start and stop checking if the client is alive.
  void Start();
  void Stop();

  // Returns whether dead was detected. Reset when Start() is called.
  bool DetectedDead();

  // Called regularly by the client to inform that it's alive. Can be called on
  // any thread.
  void NotifyAlive();

 private:
  // Internal version called by the public constructors, to keep the interface
  // and contract clear in the public versions.
  AliveChecker(base::RepeatingClosure dead_callback,
               base::TimeDelta check_interval,
               base::TimeDelta timeout,
               bool stop_at_first_alive_notification,
               bool pause_check_during_suspend,
               PowerObserverHelperFactoryCallback
                   power_observer_helper_factory_callback);

  // Checks if we have gotten an alive notification within a certain time
  // period. If not, run |dead_callback_|.
  void CheckIfAlive();

  // Sets |last_alive_notification_time_| to the current time.
  void SetLastAliveNotificationTimeToNowOnTaskRunner();

  // Timer to run the check regularly.
  std::unique_ptr<base::RepeatingTimer> check_alive_timer_;

  // Stores the time NotifyAlive() was last called.
  // TODO(grunell): Change from TimeTicks to Atomic32 and remove the task
  // posting in NotifyAlive(). The Atomic32 variable would have to
  // represent some time in seconds or tenths of seconds to be able to span over
  // enough time. Atomic64 cannot be used since it's not supported on 32-bit
  // platforms.
  base::TimeTicks last_alive_notification_time_;

  // The interval at which we check if alive.
  const base::TimeDelta check_interval_;

  // The time interval since |last_alive_notification_time_| after which we
  // decide the client is dead and run |dead_callback_|.
  const base::TimeDelta timeout_;

  // Flags that dead was detected. Set in CheckIfAlive() if we have decided that
  // the client is dead. Cleared in Start().
  bool detected_dead_ = false;

  // The task runner on which this object lives.
  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  // Dead notification callback.
  base::RepeatingClosure dead_callback_;

  // If true, checking stops after first alive notification, otherwise continues
  // until Stop() is called or the client is decided to be dead.
  const bool stop_at_first_alive_notification_;

  // Used for getting suspend/resume notifications.
  std::unique_ptr<PowerObserverHelper> power_observer_;

  base::WeakPtrFactory<AliveChecker> weak_factory_{this};
};

}  // namespace media

#endif  // MEDIA_AUDIO_ALIVE_CHECKER_H_