Commit 2f7072ff authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media Session] Switch content to using the service

Switch the content MediaSession code to using the audio
focus service on non-Android platforms.

BUG=875004

Change-Id: I8171a7351a7d64065564fe5f75937e1abaef8e7c
Reviewed-on: https://chromium-review.googlesource.com/c/1207657Reviewed-by: default avatarFredrik Hubinette <hubbe@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596456}
parent 68b5a64d
......@@ -18,7 +18,6 @@
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "build/build_config.h"
#include "content/browser/media/session/audio_focus_manager.h"
#include "content/browser/media/session/media_session_impl.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/public/browser/browser_context.h"
......@@ -30,10 +29,13 @@
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/common/service_manager_connection.h"
#include "media/base/audio_parameters.h"
#include "media/base/media_log_event.h"
#include "media/filters/gpu_video_decoder.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/media_session/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#if !defined(OS_ANDROID)
#include "media/filters/decrypting_video_decoder.h"
......@@ -719,33 +721,20 @@ void MediaInternals::SendVideoCaptureDeviceCapabilities() {
}
void MediaInternals::SendAudioFocusState() {
#if !defined(OS_ANDROID)
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!CanUpdate())
return;
audio_focus_data_.Clear();
auto& stack = AudioFocusManager::GetInstance()->audio_focus_stack_;
// We should go backwards through the stack so the top of the stack is always
// shown first in the list.
base::ListValue stack_data;
for (auto iter = stack.rbegin(); iter != stack.rend(); ++iter) {
base::DictionaryValue media_session_data;
media_session_data.SetKey(kAudioFocusIdKey, base::Value((*iter)->id()));
stack_data.GetList().push_back(std::move(media_session_data));
(*iter)->session()->GetDebugInfo(
base::BindOnce(&MediaInternals::DidGetAudioFocusDebugInfo,
base::Unretained(this), (*iter)->id()));
}
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->BindInterface(media_session::mojom::kServiceName, &audio_focus_ptr_);
audio_focus_data_.SetKey(kAudioFocusSessionsKey, std::move(stack_data));
if (!audio_focus_ptr_.is_bound())
return;
if (stack.empty())
SendUpdate(SerializeUpdate(kAudioFocusFunction, &audio_focus_data_));
#endif // !defined(OS_ANDROID)
// Get the audio focus state from the media session service.
audio_focus_ptr_->GetFocusRequests(base::BindOnce(
&MediaInternals::DidGetAudioFocusRequestList, base::Unretained(this)));
}
void MediaInternals::UpdateVideoCaptureDeviceCapabilities(
......@@ -847,6 +836,43 @@ void MediaInternals::OnFocusLost(
base::Unretained(this)));
}
void MediaInternals::DidGetAudioFocusRequestList(
std::vector<media_session::mojom::AudioFocusRequestStatePtr> stack) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!CanUpdate())
return;
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->BindInterface(media_session::mojom::kServiceName,
&audio_focus_debug_ptr_);
if (!audio_focus_debug_ptr_.is_bound())
return;
audio_focus_data_.Clear();
// We should go backwards through the stack so the top of the stack is
// always shown first in the list.
base::ListValue stack_data;
for (auto iter = stack.rbegin(); iter != stack.rend(); ++iter) {
int request_id = (*iter)->request_id;
base::DictionaryValue media_session_data;
media_session_data.SetKey(kAudioFocusIdKey, base::Value(request_id));
stack_data.GetList().push_back(std::move(media_session_data));
audio_focus_debug_ptr_->GetDebugInfoForRequest(
request_id, base::BindOnce(&MediaInternals::DidGetAudioFocusDebugInfo,
base::Unretained(this), request_id));
}
audio_focus_data_.SetKey(kAudioFocusSessionsKey, std::move(stack_data));
if (stack.empty())
SendUpdate(SerializeUpdate(kAudioFocusFunction, &audio_focus_data_));
}
void MediaInternals::DidGetAudioFocusDebugInfo(
int id,
media_session::mojom::MediaSessionDebugInfoPtr info) {
......
......@@ -126,7 +126,12 @@ class CONTENT_EXPORT MediaInternals : public media::AudioLogFactory,
void OnFocusLost(
media_session::mojom::MediaSessionInfoPtr media_session) override;
// Called when we receive audio focus debug info to display.
// Called when we receive the list of audio focus requests to display.
void DidGetAudioFocusRequestList(
std::vector<media_session::mojom::AudioFocusRequestStatePtr>);
// Called when we receive audio focus debug info to display for a single
// audio focus request.
void DidGetAudioFocusDebugInfo(
int id,
media_session::mojom::MediaSessionDebugInfoPtr info);
......@@ -157,6 +162,10 @@ class CONTENT_EXPORT MediaInternals : public media::AudioLogFactory,
int render_process_id,
int render_frame_id);
// Holds a pointer to the media session service and it's debug interface.
media_session::mojom::AudioFocusManagerPtr audio_focus_ptr_;
media_session::mojom::AudioFocusManagerDebugPtr audio_focus_debug_ptr_;
// Must only be accessed on the UI thread.
std::vector<UpdateCallback> update_callbacks_;
......
......@@ -12,14 +12,15 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "base/test/scoped_command_line.h"
#include "base/test/test_message_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/browser/media/session/audio_focus_manager.h"
#include "content/browser/media/session/media_session_impl.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_service_manager_context.h"
#include "content/test/test_web_contents.h"
#include "media/base/audio_parameters.h"
#include "media/base/channel_layout.h"
......@@ -40,8 +41,15 @@ const char kTestDeviceID[] = "test-device-id";
// integer/string values.
class MediaInternalsTestBase {
public:
MediaInternalsTestBase()
: media_internals_(content::MediaInternals::GetInstance()) {}
MediaInternalsTestBase() : media_internals_(nullptr) {
scoped_command_line_.GetProcessCommandLine()->AppendSwitch(
media_session::switches::kEnableAudioFocus);
service_manager_context_ =
std::make_unique<content::TestServiceManagerContext>();
media_internals_ = content::MediaInternals::GetInstance();
}
virtual ~MediaInternalsTestBase() {}
protected:
......@@ -98,7 +106,14 @@ class MediaInternalsTestBase {
const content::TestBrowserThreadBundle thread_bundle_;
base::DictionaryValue update_data_;
content::MediaInternals* const media_internals_;
content::MediaInternals* media_internals() const { return media_internals_; }
private:
content::MediaInternals* media_internals_;
base::test::ScopedCommandLine scoped_command_line_;
std::unique_ptr<content::TestServiceManagerContext> service_manager_context_;
};
} // namespace
......@@ -114,11 +129,11 @@ class MediaInternalsVideoCaptureDeviceTest : public testing::Test,
: update_cb_(base::Bind(
&MediaInternalsVideoCaptureDeviceTest::UpdateCallbackImpl,
base::Unretained(this))) {
media_internals_->AddUpdateCallback(update_cb_);
media_internals()->AddUpdateCallback(update_cb_);
}
~MediaInternalsVideoCaptureDeviceTest() override {
media_internals_->RemoveUpdateCallback(update_cb_);
media_internals()->RemoveUpdateCallback(update_cb_);
}
protected:
......@@ -176,7 +191,7 @@ TEST_F(MediaInternalsVideoCaptureDeviceTest,
// a JSON array of objects to string. So here, the |UpdateCallbackImpl| will
// deserialize the first object in the array. This means we have to have
// exactly one device_info in the |descriptors_and_formats|.
media_internals_->UpdateVideoCaptureDeviceCapabilities(
media_internals()->UpdateVideoCaptureDeviceCapabilities(
descriptors_and_formats);
#if defined(OS_LINUX)
......@@ -208,13 +223,13 @@ class MediaInternalsAudioLogTest
base::Unretained(this))),
test_params_(MakeAudioParams()),
test_component_(GetParam()),
audio_log_(media_internals_->CreateAudioLog(test_component_,
kTestComponentID)) {
media_internals_->AddUpdateCallback(update_cb_);
audio_log_(media_internals()->CreateAudioLog(test_component_,
kTestComponentID)) {
media_internals()->AddUpdateCallback(update_cb_);
}
virtual ~MediaInternalsAudioLogTest() {
media_internals_->RemoveUpdateCallback(update_cb_);
media_internals()->RemoveUpdateCallback(update_cb_);
}
protected:
......@@ -309,13 +324,12 @@ class MediaInternalsAudioFocusTest : public testing::Test,
base::BindRepeating(&MediaInternalsAudioFocusTest::UpdateCallbackImpl,
base::Unretained(this));
scoped_command_line_.GetProcessCommandLine()->AppendSwitch(
media_session::switches::kEnableAudioFocus);
browser_context_.reset(new TestBrowserContext());
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_ = std::make_unique<base::RunLoop>();
content::MediaInternals::GetInstance()->AddUpdateCallback(update_cb_);
browser_context_.reset(new TestBrowserContext());
}
void TearDown() override {
......@@ -325,20 +339,32 @@ class MediaInternalsAudioFocusTest : public testing::Test,
protected:
void UpdateCallbackImpl(const base::string16& update) override {
base::AutoLock auto_lock(lock_);
MediaInternalsTestBase::UpdateCallbackImpl(update);
run_loop_->Quit();
call_count_++;
if (call_count_ == wanted_call_count_)
run_loop_->Quit();
}
void ExpectValueAndReset(base::ListValue expected_list) {
base::AutoLock auto_lock(lock_);
base::DictionaryValue expected_data;
expected_data.SetKey("sessions", std::move(expected_list));
EXPECT_EQ(expected_data, update_data_);
Reset();
update_data_.Clear();
run_loop_ = std::make_unique<base::RunLoop>();
call_count_ = 0;
}
void Reset() {
base::AutoLock auto_lock(lock_);
update_data_.Clear();
run_loop_ = std::make_unique<base::RunLoop>();
call_count_ = 0;
}
std::unique_ptr<TestWebContents> CreateWebContents() {
......@@ -356,9 +382,14 @@ class MediaInternalsAudioFocusTest : public testing::Test,
session->RemoveAllPlayersForTest();
}
void WaitForCallback() {
if (!update_data_.empty())
return;
void WaitForCallbackCount(int count) {
wanted_call_count_ = count;
{
base::AutoLock auto_lock(lock_);
if (!update_data_.empty() && call_count_ == wanted_call_count_)
return;
}
run_loop_->Run();
}
......@@ -366,8 +397,11 @@ class MediaInternalsAudioFocusTest : public testing::Test,
MediaInternals::UpdateCallback update_cb_;
private:
int call_count_ = 0;
int wanted_call_count_ = 0;
base::Lock lock_;
std::unique_ptr<base::RunLoop> run_loop_;
base::test::ScopedCommandLine scoped_command_line_;
std::unique_ptr<TestBrowserContext> browser_context_;
};
......@@ -377,7 +411,7 @@ TEST_F(MediaInternalsAudioFocusTest, AudioFocusStateIsUpdated) {
web_contents1->SetTitle(base::UTF8ToUTF16(kTestTitle1));
MediaSessionImpl* media_session1 = MediaSessionImpl::Get(web_contents1.get());
media_session1->RequestSystemAudioFocus(AudioFocusType::kGain);
WaitForCallback();
WaitForCallbackCount(1);
// Check JSON is what we expect.
{
......@@ -398,9 +432,7 @@ TEST_F(MediaInternalsAudioFocusTest, AudioFocusStateIsUpdated) {
MediaSessionImpl* media_session2 = MediaSessionImpl::Get(web_contents2.get());
media_session2->RequestSystemAudioFocus(
AudioFocusType::kGainTransientMayDuck);
WaitForCallback();
Reset();
WaitForCallback();
WaitForCallbackCount(2);
// Check JSON is what we expect.
{
......@@ -424,7 +456,7 @@ TEST_F(MediaInternalsAudioFocusTest, AudioFocusStateIsUpdated) {
// Abandon audio focus.
RemoveAllPlayersForTest(media_session2);
WaitForCallback();
WaitForCallbackCount(1);
// Check JSON is what we expect.
{
......@@ -441,7 +473,7 @@ TEST_F(MediaInternalsAudioFocusTest, AudioFocusStateIsUpdated) {
// Abandon audio focus.
RemoveAllPlayersForTest(media_session1);
WaitForCallback();
WaitForCallbackCount(1);
// Check JSON is what we expect.
{
......
......@@ -5,13 +5,7 @@
#ifndef CONTENT_BROWSER_MEDIA_SESSION_AUDIO_FOCUS_DELEGATE_H_
#define CONTENT_BROWSER_MEDIA_SESSION_AUDIO_FOCUS_DELEGATE_H_
#include "content/browser/media/session/audio_focus_manager.h"
namespace media_session {
namespace mojom {
enum class AudioFocusType;
} // namespace mojom
} // namespace media_session
#include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace content {
......@@ -40,6 +34,10 @@ class AudioFocusDelegate {
// Retrieves the current |AudioFocusType| for the associated |MediaSession|.
virtual base::Optional<media_session::mojom::AudioFocusType>
GetCurrentFocusType() const = 0;
// |MediaSession| should call this when it's state changes.
virtual void MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr) = 0;
};
} // namespace content
......
......@@ -54,6 +54,10 @@ class AudioFocusDelegateAndroid : public AudioFocusDelegate {
void RecordSessionDuck(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
// This is not used by this delegate.
void MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr) override {}
private:
// Weak pointer because |this| is owned by |media_session_|.
MediaSessionImpl* media_session_;
......
......@@ -4,10 +4,13 @@
#include "content/browser/media/session/audio_focus_delegate.h"
#include "content/browser/media/session/audio_focus_manager.h"
#include "content/browser/media/session/media_session_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/service_manager_connection.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/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace content {
......@@ -25,73 +28,130 @@ class AudioFocusDelegateDefault : public AudioFocusDelegate {
// AudioFocusDelegate implementation.
AudioFocusResult RequestAudioFocus(AudioFocusType audio_focus_type) override;
void AbandonAudioFocus() override;
base::Optional<AudioFocusType> GetCurrentFocusType() const override;
base::Optional<media_session::mojom::AudioFocusType> GetCurrentFocusType()
const override;
void MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr) override;
private:
// Holds the current audio focus request id for |media_session_|.
base::Optional<AudioFocusManager::RequestId> request_id_;
// Finishes an async audio focus request.
void FinishAudioFocusRequest(AudioFocusType type);
// Ensures that |audio_focus_ptr_| is connected.
void EnsureServiceConnection();
// Holds the latest MediaSessionInfo for |media_session_|.
media_session::mojom::MediaSessionInfoPtr session_info_;
// Holds a pointer to the Media Session service.
media_session::mojom::AudioFocusManagerPtr audio_focus_ptr_;
// If the media session has acquired audio focus then this will contain a
// pointer to that requests AudioFocusRequestClient.
media_session::mojom::AudioFocusRequestClientPtr request_client_ptr_;
// Weak pointer because |this| is owned by |media_session_|.
MediaSessionImpl* media_session_;
// The last requested AudioFocusType by the associated |media_session_|.
base::Optional<AudioFocusType> audio_focus_type_if_disabled_;
base::Optional<AudioFocusType> audio_focus_type_;
};
} // anonymous namespace
AudioFocusDelegateDefault::AudioFocusDelegateDefault(
MediaSessionImpl* media_session)
: media_session_(media_session) {}
: media_session_(media_session) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
AudioFocusDelegateDefault::~AudioFocusDelegateDefault() = default;
AudioFocusDelegate::AudioFocusResult
AudioFocusDelegateDefault::RequestAudioFocus(AudioFocusType audio_focus_type) {
audio_focus_type_if_disabled_ = audio_focus_type;
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!media_session::IsAudioFocusEnabled())
if (!media_session::IsAudioFocusEnabled()) {
audio_focus_type_ = audio_focus_type;
return AudioFocusDelegate::AudioFocusResult::kSuccess;
}
if (request_client_ptr_.is_bound()) {
// We have an existing request so we should request an updated focus type.
request_client_ptr_->RequestAudioFocus(
session_info_.Clone(), audio_focus_type,
base::BindOnce(&AudioFocusDelegateDefault::FinishAudioFocusRequest,
base::Unretained(this), audio_focus_type));
} else {
EnsureServiceConnection();
// Create a mojo interface pointer to our media session.
media_session::mojom::MediaSessionPtr media_session;
media_session_->BindToMojoRequest(mojo::MakeRequest(&media_session));
audio_focus_ptr_->RequestAudioFocus(
mojo::MakeRequest(&request_client_ptr_), std::move(media_session),
session_info_.Clone(), audio_focus_type,
base::BindOnce(&AudioFocusDelegateDefault::FinishAudioFocusRequest,
base::Unretained(this), audio_focus_type));
}
// Return delayed as we make the async call to request audio focus.
return AudioFocusDelegate::AudioFocusResult::kDelayed;
}
media_session::mojom::MediaSessionInfoPtr session_info =
media_session_->GetMediaSessionInfoSync();
void AudioFocusDelegateDefault::AbandonAudioFocus() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Create a mojo interface pointer to our media session. This will allow the
// AudioFocusManager to interact with the media session across processes.
media_session::mojom::MediaSessionPtr media_session;
media_session_->BindToMojoRequest(mojo::MakeRequest(&media_session));
audio_focus_type_.reset();
AudioFocusManager::RequestResponse response =
AudioFocusManager::GetInstance()->RequestAudioFocus(
std::move(media_session), std::move(session_info), audio_focus_type,
request_id_);
if (!request_client_ptr_.is_bound())
return;
request_id_ = response.first;
request_client_ptr_->AbandonAudioFocus();
request_client_ptr_.reset();
}
return response.second ? AudioFocusDelegate::AudioFocusResult::kSuccess
: AudioFocusDelegate::AudioFocusResult::kFailed;
base::Optional<media_session::mojom::AudioFocusType>
AudioFocusDelegateDefault::GetCurrentFocusType() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return audio_focus_type_;
}
void AudioFocusDelegateDefault::AbandonAudioFocus() {
audio_focus_type_if_disabled_.reset();
void AudioFocusDelegateDefault::MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr session_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!request_id_.has_value())
return;
if (request_client_ptr_.is_bound())
request_client_ptr_->MediaSessionInfoChanged(session_info.Clone());
session_info_ = std::move(session_info);
}
void AudioFocusDelegateDefault::FinishAudioFocusRequest(AudioFocusType type) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(request_client_ptr_.is_bound());
AudioFocusManager::GetInstance()->AbandonAudioFocus(request_id_.value());
request_id_.reset();
audio_focus_type_ = type;
media_session_->FinishSystemAudioFocusRequest(type, true /* result */);
}
base::Optional<AudioFocusType> AudioFocusDelegateDefault::GetCurrentFocusType()
const {
void AudioFocusDelegateDefault::EnsureServiceConnection() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!media_session::IsAudioFocusEnabled())
return audio_focus_type_if_disabled_;
return;
if (audio_focus_ptr_.is_bound() && !audio_focus_ptr_.encountered_error())
return;
if (!request_id_.has_value())
return base::Optional<AudioFocusType>();
audio_focus_ptr_.reset();
return AudioFocusManager::GetInstance()->GetFocusTypeForSession(
request_id_.value());
// Connect to the Media Session service and bind |audio_focus_ptr_| to it.
service_manager::Connector* connector =
ServiceManagerConnection::GetForProcess()->GetConnector();
connector->BindInterface(media_session::mojom::kServiceName,
mojo::MakeRequest(&audio_focus_ptr_));
}
// static
......
......@@ -3,18 +3,75 @@
// found in the LICENSE file.
#include "base/command_line.h"
#include "content/browser/media/session/audio_focus_test_util.h"
#include "content/browser/media/session/media_session_impl.h"
#include "content/browser/media/session/mock_media_session_player_observer.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/test/content_browser_test.h"
#include "content/shell/browser/shell.h"
#include "media/base/media_content_type.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/mojom/audio_focus.mojom.h"
#include "services/media_session/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace content {
using media_session::test::TestAudioFocusObserver;
class MediaSessionStateObserver
: public media_session::mojom::MediaSessionObserver {
public:
explicit MediaSessionStateObserver(
media_session::mojom::MediaSession* media_session)
: binding_(this) {
media_session::mojom::MediaSessionObserverPtr observer;
binding_.Bind(mojo::MakeRequest(&observer));
media_session->AddObserver(std::move(observer));
}
~MediaSessionStateObserver() override = default;
// media_session::mojom::MediaSessionObserver
void MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr session_info) override {
if (desired_state_.has_value() &&
desired_state_.value() == session_info->state) {
run_loop_.Quit();
return;
}
session_info_ = std::move(session_info);
}
void WaitForState(
media_session::mojom::MediaSessionInfo::SessionState state) {
if (session_info_ && state == session_info_->state)
return;
desired_state_ = state;
run_loop_.Run();
}
protected:
base::RunLoop run_loop_;
mojo::Binding<media_session::mojom::MediaSessionObserver> binding_;
base::Optional<media_session::mojom::MediaSessionInfo::SessionState>
desired_state_;
media_session::mojom::MediaSessionInfoPtr session_info_;
DISALLOW_COPY_AND_ASSIGN(MediaSessionStateObserver);
};
class AudioFocusDelegateDefaultBrowserTest : public ContentBrowserTest {
protected:
void SetUpOnMainThread() override {
service_manager::Connector* connector =
ServiceManagerConnection::GetForProcess()->GetConnector();
connector->BindInterface(media_session::mojom::kServiceName,
mojo::MakeRequest(&audio_focus_ptr_));
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(media_session::switches::kEnableAudioFocus);
}
......@@ -33,30 +90,77 @@ class AudioFocusDelegateDefaultBrowserTest : public ContentBrowserTest {
player_observer->StartNewPlayer();
{
test::TestAudioFocusObserver observer;
std::unique_ptr<TestAudioFocusObserver> observer = CreateObserver();
media_session->AddPlayer(player_observer.get(), 0,
media::MediaContentType::Persistent);
observer.WaitForGainedEvent();
observer->WaitForGainedEvent();
}
EXPECT_TRUE(media_session->IsActive());
EXPECT_FALSE(other_media_session->IsActive());
{
MediaSessionStateObserver state_observer(media_session);
state_observer.WaitForState(
media_session::mojom::MediaSessionInfo::SessionState::kActive);
}
{
MediaSessionStateObserver state_observer(other_media_session);
state_observer.WaitForState(
media_session::mojom::MediaSessionInfo::SessionState::kInactive);
}
player_observer->StartNewPlayer();
{
test::TestAudioFocusObserver observer;
std::unique_ptr<TestAudioFocusObserver> observer = CreateObserver();
other_media_session->AddPlayer(player_observer.get(), 1,
media::MediaContentType::Persistent);
observer.WaitForGainedEvent();
observer->WaitForGainedEvent();
}
{
MediaSessionStateObserver state_observer(media_session);
state_observer.WaitForState(
media_session::mojom::MediaSessionInfo::SessionState::kSuspended);
}
{
MediaSessionStateObserver state_observer(other_media_session);
state_observer.WaitForState(
media_session::mojom::MediaSessionInfo::SessionState::kActive);
}
{
std::unique_ptr<TestAudioFocusObserver> observer = CreateObserver();
media_session->Stop(MediaSessionImpl::SuspendType::kUI);
other_media_session->Stop(MediaSessionImpl::SuspendType::kUI);
observer->WaitForLostEvent();
}
EXPECT_FALSE(media_session->IsActive());
EXPECT_TRUE(other_media_session->IsActive());
{
MediaSessionStateObserver state_observer(media_session);
state_observer.WaitForState(
media_session::mojom::MediaSessionInfo::SessionState::kInactive);
}
media_session->Stop(MediaSessionImpl::SuspendType::kUI);
other_media_session->Stop(MediaSessionImpl::SuspendType::kUI);
{
MediaSessionStateObserver state_observer(other_media_session);
state_observer.WaitForState(
media_session::mojom::MediaSessionInfo::SessionState::kInactive);
}
}
private:
std::unique_ptr<TestAudioFocusObserver> CreateObserver() {
std::unique_ptr<TestAudioFocusObserver> observer =
std::make_unique<TestAudioFocusObserver>();
media_session::mojom::AudioFocusObserverPtr observer_ptr;
observer->BindToMojoRequest(mojo::MakeRequest(&observer_ptr));
audio_focus_ptr_->AddObserver(std::move(observer_ptr));
audio_focus_ptr_.FlushForTesting();
return observer;
}
media_session::mojom::AudioFocusManagerPtr audio_focus_ptr_;
};
// Two windows from the same BrowserContext.
......
......@@ -336,23 +336,6 @@ TEST_F(AudioFocusManagerTest, AbandonAudioFocus_NoAssociatedEntry) {
EXPECT_EQ(kNoFocusedSession, GetAudioFocusedSession());
}
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientEntry) {
MockMediaSession media_session;
AudioFocusManager::RequestId request_id =
RequestAudioFocus(&media_session, AudioFocusType::kGainTransientMayDuck);
EXPECT_EQ(1, GetTransientMaybeDuckCount());
{
test::TestAudioFocusObserver observer;
AbandonAudioFocus(request_id);
EXPECT_EQ(0, GetTransientMaybeDuckCount());
EXPECT_TRUE(observer.focus_lost_session_.Equals(
test::GetMediaSessionInfoSync(&media_session)));
}
}
TEST_F(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
MockMediaSession media_session_1;
MockMediaSession media_session_2;
......@@ -528,51 +511,4 @@ TEST_F(AudioFocusManagerTest, AudioFocusObserver_AbandonNoop) {
EXPECT_TRUE(observer.focus_lost_session_.is_null());
}
TEST_F(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) {
MockMediaSession media_session;
AudioFocusManager::RequestId request_id;
{
test::TestAudioFocusObserver observer;
request_id = RequestAudioFocus(&media_session, AudioFocusType::kGain);
EXPECT_EQ(request_id, GetAudioFocusedSession());
EXPECT_EQ(AudioFocusType::kGain, observer.focus_gained_type());
EXPECT_FALSE(observer.focus_gained_session_.is_null());
}
{
test::TestAudioFocusObserver observer;
RequestAudioFocus(&media_session, AudioFocusType::kGain, request_id);
EXPECT_EQ(request_id, GetAudioFocusedSession());
EXPECT_TRUE(observer.focus_gained_session_.is_null());
}
}
TEST_F(AudioFocusManagerTest, AudioFocusObserver_TransientMayDuck) {
MockMediaSession media_session;
AudioFocusManager::RequestId request_id;
{
test::TestAudioFocusObserver observer;
request_id = RequestAudioFocus(&media_session,
AudioFocusType::kGainTransientMayDuck);
EXPECT_EQ(1, GetTransientMaybeDuckCount());
EXPECT_EQ(AudioFocusType::kGainTransientMayDuck,
observer.focus_gained_type());
EXPECT_FALSE(observer.focus_gained_session_.is_null());
}
{
test::TestAudioFocusObserver observer;
AbandonAudioFocus(request_id);
EXPECT_EQ(0, GetTransientMaybeDuckCount());
EXPECT_TRUE(observer.focus_lost_session_.Equals(
test::GetMediaSessionInfoSync(&media_session)));
}
}
} // namespace content
......@@ -4,41 +4,52 @@
#include "content/browser/media/session/audio_focus_observer.h"
#include "build/build_config.h"
#include "content/browser/media/session/audio_focus_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/service_manager_connection.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/media_session/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace content {
AudioFocusObserver::AudioFocusObserver() : binding_(this) {}
void AudioFocusObserver::RegisterAudioFocusObserver() {
if (observer_id_.has_value())
ConnectToService();
if (!audio_focus_ptr_.is_bound() || audio_focus_ptr_.encountered_error())
return;
if (binding_.is_bound())
return;
#if !defined(OS_ANDROID)
// TODO(https://crbug.com/873320): Add support for Android.
DCHECK_CURRENTLY_ON(BrowserThread::UI);
media_session::mojom::AudioFocusObserverPtr observer;
binding_.Bind(mojo::MakeRequest(&observer));
observer_id_ =
AudioFocusManager::GetInstance()->AddObserver(std::move(observer));
#endif
audio_focus_ptr_->AddObserver(std::move(observer));
}
void AudioFocusObserver::UnregisterAudioFocusObserver() {
if (!observer_id_.has_value())
return;
#if !defined(OS_ANDROID)
// TODO(https://crbug.com/873320): Add support for Android.
DCHECK_CURRENTLY_ON(BrowserThread::UI);
binding_.Close();
AudioFocusManager::GetInstance()->RemoveObserver(observer_id_.value());
#endif
}
void AudioFocusObserver::ConnectToService() {
if (audio_focus_ptr_.encountered_error())
audio_focus_ptr_.reset();
if (audio_focus_ptr_.is_bound())
return;
ServiceManagerConnection* connection =
ServiceManagerConnection::GetForProcess();
if (!connection)
return;
observer_id_.reset();
service_manager::Connector* connector = connection->GetConnector();
connector->BindInterface(media_session::mojom::kServiceName,
mojo::MakeRequest(&audio_focus_ptr_));
}
AudioFocusObserver::~AudioFocusObserver() = default;
......
......@@ -6,10 +6,8 @@
#define CONTENT_BROWSER_MEDIA_SESSION_AUDIO_FOCUS_OBSERVER_H_
#include "base/macros.h"
#include "base/optional.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h"
namespace content {
......@@ -35,7 +33,8 @@ class CONTENT_EXPORT AudioFocusObserver
void UnregisterAudioFocusObserver();
private:
base::Optional<mojo::InterfacePtrSetElementId> observer_id_;
void ConnectToService();
media_session::mojom::AudioFocusManagerPtr audio_focus_ptr_;
mojo::Binding<media_session::mojom::AudioFocusObserver> binding_;
......
......@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "build/build_config.h"
#include "content/browser/media/session/media_session_controller.h"
#include "content/public/test/test_service_manager_context.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "media/base/media_content_type.h"
......@@ -54,6 +55,8 @@ class MediaSessionControllersManagerTest
}
#endif
service_manager_context_ = std::make_unique<TestServiceManagerContext>();
media_player_id_ = MediaSessionControllersManager::MediaPlayerId(
contents()->GetMainFrame(), 1);
mock_media_session_controller_ =
......@@ -86,6 +89,7 @@ class MediaSessionControllersManagerTest
void TearDown() override {
manager_.reset();
service_manager_context_.reset();
RenderViewHostImplTestHarness::TearDown();
}
......@@ -98,6 +102,7 @@ class MediaSessionControllersManagerTest
StrictMock<MockMediaSessionController>* mock_media_session_controller_ptr_ =
nullptr;
std::unique_ptr<MediaSessionControllersManager> manager_;
std::unique_ptr<TestServiceManagerContext> service_manager_context_;
};
TEST_P(MediaSessionControllersManagerTest, RequestPlayAddsSessionsToMap) {
......
......@@ -626,6 +626,7 @@ MediaSessionImpl::MediaSessionImpl(WebContents* web_contents)
void MediaSessionImpl::Initialize() {
delegate_ = AudioFocusDelegate::Create(this);
delegate_->MediaSessionInfoChanged(GetMediaSessionInfoSync());
}
AudioFocusDelegate::AudioFocusResult MediaSessionImpl::RequestSystemAudioFocus(
......@@ -798,6 +799,8 @@ void MediaSessionImpl::NotifyObserversInfoChanged() {
[&current_info](media_session::mojom::MediaSessionObserver* observer) {
observer->MediaSessionInfoChanged(current_info.Clone());
});
delegate_->MediaSessionInfoChanged(current_info.Clone());
}
bool MediaSessionImpl::AddPepperPlayer(MediaSessionPlayerObserver* observer,
......
......@@ -16,7 +16,6 @@
#include "base/observer_list.h"
#include "base/optional.h"
#include "content/browser/media/session/audio_focus_delegate.h"
#include "content/browser/media/session/audio_focus_manager.h"
#include "content/browser/media/session/media_session_uma_helper.h"
#include "content/common/content_export.h"
#include "content/public/browser/media_session.h"
......
......@@ -71,6 +71,9 @@ class MockAudioFocusDelegate : public AudioFocusDelegate {
return audio_focus_type_;
}
void MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr session_info) override {}
void ResolveRequest(bool result) {
if (!async_mode_)
return;
......
......@@ -313,6 +313,7 @@ jumbo_static_library("test_support") {
"//ipc",
"//media/mojo/clients",
"//media/mojo/interfaces",
"//services/media_session/public/cpp/test:test_support",
"//services/media_session/public/mojom",
"//third_party/blink/public:blink",
"//third_party/blink/public:test_support",
......
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