Bug 1565689 - part2 : implement AudioFocusManager. r=baku

In order to support audio competing among different tabs, we implement a new class AudioFocusManager.

AudioFocusManager is used to assign the audio focus to different requester and decide which requester can own audio focus when audio competing happens.
When the audio competing happens, the last request would be a winner who can still own the audio focus, and all the other requesters would lose the audio focus.
Now MediaController is the onlt requester, it would request the audio focus when it becomes audible and revoke the audio focus when the controller is no longer active.

Differential Revision: https://phabricator.services.mozilla.com/D38142

--HG--
extra : moz-landing-system : lando
This commit is contained in:
alwu 2019-08-07 01:46:08 +00:00
Родитель a9d4b33f07
Коммит 4e911221c2
6 изменённых файлов: 139 добавлений и 4 удалений

Просмотреть файл

@ -0,0 +1,67 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioFocusManager.h"
#include "MediaControlService.h"
#include "mozilla/Logging.h"
extern mozilla::LazyLogModule gMediaControlLog;
#undef LOG
#define LOG(msg, ...) \
MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
("AudioFocusManager=%p, " msg, this, ##__VA_ARGS__))
namespace mozilla {
namespace dom {
AudioFocusManager::AudioFocusManager(MediaControlService* aService)
: mService(aService) {}
void AudioFocusManager::RequestAudioFocus(uint64_t aId) {
if (mOwningFocusControllers.Contains(aId)) {
return;
}
LOG("Controller %" PRId64 " grants audio focus", aId);
mOwningFocusControllers.AppendElement(aId);
HandleAudioCompetition(aId);
}
void AudioFocusManager::RevokeAudioFocus(uint64_t aId) {
if (!mOwningFocusControllers.Contains(aId)) {
return;
}
LOG("Controller %" PRId64 " loses audio focus", aId);
mOwningFocusControllers.RemoveElement(aId);
}
void AudioFocusManager::HandleAudioCompetition(uint64_t aId) {
for (size_t idx = 0; idx < mOwningFocusControllers.Length(); idx++) {
const uint64_t controllerId = mOwningFocusControllers[idx];
if (controllerId != aId) {
LOG("Controller %" PRId64 " loses audio focus in audio competitition",
controllerId);
RefPtr<MediaController> controller =
mService->GetControllerById(controllerId);
MOZ_ASSERT(controller);
controller->Stop();
}
}
mOwningFocusControllers.Clear();
mOwningFocusControllers.AppendElement(aId);
}
uint32_t AudioFocusManager::GetAudioFocusNums() const {
return mOwningFocusControllers.Length();
}
void AudioFocusManager::Shutdown() { mService = nullptr; }
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,47 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_audiofocusmanager_h__
#define mozilla_dom_audiofocusmanager_h__
#include "base/basictypes.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class MediaControlService;
/**
* AudioFocusManager is used to assign the audio focus to different requester
* and decide which requester can own audio focus when audio competing happens.
* When the audio competing happens, the last request would be a winner who can
* still own the audio focus, and all the other requesters would lose the audio
* focus. Now MediaController is the onlt requester, it would request the audio
* focus when it becomes audible and revoke the audio focus when the controller
* is no longer active.
*/
class AudioFocusManager {
public:
void RequestAudioFocus(uint64_t aId);
void RevokeAudioFocus(uint64_t aId);
explicit AudioFocusManager(MediaControlService* aService);
~AudioFocusManager() = default;
uint32_t GetAudioFocusNums() const;
private:
friend class MediaControlService;
void Shutdown();
void HandleAudioCompetition(uint64_t aId);
RefPtr<MediaControlService> mService;
nsTArray<uint64_t> mOwningFocusControllers;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_audiofocusmanager_h__

Просмотреть файл

@ -48,7 +48,7 @@ NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(MediaControlService)
NS_IMPL_RELEASE(MediaControlService)
MediaControlService::MediaControlService() {
MediaControlService::MediaControlService() : mAudioFocusManager(this) {
LOG("create media control service");
RefPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
@ -58,7 +58,7 @@ MediaControlService::MediaControlService() {
MediaControlService::~MediaControlService() {
LOG("destroy media control service");
ShutdownAllControllers();
Shutdown();
}
NS_IMETHODIMP
@ -71,14 +71,19 @@ MediaControlService::Observe(nsISupports* aSubject, const char* aTopic,
if (obs) {
obs->RemoveObserver(this, "xpcom-shutdown");
}
ShutdownAllControllers();
mControllers.Clear();
Shutdown();
sIsXPCOMShutdown = true;
gMediaControlService = nullptr;
}
return NS_OK;
}
void MediaControlService::Shutdown() {
ShutdownAllControllers();
mControllers.Clear();
mAudioFocusManager.Shutdown();
}
RefPtr<MediaController> MediaControlService::GetOrCreateControllerById(
const uint64_t aId) const {
RefPtr<MediaController> controller = mControllers.Get(aId);

Просмотреть файл

@ -7,6 +7,7 @@
#include "mozilla/AlreadyAddRefed.h"
#include "AudioFocusManager.h"
#include "MediaController.h"
#include "nsDataHashtable.h"
#include "nsIObserver.h"
@ -35,6 +36,7 @@ class MediaControlService final : public nsIObserver {
RefPtr<MediaController> GetOrCreateControllerById(const uint64_t aId) const;
RefPtr<MediaController> GetControllerById(const uint64_t aId) const;
AudioFocusManager& GetAudioFocusManager() { return mAudioFocusManager; }
void AddMediaController(const RefPtr<MediaController>& aController);
void RemoveMediaController(const RefPtr<MediaController>& aController);
@ -44,12 +46,15 @@ class MediaControlService final : public nsIObserver {
MediaControlService();
~MediaControlService();
void Shutdown();
void PlayAllControllers() const;
void PauseAllControllers() const;
void StopAllControllers() const;
void ShutdownAllControllers() const;
nsDataHashtable<nsUint64HashKey, RefPtr<MediaController>> mControllers;
AudioFocusManager mAudioFocusManager;
};
} // namespace dom

Просмотреть файл

@ -55,6 +55,9 @@ void TabMediaController::Stop() {
void TabMediaController::Shutdown() {
mIsPlaying = false;
mControlledMediaNum = 0;
RefPtr<MediaControlService> service = MediaControlService::GetService();
MOZ_ASSERT(service);
service->GetAudioFocusManager().RevokeAudioFocus(Id());
}
bool TabMediaController::IsAudible() const { return mIsPlaying && mAudible; }
@ -69,6 +72,11 @@ void TabMediaController::NotifyMediaActiveChanged(bool aActive) {
void TabMediaController::NotifyMediaAudibleChanged(bool aAudible) {
mAudible = aAudible;
if (mAudible) {
RefPtr<MediaControlService> service = MediaControlService::GetService();
MOZ_ASSERT(service);
service->GetAudioFocusManager().RequestAudioFocus(Id());
}
}
void TabMediaController::IncreaseControlledMediaNum() {
@ -102,6 +110,7 @@ void TabMediaController::Deactivate() {
RefPtr<MediaControlService> service = MediaControlService::GetService();
MOZ_ASSERT(service);
service->RemoveMediaController(this);
service->GetAudioFocusManager().RevokeAudioFocus(Id());
}
uint64_t TabMediaController::ControlledMediaNum() const {

Просмотреть файл

@ -4,12 +4,14 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'AudioFocusManager.h',
'MediaController.h',
'MediaControlService.h',
'MediaControlUtils.h',
]
UNIFIED_SOURCES += [
'AudioFocusManager.cpp',
'MediaController.cpp',
'MediaControlService.cpp',
]