зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1627999 - part1 : manage the audio focus in `MediaPlaybackStatus` r=bryce
This patch will do : - introduce a concept `audio focus` among different contexts within a tab - determine the audio focus owner when the context becomes audible or the owner destroys The advantage of doing so : - the audio focus helps us to decide the active media session that would be implemented in the following part More details: When there are serveral contexts playing at the same time within a tab, we would like to determine an audible context from them to represent the tab, and that is the `audio focus` we mean in this bug. Differential Revision: https://phabricator.services.mozilla.com/D72495
This commit is contained in:
Родитель
bba064955e
Коммит
36c9f9f54a
|
@ -46,6 +46,11 @@ void MediaPlaybackStatus::DestroyContextInfo(uint64_t aContextId) {
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
LOG("Remove context %" PRIu64, aContextId);
|
||||
mContextInfoMap.Remove(aContextId);
|
||||
// If the removed context is owning the audio focus, we would find another
|
||||
// context to take the audio focus if it's possible.
|
||||
if (IsContextOwningAudioFocus(aContextId)) {
|
||||
ChooseNewContextToOwnAudioFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlaybackStatus::UpdateMediaAudibleState(uint64_t aContextId,
|
||||
|
@ -60,6 +65,11 @@ void MediaPlaybackStatus::UpdateMediaAudibleState(uint64_t aContextId,
|
|||
MOZ_ASSERT(aState == MediaAudibleState::eInaudible);
|
||||
info.DecreaseAudibleMediaNum();
|
||||
}
|
||||
if (ShouldRequestAudioFocusForInfo(info)) {
|
||||
SetOwningAudioFocusContextId(Some(aContextId));
|
||||
} else if (ShouldAbandonAudioFocusForInfo(info)) {
|
||||
ChooseNewContextToOwnAudioFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaPlaybackStatus::IsPlaying() const {
|
||||
|
@ -101,5 +111,46 @@ MediaPlaybackStatus::GetNotNullContextInfo(uint64_t aContextId) {
|
|||
return *(mContextInfoMap.GetValue(aContextId)->get());
|
||||
}
|
||||
|
||||
Maybe<uint64_t> MediaPlaybackStatus::GetAudioFocusOwnerContextId() const {
|
||||
return mOwningAudioFocusContextId;
|
||||
}
|
||||
|
||||
void MediaPlaybackStatus::ChooseNewContextToOwnAudioFocus() {
|
||||
for (auto iter = mContextInfoMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.Data()->IsAudible()) {
|
||||
SetOwningAudioFocusContextId(Some(iter.Data()->Id()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No context is audible, so no one should the own audio focus.
|
||||
SetOwningAudioFocusContextId(Nothing());
|
||||
}
|
||||
|
||||
void MediaPlaybackStatus::SetOwningAudioFocusContextId(
|
||||
Maybe<uint64_t>&& aContextId) {
|
||||
if (mOwningAudioFocusContextId == aContextId) {
|
||||
return;
|
||||
}
|
||||
mOwningAudioFocusContextId = aContextId;
|
||||
}
|
||||
|
||||
bool MediaPlaybackStatus::ShouldRequestAudioFocusForInfo(
|
||||
const ContextMediaInfo& aInfo) const {
|
||||
return aInfo.IsAudible() && !IsContextOwningAudioFocus(aInfo.Id());
|
||||
}
|
||||
|
||||
bool MediaPlaybackStatus::ShouldAbandonAudioFocusForInfo(
|
||||
const ContextMediaInfo& aInfo) const {
|
||||
// The owner becomes inaudible and there is other context still playing, so we
|
||||
// should switch the audio focus to the audible context.
|
||||
return !aInfo.IsAudible() && IsContextOwningAudioFocus(aInfo.Id()) &&
|
||||
IsAudible();
|
||||
}
|
||||
|
||||
bool MediaPlaybackStatus::IsContextOwningAudioFocus(uint64_t aContextId) const {
|
||||
return mOwningAudioFocusContextId ? *mOwningAudioFocusContextId == aContextId
|
||||
: false;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -27,6 +27,13 @@ namespace dom {
|
|||
*
|
||||
* Use `UpdateMediaXXXState()` to update controlled media status, and use
|
||||
* `IsXXX()` methods to acquire the playback status of the tab.
|
||||
*
|
||||
* As we know each context's audible state, we can decide which context should
|
||||
* owns the audio focus when multiple contexts are all playing audible media at
|
||||
* the same time. In that cases, the latest context that plays media would own
|
||||
* the audio focus. When the context owning the audio focus is destroyed, we
|
||||
* would see if there is another other context still playing audible media, and
|
||||
* switch the audio focus to another context.
|
||||
*/
|
||||
class MediaPlaybackStatus final {
|
||||
public:
|
||||
|
@ -37,6 +44,8 @@ class MediaPlaybackStatus final {
|
|||
bool IsAudible() const;
|
||||
bool IsAnyMediaBeingControlled() const;
|
||||
|
||||
Maybe<uint64_t> GetAudioFocusOwnerContextId() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* This internal class stores detailed media status of controlled media for
|
||||
|
@ -90,8 +99,15 @@ class MediaPlaybackStatus final {
|
|||
ContextMediaInfo& GetNotNullContextInfo(uint64_t aContextId);
|
||||
void DestroyContextInfo(uint64_t aContextId);
|
||||
|
||||
void ChooseNewContextToOwnAudioFocus();
|
||||
void SetOwningAudioFocusContextId(Maybe<uint64_t>&& aContextId);
|
||||
bool IsContextOwningAudioFocus(uint64_t aContextId) const;
|
||||
bool ShouldRequestAudioFocusForInfo(const ContextMediaInfo& aInfo) const;
|
||||
bool ShouldAbandonAudioFocusForInfo(const ContextMediaInfo& aInfo) const;
|
||||
|
||||
// This contains all the media status of browsing contexts within a tab.
|
||||
nsDataHashtable<nsUint64HashKey, UniquePtr<ContextMediaInfo>> mContextInfoMap;
|
||||
Maybe<uint64_t> mOwningAudioFocusContextId;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
Загрузка…
Ссылка в новой задаче