Bug 1824856 - migrate android build-bundle tasks from firefox-android. r=bhearsum...
[gecko.git] / dom / media / ChannelMediaResource.h
blob73494b465300c41d190ff38769a11a8db5853e0b
1 /* vim:set ts=2 sw=2 sts=2 et cindent: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_dom_media_ChannelMediaResource_h
7 #define mozilla_dom_media_ChannelMediaResource_h
9 #include "BaseMediaResource.h"
10 #include "MediaCache.h"
11 #include "mozilla/Mutex.h"
12 #include "nsIChannelEventSink.h"
13 #include "nsIInterfaceRequestor.h"
14 #include "nsIThreadRetargetableStreamListener.h"
16 class nsIHttpChannel;
18 namespace mozilla {
20 /**
21 * This class is responsible for managing the suspend count and report suspend
22 * status of channel.
23 **/
24 class ChannelSuspendAgent {
25 public:
26 explicit ChannelSuspendAgent(MediaCacheStream& aCacheStream)
27 : mCacheStream(aCacheStream) {}
29 // True when the channel has been suspended or needs to be suspended.
30 bool IsSuspended();
32 // Return true when the channel is logically suspended, i.e. the suspend
33 // count goes from 0 to 1.
34 bool Suspend();
36 // Return true only when the suspend count is equal to zero.
37 bool Resume();
39 // Tell the agent to manage the suspend status of the channel.
40 void Delegate(nsIChannel* aChannel);
41 // Stop the management of the suspend status of the channel.
42 void Revoke();
44 private:
45 // Only suspends channel but not changes the suspend count.
46 void SuspendInternal();
48 nsIChannel* mChannel = nullptr;
49 MediaCacheStream& mCacheStream;
50 uint32_t mSuspendCount = 0;
51 bool mIsChannelSuspended = false;
54 DDLoggedTypeDeclNameAndBase(ChannelMediaResource, BaseMediaResource);
56 /**
57 * This is the MediaResource implementation that wraps Necko channels.
58 * Much of its functionality is actually delegated to MediaCache via
59 * an underlying MediaCacheStream.
61 * All synchronization is performed by MediaCacheStream; all off-main-
62 * thread operations are delegated directly to that object.
64 class ChannelMediaResource
65 : public BaseMediaResource,
66 public DecoderDoctorLifeLogger<ChannelMediaResource> {
67 // Store information shared among resources. Main thread only.
68 struct SharedInfo {
69 NS_INLINE_DECL_REFCOUNTING(SharedInfo);
71 nsTArray<ChannelMediaResource*> mResources;
72 // Null if there is not yet any data from any origin.
73 nsCOMPtr<nsIPrincipal> mPrincipal;
74 // Meaningful only when mPrincipal is non-null,
75 // unaffected by intermediate cross-origin redirects.
76 bool mFinalResponsesAreOpaque = false;
78 bool mHadCrossOriginRedirects = false;
80 private:
81 ~SharedInfo() = default;
83 RefPtr<SharedInfo> mSharedInfo;
85 public:
86 ChannelMediaResource(MediaResourceCallback* aDecoder, nsIChannel* aChannel,
87 nsIURI* aURI, int64_t aStreamLength,
88 bool aIsPrivateBrowsing = false);
89 ~ChannelMediaResource();
91 // These are called on the main thread by MediaCache. These must
92 // not block or grab locks, because the media cache is holding its lock.
93 // Notify that data is available from the cache. This can happen even
94 // if this stream didn't read any data, since another stream might have
95 // received data for the same resource.
96 void CacheClientNotifyDataReceived();
97 // Notify that we reached the end of the stream. This can happen even
98 // if this stream didn't read any data, since another stream might have
99 // received data for the same resource.
100 void CacheClientNotifyDataEnded(nsresult aStatus);
101 // Notify that the principal for the cached resource changed.
102 void CacheClientNotifyPrincipalChanged();
103 // Notify the decoder that the cache suspended status changed.
104 void CacheClientNotifySuspendedStatusChanged(bool aSuspended);
106 // These are called on the main thread by MediaCache. These shouldn't block,
107 // but they may grab locks --- the media cache is not holding its lock
108 // when these are called.
109 // Start a new load at the given aOffset. The old load is cancelled
110 // and no more data from the old load will be notified via
111 // MediaCacheStream::NotifyDataReceived/Ended.
112 void CacheClientSeek(int64_t aOffset, bool aResume);
113 // Suspend the current load since data is currently not wanted
114 void CacheClientSuspend();
115 // Resume the current load since data is wanted again
116 void CacheClientResume();
118 bool IsSuspended();
120 void ThrottleReadahead(bool bThrottle) override;
122 // Main thread
123 nsresult Open(nsIStreamListener** aStreamListener) override;
124 RefPtr<GenericPromise> Close() override;
125 void Suspend(bool aCloseImmediately) override;
126 void Resume() override;
127 already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
128 bool HadCrossOriginRedirects() override;
129 bool CanClone() override;
130 already_AddRefed<BaseMediaResource> CloneData(
131 MediaResourceCallback* aDecoder) override;
132 nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
133 uint32_t aCount) override;
135 // Other thread
136 void SetReadMode(MediaCacheStream::ReadMode aMode) override;
137 void SetPlaybackRate(uint32_t aBytesPerSecond) override;
138 nsresult ReadAt(int64_t offset, char* aBuffer, uint32_t aCount,
139 uint32_t* aBytes) override;
140 // Data stored in IO&lock-encumbered MediaCacheStream, caching recommended.
141 bool ShouldCacheReads() override { return true; }
143 // Any thread
144 void Pin() override;
145 void Unpin() override;
146 double GetDownloadRate(bool* aIsReliable) override;
147 int64_t GetLength() override;
148 int64_t GetNextCachedData(int64_t aOffset) override;
149 int64_t GetCachedDataEnd(int64_t aOffset) override;
150 bool IsDataCachedToEndOfResource(int64_t aOffset) override;
151 bool IsTransportSeekable() override;
152 bool IsLiveStream() const override { return mIsLiveStream; }
154 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
155 // Might be useful to track in the future:
156 // - mListener (seems minor)
157 size_t size = BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf);
158 size += mCacheStream.SizeOfExcludingThis(aMallocSizeOf);
160 return size;
163 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
164 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
167 void GetDebugInfo(dom::MediaResourceDebugInfo& aInfo) override;
169 class Listener final : public nsIInterfaceRequestor,
170 public nsIChannelEventSink,
171 public nsIThreadRetargetableStreamListener,
172 public SingleWriterLockOwner {
173 ~Listener() = default;
175 public:
176 Listener(ChannelMediaResource* aResource, int64_t aOffset, uint32_t aLoadID)
177 : mMutex("Listener.mMutex", this),
178 mResource(aResource),
179 mOffset(aOffset),
180 mLoadID(aLoadID) {}
182 NS_DECL_THREADSAFE_ISUPPORTS
183 NS_DECL_NSIREQUESTOBSERVER
184 NS_DECL_NSISTREAMLISTENER
185 NS_DECL_NSICHANNELEVENTSINK
186 NS_DECL_NSIINTERFACEREQUESTOR
187 NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
189 void Revoke();
191 bool OnWritingThread() const override { return NS_IsMainThread(); }
193 private:
194 MutexSingleWriter mMutex;
195 // mResource should only be modified on the main thread with the lock.
196 // So it can be read without lock on the main thread or on other threads
197 // with the lock.
198 RefPtr<ChannelMediaResource> mResource MOZ_GUARDED_BY(mMutex);
200 const int64_t mOffset;
201 const uint32_t mLoadID;
203 friend class Listener;
205 nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
207 protected:
208 nsresult Seek(int64_t aOffset, bool aResume);
210 // These are called on the main thread by Listener.
211 nsresult OnStartRequest(nsIRequest* aRequest, int64_t aRequestOffset);
212 nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
213 nsresult OnDataAvailable(uint32_t aLoadID, nsIInputStream* aStream,
214 uint32_t aCount);
215 nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew,
216 uint32_t aFlags, int64_t aOffset);
218 // Use only before MediaDecoder shutdown. Main thread only.
219 dom::HTMLMediaElement* MediaElement() const;
220 // Opens the channel, using an HTTP byte range request to start at aOffset
221 // if possible. Main thread only.
222 nsresult OpenChannel(int64_t aOffset);
223 nsresult RecreateChannel();
224 // Add headers to HTTP request. Main thread only.
225 nsresult SetupChannelHeaders(int64_t aOffset);
226 // Closes the channel. Main thread only.
227 void CloseChannel();
228 // Update the principal for the resource. Main thread only.
229 void UpdatePrincipal();
231 // Parses 'Content-Range' header and returns results via parameters.
232 // Returns error if header is not available, values are not parse-able or
233 // values are out of range.
234 nsresult ParseContentRangeHeader(nsIHttpChannel* aHttpChan,
235 int64_t& aRangeStart, int64_t& aRangeEnd,
236 int64_t& aRangeTotal) const;
238 // Calculates the length of the resource using HTTP headers, if this
239 // is an HTTP channel. Returns -1 on failure, or for non HTTP channels.
240 int64_t CalculateStreamLength() const;
242 struct Closure {
243 uint32_t mLoadID;
244 ChannelMediaResource* mResource;
247 static nsresult CopySegmentToCache(nsIInputStream* aInStream, void* aClosure,
248 const char* aFromSegment,
249 uint32_t aToOffset, uint32_t aCount,
250 uint32_t* aWriteCount);
252 // Main thread access only
253 // True if Close() has been called.
254 bool mClosed = false;
255 // The last reported seekability state for the underlying channel
256 bool mIsTransportSeekable = false;
257 // Length of the content first reported.
258 int64_t mFirstReadLength = -1;
259 RefPtr<Listener> mListener;
260 // A mono-increasing integer to uniquely identify the channel we are loading.
261 uint32_t mLoadID = 0;
262 bool mIsLiveStream = false;
264 // Any thread access
265 MediaCacheStream mCacheStream;
267 ChannelSuspendAgent mSuspendAgent;
269 // The size of the stream if known at construction time (such as with blob)
270 const int64_t mKnownStreamLength;
273 } // namespace mozilla
275 #endif // mozilla_dom_media_ChannelMediaResource_h