Index: content/browser/media/android/media_session.cc |
diff --git a/content/browser/media/android/media_session.cc b/content/browser/media/android/media_session.cc |
deleted file mode 100644 |
index 17321058233891f393d93ea690ec112ea1af0eee..0000000000000000000000000000000000000000 |
--- a/content/browser/media/android/media_session.cc |
+++ /dev/null |
@@ -1,362 +0,0 @@ |
-// Copyright 2015 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "content/browser/media/android/media_session.h" |
- |
-#include "base/android/context_utils.h" |
-#include "base/android/jni_android.h" |
-#include "content/browser/media/android/media_session_observer.h" |
-#include "content/browser/web_contents/web_contents_impl.h" |
-#include "content/public/browser/web_contents.h" |
-#include "content/public/browser/web_contents_delegate.h" |
-#include "jni/MediaSession_jni.h" |
-#include "media/base/android/media_player_android.h" |
- |
-namespace content { |
- |
-using MediaSessionSuspendedSource = |
- MediaSessionUmaHelper::MediaSessionSuspendedSource; |
- |
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(MediaSession); |
- |
-MediaSession::PlayerIdentifier::PlayerIdentifier(MediaSessionObserver* observer, |
- int player_id) |
- : observer(observer), |
- player_id(player_id) { |
-} |
- |
-bool MediaSession::PlayerIdentifier::operator==( |
- const PlayerIdentifier& other) const { |
- return this->observer == other.observer && this->player_id == other.player_id; |
-} |
- |
-size_t MediaSession::PlayerIdentifier::Hash::operator()( |
- const PlayerIdentifier& player_identifier) const { |
- size_t hash = BASE_HASH_NAMESPACE::hash<MediaSessionObserver*>()( |
- player_identifier.observer); |
- hash += BASE_HASH_NAMESPACE::hash<int>()(player_identifier.player_id); |
- return hash; |
-} |
- |
-// static |
-bool content::MediaSession::RegisterMediaSession(JNIEnv* env) { |
- return RegisterNativesImpl(env); |
-} |
- |
-// static |
-MediaSession* MediaSession::Get(WebContents* web_contents) { |
- MediaSession* session = FromWebContents(web_contents); |
- if (!session) { |
- CreateForWebContents(web_contents); |
- session = FromWebContents(web_contents); |
- session->Initialize(); |
- } |
- return session; |
-} |
- |
-MediaSession::~MediaSession() { |
- DCHECK(players_.empty()); |
- DCHECK(audio_focus_state_ == State::INACTIVE); |
-} |
- |
-bool MediaSession::AddPlayer(MediaSessionObserver* observer, |
- int player_id, |
- Type type) { |
- observer->OnSetVolumeMultiplier(player_id, volume_multiplier_); |
- |
- // If the audio focus is already granted and is of type Content, there is |
- // nothing to do. If it is granted of type Transient the requested type is |
- // also transient, there is also nothing to do. Otherwise, the session needs |
- // to request audio focus again. |
- if (audio_focus_state_ == State::ACTIVE && |
- (audio_focus_type_ == Type::Content || audio_focus_type_ == type)) { |
- players_.insert(PlayerIdentifier(observer, player_id)); |
- return true; |
- } |
- |
- State old_audio_focus_state = audio_focus_state_; |
- State audio_focus_state = RequestSystemAudioFocus(type) ? State::ACTIVE |
- : State::INACTIVE; |
- SetAudioFocusState(audio_focus_state); |
- audio_focus_type_ = type; |
- |
- if (audio_focus_state_ != State::ACTIVE) |
- return false; |
- |
- // The session should be reset if a player is starting while all players are |
- // suspended. |
- if (old_audio_focus_state != State::ACTIVE) |
- players_.clear(); |
- |
- players_.insert(PlayerIdentifier(observer, player_id)); |
- UpdateWebContents(); |
- |
- return true; |
-} |
- |
-void MediaSession::RemovePlayer(MediaSessionObserver* observer, |
- int player_id) { |
- auto it = players_.find(PlayerIdentifier(observer, player_id)); |
- if (it != players_.end()) |
- players_.erase(it); |
- |
- AbandonSystemAudioFocusIfNeeded(); |
-} |
- |
-void MediaSession::RemovePlayers(MediaSessionObserver* observer) { |
- for (auto it = players_.begin(); it != players_.end();) { |
- if (it->observer == observer) |
- players_.erase(it++); |
- else |
- ++it; |
- } |
- |
- AbandonSystemAudioFocusIfNeeded(); |
-} |
- |
-void MediaSession::OnSuspend(JNIEnv* env, |
- const JavaParamRef<jobject>& obj, |
- jboolean temporary) { |
- // TODO(mlamouri): this check makes it so that if a MediaSession is paused and |
- // then loses audio focus, it will still stay in the Suspended state. |
- // See https://crbug.com/539998 |
- if (audio_focus_state_ != State::ACTIVE) |
- return; |
- |
- OnSuspendInternal(SuspendType::SYSTEM, |
- temporary ? State::SUSPENDED : State::INACTIVE); |
- |
-} |
- |
-void MediaSession::OnResume(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
- if (audio_focus_state_ != State::SUSPENDED) |
- return; |
- |
- OnResumeInternal(SuspendType::SYSTEM); |
-} |
- |
-void MediaSession::RecordSessionDuck(JNIEnv* env, |
- const JavaParamRef<jobject>& obj) { |
- uma_helper_.RecordSessionSuspended( |
- MediaSessionSuspendedSource::SystemTransientDuck); |
-} |
- |
-void MediaSession::OnPlayerPaused(MediaSessionObserver* observer, |
- int player_id) { |
- // If a playback is completed, BrowserMediaPlayerManager will call |
- // OnPlayerPaused() after RemovePlayer(). This is a workaround. |
- // Also, this method may be called when a player that is not added |
- // to this session (e.g. a silent video) is paused. MediaSession |
- // should ignore the paused player for this case. |
- if (!players_.count(PlayerIdentifier(observer, player_id))) |
- return; |
- |
- // If there is more than one observer, remove the paused one from the session. |
- if (players_.size() != 1) { |
- RemovePlayer(observer, player_id); |
- return; |
- } |
- |
- // Otherwise, suspend the session. |
- DCHECK(!IsSuspended()); |
- OnSuspendInternal(SuspendType::CONTENT, State::SUSPENDED); |
-} |
-void MediaSession::OnSetVolumeMultiplier(JNIEnv *env, jobject obj, |
- jdouble volume_multiplier) { |
- OnSetVolumeMultiplierInternal(volume_multiplier); |
-} |
- |
-void MediaSession::Resume() { |
- DCHECK(IsSuspended()); |
- |
- // Request audio focus again in case we lost it because another app started |
- // playing while the playback was paused. |
- State audio_focus_state = RequestSystemAudioFocus(audio_focus_type_) |
- ? State::ACTIVE |
- : State::INACTIVE; |
- SetAudioFocusState(audio_focus_state); |
- |
- if (audio_focus_state_ != State::ACTIVE) |
- return; |
- |
- OnResumeInternal(SuspendType::UI); |
-} |
- |
-void MediaSession::Suspend() { |
- DCHECK(!IsSuspended()); |
- |
- OnSuspendInternal(SuspendType::UI, State::SUSPENDED); |
-} |
- |
-void MediaSession::Stop() { |
- DCHECK(audio_focus_state_ != State::INACTIVE); |
- |
- if (audio_focus_state_ != State::SUSPENDED) |
- OnSuspendInternal(SuspendType::UI, State::SUSPENDED); |
- |
- DCHECK(audio_focus_state_ == State::SUSPENDED); |
- players_.clear(); |
- AbandonSystemAudioFocusIfNeeded(); |
-} |
- |
-bool MediaSession::IsSuspended() const { |
- // TODO(mlamouri): should be == State::SUSPENDED. |
- return audio_focus_state_ != State::ACTIVE; |
-} |
- |
-bool MediaSession::IsControllable() const { |
- // Only content type media session can be controllable unless it is inactive. |
- return audio_focus_state_ != State::INACTIVE && |
- audio_focus_type_ == Type::Content; |
-} |
- |
-void MediaSession::ResetJavaRefForTest() { |
- j_media_session_.Reset(); |
-} |
- |
-bool MediaSession::IsActiveForTest() const { |
- return audio_focus_state_ == State::ACTIVE; |
-} |
- |
-MediaSession::Type MediaSession::audio_focus_type_for_test() const { |
- return audio_focus_type_; |
-} |
- |
-MediaSessionUmaHelper* MediaSession::uma_helper_for_test() { |
- return &uma_helper_; |
-} |
- |
-void MediaSession::RemoveAllPlayersForTest() { |
- players_.clear(); |
- AbandonSystemAudioFocusIfNeeded(); |
-} |
- |
-void MediaSession::OnSuspendInternal(SuspendType type, State new_state) { |
- DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE); |
- // UI suspend cannot use State::INACTIVE. |
- DCHECK(type == SuspendType::SYSTEM || new_state == State::SUSPENDED); |
- |
- switch (type) { |
- case SuspendType::UI: |
- uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI); |
- break; |
- case SuspendType::SYSTEM: |
- switch (new_state) { |
- case State::SUSPENDED: |
- uma_helper_.RecordSessionSuspended( |
- MediaSessionSuspendedSource::SystemTransient); |
- break; |
- case State::INACTIVE: |
- uma_helper_.RecordSessionSuspended( |
- MediaSessionSuspendedSource::SystemPermanent); |
- break; |
- case State::ACTIVE: |
- NOTREACHED(); |
- break; |
- } |
- break; |
- case SuspendType::CONTENT: |
- uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::CONTENT); |
- break; |
- } |
- |
- SetAudioFocusState(new_state); |
- suspend_type_ = type; |
- |
- if (type != SuspendType::CONTENT) { |
- // SuspendType::CONTENT happens when the suspend action came from |
- // the page in which case the player is already paused. |
- // Otherwise, the players need to be paused. |
- for (const auto& it : players_) |
- it.observer->OnSuspend(it.player_id); |
- } |
- |
- UpdateWebContents(); |
-} |
- |
-void MediaSession::OnResumeInternal(SuspendType type) { |
- if (type == SuspendType::SYSTEM && suspend_type_ != type) |
- return; |
- |
- SetAudioFocusState(State::ACTIVE); |
- |
- for (const auto& it : players_) |
- it.observer->OnResume(it.player_id); |
- |
- UpdateWebContents(); |
-} |
- |
-void MediaSession::OnSetVolumeMultiplierInternal(double volume_multiplier) { |
- volume_multiplier_ = volume_multiplier; |
- for (const auto& it : players_) |
- it.observer->OnSetVolumeMultiplier(it.player_id, volume_multiplier_); |
-} |
- |
-MediaSession::MediaSession(WebContents* web_contents) |
- : WebContentsObserver(web_contents), |
- audio_focus_state_(State::INACTIVE), |
- audio_focus_type_(Type::Transient), |
- volume_multiplier_(media::MediaPlayerAndroid::kDefaultVolumeMultiplier) { |
-} |
- |
-void MediaSession::Initialize() { |
- JNIEnv* env = base::android::AttachCurrentThread(); |
- DCHECK(env); |
- j_media_session_.Reset(Java_MediaSession_createMediaSession( |
- env, |
- base::android::GetApplicationContext(), |
- reinterpret_cast<intptr_t>(this))); |
-} |
- |
-bool MediaSession::RequestSystemAudioFocus(Type type) { |
- // During tests, j_media_session_ might be null. |
- if (j_media_session_.is_null()) |
- return true; |
- |
- JNIEnv* env = base::android::AttachCurrentThread(); |
- DCHECK(env); |
- bool result = Java_MediaSession_requestAudioFocus(env, j_media_session_.obj(), |
- type == Type::Transient); |
- uma_helper_.RecordRequestAudioFocusResult(result); |
- return result; |
-} |
- |
-void MediaSession::AbandonSystemAudioFocusIfNeeded() { |
- if (audio_focus_state_ == State::INACTIVE || !players_.empty()) |
- return; |
- |
- // During tests, j_media_session_ might be null. |
- if (!j_media_session_.is_null()) { |
- JNIEnv* env = base::android::AttachCurrentThread(); |
- DCHECK(env); |
- Java_MediaSession_abandonAudioFocus(env, j_media_session_.obj()); |
- } |
- |
- SetAudioFocusState(State::INACTIVE); |
- UpdateWebContents(); |
-} |
- |
-void MediaSession::UpdateWebContents() { |
- static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); |
-} |
- |
-void MediaSession::SetAudioFocusState(State audio_focus_state) { |
- if (audio_focus_state == audio_focus_state_) |
- return; |
- |
- audio_focus_state_ = audio_focus_state; |
- switch (audio_focus_state_) { |
- case State::ACTIVE: |
- uma_helper_.OnSessionActive(); |
- break; |
- case State::SUSPENDED: |
- uma_helper_.OnSessionSuspended(); |
- break; |
- case State::INACTIVE: |
- uma_helper_.OnSessionInactive(); |
- break; |
- } |
-} |
- |
-} // namespace content |