content/media/MediaResource.h

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     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 #if !defined(MediaResource_h_)
     7 #define MediaResource_h_
     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"
    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;
    26 static const uint32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416;
    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;
    33 class nsIHttpChannel;
    34 class nsIPrincipal;
    36 namespace mozilla {
    38 class MediaDecoder;
    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(); }
    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   }
    66   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaChannelStatistics)
    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 };
   121 // Forward declaration for use in MediaByteRange.
   122 class TimestampedMediaByteRange;
   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) {}
   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   }
   136   MediaByteRange(TimestampedMediaByteRange& aByteRange);
   138   bool IsNull() const {
   139     return mStart == 0 && mEnd == 0;
   140   }
   142   // Clears byte range values.
   143   void Clear() {
   144     mStart = 0;
   145     mEnd = 0;
   146   }
   148   int64_t mStart, mEnd;
   149 };
   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) {}
   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   }
   163   bool IsNull() const {
   164     return MediaByteRange::IsNull() && mStartTime == -1;
   165   }
   167   // Clears byte range values.
   168   void Clear() {
   169     MediaByteRange::Clear();
   170     mStartTime = -1;
   171   }
   173   // In usecs.
   174   int64_t mStartTime;
   175 };
   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 }
   183 class RtspMediaResource;
   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
   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) { }
   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() {}
   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;
   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);
   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;
   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;
   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() { }
   377   // Notify that the last data byte range was loaded.
   378   virtual void NotifyLastByteRange() { }
   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;
   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   }
   391   // Return true if the stream is a live stream
   392   virtual bool IsRealTime() {
   393     return false;
   394   }
   396   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
   397     return 0;
   398   }
   400   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
   401     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   402   }
   404 protected:
   405   virtual ~MediaResource() {};
   407 private:
   408   void Destroy();
   409 };
   411 class BaseMediaResource : public MediaResource {
   412 public:
   413   virtual nsIURI* URI() const { return mURI; }
   414   virtual void MoveLoadsToBackground();
   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);
   427     return size;
   428   }
   430   virtual size_t SizeOfIncludingThis(
   431                   MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   432   {
   433     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   434   }
   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   }
   455   virtual const nsCString& GetContentType() const MOZ_OVERRIDE
   456   {
   457     return mContentType;
   458   }
   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);
   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);
   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;
   474   // Channel used to download the media data. Must be accessed
   475   // from the main thread only.
   476   nsCOMPtr<nsIChannel> mChannel;
   478   // URI in case the stream needs to be re-opened. Access from
   479   // main thread only.
   480   nsCOMPtr<nsIURI> mURI;
   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;
   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 };
   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();
   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();
   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();
   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;
   539   // Notify that the last data byte range was loaded.
   540   virtual void NotifyLastByteRange() MOZ_OVERRIDE;
   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();
   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();
   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;
   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);
   597     return size;
   598   }
   600   virtual size_t SizeOfIncludingThis(
   601                       MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE {
   602     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   603   }
   605   class Listener MOZ_FINAL : public nsIStreamListener,
   606                              public nsIInterfaceRequestor,
   607                              public nsIChannelEventSink
   608   {
   609   public:
   610     Listener(ChannelMediaResource* aResource) : mResource(aResource) {}
   611     ~Listener() {}
   613     NS_DECL_ISUPPORTS
   614     NS_DECL_NSIREQUESTOBSERVER
   615     NS_DECL_NSISTREAMLISTENER
   616     NS_DECL_NSICHANNELEVENTSINK
   617     NS_DECL_NSIINTERFACEREQUESTOR
   619     void Revoke() { mResource = nullptr; }
   621   private:
   622     nsRefPtr<ChannelMediaResource> mResource;
   623   };
   624   friend class Listener;
   626   nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges);
   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);
   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();
   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);
   654   void DoNotifyDataReceived();
   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);
   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();
   668   // Resume from a suspend if we actually suspended (See PossiblySuspend).
   669   void PossiblyResume();
   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;
   685   // Any thread access
   686   MediaCacheStream mCacheStream;
   688   // This lock protects mChannelStatistics
   689   Mutex               mLock;
   690   nsRefPtr<MediaChannelStatistics> mChannelStatistics;
   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;
   697   // True if we are seeking to get the real duration of the file.
   698   bool mSeekingForMetadata;
   700   // Start and end offset of the bytes to be requested.
   701   MediaByteRange mByteRange;
   703   // True if the stream can seek into unbuffered ranged, i.e. if the
   704   // connection supports byte range requests.
   705   bool mIsTransportSeekable;
   706 };
   708 } // namespace mozilla
   710 #endif

mercurial