2008-10-19 11:39:21 +04:00
|
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2009-04-01 04:52:56 +04:00
|
|
|
|
2012-02-15 08:35:01 +04:00
|
|
|
#if !defined(MediaResource_h_)
|
|
|
|
#define MediaResource_h_
|
2008-10-19 11:39:21 +04:00
|
|
|
|
Rollup of bug 645263 and bug 646259: Switch to mozilla:: sync primitives. r=cjones,dbaron,doublec,ehsan src=bsmedberg
Bug 645263, part 0: Count sync primitive ctor/dtors. r=dbaron
Bug 645263, part 1: Migrate content/media to mozilla:: sync primitives. r=doublec
Bug 645263, part 2: Migrate modules/plugin to mozilla:: sync primitives. sr=bsmedberg
Bug 645263, part 3: Migrate nsComponentManagerImpl to mozilla:: sync primitives. sr=bsmedberg
Bug 645263, part 4: Migrate everything else to mozilla:: sync primitives. r=dbaron
Bug 645263, part 5: Remove nsAutoLock.*. sr=bsmedberg
Bug 645263, part 6: Make editor test be nicer to deadlock detector. r=ehsan
Bug 645263, part 7: Disable tracemalloc backtraces for xpcshell tests. r=dbaron
Bug 646259: Fix nsCacheService to use a CondVar for notifying. r=cjones
2011-04-01 08:29:02 +04:00
|
|
|
#include "mozilla/Mutex.h"
|
2008-10-19 11:39:21 +04:00
|
|
|
#include "nsIChannel.h"
|
|
|
|
#include "nsIURI.h"
|
2015-06-17 01:30:11 +03:00
|
|
|
#include "nsISeekableStream.h"
|
2013-09-23 13:53:36 +04:00
|
|
|
#include "nsIStreamingProtocolController.h"
|
2009-01-24 14:00:17 +03:00
|
|
|
#include "nsIStreamListener.h"
|
2009-05-14 01:52:50 +04:00
|
|
|
#include "nsIChannelEventSink.h"
|
|
|
|
#include "nsIInterfaceRequestor.h"
|
2015-11-24 09:57:37 +03:00
|
|
|
#include "Intervals.h"
|
2012-11-14 23:46:40 +04:00
|
|
|
#include "MediaCache.h"
|
2015-06-17 01:30:11 +03:00
|
|
|
#include "MediaData.h"
|
2015-11-16 02:50:55 +03:00
|
|
|
#include "MediaResourceCallback.h"
|
2015-08-12 06:07:59 +03:00
|
|
|
#include "mozilla/Atomics.h"
|
2012-06-19 06:30:09 +04:00
|
|
|
#include "mozilla/Attributes.h"
|
2013-08-24 10:12:51 +04:00
|
|
|
#include "mozilla/TimeStamp.h"
|
2013-09-06 00:25:17 +04:00
|
|
|
#include "nsThreadUtils.h"
|
2014-08-13 09:13:28 +04:00
|
|
|
#include <algorithm>
|
2008-10-19 11:39:21 +04:00
|
|
|
|
2009-01-16 11:22:08 +03:00
|
|
|
// For HTTP seeking, if number of bytes needing to be
|
|
|
|
// seeked forward is less than this value then a read is
|
|
|
|
// done rather than a byte range request.
|
2015-08-28 05:12:11 +03:00
|
|
|
//
|
|
|
|
// If we assume a 100Mbit connection, and assume reissuing an HTTP seek causes
|
|
|
|
// a delay of 200ms, then in that 200ms we could have simply read ahead 2MB. So
|
|
|
|
// setting SEEK_VS_READ_THRESHOLD to 1MB sounds reasonable.
|
|
|
|
static const int64_t SEEK_VS_READ_THRESHOLD = 1 * 1024 * 1024;
|
2009-01-16 11:22:08 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
static const uint32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416;
|
2009-12-15 23:08:59 +03:00
|
|
|
|
2013-05-06 03:59:05 +04:00
|
|
|
// Number of bytes we have accumulated before we assume the connection download
|
|
|
|
// rate can be reliably calculated. 57 Segments at IW=3 allows slow start to
|
|
|
|
// reach a CWND of 30 (See bug 831998)
|
|
|
|
static const int64_t RELIABLE_DATA_THRESHOLD = 57 * 1460;
|
|
|
|
|
2013-09-06 00:25:17 +04:00
|
|
|
class nsIHttpChannel;
|
|
|
|
class nsIPrincipal;
|
|
|
|
|
2012-02-15 08:35:01 +04:00
|
|
|
namespace mozilla {
|
|
|
|
|
2014-06-20 15:08:24 +04:00
|
|
|
class MediaChannelStatistics;
|
|
|
|
|
2009-04-01 04:52:56 +04:00
|
|
|
/**
|
|
|
|
* This class is useful for estimating rates of data passing through
|
|
|
|
* some channel. The idea is that activity on the channel "starts"
|
|
|
|
* and "stops" over time. At certain times data passes through the
|
|
|
|
* channel (usually while the channel is active; data passing through
|
|
|
|
* an inactive channel is ignored). The GetRate() function computes
|
|
|
|
* an estimate of the "current rate" of the channel, which is some
|
|
|
|
* kind of average of the data passing through over the time the
|
|
|
|
* channel is active.
|
2014-02-26 04:36:54 +04:00
|
|
|
*
|
2009-04-11 13:39:24 +04:00
|
|
|
* All methods take "now" as a parameter so the user of this class can
|
|
|
|
* control the timeline used.
|
2009-04-01 04:52:56 +04:00
|
|
|
*/
|
2012-02-15 08:35:01 +04:00
|
|
|
class MediaChannelStatistics {
|
2009-04-01 04:52:56 +04:00
|
|
|
public:
|
2016-01-12 21:16:59 +03:00
|
|
|
MediaChannelStatistics()
|
|
|
|
: mAccumulatedBytes(0)
|
|
|
|
, mIsStarted(false)
|
|
|
|
{
|
|
|
|
Reset();
|
|
|
|
}
|
2012-12-13 23:42:45 +04:00
|
|
|
|
2014-09-01 07:50:23 +04:00
|
|
|
explicit MediaChannelStatistics(MediaChannelStatistics * aCopyFrom)
|
2013-01-23 23:24:41 +04:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(aCopyFrom);
|
2013-07-14 05:18:03 +04:00
|
|
|
mAccumulatedBytes = aCopyFrom->mAccumulatedBytes;
|
|
|
|
mAccumulatedTime = aCopyFrom->mAccumulatedTime;
|
|
|
|
mLastStartTime = aCopyFrom->mLastStartTime;
|
|
|
|
mIsStarted = aCopyFrom->mIsStarted;
|
2013-01-23 23:24:41 +04:00
|
|
|
}
|
|
|
|
|
2012-12-13 23:42:45 +04:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaChannelStatistics)
|
|
|
|
|
2009-04-01 04:52:56 +04:00
|
|
|
void Reset() {
|
2009-04-11 13:39:24 +04:00
|
|
|
mLastStartTime = TimeStamp();
|
|
|
|
mAccumulatedTime = TimeDuration(0);
|
2009-04-01 04:52:56 +04:00
|
|
|
mAccumulatedBytes = 0;
|
2011-09-30 03:34:37 +04:00
|
|
|
mIsStarted = false;
|
2009-04-01 04:52:56 +04:00
|
|
|
}
|
2012-12-13 23:42:45 +04:00
|
|
|
void Start() {
|
2009-04-01 04:52:56 +04:00
|
|
|
if (mIsStarted)
|
|
|
|
return;
|
2012-12-13 23:42:45 +04:00
|
|
|
mLastStartTime = TimeStamp::Now();
|
2011-09-30 03:34:37 +04:00
|
|
|
mIsStarted = true;
|
2009-04-01 04:52:56 +04:00
|
|
|
}
|
2012-12-13 23:42:45 +04:00
|
|
|
void Stop() {
|
2009-04-01 04:52:56 +04:00
|
|
|
if (!mIsStarted)
|
|
|
|
return;
|
2012-12-13 23:42:45 +04:00
|
|
|
mAccumulatedTime += TimeStamp::Now() - mLastStartTime;
|
2011-09-30 03:34:37 +04:00
|
|
|
mIsStarted = false;
|
2009-04-01 04:52:56 +04:00
|
|
|
}
|
2012-08-22 19:56:38 +04:00
|
|
|
void AddBytes(int64_t aBytes) {
|
2009-04-01 04:52:56 +04:00
|
|
|
if (!mIsStarted) {
|
|
|
|
// ignore this data, it may be related to seeking or some other
|
|
|
|
// operation we don't care about
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mAccumulatedBytes += aBytes;
|
|
|
|
}
|
2011-09-29 10:19:26 +04:00
|
|
|
double GetRateAtLastStop(bool* aReliable) {
|
2009-04-11 13:39:24 +04:00
|
|
|
double seconds = mAccumulatedTime.ToSeconds();
|
2013-05-06 03:59:05 +04:00
|
|
|
*aReliable = (seconds >= 1.0) ||
|
|
|
|
(mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD);
|
2009-04-11 13:39:24 +04:00
|
|
|
if (seconds <= 0.0)
|
|
|
|
return 0.0;
|
2011-04-14 02:12:23 +04:00
|
|
|
return static_cast<double>(mAccumulatedBytes)/seconds;
|
2009-04-01 04:52:56 +04:00
|
|
|
}
|
2012-12-13 23:42:45 +04:00
|
|
|
double GetRate(bool* aReliable) {
|
2009-04-11 13:39:24 +04:00
|
|
|
TimeDuration time = mAccumulatedTime;
|
2009-04-01 04:52:56 +04:00
|
|
|
if (mIsStarted) {
|
2012-12-13 23:42:45 +04:00
|
|
|
time += TimeStamp::Now() - mLastStartTime;
|
2009-04-01 04:52:56 +04:00
|
|
|
}
|
2009-04-11 13:39:24 +04:00
|
|
|
double seconds = time.ToSeconds();
|
2013-05-06 03:59:05 +04:00
|
|
|
*aReliable = (seconds >= 3.0) ||
|
|
|
|
(mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD);
|
2009-04-11 13:39:24 +04:00
|
|
|
if (seconds <= 0.0)
|
2009-04-01 04:52:56 +04:00
|
|
|
return 0.0;
|
2011-04-14 02:12:23 +04:00
|
|
|
return static_cast<double>(mAccumulatedBytes)/seconds;
|
2009-04-01 04:52:56 +04:00
|
|
|
}
|
|
|
|
private:
|
2014-06-22 08:43:00 +04:00
|
|
|
~MediaChannelStatistics() {}
|
2012-08-22 19:56:38 +04:00
|
|
|
int64_t mAccumulatedBytes;
|
2009-04-11 13:39:24 +04:00
|
|
|
TimeDuration mAccumulatedTime;
|
|
|
|
TimeStamp mLastStartTime;
|
2012-02-15 08:35:01 +04:00
|
|
|
bool mIsStarted;
|
2009-04-01 04:52:56 +04:00
|
|
|
};
|
|
|
|
|
2011-03-24 01:28:58 +03:00
|
|
|
// Represents a section of contiguous media, with a start and end offset.
|
|
|
|
// Used to denote ranges of data which are cached.
|
|
|
|
|
2015-11-24 12:37:21 +03:00
|
|
|
typedef media::Interval<int64_t> MediaByteRange;
|
2015-11-24 12:16:52 +03:00
|
|
|
typedef media::IntervalSet<int64_t> MediaByteRangeSet;
|
|
|
|
|
2013-09-23 13:53:36 +04:00
|
|
|
class RtspMediaResource;
|
2012-12-13 23:42:45 +04:00
|
|
|
|
2012-02-15 08:35:01 +04:00
|
|
|
/**
|
|
|
|
* Provides a thread-safe, seek/read interface to resources
|
2012-11-14 23:46:40 +04:00
|
|
|
* loaded from a URI. Uses MediaCache to cache data received over
|
2012-02-15 08:35:01 +04:00
|
|
|
* Necko's async channel API, thus resolving the mismatch between clients
|
|
|
|
* that need efficient random access to the data and protocols that do not
|
|
|
|
* support efficient random access, such as HTTP.
|
|
|
|
*
|
|
|
|
* Instances of this class must be created on the main thread.
|
|
|
|
* Most methods must be called on the main thread only. Read, Seek and
|
|
|
|
* Tell must only be called on non-main threads. In the case of the Ogg
|
|
|
|
* Decoder they are called on the Decode thread for example. You must
|
|
|
|
* ensure that no threads are calling these methods once Close is called.
|
|
|
|
*
|
2013-08-30 08:51:38 +04:00
|
|
|
* Instances of this class are reference counted. Use nsRefPtr for
|
|
|
|
* managing the lifetime of instances of this class.
|
2012-02-15 08:35:01 +04:00
|
|
|
*
|
|
|
|
* The generic implementation of this class is ChannelMediaResource, which can
|
|
|
|
* handle any URI for which Necko supports AsyncOpen.
|
|
|
|
* The 'file:' protocol can be implemented efficiently with direct random
|
|
|
|
* access, so the FileMediaResource implementation class bypasses the cache.
|
|
|
|
* MediaResource::Create automatically chooses the best implementation class.
|
|
|
|
*/
|
2014-02-26 04:36:54 +04:00
|
|
|
class MediaResource : public nsISupports
|
2008-10-19 11:39:21 +04:00
|
|
|
{
|
2009-03-30 05:19:10 +04:00
|
|
|
public:
|
2014-02-26 04:36:54 +04:00
|
|
|
// Our refcounting is threadsafe, and when our refcount drops to zero
|
|
|
|
// we dispatch an event to the main thread to delete the MediaResource.
|
|
|
|
// Note that this means it's safe for references to this object to be
|
|
|
|
// released on a non main thread, but the destructor will always run on
|
|
|
|
// the main thread.
|
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
2013-02-05 01:34:23 +04:00
|
|
|
|
2009-04-01 04:52:56 +04:00
|
|
|
// The following can be called on the main thread only:
|
2009-09-15 06:28:08 +04:00
|
|
|
// Get the URI
|
2012-11-17 08:31:53 +04:00
|
|
|
virtual nsIURI* URI() const { return nullptr; }
|
2012-02-15 08:35:01 +04:00
|
|
|
// Close the resource, stop any listeners, channels, etc.
|
2009-04-01 04:52:56 +04:00
|
|
|
// Cancels any currently blocking Read request and forces that request to
|
|
|
|
// return an error.
|
2009-03-30 05:19:10 +04:00
|
|
|
virtual nsresult Close() = 0;
|
2009-04-01 04:52:56 +04:00
|
|
|
// Suspend any downloads that are in progress.
|
2009-05-18 06:02:20 +04:00
|
|
|
// If aCloseImmediately is set, resources should be released immediately
|
|
|
|
// since we don't expect to resume again any time soon. Otherwise we
|
|
|
|
// may resume again soon so resources should be held for a little
|
|
|
|
// while.
|
2011-09-29 10:19:26 +04:00
|
|
|
virtual void Suspend(bool aCloseImmediately) = 0;
|
2009-04-01 04:52:56 +04:00
|
|
|
// Resume any downloads that have been suspended.
|
|
|
|
virtual void Resume() = 0;
|
2009-05-14 01:52:50 +04:00
|
|
|
// Get the current principal for the channel
|
|
|
|
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
|
2012-03-20 11:55:40 +04:00
|
|
|
// If this returns false, then we shouldn't try to clone this MediaResource
|
|
|
|
// because its underlying resources are not suitable for reuse (e.g.
|
|
|
|
// because the underlying connection has been lost, or this resource
|
|
|
|
// just can't be safely cloned). If this returns true, CloneData could
|
|
|
|
// still fail. If this returns false, CloneData should not be called.
|
|
|
|
virtual bool CanClone() { return false; }
|
2009-09-15 06:30:44 +04:00
|
|
|
// Create a new stream of the same type that refers to the same URI
|
|
|
|
// with a new channel. Any cached data associated with the original
|
|
|
|
// stream should be accessible in the new stream too.
|
2015-10-27 05:28:26 +03:00
|
|
|
virtual already_AddRefed<MediaResource> CloneData(MediaResourceCallback* aCallback) = 0;
|
2012-12-13 23:42:45 +04:00
|
|
|
// Set statistics to be recorded to the object passed in.
|
|
|
|
virtual void RecordStatisticsTo(MediaChannelStatistics *aStatistics) { }
|
2009-04-01 04:52:56 +04:00
|
|
|
|
|
|
|
// These methods are called off the main thread.
|
|
|
|
// The mode is initially MODE_PLAYBACK.
|
2012-11-14 23:46:40 +04:00
|
|
|
virtual void SetReadMode(MediaCacheStream::ReadMode aMode) = 0;
|
2009-04-01 04:52:56 +04:00
|
|
|
// This is the client's estimate of the playback rate assuming
|
|
|
|
// the media plays continuously. The cache can't guess this itself
|
|
|
|
// because it doesn't know when the decoder was paused, buffering, etc.
|
2012-08-22 19:56:38 +04:00
|
|
|
virtual void SetPlaybackRate(uint32_t aBytesPerSecond) = 0;
|
2013-07-17 05:54:52 +04:00
|
|
|
// Read up to aCount bytes from the stream. The read starts at
|
|
|
|
// aOffset in the stream, seeking to that location initially if
|
|
|
|
// it is not the current stream offset. The remaining arguments,
|
|
|
|
// results and requirements are the same as per the Read method.
|
|
|
|
virtual nsresult ReadAt(int64_t aOffset, char* aBuffer,
|
|
|
|
uint32_t aCount, uint32_t* aBytes) = 0;
|
2015-07-10 09:08:07 +03:00
|
|
|
// This method returns nullptr if anything fails.
|
|
|
|
// Otherwise, it returns an owned buffer.
|
|
|
|
// MediaReadAt may return fewer bytes than requested if end of stream is
|
|
|
|
// encountered. There is no need to call it again to get more data.
|
|
|
|
virtual already_AddRefed<MediaByteBuffer> MediaReadAt(int64_t aOffset, uint32_t aCount)
|
2015-06-17 01:30:11 +03:00
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
|
2015-07-10 09:08:07 +03:00
|
|
|
bool ok = bytes->SetLength(aCount, fallible);
|
2015-06-17 01:30:11 +03:00
|
|
|
NS_ENSURE_TRUE(ok, nullptr);
|
|
|
|
char* curr = reinterpret_cast<char*>(bytes->Elements());
|
2015-07-10 09:08:07 +03:00
|
|
|
const char* start = curr;
|
2015-06-17 01:30:11 +03:00
|
|
|
while (aCount > 0) {
|
|
|
|
uint32_t bytesRead;
|
|
|
|
nsresult rv = ReadAt(aOffset, curr, aCount, &bytesRead);
|
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2015-07-10 09:08:07 +03:00
|
|
|
if (!bytesRead) {
|
|
|
|
break;
|
|
|
|
}
|
2015-06-17 01:30:11 +03:00
|
|
|
aOffset += bytesRead;
|
|
|
|
aCount -= bytesRead;
|
|
|
|
curr += bytesRead;
|
|
|
|
}
|
2015-07-10 09:08:07 +03:00
|
|
|
bytes->SetLength(curr - start);
|
|
|
|
return bytes.forget();
|
|
|
|
}
|
|
|
|
|
2008-10-19 11:39:21 +04:00
|
|
|
// Report the current offset in bytes from the start of the stream.
|
2015-08-13 04:15:48 +03:00
|
|
|
// This is used to approximate where we currently are in the playback of a
|
|
|
|
// media.
|
|
|
|
// A call to ReadAt will update this position.
|
2012-08-22 19:56:38 +04:00
|
|
|
virtual int64_t Tell() = 0;
|
2014-12-23 04:16:05 +03:00
|
|
|
// Moves any existing channel loads into or out of background. Background
|
|
|
|
// loads don't block the load event. This also determines whether or not any
|
|
|
|
// new loads initiated (for example to seek) will be in the background.
|
|
|
|
virtual void SetLoadInBackground(bool aLoadInBackground) {}
|
2011-11-30 09:05:49 +04:00
|
|
|
// Ensures that the value returned by IsSuspendedByCache below is up to date
|
|
|
|
// (i.e. the cache has examined this stream at least once).
|
|
|
|
virtual void EnsureCacheUpToDate() {}
|
2009-03-30 05:19:10 +04:00
|
|
|
|
2009-04-01 04:52:56 +04:00
|
|
|
// These can be called on any thread.
|
|
|
|
// Cached blocks associated with this stream will not be evicted
|
|
|
|
// while the stream is pinned.
|
|
|
|
virtual void Pin() = 0;
|
|
|
|
virtual void Unpin() = 0;
|
|
|
|
// Get the estimated download rate in bytes per second (assuming no
|
|
|
|
// pausing of the channel is requested by Gecko).
|
|
|
|
// *aIsReliable is set to true if we think the estimate is useful.
|
2011-09-29 10:19:26 +04:00
|
|
|
virtual double GetDownloadRate(bool* aIsReliable) = 0;
|
2009-04-01 04:52:56 +04:00
|
|
|
// Get the length of the stream in bytes. Returns -1 if not known.
|
|
|
|
// This can change over time; after a seek operation, a misbehaving
|
|
|
|
// server may give us a resource of a different length to what it had
|
|
|
|
// reported previously --- or it may just lie in its Content-Length
|
|
|
|
// header and give us more or less data than it reported. We will adjust
|
|
|
|
// the result of GetLength to reflect the data that's actually arriving.
|
2012-08-22 19:56:38 +04:00
|
|
|
virtual int64_t GetLength() = 0;
|
2009-05-18 02:15:57 +04:00
|
|
|
// Returns the offset of the first byte of cached data at or after aOffset,
|
|
|
|
// or -1 if there is no such cached data.
|
2012-08-22 19:56:38 +04:00
|
|
|
virtual int64_t GetNextCachedData(int64_t aOffset) = 0;
|
2009-04-01 04:52:56 +04:00
|
|
|
// Returns the end of the bytes starting at the given offset
|
|
|
|
// which are in cache.
|
2012-08-22 19:56:38 +04:00
|
|
|
virtual int64_t GetCachedDataEnd(int64_t aOffset) = 0;
|
2009-04-01 04:52:56 +04:00
|
|
|
// Returns true if all the data from aOffset to the end of the stream
|
|
|
|
// is in cache. If the end of the stream is not known, we return false.
|
2012-08-22 19:56:38 +04:00
|
|
|
virtual bool IsDataCachedToEndOfResource(int64_t aOffset) = 0;
|
2015-07-22 15:57:09 +03:00
|
|
|
// Returns true if we are expecting any more data to arrive
|
|
|
|
// sometime in the not-too-distant future, either from the network or from
|
|
|
|
// an appendBuffer call on a MediaSource element.
|
|
|
|
virtual bool IsExpectingMoreData()
|
|
|
|
{
|
2015-07-22 15:57:41 +03:00
|
|
|
// MediaDecoder::mDecoderPosition is roughly the same as Tell() which
|
|
|
|
// returns a position updated by latest Read() or ReadAt().
|
|
|
|
return !IsDataCachedToEndOfResource(Tell()) && !IsSuspended();
|
2015-07-22 15:57:09 +03:00
|
|
|
}
|
2009-04-01 04:52:56 +04:00
|
|
|
// Returns true if this stream is suspended by the cache because the
|
|
|
|
// cache is full. If true then the decoder should try to start consuming
|
|
|
|
// data, otherwise we may not be able to make progress.
|
2012-11-14 23:46:40 +04:00
|
|
|
// MediaDecoder::NotifySuspendedStatusChanged is called when this
|
2009-04-01 04:52:56 +04:00
|
|
|
// changes.
|
2011-11-30 09:05:49 +04:00
|
|
|
// For resources using the media cache, this returns true only when all
|
|
|
|
// streams for the same resource are all suspended.
|
2013-05-03 02:59:18 +04:00
|
|
|
virtual bool IsSuspendedByCache() = 0;
|
2010-08-13 04:41:47 +04:00
|
|
|
// Returns true if this stream has been suspended.
|
2011-09-29 10:19:26 +04:00
|
|
|
virtual bool IsSuspended() = 0;
|
2010-08-05 11:40:35 +04:00
|
|
|
// Reads only data which is cached in the media cache. If you try to read
|
|
|
|
// any data which overlaps uncached data, or if aCount bytes otherwise can't
|
|
|
|
// be read, this function will return failure. This function be called from
|
|
|
|
// any thread, and it is the only read operation which is safe to call on
|
|
|
|
// the main thread, since it's guaranteed to be non blocking.
|
|
|
|
virtual nsresult ReadFromCache(char* aBuffer,
|
2012-08-22 19:56:38 +04:00
|
|
|
int64_t aOffset,
|
|
|
|
uint32_t aCount) = 0;
|
2013-02-05 01:34:23 +04:00
|
|
|
// Returns true if the resource can be seeked to unbuffered ranges, i.e.
|
|
|
|
// for an HTTP network stream this returns true if HTTP1.1 Byte Range
|
|
|
|
// requests are supported by the connection/server.
|
|
|
|
virtual bool IsTransportSeekable() = 0;
|
2009-03-30 05:19:10 +04:00
|
|
|
|
|
|
|
/**
|
2012-02-15 08:35:01 +04:00
|
|
|
* Create a resource, reading data from the channel. Call on main thread only.
|
|
|
|
* The caller must follow up by calling resource->Open().
|
2009-03-30 05:19:10 +04:00
|
|
|
*/
|
2015-10-27 05:28:26 +03:00
|
|
|
static already_AddRefed<MediaResource> Create(MediaResourceCallback* aCallback, nsIChannel* aChannel);
|
2009-09-15 06:30:43 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Open the stream. This creates a stream listener and returns it in
|
|
|
|
* aStreamListener; this listener needs to be notified of incoming data.
|
|
|
|
*/
|
|
|
|
virtual nsresult Open(nsIStreamListener** aStreamListener) = 0;
|
2009-01-22 02:54:40 +03:00
|
|
|
|
2011-03-24 01:28:58 +03:00
|
|
|
/**
|
2012-02-15 08:35:01 +04:00
|
|
|
* Fills aRanges with MediaByteRanges representing the data which is cached
|
2011-03-24 01:28:58 +03:00
|
|
|
* in the media cache. Stream should be pinned during call and while
|
|
|
|
* aRanges is being used.
|
|
|
|
*/
|
2015-11-24 12:16:52 +03:00
|
|
|
virtual nsresult GetCachedRanges(MediaByteRangeSet& aRanges) = 0;
|
2012-12-07 03:27:08 +04:00
|
|
|
|
|
|
|
// Ensure that the media cache writes any data held in its partial block.
|
|
|
|
// Called on the main thread only.
|
|
|
|
virtual void FlushCache() { }
|
|
|
|
|
|
|
|
// Notify that the last data byte range was loaded.
|
|
|
|
virtual void NotifyLastByteRange() { }
|
2013-02-15 05:10:58 +04:00
|
|
|
|
|
|
|
// Returns the content type of the resource. This is copied from the
|
|
|
|
// nsIChannel when the MediaResource is created. Safe to call from
|
|
|
|
// any thread.
|
2013-02-26 15:02:20 +04:00
|
|
|
virtual const nsCString& GetContentType() const = 0;
|
2013-09-23 13:53:36 +04:00
|
|
|
|
|
|
|
// Get the RtspMediaResource pointer if this MediaResource really is a
|
|
|
|
// RtspMediaResource. For calling Rtsp specific functions.
|
|
|
|
virtual RtspMediaResource* GetRtspPointer() {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return true if the stream is a live stream
|
|
|
|
virtual bool IsRealTime() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-03-23 13:08:05 +03:00
|
|
|
// Returns true if the resource is a live stream.
|
|
|
|
virtual bool IsLiveStream()
|
|
|
|
{
|
|
|
|
return GetLength() == -1;
|
|
|
|
}
|
|
|
|
|
2014-03-06 01:31:04 +04:00
|
|
|
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
|
|
|
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
|
2015-06-10 21:48:00 +03:00
|
|
|
const nsCString& GetContentURL() const { return EmptyCString(); }
|
|
|
|
|
2013-05-03 02:59:18 +04:00
|
|
|
protected:
|
|
|
|
virtual ~MediaResource() {};
|
2014-02-26 04:36:54 +04:00
|
|
|
|
|
|
|
private:
|
|
|
|
void Destroy();
|
2012-11-17 08:31:53 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
class BaseMediaResource : public MediaResource {
|
|
|
|
public:
|
2016-01-18 06:50:29 +03:00
|
|
|
nsIURI* URI() const override { return mURI; }
|
|
|
|
void SetLoadInBackground(bool aLoadInBackground) override;
|
2011-03-24 01:28:58 +03:00
|
|
|
|
2016-01-18 06:50:29 +03:00
|
|
|
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
2014-03-06 01:31:04 +04:00
|
|
|
{
|
|
|
|
// Might be useful to track in the future:
|
|
|
|
// - mChannel
|
|
|
|
// - mURI (possibly owned, looks like just a ref from mChannel)
|
|
|
|
// Not owned:
|
2015-10-27 05:28:26 +03:00
|
|
|
// - mCallback
|
2014-03-06 01:31:04 +04:00
|
|
|
size_t size = MediaResource::SizeOfExcludingThis(aMallocSizeOf);
|
2014-04-30 01:47:56 +04:00
|
|
|
size += mContentType.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
2014-03-06 01:31:04 +04:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-01-18 06:50:29 +03:00
|
|
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
|
2014-03-06 01:31:04 +04:00
|
|
|
{
|
|
|
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
|
2015-06-10 21:48:00 +03:00
|
|
|
// Returns the url of the resource. Safe to call from any thread?
|
|
|
|
const nsCString& GetContentURL() const
|
|
|
|
{
|
|
|
|
return mContentURL;
|
|
|
|
}
|
|
|
|
|
2009-03-30 05:19:10 +04:00
|
|
|
protected:
|
2015-10-27 05:28:26 +03:00
|
|
|
BaseMediaResource(MediaResourceCallback* aCallback,
|
2013-02-15 05:10:58 +04:00
|
|
|
nsIChannel* aChannel,
|
|
|
|
nsIURI* aURI,
|
|
|
|
const nsACString& aContentType) :
|
2015-10-27 05:28:26 +03:00
|
|
|
mCallback(aCallback),
|
2014-02-26 04:36:54 +04:00
|
|
|
mChannel(aChannel),
|
|
|
|
mURI(aURI),
|
2013-02-15 05:10:58 +04:00
|
|
|
mContentType(aContentType),
|
2011-09-30 03:34:37 +04:00
|
|
|
mLoadInBackground(false)
|
2009-03-30 05:19:10 +04:00
|
|
|
{
|
2012-11-17 08:31:53 +04:00
|
|
|
MOZ_COUNT_CTOR(BaseMediaResource);
|
2013-02-15 05:10:58 +04:00
|
|
|
NS_ASSERTION(!mContentType.IsEmpty(), "Must know content type");
|
2015-06-10 21:48:00 +03:00
|
|
|
mURI->GetSpec(mContentURL);
|
2012-11-17 08:31:53 +04:00
|
|
|
}
|
|
|
|
virtual ~BaseMediaResource()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(BaseMediaResource);
|
2009-03-30 05:19:10 +04:00
|
|
|
}
|
|
|
|
|
2016-01-18 06:50:29 +03:00
|
|
|
const nsCString& GetContentType() const override
|
2013-02-15 05:10:58 +04:00
|
|
|
{
|
|
|
|
return mContentType;
|
|
|
|
}
|
|
|
|
|
2011-02-15 02:21:32 +03:00
|
|
|
// Set the request's load flags to aFlags. If the request is part of a
|
|
|
|
// load group, the request is removed from the group, the flags are set, and
|
|
|
|
// then the request is added back to the load group.
|
|
|
|
void ModifyLoadFlags(nsLoadFlags aFlags);
|
|
|
|
|
2013-09-18 07:37:23 +04:00
|
|
|
// Dispatches an event to call MediaDecoder::NotifyBytesConsumed(aNumBytes, aOffset)
|
|
|
|
// on the main thread. This is called automatically after every read.
|
|
|
|
void DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset);
|
|
|
|
|
2015-11-16 02:50:55 +03:00
|
|
|
RefPtr<MediaResourceCallback> mCallback;
|
2009-03-30 05:19:10 +04:00
|
|
|
|
|
|
|
// Channel used to download the media data. Must be accessed
|
|
|
|
// from the main thread only.
|
2014-02-26 04:36:54 +04:00
|
|
|
nsCOMPtr<nsIChannel> mChannel;
|
2009-03-30 05:19:10 +04:00
|
|
|
|
|
|
|
// URI in case the stream needs to be re-opened. Access from
|
|
|
|
// main thread only.
|
2014-02-26 04:36:54 +04:00
|
|
|
nsCOMPtr<nsIURI> mURI;
|
2009-04-10 05:28:24 +04:00
|
|
|
|
2013-02-15 05:10:58 +04:00
|
|
|
// Content-Type of the channel. This is copied from the nsIChannel when the
|
|
|
|
// MediaResource is created. This is constant, so accessing from any thread
|
|
|
|
// is safe.
|
2015-11-19 12:00:39 +03:00
|
|
|
const nsCString mContentType;
|
2013-02-15 05:10:58 +04:00
|
|
|
|
2015-06-10 21:48:00 +03:00
|
|
|
// Copy of the url of the channel resource.
|
2015-11-19 12:00:39 +03:00
|
|
|
nsCString mContentURL;
|
2015-06-10 21:48:00 +03:00
|
|
|
|
2014-12-23 04:16:05 +03:00
|
|
|
// True if SetLoadInBackground() has been called with
|
|
|
|
// aLoadInBackground = true, i.e. when the document load event is not
|
|
|
|
// blocked by this resource, and all channel loads will be in the
|
|
|
|
// background.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mLoadInBackground;
|
2009-04-01 04:52:56 +04:00
|
|
|
};
|
|
|
|
|
2015-08-19 07:43:25 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This class is responsible for managing the suspend count and report suspend
|
|
|
|
* status of channel.
|
|
|
|
**/
|
|
|
|
class ChannelSuspendAgent {
|
|
|
|
public:
|
|
|
|
explicit ChannelSuspendAgent(nsIChannel* aChannel)
|
|
|
|
: mChannel(aChannel),
|
|
|
|
mSuspendCount(0),
|
|
|
|
mIsChannelSuspended(false)
|
|
|
|
{}
|
|
|
|
|
|
|
|
// True when the channel has been suspended or needs to be suspended.
|
|
|
|
bool IsSuspended();
|
|
|
|
|
|
|
|
// Return true when the channel is logically suspended, i.e. the suspend
|
|
|
|
// count goes from 0 to 1.
|
|
|
|
bool Suspend();
|
|
|
|
|
|
|
|
// Return true only when the suspend count is equal to zero.
|
|
|
|
bool Resume();
|
|
|
|
|
|
|
|
// Call after opening channel, set channel and check whether the channel
|
|
|
|
// needs to be suspended.
|
|
|
|
void NotifyChannelOpened(nsIChannel* aChannel);
|
|
|
|
|
|
|
|
// Call before closing channel, reset the channel internal status if needed.
|
|
|
|
void NotifyChannelClosing();
|
|
|
|
|
|
|
|
// Check whether we need to suspend the channel.
|
|
|
|
void UpdateSuspendedStatusIfNeeded();
|
|
|
|
private:
|
|
|
|
// Only suspends channel but not changes the suspend count.
|
|
|
|
void SuspendInternal();
|
|
|
|
|
|
|
|
nsIChannel* mChannel;
|
|
|
|
Atomic<uint32_t> mSuspendCount;
|
|
|
|
bool mIsChannelSuspended;
|
|
|
|
};
|
|
|
|
|
2009-04-01 04:52:56 +04:00
|
|
|
/**
|
2012-02-15 08:35:01 +04:00
|
|
|
* This is the MediaResource implementation that wraps Necko channels.
|
2012-11-14 23:46:40 +04:00
|
|
|
* Much of its functionality is actually delegated to MediaCache via
|
|
|
|
* an underlying MediaCacheStream.
|
2009-04-01 04:52:56 +04:00
|
|
|
*
|
2012-11-14 23:46:40 +04:00
|
|
|
* All synchronization is performed by MediaCacheStream; all off-main-
|
2009-04-01 04:52:56 +04:00
|
|
|
* thread operations are delegated directly to that object.
|
|
|
|
*/
|
2012-11-17 08:31:53 +04:00
|
|
|
class ChannelMediaResource : public BaseMediaResource
|
2009-04-01 04:52:56 +04:00
|
|
|
{
|
|
|
|
public:
|
2015-10-27 05:28:26 +03:00
|
|
|
ChannelMediaResource(MediaResourceCallback* aDecoder,
|
2013-02-15 05:10:58 +04:00
|
|
|
nsIChannel* aChannel,
|
|
|
|
nsIURI* aURI,
|
|
|
|
const nsACString& aContentType);
|
2012-02-15 08:35:01 +04:00
|
|
|
~ChannelMediaResource();
|
2009-04-01 04:52:56 +04:00
|
|
|
|
2012-11-14 23:46:40 +04:00
|
|
|
// These are called on the main thread by MediaCache. These must
|
2009-10-09 15:46:23 +04:00
|
|
|
// not block or grab locks, because the media cache is holding its lock.
|
2009-09-15 06:30:45 +04:00
|
|
|
// Notify that data is available from the cache. This can happen even
|
|
|
|
// if this stream didn't read any data, since another stream might have
|
|
|
|
// received data for the same resource.
|
|
|
|
void CacheClientNotifyDataReceived();
|
|
|
|
// Notify that we reached the end of the stream. This can happen even
|
|
|
|
// if this stream didn't read any data, since another stream might have
|
|
|
|
// received data for the same resource.
|
|
|
|
void CacheClientNotifyDataEnded(nsresult aStatus);
|
2012-04-30 07:12:42 +04:00
|
|
|
// Notify that the principal for the cached resource changed.
|
|
|
|
void CacheClientNotifyPrincipalChanged();
|
2014-12-19 01:48:00 +03:00
|
|
|
// Notify the decoder that the cache suspended status changed.
|
|
|
|
void CacheClientNotifySuspendedStatusChanged();
|
2009-10-09 15:46:23 +04:00
|
|
|
|
2012-11-14 23:46:40 +04:00
|
|
|
// These are called on the main thread by MediaCache. These shouldn't block,
|
2009-10-09 15:46:23 +04:00
|
|
|
// but they may grab locks --- the media cache is not holding its lock
|
|
|
|
// when these are called.
|
2009-04-01 04:52:56 +04:00
|
|
|
// Start a new load at the given aOffset. The old load is cancelled
|
|
|
|
// and no more data from the old load will be notified via
|
2012-11-14 23:46:40 +04:00
|
|
|
// MediaCacheStream::NotifyDataReceived/Ended.
|
2009-04-01 04:52:56 +04:00
|
|
|
// This can fail.
|
2012-08-22 19:56:38 +04:00
|
|
|
nsresult CacheClientSeek(int64_t aOffset, bool aResume);
|
2009-04-01 04:52:56 +04:00
|
|
|
// Suspend the current load since data is currently not wanted
|
|
|
|
nsresult CacheClientSuspend();
|
|
|
|
// Resume the current load since data is wanted again
|
|
|
|
nsresult CacheClientResume();
|
|
|
|
|
2012-12-07 03:27:08 +04:00
|
|
|
// Ensure that the media cache writes any data held in its partial block.
|
|
|
|
// Called on the main thread.
|
2016-01-18 06:50:29 +03:00
|
|
|
void FlushCache() override;
|
2012-12-07 03:27:08 +04:00
|
|
|
|
|
|
|
// Notify that the last data byte range was loaded.
|
2016-01-18 06:50:29 +03:00
|
|
|
void NotifyLastByteRange() override;
|
2012-12-07 03:27:08 +04:00
|
|
|
|
2009-04-01 04:52:56 +04:00
|
|
|
// Main thread
|
2016-01-18 06:50:29 +03:00
|
|
|
nsresult Open(nsIStreamListener** aStreamListener) override;
|
|
|
|
nsresult Close() override;
|
|
|
|
void Suspend(bool aCloseImmediately) override;
|
|
|
|
void Resume() override;
|
|
|
|
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
2011-09-30 03:34:37 +04:00
|
|
|
// Return true if the stream has been closed.
|
2016-01-18 06:50:29 +03:00
|
|
|
bool IsClosed() const { return mCacheStream.IsClosed(); }
|
|
|
|
bool CanClone() override;
|
|
|
|
already_AddRefed<MediaResource> CloneData(MediaResourceCallback* aDecoder) override;
|
2012-12-13 23:42:45 +04:00
|
|
|
// Set statistics to be recorded to the object passed in. If not called,
|
|
|
|
// |ChannelMediaResource| will create it's own statistics objects in |Open|.
|
2015-03-21 19:28:04 +03:00
|
|
|
void RecordStatisticsTo(MediaChannelStatistics *aStatistics) override {
|
2012-12-13 23:42:45 +04:00
|
|
|
NS_ASSERTION(aStatistics, "Statistics param cannot be null!");
|
|
|
|
MutexAutoLock lock(mLock);
|
|
|
|
if (!mChannelStatistics) {
|
|
|
|
mChannelStatistics = aStatistics;
|
|
|
|
}
|
|
|
|
}
|
2016-01-18 06:50:29 +03:00
|
|
|
nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override;
|
|
|
|
void EnsureCacheUpToDate() override;
|
2009-04-01 04:52:56 +04:00
|
|
|
|
|
|
|
// Other thread
|
2016-01-18 06:50:29 +03:00
|
|
|
void SetReadMode(MediaCacheStream::ReadMode aMode) override;
|
|
|
|
void SetPlaybackRate(uint32_t aBytesPerSecond) override;
|
|
|
|
nsresult ReadAt(int64_t offset, char* aBuffer,
|
|
|
|
uint32_t aCount, uint32_t* aBytes) override;
|
|
|
|
already_AddRefed<MediaByteBuffer> MediaReadAt(int64_t aOffset, uint32_t aCount) override;
|
|
|
|
int64_t Tell() override;
|
2009-04-01 04:52:56 +04:00
|
|
|
|
|
|
|
// Any thread
|
2016-01-18 06:50:29 +03:00
|
|
|
void Pin() override;
|
|
|
|
void Unpin() override;
|
|
|
|
double GetDownloadRate(bool* aIsReliable) override;
|
|
|
|
int64_t GetLength() override;
|
|
|
|
int64_t GetNextCachedData(int64_t aOffset) override;
|
|
|
|
int64_t GetCachedDataEnd(int64_t aOffset) override;
|
|
|
|
bool IsDataCachedToEndOfResource(int64_t aOffset) override;
|
|
|
|
bool IsSuspendedByCache() override;
|
|
|
|
bool IsSuspended() override;
|
|
|
|
bool IsTransportSeekable() override;
|
|
|
|
|
|
|
|
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
|
2014-03-06 01:31:04 +04:00
|
|
|
// Might be useful to track in the future:
|
|
|
|
// - mListener (seems minor)
|
|
|
|
// - mChannelStatistics (seems minor)
|
|
|
|
// owned if RecordStatisticsTo is not called
|
|
|
|
// - mDataReceivedEvent (seems minor)
|
|
|
|
size_t size = BaseMediaResource::SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
size += mCacheStream.SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-01-18 06:50:29 +03:00
|
|
|
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
|
2014-03-06 01:31:04 +04:00
|
|
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
class Listener final : public nsIStreamListener,
|
2015-03-27 21:52:19 +03:00
|
|
|
public nsIInterfaceRequestor,
|
|
|
|
public nsIChannelEventSink
|
2009-05-14 01:52:50 +04:00
|
|
|
{
|
2014-06-24 20:36:43 +04:00
|
|
|
~Listener() {}
|
2009-04-01 04:52:56 +04:00
|
|
|
public:
|
2014-09-01 07:50:23 +04:00
|
|
|
explicit Listener(ChannelMediaResource* aResource) : mResource(aResource) {}
|
2009-04-01 04:52:56 +04:00
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIREQUESTOBSERVER
|
|
|
|
NS_DECL_NSISTREAMLISTENER
|
2009-05-14 01:52:50 +04:00
|
|
|
NS_DECL_NSICHANNELEVENTSINK
|
|
|
|
NS_DECL_NSIINTERFACEREQUESTOR
|
2009-04-01 04:52:56 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
void Revoke() { mResource = nullptr; }
|
2009-04-01 04:52:56 +04:00
|
|
|
|
|
|
|
private:
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ChannelMediaResource> mResource;
|
2009-04-01 04:52:56 +04:00
|
|
|
};
|
|
|
|
friend class Listener;
|
|
|
|
|
2016-01-18 06:50:29 +03:00
|
|
|
nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
|
2011-03-24 01:28:58 +03:00
|
|
|
|
2009-09-15 06:30:45 +04:00
|
|
|
protected:
|
2009-04-01 04:52:56 +04:00
|
|
|
// These are called on the main thread by Listener.
|
|
|
|
nsresult OnStartRequest(nsIRequest* aRequest);
|
|
|
|
nsresult OnStopRequest(nsIRequest* aRequest, nsresult aStatus);
|
|
|
|
nsresult OnDataAvailable(nsIRequest* aRequest,
|
|
|
|
nsIInputStream* aStream,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aCount);
|
|
|
|
nsresult OnChannelRedirect(nsIChannel* aOld, nsIChannel* aNew, uint32_t aFlags);
|
2009-04-01 04:52:56 +04:00
|
|
|
|
2009-05-18 06:02:20 +04:00
|
|
|
// Opens the channel, using an HTTP byte range request to start at mOffset
|
2009-04-01 04:52:56 +04:00
|
|
|
// if possible. Main thread only.
|
2009-05-18 06:02:20 +04:00
|
|
|
nsresult OpenChannel(nsIStreamListener** aStreamListener);
|
2009-09-15 06:30:44 +04:00
|
|
|
nsresult RecreateChannel();
|
2010-07-29 08:58:07 +04:00
|
|
|
// Add headers to HTTP request. Main thread only.
|
2014-05-11 22:43:00 +04:00
|
|
|
nsresult SetupChannelHeaders();
|
2009-04-01 04:52:56 +04:00
|
|
|
// Closes the channel. Main thread only.
|
|
|
|
void CloseChannel();
|
|
|
|
|
2012-09-30 03:29:04 +04:00
|
|
|
// Parses 'Content-Range' header and returns results via parameters.
|
|
|
|
// Returns error if header is not available, values are not parse-able or
|
|
|
|
// values are out of range.
|
|
|
|
nsresult ParseContentRangeHeader(nsIHttpChannel * aHttpChan,
|
|
|
|
int64_t& aRangeStart,
|
|
|
|
int64_t& aRangeEnd,
|
|
|
|
int64_t& aRangeTotal);
|
|
|
|
|
2009-09-15 06:30:45 +04:00
|
|
|
void DoNotifyDataReceived();
|
|
|
|
|
2009-04-01 04:52:56 +04:00
|
|
|
static NS_METHOD CopySegmentToCache(nsIInputStream *aInStream,
|
|
|
|
void *aClosure,
|
|
|
|
const char *aFromSegment,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aToOffset,
|
|
|
|
uint32_t aCount,
|
|
|
|
uint32_t *aWriteCount);
|
2009-04-01 04:52:56 +04:00
|
|
|
|
|
|
|
// Main thread access only
|
2012-08-22 19:56:38 +04:00
|
|
|
int64_t mOffset;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Listener> mListener;
|
2009-09-15 06:30:45 +04:00
|
|
|
// A data received event for the decoder that has been dispatched but has
|
|
|
|
// not yet been processed.
|
2012-02-15 08:35:01 +04:00
|
|
|
nsRevocableEventPtr<nsRunnableMethod<ChannelMediaResource, void, false> > mDataReceivedEvent;
|
2009-05-18 06:02:20 +04:00
|
|
|
// When this flag is set, if we get a network error we should silently
|
|
|
|
// reopen the stream.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mReopenOnError;
|
2009-05-18 06:02:20 +04:00
|
|
|
// When this flag is set, we should not report the next close of the
|
|
|
|
// channel.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mIgnoreClose;
|
2009-04-01 04:52:56 +04:00
|
|
|
|
|
|
|
// Any thread access
|
2012-11-14 23:46:40 +04:00
|
|
|
MediaCacheStream mCacheStream;
|
2009-03-30 05:19:10 +04:00
|
|
|
|
2011-11-30 09:05:49 +04:00
|
|
|
// This lock protects mChannelStatistics
|
Rollup of bug 645263 and bug 646259: Switch to mozilla:: sync primitives. r=cjones,dbaron,doublec,ehsan src=bsmedberg
Bug 645263, part 0: Count sync primitive ctor/dtors. r=dbaron
Bug 645263, part 1: Migrate content/media to mozilla:: sync primitives. r=doublec
Bug 645263, part 2: Migrate modules/plugin to mozilla:: sync primitives. sr=bsmedberg
Bug 645263, part 3: Migrate nsComponentManagerImpl to mozilla:: sync primitives. sr=bsmedberg
Bug 645263, part 4: Migrate everything else to mozilla:: sync primitives. r=dbaron
Bug 645263, part 5: Remove nsAutoLock.*. sr=bsmedberg
Bug 645263, part 6: Make editor test be nicer to deadlock detector. r=ehsan
Bug 645263, part 7: Disable tracemalloc backtraces for xpcshell tests. r=dbaron
Bug 646259: Fix nsCacheService to use a CondVar for notifying. r=cjones
2011-04-01 08:29:02 +04:00
|
|
|
Mutex mLock;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaChannelStatistics> mChannelStatistics;
|
2011-04-01 13:43:29 +04:00
|
|
|
|
2011-09-30 03:34:37 +04:00
|
|
|
// True if we couldn't suspend the stream and we therefore don't want
|
2011-04-01 13:43:29 +04:00
|
|
|
// to resume later. This is usually due to the channel not being in the
|
|
|
|
// isPending state at the time of the suspend request.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mIgnoreResume;
|
2012-08-17 21:01:08 +04:00
|
|
|
|
2013-04-03 04:05:00 +04:00
|
|
|
// True if the stream can seek into unbuffered ranged, i.e. if the
|
|
|
|
// connection supports byte range requests.
|
|
|
|
bool mIsTransportSeekable;
|
2015-08-19 07:43:25 +03:00
|
|
|
|
|
|
|
ChannelSuspendAgent mSuspendAgent;
|
2008-10-19 11:39:21 +04:00
|
|
|
};
|
|
|
|
|
2014-11-12 07:50:21 +03:00
|
|
|
/**
|
|
|
|
* RAII class that handles pinning and unpinning for MediaResource and derived.
|
|
|
|
* This should be used when making calculations that involve potentially-cached
|
|
|
|
* MediaResource data, so that the state of the world can't change out from under
|
|
|
|
* us.
|
|
|
|
*/
|
|
|
|
template<class T>
|
2015-09-03 19:15:23 +03:00
|
|
|
class MOZ_RAII AutoPinned {
|
2014-11-12 07:50:21 +03:00
|
|
|
public:
|
|
|
|
explicit AutoPinned(T* aResource MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mResource(aResource) {
|
|
|
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
|
|
MOZ_ASSERT(mResource);
|
|
|
|
mResource->Pin();
|
|
|
|
}
|
|
|
|
|
|
|
|
~AutoPinned() {
|
|
|
|
mResource->Unpin();
|
|
|
|
}
|
|
|
|
|
|
|
|
operator T*() const { return mResource; }
|
2014-12-25 23:18:38 +03:00
|
|
|
T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mResource; }
|
2014-11-12 07:50:21 +03:00
|
|
|
|
|
|
|
private:
|
|
|
|
T* mResource;
|
|
|
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
|
|
|
};
|
|
|
|
|
2015-08-13 04:15:48 +03:00
|
|
|
/*
|
|
|
|
* MediaResourceIndex provides a way to access MediaResource objects.
|
|
|
|
* Read, Seek and Tell must only be called on non-main threads.
|
|
|
|
* In the case of the Ogg Decoder they are called on the Decode thread for
|
|
|
|
* example. You must ensure that no threads are calling these methods once
|
|
|
|
* the MediaResource has been Closed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class MediaResourceIndex
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit MediaResourceIndex(MediaResource* aResource)
|
|
|
|
: mResource(aResource)
|
|
|
|
, mOffset(0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
// Read up to aCount bytes from the stream. The buffer must have
|
|
|
|
// enough room for at least aCount bytes. Stores the number of
|
|
|
|
// actual bytes read in aBytes (0 on end of file).
|
|
|
|
// May read less than aCount bytes if the number of
|
|
|
|
// available bytes is less than aCount. Always check *aBytes after
|
|
|
|
// read, and call again if necessary.
|
|
|
|
nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes);
|
|
|
|
// Seek to the given bytes offset in the stream. aWhence can be
|
|
|
|
// one of:
|
|
|
|
// NS_SEEK_SET
|
|
|
|
// NS_SEEK_CUR
|
|
|
|
// NS_SEEK_END
|
|
|
|
//
|
|
|
|
// In the Http strategy case the cancel will cause the http
|
|
|
|
// channel's listener to close the pipe, forcing an i/o error on any
|
|
|
|
// blocked read. This will allow the decode thread to complete the
|
|
|
|
// event.
|
|
|
|
//
|
|
|
|
// In the case of a seek in progress, the byte range request creates
|
|
|
|
// a new listener. This is done on the main thread via seek
|
|
|
|
// synchronously dispatching an event. This avoids the issue of us
|
|
|
|
// closing the listener but an outstanding byte range request
|
|
|
|
// creating a new one. They run on the same thread so no explicit
|
|
|
|
// synchronisation is required. The byte range request checks for
|
|
|
|
// the cancel flag and does not create a new channel or listener if
|
|
|
|
// we are cancelling.
|
|
|
|
//
|
|
|
|
// The default strategy does not do any seeking - the only issue is
|
|
|
|
// a blocked read which it handles by causing the listener to close
|
|
|
|
// the pipe, as per the http case.
|
|
|
|
//
|
|
|
|
// The file strategy doesn't block for any great length of time so
|
|
|
|
// is fine for a no-op cancel.
|
|
|
|
nsresult Seek(int32_t aWhence, int64_t aOffset);
|
|
|
|
// Report the current offset in bytes from the start of the stream.
|
|
|
|
int64_t Tell() const { return mOffset; }
|
|
|
|
|
|
|
|
// Return the underlying MediaResource.
|
|
|
|
MediaResource* GetResource() const { return mResource; }
|
|
|
|
|
2015-08-13 04:18:34 +03:00
|
|
|
// Read up to aCount bytes from the stream. The read starts at
|
|
|
|
// aOffset in the stream, seeking to that location initially if
|
|
|
|
// it is not the current stream offset.
|
|
|
|
// Unlike MediaResource::ReadAt, ReadAt only returns fewer bytes than
|
|
|
|
// requested if end of stream or an error is encountered. There is no need to
|
|
|
|
// call it again to get more data.
|
|
|
|
// *aBytes will contain the number of bytes copied, even if an error occurred.
|
|
|
|
// ReadAt doesn't have an impact on the offset returned by Tell().
|
|
|
|
nsresult ReadAt(int64_t aOffset, char* aBuffer,
|
|
|
|
uint32_t aCount, uint32_t* aBytes) const;
|
|
|
|
|
2015-08-13 04:15:48 +03:00
|
|
|
// Convenience methods, directly calling the MediaResource method of the same
|
|
|
|
// name.
|
|
|
|
// Those functions do not update the MediaResource offset as returned
|
|
|
|
// by Tell().
|
|
|
|
|
|
|
|
// This method returns nullptr if anything fails.
|
|
|
|
// Otherwise, it returns an owned buffer.
|
|
|
|
// MediaReadAt may return fewer bytes than requested if end of stream is
|
|
|
|
// encountered. There is no need to call it again to get more data.
|
|
|
|
already_AddRefed<MediaByteBuffer> MediaReadAt(int64_t aOffset, uint32_t aCount) const
|
|
|
|
{
|
|
|
|
return mResource->MediaReadAt(aOffset, aCount);
|
|
|
|
}
|
|
|
|
// Get the length of the stream in bytes. Returns -1 if not known.
|
|
|
|
// This can change over time; after a seek operation, a misbehaving
|
|
|
|
// server may give us a resource of a different length to what it had
|
|
|
|
// reported previously --- or it may just lie in its Content-Length
|
|
|
|
// header and give us more or less data than it reported. We will adjust
|
|
|
|
// the result of GetLength to reflect the data that's actually arriving.
|
|
|
|
int64_t GetLength() const { return mResource->GetLength(); }
|
|
|
|
|
|
|
|
private:
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaResource> mResource;
|
2015-08-13 04:15:48 +03:00
|
|
|
int64_t mOffset;
|
|
|
|
};
|
|
|
|
|
2012-11-14 23:45:33 +04:00
|
|
|
} // namespace mozilla
|
2012-02-15 08:35:01 +04:00
|
|
|
|
2008-10-19 11:39:21 +04:00
|
|
|
#endif
|