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"
21 * This class is responsible for managing the suspend count and report suspend
24 class ChannelSuspendAgent
{
26 explicit ChannelSuspendAgent(MediaCacheStream
& aCacheStream
)
27 : mCacheStream(aCacheStream
) {}
29 // True when the channel has been suspended or needs to be suspended.
32 // Return true when the channel is logically suspended, i.e. the suspend
33 // count goes from 0 to 1.
36 // Return true only when the suspend count is equal to zero.
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.
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
);
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.
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;
81 ~SharedInfo() = default;
83 RefPtr
<SharedInfo
> mSharedInfo
;
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();
120 void ThrottleReadahead(bool bThrottle
) override
;
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
;
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; }
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
);
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;
176 Listener(ChannelMediaResource
* aResource
, int64_t aOffset
, uint32_t aLoadID
)
177 : mMutex("Listener.mMutex", this),
178 mResource(aResource
),
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
191 bool OnWritingThread() const override
{ return NS_IsMainThread(); }
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
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
;
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
,
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.
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;
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;
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