1 // Copyright 2019 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 CONTENT_BROWSER_MEDIA_MEDIA_POWER_EXPERIMENT_MANAGER_H_
6 #define CONTENT_BROWSER_MEDIA_MEDIA_POWER_EXPERIMENT_MANAGER_H_
7 
8 #include <map>
9 #include <set>
10 #include <vector>
11 
12 #include "base/callback.h"
13 #include "base/macros.h"
14 #include "base/memory/scoped_refptr.h"
15 #include "base/optional.h"
16 #include "base/sequence_checker.h"
17 #include "base/sequenced_task_runner.h"
18 #include "content/common/content_export.h"
19 #include "content/public/browser/media_player_id.h"
20 #include "media/base/video_codecs.h"
21 
22 namespace content {
23 
24 // Keeps track of all media players across all pages, and notifies them when
25 // they enter or leave an active experiment.
26 class CONTENT_EXPORT MediaPowerExperimentManager {
27  public:
28   // Callback to notify the client when an experiment starts / stops.
29   using ExperimentCB = base::RepeatingCallback<void(bool)>;
30 
31   // Flags for handling notifications of stopped players.
32   enum class NotificationMode {
33     // If the stopped player is the current experiment, then notify it that it
34     // no longer is.
35     kNotify,
36 
37     // If the stopped player is the current experiment, then skip notification.
38     // This is useful if the player is being destroyed.
39     kSkip
40   };
41 
42   MediaPowerExperimentManager();
43   virtual ~MediaPowerExperimentManager();
44 
45   // May return nullptr if experiments aren't enabled.
46   static MediaPowerExperimentManager* Instance();
47 
48   // Called when the given player begins playing.  |cb| will be called if it
49   // becomes / stops being the only playing player, though never re-entrantly.
50   virtual void PlayerStarted(const MediaPlayerId& player, ExperimentCB cb);
51 
52   // Called when the given player has stopped playing.  It is okay if it was
53   // never started via PlayerStarted; we'll just ignore it.  If
54   // |notification_mode| is kSkip, then we won't notify |player| that it's
55   // stopping, if it's the current experiment.
56   virtual void PlayerStopped(
57       const MediaPlayerId& player,
58       NotificationMode notification_mode = NotificationMode::kNotify);
59 
60  private:
61   // Send start / stop notifications and update |current_experiment_player_|
62   // based on whether an experiment should be running.
63   void CheckExperimentState();
64 
65   // Set of all playing players that we know about.
66   std::map<MediaPlayerId, ExperimentCB> players_;
67 
68   // If set, this is the player that has a running experiment.
69   base::Optional<MediaPlayerId> current_experiment_player_;
70   ExperimentCB current_experiment_cb_;
71 
72   scoped_refptr<base::SequencedTaskRunner> task_runner_;
73   SEQUENCE_CHECKER(sequence_checker_);
74 
75   DISALLOW_COPY_AND_ASSIGN(MediaPowerExperimentManager);
76 };
77 
78 }  // namespace content
79 
80 #endif  // CONTENT_BROWSER_MEDIA_MEDIA_POWER_EXPERIMENT_MANAGER_H_
81