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

content / browser / media / system_media_controls_notifier.h [blame]

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

#ifndef CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_
#define CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_

#include <memory>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "components/system_media_controls/system_media_controls.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/media_session/public/mojom/media_controller.mojom.h"

namespace base {
class UnguessableToken;
}
namespace content {

// The SystemMediaControlsNotifier connects to the SystemMediaControls API and
// keeps it informed of the current media playback state and metadata. It
// observes changes to the active Media Session and updates the
// SystemMediaControls accordingly.
class CONTENT_EXPORT SystemMediaControlsNotifier
    : public media_session::mojom::MediaControllerObserver,
      public media_session::mojom::MediaControllerImageObserver {
 public:
  SystemMediaControlsNotifier(
      system_media_controls::SystemMediaControls* system_media_controls,
      base::UnguessableToken request_id);

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

  ~SystemMediaControlsNotifier() override;

  // media_session::mojom::MediaControllerObserver implementation.
  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;

  // media_session::mojom::MediaControllerImageObserver implementation.
  void MediaControllerImageChanged(
      ::media_session::mojom::MediaSessionImageType type,
      const SkBitmap& bitmap) override;
  // There's no chapter images in the system media tray view, so we don't need
  // to implement this method.
  void MediaControllerChapterImageChanged(int chapter_index,
                                          const SkBitmap& bitmap) override {}

 private:
  friend class SystemMediaControlsNotifierTest;

  // Updates the system media controls' metadata after a brief delay. If
  // multiple calls are received during the delay, only the last one is applied.
  // This prevents overloading the OS with system calls.
  void DebouncePositionUpdate(media_session::MediaPosition position);
  void DebounceMetadataUpdate(media_session::MediaMetadata metadata);
  void DebouncePlaybackStatusUpdate(
      system_media_controls::SystemMediaControls::PlaybackStatus
          playback_status);
  void DebounceIconUpdate(const SkBitmap& bitmap);
  void DebounceSetIsSeekToEnabled(bool is_seek_to_enabled);

  void MaybeScheduleMetadataUpdate();
  void UpdateMetadata();
  void UpdateIcon();

  // Clear the system's media controls' metadata, and any pending position or
  // metadata updates.
  void ClearAllMetadata();

  // We want to hide the controls on the lock screen on Windows in certain
  // cases. We don't want this functionality on other OSes.
#if BUILDFLAG(IS_WIN)
  // Polls the current idle state of the system.
  void CheckLockState();

  // Called when the idle state changes from unlocked to locked.
  void OnScreenLocked();

  // Called when the idle state changes from locked to unlocked.
  void OnScreenUnlocked();

  // Helper functions for dealing with the timer that hides the System Media
  // Transport Controls on the lock screen 5 seconds after the user pauses.
  void StartHideSmtcTimer();
  void StopHideSmtcTimer();
  void HideSmtcTimerFired();

  bool screen_locked_ = false;
  base::RepeatingTimer lock_polling_timer_;
  base::OneShotTimer hide_smtc_timer_;
#endif  // BUILDFLAG(IS_WIN)

  // Our connection to the System Media Controls instance we should notify.
  // Owned by WebAppSystemMediaControls.
  const raw_ptr<system_media_controls::SystemMediaControls>
      system_media_controls_;

  // Timer to debounce updates.
  base::OneShotTimer metadata_update_timer_;
  base::OneShotTimer icon_update_timer_;
  base::OneShotTimer actions_update_timer_;

  // Pending metadata to be set once `metadata_update_timer_` fires.
  std::optional<media_session::MediaPosition> delayed_position_update_;
  std::optional<media_session::MediaMetadata> delayed_metadata_update_;
  std::optional<system_media_controls::SystemMediaControls::PlaybackStatus>
      delayed_playback_status_;

  // Icon to use once `icon_update_timer_` fires.
  std::optional<SkBitmap> delayed_icon_update_;

  // Pending action to set once `actions_update_timer_` fires.
  std::optional<bool> delayed_is_seek_to_enabled_;

  // Tracks current media session state/metadata.
  mojo::Remote<media_session::mojom::MediaController> media_controller_remote_;
  media_session::mojom::MediaSessionInfoPtr session_info_ptr_;

  // Used to receive updates to the active media controller.
  mojo::Receiver<media_session::mojom::MediaControllerObserver>
      media_controller_observer_receiver_{this};
  mojo::Receiver<media_session::mojom::MediaControllerImageObserver>
      media_controller_image_observer_receiver_{this};

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace content

#endif  // CONTENT_BROWSER_MEDIA_SYSTEM_MEDIA_CONTROLS_NOTIFIER_H_