File: media_session_item_producer.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (258 lines) | stat: -rw-r--r-- 10,605 bytes parent folder | download | duplicates (5)
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_GLOBAL_MEDIA_CONTROLS_PUBLIC_MEDIA_SESSION_ITEM_PRODUCER_H_
#define COMPONENTS_GLOBAL_MEDIA_CONTROLS_PUBLIC_MEDIA_SESSION_ITEM_PRODUCER_H_

#include "base/callback_list.h"
#include "base/component_export.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "components/global_media_controls/public/media_item_manager_observer.h"
#include "components/global_media_controls/public/media_item_producer.h"
#include "components/global_media_controls/public/media_item_ui_observer.h"
#include "components/global_media_controls/public/media_item_ui_observer_set.h"
#include "components/global_media_controls/public/media_session_notification_item.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "services/media_session/public/mojom/media_controller.mojom.h"

namespace global_media_controls {

class MediaItemManager;
class MediaItemUI;
class MediaSessionItemProducerObserver;

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class GlobalMediaControlsDismissReason {
  kUserDismissedNotification = 0,
  kInactiveTimeout = 1,
  kTabClosed = 2,
  kMediaSessionStopped = 3,
  kMaxValue = kMediaSessionStopped,
};

class COMPONENT_EXPORT(GLOBAL_MEDIA_CONTROLS) MediaSessionItemProducer
    : public MediaItemProducer,
      public MediaSessionNotificationItem::Delegate,
      public media_session::mojom::AudioFocusObserver,
      public MediaItemUIObserver {
 public:
  // When given a |source_id|, the MediaSessionItemProducer will only
  // produce MediaItems for the given source (i.e. profile). When empty, it will
  // produce MediaItems for the Media Sessions on all sources (profiles).
  MediaSessionItemProducer(
      mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote,
      mojo::Remote<media_session::mojom::MediaControllerManager>
          controller_manager_remote,
      MediaItemManager* item_manager,
      std::optional<base::UnguessableToken> source_id);
  MediaSessionItemProducer(const MediaSessionItemProducer&) = delete;
  MediaSessionItemProducer& operator=(const MediaSessionItemProducer&) = delete;
  ~MediaSessionItemProducer() override;

  // MediaItemProducer:
  base::WeakPtr<media_message_center::MediaNotificationItem> GetMediaItem(
      const std::string& id) override;
  std::set<std::string> GetActiveControllableItemIds() const override;
  bool HasFrozenItems() override;
  void OnItemShown(const std::string& id, MediaItemUI* item_ui) override;
  bool IsItemActivelyPlaying(const std::string& id) override;

  // MediaSessionNotificationItem::Delegate:
  void ActivateItem(const std::string& id) override;
  void HideItem(const std::string& id) override;
  void RemoveItem(const std::string& id) override;
  void RefreshItem(const std::string& id) override;
  void LogMediaSessionActionButtonPressed(
      const std::string& id,
      media_session::mojom::MediaSessionAction action) override;

  // media_session::mojom::AudioFocusObserver:
  void OnFocusGained(
      media_session::mojom::AudioFocusRequestStatePtr session) override;
  void OnFocusLost(
      media_session::mojom::AudioFocusRequestStatePtr session) override;
  void OnRequestIdReleased(const base::UnguessableToken& request_id) override;

  // MediaItemUIObserver implementation.
  void OnMediaItemUIClicked(const std::string& id,
                            bool activate_original_media) override;
  void OnMediaItemUIDismissed(const std::string& id) override;

  void AddObserver(MediaSessionItemProducerObserver* observer);
  void RemoveObserver(MediaSessionItemProducerObserver* observer);

  bool HasSession(const std::string& id) const;

  void SetAudioSinkId(const std::string& id, const std::string& sink_id);

  media_session::mojom::RemotePlaybackMetadataPtr
  GetRemotePlaybackMetadataFromItem(const std::string& id);

  base::CallbackListSubscription
  RegisterIsAudioOutputDeviceSwitchingSupportedCallback(
      const std::string& id,
      base::RepeatingCallback<void(bool)> callback);

  // Sets `is_id_blocked_callback_` to be used for checking if a request id is
  // blocked.
  void SetIsIdBlockedCallback(
      base::RepeatingCallback<bool(const std::string&)> callback);

  // Called when a media session item is associated with a presentation request
  // as to show the origin associated with the request rather than that for the
  // top frame.
  void UpdateMediaItemSourceOrigin(const std::string& id,
                                   const url::Origin& origin);

 private:
  friend class MediaSessionItemProducerTest;

  class COMPONENT_EXPORT(GLOBAL_MEDIA_CONTROLS) Session
      : public media_session::mojom::MediaControllerObserver {
   public:
    Session(MediaSessionItemProducer* owner,
            const std::string& id,
            std::unique_ptr<MediaSessionNotificationItem> item,
            mojo::Remote<media_session::mojom::MediaController> controller);
    Session(const Session&) = delete;
    Session& operator=(const Session&) = delete;
    ~Session() override;

    // media_session::mojom::MediaControllerObserver:
    void MediaSessionInfoChanged(
        media_session::mojom::MediaSessionInfoPtr session_info) override;
    void MediaSessionMetadataChanged(
        const std::optional<media_session::MediaMetadata>& metadata) override {}
    void MediaSessionActionsChanged(
        const std::vector<media_session::mojom::MediaSessionAction>& actions)
        override;
    void MediaSessionChanged(
        const std::optional<base::UnguessableToken>& request_id) override {}
    void MediaSessionPositionChanged(
        const std::optional<media_session::MediaPosition>& position) override;

    // Called when the request ID associated with this session is released (i.e.
    // when the tab is closed).
    void OnRequestIdReleased();

    MediaSessionNotificationItem* item() { return item_.get(); }

    // Called when a new MediaController is given to the item. We need to
    // observe the same session as our underlying item.
    void SetController(
        mojo::Remote<media_session::mojom::MediaController> controller);

    // Sets the reason why this session was dismissed/removed. Can only be
    // called if the value has not already been set.
    void set_dismiss_reason(GlobalMediaControlsDismissReason reason);

    // Called when a session is interacted with (to reset |inactive_timer_|).
    void OnSessionInteractedWith();

    bool IsPlaying() const;

    void SetAudioSinkId(const std::string& id);

    base::CallbackListSubscription
    RegisterIsAudioDeviceSwitchingSupportedCallback(
        base::RepeatingCallback<void(bool)> callback);

   private:
    static void RecordDismissReason(GlobalMediaControlsDismissReason reason);

    void StartInactiveTimer();

    void OnInactiveTimerFired();

    void RecordInteractionDelayAfterPause();

    void MarkActiveIfNecessary();

    const raw_ptr<MediaSessionItemProducer> owner_;
    const std::string id_;
    std::unique_ptr<MediaSessionNotificationItem> item_;

    // Used to stop/hide a paused session after a period of inactivity.
    base::OneShotTimer inactive_timer_;

    base::TimeTicks last_interaction_time_ = base::TimeTicks::Now();

    // The reason why this session was dismissed/removed.
    std::optional<GlobalMediaControlsDismissReason> dismiss_reason_;

    // True if the session's playback state is "playing".
    bool is_playing_ = false;

    // True if we're currently marked inactive.
    bool is_marked_inactive_ = false;

    // True if the audio output device can be switched.
    bool is_audio_device_switching_supported_ = true;

    // Used to notify changes in audio output device switching capabilities.
    base::RepeatingCallbackList<void(bool)>
        is_audio_device_switching_supported_callback_list_;

    // Used to receive updates to the Media Session playback state.
    mojo::Receiver<media_session::mojom::MediaControllerObserver>
        observer_receiver_{this};

    // Used to request audio output be routed to a different device.
    mojo::Remote<media_session::mojom::MediaController> controller_;
  };

  // Looks up a Session object by its ID. Returns null if not found.
  Session* GetSession(const std::string& id);
  // Called by a Session when it becomes active.
  void OnSessionBecameActive(const std::string& id);
  // Called by a Session when it becomes inactive.
  void OnSessionBecameInactive(const std::string& id);
  void OnReceivedAudioFocusRequests(
      std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions);
  void OnItemUnfrozen(const std::string& id);

  // Used to track whether there are any active controllable sessions.
  std::set<std::string> active_controllable_session_ids_;

  // Tracks the sessions that are currently frozen. If there are only frozen
  // sessions, we will disable the toolbar icon and wait to hide it.
  std::set<std::string> frozen_session_ids_;

  // Tracks the sessions that are currently inactive. Sessions become inactive
  // after a period of time of being paused with no user interaction. Inactive
  // sessions are hidden from the dialog until the user interacts with them
  // again (e.g. by playing the session).
  std::set<std::string> inactive_session_ids_;

  // Connections with the media session service to listen for audio focus
  // updates and control media sessions.
  mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote_;
  mojo::Remote<media_session::mojom::MediaControllerManager>
      controller_manager_remote_;
  mojo::Receiver<media_session::mojom::AudioFocusObserver>
      audio_focus_observer_receiver_{this};

  const raw_ptr<MediaItemManager> item_manager_;

  // Keeps track of all the items we're currently observing.
  MediaItemUIObserverSet item_ui_observer_set_;

  // Checks if the given id should always be blocked (i.e. notification hidden).
  base::RepeatingCallback<bool(const std::string&)> is_id_blocked_callback_;

  // Stores a Session for each media session keyed by its |request_id| in string
  // format.
  std::map<std::string, Session> sessions_;

  base::ObserverList<MediaSessionItemProducerObserver> observers_;

  base::WeakPtrFactory<MediaSessionItemProducer> weak_ptr_factory_{this};
};

}  // namespace global_media_controls

#endif  // COMPONENTS_GLOBAL_MEDIA_CONTROLS_PUBLIC_MEDIA_SESSION_ITEM_PRODUCER_H_