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