Bug 1374930. P4 - move ResourceCallback to ChannelMediaDecoder. r=cpearce

We also move some methods to protected so they are callable from ChannelMediaDecoder.

MozReview-Commit-ID: 6s9LKNkbJhX

--HG--
extra : rebase_source : 172ea88bc01552a90f5ef51db2b5af0ac5551c3b
extra : intermediate-source : a724333159c6b408e2fa68dba2d0a467f3c55940
extra : source : 03760e05ea8044b3404d29bb62205a2f62892d4b
This commit is contained in:
JW Wang 2017-06-20 18:10:56 +08:00
Родитель 61f7ca2479
Коммит 6cd0d57b3c
4 изменённых файлов: 230 добавлений и 226 удалений

Просмотреть файл

@ -9,9 +9,157 @@
namespace mozilla {
ChannelMediaDecoder::ResourceCallback::ResourceCallback(
AbstractThread* aMainThread)
: mAbstractMainThread(aMainThread)
{
MOZ_ASSERT(aMainThread);
}
void
ChannelMediaDecoder::ResourceCallback::Connect(ChannelMediaDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
mDecoder = aDecoder;
mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->SetTarget(mAbstractMainThread->AsEventTarget());
}
void
ChannelMediaDecoder::ResourceCallback::Disconnect()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder = nullptr;
mTimer->Cancel();
mTimer = nullptr;
}
}
MediaDecoderOwner*
ChannelMediaDecoder::ResourceCallback::GetMediaOwner() const
{
MOZ_ASSERT(NS_IsMainThread());
return mDecoder ? mDecoder->GetOwner() : nullptr;
}
void
ChannelMediaDecoder::ResourceCallback::SetInfinite(bool aInfinite)
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->SetInfinite(aInfinite);
}
}
void
ChannelMediaDecoder::ResourceCallback::NotifyNetworkError()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NetworkError();
}
}
/* static */ void
ChannelMediaDecoder::ResourceCallback::TimerCallback(nsITimer* aTimer,
void* aClosure)
{
MOZ_ASSERT(NS_IsMainThread());
ResourceCallback* thiz = static_cast<ResourceCallback*>(aClosure);
MOZ_ASSERT(thiz->mDecoder);
thiz->mDecoder->NotifyDataArrivedInternal();
thiz->mTimerArmed = false;
}
void
ChannelMediaDecoder::ResourceCallback::NotifyDataArrived()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mDecoder) {
return;
}
mDecoder->DownloadProgressed();
if (mTimerArmed) {
return;
}
// In situations where these notifications come from stochastic network
// activity, we can save significant computation by throttling the
// calls to MediaDecoder::NotifyDataArrived() which will update the buffer
// ranges of the reader.
mTimerArmed = true;
mTimer->InitWithFuncCallback(
TimerCallback, this, sDelay, nsITimer::TYPE_ONE_SHOT);
}
void
ChannelMediaDecoder::ResourceCallback::NotifyDataEnded(nsresult aStatus)
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=]() {
if (!self->mDecoder) {
return;
}
self->mDecoder->NotifyDownloadEnded(aStatus);
if (NS_SUCCEEDED(aStatus)) {
MediaDecoderOwner* owner = self->GetMediaOwner();
MOZ_ASSERT(owner);
owner->DownloadSuspended();
// NotifySuspendedStatusChanged will tell the element that download
// has been suspended "by the cache", which is true since we never
// download anything. The element can then transition to HAVE_ENOUGH_DATA.
self->mDecoder->NotifySuspendedStatusChanged();
}
});
mAbstractMainThread->Dispatch(r.forget());
}
void
ChannelMediaDecoder::ResourceCallback::NotifyPrincipalChanged()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NotifyPrincipalChanged();
}
}
void
ChannelMediaDecoder::ResourceCallback::NotifySuspendedStatusChanged()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NotifySuspendedStatusChanged();
}
}
void
ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes,
int64_t aOffset)
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=]() {
if (self->mDecoder) {
self->mDecoder->NotifyBytesConsumed(aBytes, aOffset);
}
});
mAbstractMainThread->Dispatch(r.forget());
}
ChannelMediaDecoder::ChannelMediaDecoder(MediaDecoderInit& aInit)
: MediaDecoder(aInit)
, mResourceCallback(new ResourceCallback(aInit.mOwner->AbstractMainThread()))
{
mResourceCallback->Connect(this);
}
void
ChannelMediaDecoder::Shutdown()
{
mResourceCallback->Disconnect();
MediaDecoder::Shutdown();
}
} // namespace mozilla

