зеркало из https://github.com/mozilla/gecko-dev.git
Bug 604682 - Remove unnecessary copy of audio data when there's no MozAudioAvailable event listener. r=smaug,kinetik
This commit is contained in:
Родитель
568172b4f0
Коммит
f4c97fdcf9
|
@ -124,8 +124,8 @@ class Element;
|
|||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0xc3e40e8e, 0x8b91, 0x424c, \
|
||||
{ 0xbe, 0x9c, 0x9c, 0xc1, 0x76, 0xa7, 0xf7, 0x24 } }
|
||||
{ 0x184e0a3c, 0x1899, 0x417d, \
|
||||
{ 0xbf, 0xf4, 0x5a, 0x15, 0xe6, 0xe8, 0xaa, 0x94 } }
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||
|
@ -1562,7 +1562,15 @@ public:
|
|||
virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming) = 0;
|
||||
|
||||
virtual Element* FindImageMap(const nsAString& aNormalizedMapName) = 0;
|
||||
|
||||
|
||||
// Called to notify the document that a listener on the "mozaudioavailable"
|
||||
// event has been added. Media elements in the document need to ensure they
|
||||
// fire the event.
|
||||
virtual void NotifyAudioAvailableListener() = 0;
|
||||
|
||||
// Returns true if the document has "mozaudioavailable" event listeners.
|
||||
virtual bool HasAudioAvailableListeners() = 0;
|
||||
|
||||
// Add aLink to the set of links that need their status resolved.
|
||||
void RegisterPendingLinkUpdate(mozilla::dom::Link* aLink);
|
||||
|
||||
|
|
|
@ -8237,6 +8237,25 @@ nsDocument::AddImage(imgIRequest* aImage)
|
|||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
NotifyAudioAvailableListener(nsIContent *aContent, void *aUnused)
|
||||
{
|
||||
#ifdef MOZ_MEDIA
|
||||
nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent));
|
||||
if (domMediaElem) {
|
||||
nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aContent);
|
||||
mediaElem->NotifyAudioAvailableListener();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::NotifyAudioAvailableListener()
|
||||
{
|
||||
mHasAudioAvailableListener = true;
|
||||
EnumerateFreezableElements(::NotifyAudioAvailableListener, nsnull);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::RemoveImage(imgIRequest* aImage)
|
||||
{
|
||||
|
|
|
@ -949,6 +949,13 @@ public:
|
|||
|
||||
virtual Element* FindImageMap(const nsAString& aNormalizedMapName);
|
||||
|
||||
virtual void NotifyAudioAvailableListener();
|
||||
|
||||
bool HasAudioAvailableListeners()
|
||||
{
|
||||
return mHasAudioAvailableListener;
|
||||
}
|
||||
|
||||
virtual Element* GetFullScreenElement();
|
||||
virtual void AsyncRequestFullScreen(Element* aElement);
|
||||
virtual void CancelFullScreen();
|
||||
|
@ -1157,6 +1164,10 @@ protected:
|
|||
// Whether we currently require our images to animate
|
||||
bool mAnimatingImages:1;
|
||||
|
||||
// Whether some node in this document has a listener for the
|
||||
// "mozaudioavailable" event.
|
||||
bool mHasAudioAvailableListener:1;
|
||||
|
||||
// Whether we are currently in full-screen mode, as per the DOM API.
|
||||
bool mIsFullScreen:1;
|
||||
|
||||
|
|
|
@ -178,6 +178,13 @@ public:
|
|||
// (no data has arrived for a while).
|
||||
void DownloadStalled();
|
||||
|
||||
// Called when a "MozAudioAvailable" event listener is added. The media
|
||||
// element will then notify its decoder that it needs to make a copy of
|
||||
// the audio data sent to hardware and dispatch it in "mozaudioavailable"
|
||||
// events. This allows us to not perform the copy and thus reduce overhead
|
||||
// in the common case where we don't have a "MozAudioAvailable" listener.
|
||||
void NotifyAudioAvailableListener();
|
||||
|
||||
// Called by the media decoder and the video frame to get the
|
||||
// ImageContainer containing the video data.
|
||||
ImageContainer* GetImageContainer();
|
||||
|
@ -301,12 +308,6 @@ public:
|
|||
void NotifyAudioAvailable(float* aFrameBuffer, PRUint32 aFrameBufferLength,
|
||||
float aTime);
|
||||
|
||||
/**
|
||||
* Called in order to check whether some node (this window, its document,
|
||||
* or content in that document) has a MozAudioAvailable event listener.
|
||||
*/
|
||||
bool MayHaveAudioAvailableEventListener();
|
||||
|
||||
virtual bool IsNodeOfType(PRUint32 aFlags) const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -702,24 +702,6 @@ void nsHTMLMediaElement::NotifyAudioAvailable(float* aFrameBuffer,
|
|||
DispatchAudioAvailableEvent(frameBuffer.forget(), aFrameBufferLength, aTime);
|
||||
}
|
||||
|
||||
bool nsHTMLMediaElement::MayHaveAudioAvailableEventListener()
|
||||
{
|
||||
// Determine if the current element is focused, if it is not focused
|
||||
// then we should not try to blur. Note: we allow for the case of
|
||||
// |var a = new Audio()| with no parent document.
|
||||
nsIDocument *document = GetDocument();
|
||||
if (!document) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsPIDOMWindow *window = document->GetInnerWindow();
|
||||
if (!window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return window->HasAudioAvailableEventListeners();
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::LoadFromSourceChildren()
|
||||
{
|
||||
NS_ASSERTION(mDelayingLoadEvent,
|
||||
|
@ -1498,6 +1480,13 @@ nsresult nsHTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aPar
|
|||
// The preload action depends on the value of the autoplay attribute.
|
||||
// It's value may have changed, so update it.
|
||||
UpdatePreloadAction();
|
||||
|
||||
if (aDocument->HasAudioAvailableListeners()) {
|
||||
// The document already has listeners for the "MozAudioAvailable"
|
||||
// event, so the decoder must be notified so it initiates
|
||||
// "MozAudioAvailable" event dispatch.
|
||||
NotifyAudioAvailableListener();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -1914,6 +1903,10 @@ nsresult nsHTMLMediaElement::FinishDecoderSetup(nsMediaDecoder* aDecoder)
|
|||
}
|
||||
}
|
||||
|
||||
if (OwnerDoc()->HasAudioAvailableListeners()) {
|
||||
NotifyAudioAvailableListener();
|
||||
}
|
||||
|
||||
mBegun = true;
|
||||
return rv;
|
||||
}
|
||||
|
@ -2714,3 +2707,10 @@ NS_IMETHODIMP nsHTMLMediaElement::GetMozFragmentEnd(double *aTime)
|
|||
*aTime = (mFragmentEnd < 0.0 || mFragmentEnd > duration) ? duration : mFragmentEnd;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::NotifyAudioAvailableListener()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->NotifyAudioAvailableListener();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,8 @@ nsAudioAvailableEventManager::nsAudioAvailableEventManager(nsBuiltinDecoder* aDe
|
|||
mSignalBufferLength(mDecoder->GetFrameBufferLength()),
|
||||
mNewSignalBufferLength(mSignalBufferLength),
|
||||
mSignalBufferPosition(0),
|
||||
mReentrantMonitor("media.audioavailableeventmanager")
|
||||
mReentrantMonitor("media.audioavailableeventmanager"),
|
||||
mHasListener(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsAudioAvailableEventManager);
|
||||
}
|
||||
|
@ -104,6 +105,10 @@ void nsAudioAvailableEventManager::DispatchPendingEvents(PRUint64 aCurrentTime)
|
|||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (!mHasListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (mPendingEvents.Length() > 0) {
|
||||
nsAudioAvailableEventRunner* e =
|
||||
(nsAudioAvailableEventRunner*)mPendingEvents[0].get();
|
||||
|
@ -122,6 +127,10 @@ void nsAudioAvailableEventManager::QueueWrittenAudioData(AudioDataValue* aAudioD
|
|||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (!mHasListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint32 currentBufferSize = mNewSignalBufferLength;
|
||||
if (currentBufferSize == 0) {
|
||||
NS_WARNING("Decoder framebuffer length not set.");
|
||||
|
@ -212,6 +221,10 @@ void nsAudioAvailableEventManager::Drain(PRUint64 aEndTime)
|
|||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (!mHasListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Force all pending events to go now.
|
||||
for (PRUint32 i = 0; i < mPendingEvents.Length(); ++i) {
|
||||
nsCOMPtr<nsIRunnable> event = mPendingEvents[i];
|
||||
|
@ -245,3 +258,9 @@ void nsAudioAvailableEventManager::SetSignalBufferLength(PRUint32 aLength)
|
|||
mNewSignalBufferLength = aLength;
|
||||
}
|
||||
|
||||
void nsAudioAvailableEventManager::NotifyAudioAvailableListener()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
mHasListener = true;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,11 @@ public:
|
|||
// Called from the main and the state machine thread.
|
||||
void SetSignalBufferLength(PRUint32 aLength);
|
||||
|
||||
// Called by the media element to notify the manager that there is a
|
||||
// listener on the "MozAudioAvailable" event, and that we need to dispatch
|
||||
// such events. Called from the main thread.
|
||||
void NotifyAudioAvailableListener();
|
||||
|
||||
private:
|
||||
// The decoder associated with the event manager. The event manager shares
|
||||
// the same lifetime as the decoder (the decoder holds a reference to the
|
||||
|
@ -108,6 +113,11 @@ private:
|
|||
// ReentrantMonitor for shared access to mPendingEvents queue or
|
||||
// buffer length.
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
// True if something in the owning document has a listener on the
|
||||
// "MozAudioAvailable" event. If not, we don't need to bother copying played
|
||||
// audio data and dispatching the event. Synchronized by mReentrantMonitor.
|
||||
bool mHasListener;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -397,14 +397,9 @@ void nsBuiltinDecoder::AudioAvailable(float* aFrameBuffer,
|
|||
// to HTMLMediaElement::NotifyAudioAvailable().
|
||||
nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
if (mShuttingDown) {
|
||||
if (mShuttingDown || !mElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mElement || !mElement->MayHaveAudioAvailableEventListener()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mElement->NotifyAudioAvailable(frameBuffer.forget(), aFrameBufferLength, aTime);
|
||||
}
|
||||
|
||||
|
@ -1005,6 +1000,16 @@ void nsBuiltinDecoder::UpdatePlaybackOffset(PRInt64 aOffset)
|
|||
mPlaybackPosition = NS_MAX(aOffset, mPlaybackPosition);
|
||||
}
|
||||
|
||||
bool nsBuiltinDecoder::OnStateMachineThread() const {
|
||||
bool nsBuiltinDecoder::OnStateMachineThread() const
|
||||
{
|
||||
return IsCurrentThread(nsBuiltinDecoderStateMachine::GetStateMachineThread());
|
||||
}
|
||||
|
||||
void nsBuiltinDecoder::NotifyAudioAvailableListener()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
if (mDecoderStateMachine) {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mDecoderStateMachine->NotifyAudioAvailableListener();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -344,6 +344,10 @@ public:
|
|||
// Sets the current size of the framebuffer used in MozAudioAvailable events.
|
||||
// Called on the state machine thread and the main thread.
|
||||
virtual void SetFrameBufferLength(PRUint32 aLength) = 0;
|
||||
|
||||
// Called when a "MozAudioAvailable" event listener is added to the media
|
||||
// element. Called on the main thread.
|
||||
virtual void NotifyAudioAvailableListener() = 0;
|
||||
};
|
||||
|
||||
class nsBuiltinDecoder : public nsMediaDecoder
|
||||
|
@ -610,6 +614,10 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
|||
// Drop reference to state machine. Only called during shutdown dance.
|
||||
void ReleaseStateMachine() { mDecoderStateMachine = nsnull; }
|
||||
|
||||
// Called when a "MozAudioAvailable" event listener is added to the media
|
||||
// element. Called on the main thread.
|
||||
virtual void NotifyAudioAvailableListener();
|
||||
|
||||
public:
|
||||
// Notifies the element that decoding has failed.
|
||||
void DecodeError();
|
||||
|
|
|
@ -2201,4 +2201,8 @@ nsIThread* nsBuiltinDecoderStateMachine::GetStateMachineThread()
|
|||
return StateMachineTracker::Instance().GetGlobalStateMachineThread();
|
||||
}
|
||||
|
||||
|
||||
void nsBuiltinDecoderStateMachine::NotifyAudioAvailableListener()
|
||||
{
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
mEventManager.NotifyAudioAvailableListener();
|
||||
}
|
||||
|
|
|
@ -265,6 +265,10 @@ public:
|
|||
// Drop reference to decoder. Only called during shutdown dance.
|
||||
void ReleaseDecoder() { mDecoder = nsnull; }
|
||||
|
||||
// Called when a "MozAudioAvailable" event listener is added to the media
|
||||
// element. Called on the main thread.
|
||||
void NotifyAudioAvailableListener();
|
||||
|
||||
protected:
|
||||
|
||||
// Returns true if we've got less than aAudioUsecs microseconds of decoded
|
||||
|
|
|
@ -158,6 +158,11 @@ public:
|
|||
// Call in the main thread only.
|
||||
virtual bool IsEnded() const = 0;
|
||||
|
||||
// Called when a "MozAudioAvailable" event listener is added. This enables
|
||||
// the decoder to only dispatch "MozAudioAvailable" events when a
|
||||
// handler exists, reducing overhead. Called on the main thread.
|
||||
virtual void NotifyAudioAvailableListener() = 0;
|
||||
|
||||
struct Statistics {
|
||||
// Estimate of the current playback rate (bytes/second).
|
||||
double mPlaybackRate;
|
||||
|
|
|
@ -766,7 +766,6 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
|
|||
mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(false),
|
||||
mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nsnull),
|
||||
mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
|
||||
mMayHaveAudioAvailableEventListener(false),
|
||||
mMayHaveMouseEnterLeaveEventListener(false),
|
||||
mIsModalContentWindow(false),
|
||||
mIsActive(false), mIsBackground(false),
|
||||
|
@ -10676,6 +10675,14 @@ nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument,
|
|||
aForceReuseInnerWindow);
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::SetHasAudioAvailableEventListeners()
|
||||
{
|
||||
if (mDoc) {
|
||||
mDoc->NotifyAudioAvailableListener();
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsGlobalWindow: Creator Function (This should go away)
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -447,6 +447,8 @@ public:
|
|||
// Prevent further dialogs in this (top level) window
|
||||
void PreventFurtherDialogs();
|
||||
|
||||
virtual void SetHasAudioAvailableEventListeners();
|
||||
|
||||
nsIScriptContext *GetContextInternal()
|
||||
{
|
||||
if (mOuterWindow) {
|
||||
|
|
|
@ -80,8 +80,8 @@ class nsIArray;
|
|||
class nsPIWindowRoot;
|
||||
|
||||
#define NS_PIDOMWINDOW_IID \
|
||||
{ 0x8ce567b5, 0xcc8d, 0x410b, \
|
||||
{ 0xa2, 0x7b, 0x07, 0xaf, 0x31, 0xc0, 0x33, 0xb8 } }
|
||||
{ 0x9db588f7, 0x3472, 0x45d0, \
|
||||
{ 0x9f, 0x9b, 0x95, 0xca, 0xf6, 0x4d, 0x1a, 0xb1 } }
|
||||
|
||||
class nsPIDOMWindow : public nsIDOMWindowInternal
|
||||
{
|
||||
|
@ -457,23 +457,11 @@ public:
|
|||
return mMayHaveTouchEventListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to check whether some node (this window, its document,
|
||||
* or content in that document) has a MozAudioAvailable event listener.
|
||||
*/
|
||||
bool HasAudioAvailableEventListeners()
|
||||
{
|
||||
return mMayHaveAudioAvailableEventListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to indicate that some node (this window, its document,
|
||||
* or content in that document) has a MozAudioAvailable event listener.
|
||||
* or content in that document) has a "MozAudioAvailable" event listener.
|
||||
*/
|
||||
void SetHasAudioAvailableEventListeners()
|
||||
{
|
||||
mMayHaveAudioAvailableEventListener = true;
|
||||
}
|
||||
virtual void SetHasAudioAvailableEventListeners() = 0;
|
||||
|
||||
/**
|
||||
* Call this to check whether some node (this window, its document,
|
||||
|
@ -657,7 +645,6 @@ protected:
|
|||
bool mIsInnerWindow;
|
||||
bool mMayHavePaintEventListener;
|
||||
bool mMayHaveTouchEventListener;
|
||||
bool mMayHaveAudioAvailableEventListener;
|
||||
bool mMayHaveMouseEnterLeaveEventListener;
|
||||
|
||||
// This variable is used on both inner and outer windows (and they
|
||||
|
|
Загрузка…
Ссылка в новой задаче