123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "fuchsia_web/webengine/browser/media_player_impl.h"
- #include <fuchsia/media/cpp/fidl.h>
- #include "base/fuchsia/fuchsia_logging.h"
- #include "base/logging.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/time/time.h"
- #include "content/public/browser/media_session.h"
- #include "services/media_session/public/mojom/constants.mojom.h"
- namespace {
- fuchsia::media::sessions2::PlayerCapabilityFlags ActionToCapabilityFlag(
- media_session::mojom::MediaSessionAction action) {
- using MediaSessionAction = media_session::mojom::MediaSessionAction;
- using PlayerCapabilityFlags =
- fuchsia::media::sessions2::PlayerCapabilityFlags;
- switch (action) {
- case MediaSessionAction::kEnterPictureInPicture:
- case MediaSessionAction::kExitPictureInPicture:
- return {}; // PlayerControl does not support picture-in-picture.
- case MediaSessionAction::kPlay:
- return PlayerCapabilityFlags::PLAY;
- case MediaSessionAction::kPause:
- return PlayerCapabilityFlags::PAUSE;
- case MediaSessionAction::kPreviousTrack:
- return PlayerCapabilityFlags::CHANGE_TO_PREV_ITEM;
- case MediaSessionAction::kNextTrack:
- return PlayerCapabilityFlags::CHANGE_TO_NEXT_ITEM;
- case MediaSessionAction::kSeekBackward:
- return PlayerCapabilityFlags::SKIP_REVERSE;
- case MediaSessionAction::kSeekForward:
- return PlayerCapabilityFlags::SKIP_FORWARD;
- case MediaSessionAction::kSeekTo:
- return PlayerCapabilityFlags::SEEK;
- case MediaSessionAction::kScrubTo:
- return {}; // PlayerControl does not support scrub-to.
- case MediaSessionAction::kSkipAd:
- return {}; // PlayerControl does not support skipping ads.
- case MediaSessionAction::kStop:
- return {}; // PlayerControl assumes that stop is always supported.
- case MediaSessionAction::kSwitchAudioDevice:
- return {}; // PlayerControl does not support switching audio device.
- case MediaSessionAction::kToggleMicrophone:
- return {}; // PlayerControl does not support toggling microphone.
- case MediaSessionAction::kToggleCamera:
- return {}; // PlayerControl does not support toggling camera.
- case MediaSessionAction::kHangUp:
- return {}; // PlayerControl does not support hanging up.
- case MediaSessionAction::kRaise:
- return {}; // PlayerControl does not support raising.
- case MediaSessionAction::kSetMute:
- return {}; // TODO(crbug.com/1240811): implement set mute.
- }
- }
- void AddMetadata(base::StringPiece label,
- base::StringPiece16 value,
- fuchsia::media::Metadata* metadata) {
- fuchsia::media::Property property = {.label{label},
- .value{base::UTF16ToUTF8(value)}};
- metadata->properties.emplace_back(std::move(property));
- }
- fuchsia::media::sessions2::PlayerState SessionStateToPlayerState(
- media_session::mojom::MediaSessionInfo::SessionState state) {
- switch (state) {
- case media_session::mojom::MediaSessionInfo::SessionState::kActive:
- case media_session::mojom::MediaSessionInfo::SessionState::kDucking:
- return fuchsia::media::sessions2::PlayerState::PLAYING;
- case media_session::mojom::MediaSessionInfo::SessionState::kInactive:
- return fuchsia::media::sessions2::PlayerState::IDLE;
- case media_session::mojom::MediaSessionInfo::SessionState::kSuspended:
- return fuchsia::media::sessions2::PlayerState::PAUSED;
- };
- }
- } // namespace
- MediaPlayerImpl::MediaPlayerImpl(
- content::MediaSession* media_session,
- fidl::InterfaceRequest<fuchsia::media::sessions2::Player> request,
- base::OnceClosure on_disconnect)
- : media_session_(media_session),
- on_disconnect_(std::move(on_disconnect)),
- binding_(this, std::move(request)),
- observer_receiver_(this) {
- binding_.set_error_handler([this](zx_status_t status) mutable {
- ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
- << "Player disconnected.";
- std::move(on_disconnect_).Run();
- });
- // Set default values for some fields in |pending_info_delta_|, which some
- // clients may otherwise use incorrect defaults for.
- pending_info_delta_.set_local(true);
- }
- MediaPlayerImpl::~MediaPlayerImpl() = default;
- void MediaPlayerImpl::WatchInfoChange(
- WatchInfoChangeCallback info_change_callback) {
- if (pending_info_change_callback_) {
- DLOG(ERROR) << "Unexpected WatchInfoChange().";
- ReportErrorAndDisconnect(ZX_ERR_BAD_STATE);
- return;
- }
- pending_info_change_callback_ = std::move(info_change_callback);
- if (!observer_receiver_.is_bound()) {
- // |media_session| will notify us via our MediaSessionObserver interface
- // of the current state of the session (metadata, actions, etc) in response
- // to AddObserver().
- media_session_->AddObserver(observer_receiver_.BindNewPipeAndPassRemote());
- }
- MaybeSendPlayerInfoDelta();
- }
- void MediaPlayerImpl::Play() {
- media_session_->Resume(content::MediaSession::SuspendType::kUI);
- }
- void MediaPlayerImpl::Pause() {
- media_session_->Suspend(content::MediaSession::SuspendType::kUI);
- }
- void MediaPlayerImpl::Stop() {
- media_session_->Suspend(content::MediaSession::SuspendType::kUI);
- }
- void MediaPlayerImpl::Seek(zx_duration_t position) {
- media_session_->SeekTo(base::TimeDelta::FromZxDuration(position));
- }
- void MediaPlayerImpl::SkipForward() {
- media_session_->Seek(
- base::Seconds(media_session::mojom::kDefaultSeekTimeSeconds));
- }
- void MediaPlayerImpl::SkipReverse() {
- media_session_->Seek(
- -base::Seconds(media_session::mojom::kDefaultSeekTimeSeconds));
- }
- void MediaPlayerImpl::NextItem() {
- media_session_->NextTrack();
- }
- void MediaPlayerImpl::PrevItem() {
- media_session_->PreviousTrack();
- }
- void MediaPlayerImpl::SetPlaybackRate(float playback_rate) {
- // content::MediaSession does not support changes to playback rate.
- }
- void MediaPlayerImpl::SetRepeatMode(
- fuchsia::media::sessions2::RepeatMode repeat_mode) {
- // content::MediaSession does not provide control over repeat playback.
- }
- void MediaPlayerImpl::SetShuffleMode(bool shuffle_on) {
- // content::MediaSession does not provide control over item playback order.
- }
- void MediaPlayerImpl::BindVolumeControl(
- fidl::InterfaceRequest<fuchsia::media::audio::VolumeControl>
- volume_control_request) {
- // content::MediaSession does not provide control over audio gain.
- volume_control_request.Close(ZX_ERR_NOT_SUPPORTED);
- }
- void MediaPlayerImpl::MediaSessionInfoChanged(
- media_session::mojom::MediaSessionInfoPtr info) {
- fuchsia::media::sessions2::PlayerStatus status;
- status.set_player_state(SessionStateToPlayerState(info->state));
- pending_info_delta_.set_player_status(std::move(status));
- MaybeSendPlayerInfoDelta();
- }
- void MediaPlayerImpl::MediaSessionMetadataChanged(
- const absl::optional<media_session::MediaMetadata>& metadata_mojo) {
- fuchsia::media::Metadata metadata;
- if (metadata_mojo) {
- AddMetadata(fuchsia::media::METADATA_LABEL_TITLE, metadata_mojo->title,
- &metadata);
- AddMetadata(fuchsia::media::METADATA_LABEL_ARTIST, metadata_mojo->artist,
- &metadata);
- AddMetadata(fuchsia::media::METADATA_LABEL_ALBUM, metadata_mojo->album,
- &metadata);
- AddMetadata(fuchsia::media::METADATA_SOURCE_TITLE,
- metadata_mojo->source_title, &metadata);
- }
- pending_info_delta_.set_metadata(std::move(metadata));
- MaybeSendPlayerInfoDelta();
- }
- void MediaPlayerImpl::MediaSessionActionsChanged(
- const std::vector<media_session::mojom::MediaSessionAction>& actions) {
- // TODO(https://crbug.com/879317): Implement PROVIDE_BITMAPS.
- fuchsia::media::sessions2::PlayerCapabilityFlags capability_flags{};
- for (auto action : actions)
- capability_flags |= ActionToCapabilityFlag(action);
- pending_info_delta_.mutable_player_capabilities()->set_flags(
- std::move(capability_flags));
- MaybeSendPlayerInfoDelta();
- }
- void MediaPlayerImpl::MediaSessionImagesChanged(
- const base::flat_map<media_session::mojom::MediaSessionImageType,
- std::vector<media_session::MediaImage>>& images) {
- // TODO(https://crbug.com/879317): Implement image-changed.
- NOTIMPLEMENTED_LOG_ONCE();
- }
- void MediaPlayerImpl::MediaSessionPositionChanged(
- const absl::optional<media_session::MediaPosition>& position) {
- // TODO(https://crbug.com/879317): Implement media position changes.
- NOTIMPLEMENTED_LOG_ONCE();
- }
- void MediaPlayerImpl::MaybeSendPlayerInfoDelta() {
- if (!pending_info_change_callback_)
- return;
- if (pending_info_delta_.IsEmpty())
- return;
- // std::exchange(foo, {}) returns the contents of |foo|, while ensuring that
- // |foo| is reset to the initial/empty state.
- std::exchange(pending_info_change_callback_,
- {})(std::exchange(pending_info_delta_, {}));
- }
- void MediaPlayerImpl::ReportErrorAndDisconnect(zx_status_t status) {
- binding_.Close(status);
- std::move(on_disconnect_).Run();
- }
|