1 // Copyright 2018 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 SERVICES_MEDIA_SESSION_PUBLIC_CPP_TEST_MOCK_MEDIA_SESSION_H_
6 #define SERVICES_MEDIA_SESSION_PUBLIC_CPP_TEST_MOCK_MEDIA_SESSION_H_
7 
8 #include <utility>
9 #include <vector>
10 
11 #include "base/component_export.h"
12 #include "base/containers/flat_map.h"
13 #include "base/optional.h"
14 #include "base/run_loop.h"
15 #include "base/unguessable_token.h"
16 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
17 #include "mojo/public/cpp/bindings/receiver_set.h"
18 #include "mojo/public/cpp/bindings/remote_set.h"
19 #include "services/media_session/public/cpp/media_metadata.h"
20 #include "services/media_session/public/mojom/audio_focus.mojom.h"
21 #include "services/media_session/public/mojom/media_controller.mojom.h"
22 #include "services/media_session/public/mojom/media_session.mojom.h"
23 
24 namespace base {
25 class UnguessableToken;
26 }  // namespace base
27 
28 namespace media_session {
29 namespace test {
30 
31 // A mock MediaSessionObsever that can be used for waiting for state changes.
COMPONENT_EXPORT(MEDIA_SESSION_TEST_SUPPORT_CPP)32 class COMPONENT_EXPORT(MEDIA_SESSION_TEST_SUPPORT_CPP)
33     MockMediaSessionMojoObserver : public mojom::MediaSessionObserver {
34  public:
35   explicit MockMediaSessionMojoObserver(mojom::MediaSession& media_session);
36 
37   ~MockMediaSessionMojoObserver() override;
38 
39   // mojom::MediaSessionObserver overrides.
40   void MediaSessionInfoChanged(mojom::MediaSessionInfoPtr session) override;
41   void MediaSessionMetadataChanged(
42       const base::Optional<MediaMetadata>& metadata) override;
43   void MediaSessionActionsChanged(
44       const std::vector<mojom::MediaSessionAction>& actions) override;
45   void MediaSessionImagesChanged(
46       const base::flat_map<mojom::MediaSessionImageType,
47                            std::vector<MediaImage>>& images) override;
48   void MediaSessionPositionChanged(
49       const base::Optional<media_session::MediaPosition>& position) override;
50 
51   void WaitForState(mojom::MediaSessionInfo::SessionState wanted_state);
52   void WaitForPlaybackState(mojom::MediaPlaybackState wanted_state);
53   void WaitForAudioVideoState(mojom::MediaAudioVideoState wanted_state);
54   void WaitForControllable(bool is_controllable);
55 
56   void WaitForEmptyMetadata();
57   void WaitForExpectedMetadata(const MediaMetadata& metadata);
58 
59   void WaitForEmptyActions();
60   void WaitForExpectedActions(
61       const std::set<mojom::MediaSessionAction>& actions);
62 
63   void WaitForExpectedImagesOfType(mojom::MediaSessionImageType type,
64                                    const std::vector<MediaImage>& images);
65 
66   void WaitForEmptyPosition();
67 
68   // Blocks until notified about MediaPosition changing to one matching
69   // |position|.
70   void WaitForExpectedPosition(const MediaPosition& position);
71 
72   // Blocks until notified about MediaPosition changing to one matching
73   // |position|, where media time is required to be equal to or greater than
74   // the media time of |position|. Returns the media time actually reported
75   // with MediaPosition.
76   base::TimeDelta WaitForExpectedPositionAtLeast(const MediaPosition& position);
77 
78   const mojom::MediaSessionInfoPtr& session_info() const {
79     return session_info_;
80   }
81 
82   const base::Optional<base::Optional<MediaMetadata>>& session_metadata()
83       const {
84     return session_metadata_;
85   }
86 
87   const std::set<mojom::MediaSessionAction>& actions() const {
88     return *session_actions_;
89   }
90 
91   const base::Optional<base::Optional<MediaPosition>>& session_position() {
92     return session_position_;
93   }
94 
95  private:
96   void StartWaiting();
97 
98   mojom::MediaSessionInfoPtr session_info_;
99   base::Optional<base::Optional<MediaMetadata>> session_metadata_;
100   base::Optional<std::set<mojom::MediaSessionAction>> session_actions_;
101   base::Optional<
102       base::flat_map<mojom::MediaSessionImageType, std::vector<MediaImage>>>
103       session_images_;
104   base::Optional<base::Optional<MediaPosition>> session_position_;
105   bool waiting_for_empty_position_ = false;
106 
107   base::Optional<MediaMetadata> expected_metadata_;
108   base::Optional<std::set<mojom::MediaSessionAction>> expected_actions_;
109   base::Optional<bool> expected_controllable_;
110   base::Optional<
111       std::pair<mojom::MediaSessionImageType, std::vector<MediaImage>>>
112       expected_images_of_type_;
113   base::Optional<MediaPosition> expected_position_;
114   base::Optional<MediaPosition> minimum_expected_position_;
115   bool waiting_for_empty_metadata_ = false;
116 
117   base::Optional<mojom::MediaSessionInfo::SessionState> wanted_state_;
118   base::Optional<mojom::MediaPlaybackState> wanted_playback_state_;
119   base::Optional<mojom::MediaAudioVideoState> wanted_audio_video_state_;
120   std::unique_ptr<base::RunLoop> run_loop_;
121 
122   mojo::Receiver<mojom::MediaSessionObserver> receiver_{this};
123 };
124 
125 // A mock MediaSession that can be used for interacting with the Media Session
126 // service during tests.
COMPONENT_EXPORT(MEDIA_SESSION_TEST_SUPPORT_CPP)127 class COMPONENT_EXPORT(MEDIA_SESSION_TEST_SUPPORT_CPP) MockMediaSession
128     : public mojom::MediaSession {
129  public:
130   MockMediaSession();
131   explicit MockMediaSession(bool force_duck);
132 
133   ~MockMediaSession() override;
134 
135   // mojom::MediaSession overrides.
136   void Suspend(SuspendType type) override;
137   void Resume(SuspendType type) override;
138   void StartDucking() override;
139   void StopDucking() override;
140   void GetMediaSessionInfo(GetMediaSessionInfoCallback callback) override;
141   void AddObserver(
142       mojo::PendingRemote<mojom::MediaSessionObserver> observer) override;
143   void GetDebugInfo(GetDebugInfoCallback callback) override;
144   void PreviousTrack() override;
145   void NextTrack() override;
146   void SkipAd() override {}
147   void Seek(base::TimeDelta seek_time) override;
148   void Stop(SuspendType type) override;
149   void GetMediaImageBitmap(const MediaImage& image,
150                            int minimum_size_px,
151                            int desired_size_px,
152                            GetMediaImageBitmapCallback callback) override;
153   void SeekTo(base::TimeDelta seek_time) override;
154   void ScrubTo(base::TimeDelta scrub_to) override;
155   void EnterPictureInPicture() override;
156   void ExitPictureInPicture() override;
157   void SetAudioSinkId(const base::Optional<std::string>& id) override {}
158 
159   void SetIsControllable(bool value);
160   void SetPreferStop(bool value) { prefer_stop_ = value; }
161 
162   void AbandonAudioFocusFromClient();
163 
164   base::UnguessableToken RequestAudioFocusFromService(
165       mojo::Remote<mojom::AudioFocusManager>& service,
166       mojom::AudioFocusType audio_foucs_type);
167 
168   bool RequestGroupedAudioFocusFromService(
169       const base::UnguessableToken& request_id,
170       mojo::Remote<mojom::AudioFocusManager>& service,
171       mojom::AudioFocusType audio_focus_type,
172       const base::UnguessableToken& group_id);
173 
174   mojom::MediaSessionInfo::SessionState GetState() const;
175 
176   mojom::AudioFocusRequestClient* audio_focus_request() const {
177     return afr_client_.get();
178   }
179   void FlushForTesting();
180 
181   void SimulateMetadataChanged(const base::Optional<MediaMetadata>& metadata);
182   void SimulatePositionChanged(const base::Optional<MediaPosition>& position);
183 
184   void ClearAllImages();
185   void SetImagesOfType(mojom::MediaSessionImageType type,
186                        const std::vector<MediaImage>& images);
187 
188   void EnableAction(mojom::MediaSessionAction action);
189   void DisableAction(mojom::MediaSessionAction action);
190 
191   int prev_track_count() const { return prev_track_count_; }
192   int next_track_count() const { return next_track_count_; }
193   int add_observer_count() const { return add_observer_count_; }
194   int seek_count() const { return seek_count_; }
195   int seek_to_count() const { return seek_to_count_; }
196 
197   bool is_scrubbing() const { return is_scrubbing_; }
198   const GURL& last_image_src() const { return last_image_src_; }
199 
200   const base::UnguessableToken& request_id() const { return request_id_; }
201 
202  private:
203   void SetState(mojom::MediaSessionInfo::SessionState);
204   void NotifyObservers();
205   mojom::MediaSessionInfoPtr GetMediaSessionInfoSync() const;
206   void NotifyActionObservers();
207 
208   void RequestAudioFocusFromClient(mojom::AudioFocusType audio_focus_type);
209 
210   mojo::Remote<mojom::AudioFocusRequestClient> afr_client_;
211 
212   base::UnguessableToken request_id_;
213 
214   const bool force_duck_ = false;
215   bool is_ducking_ = false;
216   bool is_controllable_ = false;
217   bool is_scrubbing_ = false;
218   bool prefer_stop_ = false;
219 
220   int prev_track_count_ = 0;
221   int next_track_count_ = 0;
222   int add_observer_count_ = 0;
223   int seek_count_ = 0;
224   int seek_to_count_ = 0;
225 
226   std::set<mojom::MediaSessionAction> actions_;
227 
228   mojom::MediaSessionInfo::SessionState state_ =
229       mojom::MediaSessionInfo::SessionState::kInactive;
230 
231   base::flat_map<mojom::MediaSessionImageType, std::vector<MediaImage>> images_;
232   GURL last_image_src_;
233 
234   mojo::ReceiverSet<mojom::MediaSession> receivers_;
235 
236   mojo::RemoteSet<mojom::MediaSessionObserver> observers_;
237 
238   DISALLOW_COPY_AND_ASSIGN(MockMediaSession);
239 };
240 
241 }  // namespace test
242 }  // namespace media_session
243 
244 #endif  // SERVICES_MEDIA_SESSION_PUBLIC_CPP_TEST_MOCK_MEDIA_SESSION_H_
245