1 /* vim:set ts=2 sw=2 sts=2 et cindent: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef mozilla_dom_media_FileMediaResource_h
7 #define mozilla_dom_media_FileMediaResource_h
8 
9 #include "BaseMediaResource.h"
10 #include "mozilla/Mutex.h"
11 
12 namespace mozilla {
13 
14 class FileMediaResource : public BaseMediaResource {
15  public:
16   FileMediaResource(MediaResourceCallback* aCallback, nsIChannel* aChannel,
17                     nsIURI* aURI, int64_t aSize = -1 /* unknown size */)
BaseMediaResource(aCallback,aChannel,aURI)18       : BaseMediaResource(aCallback, aChannel, aURI),
19         mSize(aSize),
20         mLock("FileMediaResource.mLock"),
21         mSizeInitialized(aSize != -1) {}
22   ~FileMediaResource() = default;
23 
24   // Main thread
25   nsresult Open(nsIStreamListener** aStreamListener) override;
26   RefPtr<GenericPromise> Close() override;
Suspend(bool aCloseImmediately)27   void Suspend(bool aCloseImmediately) override {}
Resume()28   void Resume() override {}
29   already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
30   bool HadCrossOriginRedirects() override;
31   nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
32                          uint32_t aCount) override;
33 
34   // These methods are called off the main thread.
35 
36   // Other thread
SetReadMode(MediaCacheStream::ReadMode aMode)37   void SetReadMode(MediaCacheStream::ReadMode aMode) override {}
SetPlaybackRate(uint32_t aBytesPerSecond)38   void SetPlaybackRate(uint32_t aBytesPerSecond) override {}
39   nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
40                   uint32_t* aBytes) override;
41   // (Probably) file-based, caching recommended.
ShouldCacheReads()42   bool ShouldCacheReads() override { return true; }
43 
44   // Any thread
Pin()45   void Pin() override {}
Unpin()46   void Unpin() override {}
GetDownloadRate(bool * aIsReliable)47   double GetDownloadRate(bool* aIsReliable) override {
48     // The data's all already here
49     *aIsReliable = true;
50     return 100 * 1024 * 1024;  // arbitray, use 100MB/s
51   }
52 
GetLength()53   int64_t GetLength() override {
54     MutexAutoLock lock(mLock);
55 
56     EnsureSizeInitialized();
57     return mSizeInitialized ? mSize : 0;
58   }
59 
GetNextCachedData(int64_t aOffset)60   int64_t GetNextCachedData(int64_t aOffset) override {
61     MutexAutoLock lock(mLock);
62 
63     EnsureSizeInitialized();
64     return (aOffset < mSize) ? aOffset : -1;
65   }
66 
GetCachedDataEnd(int64_t aOffset)67   int64_t GetCachedDataEnd(int64_t aOffset) override {
68     MutexAutoLock lock(mLock);
69 
70     EnsureSizeInitialized();
71     return std::max(aOffset, mSize);
72   }
IsDataCachedToEndOfResource(int64_t aOffset)73   bool IsDataCachedToEndOfResource(int64_t aOffset) override { return true; }
IsTransportSeekable()74   bool IsTransportSeekable() override { return true; }
75 
76   nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
77 
SizeOfExcludingThis(MallocSizeOf aMallocSizeOf)78   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
79     // Might be useful to track in the future:
80     // - mInput
81     return BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf);
82   }
83 
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)84   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
85     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
86   }
87 
88  protected:
89   // These Unsafe variants of Read and Seek perform their operations
90   // without acquiring mLock. The caller must obtain the lock before
91   // calling. The implmentation of Read, Seek and ReadAt obtains the
92   // lock before calling these Unsafe variants to read or seek.
93   nsresult UnsafeRead(char* aBuffer, uint32_t aCount, uint32_t* aBytes);
94   nsresult UnsafeSeek(int32_t aWhence, int64_t aOffset);
95 
96  private:
97   // Ensures mSize is initialized, if it can be.
98   // mLock must be held when this is called, and mInput must be non-null.
99   void EnsureSizeInitialized();
100   already_AddRefed<MediaByteBuffer> UnsafeMediaReadAt(int64_t aOffset,
101                                                       uint32_t aCount);
102 
103   // The file size, or -1 if not known. Immutable after Open().
104   // Can be used from any thread.
105   int64_t mSize;
106 
107   // This lock handles synchronisation between calls to Close() and
108   // the Read, Seek, etc calls. Close must not be called while a
109   // Read or Seek is in progress since it resets various internal
110   // values to null.
111   // This lock protects mSeekable, mInput, mSize, and mSizeInitialized.
112   Mutex mLock;
113 
114   // Seekable stream interface to file. This can be used from any
115   // thread.
116   nsCOMPtr<nsISeekableStream> mSeekable;
117 
118   // Input stream for the media data. This can be used from any
119   // thread.
120   nsCOMPtr<nsIInputStream> mInput;
121 
122   // Whether we've attempted to initialize mSize. Note that mSize can be -1
123   // when mSizeInitialized is true if we tried and failed to get the size
124   // of the file.
125   bool mSizeInitialized;
126   // Set to true if NotifyDataEnded callback has been processed (which only
127   // occurs if resource size is known)
128   bool mNotifyDataEndedProcessed = false;
129 };
130 
131 }  // namespace mozilla
132 
133 #endif  // mozilla_dom_media_FileMediaResource_h
134