content/media/MediaCache.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial