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"
20 * This class is responsible for managing the suspend count and report suspend
23 class ChannelSuspendAgent
{
25 explicit ChannelSuspendAgent(MediaCacheStream
& aCacheStream
)
26 : mCacheStream(aCacheStream
) {}
28 // True when the channel has been suspended or needs to be suspended.
31 // Return true when the channel is logically suspended, i.e. the suspend
32 // count goes from 0 to 1.
35 // Return true only when the suspend count is equal to zero.
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.
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
);
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.
68 NS_INLINE_DECL_REFCOUNTING(SharedInfo
);
70 SharedInfo() : mHadCrossOriginRedirects(false) {}
72 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
73 nsTArray
<ChannelMediaResource
*> mResources
;
74 bool mHadCrossOriginRedirects
;
77 ~SharedInfo() = default;
79 RefPtr
<SharedInfo
> mSharedInfo
;
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();
116 void ThrottleReadahead(bool bThrottle
) override
;
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
;
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; }
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
);
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
{
172 Listener(ChannelMediaResource
* aResource
, int64_t aOffset
, uint32_t aLoadID
)
173 : mMutex("Listener.mMutex"),
174 mResource(aResource
),
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
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
192 RefPtr
<ChannelMediaResource
> mResource
;
194 const int64_t mOffset
;
195 const uint32_t mLoadID
;
197 friend class Listener
;
199 nsresult
GetCachedRanges(MediaByteRangeSet
& aRanges
) override
;
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
,
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.
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;
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;
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