#include "base/memory/raw_ptr.h"
#include "content/browser/media/session/audio_focus_delegate.h"
#include "base/functional/bind.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "content/browser/media/session/media_session_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/media_session_service.h"
#include "media/base/media_switches.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/media_session/public/cpp/features.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace content {
using media_session::mojom::AudioFocusType;
namespace {
const char kAudioFocusSourceName[] = "web";
base::UnguessableToken GetAudioFocusGroupId(MediaSessionImpl* session) {
if (session->audio_focus_group_id() != base::UnguessableToken::Null())
return session->audio_focus_group_id();
static const base::UnguessableToken token(base::UnguessableToken::Create());
return token;
}
class AudioFocusDelegateDefault : public AudioFocusDelegate {
public:
explicit AudioFocusDelegateDefault(MediaSessionImpl* media_session);
~AudioFocusDelegateDefault() override;
AudioFocusResult RequestAudioFocus(AudioFocusType audio_focus_type) override;
void AbandonAudioFocus() override;
std::optional<media_session::mojom::AudioFocusType> GetCurrentFocusType()
const override;
void MediaSessionInfoChanged(
const media_session::mojom::MediaSessionInfoPtr&) override;
const base::UnguessableToken& request_id() const override {
return request_id_;
}
void ReleaseRequestId() override;
private:
void FinishAudioFocusRequest(AudioFocusType type, bool success);
void EnsureServiceConnection();
media_session::mojom::MediaSessionInfoPtr session_info_;
mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_;
mojo::Remote<media_session::mojom::AudioFocusRequestClient>
request_client_remote_;
raw_ptr<MediaSessionImpl> media_session_;
std::optional<AudioFocusType> audio_focus_type_;
base::UnguessableToken const request_id_ = base::UnguessableToken::Create();
};
}
AudioFocusDelegateDefault::AudioFocusDelegateDefault(
MediaSessionImpl* media_session)
: media_session_(media_session) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
AudioFocusDelegateDefault::~AudioFocusDelegateDefault() = default;
AudioFocusDelegate::AudioFocusResult
AudioFocusDelegateDefault::RequestAudioFocus(AudioFocusType audio_focus_type) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!base::FeatureList::IsEnabled(
media_session::features::kMediaSessionService)) {
audio_focus_type_ = audio_focus_type;
return AudioFocusDelegate::AudioFocusResult::kSuccess;
}
if (request_client_remote_.is_bound()) {
request_client_remote_->RequestAudioFocus(
session_info_.Clone(), audio_focus_type,
base::BindOnce(&AudioFocusDelegateDefault::FinishAudioFocusRequest,
base::Unretained(this), audio_focus_type,
true ));
} else {
EnsureServiceConnection();
mojo::PendingRemote<media_session::mojom::MediaSession> media_session =
media_session_->AddRemote();
audio_focus_->RequestGroupedAudioFocus(
request_id_, request_client_remote_.BindNewPipeAndPassReceiver(),
std::move(media_session), session_info_.Clone(), audio_focus_type,
GetAudioFocusGroupId(media_session_),
base::BindOnce(&AudioFocusDelegateDefault::FinishAudioFocusRequest,
base::Unretained(this), audio_focus_type));
}
return AudioFocusDelegate::AudioFocusResult::kDelayed;
}
void AudioFocusDelegateDefault::AbandonAudioFocus() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
audio_focus_type_.reset();
if (!request_client_remote_.is_bound())
return;
request_client_remote_->AbandonAudioFocus();
request_client_remote_.reset();
audio_focus_.reset();
}
std::optional<media_session::mojom::AudioFocusType>
AudioFocusDelegateDefault::GetCurrentFocusType() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return audio_focus_type_;
}
void AudioFocusDelegateDefault::MediaSessionInfoChanged(
const media_session::mojom::MediaSessionInfoPtr& session_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (request_client_remote_.is_bound())
request_client_remote_->MediaSessionInfoChanged(session_info.Clone());
session_info_ = session_info.Clone();
}
void AudioFocusDelegateDefault::ReleaseRequestId() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!base::FeatureList::IsEnabled(
media_session::features::kMediaSessionService)) {
return;
}
EnsureServiceConnection();
audio_focus_->RequestIdReleased(request_id_);
}
void AudioFocusDelegateDefault::FinishAudioFocusRequest(AudioFocusType type,
bool success) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(request_client_remote_.is_bound());
audio_focus_type_ = type;
media_session_->FinishSystemAudioFocusRequest(type, success);
}
void AudioFocusDelegateDefault::EnsureServiceConnection() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!base::FeatureList::IsEnabled(
media_session::features::kMediaSessionService)) {
return;
}
if (audio_focus_.is_bound() && audio_focus_.is_connected())
return;
audio_focus_.reset();
GetMediaSessionService().BindAudioFocusManager(
audio_focus_.BindNewPipeAndPassReceiver());
audio_focus_->SetSource(media_session_->GetSourceId(), kAudioFocusSourceName);
}
std::unique_ptr<AudioFocusDelegate> AudioFocusDelegate::Create(
MediaSessionImpl* media_session) {
return std::unique_ptr<AudioFocusDelegate>(
new AudioFocusDelegateDefault(media_session));
}
}