Home | History | Annotate | Download | only in media
      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.
      4 
      5 #ifndef CHROME_BROWSER_MEDIA_AUDIO_STREAM_MONITOR_H_
      6 #define CHROME_BROWSER_MEDIA_AUDIO_STREAM_MONITOR_H_
      7 
      8 #include <map>
      9 
     10 #include "base/callback_forward.h"
     11 #include "base/threading/thread_checker.h"
     12 #include "base/time/default_tick_clock.h"
     13 #include "base/time/time.h"
     14 #include "base/timer/timer.h"
     15 #include "content/public/browser/web_contents_user_data.h"
     16 
     17 namespace base {
     18 class TickClock;
     19 }
     20 
     21 // Repeatedly polls audio streams for their power levels, and "debounces" the
     22 // information into a simple, binary "was recently audible" result for the audio
     23 // indicators in the tab UI.  The debouncing logic is to: 1) Turn on immediately
     24 // when sound is audible; and 2) Hold on for X amount of time after sound has
     25 // gone silent, then turn off.  Said another way, we don't want tab indicators
     26 // to turn on/off repeatedly and annoy the user.  AudioStreamMonitor sends UI
     27 // update notifications only when needed, but may be queried at any time.
     28 //
     29 // There are zero or one instances of AudioStreamMonitor per
     30 // content::WebContents instance (referred to as "the tab" in comments below).
     31 // AudioStreamMonitor is created on-demand, and automatically destroyed when its
     32 // associated WebContents is destroyed.  See content::WebContentsUserData for
     33 // usage.
     34 class AudioStreamMonitor
     35     : public content::WebContentsUserData<AudioStreamMonitor> {
     36  public:
     37   // Returns true if audio has recently been audible from the tab.  This is
     38   // usually called whenever the tab data model is refreshed; but there are
     39   // other use cases as well (e.g., the OOM killer uses this to de-prioritize
     40   // the killing of tabs making sounds).
     41   bool WasRecentlyAudible() const;
     42 
     43   // Starts polling the stream for audio stream power levels using |callback|.
     44   typedef base::Callback<std::pair<float, bool>()> ReadPowerAndClipCallback;
     45   void StartMonitoringStream(int stream_id,
     46                              const ReadPowerAndClipCallback& callback);
     47 
     48   // Stops polling the stream, discarding the internal copy of the |callback|
     49   // provided in the call to StartMonitoringStream().
     50   void StopMonitoringStream(int stream_id);
     51 
     52  private:
     53   friend class content::WebContentsUserData<AudioStreamMonitor>;
     54   friend class AudioStreamMonitorTest;
     55 
     56   enum {
     57     // Desired polling frequency.  Note: If this is set too low, short-duration
     58     // "blip" sounds won't be detected.  http://crbug.com/339133#c4
     59     kPowerMeasurementsPerSecond = 15,
     60 
     61     // Amount of time to hold a tab indicator on after its last blurt.
     62     kHoldOnMilliseconds = 2000
     63   };
     64 
     65   // Invoked by content::WebContentsUserData only.
     66   explicit AudioStreamMonitor(content::WebContents* contents);
     67   virtual ~AudioStreamMonitor();
     68 
     69   // Called by |poll_timer_| to sample the power levels from each of the streams
     70   // playing in the tab.
     71   void Poll();
     72 
     73   // Compares last known indicator state with what it should be, and triggers UI
     74   // updates through |web_contents_| if needed.  When the indicator is turned
     75   // on, |off_timer_| is started to re-invoke this method in the future.
     76   void MaybeToggle();
     77 
     78   // The WebContents instance instance to receive indicator toggle
     79   // notifications.  This pointer should be valid for the lifetime of
     80   // AudioStreamMonitor.
     81   content::WebContents* const web_contents_;
     82 
     83   // Note: |clock_| is always |&default_tick_clock_|, except during unit
     84   // testing.
     85   base::DefaultTickClock default_tick_clock_;
     86   base::TickClock* const clock_;
     87 
     88   // Confirms single-threaded access in debug builds.
     89   base::ThreadChecker thread_checker_;
     90 
     91   // The callbacks to read power levels for each stream.  Only playing (i.e.,
     92   // not paused) streams will have an entry in this map.
     93   typedef std::map<int, ReadPowerAndClipCallback> StreamPollCallbackMap;
     94   StreamPollCallbackMap poll_callbacks_;
     95 
     96   // Records the last time at which sound was audible from any stream.
     97   base::TimeTicks last_blurt_time_;
     98 
     99   // Set to true if the last call to MaybeToggle() determined the indicator
    100   // should be turned on.
    101   bool was_recently_audible_;
    102 
    103   // Calls Poll() at regular intervals while |poll_callbacks_| is non-empty.
    104   base::RepeatingTimer<AudioStreamMonitor> poll_timer_;
    105 
    106   // Started only when an indicator is toggled on, to turn it off again in the
    107   // future.
    108   base::OneShotTimer<AudioStreamMonitor> off_timer_;
    109 
    110   DISALLOW_COPY_AND_ASSIGN(AudioStreamMonitor);
    111 };
    112 
    113 #endif  // CHROME_BROWSER_MEDIA_AUDIO_STREAM_MONITOR_H_
    114