зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
a9d4b33f07
Коммит
4e911221c2
|
@ -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',
|
||||
]
|
||||
|
|
Загрузка…
Ссылка в новой задаче