content/media/MediaCache.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/MediaCache.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,514 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef MediaCache_h_
    1.11 +#define MediaCache_h_
    1.12 +
    1.13 +#include "nsTArray.h"
    1.14 +#include "nsCOMPtr.h"
    1.15 +#include "nsHashKeys.h"
    1.16 +#include "nsTHashtable.h"
    1.17 +
    1.18 +class nsIPrincipal;
    1.19 +
    1.20 +namespace mozilla {
    1.21 +// defined in MediaResource.h
    1.22 +class ChannelMediaResource;
    1.23 +class MediaByteRange;
    1.24 +class MediaResource;
    1.25 +class ReentrantMonitorAutoEnter;
    1.26 +
    1.27 +/**
    1.28 + * Media applications want fast, "on demand" random access to media data,
    1.29 + * for pausing, seeking, etc. But we are primarily interested
    1.30 + * in transporting media data using HTTP over the Internet, which has
    1.31 + * high latency to open a connection, requires a new connection for every
    1.32 + * seek, may not even support seeking on some connections (especially
    1.33 + * live streams), and uses a push model --- data comes from the server
    1.34 + * and you don't have much control over the rate. Also, transferring data
    1.35 + * over the Internet can be slow and/or unpredictable, so we want to read
    1.36 + * ahead to buffer and cache as much data as possible.
    1.37 + * 
    1.38 + * The job of the media cache is to resolve this impedance mismatch.
    1.39 + * The media cache reads data from Necko channels into file-backed storage,
    1.40 + * and offers a random-access file-like API to the stream data
    1.41 + * (MediaCacheStream). Along the way it solves several problems:
    1.42 + * -- The cache intelligently reads ahead to prefetch data that may be
    1.43 + * needed in the future
    1.44 + * -- The size of the cache is bounded so that we don't fill up
    1.45 + * storage with read-ahead data
    1.46 + * -- Cache replacement is managed globally so that the most valuable
    1.47 + * data (across all streams) is retained
    1.48 + * -- The cache can suspend Necko channels temporarily when their data is
    1.49 + * not wanted (yet)
    1.50 + * -- The cache translates file-like seek requests to HTTP seeks,
    1.51 + * including optimizations like not triggering a new seek if it would
    1.52 + * be faster to just keep reading until we reach the seek point. The
    1.53 + * "seek to EOF" idiom to determine file size is also handled efficiently
    1.54 + * (seeking to EOF and then seeking back to the previous offset does not
    1.55 + * trigger any Necko activity)
    1.56 + * -- The cache also handles the case where the server does not support
    1.57 + * seeking
    1.58 + * -- Necko can only send data to the main thread, but MediaCacheStream
    1.59 + * can distribute data to any thread
    1.60 + * -- The cache exposes APIs so clients can detect what data is
    1.61 + * currently held
    1.62 + * 
    1.63 + * Note that although HTTP is the most important transport and we only
    1.64 + * support transport-level seeking via HTTP byte-ranges, the media cache
    1.65 + * works with any kind of Necko channels and provides random access to
    1.66 + * cached data even for, e.g., FTP streams.
    1.67 + * 
    1.68 + * The media cache is not persistent. It does not currently allow
    1.69 + * data from one load to be used by other loads, either within the same
    1.70 + * browser session or across browser sessions. The media cache file
    1.71 + * is marked "delete on close" so it will automatically disappear in the
    1.72 + * event of a browser crash or shutdown.
    1.73 + * 
    1.74 + * The media cache is block-based. Streams are divided into blocks of a
    1.75 + * fixed size (currently 4K) and we cache blocks. A single cache contains
    1.76 + * blocks for all streams.
    1.77 + * 
    1.78 + * The cache size is controlled by the media.cache_size preference
    1.79 + * (which is in KB). The default size is 500MB.
    1.80 + * 
    1.81 + * The replacement policy predicts a "time of next use" for each block
    1.82 + * in the cache. When we need to free a block, the block with the latest
    1.83 + * "time of next use" will be evicted. Blocks are divided into
    1.84 + * different classes, each class having its own predictor:
    1.85 + * FREE_BLOCK: these blocks are effectively infinitely far in the future;
    1.86 + * a free block will always be chosen for replacement before other classes
    1.87 + * of blocks.
    1.88 + * METADATA_BLOCK: these are blocks that contain data that has been read
    1.89 + * by the decoder in "metadata mode", e.g. while the decoder is searching
    1.90 + * the stream during a seek operation. These blocks are managed with an
    1.91 + * LRU policy; the "time of next use" is predicted to be as far in the
    1.92 + * future as the last use was in the past.
    1.93 + * PLAYED_BLOCK: these are blocks that have not been read in "metadata
    1.94 + * mode", and contain data behind the current decoder read point. (They
    1.95 + * may not actually have been read by the decoder, if the decoder seeked
    1.96 + * forward.) These blocks are managed with an LRU policy except that we add
    1.97 + * REPLAY_DELAY seconds of penalty to their predicted "time of next use",
    1.98 + * to reflect the uncertainty about whether replay will actually happen
    1.99 + * or not.
   1.100 + * READAHEAD_BLOCK: these are blocks that have not been read in
   1.101 + * "metadata mode" and that are entirely ahead of the current decoder
   1.102 + * read point. (They may actually have been read by the decoder in the
   1.103 + * past if the decoder has since seeked backward.) We predict the
   1.104 + * time of next use for these blocks by assuming steady playback and
   1.105 + * dividing the number of bytes between the block and the current decoder
   1.106 + * read point by the decoder's estimate of its playback rate in bytes
   1.107 + * per second. This ensures that the blocks farthest ahead are considered
   1.108 + * least valuable.
   1.109 + * For efficient prediction of the "latest time of next use", we maintain
   1.110 + * linked lists of blocks in each class, ordering blocks by time of
   1.111 + * next use. READAHEAD_BLOCKS have one linked list per stream, since their
   1.112 + * time of next use depends on stream parameters, but the other lists
   1.113 + * are global.
   1.114 + * 
   1.115 + * A block containing a current decoder read point can contain data
   1.116 + * both behind and ahead of the read point. It will be classified as a
   1.117 + * PLAYED_BLOCK but we will give it special treatment so it is never
   1.118 + * evicted --- it actually contains the highest-priority readahead data
   1.119 + * as well as played data.
   1.120 + * 
   1.121 + * "Time of next use" estimates are also used for flow control. When
   1.122 + * reading ahead we can predict the time of next use for the data that
   1.123 + * will be read. If the predicted time of next use is later then the
   1.124 + * prediction for all currently cached blocks, and the cache is full, then
   1.125 + * we should suspend reading from the Necko channel.
   1.126 + * 
   1.127 + * Unfortunately suspending the Necko channel can't immediately stop the
   1.128 + * flow of data from the server. First our desire to suspend has to be
   1.129 + * transmitted to the server (in practice, Necko stops reading from the
   1.130 + * socket, which causes the kernel to shrink its advertised TCP receive
   1.131 + * window size to zero). Then the server can stop sending the data, but
   1.132 + * we will receive data roughly corresponding to the product of the link
   1.133 + * bandwidth multiplied by the round-trip latency. We deal with this by
   1.134 + * letting the cache overflow temporarily and then trimming it back by
   1.135 + * moving overflowing blocks back into the body of the cache, replacing
   1.136 + * less valuable blocks as they become available. We try to avoid simply
   1.137 + * discarding overflowing readahead data.
   1.138 + * 
   1.139 + * All changes to the actual contents of the cache happen on the main
   1.140 + * thread, since that's where Necko's notifications happen.
   1.141 + *
   1.142 + * The media cache maintains at most one Necko channel for each stream.
   1.143 + * (In the future it might be advantageous to relax this, e.g. so that a
   1.144 + * seek to near the end of the file can happen without disturbing
   1.145 + * the loading of data from the beginning of the file.) The Necko channel
   1.146 + * is managed through ChannelMediaResource; MediaCache does not
   1.147 + * depend on Necko directly.
   1.148 + * 
   1.149 + * Every time something changes that might affect whether we want to
   1.150 + * read from a Necko channel, or whether we want to seek on the Necko
   1.151 + * channel --- such as data arriving or data being consumed by the
   1.152 + * decoder --- we asynchronously trigger MediaCache::Update on the main
   1.153 + * thread. That method implements most cache policy. It evaluates for
   1.154 + * each stream whether we want to suspend or resume the stream and what
   1.155 + * offset we should seek to, if any. It is also responsible for trimming
   1.156 + * back the cache size to its desired limit by moving overflowing blocks
   1.157 + * into the main part of the cache.
   1.158 + * 
   1.159 + * Streams can be opened in non-seekable mode. In non-seekable mode,
   1.160 + * the cache will only call ChannelMediaResource::CacheClientSeek with
   1.161 + * a 0 offset. The cache tries hard not to discard readahead data
   1.162 + * for non-seekable streams, since that could trigger a potentially
   1.163 + * disastrous re-read of the entire stream. It's up to cache clients
   1.164 + * to try to avoid requesting seeks on such streams.
   1.165 + * 
   1.166 + * MediaCache has a single internal monitor for all synchronization.
   1.167 + * This is treated as the lowest level monitor in the media code. So,
   1.168 + * we must not acquire any MediaDecoder locks or MediaResource locks
   1.169 + * while holding the MediaCache lock. But it's OK to hold those locks
   1.170 + * and then get the MediaCache lock.
   1.171 + * 
   1.172 + * MediaCache associates a principal with each stream. CacheClientSeek
   1.173 + * can trigger new HTTP requests; due to redirects to other domains,
   1.174 + * each HTTP load can return data with a different principal. This
   1.175 + * principal must be passed to NotifyDataReceived, and MediaCache
   1.176 + * will detect when different principals are associated with data in the
   1.177 + * same stream, and replace them with a null principal.
   1.178 + */
   1.179 +class MediaCache;
   1.180 +
   1.181 +/**
   1.182 + * If the cache fails to initialize then Init will fail, so nonstatic
   1.183 + * methods of this class can assume gMediaCache is non-null.
   1.184 + * 
   1.185 + * This class can be directly embedded as a value.
   1.186 + */
   1.187 +class MediaCacheStream {
   1.188 +public:
   1.189 +  enum {
   1.190 +    // This needs to be a power of two
   1.191 +    BLOCK_SIZE = 32768
   1.192 +  };
   1.193 +  enum ReadMode {
   1.194 +    MODE_METADATA,
   1.195 +    MODE_PLAYBACK
   1.196 +  };
   1.197 +
   1.198 +  // aClient provides the underlying transport that cache will use to read
   1.199 +  // data for this stream.
   1.200 +  MediaCacheStream(ChannelMediaResource* aClient);
   1.201 +  ~MediaCacheStream();
   1.202 +
   1.203 +  // Set up this stream with the cache. Can fail on OOM. One
   1.204 +  // of InitAsClone or Init must be called before any other method on
   1.205 +  // this class. Does nothing if already initialized.
   1.206 +  nsresult Init();
   1.207 +
   1.208 +  // Set up this stream with the cache, assuming it's for the same data
   1.209 +  // as the aOriginal stream. Can fail on OOM. Exactly one
   1.210 +  // of InitAsClone or Init must be called before any other method on
   1.211 +  // this class. Does nothing if already initialized.
   1.212 +  nsresult InitAsClone(MediaCacheStream* aOriginal);
   1.213 +
   1.214 +  // These are called on the main thread.
   1.215 +  // Tell us whether the stream is seekable or not. Non-seekable streams
   1.216 +  // will always pass 0 for aOffset to CacheClientSeek. This should only
   1.217 +  // be called while the stream is at channel offset 0. Seekability can
   1.218 +  // change during the lifetime of the MediaCacheStream --- every time
   1.219 +  // we do an HTTP load the seekability may be different (and sometimes
   1.220 +  // is, in practice, due to the effects of caching proxies).
   1.221 +  void SetTransportSeekable(bool aIsTransportSeekable);
   1.222 +  // This must be called (and return) before the ChannelMediaResource
   1.223 +  // used to create this MediaCacheStream is deleted.
   1.224 +  void Close();
   1.225 +  // This returns true when the stream has been closed
   1.226 +  bool IsClosed() const { return mClosed; }
   1.227 +  // Returns true when this stream is can be shared by a new resource load
   1.228 +  bool IsAvailableForSharing() const
   1.229 +  {
   1.230 +    return !mClosed &&
   1.231 +      (!mDidNotifyDataEnded || NS_SUCCEEDED(mNotifyDataEndedStatus));
   1.232 +  }
   1.233 +  // Get the principal for this stream. Anything accessing the contents of
   1.234 +  // this stream must have a principal that subsumes this principal.
   1.235 +  nsIPrincipal* GetCurrentPrincipal() { return mPrincipal; }
   1.236 +  // Ensure a global media cache update has run with this stream present.
   1.237 +  // This ensures the cache has had a chance to suspend or unsuspend this stream.
   1.238 +  // Called only on main thread. This can change the state of streams, fire
   1.239 +  // notifications, etc.
   1.240 +  void EnsureCacheUpdate();
   1.241 +
   1.242 +  // These callbacks are called on the main thread by the client
   1.243 +  // when data has been received via the channel.
   1.244 +  // Tells the cache what the server said the data length is going to be.
   1.245 +  // The actual data length may be greater (we receive more data than
   1.246 +  // specified) or smaller (the stream ends before we reach the given
   1.247 +  // length), because servers can lie. The server's reported data length
   1.248 +  // *and* the actual data length can even vary over time because a
   1.249 +  // misbehaving server may feed us a different stream after each seek
   1.250 +  // operation. So this is really just a hint. The cache may however
   1.251 +  // stop reading (suspend the channel) when it thinks we've read all the
   1.252 +  // data available based on an incorrect reported length. Seeks relative
   1.253 +  // EOF also depend on the reported length if we haven't managed to
   1.254 +  // read the whole stream yet.
   1.255 +  void NotifyDataLength(int64_t aLength);
   1.256 +  // Notifies the cache that a load has begun. We pass the offset
   1.257 +  // because in some cases the offset might not be what the cache
   1.258 +  // requested. In particular we might unexpectedly start providing
   1.259 +  // data at offset 0. This need not be called if the offset is the
   1.260 +  // offset that the cache requested in
   1.261 +  // ChannelMediaResource::CacheClientSeek. This can be called at any
   1.262 +  // time by the client, not just after a CacheClientSeek.
   1.263 +  void NotifyDataStarted(int64_t aOffset);
   1.264 +  // Notifies the cache that data has been received. The stream already
   1.265 +  // knows the offset because data is received in sequence and
   1.266 +  // the starting offset is known via NotifyDataStarted or because
   1.267 +  // the cache requested the offset in
   1.268 +  // ChannelMediaResource::CacheClientSeek, or because it defaulted to 0.
   1.269 +  // We pass in the principal that was used to load this data.
   1.270 +  void NotifyDataReceived(int64_t aSize, const char* aData,
   1.271 +                          nsIPrincipal* aPrincipal);
   1.272 +  // Notifies the cache that the current bytes should be written to disk.
   1.273 +  // Called on the main thread.
   1.274 +  void FlushPartialBlock();
   1.275 +  // Notifies the cache that the channel has closed with the given status.
   1.276 +  void NotifyDataEnded(nsresult aStatus);
   1.277 +
   1.278 +  // These methods can be called on any thread.
   1.279 +  // Cached blocks associated with this stream will not be evicted
   1.280 +  // while the stream is pinned.
   1.281 +  void Pin();
   1.282 +  void Unpin();
   1.283 +  // See comments above for NotifyDataLength about how the length
   1.284 +  // can vary over time. Returns -1 if no length is known. Returns the
   1.285 +  // reported length if we haven't got any better information. If
   1.286 +  // the stream ended normally we return the length we actually got.
   1.287 +  // If we've successfully read data beyond the originally reported length,
   1.288 +  // we return the end of the data we've read.
   1.289 +  int64_t GetLength();
   1.290 +  // Returns the unique resource ID. Call only on the main thread or while
   1.291 +  // holding the media cache lock.
   1.292 +  int64_t GetResourceID() { return mResourceID; }
   1.293 +  // Returns the end of the bytes starting at the given offset
   1.294 +  // which are in cache.
   1.295 +  int64_t GetCachedDataEnd(int64_t aOffset);
   1.296 +  // Returns the offset of the first byte of cached data at or after aOffset,
   1.297 +  // or -1 if there is no such cached data.
   1.298 +  int64_t GetNextCachedData(int64_t aOffset);
   1.299 +  // Fills aRanges with the ByteRanges representing the data which is currently
   1.300 +  // cached. Locks the media cache while running, to prevent any ranges
   1.301 +  // growing. The stream should be pinned while this runs and while its results
   1.302 +  // are used, to ensure no data is evicted.
   1.303 +  nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges);
   1.304 +
   1.305 +  // Reads from buffered data only. Will fail if not all data to be read is
   1.306 +  // in the cache. Will not mark blocks as read. Can be called from the main
   1.307 +  // thread. It's the caller's responsibility to wrap the call in a pin/unpin,
   1.308 +  // and also to check that the range they want is cached before calling this.
   1.309 +  nsresult ReadFromCache(char* aBuffer,
   1.310 +                         int64_t aOffset,
   1.311 +                         int64_t aCount);
   1.312 +
   1.313 +  // IsDataCachedToEndOfStream returns true if all the data from
   1.314 +  // aOffset to the end of the stream (the server-reported end, if the
   1.315 +  // real end is not known) is in cache. If we know nothing about the
   1.316 +  // end of the stream, this returns false.
   1.317 +  bool IsDataCachedToEndOfStream(int64_t aOffset);
   1.318 +  // The mode is initially MODE_PLAYBACK.
   1.319 +  void SetReadMode(ReadMode aMode);
   1.320 +  // This is the client's estimate of the playback rate assuming
   1.321 +  // the media plays continuously. The cache can't guess this itself
   1.322 +  // because it doesn't know when the decoder was paused, buffering, etc.
   1.323 +  // Do not pass zero.
   1.324 +  void SetPlaybackRate(uint32_t aBytesPerSecond);
   1.325 +  // Returns the last set value of SetTransportSeekable.
   1.326 +  bool IsTransportSeekable();
   1.327 +
   1.328 +  // Returns true when all streams for this resource are suspended or their
   1.329 +  // channel has ended.
   1.330 +  bool AreAllStreamsForResourceSuspended();
   1.331 +
   1.332 +  // These methods must be called on a different thread from the main
   1.333 +  // thread. They should always be called on the same thread for a given
   1.334 +  // stream.
   1.335 +  // This can fail when aWhence is NS_SEEK_END and no stream length
   1.336 +  // is known.
   1.337 +  nsresult Seek(int32_t aWhence, int64_t aOffset);
   1.338 +  int64_t Tell();
   1.339 +  // *aBytes gets the number of bytes that were actually read. This can
   1.340 +  // be less than aCount. If the first byte of data is not in the cache,
   1.341 +  // this will block until the data is available or the stream is
   1.342 +  // closed, otherwise it won't block.
   1.343 +  nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes);
   1.344 +  // Seeks to aOffset in the stream then performs a Read operation. See
   1.345 +  // 'Read' for argument and return details.
   1.346 +  nsresult ReadAt(int64_t aOffset, char* aBuffer,
   1.347 +                  uint32_t aCount, uint32_t* aBytes);
   1.348 +
   1.349 +  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
   1.350 +
   1.351 +private:
   1.352 +  friend class MediaCache;
   1.353 +
   1.354 +  /**
   1.355 +   * A doubly-linked list of blocks. Add/Remove/Get methods are all
   1.356 +   * constant time. We declare this here so that a stream can contain a
   1.357 +   * BlockList of its read-ahead blocks. Blocks are referred to by index
   1.358 +   * into the MediaCache::mIndex array.
   1.359 +   * 
   1.360 +   * Blocks can belong to more than one list at the same time, because
   1.361 +   * the next/prev pointers are not stored in the block.
   1.362 +   */
   1.363 +  class BlockList {
   1.364 +  public:
   1.365 +    BlockList() : mFirstBlock(-1), mCount(0) {}
   1.366 +    ~BlockList() {
   1.367 +      NS_ASSERTION(mFirstBlock == -1 && mCount == 0,
   1.368 +                   "Destroying non-empty block list");
   1.369 +    }
   1.370 +    void AddFirstBlock(int32_t aBlock);
   1.371 +    void AddAfter(int32_t aBlock, int32_t aBefore);
   1.372 +    void RemoveBlock(int32_t aBlock);
   1.373 +    // Returns the first block in the list, or -1 if empty
   1.374 +    int32_t GetFirstBlock() const { return mFirstBlock; }
   1.375 +    // Returns the last block in the list, or -1 if empty
   1.376 +    int32_t GetLastBlock() const;
   1.377 +    // Returns the next block in the list after aBlock or -1 if
   1.378 +    // aBlock is the last block
   1.379 +    int32_t GetNextBlock(int32_t aBlock) const;
   1.380 +    // Returns the previous block in the list before aBlock or -1 if
   1.381 +    // aBlock is the first block
   1.382 +    int32_t GetPrevBlock(int32_t aBlock) const;
   1.383 +    bool IsEmpty() const { return mFirstBlock < 0; }
   1.384 +    int32_t GetCount() const { return mCount; }
   1.385 +    // The contents of aBlockIndex1 and aBlockIndex2 have been swapped
   1.386 +    void NotifyBlockSwapped(int32_t aBlockIndex1, int32_t aBlockIndex2);
   1.387 +#ifdef DEBUG
   1.388 +    // Verify linked-list invariants
   1.389 +    void Verify();
   1.390 +#else
   1.391 +    void Verify() {}
   1.392 +#endif
   1.393 +
   1.394 +    size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   1.395 +
   1.396 +  private:
   1.397 +    struct Entry : public nsUint32HashKey {
   1.398 +      Entry(KeyTypePointer aKey) : nsUint32HashKey(aKey) { }
   1.399 +      Entry(const Entry& toCopy) : nsUint32HashKey(&toCopy.GetKey()),
   1.400 +        mNextBlock(toCopy.mNextBlock), mPrevBlock(toCopy.mPrevBlock) {}
   1.401 +
   1.402 +      int32_t mNextBlock;
   1.403 +      int32_t mPrevBlock;
   1.404 +    };
   1.405 +    nsTHashtable<Entry> mEntries;
   1.406 +
   1.407 +    // The index of the first block in the list, or -1 if the list is empty.
   1.408 +    int32_t mFirstBlock;
   1.409 +    // The number of blocks in the list.
   1.410 +    int32_t mCount;
   1.411 +  };
   1.412 +
   1.413 +  // Returns the end of the bytes starting at the given offset
   1.414 +  // which are in cache.
   1.415 +  // This method assumes that the cache monitor is held and can be called on
   1.416 +  // any thread.
   1.417 +  int64_t GetCachedDataEndInternal(int64_t aOffset);
   1.418 +  // Returns the offset of the first byte of cached data at or after aOffset,
   1.419 +  // or -1 if there is no such cached data.
   1.420 +  // This method assumes that the cache monitor is held and can be called on
   1.421 +  // any thread.
   1.422 +  int64_t GetNextCachedDataInternal(int64_t aOffset);
   1.423 +  // Writes |mPartialBlock| to disk.
   1.424 +  // Used by |NotifyDataEnded| and |FlushPartialBlock|.
   1.425 +  // If |aNotifyAll| is true, this function will wake up readers who may be
   1.426 +  // waiting on the media cache monitor. Called on the main thread only.
   1.427 +  void FlushPartialBlockInternal(bool aNotify);
   1.428 +  // A helper function to do the work of closing the stream. Assumes
   1.429 +  // that the cache monitor is held. Main thread only.
   1.430 +  // aReentrantMonitor is the nsAutoReentrantMonitor wrapper holding the cache monitor.
   1.431 +  // This is used to NotifyAll to wake up threads that might be
   1.432 +  // blocked on reading from this stream.
   1.433 +  void CloseInternal(ReentrantMonitorAutoEnter& aReentrantMonitor);
   1.434 +  // Update mPrincipal given that data has been received from aPrincipal
   1.435 +  bool UpdatePrincipal(nsIPrincipal* aPrincipal);
   1.436 +
   1.437 +  // These fields are main-thread-only.
   1.438 +  ChannelMediaResource*  mClient;
   1.439 +  nsCOMPtr<nsIPrincipal> mPrincipal;
   1.440 +  // Set to true when Init or InitAsClone has been called
   1.441 +  bool                   mInitialized;
   1.442 +  // Set to true when MediaCache::Update() has finished while this stream
   1.443 +  // was present.
   1.444 +  bool                   mHasHadUpdate;
   1.445 +  // Set to true when the stream has been closed either explicitly or
   1.446 +  // due to an internal cache error
   1.447 +  bool                   mClosed;
   1.448 +  // True if CacheClientNotifyDataEnded has been called for this stream.
   1.449 +  bool                   mDidNotifyDataEnded;
   1.450 +
   1.451 +  // The following fields must be written holding the cache's monitor and
   1.452 +  // only on the main thread, thus can be read either on the main thread
   1.453 +  // or while holding the cache's monitor.
   1.454 +
   1.455 +  // This is a unique ID representing the resource we're loading.
   1.456 +  // All streams with the same mResourceID are loading the same
   1.457 +  // underlying resource and should share data.
   1.458 +  int64_t mResourceID;
   1.459 +  // The last reported seekability state for the underlying channel
   1.460 +  bool mIsTransportSeekable;
   1.461 +  // True if the cache has suspended our channel because the cache is
   1.462 +  // full and the priority of the data that would be received is lower
   1.463 +  // than the priority of the data already in the cache
   1.464 +  bool mCacheSuspended;
   1.465 +  // True if the channel ended and we haven't seeked it again.
   1.466 +  bool mChannelEnded;
   1.467 +  // The offset where the next data from the channel will arrive
   1.468 +  int64_t      mChannelOffset;
   1.469 +  // The reported or discovered length of the data, or -1 if nothing is
   1.470 +  // known
   1.471 +  int64_t      mStreamLength;
   1.472 +
   1.473 +  // The following fields are protected by the cache's monitor can can be written
   1.474 +  // by any thread.
   1.475 +
   1.476 +  // The offset where the reader is positioned in the stream
   1.477 +  int64_t           mStreamOffset;
   1.478 +  // For each block in the stream data, maps to the cache entry for the
   1.479 +  // block, or -1 if the block is not cached.
   1.480 +  nsTArray<int32_t> mBlocks;
   1.481 +  // The list of read-ahead blocks, ordered by stream offset; the first
   1.482 +  // block is the earliest in the stream (so the last block will be the
   1.483 +  // least valuable).
   1.484 +  BlockList         mReadaheadBlocks;
   1.485 +  // The list of metadata blocks; the first block is the most recently used
   1.486 +  BlockList         mMetadataBlocks;
   1.487 +  // The list of played-back blocks; the first block is the most recently used
   1.488 +  BlockList         mPlayedBlocks;
   1.489 +  // The last reported estimate of the decoder's playback rate
   1.490 +  uint32_t          mPlaybackBytesPerSecond;
   1.491 +  // The number of times this stream has been Pinned without a
   1.492 +  // corresponding Unpin
   1.493 +  uint32_t          mPinCount;
   1.494 +  // The status used when we did CacheClientNotifyDataEnded. Only valid
   1.495 +  // when mDidNotifyDataEnded is true.
   1.496 +  nsresult          mNotifyDataEndedStatus;
   1.497 +  // The last reported read mode
   1.498 +  ReadMode          mCurrentMode;
   1.499 +  // True if some data in mPartialBlockBuffer has been read as metadata
   1.500 +  bool              mMetadataInPartialBlockBuffer;
   1.501 +
   1.502 +  // The following field is protected by the cache's monitor but are
   1.503 +  // only written on the main thread.
   1.504 +
   1.505 +  // Data received for the block containing mChannelOffset. Data needs
   1.506 +  // to wait here so we can write back a complete block. The first
   1.507 +  // mChannelOffset%BLOCK_SIZE bytes have been filled in with good data,
   1.508 +  // the rest are garbage.
   1.509 +  // Use int64_t so that the data is well-aligned.
   1.510 +  // Heap allocate this buffer since the exact power-of-2 will cause allocation
   1.511 +  // slop when combined with the rest of the object members.
   1.512 +  nsAutoArrayPtr<int64_t> mPartialBlockBuffer;
   1.513 +};
   1.514 +
   1.515 +} // namespace mozilla
   1.516 +
   1.517 +#endif

mercurial