MediaPlaybackStatus.h (6123B)
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/. */ 4 5 #ifndef DOM_MEDIA_MEDIACONTROL_MEDIAPLAYBACKSTATUS_H_ 6 #define DOM_MEDIA_MEDIACONTROL_MEDIAPLAYBACKSTATUS_H_ 7 8 #include "mozilla/DefineEnum.h" 9 #include "mozilla/Maybe.h" 10 #include "mozilla/dom/MediaSession.h" 11 #include "nsID.h" 12 #include "nsISupportsImpl.h" 13 #include "nsTArray.h" 14 #include "nsTHashMap.h" 15 16 namespace mozilla::dom { 17 18 /** 19 * This enum is used to update controlled media state to the media controller in 20 * the chrome process. 21 * `eStarted`: media has successfully registered to the content media controller 22 * `ePlayed` : media has started playing 23 * `ePaused` : media has paused playing, but still can be resumed by content 24 * media controller 25 * `eStopped`: media has unregistered from the content media controller, we can 26 * not control it anymore 27 */ 28 MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AND_TOSTRING(MediaPlaybackState, uint32_t, 29 (eStarted, ePlayed, ePaused, 30 eStopped)); 31 32 /** 33 * This enum is used to update controlled media audible audible state to the 34 * media controller in the chrome process. 35 */ 36 MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AND_TOSTRING(MediaAudibleState, bool, 37 (eInaudible, eAudible)); 38 39 /** 40 * MediaPlaybackStatus is an internal module for the media controller, it 41 * represents a tab's media related status, such like "does the tab contain any 42 * controlled media? is the tab playing? is the tab audible?". 43 * 44 * The reason we need this class is that we would like to encapsulate the 45 * details of determining the tab's media status. A tab can contains multiple 46 * browsing contexts, and each browsing context can have different media status. 47 * The final media status would be decided by checking all those context status. 48 * 49 * Use `UpdateMediaXXXState()` to update controlled media status, and use 50 * `IsXXX()` methods to acquire the playback status of the tab. 51 * 52 * As we know each context's audible state, we can decide which context should 53 * owns the audio focus when multiple contexts are all playing audible media at 54 * the same time. In that cases, the latest context that plays media would own 55 * the audio focus. When the context owning the audio focus is destroyed, we 56 * would see if there is another other context still playing audible media, and 57 * switch the audio focus to another context. 58 */ 59 class MediaPlaybackStatus final { 60 public: 61 void UpdateMediaPlaybackState(uint64_t aContextId, MediaPlaybackState aState); 62 void UpdateMediaAudibleState(uint64_t aContextId, MediaAudibleState aState); 63 void UpdateGuessedPositionState(uint64_t aContextId, const nsID& aElementId, 64 const Maybe<PositionState>& aState); 65 66 bool IsPlaying() const; 67 bool IsAudible() const; 68 bool IsAnyMediaBeingControlled() const; 69 Maybe<PositionState> GuessedMediaPositionState( 70 Maybe<uint64_t> aPreferredContextId) const; 71 72 Maybe<uint64_t> GetAudioFocusOwnerContextId() const; 73 74 private: 75 /** 76 * This internal class stores detailed media status of controlled media for 77 * a browsing context. 78 */ 79 class ContextMediaInfo final { 80 public: 81 explicit ContextMediaInfo(uint64_t aContextId) : mContextId(aContextId) {} 82 ~ContextMediaInfo() = default; 83 84 void IncreaseControlledMediaNum() { 85 #ifndef FUZZING_SNAPSHOT 86 MOZ_DIAGNOSTIC_ASSERT(mControlledMediaNum < UINT_MAX); 87 #endif 88 mControlledMediaNum++; 89 } 90 void DecreaseControlledMediaNum() { 91 #ifndef FUZZING_SNAPSHOT 92 MOZ_DIAGNOSTIC_ASSERT(mControlledMediaNum > 0); 93 #endif 94 mControlledMediaNum--; 95 } 96 void IncreasePlayingMediaNum() { 97 #ifndef FUZZING_SNAPSHOT 98 MOZ_DIAGNOSTIC_ASSERT(mPlayingMediaNum < mControlledMediaNum); 99 #endif 100 mPlayingMediaNum++; 101 } 102 void DecreasePlayingMediaNum() { 103 #ifndef FUZZING_SNAPSHOT 104 MOZ_DIAGNOSTIC_ASSERT(mPlayingMediaNum > 0); 105 #endif 106 mPlayingMediaNum--; 107 } 108 void IncreaseAudibleMediaNum() { 109 #ifndef FUZZING_SNAPSHOT 110 MOZ_DIAGNOSTIC_ASSERT(mAudibleMediaNum < mPlayingMediaNum); 111 #endif 112 mAudibleMediaNum++; 113 } 114 void DecreaseAudibleMediaNum() { 115 #ifndef FUZZING_SNAPSHOT 116 MOZ_DIAGNOSTIC_ASSERT(mAudibleMediaNum > 0); 117 #endif 118 mAudibleMediaNum--; 119 } 120 bool IsPlaying() const { return mPlayingMediaNum > 0; } 121 bool IsAudible() const { return mAudibleMediaNum > 0; } 122 bool IsAnyMediaBeingControlled() const { return mControlledMediaNum > 0; } 123 uint64_t Id() const { return mContextId; } 124 125 Maybe<PositionState> GuessedPositionState() const; 126 void UpdateGuessedPositionState(const nsID& aElementId, 127 const Maybe<PositionState>& aState); 128 129 private: 130 /** 131 * The possible value for those three numbers should follow this rule, 132 * mControlledMediaNum >= mPlayingMediaNum >= mAudibleMediaNum 133 */ 134 uint32_t mControlledMediaNum = 0; 135 uint32_t mAudibleMediaNum = 0; 136 uint32_t mPlayingMediaNum = 0; 137 uint64_t mContextId = 0; 138 139 /** 140 * Contains the guessed position state of all media elements in this 141 * browsing context identified by their ID. 142 */ 143 nsTHashMap<nsID, PositionState> mGuessedPositionStateMap; 144 }; 145 146 ContextMediaInfo& GetNotNullContextInfo(uint64_t aContextId); 147 void DestroyContextInfo(uint64_t aContextId); 148 149 void ChooseNewContextToOwnAudioFocus(); 150 void SetOwningAudioFocusContextId(Maybe<uint64_t>&& aContextId); 151 bool IsContextOwningAudioFocus(uint64_t aContextId) const; 152 bool ShouldRequestAudioFocusForInfo(const ContextMediaInfo& aInfo) const; 153 bool ShouldAbandonAudioFocusForInfo(const ContextMediaInfo& aInfo) const; 154 155 // This contains all the media status of browsing contexts within a tab. 156 nsTHashMap<uint64_t, UniquePtr<ContextMediaInfo>> mContextInfoMap; 157 Maybe<uint64_t> mOwningAudioFocusContextId; 158 }; 159 160 } // namespace mozilla::dom 161 162 #endif // DOM_MEDIA_MEDIACONTROL_MEDIAPLAYBACKSTATUS_H_