Просмотреть файл

@ -8,14 +8,61 @@
#define ChannelMediaDecoder_h_
#include "MediaDecoder.h"
#include "MediaResourceCallback.h"
namespace mozilla {
class ChannelMediaDecoder : public MediaDecoder
{
// Used to register with MediaResource to receive notifications which will
// be forwarded to MediaDecoder.
class ResourceCallback : public MediaResourceCallback
{
// Throttle calls to MediaDecoder::NotifyDataArrived()
// to be at most once per 500ms.
static const uint32_t sDelay = 500;
public:
explicit ResourceCallback(AbstractThread* aMainThread);
// Start to receive notifications from ResourceCallback.
void Connect(ChannelMediaDecoder* aDecoder);
// Called upon shutdown to stop receiving notifications.
void Disconnect();
private:
/* MediaResourceCallback functions */
MediaDecoderOwner* GetMediaOwner() const override;
void SetInfinite(bool aInfinite) override;
void NotifyNetworkError() override;
void NotifyDataArrived() override;
void NotifyDataEnded(nsresult aStatus) override;
void NotifyPrincipalChanged() override;
void NotifySuspendedStatusChanged() override;
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) override;
static void TimerCallback(nsITimer* aTimer, void* aClosure);
// The decoder to send notifications. Main-thread only.
ChannelMediaDecoder* mDecoder = nullptr;
nsCOMPtr<nsITimer> mTimer;
bool mTimerArmed = false;
const RefPtr<AbstractThread> mAbstractMainThread;
};
RefPtr<ResourceCallback> mResourceCallback;
public:
explicit ChannelMediaDecoder(MediaDecoderInit& aInit);
// Return a callback object used to register with MediaResource to receive
// notifications.
MediaResourceCallback* GetResourceCallback() const
{
return mResourceCallback;
}
void Shutdown() override;
// Create a new decoder of the same type as this one.
// Subclasses must implement this.
virtual ChannelMediaDecoder* Clone(MediaDecoderInit& aInit) = 0;

Просмотреть файл

@ -142,142 +142,7 @@ NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
NS_IMPL_ISUPPORTS0(MediaDecoder)
MediaDecoder::ResourceCallback::ResourceCallback(AbstractThread* aMainThread)
: mAbstractMainThread(aMainThread)
{
MOZ_ASSERT(aMainThread);
}
void
MediaDecoder::ResourceCallback::Connect(MediaDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
mDecoder = aDecoder;
mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->SetTarget(mAbstractMainThread->AsEventTarget());
}
void
MediaDecoder::ResourceCallback::Disconnect()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder = nullptr;
mTimer->Cancel();
mTimer = nullptr;
}
}
MediaDecoderOwner*
MediaDecoder::ResourceCallback::GetMediaOwner() const
{
MOZ_ASSERT(NS_IsMainThread());
return mDecoder ? mDecoder->GetOwner() : nullptr;
}
void
MediaDecoder::ResourceCallback::SetInfinite(bool aInfinite)
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->SetInfinite(aInfinite);
}
}
void
MediaDecoder::ResourceCallback::NotifyNetworkError()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NetworkError();
}
}
/* static */ void
MediaDecoder::ResourceCallback::TimerCallback(nsITimer* aTimer, void* aClosure)
{
MOZ_ASSERT(NS_IsMainThread());
ResourceCallback* thiz = static_cast<ResourceCallback*>(aClosure);
MOZ_ASSERT(thiz->mDecoder);
thiz->mDecoder->NotifyDataArrivedInternal();
thiz->mTimerArmed = false;
}
void
MediaDecoder::ResourceCallback::NotifyDataArrived()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mDecoder) {
return;
}
mDecoder->DownloadProgressed();
if (mTimerArmed) {
return;
}
// In situations where these notifications come from stochastic network
// activity, we can save significant computation by throttling the
// calls to MediaDecoder::NotifyDataArrived() which will update the buffer
// ranges of the reader.
mTimerArmed = true;
mTimer->InitWithFuncCallback(
TimerCallback, this, sDelay, nsITimer::TYPE_ONE_SHOT);
}
void
MediaDecoder::ResourceCallback::NotifyDataEnded(nsresult aStatus)
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
if (!self->mDecoder) {
return;
}
self->mDecoder->NotifyDownloadEnded(aStatus);
if (NS_SUCCEEDED(aStatus)) {
MediaDecoderOwner* owner = self->GetMediaOwner();
MOZ_ASSERT(owner);
owner->DownloadSuspended();
// NotifySuspendedStatusChanged will tell the element that download
// has been suspended "by the cache", which is true since we never
// download anything. The element can then transition to HAVE_ENOUGH_DATA.
self->mDecoder->NotifySuspendedStatusChanged();
}
});
mAbstractMainThread->Dispatch(r.forget());
}
void
MediaDecoder::ResourceCallback::NotifyPrincipalChanged()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NotifyPrincipalChanged();
}
}
void
MediaDecoder::ResourceCallback::NotifySuspendedStatusChanged()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NotifySuspendedStatusChanged();
}
}
void
MediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes,
int64_t aOffset)
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
if (self->mDecoder) {
self->mDecoder->NotifyBytesConsumed(aBytes, aOffset);
}
});
mAbstractMainThread->Dispatch(r.forget());
}
void
MediaDecoder::NotifyOwnerActivityChanged(bool aIsDocumentVisible,
@ -366,7 +231,6 @@ MediaDecoder::MediaDecoder(MediaDecoderInit& aInit)
: mWatchManager(this, aInit.mOwner->AbstractMainThread())
, mLogicalPosition(0.0)
, mDuration(std::numeric_limits<double>::quiet_NaN())
, mResourceCallback(new ResourceCallback(aInit.mOwner->AbstractMainThread()))
, mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
, mIgnoreProgressData(false)
, mInfiniteStream(false)
@ -410,8 +274,6 @@ MediaDecoder::MediaDecoder(MediaDecoderInit& aInit)
MOZ_ASSERT(mAbstractMainThread);
MediaMemoryTracker::AddMediaDecoder(this);
mResourceCallback->Connect(this);
//
// Initialize watchers.
//
@ -452,8 +314,6 @@ MediaDecoder::Shutdown()
// Unwatch all watch targets to prevent further notifications.
mWatchManager.Shutdown();
mResourceCallback->Disconnect();
mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
DiscardOngoingSeekIfExists();
@ -518,7 +378,6 @@ MediaDecoder::~MediaDecoder()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(IsShutdown());
mResourceCallback->Disconnect();
MediaMemoryTracker::RemoveMediaDecoder(this);
UnpinForSeek();
}
@ -593,12 +452,6 @@ MediaDecoder::FinishShutdown()
MediaShutdownManager::Instance().Unregister(this);
}
MediaResourceCallback*
MediaDecoder::GetResourceCallback() const
{
return mResourceCallback;
}
nsresult
MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
{

Просмотреть файл

@ -13,7 +13,6 @@
#include "MediaEventSource.h"
#include "MediaMetadataManager.h"
#include "MediaResource.h"
#include "MediaResourceCallback.h"
#include "MediaStatistics.h"
#include "MediaStreamGraph.h"
#include "SeekTarget.h"
@ -88,41 +87,6 @@ struct MediaDecoderInit
class MediaDecoder : public AbstractMediaDecoder
{
public:
// Used to register with MediaResource to receive notifications which will
// be forwarded to MediaDecoder.
class ResourceCallback : public MediaResourceCallback
{
// Throttle calls to MediaDecoder::NotifyDataArrived()
// to be at most once per 500ms.
static const uint32_t sDelay = 500;
public:
explicit ResourceCallback(AbstractThread* aMainThread);
// Start to receive notifications from ResourceCallback.
void Connect(MediaDecoder* aDecoder);
// Called upon shutdown to stop receiving notifications.
void Disconnect();
private:
/* MediaResourceCallback functions */
MediaDecoderOwner* GetMediaOwner() const override;
void SetInfinite(bool aInfinite) override;
void NotifyNetworkError() override;
void NotifyDataArrived() override;
void NotifyDataEnded(nsresult aStatus) override;
void NotifyPrincipalChanged() override;
void NotifySuspendedStatusChanged() override;
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) override;
static void TimerCallback(nsITimer* aTimer, void* aClosure);
// The decoder to send notifications. Main-thread only.
MediaDecoder* mDecoder = nullptr;
nsCOMPtr<nsITimer> mTimer;
bool mTimerArmed = false;
const RefPtr<AbstractThread> mAbstractMainThread;
};
typedef MozPromise<bool /* aIgnored */, bool /* aIgnored */,
/* IsExclusive = */ true>
SeekPromise;
@ -145,9 +109,6 @@ public:
explicit MediaDecoder(MediaDecoderInit& aInit);
// Return a callback object used to register with MediaResource to receive
// notifications.
MediaResourceCallback* GetResourceCallback() const;
// Create a new state machine to run this decoder.
// Subclasses must implement this.
virtual MediaDecoderStateMachine* CreateStateMachine() = 0;
@ -578,12 +539,6 @@ protected:
media::TimeUnit::FromMicroseconds(250000);
private:
void NotifyDataArrivedInternal();
// Called to recompute playback rate and notify 'progress' event.
// Call on the main thread only.
void DownloadProgressed();
nsCString GetDebugInfo();
// Called when the metadata from the media file has been loaded by the
@ -628,15 +583,48 @@ private:
// Explicitly prievate to force access via accessors.
RefPtr<MediaDecoderStateMachine> mDecoderStateMachine;
RefPtr<ResourceCallback> mResourceCallback;
MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
RefPtr<CDMProxyPromise> mCDMProxyPromise;
protected:
void NotifyDataArrivedInternal();
void DiscardOngoingSeekIfExists();
virtual void CallSeek(const SeekTarget& aTarget);
// Called to recompute playback rate and notify 'progress' event.
// Call on the main thread only.
void DownloadProgressed();
// A media stream is assumed to be infinite if the metadata doesn't
// contain the duration, and range requests are not supported, and
// no headers give a hint of a possible duration (Content-Length,
// Content-Duration, and variants), and we cannot seek in the media
// stream to determine the duration.
//
// When the media stream ends, we can know the duration, thus the stream is
// no longer considered to be infinite.
void SetInfinite(bool aInfinite);
// Called by MediaResource when the "cache suspended" status changes.
// If MediaResource::IsSuspendedByCache returns true, then the decoder
// should stop buffering or otherwise waiting for download progress and
// start consuming data, if possible, because the cache is full.
void NotifySuspendedStatusChanged();
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.
void NotifyPrincipalChanged();
// Called by the MediaResource to keep track of the number of bytes read
// from the resource. Called on the main by an event runner dispatched
// by the MediaResource read functions.
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset);
// Called by nsChannelToPipeListener or MediaResource when the
// download has ended. Called on the main thread only. aStatus is
// the result from OnStopRequest.
void NotifyDownloadEnded(nsresult aStatus);
MozPromiseRequestHolder<SeekPromise> mSeekRequest;
// True when seeking or otherwise moving the play position around in
@ -849,38 +837,6 @@ private:
// Notify owner when the audible state changed
void NotifyAudibleStateChanged();
/* Functions called by ResourceCallback */
// A media stream is assumed to be infinite if the metadata doesn't
// contain the duration, and range requests are not supported, and
// no headers give a hint of a possible duration (Content-Length,
// Content-Duration, and variants), and we cannot seek in the media
// stream to determine the duration.
//
// When the media stream ends, we can know the duration, thus the stream is
// no longer considered to be infinite.
void SetInfinite(bool aInfinite);
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.
void NotifyPrincipalChanged();
// Called by MediaResource when the "cache suspended" status changes.
// If MediaResource::IsSuspendedByCache returns true, then the decoder
// should stop buffering or otherwise waiting for download progress and
// start consuming data, if possible, because the cache is full.
void NotifySuspendedStatusChanged();
// Called by the MediaResource to keep track of the number of bytes read
// from the resource. Called on the main by an event runner dispatched
// by the MediaResource read functions.
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset);
// Called by nsChannelToPipeListener or MediaResource when the
// download has ended. Called on the main thread only. aStatus is
// the result from OnStopRequest.
void NotifyDownloadEnded(nsresult aStatus);
bool mTelemetryReported;
// Used to debug how mOwner becomes a dangling pointer in bug 1326294.