tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ChannelMediaResource.h (10114B)


      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_ChannelMediaResource_h
      7 #define mozilla_dom_media_ChannelMediaResource_h
      8 
      9 #include "BaseMediaResource.h"
     10 #include "MediaCache.h"
     11 #include "mozilla/EventTargetAndLockCapability.h"
     12 #include "mozilla/Mutex.h"
     13 #include "nsIChannelEventSink.h"
     14 #include "nsIInterfaceRequestor.h"
     15 #include "nsIThreadRetargetableStreamListener.h"
     16 
     17 class nsIHttpChannel;
     18 
     19 namespace mozilla {
     20 
     21 /**
     22 * This class is responsible for managing the suspend count and report suspend
     23 * status of channel.
     24 **/
     25 class ChannelSuspendAgent {
     26 public:
     27  explicit ChannelSuspendAgent(MediaCacheStream& aCacheStream)
     28      : mCacheStream(aCacheStream) {}
     29 
     30  // True when the channel has been suspended or needs to be suspended.
     31  bool IsSuspended();
     32 
     33  // Return true when the channel is logically suspended, i.e. the suspend
     34  // count goes from 0 to 1.
     35  bool Suspend();
     36 
     37  // Return true only when the suspend count is equal to zero.
     38  bool Resume();
     39 
     40  // Tell the agent to manage the suspend status of the channel.
     41  void Delegate(nsIChannel* aChannel);
     42  // Stop the management of the suspend status of the channel.
     43  void Revoke();
     44 
     45 private:
     46  // Only suspends channel but not changes the suspend count.
     47  void SuspendInternal();
     48 
     49  nsIChannel* mChannel = nullptr;
     50  MediaCacheStream& mCacheStream;
     51  uint32_t mSuspendCount = 0;
     52  bool mIsChannelSuspended = false;
     53 };
     54 
     55 DDLoggedTypeDeclNameAndBase(ChannelMediaResource, BaseMediaResource);
     56 
     57 /**
     58 * This is the MediaResource implementation that wraps Necko channels.
     59 * Much of its functionality is actually delegated to MediaCache via
     60 * an underlying MediaCacheStream.
     61 *
     62 * All synchronization is performed by MediaCacheStream; all off-main-
     63 * thread operations are delegated directly to that object.
     64 */
     65 class ChannelMediaResource
     66    : public BaseMediaResource,
     67      public DecoderDoctorLifeLogger<ChannelMediaResource> {
     68  // Store information shared among resources. Main thread only.
     69  struct SharedInfo {
     70    NS_INLINE_DECL_REFCOUNTING(SharedInfo);
     71 
     72    nsTArray<ChannelMediaResource*> mResources;
     73    // Null if there is not yet any data from any origin.
     74    nsCOMPtr<nsIPrincipal> mPrincipal;
     75    // Meaningful only when mPrincipal is non-null,
     76    // unaffected by intermediate cross-origin redirects.
     77    bool mFinalResponsesAreOpaque = false;
     78 
     79    bool mHadCrossOriginRedirects = false;
     80 
     81   private:
     82    ~SharedInfo() = default;
     83  };
     84  RefPtr<SharedInfo> mSharedInfo;
     85 
     86 public:
     87  ChannelMediaResource(MediaResourceCallback* aDecoder, nsIChannel* aChannel,
     88                       nsIURI* aURI, int64_t aStreamLength,
     89                       bool aIsPrivateBrowsing = false);
     90  ~ChannelMediaResource();
     91 
     92  // These are called on the main thread by MediaCache. These must
     93  // not block or grab locks, because the media cache is holding its lock.
     94  // Notify that data is available from the cache. This can happen even
     95  // if this stream didn't read any data, since another stream might have
     96  // received data for the same resource.
     97  void CacheClientNotifyDataReceived();
     98  // Notify that we reached the end of the stream. This can happen even
     99  // if this stream didn't read any data, since another stream might have
    100  // received data for the same resource.
    101  void CacheClientNotifyDataEnded(nsresult aStatus);
    102  // Notify that the principal for the cached resource changed.
    103  void CacheClientNotifyPrincipalChanged();
    104  // Notify the decoder that the cache suspended status changed.
    105  void CacheClientNotifySuspendedStatusChanged(bool aSuspended);
    106 
    107  // These are called on the main thread by MediaCache. These shouldn't block,
    108  // but they may grab locks --- the media cache is not holding its lock
    109  // when these are called.
    110  // Start a new load at the given aOffset. The old load is cancelled
    111  // and no more data from the old load will be notified via
    112  // MediaCacheStream::NotifyDataReceived/Ended.
    113  void CacheClientSeek(int64_t aOffset, bool aResume);
    114  // Suspend the current load since data is currently not wanted
    115  void CacheClientSuspend();
    116  // Resume the current load since data is wanted again
    117  void CacheClientResume();
    118 
    119  bool IsSuspended();
    120 
    121  void ThrottleReadahead(bool bThrottle) override;
    122 
    123  // Main thread
    124  nsresult Open(nsIStreamListener** aStreamListener) override;
    125  RefPtr<GenericPromise> Close() override;
    126  void Suspend(bool aCloseImmediately) override;
    127  void Resume() override;
    128  already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
    129  bool HadCrossOriginRedirects() override;
    130  bool CanClone() override;
    131  already_AddRefed<BaseMediaResource> CloneData(
    132      MediaResourceCallback* aDecoder) override;
    133  nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
    134                         uint32_t aCount) override;
    135 
    136  // Other thread
    137  void SetReadMode(MediaCacheStream::ReadMode aMode) override;
    138  void SetPlaybackRate(uint32_t aBytesPerSecond) override;
    139  nsresult ReadAt(int64_t offset, char* aBuffer, uint32_t aCount,
    140                  uint32_t* aBytes) override;
    141  // Data stored in IO&lock-encumbered MediaCacheStream, caching recommended.
    142  bool ShouldCacheReads() override { return true; }
    143 
    144  // Any thread
    145  void Pin() override;
    146  void Unpin() override;
    147  double GetDownloadRate(bool* aIsReliable) override;
    148  int64_t GetLength() override;
    149  int64_t GetNextCachedData(int64_t aOffset) override;
    150  int64_t GetCachedDataEnd(int64_t aOffset) override;
    151  bool IsDataCachedToEndOfResource(int64_t aOffset) override;
    152  bool IsTransportSeekable() override;
    153  bool IsLiveStream() const override { return mIsLiveStream; }
    154 
    155  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
    156    // Might be useful to track in the future:
    157    //   - mListener (seems minor)
    158    size_t size = BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf);
    159    size += mCacheStream.SizeOfExcludingThis(aMallocSizeOf);
    160 
    161    return size;
    162  }
    163 
    164  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
    165    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    166  }
    167 
    168  void GetDebugInfo(dom::MediaResourceDebugInfo& aInfo) override;
    169 
    170  class Listener final : public nsIInterfaceRequestor,
    171                         public nsIChannelEventSink,
    172                         public nsIThreadRetargetableStreamListener {
    173    ~Listener() = default;
    174 
    175   public:
    176    Listener(ChannelMediaResource* aResource, int64_t aOffset, uint32_t aLoadID)
    177        : mLock("Listener.mLock"),
    178          mResource(aResource),
    179          mOffset(aOffset),
    180          mLoadID(aLoadID) {}
    181 
    182    NS_DECL_THREADSAFE_ISUPPORTS
    183    NS_DECL_NSIREQUESTOBSERVER
    184    NS_DECL_NSISTREAMLISTENER
    185    NS_DECL_NSICHANNELEVENTSINK
    186    NS_DECL_NSIINTERFACEREQUESTOR
    187    NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
    188 
    189    void Revoke();
    190 
    191   private:
    192    MainThreadAndLockCapability<Mutex> mLock;
    193    // mResource should only be modified on the main thread with the lock.
    194    // So it can be read without lock on the main thread or on other threads
    195    // with the lock.
    196    RefPtr<ChannelMediaResource> mResource MOZ_GUARDED_BY(mLock);
    197 
    198    const int64_t mOffset;
    199    const uint32_t mLoadID;
    200  };
    201  friend class Listener;
    202 
    203  nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
    204 
    205 protected:
    206  nsresult Seek(int64_t aOffset, bool aResume);
    207 
    208  // These are called on the main thread by Listener.
    209  nsresult OnStartRequest(nsIRequest* aRequest, int64_t aRequestOffset);
    210  nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
    211  nsresult OnDataAvailable(uint32_t aLoadID, nsIInputStream* aStream,
    212                           uint32_t aCount);
    213  nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew,
    214                             uint32_t aFlags, int64_t aOffset);
    215 
    216  // Use only before MediaDecoder shutdown.  Main thread only.
    217  dom::HTMLMediaElement* MediaElement() const;
    218  // Opens the channel, using an HTTP byte range request to start at aOffset
    219  // if possible. Main thread only.
    220  nsresult OpenChannel(int64_t aOffset);
    221  nsresult RecreateChannel();
    222  // Add headers to HTTP request. Main thread only.
    223  nsresult SetupChannelHeaders(int64_t aOffset);
    224  // Closes the channel. Main thread only.
    225  void CloseChannel();
    226  // Update the principal for the resource. Main thread only.
    227  void UpdatePrincipal();
    228 
    229  // Parses 'Content-Range' header and returns results via parameters.
    230  // Returns error if header is not available, values are not parse-able or
    231  // values are out of range.
    232  nsresult ParseContentRangeHeader(nsIHttpChannel* aHttpChan,
    233                                   int64_t& aRangeStart, int64_t& aRangeEnd,
    234                                   int64_t& aRangeTotal) const;
    235 
    236  // Calculates the length of the resource using HTTP headers, if this
    237  // is an HTTP channel. Returns -1 on failure, or for non HTTP channels.
    238  int64_t CalculateStreamLength() const;
    239 
    240  struct Closure {
    241    uint32_t mLoadID;
    242    ChannelMediaResource* mResource;
    243  };
    244 
    245  static nsresult CopySegmentToCache(nsIInputStream* aInStream, void* aClosure,
    246                                     const char* aFromSegment,
    247                                     uint32_t aToOffset, uint32_t aCount,
    248                                     uint32_t* aWriteCount);
    249 
    250  // Main thread access only
    251  // True if Close() has been called.
    252  bool mClosed = false;
    253  // The last reported seekability state for the underlying channel
    254  bool mIsTransportSeekable = false;
    255  // Length of the content first reported.
    256  int64_t mFirstReadLength = -1;
    257  RefPtr<Listener> mListener;
    258  // A mono-increasing integer to uniquely identify the channel we are loading.
    259  uint32_t mLoadID = 0;
    260  bool mIsLiveStream = false;
    261 
    262  // Any thread access
    263  MediaCacheStream mCacheStream;
    264 
    265  ChannelSuspendAgent mSuspendAgent;
    266 
    267  // The size of the stream if known at construction time (such as with blob)
    268  const int64_t mKnownStreamLength;
    269 };
    270 
    271 }  // namespace mozilla
    272 
    273 #endif  // mozilla_dom_media_ChannelMediaResource_h