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
|