LCOV - code coverage report
Current view: directory - content/media - nsMediaCache.h (source / functions) Found Hit Coverage
Test: app.info Lines: 17 0 0.0 %
Date: 2012-06-02 Functions: 12 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is the Mozilla Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *  Robert O'Callahan <robert@ocallahan.org>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #ifndef nsMediaCache_h_
      40                 : #define nsMediaCache_h_
      41                 : 
      42                 : #include "nsTArray.h"
      43                 : #include "nsIPrincipal.h"
      44                 : #include "nsCOMPtr.h"
      45                 : 
      46                 : namespace mozilla {
      47                 : // defined in MediaResource.h
      48                 : class ChannelMediaResource;
      49                 : class MediaByteRange;
      50                 : class MediaResource;
      51                 : class ReentrantMonitorAutoEnter;
      52                 : }
      53                 : 
      54                 : /**
      55                 :  * Media applications want fast, "on demand" random access to media data,
      56                 :  * for pausing, seeking, etc. But we are primarily interested
      57                 :  * in transporting media data using HTTP over the Internet, which has
      58                 :  * high latency to open a connection, requires a new connection for every
      59                 :  * seek, may not even support seeking on some connections (especially
      60                 :  * live streams), and uses a push model --- data comes from the server
      61                 :  * and you don't have much control over the rate. Also, transferring data
      62                 :  * over the Internet can be slow and/or unpredictable, so we want to read
      63                 :  * ahead to buffer and cache as much data as possible.
      64                 :  * 
      65                 :  * The job of the media cache is to resolve this impedance mismatch.
      66                 :  * The media cache reads data from Necko channels into file-backed storage,
      67                 :  * and offers a random-access file-like API to the stream data
      68                 :  * (nsMediaCacheStream). Along the way it solves several problems:
      69                 :  * -- The cache intelligently reads ahead to prefetch data that may be
      70                 :  * needed in the future
      71                 :  * -- The size of the cache is bounded so that we don't fill up
      72                 :  * storage with read-ahead data
      73                 :  * -- Cache replacement is managed globally so that the most valuable
      74                 :  * data (across all streams) is retained
      75                 :  * -- The cache can suspend Necko channels temporarily when their data is
      76                 :  * not wanted (yet)
      77                 :  * -- The cache translates file-like seek requests to HTTP seeks,
      78                 :  * including optimizations like not triggering a new seek if it would
      79                 :  * be faster to just keep reading until we reach the seek point. The
      80                 :  * "seek to EOF" idiom to determine file size is also handled efficiently
      81                 :  * (seeking to EOF and then seeking back to the previous offset does not
      82                 :  * trigger any Necko activity)
      83                 :  * -- The cache also handles the case where the server does not support
      84                 :  * seeking
      85                 :  * -- Necko can only send data to the main thread, but nsMediaCacheStream
      86                 :  * can distribute data to any thread
      87                 :  * -- The cache exposes APIs so clients can detect what data is
      88                 :  * currently held
      89                 :  * 
      90                 :  * Note that although HTTP is the most important transport and we only
      91                 :  * support transport-level seeking via HTTP byte-ranges, the media cache
      92                 :  * works with any kind of Necko channels and provides random access to
      93                 :  * cached data even for, e.g., FTP streams.
      94                 :  * 
      95                 :  * The media cache is not persistent. It does not currently allow
      96                 :  * data from one load to be used by other loads, either within the same
      97                 :  * browser session or across browser sessions. The media cache file
      98                 :  * is marked "delete on close" so it will automatically disappear in the
      99                 :  * event of a browser crash or shutdown.
     100                 :  * 
     101                 :  * The media cache is block-based. Streams are divided into blocks of a
     102                 :  * fixed size (currently 4K) and we cache blocks. A single cache contains
     103                 :  * blocks for all streams.
     104                 :  * 
     105                 :  * The cache size is controlled by the media.cache_size preference
     106                 :  * (which is in KB). The default size is 500MB.
     107                 :  * 
     108                 :  * The replacement policy predicts a "time of next use" for each block
     109                 :  * in the cache. When we need to free a block, the block with the latest
     110                 :  * "time of next use" will be evicted. Blocks are divided into
     111                 :  * different classes, each class having its own predictor:
     112                 :  * FREE_BLOCK: these blocks are effectively infinitely far in the future;
     113                 :  * a free block will always be chosen for replacement before other classes
     114                 :  * of blocks.
     115                 :  * METADATA_BLOCK: these are blocks that contain data that has been read
     116                 :  * by the decoder in "metadata mode", e.g. while the decoder is searching
     117                 :  * the stream during a seek operation. These blocks are managed with an
     118                 :  * LRU policy; the "time of next use" is predicted to be as far in the
     119                 :  * future as the last use was in the past.
     120                 :  * PLAYED_BLOCK: these are blocks that have not been read in "metadata
     121                 :  * mode", and contain data behind the current decoder read point. (They
     122                 :  * may not actually have been read by the decoder, if the decoder seeked
     123                 :  * forward.) These blocks are managed with an LRU policy except that we add
     124                 :  * REPLAY_DELAY seconds of penalty to their predicted "time of next use",
     125                 :  * to reflect the uncertainty about whether replay will actually happen
     126                 :  * or not.
     127                 :  * READAHEAD_BLOCK: these are blocks that have not been read in
     128                 :  * "metadata mode" and that are entirely ahead of the current decoder
     129                 :  * read point. (They may actually have been read by the decoder in the
     130                 :  * past if the decoder has since seeked backward.) We predict the
     131                 :  * time of next use for these blocks by assuming steady playback and
     132                 :  * dividing the number of bytes between the block and the current decoder
     133                 :  * read point by the decoder's estimate of its playback rate in bytes
     134                 :  * per second. This ensures that the blocks farthest ahead are considered
     135                 :  * least valuable.
     136                 :  * For efficient prediction of the "latest time of next use", we maintain
     137                 :  * linked lists of blocks in each class, ordering blocks by time of
     138                 :  * next use. READAHEAD_BLOCKS have one linked list per stream, since their
     139                 :  * time of next use depends on stream parameters, but the other lists
     140                 :  * are global.
     141                 :  * 
     142                 :  * A block containing a current decoder read point can contain data
     143                 :  * both behind and ahead of the read point. It will be classified as a
     144                 :  * PLAYED_BLOCK but we will give it special treatment so it is never
     145                 :  * evicted --- it actually contains the highest-priority readahead data
     146                 :  * as well as played data.
     147                 :  * 
     148                 :  * "Time of next use" estimates are also used for flow control. When
     149                 :  * reading ahead we can predict the time of next use for the data that
     150                 :  * will be read. If the predicted time of next use is later then the
     151                 :  * prediction for all currently cached blocks, and the cache is full, then
     152                 :  * we should suspend reading from the Necko channel.
     153                 :  * 
     154                 :  * Unfortunately suspending the Necko channel can't immediately stop the
     155                 :  * flow of data from the server. First our desire to suspend has to be
     156                 :  * transmitted to the server (in practice, Necko stops reading from the
     157                 :  * socket, which causes the kernel to shrink its advertised TCP receive
     158                 :  * window size to zero). Then the server can stop sending the data, but
     159                 :  * we will receive data roughly corresponding to the product of the link
     160                 :  * bandwidth multiplied by the round-trip latency. We deal with this by
     161                 :  * letting the cache overflow temporarily and then trimming it back by
     162                 :  * moving overflowing blocks back into the body of the cache, replacing
     163                 :  * less valuable blocks as they become available. We try to avoid simply
     164                 :  * discarding overflowing readahead data.
     165                 :  * 
     166                 :  * All changes to the actual contents of the cache happen on the main
     167                 :  * thread, since that's where Necko's notifications happen.
     168                 :  *
     169                 :  * The media cache maintains at most one Necko channel for each stream.
     170                 :  * (In the future it might be advantageous to relax this, e.g. so that a
     171                 :  * seek to near the end of the file can happen without disturbing
     172                 :  * the loading of data from the beginning of the file.) The Necko channel
     173                 :  * is managed through ChannelMediaResource; nsMediaCache does not
     174                 :  * depend on Necko directly.
     175                 :  * 
     176                 :  * Every time something changes that might affect whether we want to
     177                 :  * read from a Necko channel, or whether we want to seek on the Necko
     178                 :  * channel --- such as data arriving or data being consumed by the
     179                 :  * decoder --- we asynchronously trigger nsMediaCache::Update on the main
     180                 :  * thread. That method implements most cache policy. It evaluates for
     181                 :  * each stream whether we want to suspend or resume the stream and what
     182                 :  * offset we should seek to, if any. It is also responsible for trimming
     183                 :  * back the cache size to its desired limit by moving overflowing blocks
     184                 :  * into the main part of the cache.
     185                 :  * 
     186                 :  * Streams can be opened in non-seekable mode. In non-seekable mode,
     187                 :  * the cache will only call ChannelMediaResource::CacheClientSeek with
     188                 :  * a 0 offset. The cache tries hard not to discard readahead data
     189                 :  * for non-seekable streams, since that could trigger a potentially
     190                 :  * disastrous re-read of the entire stream. It's up to cache clients
     191                 :  * to try to avoid requesting seeks on such streams.
     192                 :  * 
     193                 :  * nsMediaCache has a single internal monitor for all synchronization.
     194                 :  * This is treated as the lowest level monitor in the media code. So,
     195                 :  * we must not acquire any nsMediaDecoder locks or MediaResource locks
     196                 :  * while holding the nsMediaCache lock. But it's OK to hold those locks
     197                 :  * and then get the nsMediaCache lock.
     198                 :  * 
     199                 :  * nsMediaCache associates a principal with each stream. CacheClientSeek
     200                 :  * can trigger new HTTP requests; due to redirects to other domains,
     201                 :  * each HTTP load can return data with a different principal. This
     202                 :  * principal must be passed to NotifyDataReceived, and nsMediaCache
     203                 :  * will detect when different principals are associated with data in the
     204                 :  * same stream, and replace them with a null principal.
     205                 :  */
     206                 : class nsMediaCache;
     207                 : 
     208                 : /**
     209                 :  * If the cache fails to initialize then Init will fail, so nonstatic
     210                 :  * methods of this class can assume gMediaCache is non-null.
     211                 :  * 
     212                 :  * This class can be directly embedded as a value.
     213                 :  */
     214                 : class nsMediaCacheStream {
     215                 : public:
     216                 :   typedef mozilla::ChannelMediaResource ChannelMediaResource;
     217                 :   typedef mozilla::MediaByteRange MediaByteRange;
     218                 :   typedef mozilla::MediaResource MediaResource;
     219                 :   typedef mozilla::ReentrantMonitorAutoEnter ReentrantMonitorAutoEnter;
     220                 : 
     221                 :   enum {
     222                 :     // This needs to be a power of two
     223                 :     BLOCK_SIZE = 32768
     224                 :   };
     225                 :   enum ReadMode {
     226                 :     MODE_METADATA,
     227                 :     MODE_PLAYBACK
     228                 :   };
     229                 : 
     230                 :   // aClient provides the underlying transport that cache will use to read
     231                 :   // data for this stream.
     232               0 :   nsMediaCacheStream(ChannelMediaResource* aClient)
     233                 :     : mClient(aClient), mResourceID(0), mInitialized(false),
     234                 :       mHasHadUpdate(false),
     235                 :       mClosed(false),
     236                 :       mDidNotifyDataEnded(false),
     237                 :       mIsSeekable(false), mCacheSuspended(false),
     238                 :       mChannelEnded(false),
     239                 :       mUsingNullPrincipal(false),
     240                 :       mChannelOffset(0), mStreamLength(-1),  
     241                 :       mStreamOffset(0), mPlaybackBytesPerSecond(10000),
     242                 :       mPinCount(0), mCurrentMode(MODE_PLAYBACK),
     243               0 :       mMetadataInPartialBlockBuffer(false) {}
     244                 :   ~nsMediaCacheStream();
     245                 : 
     246                 :   // Set up this stream with the cache. Can fail on OOM. One
     247                 :   // of InitAsClone or Init must be called before any other method on
     248                 :   // this class. Does nothing if already initialized.
     249                 :   nsresult Init();
     250                 : 
     251                 :   // Set up this stream with the cache, assuming it's for the same data
     252                 :   // as the aOriginal stream. Can fail on OOM. Exactly one
     253                 :   // of InitAsClone or Init must be called before any other method on
     254                 :   // this class. Does nothing if already initialized.
     255                 :   nsresult InitAsClone(nsMediaCacheStream* aOriginal);
     256                 : 
     257                 :   // These are called on the main thread.
     258                 :   // Tell us whether the stream is seekable or not. Non-seekable streams
     259                 :   // will always pass 0 for aOffset to CacheClientSeek. This should only
     260                 :   // be called while the stream is at channel offset 0. Seekability can
     261                 :   // change during the lifetime of the nsMediaCacheStream --- every time
     262                 :   // we do an HTTP load the seekability may be different (and sometimes
     263                 :   // is, in practice, due to the effects of caching proxies).
     264                 :   void SetSeekable(bool aIsSeekable);
     265                 :   // This must be called (and return) before the ChannelMediaResource
     266                 :   // used to create this nsMediaCacheStream is deleted.
     267                 :   void Close();
     268                 :   // This returns true when the stream has been closed
     269               0 :   bool IsClosed() const { return mClosed; }
     270                 :   // Returns true when this stream is can be shared by a new resource load
     271               0 :   bool IsAvailableForSharing() const
     272                 :   {
     273               0 :     return !mClosed &&
     274               0 :       (!mDidNotifyDataEnded || NS_SUCCEEDED(mNotifyDataEndedStatus));
     275                 :   }
     276                 :   // Get the principal for this stream.
     277               0 :   nsIPrincipal* GetCurrentPrincipal() { return mPrincipal; }
     278                 :   // Ensure a global media cache update has run with this stream present.
     279                 :   // This ensures the cache has had a chance to suspend or unsuspend this stream.
     280                 :   // Called only on main thread. This can change the state of streams, fire
     281                 :   // notifications, etc.
     282                 :   void EnsureCacheUpdate();
     283                 : 
     284                 :   // These callbacks are called on the main thread by the client
     285                 :   // when data has been received via the channel.
     286                 :   // Tells the cache what the server said the data length is going to be.
     287                 :   // The actual data length may be greater (we receive more data than
     288                 :   // specified) or smaller (the stream ends before we reach the given
     289                 :   // length), because servers can lie. The server's reported data length
     290                 :   // *and* the actual data length can even vary over time because a
     291                 :   // misbehaving server may feed us a different stream after each seek
     292                 :   // operation. So this is really just a hint. The cache may however
     293                 :   // stop reading (suspend the channel) when it thinks we've read all the
     294                 :   // data available based on an incorrect reported length. Seeks relative
     295                 :   // EOF also depend on the reported length if we haven't managed to
     296                 :   // read the whole stream yet.
     297                 :   void NotifyDataLength(PRInt64 aLength);
     298                 :   // Notifies the cache that a load has begun. We pass the offset
     299                 :   // because in some cases the offset might not be what the cache
     300                 :   // requested. In particular we might unexpectedly start providing
     301                 :   // data at offset 0. This need not be called if the offset is the
     302                 :   // offset that the cache requested in
     303                 :   // ChannelMediaResource::CacheClientSeek. This can be called at any
     304                 :   // time by the client, not just after a CacheClientSeek.
     305                 :   void NotifyDataStarted(PRInt64 aOffset);
     306                 :   // Notifies the cache that data has been received. The stream already
     307                 :   // knows the offset because data is received in sequence and
     308                 :   // the starting offset is known via NotifyDataStarted or because
     309                 :   // the cache requested the offset in
     310                 :   // ChannelMediaResource::CacheClientSeek, or because it defaulted to 0.
     311                 :   // We pass in the principal that was used to load this data.
     312                 :   void NotifyDataReceived(PRInt64 aSize, const char* aData,
     313                 :                           nsIPrincipal* aPrincipal);
     314                 :   // Notifies the cache that the channel has closed with the given status.
     315                 :   void NotifyDataEnded(nsresult aStatus);
     316                 : 
     317                 :   // These methods can be called on any thread.
     318                 :   // Cached blocks associated with this stream will not be evicted
     319                 :   // while the stream is pinned.
     320                 :   void Pin();
     321                 :   void Unpin();
     322                 :   // See comments above for NotifyDataLength about how the length
     323                 :   // can vary over time. Returns -1 if no length is known. Returns the
     324                 :   // reported length if we haven't got any better information. If
     325                 :   // the stream ended normally we return the length we actually got.
     326                 :   // If we've successfully read data beyond the originally reported length,
     327                 :   // we return the end of the data we've read.
     328                 :   PRInt64 GetLength();
     329                 :   // Returns the unique resource ID
     330               0 :   PRInt64 GetResourceID() { return mResourceID; }
     331                 :   // Returns the end of the bytes starting at the given offset
     332                 :   // which are in cache.
     333                 :   PRInt64 GetCachedDataEnd(PRInt64 aOffset);
     334                 :   // Returns the offset of the first byte of cached data at or after aOffset,
     335                 :   // or -1 if there is no such cached data.
     336                 :   PRInt64 GetNextCachedData(PRInt64 aOffset);
     337                 :   // Fills aRanges with the ByteRanges representing the data which is currently
     338                 :   // cached. Locks the media cache while running, to prevent any ranges
     339                 :   // growing. The stream should be pinned while this runs and while its results
     340                 :   // are used, to ensure no data is evicted.
     341                 :   nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges);
     342                 : 
     343                 :   // Reads from buffered data only. Will fail if not all data to be read is
     344                 :   // in the cache. Will not mark blocks as read. Can be called from the main
     345                 :   // thread. It's the caller's responsibility to wrap the call in a pin/unpin,
     346                 :   // and also to check that the range they want is cached before calling this.
     347                 :   nsresult ReadFromCache(char* aBuffer,
     348                 :                          PRInt64 aOffset,
     349                 :                          PRInt64 aCount);
     350                 : 
     351                 :   // IsDataCachedToEndOfStream returns true if all the data from
     352                 :   // aOffset to the end of the stream (the server-reported end, if the
     353                 :   // real end is not known) is in cache. If we know nothing about the
     354                 :   // end of the stream, this returns false.
     355                 :   bool IsDataCachedToEndOfStream(PRInt64 aOffset);
     356                 :   // The mode is initially MODE_PLAYBACK.
     357                 :   void SetReadMode(ReadMode aMode);
     358                 :   // This is the client's estimate of the playback rate assuming
     359                 :   // the media plays continuously. The cache can't guess this itself
     360                 :   // because it doesn't know when the decoder was paused, buffering, etc.
     361                 :   // Do not pass zero.
     362                 :   void SetPlaybackRate(PRUint32 aBytesPerSecond);
     363                 :   // Returns the last set value of SetSeekable.
     364                 :   bool IsSeekable();
     365                 : 
     366                 :   // Returns true when all streams for this resource are suspended or their
     367                 :   // channel has ended.
     368                 :   // If aActiveResource is non-null, fills it with a pointer to a stream
     369                 :   // for this resource that is not suspended or ended.
     370                 :   bool AreAllStreamsForResourceSuspended(MediaResource** aActiveResource);
     371                 : 
     372                 :   // These methods must be called on a different thread from the main
     373                 :   // thread. They should always be called on the same thread for a given
     374                 :   // stream.
     375                 :   // This can fail when aWhence is NS_SEEK_END and no stream length
     376                 :   // is known.
     377                 :   nsresult Seek(PRInt32 aWhence, PRInt64 aOffset);
     378                 :   PRInt64 Tell();
     379                 :   // *aBytes gets the number of bytes that were actually read. This can
     380                 :   // be less than aCount. If the first byte of data is not in the cache,
     381                 :   // this will block until the data is available or the stream is
     382                 :   // closed, otherwise it won't block.
     383                 :   nsresult Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes);
     384                 : 
     385                 : private:
     386                 :   friend class nsMediaCache;
     387                 : 
     388                 :   /**
     389                 :    * A doubly-linked list of blocks. Add/Remove/Get methods are all
     390                 :    * constant time. We declare this here so that a stream can contain a
     391                 :    * BlockList of its read-ahead blocks. Blocks are referred to by index
     392                 :    * into the nsMediaCache::mIndex array.
     393                 :    * 
     394                 :    * Blocks can belong to more than one list at the same time, because
     395                 :    * the next/prev pointers are not stored in the block.
     396                 :    */
     397                 :   class BlockList {
     398                 :   public:
     399               0 :     BlockList() : mFirstBlock(-1), mCount(0) { mEntries.Init(); }
     400               0 :     ~BlockList() {
     401               0 :       NS_ASSERTION(mFirstBlock == -1 && mCount == 0,
     402                 :                    "Destroying non-empty block list");
     403               0 :     }
     404                 :     void AddFirstBlock(PRInt32 aBlock);
     405                 :     void AddAfter(PRInt32 aBlock, PRInt32 aBefore);
     406                 :     void RemoveBlock(PRInt32 aBlock);
     407                 :     // Returns the first block in the list, or -1 if empty
     408               0 :     PRInt32 GetFirstBlock() const { return mFirstBlock; }
     409                 :     // Returns the last block in the list, or -1 if empty
     410                 :     PRInt32 GetLastBlock() const;
     411                 :     // Returns the next block in the list after aBlock or -1 if
     412                 :     // aBlock is the last block
     413                 :     PRInt32 GetNextBlock(PRInt32 aBlock) const;
     414                 :     // Returns the previous block in the list before aBlock or -1 if
     415                 :     // aBlock is the first block
     416                 :     PRInt32 GetPrevBlock(PRInt32 aBlock) const;
     417               0 :     bool IsEmpty() const { return mFirstBlock < 0; }
     418               0 :     PRInt32 GetCount() const { return mCount; }
     419                 :     // The contents of aBlockIndex1 and aBlockIndex2 have been swapped
     420                 :     void NotifyBlockSwapped(PRInt32 aBlockIndex1, PRInt32 aBlockIndex2);
     421                 : #ifdef DEBUG
     422                 :     // Verify linked-list invariants
     423                 :     void Verify();
     424                 : #else
     425                 :     void Verify() {}
     426                 : #endif
     427                 : 
     428                 :   private:
     429               0 :     struct Entry : public nsUint32HashKey {
     430               0 :       Entry(KeyTypePointer aKey) : nsUint32HashKey(aKey) { }
     431                 :       Entry(const Entry& toCopy) : nsUint32HashKey(&toCopy.GetKey()),
     432                 :         mNextBlock(toCopy.mNextBlock), mPrevBlock(toCopy.mPrevBlock) {}
     433                 : 
     434                 :       PRInt32 mNextBlock;
     435                 :       PRInt32 mPrevBlock;
     436                 :     };
     437                 :     nsTHashtable<Entry> mEntries;
     438                 : 
     439                 :     // The index of the first block in the list, or -1 if the list is empty.
     440                 :     PRInt32 mFirstBlock;
     441                 :     // The number of blocks in the list.
     442                 :     PRInt32 mCount;
     443                 :   };
     444                 : 
     445                 :   // Returns the end of the bytes starting at the given offset
     446                 :   // which are in cache.
     447                 :   // This method assumes that the cache monitor is held and can be called on
     448                 :   // any thread.
     449                 :   PRInt64 GetCachedDataEndInternal(PRInt64 aOffset);
     450                 :   // Returns the offset of the first byte of cached data at or after aOffset,
     451                 :   // or -1 if there is no such cached data.
     452                 :   // This method assumes that the cache monitor is held and can be called on
     453                 :   // any thread.
     454                 :   PRInt64 GetNextCachedDataInternal(PRInt64 aOffset);
     455                 :   // A helper function to do the work of closing the stream. Assumes
     456                 :   // that the cache monitor is held. Main thread only.
     457                 :   // aReentrantMonitor is the nsAutoReentrantMonitor wrapper holding the cache monitor.
     458                 :   // This is used to NotifyAll to wake up threads that might be
     459                 :   // blocked on reading from this stream.
     460                 :   void CloseInternal(ReentrantMonitorAutoEnter& aReentrantMonitor);
     461                 :   // Update mPrincipal given that data has been received from aPrincipal
     462                 :   void UpdatePrincipal(nsIPrincipal* aPrincipal);
     463                 : 
     464                 :   // These fields are main-thread-only.
     465                 :   ChannelMediaResource*  mClient;
     466                 :   nsCOMPtr<nsIPrincipal> mPrincipal;
     467                 :   // This is a unique ID representing the resource we're loading.
     468                 :   // All streams with the same mResourceID are loading the same
     469                 :   // underlying resource and should share data.
     470                 :   PRInt64                mResourceID;
     471                 :   // Set to true when Init or InitAsClone has been called
     472                 :   bool                   mInitialized;
     473                 :   // Set to true when nsMediaCache::Update() has finished while this stream
     474                 :   // was present.
     475                 :   bool                   mHasHadUpdate;
     476                 :   // Set to true when the stream has been closed either explicitly or
     477                 :   // due to an internal cache error
     478                 :   bool                   mClosed;
     479                 :   // True if CacheClientNotifyDataEnded has been called for this stream.
     480                 :   bool                   mDidNotifyDataEnded;
     481                 : 
     482                 :   // The following fields are protected by the cache's monitor but are
     483                 :   // only written on the main thread. 
     484                 : 
     485                 :   // The last reported seekability state for the underlying channel
     486                 :   bool mIsSeekable;
     487                 :   // True if the cache has suspended our channel because the cache is
     488                 :   // full and the priority of the data that would be received is lower
     489                 :   // than the priority of the data already in the cache
     490                 :   bool mCacheSuspended;
     491                 :   // True if the channel ended and we haven't seeked it again.
     492                 :   bool mChannelEnded;
     493                 :   // True if mPrincipal is a null principal because we saw data from
     494                 :   // multiple origins
     495                 :   bool mUsingNullPrincipal;
     496                 :   // The offset where the next data from the channel will arrive
     497                 :   PRInt64      mChannelOffset;
     498                 :   // The reported or discovered length of the data, or -1 if nothing is
     499                 :   // known
     500                 :   PRInt64      mStreamLength;
     501                 : 
     502                 :   // The following fields are protected by the cache's monitor can can be written
     503                 :   // by any thread.
     504                 : 
     505                 :   // The offset where the reader is positioned in the stream
     506                 :   PRInt64           mStreamOffset;
     507                 :   // For each block in the stream data, maps to the cache entry for the
     508                 :   // block, or -1 if the block is not cached.
     509                 :   nsTArray<PRInt32> mBlocks;
     510                 :   // The list of read-ahead blocks, ordered by stream offset; the first
     511                 :   // block is the earliest in the stream (so the last block will be the
     512                 :   // least valuable).
     513                 :   BlockList         mReadaheadBlocks;
     514                 :   // The list of metadata blocks; the first block is the most recently used
     515                 :   BlockList         mMetadataBlocks;
     516                 :   // The list of played-back blocks; the first block is the most recently used
     517                 :   BlockList         mPlayedBlocks;
     518                 :   // The last reported estimate of the decoder's playback rate
     519                 :   PRUint32          mPlaybackBytesPerSecond;
     520                 :   // The number of times this stream has been Pinned without a
     521                 :   // corresponding Unpin
     522                 :   PRUint32          mPinCount;
     523                 :   // The status used when we did CacheClientNotifyDataEnded. Only valid
     524                 :   // when mDidNotifyDataEnded is true.
     525                 :   nsresult          mNotifyDataEndedStatus;
     526                 :   // The last reported read mode
     527                 :   ReadMode          mCurrentMode;
     528                 :   // True if some data in mPartialBlockBuffer has been read as metadata
     529                 :   bool              mMetadataInPartialBlockBuffer;
     530                 : 
     531                 :   // The following field is protected by the cache's monitor but are
     532                 :   // only written on the main thread.
     533                 : 
     534                 :   // Data received for the block containing mChannelOffset. Data needs
     535                 :   // to wait here so we can write back a complete block. The first
     536                 :   // mChannelOffset%BLOCK_SIZE bytes have been filled in with good data,
     537                 :   // the rest are garbage.
     538                 :   // Use PRInt64 so that the data is well-aligned.
     539                 :   PRInt64           mPartialBlockBuffer[BLOCK_SIZE/sizeof(PRInt64)];
     540                 : };
     541                 : 
     542                 : #endif

Generated by: LCOV version 1.7