Commit 6ce33412 authored by Xiao Yang's avatar Xiao Yang Committed by Commit Bot

AssistantMediaSession handle losing audio focus

1. Register AssistantManagerServiceImpl as a listener of libassisant media
manager and notify assistant_media_session about media metadata in
OnPlaybackStateChange().
2. Implemented addObserver(), suspend() and resume() API for
assistant_media_session.


CQ_INCLUDE_TRYBOTS=luci.chrome.try:linux-chromeos-chrome

Change-Id: Ib81b9b10e1fad6e711e48b31f0703dd710ae0ba6
Bug: 130315881
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1557006
Commit-Queue: Xiao Yang <yanxiao@google.com>
Reviewed-by: default avatarTao Wu <wutao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#652747}
parent b16277af
......@@ -134,7 +134,7 @@ AssistantManagerServiceImpl::AssistantManagerServiceImpl(
network::NetworkConnectionTracker* network_connection_tracker,
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
url_loader_factory_info)
: media_session_(std::make_unique<AssistantMediaSession>(connector)),
: media_session_(std::make_unique<AssistantMediaSession>(connector, this)),
action_module_(std::make_unique<action::CrosActionModule>(
this,
assistant::features::IsAppSupportEnabled(),
......@@ -250,6 +250,30 @@ void AssistantManagerServiceImpl::RegisterFallbackMediaHandler() {
});
}
void AssistantManagerServiceImpl::UpdateInternalMediaPlayerStatus(
media_session::mojom::MediaSessionAction action) {
auto* media_manager = assistant_manager_->GetMediaManager();
if (!media_manager)
return;
switch (action) {
case media_session::mojom::MediaSessionAction::kPause:
media_manager->Pause();
break;
case media_session::mojom::MediaSessionAction::kPlay:
media_manager->Resume();
break;
case media_session::mojom::MediaSessionAction::kPreviousTrack:
case media_session::mojom::MediaSessionAction::kNextTrack:
case media_session::mojom::MediaSessionAction::kSeekBackward:
case media_session::mojom::MediaSessionAction::kSeekForward:
case media_session::mojom::MediaSessionAction::kSkipAd:
case media_session::mojom::MediaSessionAction::kStop:
NOTIMPLEMENTED();
break;
}
}
void AssistantManagerServiceImpl::AddMediaControllerObserver() {
if (features::IsMediaSessionIntegrationEnabled()) {
media_session::mojom::MediaControllerObserverPtr observer;
......@@ -1048,6 +1072,10 @@ void AssistantManagerServiceImpl::OnStartFinished() {
RegisterFallbackMediaHandler();
AddMediaControllerObserver();
auto* media_manager = assistant_manager_->GetMediaManager();
if (media_manager)
media_manager->AddListener(this);
if (service_->assistant_state()->arc_play_store_enabled().has_value()) {
SetArcPlayStoreEnabled(
service_->assistant_state()->arc_play_store_enabled().value());
......@@ -1235,6 +1263,12 @@ void AssistantManagerServiceImpl::OnOpenUrlOnMainThread(
[&url](auto* ptr) { ptr->OnOpenUrlResponse(GURL(url)); });
}
void AssistantManagerServiceImpl::OnPlaybackStateChange(
const MediaStatus& status) {
if (media_session_)
media_session_->NotifyMediaSessionMetadataChanged(status);
}
void AssistantManagerServiceImpl::OnShowNotificationOnMainThread(
const mojom::AssistantNotificationPtr& notification) {
service_->assistant_notification_controller()->AddOrUpdateNotification(
......
......@@ -26,6 +26,7 @@
#include "libassistant/shared/internal_api/assistant_manager_delegate.h"
#include "libassistant/shared/public/conversation_state_listener.h"
#include "libassistant/shared/public/device_state_listener.h"
#include "libassistant/shared/public/media_manager.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/device/public/mojom/battery_monitor.mojom.h"
......@@ -88,6 +89,7 @@ class AssistantManagerServiceImpl
public assistant_client::ConversationStateListener,
public assistant_client::AssistantManagerDelegate,
public assistant_client::DeviceStateListener,
public assistant_client::MediaManager::Listener,
public media_session::mojom::MediaControllerObserver {
public:
// |service| owns this class and must outlive this class.
......@@ -143,6 +145,8 @@ class AssistantManagerServiceImpl
const std::vector<action::Suggestion>& suggestions) override;
void OnShowText(const std::string& text) override;
void OnOpenUrl(const std::string& url) override;
void OnPlaybackStateChange(
const assistant_client::MediaStatus& status) override;
void OnShowNotification(const action::Notification& notification) override;
void OnOpenAndroidApp(const action::AndroidAppInfo& app_info,
const action::InteractionInfo& interaction) override;
......@@ -199,6 +203,9 @@ class AssistantManagerServiceImpl
void MediaSessionChanged(
const base::Optional<base::UnguessableToken>& request_id) override {}
void UpdateInternalMediaPlayerStatus(
media_session::mojom::MediaSessionAction action);
private:
void StartAssistantInternal(const base::Optional<std::string>& access_token);
void PostInitAssistant(base::OnceClosure post_init_callback);
......
......@@ -5,6 +5,8 @@
#include "chromeos/services/assistant/media_session/assistant_media_session.h"
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/services/assistant/assistant_manager_service_impl.h"
#include "services/media_session/public/cpp/features.h"
#include "services/media_session/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
......@@ -23,8 +25,12 @@ const char kAudioFocusSourceName[] = "assistant";
} // namespace
AssistantMediaSession::AssistantMediaSession(
service_manager::Connector* connector)
: connector_(connector), binding_(this), weak_factory_(this) {}
service_manager::Connector* connector,
AssistantManagerServiceImpl* assistant_manager)
: assistant_manager_service_(assistant_manager),
connector_(connector),
binding_(this),
weak_factory_(this) {}
AssistantMediaSession::~AssistantMediaSession() {
AbandonAudioFocusIfNeeded();
......@@ -35,12 +41,37 @@ void AssistantMediaSession::GetMediaSessionInfo(
std::move(callback).Run(GetMediaSessionInfoInternal());
}
void AssistantMediaSession::AddObserver(
media_session::mojom::MediaSessionObserverPtr observer) {
observer->MediaSessionInfoChanged(GetMediaSessionInfoInternal());
observer->MediaSessionMetadataChanged(metadata_);
observers_.AddPtr(std::move(observer));
}
void AssistantMediaSession::GetDebugInfo(GetDebugInfoCallback callback) {
media_session::mojom::MediaSessionDebugInfoPtr info(
media_session::mojom::MediaSessionDebugInfo::New());
std::move(callback).Run(std::move(info));
}
void AssistantMediaSession::Suspend(SuspendType suspend_type) {
if (!IsActive())
return;
SetAudioFocusState(State::SUSPENDED);
assistant_manager_service_->UpdateInternalMediaPlayerStatus(
media_session::mojom::MediaSessionAction::kPause);
}
void AssistantMediaSession::Resume(SuspendType suspend_type) {
if (!IsSuspended())
return;
SetAudioFocusState(State::ACTIVE);
assistant_manager_service_->UpdateInternalMediaPlayerStatus(
media_session::mojom::MediaSessionAction::kPlay);
}
void AssistantMediaSession::RequestAudioFocus(AudioFocusType audio_focus_type) {
if (!base::FeatureList::IsEnabled(
media_session::features::kMediaSessionService)) {
......@@ -122,26 +153,75 @@ void AssistantMediaSession::SetAudioFocusState(State audio_focus_state) {
NotifyMediaSessionInfoChanged();
}
void AssistantMediaSession::NotifyMediaSessionMetadataChanged(
const assistant_client::MediaStatus& status) {
media_session::MediaMetadata metadata;
metadata.title = base::UTF8ToUTF16(status.metadata.title);
metadata.artist = base::UTF8ToUTF16(status.metadata.artist);
metadata.album = base::UTF8ToUTF16(status.metadata.album);
bool metadata_changed = metadata_ != metadata;
if (!metadata_changed)
return;
metadata_ = metadata;
current_track_ = status.track_type;
observers_.ForAllPtrs(
[this](media_session::mojom::MediaSessionObserver* observer) {
observer->MediaSessionMetadataChanged(this->metadata_);
});
}
media_session::mojom::MediaSessionInfoPtr
AssistantMediaSession::GetMediaSessionInfoInternal() {
media_session::mojom::MediaSessionInfoPtr info(
media_session::mojom::MediaSessionInfo::New());
// TODO(wutao): Set other states when supporting pause/resume.
info->state = IsActive() ? MediaSessionInfo::SessionState::kActive
: MediaSessionInfo::SessionState::kInactive;
switch (audio_focus_state_) {
case State::ACTIVE:
info->state = MediaSessionInfo::SessionState::kActive;
break;
case State::SUSPENDED:
info->state = MediaSessionInfo::SessionState::kSuspended;
break;
case State::INACTIVE:
info->state = MediaSessionInfo::SessionState::kInactive;
break;
}
if (audio_focus_state_ != State::INACTIVE &&
current_track_ == assistant_client::TrackType::MEDIA_TRACK_CONTENT) {
info->is_controllable = true;
}
return info;
}
void AssistantMediaSession::NotifyMediaSessionInfoChanged() {
// TODO(wutao): Notify observers.
media_session::mojom::MediaSessionInfoPtr current_info =
GetMediaSessionInfoInternal();
if (current_info == session_info_)
return;
if (request_client_ptr_.is_bound())
request_client_ptr_->MediaSessionInfoChanged(GetMediaSessionInfoInternal());
request_client_ptr_->MediaSessionInfoChanged(current_info.Clone());
observers_.ForAllPtrs(
[&current_info](media_session::mojom::MediaSessionObserver* observer) {
observer->MediaSessionInfoChanged(current_info.Clone());
});
session_info_ = std::move(current_info);
}
bool AssistantMediaSession::IsActive() const {
return audio_focus_state_ == State::ACTIVE;
}
bool AssistantMediaSession::IsSuspended() const {
return audio_focus_state_ == State::SUSPENDED;
}
base::WeakPtr<AssistantMediaSession> AssistantMediaSession::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
......
......@@ -8,7 +8,9 @@
#include "base/macros.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "libassistant/shared/public/media_manager.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
......@@ -16,30 +18,40 @@ namespace service_manager {
class Connector;
} // namespace service_manager
namespace assistant_client {
struct MediaStatus;
} // namespace assistant_client
namespace chromeos {
namespace assistant {
class AssistantManagerServiceImpl;
// MediaSession manages the media session and audio focus for Assistant.
// MediaSession allows clients to observe its changes via MediaSessionObserver,
// and allows clients to resume/suspend/stop the managed players.
class AssistantMediaSession : public media_session::mojom::MediaSession {
public:
enum class State { ACTIVE, INACTIVE };
enum class State { ACTIVE, SUSPENDED, INACTIVE };
explicit AssistantMediaSession(service_manager::Connector* connector);
explicit AssistantMediaSession(
service_manager::Connector* connector,
AssistantManagerServiceImpl* assistant_manager);
~AssistantMediaSession() override;
// media_session.mojom.MediaSession overrides:
void Suspend(SuspendType suspend_type) override {}
void Resume(SuspendType suspend_type) override {}
void Suspend(SuspendType suspend_type) override;
void Resume(SuspendType suspend_type) override;
void StartDucking() override {}
void StopDucking() override {}
void GetMediaSessionInfo(GetMediaSessionInfoCallback callback) override;
void GetDebugInfo(GetDebugInfoCallback callback) override;
void AddObserver(
media_session::mojom::MediaSessionObserverPtr observer) override {}
media_session::mojom::MediaSessionObserverPtr observer) override;
void PreviousTrack() override {}
void NextTrack() override {}
void NotifyMediaSessionMetadataChanged(
const assistant_client::MediaStatus& status);
void SkipAd() override {}
void Seek(base::TimeDelta seek_time) override {}
void Stop(SuspendType suspend_type) override {}
......@@ -75,11 +87,22 @@ class AssistantMediaSession : public media_session::mojom::MediaSession {
// Returns if the session is currently active.
bool IsActive() const;
// Returns if the session is currently suspended.
bool IsSuspended() const;
// The current metadata associated with the current media session.
media_session::MediaMetadata metadata_;
AssistantManagerServiceImpl* const assistant_manager_service_;
service_manager::Connector* connector_;
// Binding for Mojo pointer to |this| held by AudioFocusManager.
mojo::Binding<media_session::mojom::MediaSession> binding_;
assistant_client::TrackType current_track_;
mojo::InterfacePtrSet<media_session::mojom::MediaSessionObserver> observers_;
// Holds a pointer to the MediaSessionService.
media_session::mojom::AudioFocusManagerPtr audio_focus_ptr_;
......@@ -87,6 +110,9 @@ class AssistantMediaSession : public media_session::mojom::MediaSession {
// pointer to that requests AudioFocusRequestClient.
media_session::mojom::AudioFocusRequestClientPtr request_client_ptr_;
// The last updated |MediaSessionInfo| that was sent to |observers_|.
media_session::mojom::MediaSessionInfoPtr session_info_;
State audio_focus_state_ = State::INACTIVE;
base::WeakPtrFactory<AssistantMediaSession> weak_factory_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment