Commit 238868bf authored by zqzhang's avatar zqzhang Committed by Commit bot

Let MediaSession store duck state instead of volume multiplier

BUG=642361

Review-Url: https://codereview.chromium.org/2291163002
Cr-Commit-Position: refs/heads/master@{#415608}
parent 7c1b7483
......@@ -9,13 +9,6 @@
namespace content {
namespace {
const double kDuckingVolumeMultiplier = 0.2;
const double kDefaultVolumeMultiplier = 1.0;
} // anonymous namespace
AudioFocusManager::AudioFocusEntry::AudioFocusEntry(
WebContents* web_contents,
AudioFocusManager* audio_focus_manager,
......@@ -93,18 +86,14 @@ void AudioFocusManager::MaybeStartDucking() const {
if (TransientMayDuckEntriesCount() != 1 || !focus_entry_)
return;
// TODO(mlamouri): add StartDuck to MediaSession.
MediaSession::Get(focus_entry_->web_contents())
->SetVolumeMultiplier(kDuckingVolumeMultiplier);
MediaSession::Get(focus_entry_->web_contents())->StartDucking();
}
void AudioFocusManager::MaybeStopDucking() const {
if (TransientMayDuckEntriesCount() != 0 || !focus_entry_)
return;
// TODO(mlamouri): add StopDuck to MediaSession.
MediaSession::Get(focus_entry_->web_contents())
->SetVolumeMultiplier(kDefaultVolumeMultiplier);
MediaSession::Get(focus_entry_->web_contents())->StopDucking();
}
int AudioFocusManager::TransientMayDuckEntriesCount() const {
......@@ -118,8 +107,7 @@ void AudioFocusManager::MaybeRemoveTransientEntry(WebContents* web_contents) {
void AudioFocusManager::MaybeRemoveFocusEntry(WebContents* web_contents) {
if (focus_entry_ && focus_entry_->web_contents() == web_contents) {
MediaSession::Get(focus_entry_->web_contents())
->SetVolumeMultiplier(kDefaultVolumeMultiplier);
MediaSession::Get(focus_entry_->web_contents())->StopDucking();
focus_entry_.reset();
}
}
......
......@@ -17,9 +17,6 @@ using SuspendType = MediaSession::SuspendType;
class AudioFocusManagerTest : public testing::Test {
public:
const double kDuckingVolumeMultiplier = 0.2;
const double kDefaultVolumeMultiplier = 1.0;
AudioFocusManagerTest() : ui_thread_(BrowserThread::UI, &message_loop_) {}
void SetUp() override {
......@@ -44,8 +41,8 @@ class AudioFocusManagerTest : public testing::Test {
return AudioFocusManager::GetInstance()->TransientMayDuckEntriesCount();
}
double GetVolumeMultiplier(MediaSession* session) {
return session->volume_multiplier_;
double IsSessionDucking(MediaSession* session) {
return session->is_ducking_; // Quack! Quack!
}
WebContents* CreateWebContents() {
......@@ -135,7 +132,7 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGain) {
media_session, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(nullptr, GetAudioFocusedContent());
ASSERT_EQ(1, GetTransientMaybeDuckCount());
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session));
ASSERT_FALSE(IsSessionDucking(media_session));
}
TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) {
......@@ -148,17 +145,17 @@ TEST_F(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) {
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::Gain);
ASSERT_EQ(0, GetTransientMaybeDuckCount());
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(2, GetTransientMaybeDuckCount());
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
}
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesFocusedEntry) {
......@@ -203,12 +200,12 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::Gain);
ASSERT_EQ(0, GetTransientMaybeDuckCount());
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->AbandonAudioFocus(media_session_1);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
......@@ -218,7 +215,7 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::Gain);
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
}
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) {
......@@ -231,17 +228,16 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) {
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::Gain);
ASSERT_EQ(0, GetTransientMaybeDuckCount());
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(1, GetTransientMaybeDuckCount());
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->AbandonAudioFocus(media_session_2);
ASSERT_EQ(0, GetTransientMaybeDuckCount());
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
}
TEST_F(AudioFocusManagerTest, DuckWhilePlaying) {
......@@ -253,11 +249,11 @@ TEST_F(AudioFocusManagerTest, DuckWhilePlaying) {
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::Gain);
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
}
TEST_F(AudioFocusManagerTest, DuckWhenStarting) {
......@@ -272,7 +268,7 @@ TEST_F(AudioFocusManagerTest, DuckWhenStarting) {
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::Gain);
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
}
TEST_F(AudioFocusManagerTest, DuckWithMultipleTransients) {
......@@ -287,21 +283,21 @@ TEST_F(AudioFocusManagerTest, DuckWithMultipleTransients) {
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::Gain);
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_3, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->AbandonAudioFocus(media_session_2);
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->AbandonAudioFocus(media_session_3);
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
}
TEST_F(AudioFocusManagerTest, WebContentsDestroyed_ReleasesFocus) {
......@@ -337,14 +333,14 @@ TEST_F(AudioFocusManagerTest, WebContentsDestroyed_StopsDucking) {
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_1, AudioFocusManager::AudioFocusType::Gain);
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
AudioFocusManager::GetInstance()->RequestAudioFocus(
media_session_2, AudioFocusManager::AudioFocusType::GainTransientMayDuck);
ASSERT_EQ(kDuckingVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_TRUE(IsSessionDucking(media_session_1));
web_contents_2.reset();
ASSERT_EQ(kDefaultVolumeMultiplier, GetVolumeMultiplier(media_session_1));
ASSERT_FALSE(IsSessionDucking(media_session_1));
}
} // namespace content
......@@ -16,6 +16,7 @@ namespace content {
namespace {
const double kDefaultVolumeMultiplier = 1.0;
const double kDuckingVolumeMultiplier = 0.2;
} // anonymous namespace
......@@ -70,7 +71,7 @@ void MediaSession::SetMetadata(const MediaMetadata& metadata) {
bool MediaSession::AddPlayer(MediaSessionObserver* observer,
int player_id,
media::MediaContentType media_content_type) {
observer->OnSetVolumeMultiplier(player_id, volume_multiplier_);
observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier());
// Determine the audio focus type required for playing the new player.
// TODO(zqzhang): handle duckable and uncontrollable.
......@@ -206,10 +207,27 @@ void MediaSession::Stop(SuspendType suspend_type) {
AbandonSystemAudioFocusIfNeeded();
}
void MediaSession::SetVolumeMultiplier(double volume_multiplier) {
volume_multiplier_ = volume_multiplier;
void MediaSession::StartDucking() {
if (is_ducking_)
return;
is_ducking_ = true;
UpdateVolumeMultiplier();
}
void MediaSession::StopDucking() {
if (!is_ducking_)
return;
is_ducking_ = false;
UpdateVolumeMultiplier();
}
void MediaSession::UpdateVolumeMultiplier() {
for (const auto& it : players_)
it.observer->OnSetVolumeMultiplier(it.player_id, volume_multiplier_);
it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier());
}
double MediaSession::GetVolumeMultiplier() const {
return is_ducking_ ? kDuckingVolumeMultiplier : kDefaultVolumeMultiplier;
}
bool MediaSession::IsActive() const {
......@@ -325,7 +343,7 @@ MediaSession::MediaSession(WebContents* web_contents)
audio_focus_state_(State::INACTIVE),
audio_focus_type_(
AudioFocusManager::AudioFocusType::GainTransientMayDuck),
volume_multiplier_(kDefaultVolumeMultiplier) {}
is_ducking_(false) {}
void MediaSession::Initialize() {
delegate_ = MediaSessionDelegate::Create(this);
......
......@@ -103,8 +103,13 @@ class MediaSession : public WebContentsObserver,
// |type| represents the origin of the request.
CONTENT_EXPORT void Stop(SuspendType suspend_type);
// Change the volume multiplier of the session to |volume_multiplier|.
CONTENT_EXPORT void SetVolumeMultiplier(double volume_multiplier);
// Let the media session start ducking such that the volume multiplier is
// reduced.
CONTENT_EXPORT void StartDucking();
// Let the media session stop ducking such that the volume multiplier is
// recovered.
CONTENT_EXPORT void StopDucking();
// Returns if the session can be controlled by Resume() and Suspend calls
// above.
......@@ -187,6 +192,13 @@ class MediaSession : public WebContentsObserver,
// It sets audio_focus_state_ and notifies observers about the state change.
void SetAudioFocusState(State audio_focus_state);
// Update the volume multiplier when ducking state changes.
void UpdateVolumeMultiplier();
// Get the volume multiplier, which depends on whether the media session is
// ducking.
double GetVolumeMultiplier() const;
// Registers a MediaSession state change callback.
CONTENT_EXPORT std::unique_ptr<base::CallbackList<void(State)>::Subscription>
RegisterMediaSessionStateChangedCallbackForTest(
......@@ -201,9 +213,10 @@ class MediaSession : public WebContentsObserver,
MediaSessionUmaHelper uma_helper_;
// The volume multiplier of this session. All players in this session should
// multiply their volume with this multiplier to get the effective volume.
double volume_multiplier_;
// The ducking state of this media session. The initial value is |false|, and
// is set to |true| after StartDucking(), and will be set to |false| after
// StopDucking().
bool is_ducking_;
MediaMetadata metadata_;
base::CallbackList<void(State)> media_session_state_listeners_;
......
......@@ -34,6 +34,9 @@ using ::testing::Expectation;
namespace {
const double kDefaultVolumeMultiplier = 1.0;
const double kDuckingVolumeMultiplier = 0.2;
class MockMediaSessionDelegate : public MediaSessionDelegate {
public:
bool RequestAudioFocus(content::AudioFocusManager::AudioFocusType) override {
......@@ -137,8 +140,12 @@ class MediaSessionBrowserTest : public content::ContentBrowserTest {
: MediaSession::State::INACTIVE);
}
void SystemSetVolumeMultiplier(double volume_multiplier) {
media_session_->SetVolumeMultiplier(volume_multiplier);
void SystemStartDucking() {
media_session_->StartDucking();
}
void SystemStopDucking() {
media_session_->StopDucking();
}
MockWebContentsObserver* mock_web_contents_observer() {
......@@ -266,7 +273,24 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
MediaSessionSetVolumeMultiplier) {
InitialVolumeMultiplier) {
std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(),
media::MediaContentType::Persistent);
StartNewPlayer(media_session_observer.get(),
media::MediaContentType::Persistent);
EXPECT_EQ(kDefaultVolumeMultiplier,
media_session_observer->GetVolumeMultiplier(0));
EXPECT_EQ(kDefaultVolumeMultiplier,
media_session_observer->GetVolumeMultiplier(1));
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
StartDuckingReducesVolumeMultiplier) {
std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
......@@ -274,17 +298,42 @@ IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
media::MediaContentType::Persistent);
StartNewPlayer(media_session_observer.get(),
media::MediaContentType::Persistent);
SystemStartDucking();
double volume_multiplier = 0.2f;
SystemSetVolumeMultiplier(volume_multiplier);
EXPECT_EQ(kDuckingVolumeMultiplier,
media_session_observer->GetVolumeMultiplier(0));
EXPECT_EQ(kDuckingVolumeMultiplier,
media_session_observer->GetVolumeMultiplier(1));
StartNewPlayer(media_session_observer.get(),
media::MediaContentType::Persistent);
EXPECT_EQ(kDuckingVolumeMultiplier,
media_session_observer->GetVolumeMultiplier(2));
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
StopDuckingRecoversVolumeMultiplier) {
std::unique_ptr<MockMediaSessionObserver> media_session_observer(
new MockMediaSessionObserver);
StartNewPlayer(media_session_observer.get(),
media::MediaContentType::Persistent);
StartNewPlayer(media_session_observer.get(),
media::MediaContentType::Persistent);
SystemStartDucking();
SystemStopDucking();
EXPECT_EQ(volume_multiplier, media_session_observer->GetVolumeMultiplier(0));
EXPECT_EQ(volume_multiplier, media_session_observer->GetVolumeMultiplier(1));
EXPECT_EQ(kDefaultVolumeMultiplier,
media_session_observer->GetVolumeMultiplier(0));
EXPECT_EQ(kDefaultVolumeMultiplier,
media_session_observer->GetVolumeMultiplier(1));
StartNewPlayer(media_session_observer.get(),
media::MediaContentType::Persistent);
EXPECT_EQ(volume_multiplier, media_session_observer->GetVolumeMultiplier(2));
EXPECT_EQ(kDefaultVolumeMultiplier,
media_session_observer->GetVolumeMultiplier(2));
}
IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, AudioFocusInitialState) {
......
......@@ -76,9 +76,12 @@ void MediaSessionDelegateAndroid::OnResume(
media_session_->Resume(MediaSession::SuspendType::SYSTEM);
}
void MediaSessionDelegateAndroid::OnSetVolumeMultiplier(
JNIEnv*, jobject, jdouble volume_multiplier) {
media_session_->SetVolumeMultiplier(volume_multiplier);
void MediaSessionDelegateAndroid::OnStartDucking(JNIEnv*, jobject) {
media_session_->StartDucking();
}
void MediaSessionDelegateAndroid::OnStopDucking(JNIEnv*, jobject) {
media_session_->StopDucking();
}
void MediaSessionDelegateAndroid::RecordSessionDuck(
......
......@@ -37,12 +37,15 @@ class MediaSessionDelegateAndroid : public MediaSessionDelegate {
// Called by Java through JNI.
void OnResume(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
// Called when the Android system requests the MediaSession to duck.
// Called when the Android system requests the MediaSession to start ducking.
// Called by Java through JNI.
void OnSetVolumeMultiplier(JNIEnv* env, jobject obj,
jdouble volume_multiplier);
void OnStartDucking(JNIEnv* env, jobject obj);
// Called when the Android system requests the MediaSession to duck.
// Called when the Android system requests the MediaSession to stop ducking.
// Called by Java through JNI.
void OnStopDucking(JNIEnv* env, jobject obj);
// Record when the Android system requests the MediaSession to duck.
// Called by Java through JNI.
void RecordSessionDuck(JNIEnv* env,
const base::android::JavaParamRef<jobject> &obj);
......
......@@ -26,10 +26,6 @@ import org.chromium.base.annotations.JNINamespace;
public class MediaSessionDelegate implements AudioManager.OnAudioFocusChangeListener {
private static final String TAG = "MediaSession";
// These need to match the values in native apps.
public static final double DUCKING_VOLUME_MULTIPLIER = 0.2f;
public static final double DEFAULT_VOLUME_MULTIPLIER = 1.0f;
private Context mContext;
private int mFocusType;
private boolean mIsDucking = false;
......@@ -82,8 +78,7 @@ public class MediaSessionDelegate implements AudioManager.OnAudioFocusChangeList
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
if (mIsDucking) {
nativeOnSetVolumeMultiplier(mNativeMediaSessionDelegateAndroid,
DEFAULT_VOLUME_MULTIPLIER);
nativeOnStopDucking(mNativeMediaSessionDelegateAndroid);
mIsDucking = false;
} else {
nativeOnResume(mNativeMediaSessionDelegateAndroid);
......@@ -95,8 +90,7 @@ public class MediaSessionDelegate implements AudioManager.OnAudioFocusChangeList
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
mIsDucking = true;
nativeRecordSessionDuck(mNativeMediaSessionDelegateAndroid);
nativeOnSetVolumeMultiplier(mNativeMediaSessionDelegateAndroid,
DUCKING_VOLUME_MULTIPLIER);
nativeOnStartDucking(mNativeMediaSessionDelegateAndroid);
break;
case AudioManager.AUDIOFOCUS_LOSS:
abandonAudioFocus();
......@@ -110,7 +104,7 @@ public class MediaSessionDelegate implements AudioManager.OnAudioFocusChangeList
private native void nativeOnSuspend(long nativeMediaSessionDelegateAndroid, boolean temporary);
private native void nativeOnResume(long nativeMediaSessionDelegateAndroid);
private native void nativeOnSetVolumeMultiplier(long nativeMediaSessionDelegateAndroid,
double volumeMultiplier);
private native void nativeOnStartDucking(long nativeMediaSessionDelegateAndroid);
private native void nativeOnStopDucking(long nativeMediaSessionDelegateAndroid);
private native void nativeRecordSessionDuck(long nativeMediaSessionDelegateAndroid);
}
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