Fix emulator build error
[platform/framework/web/chromium-efl.git] / services / media_session / media_controller.cc
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/media_session/media_controller.h"
6
7 #include <set>
8
9 #include "base/containers/contains.h"
10 #include "base/containers/cxx20_erase.h"
11 #include "base/memory/raw_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "mojo/public/cpp/bindings/remote.h"
14 #include "services/media_session/audio_focus_request.h"
15 #include "services/media_session/public/cpp/media_image_manager.h"
16
17 namespace media_session {
18
19 // ImageObserverHolder will hold each mojo image observer with the image
20 // size and type preferences it specified when the observer was added.
21 class MediaController::ImageObserverHolder {
22  public:
23   ImageObserverHolder(
24       MediaController* owner,
25       mojom::MediaSessionImageType type,
26       int minimum_size_px,
27       int desired_size_px,
28       mojo::PendingRemote<mojom::MediaControllerImageObserver> observer,
29       const std::vector<MediaImage>& current_images)
30       : manager_(minimum_size_px, desired_size_px),
31         owner_(owner),
32         type_(type),
33         minimum_size_px_(minimum_size_px),
34         desired_size_px_(desired_size_px),
35         observer_(std::move(observer)) {
36     // Set a connection error handler so that we will remove observers that have
37     // had an error / been closed.
38     observer_.set_disconnect_handler(base::BindOnce(
39         &MediaController::CleanupImageObservers, base::Unretained(owner_)));
40
41     // Flush the observer with the latest state.
42     ImagesChanged(current_images);
43   }
44
45   ImageObserverHolder(const ImageObserverHolder&) = delete;
46   ImageObserverHolder& operator=(const ImageObserverHolder&) = delete;
47
48   ~ImageObserverHolder() = default;
49
50   bool is_valid() const { return observer_.is_connected(); }
51
52   mojom::MediaSessionImageType type() const { return type_; }
53
54   void ImagesChanged(const std::vector<MediaImage>& images) {
55     absl::optional<MediaImage> image = manager_.SelectImage(images);
56
57     // If we could not find an image then we should call with an empty image to
58     // flush the observer.
59     if (!image) {
60       ClearImage();
61       return;
62     }
63
64     DCHECK(owner_->session_->ipc());
65     owner_->session_->GetMediaImageBitmap(
66         *image, minimum_size_px_, desired_size_px_,
67         base::BindOnce(&MediaController::ImageObserverHolder::OnImage,
68                        weak_ptr_factory_.GetWeakPtr()));
69   }
70
71   void ClearImage() {
72     // If the last thing we sent was a ClearImage, don't send another one. If we
73     // haven't sent anything before, then send a ClearImage.
74     if (!did_send_image_last_.value_or(true))
75       return;
76     did_send_image_last_ = false;
77     observer_->MediaControllerImageChanged(type_, SkBitmap());
78   }
79
80  private:
81   void OnImage(const SkBitmap& image) {
82     did_send_image_last_ = true;
83     observer_->MediaControllerImageChanged(type_, image);
84   }
85
86   media_session::MediaImageManager manager_;
87
88   const raw_ptr<MediaController> owner_;
89
90   mojom::MediaSessionImageType const type_;
91
92   int const minimum_size_px_;
93
94   int const desired_size_px_;
95
96   mojo::Remote<mojom::MediaControllerImageObserver> observer_;
97
98   // Whether the last information sent to the observer was an image.
99   // Empty if we have not yet sent anything.
100   absl::optional<bool> did_send_image_last_;
101
102   base::WeakPtrFactory<ImageObserverHolder> weak_ptr_factory_{this};
103 };
104
105 MediaController::MediaController() {
106   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107 }
108
109 MediaController::~MediaController() = default;
110
111 void MediaController::Suspend() {
112   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
113
114   if (session_)
115     session_->PerformUIAction(mojom::MediaSessionAction::kPause);
116 }
117
118 void MediaController::Resume() {
119   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
120
121   if (session_)
122     session_->PerformUIAction(mojom::MediaSessionAction::kPlay);
123 }
124
125 void MediaController::Stop() {
126   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
127
128   if (session_)
129     session_->PerformUIAction(mojom::MediaSessionAction::kStop);
130 }
131
132 void MediaController::ToggleSuspendResume() {
133   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
134
135   if (session_info_.is_null())
136     return;
137
138   switch (session_info_->playback_state) {
139     case mojom::MediaPlaybackState::kPlaying:
140       Suspend();
141       break;
142     case mojom::MediaPlaybackState::kPaused:
143       Resume();
144       break;
145   }
146 }
147
148 void MediaController::AddObserver(
149     mojo::PendingRemote<mojom::MediaControllerObserver> observer) {
150   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
151
152   mojo::Remote<mojom::MediaControllerObserver> media_controller_observer(
153       std::move(observer));
154   if (session_) {
155     media_controller_observer->MediaSessionChanged(session_->id());
156   } else {
157     media_controller_observer->MediaSessionChanged(absl::nullopt);
158   }
159
160   // Flush the new observer with the current state.
161   media_controller_observer->MediaSessionInfoChanged(session_info_.Clone());
162   media_controller_observer->MediaSessionMetadataChanged(session_metadata_);
163   media_controller_observer->MediaSessionActionsChanged(session_actions_);
164   media_controller_observer->MediaSessionPositionChanged(session_position_);
165
166   observers_.Add(std::move(media_controller_observer));
167 }
168
169 void MediaController::MediaSessionInfoChanged(mojom::MediaSessionInfoPtr info) {
170   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
171
172   for (auto& observer : observers_)
173     observer->MediaSessionInfoChanged(info.Clone());
174
175   session_info_ = std::move(info);
176 }
177
178 void MediaController::MediaSessionMetadataChanged(
179     const absl::optional<MediaMetadata>& metadata) {
180   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
181
182   for (auto& observer : observers_)
183     observer->MediaSessionMetadataChanged(metadata);
184
185   session_metadata_ = metadata;
186 }
187
188 void MediaController::MediaSessionActionsChanged(
189     const std::vector<mojom::MediaSessionAction>& actions) {
190   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
191
192   for (auto& observer : observers_)
193     observer->MediaSessionActionsChanged(actions);
194
195   session_actions_ = actions;
196 }
197
198 void MediaController::MediaSessionPositionChanged(
199     const absl::optional<media_session::MediaPosition>& position) {
200   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
201
202   for (auto& observer : observers_)
203     observer->MediaSessionPositionChanged(position);
204
205   session_position_ = position;
206 }
207
208 void MediaController::MediaSessionImagesChanged(
209     const base::flat_map<mojom::MediaSessionImageType, std::vector<MediaImage>>&
210         images) {
211   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
212
213   // Work out which image types have changed.
214   std::set<mojom::MediaSessionImageType> types_changed;
215   for (const auto& entry : images) {
216     auto it = session_images_.find(entry.first);
217     if (it != session_images_.end() && entry.second == it->second)
218       continue;
219
220     types_changed.insert(entry.first);
221   }
222
223   session_images_ = images;
224
225   for (auto& holder : image_observers_) {
226     auto it = session_images_.find(holder->type());
227
228     if (it == session_images_.end()) {
229       // No image of this type is available from the session so we should clear
230       // any image the observers might have.
231       holder->ClearImage();
232     } else if (base::Contains(types_changed, holder->type())) {
233       holder->ImagesChanged(it->second);
234     }
235   }
236 }
237
238 void MediaController::PreviousTrack() {
239   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
240
241   if (session_)
242     session_->ipc()->PreviousTrack();
243 }
244
245 void MediaController::NextTrack() {
246   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
247
248   if (session_)
249     session_->ipc()->NextTrack();
250 }
251
252 void MediaController::Seek(base::TimeDelta seek_time) {
253   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
254
255   if (session_)
256     session_->ipc()->Seek(seek_time);
257 }
258
259 void MediaController::ObserveImages(
260     mojom::MediaSessionImageType type,
261     int minimum_size_px,
262     int desired_size_px,
263     mojo::PendingRemote<mojom::MediaControllerImageObserver> observer) {
264   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
265
266   auto it = session_images_.find(type);
267
268   image_observers_.push_back(std::make_unique<ImageObserverHolder>(
269       this, type, minimum_size_px, desired_size_px, std::move(observer),
270       it == session_images_.end() ? std::vector<MediaImage>() : it->second));
271 }
272
273 void MediaController::SeekTo(base::TimeDelta seek_time) {
274   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
275
276   if (session_)
277     session_->ipc()->SeekTo(seek_time);
278 }
279
280 void MediaController::ScrubTo(base::TimeDelta seek_time) {
281   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
282
283   if (session_)
284     session_->ipc()->ScrubTo(seek_time);
285 }
286
287 void MediaController::EnterPictureInPicture() {
288   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
289
290   if (session_)
291     session_->ipc()->EnterPictureInPicture();
292 }
293
294 void MediaController::ExitPictureInPicture() {
295   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
296
297   if (session_)
298     session_->ipc()->ExitPictureInPicture();
299 }
300
301 void MediaController::SetAudioSinkId(const absl::optional<std::string>& id) {
302   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
303
304   if (session_)
305     session_->ipc()->SetAudioSinkId(id);
306 }
307
308 void MediaController::ToggleMicrophone() {
309   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
310
311   if (session_)
312     session_->ipc()->ToggleMicrophone();
313 }
314
315 void MediaController::ToggleCamera() {
316   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
317
318   if (session_)
319     session_->ipc()->ToggleCamera();
320 }
321
322 void MediaController::HangUp() {
323   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
324
325   if (session_)
326     session_->ipc()->HangUp();
327 }
328
329 void MediaController::Raise() {
330   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
331
332   if (session_)
333     session_->ipc()->Raise();
334 }
335
336 void MediaController::SetMute(bool mute) {
337   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
338
339   if (session_)
340     session_->ipc()->SetMute(mute);
341 }
342
343 void MediaController::RequestMediaRemoting() {
344   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
345
346   if (session_)
347     session_->ipc()->RequestMediaRemoting();
348 }
349
350 void MediaController::EnterAutoPictureInPicture() {
351   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
352
353   if (session_) {
354     session_->ipc()->EnterAutoPictureInPicture();
355   }
356 }
357
358 void MediaController::SetMediaSession(AudioFocusRequest* session) {
359   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
360
361   DCHECK(session);
362
363   if (session_ == session)
364     return;
365
366   Reset();
367
368   session_ = session;
369
370   // We should always notify the observers that the media session has changed.
371   for (auto& observer : observers_)
372     observer->MediaSessionChanged(session->id());
373
374   // Add |this| as an observer for |session|.
375   session->ipc()->AddObserver(session_receiver_.BindNewPipeAndPassRemote());
376 }
377
378 void MediaController::ClearMediaSession() {
379   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
380
381   if (!session_)
382     return;
383
384   Reset();
385
386   // If we are no longer bound to a session we should flush the observers
387   // with empty data.
388   for (auto& observer : observers_) {
389     observer->MediaSessionChanged(absl::nullopt);
390     observer->MediaSessionInfoChanged(nullptr);
391     observer->MediaSessionMetadataChanged(absl::nullopt);
392     observer->MediaSessionActionsChanged(
393         std::vector<mojom::MediaSessionAction>());
394     observer->MediaSessionPositionChanged(absl::nullopt);
395   }
396
397   for (auto& holder : image_observers_)
398     holder->ClearImage();
399 }
400
401 void MediaController::BindToInterface(
402     mojo::PendingReceiver<mojom::MediaController> receiver) {
403   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
404   receivers_.Add(this, std::move(receiver));
405 }
406
407 void MediaController::FlushForTesting() {
408   receivers_.FlushForTesting();
409 }
410
411 void MediaController::CleanupImageObservers() {
412   base::EraseIf(image_observers_,
413                 [](const auto& holder) { return !holder->is_valid(); });
414 }
415
416 void MediaController::Reset() {
417   session_ = nullptr;
418   session_receiver_.reset();
419   session_info_.reset();
420   session_metadata_.reset();
421   session_actions_.clear();
422   session_images_.clear();
423   session_position_.reset();
424 }
425
426 }  // namespace media_session