|
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 #if !defined(MediaResource_h_) |
|
7 #define MediaResource_h_ |
|
8 |
|
9 #include "mozilla/Mutex.h" |
|
10 #include "nsIChannel.h" |
|
11 #include "nsIURI.h" |
|
12 #include "nsIStreamingProtocolController.h" |
|
13 #include "nsIStreamListener.h" |
|
14 #include "nsIChannelEventSink.h" |
|
15 #include "nsIInterfaceRequestor.h" |
|
16 #include "MediaCache.h" |
|
17 #include "mozilla/Attributes.h" |
|
18 #include "mozilla/TimeStamp.h" |
|
19 #include "nsThreadUtils.h" |
|
20 |
|
21 // For HTTP seeking, if number of bytes needing to be |
|
22 // seeked forward is less than this value then a read is |
|
23 // done rather than a byte range request. |
|
24 static const int64_t SEEK_VS_READ_THRESHOLD = 32*1024; |
|
25 |
|
26 static const uint32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416; |
|
27 |
|
28 // Number of bytes we have accumulated before we assume the connection download |
|
29 // rate can be reliably calculated. 57 Segments at IW=3 allows slow start to |
|
30 // reach a CWND of 30 (See bug 831998) |
|
31 static const int64_t RELIABLE_DATA_THRESHOLD = 57 * 1460; |
|
32 |
|
33 class nsIHttpChannel; |
|
34 class nsIPrincipal; |
|
35 |
|
36 namespace mozilla { |
|
37 |
|
38 class MediaDecoder; |
|
39 |
|
40 /** |
|
41 * This class is useful for estimating rates of data passing through |
|
42 * some channel. The idea is that activity on the channel "starts" |
|
43 * and "stops" over time. At certain times data passes through the |
|
44 * channel (usually while the channel is active; data passing through |
|
45 * an inactive channel is ignored). The GetRate() function computes |
|
46 * an estimate of the "current rate" of the channel, which is some |
|
47 * kind of average of the data passing through over the time the |
|
48 * channel is active. |
|
49 * |
|
50 * All methods take "now" as a parameter so the user of this class can |
|
51 * control the timeline used. |
|
52 */ |
|
53 class MediaChannelStatistics { |
|
54 public: |
|
55 MediaChannelStatistics() { Reset(); } |
|
56 |
|
57 MediaChannelStatistics(MediaChannelStatistics * aCopyFrom) |
|
58 { |
|
59 MOZ_ASSERT(aCopyFrom); |
|
60 mAccumulatedBytes = aCopyFrom->mAccumulatedBytes; |
|
61 mAccumulatedTime = aCopyFrom->mAccumulatedTime; |
|
62 mLastStartTime = aCopyFrom->mLastStartTime; |
|
63 mIsStarted = aCopyFrom->mIsStarted; |
|
64 } |
|
65 |
|
66 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaChannelStatistics) |
|
67 |
|
68 void Reset() { |
|
69 mLastStartTime = TimeStamp(); |
|
70 mAccumulatedTime = TimeDuration(0); |
|
71 mAccumulatedBytes = 0; |
|
72 mIsStarted = false; |
|
73 } |
|
74 void Start() { |
|
75 if (mIsStarted) |
|
76 return; |
|
77 mLastStartTime = TimeStamp::Now(); |
|
78 mIsStarted = true; |
|
79 } |
|
80 void Stop() { |
|
81 if (!mIsStarted) |
|
82 return; |
|
83 mAccumulatedTime += TimeStamp::Now() - mLastStartTime; |
|
84 mIsStarted = false; |
|
85 } |
|
86 void AddBytes(int64_t aBytes) { |
|
87 if (!mIsStarted) { |
|
88 // ignore this data, it may be related to seeking or some other |
|
89 // operation we don't care about |
|
90 return; |
|
91 } |
|
92 mAccumulatedBytes += aBytes; |
|
93 } |
|
94 double GetRateAtLastStop(bool* aReliable) { |
|
95 double seconds = mAccumulatedTime.ToSeconds(); |
|
96 *aReliable = (seconds >= 1.0) || |
|
97 (mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD); |
|
98 if (seconds <= 0.0) |
|
99 return 0.0; |
|
100 return static_cast<double>(mAccumulatedBytes)/seconds; |
|
101 } |
|
102 double GetRate(bool* aReliable) { |
|
103 TimeDuration time = mAccumulatedTime; |
|
104 if (mIsStarted) { |
|
105 time += TimeStamp::Now() - mLastStartTime; |
|
106 } |
|
107 double seconds = time.ToSeconds(); |
|
108 *aReliable = (seconds >= 3.0) || |
|
109 (mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD); |
|
110 if (seconds <= 0.0) |
|
111 return 0.0; |
|
112 return static_cast<double>(mAccumulatedBytes)/seconds; |
|
113 } |
|
114 private: |
|
115 int64_t mAccumulatedBytes; |
|
116 TimeDuration mAccumulatedTime; |
|
117 TimeStamp mLastStartTime; |
|
118 bool mIsStarted; |
|
119 }; |
|
120 |
|
121 // Forward declaration for use in MediaByteRange. |
|
122 class TimestampedMediaByteRange; |
|
123 |
|
124 // Represents a section of contiguous media, with a start and end offset. |
|
125 // Used to denote ranges of data which are cached. |
|
126 class MediaByteRange { |
|
127 public: |
|
128 MediaByteRange() : mStart(0), mEnd(0) {} |
|
129 |
|
130 MediaByteRange(int64_t aStart, int64_t aEnd) |
|
131 : mStart(aStart), mEnd(aEnd) |
|
132 { |
|
133 NS_ASSERTION(mStart < mEnd, "Range should end after start!"); |
|
134 } |
|
135 |
|
136 MediaByteRange(TimestampedMediaByteRange& aByteRange); |
|
137 |
|
138 bool IsNull() const { |
|
139 return mStart == 0 && mEnd == 0; |
|
140 } |
|
141 |
|
142 // Clears byte range values. |
|
143 void Clear() { |
|
144 mStart = 0; |
|
145 mEnd = 0; |
|
146 } |
|
147 |
|
148 int64_t mStart, mEnd; |
|
149 }; |
|
150 |
|
151 // Represents a section of contiguous media, with a start and end offset, and |
|
152 // a timestamp representing the start time. |
|
153 class TimestampedMediaByteRange : public MediaByteRange { |
|
154 public: |
|
155 TimestampedMediaByteRange() : MediaByteRange(), mStartTime(-1) {} |
|
156 |
|
157 TimestampedMediaByteRange(int64_t aStart, int64_t aEnd, int64_t aStartTime) |
|
158 : MediaByteRange(aStart, aEnd), mStartTime(aStartTime) |
|
159 { |
|
160 NS_ASSERTION(aStartTime >= 0, "Start time should not be negative!"); |
|
161 } |
|
162 |
|
163 bool IsNull() const { |
|
164 return MediaByteRange::IsNull() && mStartTime == -1; |
|
165 } |
|
166 |
|
167 // Clears byte range values. |
|
168 void Clear() { |
|
169 MediaByteRange::Clear(); |
|
170 mStartTime = -1; |
|
171 } |
|
172 |
|
173 // In usecs. |
|
174 int64_t mStartTime; |
|
175 }; |
|
176 |
|
177 inline MediaByteRange::MediaByteRange(TimestampedMediaByteRange& aByteRange) |
|
178 : mStart(aByteRange.mStart), mEnd(aByteRange.mEnd) |
|
179 { |
|
180 NS_ASSERTION(mStart < mEnd, "Range should end after start!"); |
|
181 } |
|
182 |
|
183 class RtspMediaResource; |
|
184 |
|
185 /** |
|
186 * Provides a thread-safe, seek/read interface to resources |
|
187 * loaded from a URI. Uses MediaCache to cache data received over |
|
188 * Necko's async channel API, thus resolving the mismatch between clients |
|
189 * that need efficient random access to the data and protocols that do not |
|
190 * support efficient random access, such as HTTP. |
|
191 * |
|
192 * Instances of this class must be created on the main thread. |
|
193 * Most methods must be called on the main thread only. Read, Seek and |
|
194 * Tell must only be called on non-main threads. In the case of the Ogg |
|
195 * Decoder they are called on the Decode thread for example. You must |
|
196 * ensure that no threads are calling these methods once Close is called. |
|
197 * |
|
198 * Instances of this class are reference counted. Use nsRefPtr for |
|
199 * managing the lifetime of instances of this class. |
|
200 * |
|
201 * The generic implementation of this class is ChannelMediaResource, which can |
|
202 * handle any URI for which Necko supports AsyncOpen. |
|
203 * The 'file:' protocol can be implemented efficiently with direct random |
|
204 * access, so the FileMediaResource implementation class bypasses the cache. |
|
205 * MediaResource::Create automatically chooses the best implementation class. |
|
206 */ |
|
207 class MediaResource : public nsISupports |
|
208 { |
|
209 public: |
|
210 // Our refcounting is threadsafe, and when our refcount drops to zero |
|
211 // we dispatch an event to the main thread to delete the MediaResource. |
|
212 // Note that this means it's safe for references to this object to be |
|
213 // released on a non main thread, but the destructor will always run on |
|
214 // the main thread. |
|
215 NS_DECL_THREADSAFE_ISUPPORTS |
|
216 |
|
217 // The following can be called on the main thread only: |
|
218 // Get the URI |
|
219 virtual nsIURI* URI() const { return nullptr; } |
|
220 // Close the resource, stop any listeners, channels, etc. |
|
221 // Cancels any currently blocking Read request and forces that request to |
|
222 // return an error. |
|
223 virtual nsresult Close() = 0; |
|
224 // Suspend any downloads that are in progress. |
|
225 // If aCloseImmediately is set, resources should be released immediately |
|
226 // since we don't expect to resume again any time soon. Otherwise we |
|
227 // may resume again soon so resources should be held for a little |
|
228 // while. |
|
229 virtual void Suspend(bool aCloseImmediately) = 0; |
|
230 // Resume any downloads that have been suspended. |
|
231 virtual void Resume() = 0; |
|
232 // Get the current principal for the channel |
|
233 virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0; |
|
234 // If this returns false, then we shouldn't try to clone this MediaResource |
|
235 // because its underlying resources are not suitable for reuse (e.g. |
|
236 // because the underlying connection has been lost, or this resource |
|
237 // just can't be safely cloned). If this returns true, CloneData could |
|
238 // still fail. If this returns false, CloneData should not be called. |
|
239 virtual bool CanClone() { return false; } |
|
240 // Create a new stream of the same type that refers to the same URI |
|
241 // with a new channel. Any cached data associated with the original |
|
242 // stream should be accessible in the new stream too. |
|
243 virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder) = 0; |
|
244 // Set statistics to be recorded to the object passed in. |
|
245 virtual void RecordStatisticsTo(MediaChannelStatistics *aStatistics) { } |
|
246 |
|
247 // These methods are called off the main thread. |
|
248 // The mode is initially MODE_PLAYBACK. |
|
249 virtual void SetReadMode(MediaCacheStream::ReadMode aMode) = 0; |
|
250 // This is the client's estimate of the playback rate assuming |
|
251 // the media plays continuously. The cache can't guess this itself |
|
252 // because it doesn't know when the decoder was paused, buffering, etc. |
|
253 virtual void SetPlaybackRate(uint32_t aBytesPerSecond) = 0; |
|
254 // Read up to aCount bytes from the stream. The buffer must have |
|
255 // enough room for at least aCount bytes. Stores the number of |
|
256 // actual bytes read in aBytes (0 on end of file). |
|
257 // May read less than aCount bytes if the number of |
|
258 // available bytes is less than aCount. Always check *aBytes after |
|
259 // read, and call again if necessary. |
|
260 virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) = 0; |
|
261 // Read up to aCount bytes from the stream. The read starts at |
|
262 // aOffset in the stream, seeking to that location initially if |
|
263 // it is not the current stream offset. The remaining arguments, |
|
264 // results and requirements are the same as per the Read method. |
|
265 virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, |
|
266 uint32_t aCount, uint32_t* aBytes) = 0; |
|
267 // Seek to the given bytes offset in the stream. aWhence can be |
|
268 // one of: |
|
269 // NS_SEEK_SET |
|
270 // NS_SEEK_CUR |
|
271 // NS_SEEK_END |
|
272 // |
|
273 // In the Http strategy case the cancel will cause the http |
|
274 // channel's listener to close the pipe, forcing an i/o error on any |
|
275 // blocked read. This will allow the decode thread to complete the |
|
276 // event. |
|
277 // |
|
278 // In the case of a seek in progress, the byte range request creates |
|
279 // a new listener. This is done on the main thread via seek |
|
280 // synchronously dispatching an event. This avoids the issue of us |
|
281 // closing the listener but an outstanding byte range request |
|
282 // creating a new one. They run on the same thread so no explicit |
|
283 // synchronisation is required. The byte range request checks for |
|
284 // the cancel flag and does not create a new channel or listener if |
|
285 // we are cancelling. |
|
286 // |
|
287 // The default strategy does not do any seeking - the only issue is |
|
288 // a blocked read which it handles by causing the listener to close |
|
289 // the pipe, as per the http case. |
|
290 // |
|
291 // The file strategy doesn't block for any great length of time so |
|
292 // is fine for a no-op cancel. |
|
293 virtual nsresult Seek(int32_t aWhence, int64_t aOffset) = 0; |
|
294 virtual void StartSeekingForMetadata() = 0; |
|
295 virtual void EndSeekingForMetadata() = 0; |
|
296 // Report the current offset in bytes from the start of the stream. |
|
297 virtual int64_t Tell() = 0; |
|
298 // Moves any existing channel loads into the background, so that they don't |
|
299 // block the load event. Any new loads initiated (for example to seek) |
|
300 // will also be in the background. |
|
301 virtual void MoveLoadsToBackground() {} |
|
302 // Ensures that the value returned by IsSuspendedByCache below is up to date |
|
303 // (i.e. the cache has examined this stream at least once). |
|
304 virtual void EnsureCacheUpToDate() {} |
|
305 |
|
306 // These can be called on any thread. |
|
307 // Cached blocks associated with this stream will not be evicted |
|
308 // while the stream is pinned. |
|
309 virtual void Pin() = 0; |
|
310 virtual void Unpin() = 0; |
|
311 // Get the estimated download rate in bytes per second (assuming no |
|
312 // pausing of the channel is requested by Gecko). |
|
313 // *aIsReliable is set to true if we think the estimate is useful. |
|
314 virtual double GetDownloadRate(bool* aIsReliable) = 0; |
|
315 // Get the length of the stream in bytes. Returns -1 if not known. |
|
316 // This can change over time; after a seek operation, a misbehaving |
|
317 // server may give us a resource of a different length to what it had |
|
318 // reported previously --- or it may just lie in its Content-Length |
|
319 // header and give us more or less data than it reported. We will adjust |
|
320 // the result of GetLength to reflect the data that's actually arriving. |
|
321 virtual int64_t GetLength() = 0; |
|
322 // Returns the offset of the first byte of cached data at or after aOffset, |
|
323 // or -1 if there is no such cached data. |
|
324 virtual int64_t GetNextCachedData(int64_t aOffset) = 0; |
|
325 // Returns the end of the bytes starting at the given offset |
|
326 // which are in cache. |
|
327 virtual int64_t GetCachedDataEnd(int64_t aOffset) = 0; |
|
328 // Returns true if all the data from aOffset to the end of the stream |
|
329 // is in cache. If the end of the stream is not known, we return false. |
|
330 virtual bool IsDataCachedToEndOfResource(int64_t aOffset) = 0; |
|
331 // Returns true if this stream is suspended by the cache because the |
|
332 // cache is full. If true then the decoder should try to start consuming |
|
333 // data, otherwise we may not be able to make progress. |
|
334 // MediaDecoder::NotifySuspendedStatusChanged is called when this |
|
335 // changes. |
|
336 // For resources using the media cache, this returns true only when all |
|
337 // streams for the same resource are all suspended. |
|
338 virtual bool IsSuspendedByCache() = 0; |
|
339 // Returns true if this stream has been suspended. |
|
340 virtual bool IsSuspended() = 0; |
|
341 // Reads only data which is cached in the media cache. If you try to read |
|
342 // any data which overlaps uncached data, or if aCount bytes otherwise can't |
|
343 // be read, this function will return failure. This function be called from |
|
344 // any thread, and it is the only read operation which is safe to call on |
|
345 // the main thread, since it's guaranteed to be non blocking. |
|
346 virtual nsresult ReadFromCache(char* aBuffer, |
|
347 int64_t aOffset, |
|
348 uint32_t aCount) = 0; |
|
349 // Returns true if the resource can be seeked to unbuffered ranges, i.e. |
|
350 // for an HTTP network stream this returns true if HTTP1.1 Byte Range |
|
351 // requests are supported by the connection/server. |
|
352 virtual bool IsTransportSeekable() = 0; |
|
353 |
|
354 /** |
|
355 * Create a resource, reading data from the channel. Call on main thread only. |
|
356 * The caller must follow up by calling resource->Open(). |
|
357 */ |
|
358 static already_AddRefed<MediaResource> Create(MediaDecoder* aDecoder, nsIChannel* aChannel); |
|
359 |
|
360 /** |
|
361 * Open the stream. This creates a stream listener and returns it in |
|
362 * aStreamListener; this listener needs to be notified of incoming data. |
|
363 */ |
|
364 virtual nsresult Open(nsIStreamListener** aStreamListener) = 0; |
|
365 |
|
366 /** |
|
367 * Fills aRanges with MediaByteRanges representing the data which is cached |
|
368 * in the media cache. Stream should be pinned during call and while |
|
369 * aRanges is being used. |
|
370 */ |
|
371 virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) = 0; |
|
372 |
|
373 // Ensure that the media cache writes any data held in its partial block. |
|
374 // Called on the main thread only. |
|
375 virtual void FlushCache() { } |
|
376 |
|
377 // Notify that the last data byte range was loaded. |
|
378 virtual void NotifyLastByteRange() { } |
|
379 |
|
380 // Returns the content type of the resource. This is copied from the |
|
381 // nsIChannel when the MediaResource is created. Safe to call from |
|
382 // any thread. |
|
383 virtual const nsCString& GetContentType() const = 0; |
|
384 |
|
385 // Get the RtspMediaResource pointer if this MediaResource really is a |
|
386 // RtspMediaResource. For calling Rtsp specific functions. |
|
387 virtual RtspMediaResource* GetRtspPointer() { |
|
388 return nullptr; |
|
389 } |
|
390 |
|
391 // Return true if the stream is a live stream |
|
392 virtual bool IsRealTime() { |
|
393 return false; |
|
394 } |
|
395 |
|
396 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { |
|
397 return 0; |
|
398 } |
|
399 |
|
400 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { |
|
401 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
|
402 } |
|
403 |
|
404 protected: |
|
405 virtual ~MediaResource() {}; |
|
406 |
|
407 private: |
|
408 void Destroy(); |
|
409 }; |
|
410 |
|
411 class BaseMediaResource : public MediaResource { |
|
412 public: |
|
413 virtual nsIURI* URI() const { return mURI; } |
|
414 virtual void MoveLoadsToBackground(); |
|
415 |
|
416 virtual size_t SizeOfExcludingThis( |
|
417 MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE |
|
418 { |
|
419 // Might be useful to track in the future: |
|
420 // - mChannel |
|
421 // - mURI (possibly owned, looks like just a ref from mChannel) |
|
422 // Not owned: |
|
423 // - mDecoder |
|
424 size_t size = MediaResource::SizeOfExcludingThis(aMallocSizeOf); |
|
425 size += mContentType.SizeOfIncludingThisIfUnshared(aMallocSizeOf); |
|
426 |
|
427 return size; |
|
428 } |
|
429 |
|
430 virtual size_t SizeOfIncludingThis( |
|
431 MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE |
|
432 { |
|
433 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
|
434 } |
|
435 |
|
436 protected: |
|
437 BaseMediaResource(MediaDecoder* aDecoder, |
|
438 nsIChannel* aChannel, |
|
439 nsIURI* aURI, |
|
440 const nsACString& aContentType) : |
|
441 mDecoder(aDecoder), |
|
442 mChannel(aChannel), |
|
443 mURI(aURI), |
|
444 mContentType(aContentType), |
|
445 mLoadInBackground(false) |
|
446 { |
|
447 MOZ_COUNT_CTOR(BaseMediaResource); |
|
448 NS_ASSERTION(!mContentType.IsEmpty(), "Must know content type"); |
|
449 } |
|
450 virtual ~BaseMediaResource() |
|
451 { |
|
452 MOZ_COUNT_DTOR(BaseMediaResource); |
|
453 } |
|
454 |
|
455 virtual const nsCString& GetContentType() const MOZ_OVERRIDE |
|
456 { |
|
457 return mContentType; |
|
458 } |
|
459 |
|
460 // Set the request's load flags to aFlags. If the request is part of a |
|
461 // load group, the request is removed from the group, the flags are set, and |
|
462 // then the request is added back to the load group. |
|
463 void ModifyLoadFlags(nsLoadFlags aFlags); |
|
464 |
|
465 // Dispatches an event to call MediaDecoder::NotifyBytesConsumed(aNumBytes, aOffset) |
|
466 // on the main thread. This is called automatically after every read. |
|
467 void DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset); |
|
468 |
|
469 // This is not an nsCOMPointer to prevent a circular reference |
|
470 // between the decoder to the media stream object. The stream never |
|
471 // outlives the lifetime of the decoder. |
|
472 MediaDecoder* mDecoder; |
|
473 |
|
474 // Channel used to download the media data. Must be accessed |
|
475 // from the main thread only. |
|
476 nsCOMPtr<nsIChannel> mChannel; |
|
477 |
|
478 // URI in case the stream needs to be re-opened. Access from |
|
479 // main thread only. |
|
480 nsCOMPtr<nsIURI> mURI; |
|
481 |
|
482 // Content-Type of the channel. This is copied from the nsIChannel when the |
|
483 // MediaResource is created. This is constant, so accessing from any thread |
|
484 // is safe. |
|
485 const nsAutoCString mContentType; |
|
486 |
|
487 // True if MoveLoadsToBackground() has been called, i.e. the load event |
|
488 // has been fired, and all channel loads will be in the background. |
|
489 bool mLoadInBackground; |
|
490 }; |
|
491 |
|
492 /** |
|
493 * This is the MediaResource implementation that wraps Necko channels. |
|
494 * Much of its functionality is actually delegated to MediaCache via |
|
495 * an underlying MediaCacheStream. |
|
496 * |
|
497 * All synchronization is performed by MediaCacheStream; all off-main- |
|
498 * thread operations are delegated directly to that object. |
|
499 */ |
|
500 class ChannelMediaResource : public BaseMediaResource |
|
501 { |
|
502 public: |
|
503 ChannelMediaResource(MediaDecoder* aDecoder, |
|
504 nsIChannel* aChannel, |
|
505 nsIURI* aURI, |
|
506 const nsACString& aContentType); |
|
507 ~ChannelMediaResource(); |
|
508 |
|
509 // These are called on the main thread by MediaCache. These must |
|
510 // not block or grab locks, because the media cache is holding its lock. |
|
511 // Notify that data is available from the cache. This can happen even |
|
512 // if this stream didn't read any data, since another stream might have |
|
513 // received data for the same resource. |
|
514 void CacheClientNotifyDataReceived(); |
|
515 // Notify that we reached the end of the stream. This can happen even |
|
516 // if this stream didn't read any data, since another stream might have |
|
517 // received data for the same resource. |
|
518 void CacheClientNotifyDataEnded(nsresult aStatus); |
|
519 // Notify that the principal for the cached resource changed. |
|
520 void CacheClientNotifyPrincipalChanged(); |
|
521 |
|
522 // These are called on the main thread by MediaCache. These shouldn't block, |
|
523 // but they may grab locks --- the media cache is not holding its lock |
|
524 // when these are called. |
|
525 // Start a new load at the given aOffset. The old load is cancelled |
|
526 // and no more data from the old load will be notified via |
|
527 // MediaCacheStream::NotifyDataReceived/Ended. |
|
528 // This can fail. |
|
529 nsresult CacheClientSeek(int64_t aOffset, bool aResume); |
|
530 // Suspend the current load since data is currently not wanted |
|
531 nsresult CacheClientSuspend(); |
|
532 // Resume the current load since data is wanted again |
|
533 nsresult CacheClientResume(); |
|
534 |
|
535 // Ensure that the media cache writes any data held in its partial block. |
|
536 // Called on the main thread. |
|
537 virtual void FlushCache() MOZ_OVERRIDE; |
|
538 |
|
539 // Notify that the last data byte range was loaded. |
|
540 virtual void NotifyLastByteRange() MOZ_OVERRIDE; |
|
541 |
|
542 // Main thread |
|
543 virtual nsresult Open(nsIStreamListener** aStreamListener); |
|
544 virtual nsresult Close(); |
|
545 virtual void Suspend(bool aCloseImmediately); |
|
546 virtual void Resume(); |
|
547 virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal(); |
|
548 // Return true if the stream has been closed. |
|
549 bool IsClosed() const { return mCacheStream.IsClosed(); } |
|
550 virtual bool CanClone(); |
|
551 virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder); |
|
552 // Set statistics to be recorded to the object passed in. If not called, |
|
553 // |ChannelMediaResource| will create it's own statistics objects in |Open|. |
|
554 void RecordStatisticsTo(MediaChannelStatistics *aStatistics) MOZ_OVERRIDE { |
|
555 NS_ASSERTION(aStatistics, "Statistics param cannot be null!"); |
|
556 MutexAutoLock lock(mLock); |
|
557 if (!mChannelStatistics) { |
|
558 mChannelStatistics = aStatistics; |
|
559 } |
|
560 } |
|
561 virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount); |
|
562 virtual void EnsureCacheUpToDate(); |
|
563 |
|
564 // Other thread |
|
565 virtual void SetReadMode(MediaCacheStream::ReadMode aMode); |
|
566 virtual void SetPlaybackRate(uint32_t aBytesPerSecond); |
|
567 virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes); |
|
568 virtual nsresult ReadAt(int64_t offset, char* aBuffer, |
|
569 uint32_t aCount, uint32_t* aBytes); |
|
570 virtual nsresult Seek(int32_t aWhence, int64_t aOffset); |
|
571 virtual void StartSeekingForMetadata(); |
|
572 virtual void EndSeekingForMetadata(); |
|
573 virtual int64_t Tell(); |
|
574 |
|
575 // Any thread |
|
576 virtual void Pin(); |
|
577 virtual void Unpin(); |
|
578 virtual double GetDownloadRate(bool* aIsReliable); |
|
579 virtual int64_t GetLength(); |
|
580 virtual int64_t GetNextCachedData(int64_t aOffset); |
|
581 virtual int64_t GetCachedDataEnd(int64_t aOffset); |
|
582 virtual bool IsDataCachedToEndOfResource(int64_t aOffset); |
|
583 virtual bool IsSuspendedByCache(); |
|
584 virtual bool IsSuspended(); |
|
585 virtual bool IsTransportSeekable() MOZ_OVERRIDE; |
|
586 |
|
587 virtual size_t SizeOfExcludingThis( |
|
588 MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE { |
|
589 // Might be useful to track in the future: |
|
590 // - mListener (seems minor) |
|
591 // - mChannelStatistics (seems minor) |
|
592 // owned if RecordStatisticsTo is not called |
|
593 // - mDataReceivedEvent (seems minor) |
|
594 size_t size = BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf); |
|
595 size += mCacheStream.SizeOfExcludingThis(aMallocSizeOf); |
|
596 |
|
597 return size; |
|
598 } |
|
599 |
|
600 virtual size_t SizeOfIncludingThis( |
|
601 MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE { |
|
602 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
|
603 } |
|
604 |
|
605 class Listener MOZ_FINAL : public nsIStreamListener, |
|
606 public nsIInterfaceRequestor, |
|
607 public nsIChannelEventSink |
|
608 { |
|
609 public: |
|
610 Listener(ChannelMediaResource* aResource) : mResource(aResource) {} |
|
611 ~Listener() {} |
|
612 |
|
613 NS_DECL_ISUPPORTS |
|
614 NS_DECL_NSIREQUESTOBSERVER |
|
615 NS_DECL_NSISTREAMLISTENER |
|
616 NS_DECL_NSICHANNELEVENTSINK |
|
617 NS_DECL_NSIINTERFACEREQUESTOR |
|
618 |
|
619 void Revoke() { mResource = nullptr; } |
|
620 |
|
621 private: |
|
622 nsRefPtr<ChannelMediaResource> mResource; |
|
623 }; |
|
624 friend class Listener; |
|
625 |
|
626 nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges); |
|
627 |
|
628 protected: |
|
629 // These are called on the main thread by Listener. |
|
630 nsresult OnStartRequest(nsIRequest* aRequest); |
|
631 nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus); |
|
632 nsresult OnDataAvailable(nsIRequest* aRequest, |
|
633 nsIInputStream* aStream, |
|
634 uint32_t aCount); |
|
635 nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew, uint32_t aFlags); |
|
636 |
|
637 // Opens the channel, using an HTTP byte range request to start at mOffset |
|
638 // if possible. Main thread only. |
|
639 nsresult OpenChannel(nsIStreamListener** aStreamListener); |
|
640 nsresult RecreateChannel(); |
|
641 // Add headers to HTTP request. Main thread only. |
|
642 void SetupChannelHeaders(); |
|
643 // Closes the channel. Main thread only. |
|
644 void CloseChannel(); |
|
645 |
|
646 // Parses 'Content-Range' header and returns results via parameters. |
|
647 // Returns error if header is not available, values are not parse-able or |
|
648 // values are out of range. |
|
649 nsresult ParseContentRangeHeader(nsIHttpChannel * aHttpChan, |
|
650 int64_t& aRangeStart, |
|
651 int64_t& aRangeEnd, |
|
652 int64_t& aRangeTotal); |
|
653 |
|
654 void DoNotifyDataReceived(); |
|
655 |
|
656 static NS_METHOD CopySegmentToCache(nsIInputStream *aInStream, |
|
657 void *aClosure, |
|
658 const char *aFromSegment, |
|
659 uint32_t aToOffset, |
|
660 uint32_t aCount, |
|
661 uint32_t *aWriteCount); |
|
662 |
|
663 // Suspend the channel only if the channels is currently downloading data. |
|
664 // If it isn't we set a flag, mIgnoreResume, so that PossiblyResume knows |
|
665 // whether to acutually resume or not. |
|
666 void PossiblySuspend(); |
|
667 |
|
668 // Resume from a suspend if we actually suspended (See PossiblySuspend). |
|
669 void PossiblyResume(); |
|
670 |
|
671 // Main thread access only |
|
672 int64_t mOffset; |
|
673 nsRefPtr<Listener> mListener; |
|
674 // A data received event for the decoder that has been dispatched but has |
|
675 // not yet been processed. |
|
676 nsRevocableEventPtr<nsRunnableMethod<ChannelMediaResource, void, false> > mDataReceivedEvent; |
|
677 uint32_t mSuspendCount; |
|
678 // When this flag is set, if we get a network error we should silently |
|
679 // reopen the stream. |
|
680 bool mReopenOnError; |
|
681 // When this flag is set, we should not report the next close of the |
|
682 // channel. |
|
683 bool mIgnoreClose; |
|
684 |
|
685 // Any thread access |
|
686 MediaCacheStream mCacheStream; |
|
687 |
|
688 // This lock protects mChannelStatistics |
|
689 Mutex mLock; |
|
690 nsRefPtr<MediaChannelStatistics> mChannelStatistics; |
|
691 |
|
692 // True if we couldn't suspend the stream and we therefore don't want |
|
693 // to resume later. This is usually due to the channel not being in the |
|
694 // isPending state at the time of the suspend request. |
|
695 bool mIgnoreResume; |
|
696 |
|
697 // True if we are seeking to get the real duration of the file. |
|
698 bool mSeekingForMetadata; |
|
699 |
|
700 // Start and end offset of the bytes to be requested. |
|
701 MediaByteRange mByteRange; |
|
702 |
|
703 // True if the stream can seek into unbuffered ranged, i.e. if the |
|
704 // connection supports byte range requests. |
|
705 bool mIsTransportSeekable; |
|
706 }; |
|
707 |
|
708 } // namespace mozilla |
|
709 |
|
710 #endif |