Coverage Report

Created: 2018-09-25 14:53

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