Coverage Report

Created: 2018-09-25 14:53

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