Bug 1572460 - Refactor `selection` out of the `InspectorFront`. r=yulia
[gecko.git] / dom / media / ChannelMediaResource.h
bloba9e07e80691caa0286d043291a2b6baa6dd0f13b
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 "nsIHttpChannel.h"
14 #include "nsIInterfaceRequestor.h"
15 #include "nsIThreadRetargetableStreamListener.h"
17 namespace mozilla {
19 /**
20 * This class is responsible for managing the suspend count and report suspend
21 * status of channel.
22 **/
23 class ChannelSuspendAgent {
24 public:
25 explicit ChannelSuspendAgent(MediaCacheStream& aCacheStream)
26 : mCacheStream(aCacheStream) {}
28 // True when the channel has been suspended or needs to be suspended.
29 bool IsSuspended();
31 // Return true when the channel is logically suspended, i.e. the suspend
32 // count goes from 0 to 1.
33 bool Suspend();
35 // Return true only when the suspend count is equal to zero.
36 bool Resume();
38 // Tell the agent to manage the suspend status of the channel.
39 void Delegate(nsIChannel* aChannel);
40 // Stop the management of the suspend status of the channel.
41 void Revoke();
43 private:
44 // Only suspends channel but not changes the suspend count.
45 void SuspendInternal();
47 nsIChannel* mChannel = nullptr;
48 MediaCacheStream& mCacheStream;
49 uint32_t mSuspendCount = 0;
50 bool mIsChannelSuspended = false;
53 DDLoggedTypeDeclNameAndBase(ChannelMediaResource, BaseMediaResource);
55 /**
56 * This is the MediaResource implementation that wraps Necko channels.
57 * Much of its functionality is actually delegated to MediaCache via
58 * an underlying MediaCacheStream.
60 * All synchronization is performed by MediaCacheStream; all off-main-
61 * thread operations are delegated directly to that object.
63 class ChannelMediaResource
64 : public BaseMediaResource,
65 public DecoderDoctorLifeLogger<ChannelMediaResource> {
66 // Store information shared among resources. Main thread only.
67 struct SharedInfo {
68 NS_INLINE_DECL_REFCOUNTING(SharedInfo);
70 SharedInfo() : mHadCrossOriginRedirects(false) {}
72 nsCOMPtr<nsIPrincipal> mPrincipal;
73 nsTArray<ChannelMediaResource*> mResources;
74 bool mHadCrossOriginRedirects;
76 private:
77 ~SharedInfo() = default;
79 RefPtr<SharedInfo> mSharedInfo;
81 public:
82 ChannelMediaResource(MediaResourceCallback* aDecoder, nsIChannel* aChannel,
83 nsIURI* aURI, int64_t aStreamLength,
84 bool aIsPrivateBrowsing = false);
85 ~ChannelMediaResource();
87 // These are called on the main thread by MediaCache. These must
88 // not block or grab locks, because the media cache is holding its lock.
89 // Notify that data is available from the cache. This can happen even
90 // if this stream didn't read any data, since another stream might have
91 // received data for the same resource.
92 void CacheClientNotifyDataReceived();
93 // Notify that we reached the end of the stream. 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 CacheClientNotifyDataEnded(nsresult aStatus);
97 // Notify that the principal for the cached resource changed.
98 void CacheClientNotifyPrincipalChanged();
99 // Notify the decoder that the cache suspended status changed.
100 void CacheClientNotifySuspendedStatusChanged(bool aSuspended);
102 // These are called on the main thread by MediaCache. These shouldn't block,
103 // but they may grab locks --- the media cache is not holding its lock
104 // when these are called.
105 // Start a new load at the given aOffset. The old load is cancelled
106 // and no more data from the old load will be notified via
107 // MediaCacheStream::NotifyDataReceived/Ended.
108 void CacheClientSeek(int64_t aOffset, bool aResume);
109 // Suspend the current load since data is currently not wanted
110 void CacheClientSuspend();
111 // Resume the current load since data is wanted again
112 void CacheClientResume();
114 bool IsSuspended();
116 void ThrottleReadahead(bool bThrottle) override;
118 // Main thread
119 nsresult Open(nsIStreamListener** aStreamListener) override;
120 nsresult Close() override;
121 void Suspend(bool aCloseImmediately) override;
122 void Resume() override;
123 already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
124 bool HadCrossOriginRedirects() override;
125 bool CanClone() override;
126 already_AddRefed<BaseMediaResource> CloneData(
127 MediaResourceCallback* aDecoder) override;
128 nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
129 uint32_t aCount) override;
131 // Other thread
132 void SetReadMode(MediaCacheStream::ReadMode aMode) override;
133 void SetPlaybackRate(uint32_t aBytesPerSecond) override;
134 nsresult ReadAt(int64_t offset, char* aBuffer, uint32_t aCount,
135 uint32_t* aBytes) override;
136 // Data stored in IO&lock-encumbered MediaCacheStream, caching recommended.
137 bool ShouldCacheReads() override { return true; }
139 // Any thread
140 void Pin() override;
141 void Unpin() override;
142 double GetDownloadRate(bool* aIsReliable) override;
143 int64_t GetLength() override;
144 int64_t GetNextCachedData(int64_t aOffset) override;
145 int64_t GetCachedDataEnd(int64_t aOffset) override;
146 bool IsDataCachedToEndOfResource(int64_t aOffset) override;
147 bool IsTransportSeekable() override;
148 bool IsLiveStream() const override { return mIsLiveStream; }
150 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
151 // Might be useful to track in the future:
152 // - mListener (seems minor)
153 size_t size = BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf);
154 size += mCacheStream.SizeOfExcludingThis(aMallocSizeOf);
156 return size;
159 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
160 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
163 void GetDebugInfo(dom::MediaResourceDebugInfo& aInfo) override;
165 class Listener final : public nsIStreamListener,
166 public nsIInterfaceRequestor,
167 public nsIChannelEventSink,
168 public nsIThreadRetargetableStreamListener {
169 ~Listener() {}
171 public:
172 Listener(ChannelMediaResource* aResource, int64_t aOffset, uint32_t aLoadID)
173 : mMutex("Listener.mMutex"),
174 mResource(aResource),
175 mOffset(aOffset),
176 mLoadID(aLoadID) {}
178 NS_DECL_THREADSAFE_ISUPPORTS
179 NS_DECL_NSIREQUESTOBSERVER
180 NS_DECL_NSISTREAMLISTENER
181 NS_DECL_NSICHANNELEVENTSINK
182 NS_DECL_NSIINTERFACEREQUESTOR
183 NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
185 void Revoke();
187 private:
188 Mutex mMutex;
189 // mResource should only be modified on the main thread with the lock.
190 // So it can be read without lock on the main thread or on other threads
191 // with the lock.
192 RefPtr<ChannelMediaResource> mResource;
194 const int64_t mOffset;
195 const uint32_t mLoadID;
197 friend class Listener;
199 nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
201 protected:
202 nsresult Seek(int64_t aOffset, bool aResume);
204 // These are called on the main thread by Listener.
205 nsresult OnStartRequest(nsIRequest* aRequest, int64_t aRequestOffset);
206 nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
207 nsresult OnDataAvailable(uint32_t aLoadID, nsIInputStream* aStream,
208 uint32_t aCount);
209 nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew,
210 uint32_t aFlags, int64_t aOffset);
212 // Opens the channel, using an HTTP byte range request to start at aOffset
213 // if possible. Main thread only.
214 nsresult OpenChannel(int64_t aOffset);
215 nsresult RecreateChannel();
216 // Add headers to HTTP request. Main thread only.
217 nsresult SetupChannelHeaders(int64_t aOffset);
218 // Closes the channel. Main thread only.
219 void CloseChannel();
220 // Update the principal for the resource. Main thread only.
221 void UpdatePrincipal();
223 // Parses 'Content-Range' header and returns results via parameters.
224 // Returns error if header is not available, values are not parse-able or
225 // values are out of range.
226 nsresult ParseContentRangeHeader(nsIHttpChannel* aHttpChan,
227 int64_t& aRangeStart, int64_t& aRangeEnd,
228 int64_t& aRangeTotal) const;
230 // Calculates the length of the resource using HTTP headers, if this
231 // is an HTTP channel. Returns -1 on failure, or for non HTTP channels.
232 int64_t CalculateStreamLength() const;
234 struct Closure {
235 uint32_t mLoadID;
236 ChannelMediaResource* mResource;
239 static nsresult CopySegmentToCache(nsIInputStream* aInStream, void* aClosure,
240 const char* aFromSegment,
241 uint32_t aToOffset, uint32_t aCount,
242 uint32_t* aWriteCount);
244 // Main thread access only
245 // True if Close() has been called.
246 bool mClosed = false;
247 // The last reported seekability state for the underlying channel
248 bool mIsTransportSeekable = false;
249 // Length of the content first reported.
250 int64_t mFirstReadLength = -1;
251 RefPtr<Listener> mListener;
252 // A mono-increasing integer to uniquely identify the channel we are loading.
253 uint32_t mLoadID = 0;
254 bool mIsLiveStream = false;
256 // Any thread access
257 MediaCacheStream mCacheStream;
259 ChannelSuspendAgent mSuspendAgent;
261 // The size of the stream if known at construction time (such as with blob)
262 const int64_t mKnownStreamLength;
265 } // namespace mozilla
267 #endif // mozilla_dom_media_ChannelMediaResource_h