Backed out 7 changesets (bug 1942424) for causing frequent crashes. a=backout
[gecko.git] / dom / media / mediacontrol / MediaPlaybackStatus.cpp
blob88091356dd288035b58ff2a5066c8f2aac2ac06e
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "MediaPlaybackStatus.h"
7 #include "MediaControlUtils.h"
9 namespace mozilla::dom {
11 #undef LOG
12 #define LOG(msg, ...) \
13 MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
14 ("MediaPlaybackStatus=%p, " msg, this, ##__VA_ARGS__))
16 void MediaPlaybackStatus::UpdateMediaPlaybackState(uint64_t aContextId,
17 MediaPlaybackState aState) {
18 LOG("Update playback state '%s' for context %" PRIu64,
19 EnumValueToString(aState), aContextId);
20 MOZ_ASSERT(NS_IsMainThread());
22 ContextMediaInfo& info = GetNotNullContextInfo(aContextId);
23 if (aState == MediaPlaybackState::eStarted) {
24 info.IncreaseControlledMediaNum();
25 } else if (aState == MediaPlaybackState::eStopped) {
26 info.DecreaseControlledMediaNum();
27 } else if (aState == MediaPlaybackState::ePlayed) {
28 info.IncreasePlayingMediaNum();
29 } else {
30 MOZ_ASSERT(aState == MediaPlaybackState::ePaused);
31 info.DecreasePlayingMediaNum();
34 // The context still has controlled media, we should keep its alive.
35 if (info.IsAnyMediaBeingControlled()) {
36 return;
38 MOZ_ASSERT(!info.IsPlaying());
39 MOZ_ASSERT(!info.IsAudible());
40 // DO NOT access `info` after this line.
41 DestroyContextInfo(aContextId);
44 void MediaPlaybackStatus::DestroyContextInfo(uint64_t aContextId) {
45 MOZ_ASSERT(NS_IsMainThread());
46 LOG("Remove context %" PRIu64, aContextId);
47 mContextInfoMap.Remove(aContextId);
48 // If the removed context is owning the audio focus, we would find another
49 // context to take the audio focus if it's possible.
50 if (IsContextOwningAudioFocus(aContextId)) {
51 ChooseNewContextToOwnAudioFocus();
55 void MediaPlaybackStatus::UpdateMediaAudibleState(uint64_t aContextId,
56 MediaAudibleState aState) {
57 LOG("Update audible state '%s' for context %" PRIu64,
58 EnumValueToString(aState), aContextId);
59 MOZ_ASSERT(NS_IsMainThread());
60 ContextMediaInfo& info = GetNotNullContextInfo(aContextId);
61 if (aState == MediaAudibleState::eAudible) {
62 info.IncreaseAudibleMediaNum();
63 } else {
64 MOZ_ASSERT(aState == MediaAudibleState::eInaudible);
65 info.DecreaseAudibleMediaNum();
67 if (ShouldRequestAudioFocusForInfo(info)) {
68 SetOwningAudioFocusContextId(Some(aContextId));
69 } else if (ShouldAbandonAudioFocusForInfo(info)) {
70 ChooseNewContextToOwnAudioFocus();
74 void MediaPlaybackStatus::UpdateGuessedPositionState(
75 uint64_t aContextId, const nsID& aElementId,
76 const Maybe<PositionState>& aState) {
77 MOZ_ASSERT(NS_IsMainThread());
78 if (aState) {
79 LOG("Update guessed position state for context %" PRIu64
80 " element %s (duration=%f, playbackRate=%f, position=%f)",
81 aContextId, aElementId.ToString().get(), aState->mDuration,
82 aState->mPlaybackRate, aState->mLastReportedPlaybackPosition);
83 } else {
84 LOG("Clear guessed position state for context %" PRIu64 " element %s",
85 aContextId, aElementId.ToString().get());
87 ContextMediaInfo& info = GetNotNullContextInfo(aContextId);
88 info.UpdateGuessedPositionState(aElementId, aState);
91 bool MediaPlaybackStatus::IsPlaying() const {
92 MOZ_ASSERT(NS_IsMainThread());
93 return std::any_of(mContextInfoMap.Values().cbegin(),
94 mContextInfoMap.Values().cend(),
95 [](const auto& info) { return info->IsPlaying(); });
98 bool MediaPlaybackStatus::IsAudible() const {
99 MOZ_ASSERT(NS_IsMainThread());
100 return std::any_of(mContextInfoMap.Values().cbegin(),
101 mContextInfoMap.Values().cend(),
102 [](const auto& info) { return info->IsAudible(); });
105 bool MediaPlaybackStatus::IsAnyMediaBeingControlled() const {
106 MOZ_ASSERT(NS_IsMainThread());
107 return std::any_of(
108 mContextInfoMap.Values().cbegin(), mContextInfoMap.Values().cend(),
109 [](const auto& info) { return info->IsAnyMediaBeingControlled(); });
112 Maybe<PositionState> MediaPlaybackStatus::GuessedMediaPositionState(
113 Maybe<uint64_t> aPreferredContextId) const {
114 auto contextId = aPreferredContextId;
115 if (!contextId) {
116 contextId = mOwningAudioFocusContextId;
119 // either the preferred or focused context
120 if (contextId) {
121 auto entry = mContextInfoMap.Lookup(*contextId);
122 if (!entry) {
123 return Nothing();
125 LOG("Using guessed position state from preferred/focused BC %" PRId64,
126 *contextId);
127 return entry.Data()->GuessedPositionState();
130 // look for the first position state
131 for (const auto& context : mContextInfoMap.Values()) {
132 auto state = context->GuessedPositionState();
133 if (state) {
134 LOG("Using guessed position state from BC %" PRId64, context->Id());
135 return state;
138 return Nothing();
141 MediaPlaybackStatus::ContextMediaInfo&
142 MediaPlaybackStatus::GetNotNullContextInfo(uint64_t aContextId) {
143 MOZ_ASSERT(NS_IsMainThread());
144 return *mContextInfoMap.GetOrInsertNew(aContextId, aContextId);
147 Maybe<uint64_t> MediaPlaybackStatus::GetAudioFocusOwnerContextId() const {
148 return mOwningAudioFocusContextId;
151 void MediaPlaybackStatus::ChooseNewContextToOwnAudioFocus() {
152 for (const auto& info : mContextInfoMap.Values()) {
153 if (info->IsAudible()) {
154 SetOwningAudioFocusContextId(Some(info->Id()));
155 return;
158 // No context is audible, so no one should the own audio focus.
159 SetOwningAudioFocusContextId(Nothing());
162 void MediaPlaybackStatus::SetOwningAudioFocusContextId(
163 Maybe<uint64_t>&& aContextId) {
164 if (mOwningAudioFocusContextId == aContextId) {
165 return;
167 mOwningAudioFocusContextId = aContextId;
170 bool MediaPlaybackStatus::ShouldRequestAudioFocusForInfo(
171 const ContextMediaInfo& aInfo) const {
172 return aInfo.IsAudible() && !IsContextOwningAudioFocus(aInfo.Id());
175 bool MediaPlaybackStatus::ShouldAbandonAudioFocusForInfo(
176 const ContextMediaInfo& aInfo) const {
177 // The owner becomes inaudible and there is other context still playing, so we
178 // should switch the audio focus to the audible context.
179 return !aInfo.IsAudible() && IsContextOwningAudioFocus(aInfo.Id()) &&
180 IsAudible();
183 bool MediaPlaybackStatus::IsContextOwningAudioFocus(uint64_t aContextId) const {
184 return mOwningAudioFocusContextId ? *mOwningAudioFocusContextId == aContextId
185 : false;
188 Maybe<PositionState>
189 MediaPlaybackStatus::ContextMediaInfo::GuessedPositionState() const {
190 if (mGuessedPositionStateMap.Count() != 1) {
191 LOG("Count is %d", mGuessedPositionStateMap.Count());
192 return Nothing();
194 return Some(mGuessedPositionStateMap.begin()->GetData());
197 void MediaPlaybackStatus::ContextMediaInfo::UpdateGuessedPositionState(
198 const nsID& aElementId, const Maybe<PositionState>& aState) {
199 if (aState) {
200 mGuessedPositionStateMap.InsertOrUpdate(aElementId, *aState);
201 } else {
202 mGuessedPositionStateMap.Remove(aElementId);
206 } // namespace mozilla::dom