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

content / browser / media / session / media_session_controller.h [blame]

// Copyright 2016 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_SESSION_MEDIA_SESSION_CONTROLLER_H_
#define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLER_H_

#include <optional>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/browser/media/media_devices_util.h"
#include "content/browser/media/session/media_session_player_observer.h"
#include "content/common/content_export.h"
#include "content/public/browser/media_player_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "media/audio/audio_device_description.h"
#include "media/base/media_content_type.h"
#include "services/media_session/public/cpp/media_position.h"
#include "services/media_session/public/mojom/media_session.mojom.h"

namespace content {

class MediaSessionImpl;
class WebContentsImpl;

// Helper class for controlling a single player's MediaSession instance.  Sends
// browser side MediaSession commands back to a player hosted in the renderer
// process.
// MediaSessionController registers itself with MediaSessionImpl as the
// MediaSessionPlayerObserver for the associated player, and for that player
// only.  Consequently, it expects all MediaSessionPlayerObserver calls to
// occur for that player only.
class CONTENT_EXPORT MediaSessionController
    : public MediaSessionPlayerObserver {
 public:
  MediaSessionController(const MediaPlayerId& id,
                         WebContentsImpl* web_contents);

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

  ~MediaSessionController() override;

  // Must be called when media player metadata changes.
  void SetMetadata(bool has_audio,
                   bool has_video,
                   media::MediaContentType media_content_type);

  // Must be called when playback starts.  Returns false if a media session
  // cannot be created.
  bool OnPlaybackStarted();

  // Must be called when a pause occurs on the renderer side media player; keeps
  // the MediaSession instance in sync with renderer side behavior.
  void OnPlaybackPaused(bool reached_end_of_stream);

  // MediaSessionPlayerObserver implementation.
  void OnSuspend(int player_id) override;
  void OnResume(int player_id) override;
  void OnSeekForward(int player_id, base::TimeDelta seek_time) override;
  void OnSeekBackward(int player_id, base::TimeDelta seek_time) override;
  void OnSeekTo(int player_id, base::TimeDelta seek_time) override;
  void OnSetVolumeMultiplier(int player_id, double volume_multiplier) override;
  void OnEnterPictureInPicture(int player_id) override;
  void OnSetAudioSinkId(int player_id,
                        const std::string& raw_device_id) override;
  void OnSetMute(int player_id, bool mute) override;
  void OnRequestMediaRemoting(int player_id) override;
  void OnRequestVisibility(
      int player_id,
      RequestVisibilityCallback request_visibility_callback) override;
  RenderFrameHost* render_frame_host() const override;
  std::optional<media_session::MediaPosition> GetPosition(
      int player_id) const override;
  bool IsPictureInPictureAvailable(int player_id) const override;
  bool HasSufficientlyVisibleVideo(int player_id) const override;
  bool HasAudio(int player_id) const override;
  bool HasVideo(int player_id) const override;
  bool IsPaused(int player_id) const override;
  std::string GetAudioOutputSinkId(int player_id) const override;
  bool SupportsAudioOutputDeviceSwitching(int player_id) const override;
  media::MediaContentType GetMediaContentType() const override;

  // Test helpers.
  int get_player_id_for_testing() const { return player_id_; }

  // Called when entering/leaving Picture-in-Picture for the given media
  // player.
  void PictureInPictureStateChanged(bool is_picture_in_picture);

  // Called when the WebContents is either muted or unmuted.
  void WebContentsMutedStateChanged(bool muted);

  // Called when the media position state of the player has changed.
  void OnMediaPositionStateChanged(
      const media_session::MediaPosition& position);

  void OnMediaMutedStatusChanged(bool mute);

  // Called when the media picture-in-picture availability has changed.
  void OnPictureInPictureAvailabilityChanged(bool available);

  // Called when the audio output device has changed.
  void OnAudioOutputSinkChanged(const std::string& raw_device_id);

  // Called when the ability to switch audio output devices has been disabled.
  void OnAudioOutputSinkChangingDisabled();

  // Called when the RemotePlayback metadata has changed.
  void OnRemotePlaybackMetadataChanged(
      media_session::mojom::RemotePlaybackMetadataPtr metadata);

  // Called when video visibility changes for the given media player.
  void OnVideoVisibilityChanged(bool meets_visibility_threshold);

 private:
  bool IsMediaSessionNeeded() const;

  // Determines whether a session is needed and adds or removes the player
  // accordingly.
  bool AddOrRemovePlayer();

  void OnHashedSinkIdReceived(const std::string& hashed_sink_id);

  const MediaPlayerId id_;

  // Outlives |this|.
  const raw_ptr<WebContentsImpl> web_contents_;

  // Outlives |this|.
  const raw_ptr<MediaSessionImpl> media_session_;

  std::optional<media_session::MediaPosition> position_;

  // These objects are only created on the UI thread, so this is safe.
  static int player_count_;
  const int player_id_ = player_count_++;

  bool is_paused_ = true;
  // Playing or paused, but not ended.
  bool is_playback_in_progress_ = false;
  bool has_audio_ = false;
  bool has_video_ = false;
  bool is_picture_in_picture_available_ = false;
  bool has_sufficiently_visible_video_ = false;
  std::string audio_output_sink_id_ =
      media::AudioDeviceDescription::kDefaultDeviceId;
  bool supports_audio_output_device_switching_ = true;
  media::MediaContentType media_content_type_ =
      media::MediaContentType::kPersistent;

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

}  // namespace content

#endif  // CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLER_H_