blob: 0f2570b50b6ab5237b664da7988e45dcef354019 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media/audio_ducker.h"
#include "content/public/browser/media_session.h"
#include "content/public/browser/media_session_service.h"
AudioDucker::AudioDucker(content::Page& page)
: content::PageUserData<AudioDucker>(page),
content::WebContentsObserver(GetWebContents()) {}
AudioDucker::~AudioDucker() {
StopDuckingOtherAudio();
}
bool AudioDucker::StartDuckingOtherAudio() {
if (ducking_state_ == AudioDuckingState::kDucking) {
return true;
}
if (!BindToAudioFocusManagerIfNecessary()) {
return false;
}
StartDuckingImpl();
ducking_state_ = AudioDuckingState::kDucking;
return true;
}
bool AudioDucker::StopDuckingOtherAudio() {
if (ducking_state_ == AudioDuckingState::kNoDucking) {
return true;
}
if (!BindToAudioFocusManagerIfNecessary()) {
return false;
}
audio_focus_remote_->StopDuckingAllAudio();
ducking_state_ = AudioDuckingState::kNoDucking;
return true;
}
void AudioDucker::MediaSessionCreated(content::MediaSession*) {
// When a MediaSession is created and we're already ducking, we need to tell
// the AudioFocusManager to start ducking again while exempting the new
// request ID. This will supercede the previous request and replace it with a
// request that has an exempted MediaSession.
if (ducking_state_ == AudioDuckingState::kDucking &&
BindToAudioFocusManagerIfNecessary()) {
StartDuckingImpl();
}
}
void AudioDucker::StartDuckingImpl() {
// Null base::UnguessableTokens cannot be passed via mojo, so convert to an
// empty optional if the request ID is null.
const base::UnguessableToken& request_id =
content::MediaSession::GetRequestIdFromWebContents(GetWebContents());
std::optional<base::UnguessableToken> optional_request_id;
if (!request_id.is_empty()) {
optional_request_id = request_id;
}
audio_focus_remote_->StartDuckingAllAudio(optional_request_id);
}
content::WebContents* AudioDucker::GetWebContents() const {
return content::WebContents::FromRenderFrameHost(&page().GetMainDocument());
}
bool AudioDucker::BindToAudioFocusManagerIfNecessary() {
if (audio_focus_remote_.is_bound()) {
return true;
}
content::GetMediaSessionService().BindAudioFocusManager(
audio_focus_remote_.BindNewPipeAndPassReceiver());
audio_focus_remote_.reset_on_disconnect();
return audio_focus_remote_.is_bound();
}
PAGE_USER_DATA_KEY_IMPL(AudioDucker);