1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/MediaResource.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,710 @@ 1.4 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#if !defined(MediaResource_h_) 1.10 +#define MediaResource_h_ 1.11 + 1.12 +#include "mozilla/Mutex.h" 1.13 +#include "nsIChannel.h" 1.14 +#include "nsIURI.h" 1.15 +#include "nsIStreamingProtocolController.h" 1.16 +#include "nsIStreamListener.h" 1.17 +#include "nsIChannelEventSink.h" 1.18 +#include "nsIInterfaceRequestor.h" 1.19 +#include "MediaCache.h" 1.20 +#include "mozilla/Attributes.h" 1.21 +#include "mozilla/TimeStamp.h" 1.22 +#include "nsThreadUtils.h" 1.23 + 1.24 +// For HTTP seeking, if number of bytes needing to be 1.25 +// seeked forward is less than this value then a read is 1.26 +// done rather than a byte range request. 1.27 +static const int64_t SEEK_VS_READ_THRESHOLD = 32*1024; 1.28 + 1.29 +static const uint32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416; 1.30 + 1.31 +// Number of bytes we have accumulated before we assume the connection download 1.32 +// rate can be reliably calculated. 57 Segments at IW=3 allows slow start to 1.33 +// reach a CWND of 30 (See bug 831998) 1.34 +static const int64_t RELIABLE_DATA_THRESHOLD = 57 * 1460; 1.35 + 1.36 +class nsIHttpChannel; 1.37 +class nsIPrincipal; 1.38 + 1.39 +namespace mozilla { 1.40 + 1.41 +class MediaDecoder; 1.42 + 1.43 +/** 1.44 + * This class is useful for estimating rates of data passing through 1.45 + * some channel. The idea is that activity on the channel "starts" 1.46 + * and "stops" over time. At certain times data passes through the 1.47 + * channel (usually while the channel is active; data passing through 1.48 + * an inactive channel is ignored). The GetRate() function computes 1.49 + * an estimate of the "current rate" of the channel, which is some 1.50 + * kind of average of the data passing through over the time the 1.51 + * channel is active. 1.52 + * 1.53 + * All methods take "now" as a parameter so the user of this class can 1.54 + * control the timeline used. 1.55 + */ 1.56 +class MediaChannelStatistics { 1.57 +public: 1.58 + MediaChannelStatistics() { Reset(); } 1.59 + 1.60 + MediaChannelStatistics(MediaChannelStatistics * aCopyFrom) 1.61 + { 1.62 + MOZ_ASSERT(aCopyFrom); 1.63 + mAccumulatedBytes = aCopyFrom->mAccumulatedBytes; 1.64 + mAccumulatedTime = aCopyFrom->mAccumulatedTime; 1.65 + mLastStartTime = aCopyFrom->mLastStartTime; 1.66 + mIsStarted = aCopyFrom->mIsStarted; 1.67 + } 1.68 + 1.69 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaChannelStatistics) 1.70 + 1.71 + void Reset() { 1.72 + mLastStartTime = TimeStamp(); 1.73 + mAccumulatedTime = TimeDuration(0); 1.74 + mAccumulatedBytes = 0; 1.75 + mIsStarted = false; 1.76 + } 1.77 + void Start() { 1.78 + if (mIsStarted) 1.79 + return; 1.80 + mLastStartTime = TimeStamp::Now(); 1.81 + mIsStarted = true; 1.82 + } 1.83 + void Stop() { 1.84 + if (!mIsStarted) 1.85 + return; 1.86 + mAccumulatedTime += TimeStamp::Now() - mLastStartTime; 1.87 + mIsStarted = false; 1.88 + } 1.89 + void AddBytes(int64_t aBytes) { 1.90 + if (!mIsStarted) { 1.91 + // ignore this data, it may be related to seeking or some other 1.92 + // operation we don't care about 1.93 + return; 1.94 + } 1.95 + mAccumulatedBytes += aBytes; 1.96 + } 1.97 + double GetRateAtLastStop(bool* aReliable) { 1.98 + double seconds = mAccumulatedTime.ToSeconds(); 1.99 + *aReliable = (seconds >= 1.0) || 1.100 + (mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD); 1.101 + if (seconds <= 0.0) 1.102 + return 0.0; 1.103 + return static_cast<double>(mAccumulatedBytes)/seconds; 1.104 + } 1.105 + double GetRate(bool* aReliable) { 1.106 + TimeDuration time = mAccumulatedTime; 1.107 + if (mIsStarted) { 1.108 + time += TimeStamp::Now() - mLastStartTime; 1.109 + } 1.110 + double seconds = time.ToSeconds(); 1.111 + *aReliable = (seconds >= 3.0) || 1.112 + (mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD); 1.113 + if (seconds <= 0.0) 1.114 + return 0.0; 1.115 + return static_cast<double>(mAccumulatedBytes)/seconds; 1.116 + } 1.117 +private: 1.118 + int64_t mAccumulatedBytes; 1.119 + TimeDuration mAccumulatedTime; 1.120 + TimeStamp mLastStartTime; 1.121 + bool mIsStarted; 1.122 +}; 1.123 + 1.124 +// Forward declaration for use in MediaByteRange. 1.125 +class TimestampedMediaByteRange; 1.126 + 1.127 +// Represents a section of contiguous media, with a start and end offset. 1.128 +// Used to denote ranges of data which are cached. 1.129 +class MediaByteRange { 1.130 +public: 1.131 + MediaByteRange() : mStart(0), mEnd(0) {} 1.132 + 1.133 + MediaByteRange(int64_t aStart, int64_t aEnd) 1.134 + : mStart(aStart), mEnd(aEnd) 1.135 + { 1.136 + NS_ASSERTION(mStart < mEnd, "Range should end after start!"); 1.137 + } 1.138 + 1.139 + MediaByteRange(TimestampedMediaByteRange& aByteRange); 1.140 + 1.141 + bool IsNull() const { 1.142 + return mStart == 0 && mEnd == 0; 1.143 + } 1.144 + 1.145 + // Clears byte range values. 1.146 + void Clear() { 1.147 + mStart = 0; 1.148 + mEnd = 0; 1.149 + } 1.150 + 1.151 + int64_t mStart, mEnd; 1.152 +}; 1.153 + 1.154 +// Represents a section of contiguous media, with a start and end offset, and 1.155 +// a timestamp representing the start time. 1.156 +class TimestampedMediaByteRange : public MediaByteRange { 1.157 +public: 1.158 + TimestampedMediaByteRange() : MediaByteRange(), mStartTime(-1) {} 1.159 + 1.160 + TimestampedMediaByteRange(int64_t aStart, int64_t aEnd, int64_t aStartTime) 1.161 + : MediaByteRange(aStart, aEnd), mStartTime(aStartTime) 1.162 + { 1.163 + NS_ASSERTION(aStartTime >= 0, "Start time should not be negative!"); 1.164 + } 1.165 + 1.166 + bool IsNull() const { 1.167 + return MediaByteRange::IsNull() && mStartTime == -1; 1.168 + } 1.169 + 1.170 + // Clears byte range values. 1.171 + void Clear() { 1.172 + MediaByteRange::Clear(); 1.173 + mStartTime = -1; 1.174 + } 1.175 + 1.176 + // In usecs. 1.177 + int64_t mStartTime; 1.178 +}; 1.179 + 1.180 +inline MediaByteRange::MediaByteRange(TimestampedMediaByteRange& aByteRange) 1.181 + : mStart(aByteRange.mStart), mEnd(aByteRange.mEnd) 1.182 +{ 1.183 + NS_ASSERTION(mStart < mEnd, "Range should end after start!"); 1.184 +} 1.185 + 1.186 +class RtspMediaResource; 1.187 + 1.188 +/** 1.189 + * Provides a thread-safe, seek/read interface to resources 1.190 + * loaded from a URI. Uses MediaCache to cache data received over 1.191 + * Necko's async channel API, thus resolving the mismatch between clients 1.192 + * that need efficient random access to the data and protocols that do not 1.193 + * support efficient random access, such as HTTP. 1.194 + * 1.195 + * Instances of this class must be created on the main thread. 1.196 + * Most methods must be called on the main thread only. Read, Seek and 1.197 + * Tell must only be called on non-main threads. In the case of the Ogg 1.198 + * Decoder they are called on the Decode thread for example. You must 1.199 + * ensure that no threads are calling these methods once Close is called. 1.200 + * 1.201 + * Instances of this class are reference counted. Use nsRefPtr for 1.202 + * managing the lifetime of instances of this class. 1.203 + * 1.204 + * The generic implementation of this class is ChannelMediaResource, which can 1.205 + * handle any URI for which Necko supports AsyncOpen. 1.206 + * The 'file:' protocol can be implemented efficiently with direct random 1.207 + * access, so the FileMediaResource implementation class bypasses the cache. 1.208 + * MediaResource::Create automatically chooses the best implementation class. 1.209 + */ 1.210 +class MediaResource : public nsISupports 1.211 +{ 1.212 +public: 1.213 + // Our refcounting is threadsafe, and when our refcount drops to zero 1.214 + // we dispatch an event to the main thread to delete the MediaResource. 1.215 + // Note that this means it's safe for references to this object to be 1.216 + // released on a non main thread, but the destructor will always run on 1.217 + // the main thread. 1.218 + NS_DECL_THREADSAFE_ISUPPORTS 1.219 + 1.220 + // The following can be called on the main thread only: 1.221 + // Get the URI 1.222 + virtual nsIURI* URI() const { return nullptr; } 1.223 + // Close the resource, stop any listeners, channels, etc. 1.224 + // Cancels any currently blocking Read request and forces that request to 1.225 + // return an error. 1.226 + virtual nsresult Close() = 0; 1.227 + // Suspend any downloads that are in progress. 1.228 + // If aCloseImmediately is set, resources should be released immediately 1.229 + // since we don't expect to resume again any time soon. Otherwise we 1.230 + // may resume again soon so resources should be held for a little 1.231 + // while. 1.232 + virtual void Suspend(bool aCloseImmediately) = 0; 1.233 + // Resume any downloads that have been suspended. 1.234 + virtual void Resume() = 0; 1.235 + // Get the current principal for the channel 1.236 + virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0; 1.237 + // If this returns false, then we shouldn't try to clone this MediaResource 1.238 + // because its underlying resources are not suitable for reuse (e.g. 1.239 + // because the underlying connection has been lost, or this resource 1.240 + // just can't be safely cloned). If this returns true, CloneData could 1.241 + // still fail. If this returns false, CloneData should not be called. 1.242 + virtual bool CanClone() { return false; } 1.243 + // Create a new stream of the same type that refers to the same URI 1.244 + // with a new channel. Any cached data associated with the original 1.245 + // stream should be accessible in the new stream too. 1.246 + virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder) = 0; 1.247 + // Set statistics to be recorded to the object passed in. 1.248 + virtual void RecordStatisticsTo(MediaChannelStatistics *aStatistics) { } 1.249 + 1.250 + // These methods are called off the main thread. 1.251 + // The mode is initially MODE_PLAYBACK. 1.252 + virtual void SetReadMode(MediaCacheStream::ReadMode aMode) = 0; 1.253 + // This is the client's estimate of the playback rate assuming 1.254 + // the media plays continuously. The cache can't guess this itself 1.255 + // because it doesn't know when the decoder was paused, buffering, etc. 1.256 + virtual void SetPlaybackRate(uint32_t aBytesPerSecond) = 0; 1.257 + // Read up to aCount bytes from the stream. The buffer must have 1.258 + // enough room for at least aCount bytes. Stores the number of 1.259 + // actual bytes read in aBytes (0 on end of file). 1.260 + // May read less than aCount bytes if the number of 1.261 + // available bytes is less than aCount. Always check *aBytes after 1.262 + // read, and call again if necessary. 1.263 + virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) = 0; 1.264 + // Read up to aCount bytes from the stream. The read starts at 1.265 + // aOffset in the stream, seeking to that location initially if 1.266 + // it is not the current stream offset. The remaining arguments, 1.267 + // results and requirements are the same as per the Read method. 1.268 + virtual nsresult ReadAt(int64_t aOffset, char* aBuffer, 1.269 + uint32_t aCount, uint32_t* aBytes) = 0; 1.270 + // Seek to the given bytes offset in the stream. aWhence can be 1.271 + // one of: 1.272 + // NS_SEEK_SET 1.273 + // NS_SEEK_CUR 1.274 + // NS_SEEK_END 1.275 + // 1.276 + // In the Http strategy case the cancel will cause the http 1.277 + // channel's listener to close the pipe, forcing an i/o error on any 1.278 + // blocked read. This will allow the decode thread to complete the 1.279 + // event. 1.280 + // 1.281 + // In the case of a seek in progress, the byte range request creates 1.282 + // a new listener. This is done on the main thread via seek 1.283 + // synchronously dispatching an event. This avoids the issue of us 1.284 + // closing the listener but an outstanding byte range request 1.285 + // creating a new one. They run on the same thread so no explicit 1.286 + // synchronisation is required. The byte range request checks for 1.287 + // the cancel flag and does not create a new channel or listener if 1.288 + // we are cancelling. 1.289 + // 1.290 + // The default strategy does not do any seeking - the only issue is 1.291 + // a blocked read which it handles by causing the listener to close 1.292 + // the pipe, as per the http case. 1.293 + // 1.294 + // The file strategy doesn't block for any great length of time so 1.295 + // is fine for a no-op cancel. 1.296 + virtual nsresult Seek(int32_t aWhence, int64_t aOffset) = 0; 1.297 + virtual void StartSeekingForMetadata() = 0; 1.298 + virtual void EndSeekingForMetadata() = 0; 1.299 + // Report the current offset in bytes from the start of the stream. 1.300 + virtual int64_t Tell() = 0; 1.301 + // Moves any existing channel loads into the background, so that they don't 1.302 + // block the load event. Any new loads initiated (for example to seek) 1.303 + // will also be in the background. 1.304 + virtual void MoveLoadsToBackground() {} 1.305 + // Ensures that the value returned by IsSuspendedByCache below is up to date 1.306 + // (i.e. the cache has examined this stream at least once). 1.307 + virtual void EnsureCacheUpToDate() {} 1.308 + 1.309 + // These can be called on any thread. 1.310 + // Cached blocks associated with this stream will not be evicted 1.311 + // while the stream is pinned. 1.312 + virtual void Pin() = 0; 1.313 + virtual void Unpin() = 0; 1.314 + // Get the estimated download rate in bytes per second (assuming no 1.315 + // pausing of the channel is requested by Gecko). 1.316 + // *aIsReliable is set to true if we think the estimate is useful. 1.317 + virtual double GetDownloadRate(bool* aIsReliable) = 0; 1.318 + // Get the length of the stream in bytes. Returns -1 if not known. 1.319 + // This can change over time; after a seek operation, a misbehaving 1.320 + // server may give us a resource of a different length to what it had 1.321 + // reported previously --- or it may just lie in its Content-Length 1.322 + // header and give us more or less data than it reported. We will adjust 1.323 + // the result of GetLength to reflect the data that's actually arriving. 1.324 + virtual int64_t GetLength() = 0; 1.325 + // Returns the offset of the first byte of cached data at or after aOffset, 1.326 + // or -1 if there is no such cached data. 1.327 + virtual int64_t GetNextCachedData(int64_t aOffset) = 0; 1.328 + // Returns the end of the bytes starting at the given offset 1.329 + // which are in cache. 1.330 + virtual int64_t GetCachedDataEnd(int64_t aOffset) = 0; 1.331 + // Returns true if all the data from aOffset to the end of the stream 1.332 + // is in cache. If the end of the stream is not known, we return false. 1.333 + virtual bool IsDataCachedToEndOfResource(int64_t aOffset) = 0; 1.334 + // Returns true if this stream is suspended by the cache because the 1.335 + // cache is full. If true then the decoder should try to start consuming 1.336 + // data, otherwise we may not be able to make progress. 1.337 + // MediaDecoder::NotifySuspendedStatusChanged is called when this 1.338 + // changes. 1.339 + // For resources using the media cache, this returns true only when all 1.340 + // streams for the same resource are all suspended. 1.341 + virtual bool IsSuspendedByCache() = 0; 1.342 + // Returns true if this stream has been suspended. 1.343 + virtual bool IsSuspended() = 0; 1.344 + // Reads only data which is cached in the media cache. If you try to read 1.345 + // any data which overlaps uncached data, or if aCount bytes otherwise can't 1.346 + // be read, this function will return failure. This function be called from 1.347 + // any thread, and it is the only read operation which is safe to call on 1.348 + // the main thread, since it's guaranteed to be non blocking. 1.349 + virtual nsresult ReadFromCache(char* aBuffer, 1.350 + int64_t aOffset, 1.351 + uint32_t aCount) = 0; 1.352 + // Returns true if the resource can be seeked to unbuffered ranges, i.e. 1.353 + // for an HTTP network stream this returns true if HTTP1.1 Byte Range 1.354 + // requests are supported by the connection/server. 1.355 + virtual bool IsTransportSeekable() = 0; 1.356 + 1.357 + /** 1.358 + * Create a resource, reading data from the channel. Call on main thread only. 1.359 + * The caller must follow up by calling resource->Open(). 1.360 + */ 1.361 + static already_AddRefed<MediaResource> Create(MediaDecoder* aDecoder, nsIChannel* aChannel); 1.362 + 1.363 + /** 1.364 + * Open the stream. This creates a stream listener and returns it in 1.365 + * aStreamListener; this listener needs to be notified of incoming data. 1.366 + */ 1.367 + virtual nsresult Open(nsIStreamListener** aStreamListener) = 0; 1.368 + 1.369 + /** 1.370 + * Fills aRanges with MediaByteRanges representing the data which is cached 1.371 + * in the media cache. Stream should be pinned during call and while 1.372 + * aRanges is being used. 1.373 + */ 1.374 + virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) = 0; 1.375 + 1.376 + // Ensure that the media cache writes any data held in its partial block. 1.377 + // Called on the main thread only. 1.378 + virtual void FlushCache() { } 1.379 + 1.380 + // Notify that the last data byte range was loaded. 1.381 + virtual void NotifyLastByteRange() { } 1.382 + 1.383 + // Returns the content type of the resource. This is copied from the 1.384 + // nsIChannel when the MediaResource is created. Safe to call from 1.385 + // any thread. 1.386 + virtual const nsCString& GetContentType() const = 0; 1.387 + 1.388 + // Get the RtspMediaResource pointer if this MediaResource really is a 1.389 + // RtspMediaResource. For calling Rtsp specific functions. 1.390 + virtual RtspMediaResource* GetRtspPointer() { 1.391 + return nullptr; 1.392 + } 1.393 + 1.394 + // Return true if the stream is a live stream 1.395 + virtual bool IsRealTime() { 1.396 + return false; 1.397 + } 1.398 + 1.399 + virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { 1.400 + return 0; 1.401 + } 1.402 + 1.403 + virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { 1.404 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.405 + } 1.406 + 1.407 +protected: 1.408 + virtual ~MediaResource() {}; 1.409 + 1.410 +private: 1.411 + void Destroy(); 1.412 +}; 1.413 + 1.414 +class BaseMediaResource : public MediaResource { 1.415 +public: 1.416 + virtual nsIURI* URI() const { return mURI; } 1.417 + virtual void MoveLoadsToBackground(); 1.418 + 1.419 + virtual size_t SizeOfExcludingThis( 1.420 + MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE 1.421 + { 1.422 + // Might be useful to track in the future: 1.423 + // - mChannel 1.424 + // - mURI (possibly owned, looks like just a ref from mChannel) 1.425 + // Not owned: 1.426 + // - mDecoder 1.427 + size_t size = MediaResource::SizeOfExcludingThis(aMallocSizeOf); 1.428 + size += mContentType.SizeOfIncludingThisIfUnshared(aMallocSizeOf); 1.429 + 1.430 + return size; 1.431 + } 1.432 + 1.433 + virtual size_t SizeOfIncludingThis( 1.434 + MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE 1.435 + { 1.436 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.437 + } 1.438 + 1.439 +protected: 1.440 + BaseMediaResource(MediaDecoder* aDecoder, 1.441 + nsIChannel* aChannel, 1.442 + nsIURI* aURI, 1.443 + const nsACString& aContentType) : 1.444 + mDecoder(aDecoder), 1.445 + mChannel(aChannel), 1.446 + mURI(aURI), 1.447 + mContentType(aContentType), 1.448 + mLoadInBackground(false) 1.449 + { 1.450 + MOZ_COUNT_CTOR(BaseMediaResource); 1.451 + NS_ASSERTION(!mContentType.IsEmpty(), "Must know content type"); 1.452 + } 1.453 + virtual ~BaseMediaResource() 1.454 + { 1.455 + MOZ_COUNT_DTOR(BaseMediaResource); 1.456 + } 1.457 + 1.458 + virtual const nsCString& GetContentType() const MOZ_OVERRIDE 1.459 + { 1.460 + return mContentType; 1.461 + } 1.462 + 1.463 + // Set the request's load flags to aFlags. If the request is part of a 1.464 + // load group, the request is removed from the group, the flags are set, and 1.465 + // then the request is added back to the load group. 1.466 + void ModifyLoadFlags(nsLoadFlags aFlags); 1.467 + 1.468 + // Dispatches an event to call MediaDecoder::NotifyBytesConsumed(aNumBytes, aOffset) 1.469 + // on the main thread. This is called automatically after every read. 1.470 + void DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset); 1.471 + 1.472 + // This is not an nsCOMPointer to prevent a circular reference 1.473 + // between the decoder to the media stream object. The stream never 1.474 + // outlives the lifetime of the decoder. 1.475 + MediaDecoder* mDecoder; 1.476 + 1.477 + // Channel used to download the media data. Must be accessed 1.478 + // from the main thread only. 1.479 + nsCOMPtr<nsIChannel> mChannel; 1.480 + 1.481 + // URI in case the stream needs to be re-opened. Access from 1.482 + // main thread only. 1.483 + nsCOMPtr<nsIURI> mURI; 1.484 + 1.485 + // Content-Type of the channel. This is copied from the nsIChannel when the 1.486 + // MediaResource is created. This is constant, so accessing from any thread 1.487 + // is safe. 1.488 + const nsAutoCString mContentType; 1.489 + 1.490 + // True if MoveLoadsToBackground() has been called, i.e. the load event 1.491 + // has been fired, and all channel loads will be in the background. 1.492 + bool mLoadInBackground; 1.493 +}; 1.494 + 1.495 +/** 1.496 + * This is the MediaResource implementation that wraps Necko channels. 1.497 + * Much of its functionality is actually delegated to MediaCache via 1.498 + * an underlying MediaCacheStream. 1.499 + * 1.500 + * All synchronization is performed by MediaCacheStream; all off-main- 1.501 + * thread operations are delegated directly to that object. 1.502 + */ 1.503 +class ChannelMediaResource : public BaseMediaResource 1.504 +{ 1.505 +public: 1.506 + ChannelMediaResource(MediaDecoder* aDecoder, 1.507 + nsIChannel* aChannel, 1.508 + nsIURI* aURI, 1.509 + const nsACString& aContentType); 1.510 + ~ChannelMediaResource(); 1.511 + 1.512 + // These are called on the main thread by MediaCache. These must 1.513 + // not block or grab locks, because the media cache is holding its lock. 1.514 + // Notify that data is available from the cache. This can happen even 1.515 + // if this stream didn't read any data, since another stream might have 1.516 + // received data for the same resource. 1.517 + void CacheClientNotifyDataReceived(); 1.518 + // Notify that we reached the end of the stream. This can happen even 1.519 + // if this stream didn't read any data, since another stream might have 1.520 + // received data for the same resource. 1.521 + void CacheClientNotifyDataEnded(nsresult aStatus); 1.522 + // Notify that the principal for the cached resource changed. 1.523 + void CacheClientNotifyPrincipalChanged(); 1.524 + 1.525 + // These are called on the main thread by MediaCache. These shouldn't block, 1.526 + // but they may grab locks --- the media cache is not holding its lock 1.527 + // when these are called. 1.528 + // Start a new load at the given aOffset. The old load is cancelled 1.529 + // and no more data from the old load will be notified via 1.530 + // MediaCacheStream::NotifyDataReceived/Ended. 1.531 + // This can fail. 1.532 + nsresult CacheClientSeek(int64_t aOffset, bool aResume); 1.533 + // Suspend the current load since data is currently not wanted 1.534 + nsresult CacheClientSuspend(); 1.535 + // Resume the current load since data is wanted again 1.536 + nsresult CacheClientResume(); 1.537 + 1.538 + // Ensure that the media cache writes any data held in its partial block. 1.539 + // Called on the main thread. 1.540 + virtual void FlushCache() MOZ_OVERRIDE; 1.541 + 1.542 + // Notify that the last data byte range was loaded. 1.543 + virtual void NotifyLastByteRange() MOZ_OVERRIDE; 1.544 + 1.545 + // Main thread 1.546 + virtual nsresult Open(nsIStreamListener** aStreamListener); 1.547 + virtual nsresult Close(); 1.548 + virtual void Suspend(bool aCloseImmediately); 1.549 + virtual void Resume(); 1.550 + virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal(); 1.551 + // Return true if the stream has been closed. 1.552 + bool IsClosed() const { return mCacheStream.IsClosed(); } 1.553 + virtual bool CanClone(); 1.554 + virtual already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder); 1.555 + // Set statistics to be recorded to the object passed in. If not called, 1.556 + // |ChannelMediaResource| will create it's own statistics objects in |Open|. 1.557 + void RecordStatisticsTo(MediaChannelStatistics *aStatistics) MOZ_OVERRIDE { 1.558 + NS_ASSERTION(aStatistics, "Statistics param cannot be null!"); 1.559 + MutexAutoLock lock(mLock); 1.560 + if (!mChannelStatistics) { 1.561 + mChannelStatistics = aStatistics; 1.562 + } 1.563 + } 1.564 + virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount); 1.565 + virtual void EnsureCacheUpToDate(); 1.566 + 1.567 + // Other thread 1.568 + virtual void SetReadMode(MediaCacheStream::ReadMode aMode); 1.569 + virtual void SetPlaybackRate(uint32_t aBytesPerSecond); 1.570 + virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes); 1.571 + virtual nsresult ReadAt(int64_t offset, char* aBuffer, 1.572 + uint32_t aCount, uint32_t* aBytes); 1.573 + virtual nsresult Seek(int32_t aWhence, int64_t aOffset); 1.574 + virtual void StartSeekingForMetadata(); 1.575 + virtual void EndSeekingForMetadata(); 1.576 + virtual int64_t Tell(); 1.577 + 1.578 + // Any thread 1.579 + virtual void Pin(); 1.580 + virtual void Unpin(); 1.581 + virtual double GetDownloadRate(bool* aIsReliable); 1.582 + virtual int64_t GetLength(); 1.583 + virtual int64_t GetNextCachedData(int64_t aOffset); 1.584 + virtual int64_t GetCachedDataEnd(int64_t aOffset); 1.585 + virtual bool IsDataCachedToEndOfResource(int64_t aOffset); 1.586 + virtual bool IsSuspendedByCache(); 1.587 + virtual bool IsSuspended(); 1.588 + virtual bool IsTransportSeekable() MOZ_OVERRIDE; 1.589 + 1.590 + virtual size_t SizeOfExcludingThis( 1.591 + MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE { 1.592 + // Might be useful to track in the future: 1.593 + // - mListener (seems minor) 1.594 + // - mChannelStatistics (seems minor) 1.595 + // owned if RecordStatisticsTo is not called 1.596 + // - mDataReceivedEvent (seems minor) 1.597 + size_t size = BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf); 1.598 + size += mCacheStream.SizeOfExcludingThis(aMallocSizeOf); 1.599 + 1.600 + return size; 1.601 + } 1.602 + 1.603 + virtual size_t SizeOfIncludingThis( 1.604 + MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE { 1.605 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.606 + } 1.607 + 1.608 + class Listener MOZ_FINAL : public nsIStreamListener, 1.609 + public nsIInterfaceRequestor, 1.610 + public nsIChannelEventSink 1.611 + { 1.612 + public: 1.613 + Listener(ChannelMediaResource* aResource) : mResource(aResource) {} 1.614 + ~Listener() {} 1.615 + 1.616 + NS_DECL_ISUPPORTS 1.617 + NS_DECL_NSIREQUESTOBSERVER 1.618 + NS_DECL_NSISTREAMLISTENER 1.619 + NS_DECL_NSICHANNELEVENTSINK 1.620 + NS_DECL_NSIINTERFACEREQUESTOR 1.621 + 1.622 + void Revoke() { mResource = nullptr; } 1.623 + 1.624 + private: 1.625 + nsRefPtr<ChannelMediaResource> mResource; 1.626 + }; 1.627 + friend class Listener; 1.628 + 1.629 + nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges); 1.630 + 1.631 +protected: 1.632 + // These are called on the main thread by Listener. 1.633 + nsresult OnStartRequest(nsIRequest* aRequest); 1.634 + nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus); 1.635 + nsresult OnDataAvailable(nsIRequest* aRequest, 1.636 + nsIInputStream* aStream, 1.637 + uint32_t aCount); 1.638 + nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew, uint32_t aFlags); 1.639 + 1.640 + // Opens the channel, using an HTTP byte range request to start at mOffset 1.641 + // if possible. Main thread only. 1.642 + nsresult OpenChannel(nsIStreamListener** aStreamListener); 1.643 + nsresult RecreateChannel(); 1.644 + // Add headers to HTTP request. Main thread only. 1.645 + void SetupChannelHeaders(); 1.646 + // Closes the channel. Main thread only. 1.647 + void CloseChannel(); 1.648 + 1.649 + // Parses 'Content-Range' header and returns results via parameters. 1.650 + // Returns error if header is not available, values are not parse-able or 1.651 + // values are out of range. 1.652 + nsresult ParseContentRangeHeader(nsIHttpChannel * aHttpChan, 1.653 + int64_t& aRangeStart, 1.654 + int64_t& aRangeEnd, 1.655 + int64_t& aRangeTotal); 1.656 + 1.657 + void DoNotifyDataReceived(); 1.658 + 1.659 + static NS_METHOD CopySegmentToCache(nsIInputStream *aInStream, 1.660 + void *aClosure, 1.661 + const char *aFromSegment, 1.662 + uint32_t aToOffset, 1.663 + uint32_t aCount, 1.664 + uint32_t *aWriteCount); 1.665 + 1.666 + // Suspend the channel only if the channels is currently downloading data. 1.667 + // If it isn't we set a flag, mIgnoreResume, so that PossiblyResume knows 1.668 + // whether to acutually resume or not. 1.669 + void PossiblySuspend(); 1.670 + 1.671 + // Resume from a suspend if we actually suspended (See PossiblySuspend). 1.672 + void PossiblyResume(); 1.673 + 1.674 + // Main thread access only 1.675 + int64_t mOffset; 1.676 + nsRefPtr<Listener> mListener; 1.677 + // A data received event for the decoder that has been dispatched but has 1.678 + // not yet been processed. 1.679 + nsRevocableEventPtr<nsRunnableMethod<ChannelMediaResource, void, false> > mDataReceivedEvent; 1.680 + uint32_t mSuspendCount; 1.681 + // When this flag is set, if we get a network error we should silently 1.682 + // reopen the stream. 1.683 + bool mReopenOnError; 1.684 + // When this flag is set, we should not report the next close of the 1.685 + // channel. 1.686 + bool mIgnoreClose; 1.687 + 1.688 + // Any thread access 1.689 + MediaCacheStream mCacheStream; 1.690 + 1.691 + // This lock protects mChannelStatistics 1.692 + Mutex mLock; 1.693 + nsRefPtr<MediaChannelStatistics> mChannelStatistics; 1.694 + 1.695 + // True if we couldn't suspend the stream and we therefore don't want 1.696 + // to resume later. This is usually due to the channel not being in the 1.697 + // isPending state at the time of the suspend request. 1.698 + bool mIgnoreResume; 1.699 + 1.700 + // True if we are seeking to get the real duration of the file. 1.701 + bool mSeekingForMetadata; 1.702 + 1.703 + // Start and end offset of the bytes to be requested. 1.704 + MediaByteRange mByteRange; 1.705 + 1.706 + // True if the stream can seek into unbuffered ranged, i.e. if the 1.707 + // connection supports byte range requests. 1.708 + bool mIsTransportSeekable; 1.709 +}; 1.710 + 1.711 +} // namespace mozilla 1.712 + 1.713 +#endif