Commit 87b17ae6 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Audio Focus] Add no enforce flag

Adds an audio focus flag that enables audio focus manager but
disables enforcement of a single media session. This gives us
the option of enabling audio focus tracking without the user
facing change of enforcing a single media session.

BUG=875004

Change-Id: I5415ec76db7b22d4d91ea98c92e3f1515d9df97b
Reviewed-on: https://chromium-review.googlesource.com/c/1231915
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596446}
parent f6978cc5
...@@ -801,6 +801,9 @@ const FeatureEntry::Choice kEnableAudioFocusChoices[] = { ...@@ -801,6 +801,9 @@ const FeatureEntry::Choice kEnableAudioFocusChoices[] = {
media_session::switches::kEnableAudioFocus, media_session::switches::kEnableAudioFocus,
media_session::switches::kEnableAudioFocusDuckFlash}, media_session::switches::kEnableAudioFocusDuckFlash},
#endif // BUILDFLAG(ENABLE_PLUGINS) #endif // BUILDFLAG(ENABLE_PLUGINS)
{flag_descriptions::kEnableAudioFocusEnabledNoEnforce,
media_session::switches::kEnableAudioFocus,
media_session::switches::kEnableAudioFocusNoEnforce},
}; };
#endif // !defined(OS_ANDROID) #endif // !defined(OS_ANDROID)
......
...@@ -2733,6 +2733,8 @@ const char kEnableAudioFocusEnabled[] = "Enabled"; ...@@ -2733,6 +2733,8 @@ const char kEnableAudioFocusEnabled[] = "Enabled";
const char kEnableAudioFocusEnabledDuckFlash[] = const char kEnableAudioFocusEnabledDuckFlash[] =
"Enabled (Flash lowers volume when interrupted by other sound, " "Enabled (Flash lowers volume when interrupted by other sound, "
"experimental)"; "experimental)";
const char kEnableAudioFocusEnabledNoEnforce[] =
"Enabled (without enforcement of a single active media session)";
const char kInfiniteSessionRestoreName[] = "Infinite Session Restore"; const char kInfiniteSessionRestoreName[] = "Infinite Session Restore";
const char kInfiniteSessionRestoreDescription[] = const char kInfiniteSessionRestoreDescription[] =
......
...@@ -1655,6 +1655,7 @@ extern const char kEnableAudioFocusDescription[]; ...@@ -1655,6 +1655,7 @@ extern const char kEnableAudioFocusDescription[];
extern const char kEnableAudioFocusDisabled[]; extern const char kEnableAudioFocusDisabled[];
extern const char kEnableAudioFocusEnabled[]; extern const char kEnableAudioFocusEnabled[];
extern const char kEnableAudioFocusEnabledDuckFlash[]; extern const char kEnableAudioFocusEnabledDuckFlash[];
extern const char kEnableAudioFocusEnabledNoEnforce[];
extern const char kEnableNewAppMenuIconName[]; extern const char kEnableNewAppMenuIconName[];
extern const char kEnableNewAppMenuIconDescription[]; extern const char kEnableNewAppMenuIconDescription[];
......
...@@ -20,6 +20,7 @@ source_set("lib") { ...@@ -20,6 +20,7 @@ source_set("lib") {
deps = [ deps = [
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//services/media_session/public/cpp",
"//services/media_session/public/mojom", "//services/media_session/public/mojom",
] ]
...@@ -45,6 +46,7 @@ source_set("tests") { ...@@ -45,6 +46,7 @@ source_set("tests") {
":lib", ":lib",
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//services/media_session/public/cpp",
"//services/media_session/public/cpp/test:test_support", "//services/media_session/public/cpp/test:test_support",
"//services/media_session/public/mojom", "//services/media_session/public/mojom",
"//services/service_manager/public/cpp/test:test_support", "//services/service_manager/public/cpp/test:test_support",
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/atomic_sequence_num.h" #include "base/atomic_sequence_num.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/interface_request.h"
#include "services/media_session/public/cpp/switches.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace media_session { namespace media_session {
...@@ -187,24 +188,8 @@ void AudioFocusManager::AbandonAudioFocusInternal(RequestId id) { ...@@ -187,24 +188,8 @@ void AudioFocusManager::AbandonAudioFocusInternal(RequestId id) {
return; return;
} }
// Allow the top-most MediaSession having force duck to unduck even if if (IsAudioFocusEnforcementEnabled())
// it is not active. EnforceAudioFocusAbandon();
for (auto iter = audio_focus_stack_.rbegin();
iter != audio_focus_stack_.rend(); ++iter) {
if (!(*iter)->info()->force_duck)
continue;
auto duck_row = std::move(*iter);
duck_row->session()->StopDucking();
audio_focus_stack_.erase(std::next(iter).base());
audio_focus_stack_.push_back(std::move(duck_row));
return;
}
// Only try to unduck the new MediaSession on top. The session might be
// still inactive but it will not be resumed (so it doesn't surprise the
// user).
audio_focus_stack_.back()->session()->StopDucking();
// Notify observers that we lost audio focus. // Notify observers that we lost audio focus.
observers_.ForAllPtrs([&row](mojom::AudioFocusObserver* observer) { observers_.ForAllPtrs([&row](mojom::AudioFocusObserver* observer) {
...@@ -240,6 +225,32 @@ void AudioFocusManager::RequestAudioFocusInternal( ...@@ -240,6 +225,32 @@ void AudioFocusManager::RequestAudioFocusInternal(
std::unique_ptr<StackRow> row, std::unique_ptr<StackRow> row,
mojom::AudioFocusType type, mojom::AudioFocusType type,
base::OnceCallback<void()> callback) { base::OnceCallback<void()> callback) {
// If audio focus is enabled then we should enforce this request and make sure
// the new active session is not ducking.
if (IsAudioFocusEnforcementEnabled()) {
EnforceAudioFocusRequest(type);
row->session()->StopDucking();
}
row->SetAudioFocusType(type);
audio_focus_stack_.push_back(std::move(row));
// Notify observers that we were gained audio focus.
mojom::MediaSessionInfoPtr session_info =
audio_focus_stack_.back()->info().Clone();
observers_.ForAllPtrs(
[&session_info, type](mojom::AudioFocusObserver* observer) {
observer->OnFocusGained(session_info.Clone(), type);
});
// We always grant the audio focus request but this may not always be the case
// in the future.
std::move(callback).Run();
}
void AudioFocusManager::EnforceAudioFocusRequest(mojom::AudioFocusType type) {
DCHECK(IsAudioFocusEnforcementEnabled());
if (type == mojom::AudioFocusType::kGainTransientMayDuck) { if (type == mojom::AudioFocusType::kGainTransientMayDuck) {
for (auto& old_session : audio_focus_stack_) for (auto& old_session : audio_focus_stack_)
old_session->session()->StartDucking(); old_session->session()->StartDucking();
...@@ -255,22 +266,29 @@ void AudioFocusManager::RequestAudioFocusInternal( ...@@ -255,22 +266,29 @@ void AudioFocusManager::RequestAudioFocusInternal(
} }
} }
} }
}
row->SetAudioFocusType(type); void AudioFocusManager::EnforceAudioFocusAbandon() {
row->session()->StopDucking(); DCHECK(IsAudioFocusEnforcementEnabled());
audio_focus_stack_.push_back(std::move(row));
// Notify observers that we were gained audio focus. // Allow the top-most MediaSession having force duck to unduck even if
mojom::MediaSessionInfoPtr session_info = // it is not active.
audio_focus_stack_.back()->info().Clone(); for (auto iter = audio_focus_stack_.rbegin();
observers_.ForAllPtrs( iter != audio_focus_stack_.rend(); ++iter) {
[&session_info, type](mojom::AudioFocusObserver* observer) { if (!(*iter)->info()->force_duck)
observer->OnFocusGained(session_info.Clone(), type); continue;
});
// We always grant the audio focus request but this may not always be the case auto duck_row = std::move(*iter);
// in the future. duck_row->session()->StopDucking();
std::move(callback).Run(); audio_focus_stack_.erase(std::next(iter).base());
audio_focus_stack_.push_back(std::move(duck_row));
return;
}
// Only try to unduck the new MediaSession on top. The session might be
// still inactive but it will not be resumed (so it doesn't surprise the
// user).
audio_focus_stack_.back()->session()->StopDucking();
} }
void AudioFocusManager::ResetForTesting() { void AudioFocusManager::ResetForTesting() {
......
...@@ -57,10 +57,13 @@ class AudioFocusManager : public mojom::AudioFocusManager, ...@@ -57,10 +57,13 @@ class AudioFocusManager : public mojom::AudioFocusManager,
// control its audio focus. // control its audio focus.
class StackRow; class StackRow;
void RequestAudioFocusInternal(std::unique_ptr<StackRow> row, void RequestAudioFocusInternal(std::unique_ptr<StackRow>,
mojom::AudioFocusType type, mojom::AudioFocusType,
base::OnceCallback<void()> callback); base::OnceCallback<void()>);
void AbandonAudioFocusInternal(RequestId id); void EnforceAudioFocusRequest(mojom::AudioFocusType);
void AbandonAudioFocusInternal(RequestId);
void EnforceAudioFocusAbandon();
// Flush for testing will flush any pending messages to the observers. // Flush for testing will flush any pending messages to the observers.
void FlushForTesting(); void FlushForTesting();
......
...@@ -11,10 +11,12 @@ ...@@ -11,10 +11,12 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/interface_request.h"
#include "services/media_session/media_session_service.h" #include "services/media_session/media_session_service.h"
#include "services/media_session/public/cpp/switches.h"
#include "services/media_session/public/cpp/test/audio_focus_test_util.h" #include "services/media_session/public/cpp/test/audio_focus_test_util.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "services/service_manager/public/cpp/test/test_connector_factory.h" #include "services/service_manager/public/cpp/test/test_connector_factory.h"
...@@ -126,11 +128,21 @@ class MockMediaSession : public mojom::MediaSession { ...@@ -126,11 +128,21 @@ class MockMediaSession : public mojom::MediaSession {
} // anonymous namespace } // anonymous namespace
class AudioFocusManagerTest : public testing::Test { // This tests the Audio Focus Manager API. The parameter determines whether
// audio focus is enabled or not. If it is not enabled it should track the media
// sessions but not enforce single session focus.
class AudioFocusManagerTest : public testing::TestWithParam<bool> {
public: public:
AudioFocusManagerTest() = default; AudioFocusManagerTest() = default;
void SetUp() override { void SetUp() override {
if (!GetParam()) {
command_line_.GetProcessCommandLine()->AppendSwitchASCII(
switches::kEnableAudioFocus, switches::kEnableAudioFocusNoEnforce);
}
ASSERT_EQ(GetParam(), IsAudioFocusEnforcementEnabled());
// Create an instance of the MediaSessionService. // Create an instance of the MediaSessionService.
connector_factory_ = connector_factory_ =
service_manager::TestConnectorFactory::CreateForUniqueService( service_manager::TestConnectorFactory::CreateForUniqueService(
...@@ -220,7 +232,8 @@ class AudioFocusManagerTest : public testing::Test { ...@@ -220,7 +232,8 @@ class AudioFocusManagerTest : public testing::Test {
audio_focus_type, std::move(callback)); audio_focus_type, std::move(callback));
session->SetAudioFocusRequestClient(std::move(afr_client)); session->SetAudioFocusRequestClient(std::move(afr_client));
FlushForTesting();
audio_focus_ptr_.FlushForTesting();
} }
// If the audio focus was granted then we should set the session state to // If the audio focus was granted then we should set the session state to
...@@ -228,7 +241,7 @@ class AudioFocusManagerTest : public testing::Test { ...@@ -228,7 +241,7 @@ class AudioFocusManagerTest : public testing::Test {
if (result) if (result)
session->SetState(mojom::MediaSessionInfo::SessionState::kActive); session->SetState(mojom::MediaSessionInfo::SessionState::kActive);
FlushForTesting(); FlushForTestingIfEnabled();
return GetRequestIdForSession(session); return GetRequestIdForSession(session);
} }
...@@ -252,7 +265,17 @@ class AudioFocusManagerTest : public testing::Test { ...@@ -252,7 +265,17 @@ class AudioFocusManagerTest : public testing::Test {
} }
mojom::MediaSessionInfo::SessionState GetState(MockMediaSession* session) { mojom::MediaSessionInfo::SessionState GetState(MockMediaSession* session) {
return test::GetMediaSessionInfoSync(session)->state; mojom::MediaSessionInfo::SessionState state =
test::GetMediaSessionInfoSync(session)->state;
if (!GetParam()) {
// If audio focus enforcement is disabled then we should never see these
// states in the tests.
EXPECT_NE(mojom::MediaSessionInfo::SessionState::kSuspended, state);
EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, state);
}
return state;
} }
std::unique_ptr<test::TestAudioFocusObserver> CreateObserver() { std::unique_ptr<test::TestAudioFocusObserver> CreateObserver() {
...@@ -267,6 +290,15 @@ class AudioFocusManagerTest : public testing::Test { ...@@ -267,6 +290,15 @@ class AudioFocusManagerTest : public testing::Test {
return observer; return observer;
} }
mojom::MediaSessionInfo::SessionState GetStateFromParam(
mojom::MediaSessionInfo::SessionState state) {
// If enforcement is enabled then returns the provided state, otherwise
// returns kActive because without enforcement we did not change state.
if (GetParam())
return state;
return mojom::MediaSessionInfo::SessionState::kActive;
}
private: private:
std::vector<mojom::AudioFocusRequestStatePtr> GetRequests() { std::vector<mojom::AudioFocusRequestStatePtr> GetRequests() {
std::vector<mojom::AudioFocusRequestStatePtr> result; std::vector<mojom::AudioFocusRequestStatePtr> result;
...@@ -306,11 +338,19 @@ class AudioFocusManagerTest : public testing::Test { ...@@ -306,11 +338,19 @@ class AudioFocusManagerTest : public testing::Test {
return audio_focus_debug_ptr_.get(); return audio_focus_debug_ptr_.get();
} }
void FlushForTestingIfEnabled() {
if (!GetParam())
return;
FlushForTesting();
}
void FlushForTesting() { void FlushForTesting() {
audio_focus_ptr_.FlushForTesting(); audio_focus_ptr_.FlushForTesting();
AudioFocusManager::GetInstance()->FlushForTesting(); AudioFocusManager::GetInstance()->FlushForTesting();
} }
base::test::ScopedCommandLine command_line_;
base::test::ScopedTaskEnvironment task_environment_; base::test::ScopedTaskEnvironment task_environment_;
std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_; std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
std::unique_ptr<service_manager::Connector> connector_; std::unique_ptr<service_manager::Connector> connector_;
...@@ -320,13 +360,15 @@ class AudioFocusManagerTest : public testing::Test { ...@@ -320,13 +360,15 @@ class AudioFocusManagerTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(AudioFocusManagerTest); DISALLOW_COPY_AND_ASSIGN(AudioFocusManagerTest);
}; };
TEST_F(AudioFocusManagerTest, InstanceAvailableAndSame) { INSTANTIATE_TEST_CASE_P(, AudioFocusManagerTest, testing::Bool());
TEST_P(AudioFocusManagerTest, InstanceAvailableAndSame) {
AudioFocusManager* audio_focus_manager = AudioFocusManager::GetInstance(); AudioFocusManager* audio_focus_manager = AudioFocusManager::GetInstance();
EXPECT_TRUE(!!audio_focus_manager); EXPECT_TRUE(!!audio_focus_manager);
EXPECT_EQ(audio_focus_manager, AudioFocusManager::GetInstance()); EXPECT_EQ(audio_focus_manager, AudioFocusManager::GetInstance());
} }
TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_ReplaceFocusedEntry) { TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_ReplaceFocusedEntry) {
MockMediaSession media_session_1; MockMediaSession media_session_1;
MockMediaSession media_session_2; MockMediaSession media_session_2;
MockMediaSession media_session_3; MockMediaSession media_session_3;
...@@ -348,17 +390,19 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_ReplaceFocusedEntry) { ...@@ -348,17 +390,19 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_ReplaceFocusedEntry) {
AudioFocusManager::RequestId request_id_2 = AudioFocusManager::RequestId request_id_2 =
RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain);
EXPECT_EQ(request_id_2, GetAudioFocusedSession()); EXPECT_EQ(request_id_2, GetAudioFocusedSession());
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kSuspended, EXPECT_EQ(
GetState(&media_session_1)); GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended),
GetState(&media_session_1));
AudioFocusManager::RequestId request_id_3 = AudioFocusManager::RequestId request_id_3 =
RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGain); RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGain);
EXPECT_EQ(request_id_3, GetAudioFocusedSession()); EXPECT_EQ(request_id_3, GetAudioFocusedSession());
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kSuspended, EXPECT_EQ(
GetState(&media_session_2)); GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended),
GetState(&media_session_2));
} }
TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_Duplicate) { TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_Duplicate) {
MockMediaSession media_session; MockMediaSession media_session;
EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession());
...@@ -371,7 +415,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_Duplicate) { ...@@ -371,7 +415,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_Duplicate) {
EXPECT_EQ(request_id, GetAudioFocusedSession()); EXPECT_EQ(request_id, GetAudioFocusedSession());
} }
TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_FromTransient) { TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_FromTransient) {
MockMediaSession media_session; MockMediaSession media_session;
AudioFocusManager::RequestId request_id = RequestAudioFocus( AudioFocusManager::RequestId request_id = RequestAudioFocus(
...@@ -384,7 +428,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_FromTransient) { ...@@ -384,7 +428,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusGain_FromTransient) {
EXPECT_EQ(0, GetTransientMaybeDuckCount()); EXPECT_EQ(0, GetTransientMaybeDuckCount());
} }
TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGain) { TEST_P(AudioFocusManagerTest, RequestAudioFocusTransient_FromGain) {
MockMediaSession media_session; MockMediaSession media_session;
AudioFocusManager::RequestId request_id = AudioFocusManager::RequestId request_id =
...@@ -401,7 +445,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGain) { ...@@ -401,7 +445,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGain) {
GetState(&media_session)); GetState(&media_session));
} }
TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) { TEST_P(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) {
MockMediaSession media_session_1; MockMediaSession media_session_1;
MockMediaSession media_session_2; MockMediaSession media_session_2;
...@@ -413,7 +457,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) { ...@@ -413,7 +457,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) {
RequestAudioFocus(&media_session_2, RequestAudioFocus(&media_session_2,
mojom::AudioFocusType::kGainTransientMayDuck); mojom::AudioFocusType::kGainTransientMayDuck);
EXPECT_EQ(1, GetTransientMaybeDuckCount()); EXPECT_EQ(1, GetTransientMaybeDuckCount());
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
RequestAudioFocus(&media_session_1, RequestAudioFocus(&media_session_1,
...@@ -423,7 +467,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) { ...@@ -423,7 +467,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) {
GetState(&media_session_1)); GetState(&media_session_1));
} }
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesFocusedEntry) { TEST_P(AudioFocusManagerTest, AbandonAudioFocus_RemovesFocusedEntry) {
MockMediaSession media_session; MockMediaSession media_session;
AudioFocusManager::RequestId request_id = AudioFocusManager::RequestId request_id =
...@@ -434,7 +478,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesFocusedEntry) { ...@@ -434,7 +478,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesFocusedEntry) {
EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession());
} }
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_MultipleCalls) { TEST_P(AudioFocusManagerTest, AbandonAudioFocus_MultipleCalls) {
MockMediaSession media_session; MockMediaSession media_session;
AudioFocusManager::RequestId request_id = AudioFocusManager::RequestId request_id =
...@@ -450,7 +494,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_MultipleCalls) { ...@@ -450,7 +494,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_MultipleCalls) {
EXPECT_TRUE(observer->focus_lost_session_.is_null()); EXPECT_TRUE(observer->focus_lost_session_.is_null());
} }
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientEntry) { TEST_P(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientEntry) {
MockMediaSession media_session; MockMediaSession media_session;
RequestAudioFocus(&media_session, RequestAudioFocus(&media_session,
...@@ -467,7 +511,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientEntry) { ...@@ -467,7 +511,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientEntry) {
} }
} }
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) { TEST_P(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
MockMediaSession media_session_1; MockMediaSession media_session_1;
MockMediaSession media_session_2; MockMediaSession media_session_2;
...@@ -479,7 +523,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) { ...@@ -479,7 +523,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
RequestAudioFocus(&media_session_2, RequestAudioFocus(&media_session_2,
mojom::AudioFocusType::kGainTransientMayDuck); mojom::AudioFocusType::kGainTransientMayDuck);
EXPECT_EQ(1, GetTransientMaybeDuckCount()); EXPECT_EQ(1, GetTransientMaybeDuckCount());
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
AbandonAudioFocus(&media_session_1); AbandonAudioFocus(&media_session_1);
...@@ -493,7 +537,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) { ...@@ -493,7 +537,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
GetState(&media_session_1)); GetState(&media_session_1));
} }
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) { TEST_P(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) {
MockMediaSession media_session_1; MockMediaSession media_session_1;
MockMediaSession media_session_2; MockMediaSession media_session_2;
...@@ -505,7 +549,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) { ...@@ -505,7 +549,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) {
RequestAudioFocus(&media_session_2, RequestAudioFocus(&media_session_2,
mojom::AudioFocusType::kGainTransientMayDuck); mojom::AudioFocusType::kGainTransientMayDuck);
EXPECT_EQ(1, GetTransientMaybeDuckCount()); EXPECT_EQ(1, GetTransientMaybeDuckCount());
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
AbandonAudioFocus(&media_session_2); AbandonAudioFocus(&media_session_2);
...@@ -514,7 +558,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) { ...@@ -514,7 +558,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) {
GetState(&media_session_1)); GetState(&media_session_1));
} }
TEST_F(AudioFocusManagerTest, DuckWhilePlaying) { TEST_P(AudioFocusManagerTest, DuckWhilePlaying) {
MockMediaSession media_session_1; MockMediaSession media_session_1;
MockMediaSession media_session_2; MockMediaSession media_session_2;
...@@ -524,11 +568,11 @@ TEST_F(AudioFocusManagerTest, DuckWhilePlaying) { ...@@ -524,11 +568,11 @@ TEST_F(AudioFocusManagerTest, DuckWhilePlaying) {
RequestAudioFocus(&media_session_2, RequestAudioFocus(&media_session_2,
mojom::AudioFocusType::kGainTransientMayDuck); mojom::AudioFocusType::kGainTransientMayDuck);
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
} }
TEST_F(AudioFocusManagerTest, GainSuspendsTransient) { TEST_P(AudioFocusManagerTest, GainSuspendsTransient) {
MockMediaSession media_session_1; MockMediaSession media_session_1;
MockMediaSession media_session_2; MockMediaSession media_session_2;
...@@ -536,11 +580,12 @@ TEST_F(AudioFocusManagerTest, GainSuspendsTransient) { ...@@ -536,11 +580,12 @@ TEST_F(AudioFocusManagerTest, GainSuspendsTransient) {
mojom::AudioFocusType::kGainTransientMayDuck); mojom::AudioFocusType::kGainTransientMayDuck);
RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kSuspended, EXPECT_EQ(
GetState(&media_session_2)); GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended),
GetState(&media_session_2));
} }
TEST_F(AudioFocusManagerTest, DuckWithMultipleTransients) { TEST_P(AudioFocusManagerTest, DuckWithMultipleTransients) {
MockMediaSession media_session_1; MockMediaSession media_session_1;
MockMediaSession media_session_2; MockMediaSession media_session_2;
MockMediaSession media_session_3; MockMediaSession media_session_3;
...@@ -551,16 +596,16 @@ TEST_F(AudioFocusManagerTest, DuckWithMultipleTransients) { ...@@ -551,16 +596,16 @@ TEST_F(AudioFocusManagerTest, DuckWithMultipleTransients) {
RequestAudioFocus(&media_session_2, RequestAudioFocus(&media_session_2,
mojom::AudioFocusType::kGainTransientMayDuck); mojom::AudioFocusType::kGainTransientMayDuck);
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
RequestAudioFocus(&media_session_3, RequestAudioFocus(&media_session_3,
mojom::AudioFocusType::kGainTransientMayDuck); mojom::AudioFocusType::kGainTransientMayDuck);
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
AbandonAudioFocus(&media_session_2); AbandonAudioFocus(&media_session_2);
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
AbandonAudioFocus(&media_session_3); AbandonAudioFocus(&media_session_3);
...@@ -568,7 +613,7 @@ TEST_F(AudioFocusManagerTest, DuckWithMultipleTransients) { ...@@ -568,7 +613,7 @@ TEST_F(AudioFocusManagerTest, DuckWithMultipleTransients) {
GetState(&media_session_1)); GetState(&media_session_1));
} }
TEST_F(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesFocus) { TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesFocus) {
{ {
MockMediaSession media_session; MockMediaSession media_session;
...@@ -585,7 +630,7 @@ TEST_F(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesFocus) { ...@@ -585,7 +630,7 @@ TEST_F(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesFocus) {
EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession()); EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession());
} }
TEST_F(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransients) { TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransients) {
{ {
MockMediaSession media_session; MockMediaSession media_session;
RequestAudioFocus(&media_session, RequestAudioFocus(&media_session,
...@@ -600,7 +645,7 @@ TEST_F(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransients) { ...@@ -600,7 +645,7 @@ TEST_F(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransients) {
EXPECT_EQ(0, GetTransientMaybeDuckCount()); EXPECT_EQ(0, GetTransientMaybeDuckCount());
} }
TEST_F(AudioFocusManagerTest, GainDucksForceDuck) { TEST_P(AudioFocusManagerTest, GainDucksForceDuck) {
MockMediaSession media_session_1(true /* force_duck */); MockMediaSession media_session_1(true /* force_duck */);
MockMediaSession media_session_2; MockMediaSession media_session_2;
...@@ -610,11 +655,11 @@ TEST_F(AudioFocusManagerTest, GainDucksForceDuck) { ...@@ -610,11 +655,11 @@ TEST_F(AudioFocusManagerTest, GainDucksForceDuck) {
RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain);
EXPECT_EQ(request_id_2, GetAudioFocusedSession()); EXPECT_EQ(request_id_2, GetAudioFocusedSession());
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
} }
TEST_F(AudioFocusManagerTest, TEST_P(AudioFocusManagerTest,
AbandoningGainFocusRevokesTopMostForceDuckSession) { AbandoningGainFocusRevokesTopMostForceDuckSession) {
MockMediaSession media_session_1(true /* force_duck */); MockMediaSession media_session_1(true /* force_duck */);
MockMediaSession media_session_2; MockMediaSession media_session_2;
...@@ -622,22 +667,24 @@ TEST_F(AudioFocusManagerTest, ...@@ -622,22 +667,24 @@ TEST_F(AudioFocusManagerTest,
AudioFocusManager::RequestId request_id_1 = AudioFocusManager::RequestId request_id_1 =
RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); AudioFocusManager::RequestId request_id_2 =
RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain);
AudioFocusManager::RequestId request_id_3 = AudioFocusManager::RequestId request_id_3 =
RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGain); RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGain);
EXPECT_EQ(request_id_3, GetAudioFocusedSession()); EXPECT_EQ(request_id_3, GetAudioFocusedSession());
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kSuspended, EXPECT_EQ(
GetState(&media_session_2)); GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended),
EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kDucking, GetState(&media_session_2));
EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
GetState(&media_session_1)); GetState(&media_session_1));
AbandonAudioFocus(&media_session_3); AbandonAudioFocus(&media_session_3);
EXPECT_EQ(request_id_1, GetAudioFocusedSession()); EXPECT_EQ(GetParam() ? request_id_1 : request_id_2, GetAudioFocusedSession());
} }
TEST_F(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) { TEST_P(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) {
MockMediaSession media_session; MockMediaSession media_session;
AudioFocusManager::RequestId request_id; AudioFocusManager::RequestId request_id;
...@@ -660,7 +707,7 @@ TEST_F(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) { ...@@ -660,7 +707,7 @@ TEST_F(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) {
} }
} }
TEST_F(AudioFocusManagerTest, AudioFocusObserver_TransientMayDuck) { TEST_P(AudioFocusManagerTest, AudioFocusObserver_TransientMayDuck) {
MockMediaSession media_session; MockMediaSession media_session;
{ {
...@@ -684,7 +731,7 @@ TEST_F(AudioFocusManagerTest, AudioFocusObserver_TransientMayDuck) { ...@@ -684,7 +731,7 @@ TEST_F(AudioFocusManagerTest, AudioFocusObserver_TransientMayDuck) {
} }
} }
TEST_F(AudioFocusManagerTest, GetDebugInfo) { TEST_P(AudioFocusManagerTest, GetDebugInfo) {
MockMediaSession media_session; MockMediaSession media_session;
AudioFocusManager::RequestId request_id = AudioFocusManager::RequestId request_id =
RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
...@@ -695,7 +742,7 @@ TEST_F(AudioFocusManagerTest, GetDebugInfo) { ...@@ -695,7 +742,7 @@ TEST_F(AudioFocusManagerTest, GetDebugInfo) {
EXPECT_EQ(kExampleDebugInfoState, debug_info->state); EXPECT_EQ(kExampleDebugInfoState, debug_info->state);
} }
TEST_F(AudioFocusManagerTest, GetDebugInfo_BadRequestId) { TEST_P(AudioFocusManagerTest, GetDebugInfo_BadRequestId) {
mojom::MediaSessionDebugInfoPtr debug_info = GetDebugInfo(kNoFocusedSession); mojom::MediaSessionDebugInfoPtr debug_info = GetDebugInfo(kNoFocusedSession);
EXPECT_TRUE(debug_info->name.empty()); EXPECT_TRUE(debug_info->name.empty());
} }
......
...@@ -12,13 +12,19 @@ namespace switches { ...@@ -12,13 +12,19 @@ namespace switches {
// Enable a internal audio focus management between tabs in such a way that two // Enable a internal audio focus management between tabs in such a way that two
// tabs can't play on top of each other. // tabs can't play on top of each other.
// The allowed values are: "" (empty) or |switches::kEnableAudioFocusDuckFlash|. // The allowed values are: "" (empty) or |kEnableAudioFocusDuckFlash|
// or |kEnableAudioFocusNoEnforce|.
const char kEnableAudioFocus[] = "enable-audio-focus"; const char kEnableAudioFocus[] = "enable-audio-focus";
// This value is used as an option for |kEnableAudioFocus|. Flash will // This value is used as an option for |kEnableAudioFocus|. Flash will
// be ducked when losing audio focus. // be ducked when losing audio focus.
const char kEnableAudioFocusDuckFlash[] = "duck-flash"; const char kEnableAudioFocusDuckFlash[] = "duck-flash";
// This value is used as an option for |kEnableAudioFocus|. If enabled then
// single media session audio focus will not be enforced. This should be used by
// embedders that wish to track audio focus but without the enforcement.
const char kEnableAudioFocusNoEnforce[] = "no-enforce";
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
// Turns on the internal media session backend. This should be used by embedders // Turns on the internal media session backend. This should be used by embedders
// that want to control the media playback with the media session interfaces. // that want to control the media playback with the media session interfaces.
...@@ -38,6 +44,12 @@ bool IsAudioFocusDuckFlashEnabled() { ...@@ -38,6 +44,12 @@ bool IsAudioFocusDuckFlashEnabled() {
switches::kEnableAudioFocusDuckFlash; switches::kEnableAudioFocusDuckFlash;
} }
bool IsAudioFocusEnforcementEnabled() {
return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kEnableAudioFocus) !=
switches::kEnableAudioFocusNoEnforce;
}
bool IsMediaSessionEnabled() { bool IsMediaSessionEnabled() {
// Media session is enabled on Android and Chrome OS to allow control of media // Media session is enabled on Android and Chrome OS to allow control of media
// players as needed. // players as needed.
......
...@@ -14,6 +14,8 @@ namespace switches { ...@@ -14,6 +14,8 @@ namespace switches {
COMPONENT_EXPORT(MEDIA_SESSION_CPP) extern const char kEnableAudioFocus[]; COMPONENT_EXPORT(MEDIA_SESSION_CPP) extern const char kEnableAudioFocus[];
COMPONENT_EXPORT(MEDIA_SESSION_CPP) COMPONENT_EXPORT(MEDIA_SESSION_CPP)
extern const char kEnableAudioFocusDuckFlash[]; extern const char kEnableAudioFocusDuckFlash[];
COMPONENT_EXPORT(MEDIA_SESSION_CPP)
extern const char kEnableAudioFocusNoEnforce[];
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
COMPONENT_EXPORT(MEDIA_SESSION_CPP) COMPONENT_EXPORT(MEDIA_SESSION_CPP)
...@@ -28,6 +30,10 @@ COMPONENT_EXPORT(MEDIA_SESSION_CPP) bool IsAudioFocusEnabled(); ...@@ -28,6 +30,10 @@ COMPONENT_EXPORT(MEDIA_SESSION_CPP) bool IsAudioFocusEnabled();
// audio focus duck flash should be enabled. // audio focus duck flash should be enabled.
COMPONENT_EXPORT(MEDIA_SESSION_CPP) bool IsAudioFocusDuckFlashEnabled(); COMPONENT_EXPORT(MEDIA_SESSION_CPP) bool IsAudioFocusDuckFlashEnabled();
// Based on the command line of the current process, determine if
// audio focus enforcement should be enabled.
COMPONENT_EXPORT(MEDIA_SESSION_CPP) bool IsAudioFocusEnforcementEnabled();
COMPONENT_EXPORT(MEDIA_SESSION_CPP) bool IsMediaSessionEnabled(); COMPONENT_EXPORT(MEDIA_SESSION_CPP) bool IsMediaSessionEnabled();
} // namespace media_session } // namespace media_session
......
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