Commit ae6e6928 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Audio Focus] Add a source name

Adds a source name to the AudioFocusManager API that can
be used to identify a client to the media session service.

This adds more granularity than service_manager::Identity
so we can differentiate between ARC and Content. It will
be used to identify a client when recording metrics and
for tweaking the UI based on where the media session
originated from.

BUG=875004

Change-Id: I4a78fd2bf17189de503aa507d51a7260f62ac7ee
Reviewed-on: https://chromium-review.googlesource.com/c/1239258
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#597287}
parent 781a65e2
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
namespace arc { namespace arc {
namespace { namespace {
constexpr char kAudioFocusSourceName[] = "arc";
// Singleton factory for ArcAccessibilityHelperBridge. // Singleton factory for ArcAccessibilityHelperBridge.
class ArcMediaSessionBridgeFactory class ArcMediaSessionBridgeFactory
: public internal::ArcBrowserContextKeyedServiceFactoryBase< : public internal::ArcBrowserContextKeyedServiceFactoryBase<
...@@ -87,6 +89,8 @@ void ArcMediaSessionBridge::SetupAudioFocus() { ...@@ -87,6 +89,8 @@ void ArcMediaSessionBridge::SetupAudioFocus() {
->GetConnector() ->GetConnector()
->BindInterface(media_session::mojom::kServiceName, &audio_focus_ptr); ->BindInterface(media_session::mojom::kServiceName, &audio_focus_ptr);
audio_focus_ptr->SetSourceName(kAudioFocusSourceName);
DVLOG(2) << "ArcMediaSessionBridge will enable audio focus"; DVLOG(2) << "ArcMediaSessionBridge will enable audio focus";
ms_instance->EnableAudioFocus(std::move(audio_focus_ptr)); ms_instance->EnableAudioFocus(std::move(audio_focus_ptr));
} }
......
...@@ -34,8 +34,10 @@ class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient { ...@@ -34,8 +34,10 @@ class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient {
mojom::MediaSessionPtr session, mojom::MediaSessionPtr session,
mojom::MediaSessionInfoPtr session_info, mojom::MediaSessionInfoPtr session_info,
mojom::AudioFocusType audio_focus_type, mojom::AudioFocusType audio_focus_type,
RequestId id) RequestId id,
const std::string& source_name)
: id_(id), : id_(id),
source_name_(source_name),
session_(std::move(session)), session_(std::move(session)),
session_info_(std::move(session_info)), session_info_(std::move(session_info)),
audio_focus_type_(audio_focus_type), audio_focus_type_(audio_focus_type),
...@@ -98,6 +100,8 @@ class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient { ...@@ -98,6 +100,8 @@ class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient {
RequestId id() const { return id_; } RequestId id() const { return id_; }
const std::string& source_name() const { return source_name_; }
// Flush any pending mojo messages for testing. // Flush any pending mojo messages for testing.
void FlushForTesting() { void FlushForTesting() {
session_.FlushForTesting(); session_.FlushForTesting();
...@@ -112,6 +116,8 @@ class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient { ...@@ -112,6 +116,8 @@ class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient {
} }
const RequestId id_; const RequestId id_;
const std::string source_name_;
mojom::MediaSessionPtr session_; mojom::MediaSessionPtr session_;
mojom::MediaSessionInfoPtr session_info_; mojom::MediaSessionInfoPtr session_info_;
mojom::AudioFocusType audio_focus_type_; mojom::AudioFocusType audio_focus_type_;
...@@ -137,7 +143,8 @@ void AudioFocusManager::RequestAudioFocus( ...@@ -137,7 +143,8 @@ void AudioFocusManager::RequestAudioFocus(
RequestAudioFocusInternal( RequestAudioFocusInternal(
std::make_unique<StackRow>( std::make_unique<StackRow>(
this, std::move(request), std::move(media_session), this, std::move(request), std::move(media_session),
std::move(session_info), type, GenerateAudioFocusRequestId()), std::move(session_info), type, GenerateAudioFocusRequestId(),
GetBindingSourceName()),
type, std::move(callback)); type, std::move(callback));
} }
...@@ -149,6 +156,7 @@ void AudioFocusManager::GetFocusRequests(GetFocusRequestsCallback callback) { ...@@ -149,6 +156,7 @@ void AudioFocusManager::GetFocusRequests(GetFocusRequestsCallback callback) {
request->session_info = row->info().Clone(); request->session_info = row->info().Clone();
request->audio_focus_type = row->audio_focus_type(); request->audio_focus_type = row->audio_focus_type();
request->request_id = row->id(); request->request_id = row->id();
request->source_name = row->source_name();
requests.push_back(std::move(request)); requests.push_back(std::move(request));
} }
...@@ -203,10 +211,16 @@ void AudioFocusManager::AddObserver(mojom::AudioFocusObserverPtr observer) { ...@@ -203,10 +211,16 @@ void AudioFocusManager::AddObserver(mojom::AudioFocusObserverPtr observer) {
observers_.AddPtr(std::move(observer)); observers_.AddPtr(std::move(observer));
} }
void AudioFocusManager::SetSourceName(const std::string& name) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
bindings_.dispatch_context()->source_name = name;
}
void AudioFocusManager::BindToInterface( void AudioFocusManager::BindToInterface(
mojom::AudioFocusManagerRequest request) { mojom::AudioFocusManagerRequest request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
bindings_.AddBinding(this, std::move(request)); bindings_.AddBinding(this, std::move(request),
std::make_unique<BindingContext>());
} }
void AudioFocusManager::BindToDebugInterface( void AudioFocusManager::BindToDebugInterface(
...@@ -357,6 +371,11 @@ AudioFocusManager::RemoveFocusEntryIfPresent(RequestId id) { ...@@ -357,6 +371,11 @@ AudioFocusManager::RemoveFocusEntryIfPresent(RequestId id) {
return row; return row;
} }
const std::string& AudioFocusManager::GetBindingSourceName() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return bindings_.dispatch_context()->source_name;
}
bool AudioFocusManager::IsSessionOnTopOfAudioFocusStack( bool AudioFocusManager::IsSessionOnTopOfAudioFocusStack(
RequestId id, RequestId id,
mojom::AudioFocusType type) const { mojom::AudioFocusType type) const {
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define SERVICES_MEDIA_SESSION_AUDIO_FOCUS_MANAGER_H_ #define SERVICES_MEDIA_SESSION_AUDIO_FOCUS_MANAGER_H_
#include <list> #include <list>
#include <string>
#include <unordered_map> #include <unordered_map>
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
...@@ -34,6 +35,7 @@ class AudioFocusManager : public mojom::AudioFocusManager, ...@@ -34,6 +35,7 @@ class AudioFocusManager : public mojom::AudioFocusManager,
RequestAudioFocusCallback callback) override; RequestAudioFocusCallback callback) override;
void GetFocusRequests(GetFocusRequestsCallback callback) override; void GetFocusRequests(GetFocusRequestsCallback callback) override;
void AddObserver(mojom::AudioFocusObserverPtr observer) override; void AddObserver(mojom::AudioFocusObserverPtr observer) override;
void SetSourceName(const std::string& name) override;
// mojom::AudioFocusManagerDebug. // mojom::AudioFocusManagerDebug.
void GetDebugInfoForRequest(uint64_t request_id, void GetDebugInfoForRequest(uint64_t request_id,
...@@ -57,6 +59,15 @@ class AudioFocusManager : public mojom::AudioFocusManager, ...@@ -57,6 +59,15 @@ class AudioFocusManager : public mojom::AudioFocusManager,
// control its audio focus. // control its audio focus.
class StackRow; class StackRow;
// BindingContext stores associated metadata for mojo binding.
struct BindingContext {
// The source name is associated with a binding when a client calls
// |SetSourceName|. It is used to provide more granularity than a
// service_manager::Identity for metrics and for identifying where an audio
// focus request originated from.
std::string source_name;
};
void RequestAudioFocusInternal(std::unique_ptr<StackRow>, void RequestAudioFocusInternal(std::unique_ptr<StackRow>,
mojom::AudioFocusType, mojom::AudioFocusType,
base::OnceCallback<void()>); base::OnceCallback<void()>);
...@@ -76,11 +87,16 @@ class AudioFocusManager : public mojom::AudioFocusManager, ...@@ -76,11 +87,16 @@ class AudioFocusManager : public mojom::AudioFocusManager,
std::unique_ptr<StackRow> RemoveFocusEntryIfPresent(RequestId id); std::unique_ptr<StackRow> RemoveFocusEntryIfPresent(RequestId id);
// Returns the source name of the binding currently accessing the Audio
// Focus Manager API over mojo.
const std::string& GetBindingSourceName() const;
bool IsSessionOnTopOfAudioFocusStack(RequestId id, bool IsSessionOnTopOfAudioFocusStack(RequestId id,
mojom::AudioFocusType type) const; mojom::AudioFocusType type) const;
// Holds mojo bindings for the Audio Focus Manager API. // Holds mojo bindings for the Audio Focus Manager API.
mojo::BindingSet<mojom::AudioFocusManager> bindings_; mojo::BindingSet<mojom::AudioFocusManager, std::unique_ptr<BindingContext>>
bindings_;
// Holds mojo bindings for the Audio Focus Manager Debug API. // Holds mojo bindings for the Audio Focus Manager Debug API.
mojo::BindingSet<mojom::AudioFocusManagerDebug> debug_bindings_; mojo::BindingSet<mojom::AudioFocusManagerDebug> debug_bindings_;
......
...@@ -34,6 +34,9 @@ const char kExampleDebugInfoName[] = "name"; ...@@ -34,6 +34,9 @@ const char kExampleDebugInfoName[] = "name";
const char kExampleDebugInfoOwner[] = "owner"; const char kExampleDebugInfoOwner[] = "owner";
const char kExampleDebugInfoState[] = "state"; const char kExampleDebugInfoState[] = "state";
const char kExampleSourceName[] = "test";
const char kExampleSourceName2[] = "test2";
class MockMediaSession : public mojom::MediaSession { class MockMediaSession : public mojom::MediaSession {
public: public:
MockMediaSession() = default; MockMediaSession() = default;
...@@ -296,6 +299,23 @@ class AudioFocusManagerTest : public testing::TestWithParam<bool> { ...@@ -296,6 +299,23 @@ class AudioFocusManagerTest : public testing::TestWithParam<bool> {
return mojom::MediaSessionInfo::SessionState::kActive; return mojom::MediaSessionInfo::SessionState::kActive;
} }
void SetSourceName(const std::string& name) {
GetService()->SetSourceName(name);
audio_focus_ptr_.FlushForTesting();
}
mojom::AudioFocusManagerPtr CreateAudioFocusManagerPtr() {
mojom::AudioFocusManagerPtr ptr;
connector_->BindInterface("test", mojo::MakeRequest(&ptr));
return ptr;
}
const std::string GetSourceNameForLastRequest() {
std::vector<mojom::AudioFocusRequestStatePtr> requests = GetRequests();
EXPECT_TRUE(requests.back());
return requests.back()->source_name.value();
}
private: private:
int GetCountForType(mojom::AudioFocusType type) { int GetCountForType(mojom::AudioFocusType type) {
const auto audio_focus_requests = GetRequests(); const auto audio_focus_requests = GetRequests();
...@@ -930,4 +950,33 @@ TEST_P(AudioFocusManagerTest, ...@@ -930,4 +950,33 @@ TEST_P(AudioFocusManagerTest,
GetState(&media_session_1)); GetState(&media_session_1));
} }
TEST_P(AudioFocusManagerTest, SourceName_AssociatedWithBinding) {
SetSourceName(kExampleSourceName);
mojom::AudioFocusManagerPtr new_ptr = CreateAudioFocusManagerPtr();
new_ptr->SetSourceName(kExampleSourceName2);
new_ptr.FlushForTesting();
MockMediaSession media_session;
RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest());
}
TEST_P(AudioFocusManagerTest, SourceName_Empty) {
MockMediaSession media_session;
RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
EXPECT_TRUE(GetSourceNameForLastRequest().empty());
}
TEST_P(AudioFocusManagerTest, SourceName_Updated) {
SetSourceName(kExampleSourceName);
MockMediaSession media_session;
RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest());
SetSourceName(kExampleSourceName2);
EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest());
}
} // namespace media_session } // namespace media_session
...@@ -6,7 +6,7 @@ module media_session.mojom; ...@@ -6,7 +6,7 @@ module media_session.mojom;
import "services/media_session/public/mojom/media_session.mojom"; import "services/media_session/public/mojom/media_session.mojom";
// Next MinVersion: 1 // Next MinVersion: 2
// These are the different types of audio focus that can be requested. // These are the different types of audio focus that can be requested.
[Extensible] [Extensible]
...@@ -32,6 +32,7 @@ struct AudioFocusRequestState { ...@@ -32,6 +32,7 @@ struct AudioFocusRequestState {
MediaSessionInfo session_info; MediaSessionInfo session_info;
AudioFocusType audio_focus_type; AudioFocusType audio_focus_type;
uint64 request_id; uint64 request_id;
[MinVersion=2] string? source_name;
}; };
// The observer for audio focus events. // The observer for audio focus events.
...@@ -62,7 +63,7 @@ interface AudioFocusRequestClient { ...@@ -62,7 +63,7 @@ interface AudioFocusRequestClient {
}; };
// Controls audio focus across the entire system. // Controls audio focus across the entire system.
// Next Method ID: 3 // Next Method ID: 4
interface AudioFocusManager { interface AudioFocusManager {
// Requests audio focus with |type| for the |media_session| with // Requests audio focus with |type| for the |media_session| with
// |session_info|. Media sessions should provide a |request| that will // |session_info|. Media sessions should provide a |request| that will
...@@ -79,6 +80,12 @@ interface AudioFocusManager { ...@@ -79,6 +80,12 @@ interface AudioFocusManager {
// Adds observers that receive audio focus events. // Adds observers that receive audio focus events.
AddObserver@2(AudioFocusObserver observer); AddObserver@2(AudioFocusObserver observer);
// Associates a name with this binding. This will be associated with all
// audio focus requests made with this binding. It will also be used for
// associating metrics to a source. If the source name is updated then
// the audio focus requests will retain the previous source name.
[MinVersion=2] SetSourceName@3(string name);
}; };
// Provides debug information about audio focus requests. // Provides debug information about audio focus requests.
......
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