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