2008-07-09 01:22:20 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
2012-05-21 04:12:37 -07: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-09-29 14:32:44 -07:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
#include "mozilla/dom/HTMLMediaElement.h"
|
2013-03-19 05:25:19 -07:00
|
|
|
#include "mozilla/dom/HTMLMediaElementBinding.h"
|
2013-02-15 19:55:36 -08:00
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2011-10-10 22:50:08 -07:00
|
|
|
#include "mozilla/Util.h"
|
|
|
|
|
2012-09-26 21:33:43 -07:00
|
|
|
#include "base/basictypes.h"
|
2008-07-09 01:22:20 -07:00
|
|
|
#include "nsIDOMHTMLMediaElement.h"
|
|
|
|
#include "nsIDOMHTMLSourceElement.h"
|
2013-03-02 11:14:44 -08:00
|
|
|
#include "TimeRanges.h"
|
2008-07-09 01:22:20 -07:00
|
|
|
#include "nsGenericHTMLElement.h"
|
2012-09-30 09:40:24 -07:00
|
|
|
#include "nsAttrValueInlines.h"
|
2008-07-09 01:22:20 -07:00
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsSize.h"
|
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIDOMDocument.h"
|
2013-03-29 14:52:59 -07:00
|
|
|
#include "nsIDocShell.h"
|
2012-07-27 07:03:27 -07:00
|
|
|
#include "nsError.h"
|
2008-07-09 01:22:20 -07:00
|
|
|
#include "nsNodeInfoManager.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsXPCOMStrings.h"
|
2012-04-29 20:12:28 -07:00
|
|
|
#include "xpcpublic.h"
|
2008-07-09 01:22:20 -07:00
|
|
|
#include "nsThreadUtils.h"
|
2010-09-02 17:03:03 -07:00
|
|
|
#include "nsIThreadInternal.h"
|
2008-12-16 18:11:07 -08:00
|
|
|
#include "nsContentUtils.h"
|
2012-03-22 16:39:31 -07:00
|
|
|
#include "nsIRequest.h"
|
|
|
|
|
2010-09-09 21:20:10 -07:00
|
|
|
#include "nsFrameManager.h"
|
2008-07-09 01:22:20 -07:00
|
|
|
#include "nsIScriptSecurityManager.h"
|
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
#include "jsapi.h"
|
|
|
|
|
|
|
|
#include "nsITimer.h"
|
|
|
|
|
|
|
|
#include "nsEventDispatcher.h"
|
2013-02-14 07:59:21 -08:00
|
|
|
#include "MediaError.h"
|
2012-11-14 11:46:40 -08:00
|
|
|
#include "MediaDecoder.h"
|
2008-10-29 22:20:08 -07:00
|
|
|
#include "nsICategoryManager.h"
|
2012-02-14 20:35:01 -08:00
|
|
|
#include "MediaResource.h"
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2010-03-01 15:41:49 -08:00
|
|
|
#include "nsIDOMHTMLVideoElement.h"
|
2009-01-24 03:00:17 -08:00
|
|
|
#include "nsIContentPolicy.h"
|
|
|
|
#include "nsContentPolicyUtils.h"
|
|
|
|
#include "nsCrossSiteListenerProxy.h"
|
2009-03-08 13:59:08 -07:00
|
|
|
#include "nsCycleCollectionParticipant.h"
|
2010-03-17 20:00:18 -07:00
|
|
|
#include "nsICachingChannel.h"
|
2009-12-10 20:02:13 -08:00
|
|
|
#include "nsLayoutUtils.h"
|
|
|
|
#include "nsVideoFrame.h"
|
2013-09-01 15:20:45 -07:00
|
|
|
#include "Layers.h"
|
2010-04-01 20:03:07 -07:00
|
|
|
#include <limits>
|
2010-08-04 19:15:55 -07:00
|
|
|
#include "nsIAsyncVerifyRedirectCallback.h"
|
2010-09-02 17:03:03 -07:00
|
|
|
#include "nsIAppShell.h"
|
|
|
|
#include "nsWidgetsCID.h"
|
2010-08-25 06:10:00 -07:00
|
|
|
#include "nsIDOMNotifyAudioAvailableEvent.h"
|
2011-08-24 16:42:23 -07:00
|
|
|
#include "nsMediaFragmentURIParser.h"
|
2011-11-24 18:06:22 -08:00
|
|
|
#include "nsURIHashKey.h"
|
2012-04-29 20:12:28 -07:00
|
|
|
#include "nsJSUtils.h"
|
|
|
|
#include "MediaStreamGraph.h"
|
2011-12-21 15:33:39 -08:00
|
|
|
#include "nsIScriptError.h"
|
2012-09-24 20:25:43 -07:00
|
|
|
#include "nsHostObjectProtocolHandler.h"
|
2013-06-20 20:15:47 -07:00
|
|
|
#include "mozilla/dom/MediaSource.h"
|
2012-11-30 05:17:54 -08:00
|
|
|
#include "MediaMetadataManager.h"
|
2013-09-26 22:22:37 -07:00
|
|
|
#include "MediaSourceDecoder.h"
|
2010-08-25 06:10:00 -07:00
|
|
|
|
2012-12-04 11:46:07 -08:00
|
|
|
#include "AudioChannelService.h"
|
|
|
|
|
2012-05-15 05:56:51 -07:00
|
|
|
#include "nsCSSParser.h"
|
|
|
|
#include "nsIMediaList.h"
|
|
|
|
|
2012-08-20 21:06:46 -07:00
|
|
|
#include "ImageContainer.h"
|
2012-11-01 05:47:51 -07:00
|
|
|
#include "nsIPowerManagerService.h"
|
2013-08-22 11:32:52 -07:00
|
|
|
#include "nsRange.h"
|
2013-01-15 04:22:03 -08:00
|
|
|
#include <algorithm>
|
2012-08-20 21:06:46 -07:00
|
|
|
|
2009-09-29 14:32:44 -07:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
static PRLogModuleInfo* gMediaElementLog;
|
|
|
|
static PRLogModuleInfo* gMediaElementEventsLog;
|
|
|
|
#define LOG(type, msg) PR_LOG(gMediaElementLog, type, msg)
|
|
|
|
#define LOG_EVENT(type, msg) PR_LOG(gMediaElementEventsLog, type, msg)
|
|
|
|
#else
|
|
|
|
#define LOG(type, msg)
|
|
|
|
#define LOG_EVENT(type, msg)
|
|
|
|
#endif
|
2009-02-19 18:49:00 -08:00
|
|
|
|
2010-04-23 12:50:28 -07:00
|
|
|
#include "nsIContentSecurityPolicy.h"
|
|
|
|
#include "nsIChannelPolicy.h"
|
|
|
|
#include "nsChannelPolicy.h"
|
|
|
|
|
2011-05-24 23:31:59 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
|
2012-12-03 01:46:43 -08:00
|
|
|
#include "nsIPermissionManager.h"
|
2013-08-21 12:28:26 -07:00
|
|
|
#include "nsContentTypeParser.h"
|
2012-12-03 01:46:43 -08:00
|
|
|
|
2010-03-01 15:41:49 -08:00
|
|
|
using namespace mozilla::layers;
|
2012-12-20 17:04:50 -08:00
|
|
|
using mozilla::net::nsMediaFragmentURIParser;
|
2012-11-14 11:45:33 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
2010-11-24 10:34:57 -08:00
|
|
|
// Number of milliseconds between timeupdate events as defined by spec
|
|
|
|
#define TIMEUPDATE_MS 250
|
|
|
|
|
2013-09-02 02:45:44 -07:00
|
|
|
// Used by AudioChannel for suppresssing the volume to this ratio.
|
|
|
|
#define FADED_VOLUME_RATIO 0.25
|
|
|
|
|
2012-11-22 02:38:28 -08:00
|
|
|
// These constants are arbitrary
|
|
|
|
// Minimum playbackRate for a media
|
|
|
|
static const double MIN_PLAYBACKRATE = 0.25;
|
|
|
|
// Maximum playbackRate for a media
|
|
|
|
static const double MAX_PLAYBACKRATE = 5.0;
|
|
|
|
// These are the limits beyonds which SoundTouch does not perform too well and when
|
|
|
|
// speech is hard to understand anyway.
|
|
|
|
// Threshold above which audio is muted
|
|
|
|
static const double THRESHOLD_HIGH_PLAYBACKRATE_AUDIO = 4.0;
|
|
|
|
// Threshold under which audio is muted
|
|
|
|
static const double THRESHOLD_LOW_PLAYBACKRATE_AUDIO = 0.5;
|
|
|
|
|
2009-10-01 07:10:13 -07:00
|
|
|
// Under certain conditions there may be no-one holding references to
|
|
|
|
// a media element from script, DOM parent, etc, but the element may still
|
|
|
|
// fire meaningful events in the future so we can't destroy it yet:
|
|
|
|
// 1) If the element is delaying the load event (or would be, if it were
|
|
|
|
// in a document), then events up to loadeddata or error could be fired,
|
|
|
|
// so we need to stay alive.
|
|
|
|
// 2) If the element is not paused and playback has not ended, then
|
|
|
|
// we will (or might) play, sending timeupdate and ended events and possibly
|
|
|
|
// audio output, so we need to stay alive.
|
|
|
|
// 3) if the element is seeking then we will fire seeking events and possibly
|
|
|
|
// start playing afterward, so we need to stay alive.
|
|
|
|
// 4) If autoplay could start playback in this element (if we got enough data),
|
|
|
|
// then we need to stay alive.
|
|
|
|
// 5) if the element is currently loading and not suspended,
|
|
|
|
// script might be waiting for progress events or a 'suspend' event,
|
|
|
|
// so we need to stay alive. If we're already suspended then (all other
|
|
|
|
// conditions being met) it's OK to just disappear without firing any more
|
|
|
|
// events, since we have the freedom to remain suspended indefinitely. Note
|
|
|
|
// that we could use this 'suspended' loophole to garbage-collect a suspended
|
|
|
|
// element in case 4 even if it had 'autoplay' set, but we choose not to.
|
|
|
|
// If someone throws away all references to a loading 'autoplay' element
|
|
|
|
// sound should still eventually play.
|
|
|
|
//
|
|
|
|
// Media elements owned by inactive documents (i.e. documents not contained in any
|
|
|
|
// document viewer) should never hold a self-reference because none of the
|
|
|
|
// above conditions are allowed: the element will stop loading and playing
|
|
|
|
// and never resume loading or playing unless its owner document changes to
|
|
|
|
// an active document (which can only happen if there is an external reference
|
|
|
|
// to the element).
|
|
|
|
// Media elements with no owner doc should be able to hold a self-reference.
|
|
|
|
// Something native must have created the element and may expect it to
|
|
|
|
// stay alive to play.
|
|
|
|
|
|
|
|
// It's very important that any change in state which could change the value of
|
|
|
|
// needSelfReference in AddRemoveSelfReference be followed by a call to
|
|
|
|
// AddRemoveSelfReference before this element could die!
|
|
|
|
// It's especially important if needSelfReference would change to 'true',
|
|
|
|
// since if we neglect to add a self-reference, this element might be
|
|
|
|
// garbage collected while there are still event listeners that should
|
|
|
|
// receive events. If we neglect to remove the self-reference then the element
|
|
|
|
// just lives longer than it needs to.
|
|
|
|
|
2009-02-19 18:49:00 -08:00
|
|
|
class nsMediaEvent : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsMediaEvent(HTMLMediaElement* aElement) :
|
2009-02-19 18:49:00 -08:00
|
|
|
mElement(aElement),
|
2009-03-08 13:59:08 -07:00
|
|
|
mLoadID(mElement->GetCurrentLoadID()) {}
|
2009-02-19 18:49:00 -08:00
|
|
|
~nsMediaEvent() {}
|
|
|
|
|
|
|
|
NS_IMETHOD Run() = 0;
|
|
|
|
|
|
|
|
protected:
|
2011-09-28 23:19:26 -07:00
|
|
|
bool IsCancelled() {
|
2009-03-08 13:59:08 -07:00
|
|
|
return mElement->GetCurrentLoadID() != mLoadID;
|
2009-02-19 18:49:00 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsRefPtr<HTMLMediaElement> mElement;
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t mLoadID;
|
2009-02-19 18:49:00 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
class nsAsyncEventRunner : public nsMediaEvent
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
nsString mName;
|
2009-11-05 23:32:52 -08:00
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
public:
|
2013-03-19 05:23:54 -07:00
|
|
|
nsAsyncEventRunner(const nsAString& aName, HTMLMediaElement* aElement) :
|
2010-09-09 20:29:06 -07:00
|
|
|
nsMediaEvent(aElement), mName(aName)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
|
|
|
}
|
2009-11-05 23:32:52 -08:00
|
|
|
|
2010-08-25 06:10:00 -07:00
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
2009-02-19 18:49:00 -08:00
|
|
|
// Silently cancel if our load has been cancelled.
|
|
|
|
if (IsCancelled())
|
|
|
|
return NS_OK;
|
2010-08-25 06:10:00 -07:00
|
|
|
|
2010-09-09 20:29:06 -07:00
|
|
|
return mElement->DispatchEvent(mName);
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-09-02 17:03:03 -07:00
|
|
|
class nsSourceErrorEventRunner : public nsMediaEvent
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIContent> mSource;
|
2009-02-15 17:05:28 -08:00
|
|
|
public:
|
2013-03-19 05:23:54 -07:00
|
|
|
nsSourceErrorEventRunner(HTMLMediaElement* aElement,
|
2010-09-02 17:03:03 -07:00
|
|
|
nsIContent* aSource)
|
|
|
|
: nsMediaEvent(aElement),
|
|
|
|
mSource(aSource)
|
|
|
|
{
|
2009-02-15 17:05:28 -08:00
|
|
|
}
|
|
|
|
|
2009-02-19 18:49:00 -08:00
|
|
|
NS_IMETHOD Run() {
|
2010-09-02 17:03:03 -07:00
|
|
|
// Silently cancel if our load has been cancelled.
|
|
|
|
if (IsCancelled())
|
|
|
|
return NS_OK;
|
|
|
|
LOG_EVENT(PR_LOG_DEBUG, ("%p Dispatching simple event source error", mElement.get()));
|
2011-10-18 03:53:36 -07:00
|
|
|
return nsContentUtils::DispatchTrustedEvent(mElement->OwnerDoc(),
|
2010-09-02 17:03:03 -07:00
|
|
|
mSource,
|
|
|
|
NS_LITERAL_STRING("error"),
|
2011-09-29 16:34:37 -07:00
|
|
|
false,
|
2012-08-13 20:26:43 -07:00
|
|
|
false);
|
2009-02-19 18:49:00 -08:00
|
|
|
}
|
2009-02-15 17:05:28 -08:00
|
|
|
};
|
|
|
|
|
2009-07-09 19:03:03 -07:00
|
|
|
/**
|
|
|
|
* There is a reference cycle involving this class: MediaLoadListener
|
2013-03-19 05:23:54 -07:00
|
|
|
* holds a reference to the HTMLMediaElement, which holds a reference
|
2009-07-09 19:03:03 -07:00
|
|
|
* to an nsIChannel, which holds a reference to this listener.
|
|
|
|
* We break the reference cycle in OnStartRequest by clearing mElement.
|
|
|
|
*/
|
2013-03-19 05:23:54 -07:00
|
|
|
class HTMLMediaElement::MediaLoadListener MOZ_FINAL : public nsIStreamListener,
|
|
|
|
public nsIChannelEventSink,
|
|
|
|
public nsIInterfaceRequestor,
|
|
|
|
public nsIObserver
|
2008-12-15 19:32:03 -08:00
|
|
|
{
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIREQUESTOBSERVER
|
|
|
|
NS_DECL_NSISTREAMLISTENER
|
2009-05-13 14:52:50 -07:00
|
|
|
NS_DECL_NSICHANNELEVENTSINK
|
2010-02-24 11:14:14 -08:00
|
|
|
NS_DECL_NSIOBSERVER
|
2009-05-13 14:52:50 -07:00
|
|
|
NS_DECL_NSIINTERFACEREQUESTOR
|
2008-12-15 19:32:03 -08:00
|
|
|
|
|
|
|
public:
|
2013-03-19 05:23:54 -07:00
|
|
|
MediaLoadListener(HTMLMediaElement* aElement)
|
2011-05-03 19:43:48 -07:00
|
|
|
: mElement(aElement),
|
|
|
|
mLoadID(aElement->GetCurrentLoadID())
|
2008-12-15 19:32:03 -08:00
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(mElement, "Must pass an element to call back");
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2013-03-19 05:23:54 -07:00
|
|
|
nsRefPtr<HTMLMediaElement> mElement;
|
2008-12-15 19:32:03 -08:00
|
|
|
nsCOMPtr<nsIStreamListener> mNextListener;
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t mLoadID;
|
2008-12-15 19:32:03 -08:00
|
|
|
};
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMPL_ISUPPORTS5(HTMLMediaElement::MediaLoadListener, nsIRequestObserver,
|
2009-05-13 14:52:50 -07:00
|
|
|
nsIStreamListener, nsIChannelEventSink,
|
2010-02-24 11:14:14 -08:00
|
|
|
nsIInterfaceRequestor, nsIObserver)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::MediaLoadListener::Observe(nsISupports* aSubject,
|
|
|
|
const char* aTopic, const PRUnichar* aData)
|
2010-02-24 11:14:14 -08:00
|
|
|
{
|
|
|
|
nsContentUtils::UnregisterShutdownObserver(this);
|
|
|
|
|
|
|
|
// Clear mElement to break cycle so we don't leak on shutdown
|
2012-07-30 07:20:58 -07:00
|
|
|
mElement = nullptr;
|
2010-02-24 14:48:32 -08:00
|
|
|
return NS_OK;
|
2010-02-24 11:14:14 -08:00
|
|
|
}
|
2008-12-15 19:32:03 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::ReportLoadError(const char* aMsg,
|
|
|
|
const PRUnichar** aParams,
|
|
|
|
uint32_t aParamCount)
|
2011-12-21 15:33:39 -08:00
|
|
|
{
|
|
|
|
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
2013-08-21 12:28:26 -07:00
|
|
|
NS_LITERAL_CSTRING("Media"),
|
2011-12-21 15:33:39 -08:00
|
|
|
OwnerDoc(),
|
|
|
|
nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
aMsg,
|
|
|
|
aParams,
|
|
|
|
aParamCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::MediaLoadListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
2008-12-15 19:32:03 -08:00
|
|
|
{
|
2010-02-24 11:14:14 -08:00
|
|
|
nsContentUtils::UnregisterShutdownObserver(this);
|
|
|
|
|
2012-01-05 22:40:51 -08:00
|
|
|
if (!mElement) {
|
|
|
|
// We've been notified by the shutdown observer, and are shutting down.
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
2009-07-09 19:03:03 -07:00
|
|
|
// The element is only needed until we've had a chance to call
|
|
|
|
// InitializeDecoderForChannel. So make sure mElement is cleared here.
|
2013-03-19 05:23:54 -07:00
|
|
|
nsRefPtr<HTMLMediaElement> element;
|
2009-07-09 19:03:03 -07:00
|
|
|
element.swap(mElement);
|
|
|
|
|
2011-05-03 19:43:48 -07:00
|
|
|
if (mLoadID != element->GetCurrentLoadID()) {
|
|
|
|
// The channel has been cancelled before we had a chance to create
|
|
|
|
// a decoder. Abort, don't dispatch an "error" event, as the new load
|
|
|
|
// may not be in an error state.
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
2009-03-17 17:34:48 -07:00
|
|
|
// Don't continue to load if the request failed or has been canceled.
|
|
|
|
nsresult status;
|
2011-11-15 23:50:19 -08:00
|
|
|
nsresult rv = aRequest->GetStatus(&status);
|
2009-03-17 17:34:48 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (NS_FAILED(status)) {
|
2009-07-09 19:03:03 -07:00
|
|
|
if (element)
|
|
|
|
element->NotifyLoadError();
|
2009-03-17 17:34:48 -07:00
|
|
|
return status;
|
|
|
|
}
|
2008-12-15 19:32:03 -08:00
|
|
|
|
2011-12-21 15:33:39 -08:00
|
|
|
nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(aRequest);
|
|
|
|
bool succeeded;
|
|
|
|
if (hc && NS_SUCCEEDED(hc->GetRequestSucceeded(&succeeded)) && !succeeded) {
|
|
|
|
element->NotifyLoadError();
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t responseStatus = 0;
|
2011-12-21 15:33:39 -08:00
|
|
|
hc->GetResponseStatus(&responseStatus);
|
|
|
|
nsAutoString code;
|
|
|
|
code.AppendInt(responseStatus);
|
|
|
|
nsAutoString src;
|
|
|
|
element->GetCurrentSrc(src);
|
|
|
|
const PRUnichar* params[] = { code.get(), src.get() };
|
|
|
|
element->ReportLoadError("MediaLoadHttpError", params, ArrayLength(params));
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
2008-12-15 19:32:03 -08:00
|
|
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
|
|
|
|
if (channel &&
|
2009-07-09 19:03:03 -07:00
|
|
|
element &&
|
2009-07-09 21:05:40 -07:00
|
|
|
NS_SUCCEEDED(rv = element->InitializeDecoderForChannel(channel, getter_AddRefs(mNextListener))) &&
|
2008-12-15 19:32:03 -08:00
|
|
|
mNextListener) {
|
|
|
|
rv = mNextListener->OnStartRequest(aRequest, aContext);
|
|
|
|
} else {
|
2009-02-15 08:26:32 -08:00
|
|
|
// If InitializeDecoderForChannel() returned an error, fire a network
|
|
|
|
// error.
|
2009-07-09 19:03:03 -07:00
|
|
|
if (NS_FAILED(rv) && !mNextListener && element) {
|
2009-02-19 18:49:00 -08:00
|
|
|
// Load failed, attempt to load the next candidate resource. If there
|
2009-09-21 17:08:13 -07:00
|
|
|
// are none, this will trigger a MEDIA_ERR_SRC_NOT_SUPPORTED error.
|
2009-07-09 19:03:03 -07:00
|
|
|
element->NotifyLoadError();
|
2009-02-15 08:26:32 -08:00
|
|
|
}
|
|
|
|
// If InitializeDecoderForChannel did not return a listener (but may
|
|
|
|
// have otherwise succeeded), we abort the connection since we aren't
|
|
|
|
// interested in keeping the channel alive ourselves.
|
2008-12-15 19:32:03 -08:00
|
|
|
rv = NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::MediaLoadListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
|
|
|
|
nsresult aStatus)
|
2008-12-15 19:32:03 -08:00
|
|
|
{
|
|
|
|
if (mNextListener) {
|
|
|
|
return mNextListener->OnStopRequest(aRequest, aContext, aStatus);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-09-05 19:41:02 -07:00
|
|
|
NS_IMETHODIMP
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::MediaLoadListener::OnDataAvailable(nsIRequest* aRequest,
|
|
|
|
nsISupports* aContext,
|
|
|
|
nsIInputStream* aStream,
|
|
|
|
uint64_t aOffset,
|
|
|
|
uint32_t aCount)
|
2008-12-15 19:32:03 -08:00
|
|
|
{
|
2009-05-04 23:13:26 -07:00
|
|
|
if (!mNextListener) {
|
|
|
|
NS_ERROR("Must have a chained listener; OnStartRequest should have canceled this request");
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
2008-12-15 19:32:03 -08:00
|
|
|
return mNextListener->OnDataAvailable(aRequest, aContext, aStream, aOffset, aCount);
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::MediaLoadListener::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
|
|
|
nsIChannel* aNewChannel,
|
|
|
|
uint32_t aFlags,
|
|
|
|
nsIAsyncVerifyRedirectCallback* cb)
|
2009-05-13 14:52:50 -07:00
|
|
|
{
|
2010-08-04 19:15:55 -07:00
|
|
|
// TODO is this really correct?? See bug #579329.
|
2009-05-17 15:20:37 -07:00
|
|
|
if (mElement)
|
|
|
|
mElement->OnChannelRedirect(aOldChannel, aNewChannel, aFlags);
|
2009-05-13 14:52:50 -07:00
|
|
|
nsCOMPtr<nsIChannelEventSink> sink = do_QueryInterface(mNextListener);
|
|
|
|
if (sink)
|
2010-08-04 19:15:55 -07:00
|
|
|
return sink->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, cb);
|
|
|
|
|
|
|
|
cb->OnRedirectVerifyCallback(NS_OK);
|
2009-05-13 14:52:50 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::MediaLoadListener::GetInterface(const nsIID & aIID, void **aResult)
|
2009-05-13 14:52:50 -07:00
|
|
|
{
|
|
|
|
return QueryInterface(aIID, aResult);
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMPL_ADDREF_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
|
2013-08-01 18:29:05 -07:00
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLMediaElement)
|
2009-02-19 18:49:00 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
|
2013-06-20 20:15:47 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSource)
|
2012-11-14 23:32:40 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrcStream)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrcAttrStream)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourcePointer)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadBlockedDoc)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceLoadCandidate)
|
2013-04-23 08:28:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelAgent)
|
2013-02-14 07:59:21 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
|
2012-11-14 23:32:40 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mStream);
|
2012-04-29 20:12:42 -07:00
|
|
|
}
|
2013-04-22 16:45:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed);
|
2013-05-21 09:14:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTracks);
|
2009-03-08 13:59:08 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
|
2012-08-19 21:52:59 -07:00
|
|
|
if (tmp->mSrcStream) {
|
2013-05-01 04:24:16 -07:00
|
|
|
// Need to EndMediaStreamPlayback to clear mSrcStream and make sure everything
|
2012-04-29 20:12:28 -07:00
|
|
|
// gets unhooked correctly.
|
2012-08-19 21:52:59 -07:00
|
|
|
tmp->EndSrcMediaStreamPlayback();
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2012-11-14 23:32:40 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSrcAttrStream)
|
2013-06-20 20:15:47 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaSource)
|
2012-11-14 23:32:40 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourcePointer)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoadBlockedDoc)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceLoadCandidate)
|
2013-04-23 08:28:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioChannelAgent)
|
2013-02-14 07:59:21 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
|
2012-11-14 23:32:40 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputStreams[i].mStream);
|
2012-04-29 20:12:42 -07:00
|
|
|
}
|
2013-04-22 16:45:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlayed);
|
2013-05-21 09:14:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextTracks);
|
2009-03-08 13:59:08 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLMediaElement)
|
2010-02-24 11:14:14 -08:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
2013-01-07 00:40:02 -08:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
|
2009-03-08 13:59:08 -07:00
|
|
|
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
2009-02-15 17:05:28 -08:00
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
// nsIDOMHTMLMediaElement
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMPL_URI_ATTR(HTMLMediaElement, Src, src)
|
2013-03-19 08:18:29 -07:00
|
|
|
NS_IMPL_STRING_ATTR(HTMLMediaElement, CrossOrigin, crossorigin)
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMPL_BOOL_ATTR(HTMLMediaElement, Controls, controls)
|
|
|
|
NS_IMPL_BOOL_ATTR(HTMLMediaElement, Autoplay, autoplay)
|
|
|
|
NS_IMPL_BOOL_ATTR(HTMLMediaElement, Loop, loop)
|
|
|
|
NS_IMPL_BOOL_ATTR(HTMLMediaElement, DefaultMuted, muted)
|
2013-04-02 18:14:24 -07:00
|
|
|
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMediaElement, Preload, preload, nullptr)
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMediaElement, MozAudioChannelType, mozaudiochannel, "normal")
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
already_AddRefed<DOMMediaStream>
|
|
|
|
HTMLMediaElement::GetMozSrcObject() const
|
2012-04-29 20:12:28 -07:00
|
|
|
{
|
2013-03-09 23:58:18 -08:00
|
|
|
NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetStream(),
|
|
|
|
"MediaStream should have been set up properly");
|
|
|
|
nsRefPtr<DOMMediaStream> stream = mSrcAttrStream;
|
2013-03-19 05:25:19 -07:00
|
|
|
return stream.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLMediaElement::GetMozSrcObject(nsIDOMMediaStream** aStream)
|
|
|
|
{
|
|
|
|
nsRefPtr<DOMMediaStream> stream = GetMozSrcObject();
|
2013-03-09 23:58:18 -08:00
|
|
|
stream.forget(aStream);
|
2012-04-29 20:12:28 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::SetMozSrcObject(DOMMediaStream& aValue)
|
|
|
|
{
|
|
|
|
mSrcAttrStream = &aValue;
|
|
|
|
Load();
|
|
|
|
}
|
|
|
|
|
2012-04-29 20:12:28 -07:00
|
|
|
NS_IMETHODIMP
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::SetMozSrcObject(nsIDOMMediaStream* aStream)
|
2012-04-29 20:12:28 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
DOMMediaStream* stream = static_cast<DOMMediaStream*>(aStream);
|
|
|
|
SetMozSrcObject(*stream);
|
2012-09-23 20:47:30 -07:00
|
|
|
return NS_OK;
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
|
2009-02-19 20:05:07 -08:00
|
|
|
/* readonly attribute nsIDOMHTMLMediaElement mozAutoplayEnabled; */
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetMozAutoplayEnabled(bool *aAutoplayEnabled)
|
2009-02-19 20:05:07 -08:00
|
|
|
{
|
2010-10-14 17:13:29 -07:00
|
|
|
*aAutoplayEnabled = mAutoplayEnabled;
|
2009-02-19 20:05:07 -08:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-25 01:43:00 -07:00
|
|
|
/* readonly attribute nsIDOMMediaError error; */
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetError(nsIDOMMediaError * *aError)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
|
|
|
NS_IF_ADDREF(*aError = mError);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-07-29 21:55:27 -07:00
|
|
|
/* readonly attribute boolean ended; */
|
2013-03-19 05:25:19 -07:00
|
|
|
bool
|
|
|
|
HTMLMediaElement::Ended()
|
2008-07-29 21:55:27 -07:00
|
|
|
{
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
2013-03-19 05:25:19 -07:00
|
|
|
return GetSrcMediaStream()->IsFinished();
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-03-19 05:25:19 -07:00
|
|
|
|
|
|
|
if (mDecoder) {
|
|
|
|
return mDecoder->IsEnded();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetEnded(bool* aEnded)
|
|
|
|
{
|
|
|
|
*aEnded = Ended();
|
2008-07-29 21:55:27 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
/* readonly attribute DOMString currentSrc; */
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetCurrentSrc(nsAString & aCurrentSrc)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString src;
|
2011-08-24 16:42:23 -07:00
|
|
|
GetCurrentSpec(src);
|
2008-07-09 01:22:20 -07:00
|
|
|
aCurrentSrc = NS_ConvertUTF8toUTF16(src);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute unsigned short networkState; */
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetNetworkState(uint16_t* aNetworkState)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
*aNetworkState = NetworkState();
|
2008-07-09 01:22:20 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-05-17 15:20:37 -07:00
|
|
|
nsresult
|
2013-03-19 05:25:19 -07:00
|
|
|
HTMLMediaElement::OnChannelRedirect(nsIChannel* aChannel,
|
|
|
|
nsIChannel* aNewChannel,
|
2013-03-19 05:23:54 -07:00
|
|
|
uint32_t aFlags)
|
2009-05-17 15:20:37 -07:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aChannel == mChannel, "Channels should match!");
|
|
|
|
mChannel = aNewChannel;
|
2010-04-21 17:32:52 -07:00
|
|
|
|
|
|
|
// Handle forwarding of Range header so that the intial detection
|
|
|
|
// of seeking support (via result code 206) works across redirects.
|
|
|
|
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aChannel);
|
|
|
|
NS_ENSURE_STATE(http);
|
|
|
|
|
|
|
|
NS_NAMED_LITERAL_CSTRING(rangeHdr, "Range");
|
2012-11-15 19:25:26 -08:00
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString rangeVal;
|
2010-04-21 17:32:52 -07:00
|
|
|
if (NS_SUCCEEDED(http->GetRequestHeader(rangeHdr, rangeVal))) {
|
|
|
|
NS_ENSURE_STATE(!rangeVal.IsEmpty());
|
|
|
|
|
|
|
|
http = do_QueryInterface(aNewChannel);
|
|
|
|
NS_ENSURE_STATE(http);
|
2012-11-15 19:25:26 -08:00
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
nsresult rv = http->SetRequestHeader(rangeHdr, rangeVal, false);
|
2010-04-21 17:32:52 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2012-11-15 19:25:26 -08:00
|
|
|
|
2009-05-17 15:20:37 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::ShutdownDecoder()
|
2012-04-29 20:13:09 -07:00
|
|
|
{
|
|
|
|
RemoveMediaElementFromURITable();
|
|
|
|
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
|
|
|
|
mDecoder->Shutdown();
|
2012-07-30 07:20:58 -07:00
|
|
|
mDecoder = nullptr;
|
2012-04-29 20:13:09 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::AbortExistingLoads()
|
2008-10-29 22:20:08 -07:00
|
|
|
{
|
2009-03-08 13:59:08 -07:00
|
|
|
// Abort any already-running instance of the resource selection algorithm.
|
|
|
|
mLoadWaitStatus = NOT_WAITING;
|
|
|
|
|
|
|
|
// Set a new load ID. This will cause events which were enqueued
|
2009-03-15 23:05:28 -07:00
|
|
|
// with a different load ID to silently be cancelled.
|
2009-03-08 13:59:08 -07:00
|
|
|
mCurrentLoadID++;
|
2009-02-19 18:49:00 -08:00
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool fireTimeUpdate = false;
|
2011-11-24 18:06:22 -08:00
|
|
|
|
2008-12-15 19:32:03 -08:00
|
|
|
if (mDecoder) {
|
2010-07-25 15:45:41 -07:00
|
|
|
fireTimeUpdate = mDecoder->GetCurrentTime() != 0.0;
|
2012-04-29 20:13:09 -07:00
|
|
|
ShutdownDecoder();
|
2008-10-29 22:20:08 -07:00
|
|
|
}
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
|
|
|
EndSrcMediaStreamPlayback();
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-06-20 20:15:47 -07:00
|
|
|
if (mMediaSource) {
|
2013-09-26 22:22:37 -07:00
|
|
|
mMediaSource->Detach();
|
2013-06-20 20:15:47 -07:00
|
|
|
mMediaSource = nullptr;
|
|
|
|
}
|
2012-08-20 22:06:55 -07:00
|
|
|
if (mAudioStream) {
|
|
|
|
mAudioStream->Shutdown();
|
|
|
|
mAudioStream = nullptr;
|
|
|
|
}
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
mLoadingSrc = nullptr;
|
2008-10-29 22:20:08 -07:00
|
|
|
|
2009-03-08 13:59:08 -07:00
|
|
|
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING ||
|
|
|
|
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE)
|
|
|
|
{
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchEvent(NS_LITERAL_STRING("abort"));
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
mError = nullptr;
|
2011-09-29 16:34:37 -07:00
|
|
|
mLoadedFirstFrame = false;
|
|
|
|
mAutoplaying = true;
|
|
|
|
mIsLoadingFromSourceChildren = false;
|
|
|
|
mSuspendedAfterFirstFrame = false;
|
|
|
|
mAllowSuspendAfterFirstFrame = true;
|
2012-02-19 13:02:08 -08:00
|
|
|
mHaveQueuedSelectResource = false;
|
2012-05-27 15:40:06 -07:00
|
|
|
mSuspendedForPreloadNone = false;
|
|
|
|
mDownloadSuspendedByCache = false;
|
2012-07-30 07:20:58 -07:00
|
|
|
mSourcePointer = nullptr;
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2012-07-30 17:14:29 -07:00
|
|
|
mChannels = 0;
|
|
|
|
mRate = 0;
|
|
|
|
mTags = nullptr;
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2008-12-14 19:38:16 -08:00
|
|
|
if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
|
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
|
2012-08-19 21:52:59 -07:00
|
|
|
NS_ASSERTION(!mDecoder && !mSrcStream, "How did someone setup a new stream/decoder already?");
|
2008-12-14 19:38:16 -08:00
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
|
2011-09-29 16:34:37 -07:00
|
|
|
mPaused = true;
|
2009-03-08 13:59:08 -07:00
|
|
|
|
2010-07-25 15:45:41 -07:00
|
|
|
if (fireTimeUpdate) {
|
|
|
|
// Since we destroyed the decoder above, the current playback position
|
|
|
|
// will now be reported as 0. The playback position was non-zero when
|
|
|
|
// we destroyed the decoder, so fire a timeupdate event so that the
|
|
|
|
// change will be reflected in the controls.
|
2011-09-29 16:34:37 -07:00
|
|
|
FireTimeUpdate(false);
|
2010-07-25 15:45:41 -07:00
|
|
|
}
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchEvent(NS_LITERAL_STRING("emptied"));
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
2009-03-08 14:01:03 -07:00
|
|
|
|
2009-10-01 07:10:13 -07:00
|
|
|
// We may have changed mPaused, mAutoplaying, mNetworkState and other
|
|
|
|
// things which can affect AddRemoveSelfReference
|
|
|
|
AddRemoveSelfReference();
|
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
mIsRunningSelectResource = false;
|
2008-12-15 19:32:03 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NoSupportedMediaSourceError()
|
2009-02-15 08:26:32 -08:00
|
|
|
{
|
2009-10-01 07:10:13 -07:00
|
|
|
NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during source selection?");
|
|
|
|
|
2013-02-14 07:59:21 -08:00
|
|
|
mError = new MediaError(this, nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
|
2009-03-08 13:59:08 -07:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("error"));
|
2009-10-01 07:10:13 -07:00
|
|
|
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(false);
|
2009-02-15 08:26:32 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
typedef void (HTMLMediaElement::*SyncSectionFn)();
|
2010-09-02 17:03:03 -07:00
|
|
|
|
|
|
|
// Runs a "synchronous section", a function that must run once the event loop
|
|
|
|
// has reached a "stable state". See:
|
|
|
|
// http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#synchronous-section
|
|
|
|
class nsSyncSection : public nsMediaEvent
|
|
|
|
{
|
|
|
|
private:
|
2013-06-27 18:05:03 -07:00
|
|
|
nsCOMPtr<nsIRunnable> mRunnable;
|
2010-09-02 17:03:03 -07:00
|
|
|
public:
|
2013-03-19 05:23:54 -07:00
|
|
|
nsSyncSection(HTMLMediaElement* aElement,
|
2013-06-27 18:05:03 -07:00
|
|
|
nsIRunnable* aRunnable) :
|
2010-09-02 17:03:03 -07:00
|
|
|
nsMediaEvent(aElement),
|
2013-06-27 18:05:03 -07:00
|
|
|
mRunnable(aRunnable)
|
2010-09-02 17:03:03 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD Run() {
|
|
|
|
// Silently cancel if our load has been cancelled.
|
|
|
|
if (IsCancelled())
|
|
|
|
return NS_OK;
|
2013-06-27 18:05:03 -07:00
|
|
|
mRunnable->Run();
|
2010-09-02 17:03:03 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
|
|
|
|
2013-06-27 18:05:03 -07:00
|
|
|
void HTMLMediaElement::RunInStableState(nsIRunnable* aRunnable)
|
2010-09-02 17:03:03 -07:00
|
|
|
{
|
2013-06-27 18:05:03 -07:00
|
|
|
nsCOMPtr<nsIRunnable> event = new nsSyncSection(this, aRunnable);
|
2010-09-02 17:03:03 -07:00
|
|
|
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
|
|
|
appShell->RunInStableState(event);
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::QueueLoadFromSourceTask()
|
2010-09-02 17:03:03 -07:00
|
|
|
{
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(true);
|
2010-09-02 17:03:03 -07:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
|
2013-06-27 18:05:03 -07:00
|
|
|
RunInStableState(
|
|
|
|
NS_NewRunnableMethod(this, &HTMLMediaElement::LoadFromSourceChildren));
|
2010-09-02 17:03:03 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::QueueSelectResourceTask()
|
2010-09-02 17:03:03 -07:00
|
|
|
{
|
|
|
|
// Don't allow multiple async select resource calls to be queued.
|
2012-02-19 13:02:08 -08:00
|
|
|
if (mHaveQueuedSelectResource)
|
2010-09-02 17:03:03 -07:00
|
|
|
return;
|
2012-02-19 13:02:08 -08:00
|
|
|
mHaveQueuedSelectResource = true;
|
2010-09-02 17:03:03 -07:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
|
2013-06-27 18:05:03 -07:00
|
|
|
RunInStableState(
|
|
|
|
NS_NewRunnableMethod(this, &HTMLMediaElement::SelectResourceWrapper));
|
2010-09-02 17:03:03 -07:00
|
|
|
}
|
|
|
|
|
2008-12-15 19:32:03 -08:00
|
|
|
/* void load (); */
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::Load()
|
2008-12-15 19:32:03 -08:00
|
|
|
{
|
2009-03-08 13:59:08 -07:00
|
|
|
if (mIsRunningLoadMethod)
|
2008-12-15 19:32:03 -08:00
|
|
|
return NS_OK;
|
2013-03-19 05:25:19 -07:00
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
SetPlayedOrSeeked(false);
|
|
|
|
mIsRunningLoadMethod = true;
|
2009-03-08 13:59:08 -07:00
|
|
|
AbortExistingLoads();
|
2012-11-22 02:38:28 -08:00
|
|
|
SetPlaybackRate(mDefaultPlaybackRate);
|
2009-03-08 13:59:08 -07:00
|
|
|
QueueSelectResourceTask();
|
2012-12-27 07:21:30 -08:00
|
|
|
ResetState();
|
2011-09-29 16:34:37 -07:00
|
|
|
mIsRunningLoadMethod = false;
|
2013-03-19 05:25:19 -07:00
|
|
|
|
2009-03-08 13:59:08 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::ResetState()
|
2012-12-27 07:21:30 -08:00
|
|
|
{
|
|
|
|
mMediaSize = nsIntSize(-1, -1);
|
|
|
|
VideoFrameContainer* container = GetVideoFrameContainer();
|
|
|
|
if (container) {
|
|
|
|
container->Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
static bool HasSourceChildren(nsIContent* aElement)
|
2009-03-08 13:59:08 -07:00
|
|
|
{
|
2011-09-27 00:54:58 -07:00
|
|
|
for (nsIContent* child = aElement->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
|
|
|
if (child->IsHTML(nsGkAtoms::source))
|
2009-03-08 13:59:08 -07:00
|
|
|
{
|
2011-09-29 16:34:37 -07:00
|
|
|
return true;
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
|
|
|
}
|
2011-09-29 16:34:37 -07:00
|
|
|
return false;
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SelectResourceWrapper()
|
2012-02-19 13:02:08 -08:00
|
|
|
{
|
|
|
|
SelectResource();
|
|
|
|
mIsRunningSelectResource = false;
|
|
|
|
mHaveQueuedSelectResource = false;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SelectResource()
|
2009-03-08 13:59:08 -07:00
|
|
|
{
|
2012-04-29 20:12:28 -07:00
|
|
|
if (!mSrcAttrStream && !HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
|
|
|
|
!HasSourceChildren(this)) {
|
2010-09-02 17:03:03 -07:00
|
|
|
// The media element has neither a src attribute nor any source
|
|
|
|
// element children, abort the load.
|
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
|
2009-10-01 07:10:13 -07:00
|
|
|
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(false);
|
2009-03-08 13:59:08 -07:00
|
|
|
return;
|
|
|
|
}
|
2008-12-15 19:32:03 -08:00
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(true);
|
2010-09-02 17:03:03 -07:00
|
|
|
|
2009-02-15 08:26:32 -08:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
|
2009-10-01 07:10:13 -07:00
|
|
|
// Load event was delayed, and still is, so no need to call
|
|
|
|
// AddRemoveSelfReference, since it must still be held
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
|
2009-02-15 08:26:32 -08:00
|
|
|
|
2012-02-19 13:02:08 -08:00
|
|
|
// Delay setting mIsRunningSeletResource until after UpdatePreloadAction
|
|
|
|
// so that we don't lose our state change by bailing out of the preload
|
|
|
|
// state update
|
|
|
|
UpdatePreloadAction();
|
|
|
|
mIsRunningSelectResource = true;
|
|
|
|
|
2009-03-08 13:59:08 -07:00
|
|
|
// If we have a 'src' attribute, use that exclusively.
|
2011-11-15 23:50:19 -08:00
|
|
|
nsAutoString src;
|
2012-04-29 20:12:28 -07:00
|
|
|
if (mSrcAttrStream) {
|
2012-09-24 20:25:43 -07:00
|
|
|
SetupSrcMediaStreamPlayback(mSrcAttrStream);
|
2012-04-29 20:12:28 -07:00
|
|
|
} else if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
|
2011-11-15 23:50:19 -08:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
2009-03-08 13:59:08 -07:00
|
|
|
nsresult rv = NewURIFromString(src, getter_AddRefs(uri));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2009-11-05 23:32:52 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p Trying load from src=%s", this, NS_ConvertUTF16toUTF8(src).get()));
|
2010-10-16 12:57:50 -07:00
|
|
|
NS_ASSERTION(!mIsLoadingFromSourceChildren,
|
|
|
|
"Should think we're not loading from source children by default");
|
2012-09-24 20:25:43 -07:00
|
|
|
|
2010-09-02 17:03:03 -07:00
|
|
|
mLoadingSrc = uri;
|
2013-03-19 05:23:54 -07:00
|
|
|
if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE) {
|
2010-08-19 15:50:37 -07:00
|
|
|
// preload:none media, suspend the load here before we make any
|
|
|
|
// network requests.
|
2011-11-24 18:06:22 -08:00
|
|
|
SuspendLoad();
|
2010-08-19 15:50:37 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-11-24 18:06:22 -08:00
|
|
|
rv = LoadResource();
|
2010-09-02 17:03:03 -07:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2009-03-08 13:59:08 -07:00
|
|
|
return;
|
2010-09-02 17:03:03 -07:00
|
|
|
}
|
2011-12-21 15:33:39 -08:00
|
|
|
} else {
|
|
|
|
const PRUnichar* params[] = { src.get() };
|
|
|
|
ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
2009-09-21 17:08:13 -07:00
|
|
|
NoSupportedMediaSourceError();
|
2009-03-08 13:59:08 -07:00
|
|
|
} else {
|
|
|
|
// Otherwise, the source elements will be used.
|
2011-09-29 16:34:37 -07:00
|
|
|
mIsLoadingFromSourceChildren = true;
|
2009-03-08 13:59:08 -07:00
|
|
|
LoadFromSourceChildren();
|
|
|
|
}
|
2009-02-19 18:49:00 -08:00
|
|
|
}
|
2009-01-26 18:32:33 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NotifyLoadError()
|
2009-02-19 18:49:00 -08:00
|
|
|
{
|
2010-10-16 12:57:50 -07:00
|
|
|
if (!mIsLoadingFromSourceChildren) {
|
2010-09-02 17:03:03 -07:00
|
|
|
LOG(PR_LOG_DEBUG, ("NotifyLoadError(), no supported media error"));
|
2009-09-21 17:08:13 -07:00
|
|
|
NoSupportedMediaSourceError();
|
2011-04-28 07:08:03 -07:00
|
|
|
} else if (mSourceLoadCandidate) {
|
2010-09-02 17:03:03 -07:00
|
|
|
DispatchAsyncSourceError(mSourceLoadCandidate);
|
2009-03-08 13:59:08 -07:00
|
|
|
QueueLoadFromSourceTask();
|
2011-04-28 07:08:03 -07:00
|
|
|
} else {
|
|
|
|
NS_WARNING("Should know the source we were loading from!");
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
|
|
|
}
|
2009-02-19 18:49:00 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NotifyAudioAvailable(float* aFrameBuffer,
|
|
|
|
uint32_t aFrameBufferLength,
|
|
|
|
float aTime)
|
2010-08-25 06:10:00 -07:00
|
|
|
{
|
2010-09-05 19:14:50 -07:00
|
|
|
// Auto manage the memory for the frame buffer, so that if we add an early
|
|
|
|
// return-on-error here in future, we won't forget to release the memory.
|
2012-11-15 19:25:26 -08:00
|
|
|
// Otherwise we hand ownership of the memory over to the event created by
|
2010-09-05 19:14:50 -07:00
|
|
|
// DispatchAudioAvailableEvent().
|
|
|
|
nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
|
2010-08-25 06:10:00 -07:00
|
|
|
// Do same-origin check on element and media before allowing MozAudioAvailable events.
|
|
|
|
if (!mMediaSecurityVerified) {
|
|
|
|
nsCOMPtr<nsIPrincipal> principal = GetCurrentPrincipal();
|
|
|
|
nsresult rv = NodePrincipal()->Subsumes(principal, &mAllowAudioData);
|
|
|
|
if (NS_FAILED(rv)) {
|
2011-09-29 16:34:37 -07:00
|
|
|
mAllowAudioData = false;
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-05 19:14:50 -07:00
|
|
|
DispatchAudioAvailableEvent(frameBuffer.forget(), aFrameBufferLength, aTime);
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::LoadFromSourceChildren()
|
2009-03-08 13:59:08 -07:00
|
|
|
{
|
2009-10-01 07:10:13 -07:00
|
|
|
NS_ASSERTION(mDelayingLoadEvent,
|
|
|
|
"Should delay load event (if in document) during load");
|
2010-10-16 12:57:50 -07:00
|
|
|
NS_ASSERTION(mIsLoadingFromSourceChildren,
|
2010-09-02 17:03:03 -07:00
|
|
|
"Must remember we're loading from source children");
|
2012-05-15 05:56:51 -07:00
|
|
|
|
|
|
|
nsIDocument* parentDoc = OwnerDoc()->GetParentDocument();
|
|
|
|
if (parentDoc) {
|
|
|
|
parentDoc->FlushPendingNotifications(Flush_Layout);
|
|
|
|
}
|
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
while (true) {
|
2010-09-02 17:03:03 -07:00
|
|
|
nsIContent* child = GetNextSource();
|
|
|
|
if (!child) {
|
2009-03-08 13:59:08 -07:00
|
|
|
// Exhausted candidates, wait for more candidates to be appended to
|
|
|
|
// the media element.
|
|
|
|
mLoadWaitStatus = WAITING_FOR_SOURCE;
|
2010-09-02 17:03:03 -07:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(false);
|
2011-12-21 15:33:39 -08:00
|
|
|
ReportLoadError("MediaLoadExhaustedCandidates");
|
2009-03-08 13:59:08 -07:00
|
|
|
return;
|
2009-02-15 08:26:32 -08:00
|
|
|
}
|
2009-02-19 18:49:00 -08:00
|
|
|
|
2010-09-02 17:03:03 -07:00
|
|
|
// Must have src attribute.
|
2011-11-15 23:50:19 -08:00
|
|
|
nsAutoString src;
|
2010-09-02 17:03:03 -07:00
|
|
|
if (!child->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
|
2011-12-21 15:33:39 -08:00
|
|
|
ReportLoadError("MediaLoadSourceMissingSrc");
|
2010-09-02 17:03:03 -07:00
|
|
|
DispatchAsyncSourceError(child);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have a type attribute, it must be a supported type.
|
2011-11-15 23:50:19 -08:00
|
|
|
nsAutoString type;
|
|
|
|
if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type) &&
|
|
|
|
GetCanPlay(type) == CANPLAY_NO) {
|
2010-09-02 17:03:03 -07:00
|
|
|
DispatchAsyncSourceError(child);
|
2011-12-21 15:33:39 -08:00
|
|
|
const PRUnichar* params[] = { type.get(), src.get() };
|
2012-05-15 05:56:51 -07:00
|
|
|
ReportLoadError("MediaLoadUnsupportedTypeAttribute", params, ArrayLength(params));
|
2010-09-02 17:03:03 -07:00
|
|
|
continue;
|
|
|
|
}
|
2012-05-15 05:56:51 -07:00
|
|
|
nsAutoString media;
|
|
|
|
if (child->GetAttr(kNameSpaceID_None, nsGkAtoms::media, media) && !media.IsEmpty()) {
|
|
|
|
nsCSSParser cssParser;
|
|
|
|
nsRefPtr<nsMediaList> mediaList(new nsMediaList());
|
2013-04-02 18:14:24 -07:00
|
|
|
cssParser.ParseMediaList(media, nullptr, 0, mediaList, false);
|
2012-05-15 05:56:51 -07:00
|
|
|
nsIPresShell* presShell = OwnerDoc()->GetShell();
|
2013-04-02 18:14:24 -07:00
|
|
|
if (presShell && !mediaList->Matches(presShell->GetPresContext(), nullptr)) {
|
2012-05-15 05:56:51 -07:00
|
|
|
DispatchAsyncSourceError(child);
|
|
|
|
const PRUnichar* params[] = { media.get(), src.get() };
|
|
|
|
ReportLoadError("MediaLoadSourceMediaNotMatched", params, ArrayLength(params));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOG(PR_LOG_DEBUG, ("%p Trying load from <source>=%s type=%s media=%s", this,
|
|
|
|
NS_ConvertUTF16toUTF8(src).get(), NS_ConvertUTF16toUTF8(type).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(media).get()));
|
2011-11-15 23:50:19 -08:00
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
2010-09-02 17:03:03 -07:00
|
|
|
NewURIFromString(src, getter_AddRefs(uri));
|
|
|
|
if (!uri) {
|
|
|
|
DispatchAsyncSourceError(child);
|
2011-12-21 15:33:39 -08:00
|
|
|
const PRUnichar* params[] = { src.get() };
|
|
|
|
ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
|
2010-09-02 17:03:03 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
mLoadingSrc = uri;
|
|
|
|
NS_ASSERTION(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING,
|
|
|
|
"Network state should be loading");
|
2009-11-05 23:32:52 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE) {
|
2010-08-19 15:50:37 -07:00
|
|
|
// preload:none media, suspend the load here before we make any
|
|
|
|
// network requests.
|
2011-11-24 18:06:22 -08:00
|
|
|
SuspendLoad();
|
2010-08-19 15:50:37 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-11-24 18:06:22 -08:00
|
|
|
if (NS_SUCCEEDED(LoadResource())) {
|
2009-03-08 13:59:08 -07:00
|
|
|
return;
|
2011-11-15 23:50:19 -08:00
|
|
|
}
|
2008-12-15 19:32:03 -08:00
|
|
|
|
2009-03-08 13:59:08 -07:00
|
|
|
// If we fail to load, loop back and try loading the next resource.
|
2010-09-02 17:03:03 -07:00
|
|
|
DispatchAsyncSourceError(child);
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
|
|
|
NS_NOTREACHED("Execution should not reach here!");
|
|
|
|
}
|
2008-12-15 19:32:03 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SuspendLoad()
|
2010-08-19 15:50:37 -07:00
|
|
|
{
|
2012-05-27 15:40:06 -07:00
|
|
|
mSuspendedForPreloadNone = true;
|
2010-08-19 15:50:37 -07:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(false);
|
2010-08-19 15:50:37 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::ResumeLoad(PreloadAction aAction)
|
2010-08-19 15:50:37 -07:00
|
|
|
{
|
2012-05-27 15:40:06 -07:00
|
|
|
NS_ASSERTION(mSuspendedForPreloadNone,
|
|
|
|
"Must be halted for preload:none to resume from preload:none suspended load.");
|
|
|
|
mSuspendedForPreloadNone = false;
|
2010-08-19 15:50:37 -07:00
|
|
|
mPreloadAction = aAction;
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(true);
|
2010-08-19 15:50:37 -07:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
|
2010-10-16 12:57:50 -07:00
|
|
|
if (!mIsLoadingFromSourceChildren) {
|
2010-08-19 15:50:37 -07:00
|
|
|
// We were loading from the element's src attribute.
|
2011-11-24 18:06:22 -08:00
|
|
|
if (NS_FAILED(LoadResource())) {
|
2010-08-19 15:50:37 -07:00
|
|
|
NoSupportedMediaSourceError();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We were loading from a child <source> element. Try to resume the
|
|
|
|
// load of that child, and if that fails, try the next child.
|
2011-11-24 18:06:22 -08:00
|
|
|
if (NS_FAILED(LoadResource())) {
|
2010-08-19 15:50:37 -07:00
|
|
|
LoadFromSourceChildren();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool IsAutoplayEnabled()
|
2010-08-19 15:50:37 -07:00
|
|
|
{
|
2011-05-24 23:31:59 -07:00
|
|
|
return Preferences::GetBool("media.autoplay.enabled");
|
2010-08-19 15:50:37 -07:00
|
|
|
}
|
|
|
|
|
2013-04-25 17:53:25 -07:00
|
|
|
static bool UseAudioChannelService()
|
|
|
|
{
|
|
|
|
return Preferences::GetBool("media.useAudioChannelService");
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::UpdatePreloadAction()
|
2010-08-19 15:50:37 -07:00
|
|
|
{
|
|
|
|
PreloadAction nextAction = PRELOAD_UNDEFINED;
|
2010-10-16 11:41:53 -07:00
|
|
|
// If autoplay is set, or we're playing, we should always preload data,
|
|
|
|
// as we'll need it to play.
|
|
|
|
if ((IsAutoplayEnabled() && HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) ||
|
|
|
|
!mPaused)
|
|
|
|
{
|
2013-03-19 05:23:54 -07:00
|
|
|
nextAction = HTMLMediaElement::PRELOAD_ENOUGH;
|
2010-08-19 15:50:37 -07:00
|
|
|
} else {
|
|
|
|
// Find the appropriate preload action by looking at the attribute.
|
|
|
|
const nsAttrValue* val = mAttrsAndChildren.GetAttr(nsGkAtoms::preload,
|
|
|
|
kNameSpaceID_None);
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t preloadDefault =
|
2011-05-24 23:32:00 -07:00
|
|
|
Preferences::GetInt("media.preload.default",
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::PRELOAD_ATTR_METADATA);
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t preloadAuto =
|
2011-05-24 23:32:00 -07:00
|
|
|
Preferences::GetInt("media.preload.auto",
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::PRELOAD_ENOUGH);
|
2010-08-19 15:50:37 -07:00
|
|
|
if (!val) {
|
2012-11-15 19:25:26 -08:00
|
|
|
// Attribute is not set. Use the preload action specified by the
|
2011-02-15 16:54:47 -08:00
|
|
|
// media.preload.default pref, or just preload metadata if not present.
|
|
|
|
nextAction = static_cast<PreloadAction>(preloadDefault);
|
2010-08-19 15:50:37 -07:00
|
|
|
} else if (val->Type() == nsAttrValue::eEnum) {
|
|
|
|
PreloadAttrValue attr = static_cast<PreloadAttrValue>(val->GetEnumValue());
|
2013-03-19 05:23:54 -07:00
|
|
|
if (attr == HTMLMediaElement::PRELOAD_ATTR_EMPTY ||
|
|
|
|
attr == HTMLMediaElement::PRELOAD_ATTR_AUTO)
|
2010-08-19 15:50:37 -07:00
|
|
|
{
|
2011-02-15 16:54:47 -08:00
|
|
|
nextAction = static_cast<PreloadAction>(preloadAuto);
|
2013-03-19 05:23:54 -07:00
|
|
|
} else if (attr == HTMLMediaElement::PRELOAD_ATTR_METADATA) {
|
|
|
|
nextAction = HTMLMediaElement::PRELOAD_METADATA;
|
|
|
|
} else if (attr == HTMLMediaElement::PRELOAD_ATTR_NONE) {
|
|
|
|
nextAction = HTMLMediaElement::PRELOAD_NONE;
|
2010-08-19 15:50:37 -07:00
|
|
|
}
|
|
|
|
} else {
|
2011-02-15 16:54:47 -08:00
|
|
|
// Use the suggested "missing value default" of "metadata", or the value
|
|
|
|
// specified by the media.preload.default, if present.
|
|
|
|
nextAction = static_cast<PreloadAction>(preloadDefault);
|
2010-08-19 15:50:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mBegun || mIsRunningSelectResource) && nextAction < mPreloadAction) {
|
|
|
|
// We've started a load or are already downloading, and the preload was
|
|
|
|
// changed to a state where we buffer less. We don't support this case,
|
|
|
|
// so don't change the preload behaviour.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mPreloadAction = nextAction;
|
2013-03-19 05:23:54 -07:00
|
|
|
if (nextAction == HTMLMediaElement::PRELOAD_ENOUGH) {
|
2012-05-27 15:40:06 -07:00
|
|
|
if (mSuspendedForPreloadNone) {
|
2010-08-19 15:50:37 -07:00
|
|
|
// Our load was previouly suspended due to the media having preload
|
|
|
|
// value "none". The preload value has changed to preload:auto, so
|
|
|
|
// resume the load.
|
|
|
|
ResumeLoad(PRELOAD_ENOUGH);
|
|
|
|
} else {
|
|
|
|
// Preload as much of the video as we can, i.e. don't suspend after
|
|
|
|
// the first frame.
|
|
|
|
StopSuspendingAfterFirstFrame();
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
} else if (nextAction == HTMLMediaElement::PRELOAD_METADATA) {
|
2010-08-19 15:50:37 -07:00
|
|
|
// Ensure that the video can be suspended after first frame.
|
2011-09-29 16:34:37 -07:00
|
|
|
mAllowSuspendAfterFirstFrame = true;
|
2012-05-27 15:40:06 -07:00
|
|
|
if (mSuspendedForPreloadNone) {
|
2010-08-19 15:50:37 -07:00
|
|
|
// Our load was previouly suspended due to the media having preload
|
|
|
|
// value "none". The preload value has changed to preload:metadata, so
|
|
|
|
// resume the load. We'll pause the load again after we've read the
|
|
|
|
// metadata.
|
|
|
|
ResumeLoad(PRELOAD_METADATA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::LoadResource()
|
2009-03-08 13:59:08 -07:00
|
|
|
{
|
2009-10-01 07:10:13 -07:00
|
|
|
NS_ASSERTION(mDelayingLoadEvent,
|
|
|
|
"Should delay load event (if in document) during load");
|
2009-02-19 18:49:00 -08:00
|
|
|
|
2009-03-08 13:59:08 -07:00
|
|
|
if (mChannel) {
|
|
|
|
mChannel->Cancel(NS_BINDING_ABORTED);
|
2012-07-30 07:20:58 -07:00
|
|
|
mChannel = nullptr;
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
|
|
|
|
2013-03-29 14:52:59 -07:00
|
|
|
// Check if media is allowed for the docshell.
|
|
|
|
nsCOMPtr<nsISupports> container = OwnerDoc()->GetContainer();
|
|
|
|
if (container) {
|
|
|
|
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
|
|
|
|
if (docShell && !docShell->GetAllowMedia()) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-08 11:55:09 -08:00
|
|
|
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
|
|
|
nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_MEDIA,
|
|
|
|
mLoadingSrc,
|
|
|
|
NodePrincipal(),
|
|
|
|
static_cast<Element*>(this),
|
|
|
|
EmptyCString(), // mime type
|
|
|
|
nullptr, // extra
|
|
|
|
&shouldLoad,
|
|
|
|
nsContentUtils::GetContentPolicy(),
|
|
|
|
nsContentUtils::GetSecurityManager());
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (NS_CP_REJECTED(shouldLoad)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-01-25 14:31:30 -08:00
|
|
|
// Set the media element's CORS mode only when loading a resource
|
2012-03-10 08:13:52 -08:00
|
|
|
mCORSMode = AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
|
2012-01-25 14:31:30 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
|
2012-09-24 20:25:43 -07:00
|
|
|
if (other && other->mDecoder) {
|
2011-11-24 18:06:22 -08:00
|
|
|
// Clone it.
|
|
|
|
nsresult rv = InitializeDecoderAsClone(other->mDecoder);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-09-24 20:25:43 -07:00
|
|
|
if (IsMediaStreamURI(mLoadingSrc)) {
|
|
|
|
nsCOMPtr<nsIDOMMediaStream> stream;
|
|
|
|
rv = NS_GetStreamForMediaStreamURI(mLoadingSrc, getter_AddRefs(stream));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
nsCString specUTF8;
|
|
|
|
mLoadingSrc->GetSpec(specUTF8);
|
|
|
|
NS_ConvertUTF8toUTF16 spec(specUTF8);
|
|
|
|
const PRUnichar* params[] = { spec.get() };
|
|
|
|
ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
|
|
|
|
return rv;
|
|
|
|
}
|
2013-02-15 00:01:58 -08:00
|
|
|
SetupSrcMediaStreamPlayback(static_cast<DOMMediaStream*>(stream.get()));
|
2012-09-24 20:25:43 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-06-20 20:15:47 -07:00
|
|
|
if (IsMediaSourceURI(mLoadingSrc)) {
|
|
|
|
nsRefPtr<MediaSource> source;
|
|
|
|
rv = NS_GetSourceForMediaSourceURI(mLoadingSrc, getter_AddRefs(source));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
nsCString specUTF8;
|
|
|
|
mLoadingSrc->GetSpec(specUTF8);
|
|
|
|
NS_ConvertUTF8toUTF16 spec(specUTF8);
|
|
|
|
const PRUnichar* params[] = { spec.get() };
|
|
|
|
ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
mMediaSource = source.forget();
|
2013-09-26 22:22:37 -07:00
|
|
|
nsRefPtr<MediaSourceDecoder> decoder = new MediaSourceDecoder(this);
|
|
|
|
if (!mMediaSource->Attach(decoder)) {
|
|
|
|
// TODO: Handle failure: run "If the media data cannot be fetched at
|
|
|
|
// all, due to network errors, causing the user agent to give up
|
|
|
|
// trying to fetch the resource" section of resource fetch algorithm.
|
2013-06-20 20:15:47 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2013-09-26 22:22:37 -07:00
|
|
|
nsRefPtr<MediaResource> resource = new MediaSourceResource();
|
|
|
|
return FinishDecoderSetup(decoder, resource, nullptr, nullptr);
|
2013-06-20 20:15:47 -07:00
|
|
|
}
|
|
|
|
|
2009-04-09 18:28:24 -07:00
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
|
2010-04-23 12:50:28 -07:00
|
|
|
|
|
|
|
// check for a Content Security Policy to pass down to the channel
|
|
|
|
// created to load the media content
|
|
|
|
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
|
|
|
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
|
|
|
rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
|
|
|
NS_ENSURE_SUCCESS(rv,rv);
|
|
|
|
if (csp) {
|
|
|
|
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
|
|
|
channelPolicy->SetContentSecurityPolicy(csp);
|
|
|
|
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA);
|
|
|
|
}
|
2010-11-16 05:26:48 -08:00
|
|
|
nsCOMPtr<nsIChannel> channel;
|
|
|
|
rv = NS_NewChannel(getter_AddRefs(channel),
|
2011-11-24 18:06:22 -08:00
|
|
|
mLoadingSrc,
|
2012-07-30 07:20:58 -07:00
|
|
|
nullptr,
|
2009-04-09 18:28:24 -07:00
|
|
|
loadGroup,
|
2012-07-30 07:20:58 -07:00
|
|
|
nullptr,
|
2012-09-04 16:22:34 -07:00
|
|
|
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
|
|
|
|
nsIChannel::LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN,
|
2010-04-23 12:50:28 -07:00
|
|
|
channelPolicy);
|
2009-03-08 13:59:08 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv,rv);
|
|
|
|
|
2010-11-16 05:26:48 -08:00
|
|
|
// The listener holds a strong reference to us. This creates a
|
|
|
|
// reference cycle, once we've set mChannel, which is manually broken
|
|
|
|
// in the listener's OnStartRequest method after it is finished with
|
|
|
|
// the element. The cycle will also be broken if we get a shutdown
|
|
|
|
// notification before OnStartRequest fires. Necko guarantees that
|
|
|
|
// OnStartRequest will eventually fire if we don't shut down first.
|
2009-05-13 14:52:50 -07:00
|
|
|
nsRefPtr<MediaLoadListener> loadListener = new MediaLoadListener(this);
|
2009-11-05 23:32:52 -08:00
|
|
|
|
2010-11-16 05:26:48 -08:00
|
|
|
channel->SetNotificationCallbacks(loadListener);
|
2009-03-08 13:59:08 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIStreamListener> listener;
|
|
|
|
if (ShouldCheckAllowOrigin()) {
|
2012-09-18 19:16:23 -07:00
|
|
|
nsRefPtr<nsCORSListenerProxy> corsListener =
|
2011-03-28 13:18:45 -07:00
|
|
|
new nsCORSListenerProxy(loadListener,
|
|
|
|
NodePrincipal(),
|
2012-09-18 19:16:23 -07:00
|
|
|
GetCORSMode() == CORS_USE_CREDENTIALS);
|
|
|
|
rv = corsListener->Init(channel);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
listener = corsListener;
|
2009-03-08 13:59:08 -07:00
|
|
|
} else {
|
|
|
|
rv = nsContentUtils::GetSecurityManager()->
|
|
|
|
CheckLoadURIWithPrincipal(NodePrincipal(),
|
2011-11-24 18:06:22 -08:00
|
|
|
mLoadingSrc,
|
2009-03-08 13:59:08 -07:00
|
|
|
nsIScriptSecurityManager::STANDARD);
|
|
|
|
listener = loadListener;
|
2012-09-18 19:16:23 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
|
|
|
|
2010-11-16 05:26:48 -08:00
|
|
|
nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(channel);
|
2009-03-08 13:59:08 -07:00
|
|
|
if (hc) {
|
|
|
|
// Use a byte range request from the start of the resource.
|
|
|
|
// This enables us to detect if the stream supports byte range
|
|
|
|
// requests, and therefore seeking, early.
|
|
|
|
hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"),
|
|
|
|
NS_LITERAL_CSTRING("bytes=0-"),
|
2011-09-29 16:34:37 -07:00
|
|
|
false);
|
2010-07-28 21:58:07 -07:00
|
|
|
|
2010-09-16 10:36:23 -07:00
|
|
|
SetRequestHeaders(hc);
|
2008-12-15 19:32:03 -08:00
|
|
|
}
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
rv = channel->AsyncOpen(listener, nullptr);
|
2010-11-16 05:26:48 -08:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2009-03-08 13:59:08 -07:00
|
|
|
|
|
|
|
// Else the channel must be open and starting to download. If it encounters
|
2010-05-13 05:19:50 -07:00
|
|
|
// a non-catastrophic failure, it will set a new task to continue loading
|
2010-11-16 05:26:48 -08:00
|
|
|
// another candidate. It's safe to set it as mChannel now.
|
|
|
|
mChannel = channel;
|
|
|
|
|
|
|
|
// loadListener will be unregistered either on shutdown or when
|
|
|
|
// OnStartRequest for the channel we just opened fires.
|
|
|
|
nsContentUtils::RegisterShutdownObserver(loadListener);
|
2009-03-08 13:59:08 -07:00
|
|
|
return NS_OK;
|
2008-12-15 19:32:03 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
nsresult HTMLMediaElement::LoadWithChannel(nsIChannel* aChannel,
|
|
|
|
nsIStreamListener** aListener)
|
2008-12-15 19:32:03 -08:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aChannel);
|
|
|
|
NS_ENSURE_ARG_POINTER(aListener);
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
*aListener = nullptr;
|
2008-12-15 19:32:03 -08:00
|
|
|
|
2012-04-29 20:12:28 -07:00
|
|
|
// Make sure we don't reenter during synchronous abort events.
|
|
|
|
if (mIsRunningLoadMethod)
|
|
|
|
return NS_OK;
|
|
|
|
mIsRunningLoadMethod = true;
|
2009-03-08 13:59:08 -07:00
|
|
|
AbortExistingLoads();
|
2012-04-29 20:12:28 -07:00
|
|
|
mIsRunningLoadMethod = false;
|
2008-12-15 19:32:03 -08:00
|
|
|
|
2011-11-24 18:06:22 -08:00
|
|
|
nsresult rv = aChannel->GetOriginalURI(getter_AddRefs(mLoadingSrc));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2011-11-23 15:30:03 -08:00
|
|
|
|
2011-11-24 18:06:22 -08:00
|
|
|
ChangeDelayLoadStatus(true);
|
|
|
|
rv = InitializeDecoderForChannel(aChannel, aListener);
|
2008-12-15 19:32:03 -08:00
|
|
|
if (NS_FAILED(rv)) {
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(false);
|
2009-09-14 19:30:44 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-11-22 02:38:28 -08:00
|
|
|
SetPlaybackRate(mDefaultPlaybackRate);
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
|
2009-09-14 19:30:44 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
/* readonly attribute unsigned short readyState; */
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetReadyState(uint16_t* aReadyState)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
*aReadyState = ReadyState();
|
2008-07-09 01:22:20 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute boolean seeking; */
|
2013-03-19 05:25:19 -07:00
|
|
|
bool
|
|
|
|
HTMLMediaElement::Seeking() const
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
return mDecoder && mDecoder->IsSeeking();
|
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetSeeking(bool* aSeeking)
|
|
|
|
{
|
|
|
|
*aSeeking = Seeking();
|
2008-07-09 01:22:20 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-01-16 19:03:00 -08:00
|
|
|
/* attribute double currentTime; */
|
2013-03-19 05:25:19 -07:00
|
|
|
double
|
|
|
|
HTMLMediaElement::CurrentTime() const
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
2013-05-01 04:24:16 -07:00
|
|
|
MediaStream* stream = GetSrcMediaStream();
|
|
|
|
if (stream) {
|
|
|
|
return MediaTimeToSeconds(stream->GetCurrentTime());
|
|
|
|
}
|
2013-03-19 05:25:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mDecoder) {
|
|
|
|
return mDecoder->GetCurrentTime();
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-03-19 05:25:19 -07:00
|
|
|
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetCurrentTime(double* aCurrentTime)
|
|
|
|
{
|
|
|
|
*aCurrentTime = CurrentTime();
|
2008-07-09 01:22:20 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::SetCurrentTime(double aCurrentTime, ErrorResult& aRv)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
MOZ_ASSERT(aCurrentTime == aCurrentTime);
|
|
|
|
|
2009-05-17 19:00:44 -07:00
|
|
|
StopSuspendingAfterFirstFrame();
|
|
|
|
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
2012-04-29 20:12:28 -07:00
|
|
|
// do nothing since streams aren't seekable; we effectively clamp to
|
|
|
|
// the current time.
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
|
2012-04-30 17:29:24 -07:00
|
|
|
if (mCurrentPlayRangeStart != -1.0) {
|
2013-03-19 05:25:19 -07:00
|
|
|
double rangeEndTime = CurrentTime();
|
2012-04-30 17:29:24 -07:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p Adding \'played\' a range : [%f, %f]", this, mCurrentPlayRangeStart, rangeEndTime));
|
|
|
|
// Multiple seek without playing, or seek while playing.
|
|
|
|
if (mCurrentPlayRangeStart != rangeEndTime) {
|
2013-04-22 16:45:00 -07:00
|
|
|
mPlayed->Add(mCurrentPlayRangeStart, rangeEndTime);
|
2012-04-30 17:29:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-29 14:32:44 -07:00
|
|
|
if (!mDecoder) {
|
2009-11-05 23:32:52 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: no decoder", this, aCurrentTime));
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
2009-09-29 14:32:44 -07:00
|
|
|
}
|
2008-10-19 00:39:21 -07:00
|
|
|
|
2009-09-29 14:32:44 -07:00
|
|
|
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
|
2009-11-05 23:32:52 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: no source", this, aCurrentTime));
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
2009-09-29 14:32:44 -07:00
|
|
|
}
|
2008-10-19 00:39:21 -07:00
|
|
|
|
2012-04-30 17:29:24 -07:00
|
|
|
// Clamp the time to [0, duration] as required by the spec.
|
2013-01-15 04:22:03 -08:00
|
|
|
double clampedTime = std::max(0.0, aCurrentTime);
|
2011-01-16 19:03:00 -08:00
|
|
|
double duration = mDecoder->GetDuration();
|
2009-05-19 02:55:04 -07:00
|
|
|
if (duration >= 0) {
|
2013-01-15 04:22:03 -08:00
|
|
|
clampedTime = std::min(clampedTime, duration);
|
2009-05-19 02:55:04 -07:00
|
|
|
}
|
2008-10-19 00:39:21 -07:00
|
|
|
|
2008-12-14 19:38:16 -08:00
|
|
|
mPlayingBeforeSeek = IsPotentiallyPlaying();
|
2008-10-23 01:02:18 -07:00
|
|
|
// The media backend is responsible for dispatching the timeupdate
|
|
|
|
// event if it changes the playback position as a result of the seek.
|
2009-11-05 23:32:52 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) starting seek", this, aCurrentTime));
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv = mDecoder->Seek(clampedTime);
|
2012-04-30 17:29:24 -07:00
|
|
|
// Start a new range at position we seeked to.
|
2012-06-06 16:43:29 -07:00
|
|
|
mCurrentPlayRangeStart = mDecoder->GetCurrentTime();
|
2009-10-01 07:10:13 -07:00
|
|
|
|
2012-04-30 17:29:24 -07:00
|
|
|
// We changed whether we're seeking so we need to AddRemoveSelfReference.
|
2009-10-01 07:10:13 -07:00
|
|
|
AddRemoveSelfReference();
|
2013-03-19 05:25:19 -07:00
|
|
|
}
|
2009-10-01 07:10:13 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::SetCurrentTime(double aCurrentTime)
|
|
|
|
{
|
|
|
|
// Detect for a NaN and invalid values.
|
|
|
|
if (aCurrentTime != aCurrentTime) {
|
|
|
|
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: bad time", this, aCurrentTime));
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorResult rv;
|
|
|
|
SetCurrentTime(aCurrentTime, rv);
|
|
|
|
return rv.ErrorCode();
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2011-01-16 19:03:00 -08:00
|
|
|
/* readonly attribute double duration; */
|
2013-03-19 05:25:19 -07:00
|
|
|
double
|
|
|
|
HTMLMediaElement::Duration() const
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
2013-03-19 05:25:19 -07:00
|
|
|
return std::numeric_limits<double>::infinity();
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-03-19 05:25:19 -07:00
|
|
|
|
|
|
|
if (mDecoder) {
|
|
|
|
return mDecoder->GetDuration();
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::numeric_limits<double>::quiet_NaN();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetDuration(double* aDuration)
|
|
|
|
{
|
|
|
|
*aDuration = Duration();
|
2008-07-09 01:22:20 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
already_AddRefed<TimeRanges>
|
|
|
|
HTMLMediaElement::Seekable() const
|
2011-08-09 03:10:48 -07:00
|
|
|
{
|
2013-03-02 11:14:44 -08:00
|
|
|
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
2013-06-20 20:15:47 -07:00
|
|
|
if (mMediaSource) {
|
|
|
|
double duration = mMediaSource->Duration();
|
|
|
|
if (IsNaN(duration)) {
|
|
|
|
// Return empty range.
|
|
|
|
} else if (duration > 0 && IsInfinite(duration)) {
|
|
|
|
nsRefPtr<TimeRanges> bufferedRanges = Buffered();
|
|
|
|
ranges->Add(0, bufferedRanges->GetFinalEndTime());
|
|
|
|
} else {
|
|
|
|
ranges->Add(0, duration);
|
|
|
|
}
|
|
|
|
} else if (mDecoder && mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) {
|
2011-08-09 03:10:48 -07:00
|
|
|
mDecoder->GetSeekable(ranges);
|
|
|
|
}
|
2013-09-26 22:22:38 -07:00
|
|
|
ranges->Normalize();
|
2013-03-19 05:25:19 -07:00
|
|
|
return ranges.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* readonly attribute nsIDOMHTMLTimeRanges seekable; */
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetSeekable(nsIDOMTimeRanges** aSeekable)
|
|
|
|
{
|
|
|
|
nsRefPtr<TimeRanges> ranges = Seekable();
|
2011-11-15 23:50:19 -08:00
|
|
|
ranges.forget(aSeekable);
|
2011-08-09 03:10:48 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-28 14:54:17 -07:00
|
|
|
/* readonly attribute boolean paused; */
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetPaused(bool* aPaused)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
*aPaused = Paused();
|
2008-07-09 01:22:20 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
already_AddRefed<TimeRanges>
|
|
|
|
HTMLMediaElement::Played()
|
2012-04-30 17:29:24 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
2012-04-30 17:29:24 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t timeRangeCount = 0;
|
2013-04-22 16:45:00 -07:00
|
|
|
mPlayed->GetLength(&timeRangeCount);
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < timeRangeCount; i++) {
|
2012-04-30 17:29:24 -07:00
|
|
|
double begin;
|
|
|
|
double end;
|
2013-04-22 16:45:00 -07:00
|
|
|
mPlayed->Start(i, &begin);
|
|
|
|
mPlayed->End(i, &end);
|
2012-04-30 17:29:24 -07:00
|
|
|
ranges->Add(begin, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mCurrentPlayRangeStart != -1.0) {
|
2013-03-19 05:25:19 -07:00
|
|
|
double now = CurrentTime();
|
2012-04-30 17:29:24 -07:00
|
|
|
if (mCurrentPlayRangeStart != now) {
|
|
|
|
ranges->Add(mCurrentPlayRangeStart, now);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ranges->Normalize();
|
2013-03-19 05:25:19 -07:00
|
|
|
return ranges.forget();
|
|
|
|
}
|
2012-04-30 17:29:24 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
/* readonly attribute nsIDOMHTMLTimeRanges played; */
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetPlayed(nsIDOMTimeRanges** aPlayed)
|
|
|
|
{
|
|
|
|
nsRefPtr<TimeRanges> ranges = Played();
|
|
|
|
ranges.forget(aPlayed);
|
2012-04-30 17:29:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
/* void pause (); */
|
2013-03-19 05:25:19 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::Pause(ErrorResult& aRv)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2008-12-14 19:38:16 -08:00
|
|
|
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
|
2010-09-02 17:03:03 -07:00
|
|
|
LOG(PR_LOG_DEBUG, ("Loading due to Pause()"));
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv = Load();
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
2009-01-08 00:44:38 -08:00
|
|
|
} else if (mDecoder) {
|
|
|
|
mDecoder->Pause();
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool oldPaused = mPaused;
|
2011-09-29 16:34:37 -07:00
|
|
|
mPaused = true;
|
|
|
|
mAutoplaying = false;
|
2009-10-01 07:10:13 -07:00
|
|
|
// We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
|
|
|
|
AddRemoveSelfReference();
|
2009-11-05 23:32:52 -08:00
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
if (!oldPaused) {
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
2013-05-01 04:24:16 -07:00
|
|
|
MediaStream* stream = GetSrcMediaStream();
|
|
|
|
if (stream) {
|
|
|
|
stream->ChangeExplicitBlockerCount(1);
|
|
|
|
}
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2011-09-29 16:34:37 -07:00
|
|
|
FireTimeUpdate(false);
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("pause"));
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
2013-03-19 05:25:19 -07:00
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::Pause()
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
Pause(rv);
|
|
|
|
return rv.ErrorCode();
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2011-01-16 19:03:00 -08:00
|
|
|
/* attribute double volume; */
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetVolume(double* aVolume)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
*aVolume = Volume();
|
2008-07-09 01:22:20 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::SetVolume(double aVolume, ErrorResult& aRv)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
if (aVolume < 0.0 || aVolume > 1.0) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
2008-09-30 22:44:16 -07:00
|
|
|
|
2009-02-25 02:59:00 -08:00
|
|
|
if (aVolume == mVolume)
|
2013-03-19 05:25:19 -07:00
|
|
|
return;
|
2009-02-25 02:59:00 -08:00
|
|
|
|
|
|
|
mVolume = aVolume;
|
|
|
|
|
2013-05-21 10:49:17 -07:00
|
|
|
// Here we want just to update the volume.
|
2013-05-26 22:13:05 -07:00
|
|
|
SetVolumeInternal();
|
2009-02-25 02:59:00 -08:00
|
|
|
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("volumechange"));
|
2013-03-19 05:25:19 -07:00
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::SetVolume(double aVolume)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
SetVolume(aVolume, rv);
|
|
|
|
return rv.ErrorCode();
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
uint32_t
|
|
|
|
HTMLMediaElement::GetMozChannels(ErrorResult& aRv) const
|
2010-08-25 06:10:00 -07:00
|
|
|
{
|
|
|
|
if (!mDecoder && !mAudioStream) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return 0;
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
return mChannels;
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-19 05:25:19 -07:00
|
|
|
HTMLMediaElement::GetMozChannels(uint32_t* aMozChannels)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
*aMozChannels = GetMozChannels(rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
HTMLMediaElement::GetMozSampleRate(ErrorResult& aRv) const
|
2010-08-25 06:10:00 -07:00
|
|
|
{
|
|
|
|
if (!mDecoder && !mAudioStream) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return 0;
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
return mRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLMediaElement::GetMozSampleRate(uint32_t* aMozSampleRate)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
*aMozSampleRate = GetMozSampleRate(rv);
|
|
|
|
return rv.ErrorCode();
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-30 17:14:29 -07:00
|
|
|
// Helper struct with arguments for our hash iterator.
|
2013-05-13 10:43:53 -07:00
|
|
|
typedef struct MOZ_STACK_CLASS {
|
2012-07-30 17:14:29 -07:00
|
|
|
JSContext* cx;
|
2013-05-13 10:43:53 -07:00
|
|
|
JS::HandleObject tags;
|
2012-09-21 13:13:41 -07:00
|
|
|
bool error;
|
2012-07-30 17:14:29 -07:00
|
|
|
} MetadataIterCx;
|
|
|
|
|
|
|
|
PLDHashOperator
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::BuildObjectFromTags(nsCStringHashKey::KeyType aKey,
|
|
|
|
nsCString aValue,
|
|
|
|
void* aUserArg)
|
2012-07-30 17:14:29 -07:00
|
|
|
{
|
|
|
|
MetadataIterCx* args = static_cast<MetadataIterCx*>(aUserArg);
|
|
|
|
|
|
|
|
nsString wideValue = NS_ConvertUTF8toUTF16(aValue);
|
|
|
|
JSString* string = JS_NewUCStringCopyZ(args->cx, wideValue.Data());
|
2012-12-22 15:35:07 -08:00
|
|
|
if (!string) {
|
|
|
|
NS_WARNING("Failed to perform string copy");
|
|
|
|
args->error = true;
|
|
|
|
return PL_DHASH_STOP;
|
|
|
|
}
|
2012-07-30 17:14:29 -07:00
|
|
|
JS::Value value = STRING_TO_JSVAL(string);
|
2012-09-14 13:04:46 -07:00
|
|
|
if (!JS_DefineProperty(args->cx, args->tags, aKey.Data(), value,
|
2013-04-02 18:14:24 -07:00
|
|
|
nullptr, nullptr, JSPROP_ENUMERATE)) {
|
2012-07-30 17:14:29 -07:00
|
|
|
NS_WARNING("Failed to set metadata property");
|
2012-09-21 13:13:41 -07:00
|
|
|
args->error = true;
|
2012-09-14 13:04:46 -07:00
|
|
|
return PL_DHASH_STOP;
|
2012-07-30 17:14:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
JSObject*
|
|
|
|
HTMLMediaElement::MozGetMetadata(JSContext* cx, ErrorResult& aRv)
|
2012-07-30 17:14:29 -07:00
|
|
|
{
|
|
|
|
if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return nullptr;
|
2012-07-30 17:14:29 -07:00
|
|
|
}
|
|
|
|
|
2013-05-02 02:12:45 -07:00
|
|
|
JS::Rooted<JSObject*> tags(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
|
2012-07-30 17:14:29 -07:00
|
|
|
if (!tags) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
2012-07-30 17:14:29 -07:00
|
|
|
}
|
|
|
|
if (mTags) {
|
2012-09-21 13:13:41 -07:00
|
|
|
MetadataIterCx iter = {cx, tags, false};
|
|
|
|
mTags->EnumerateRead(BuildObjectFromTags, static_cast<void*>(&iter));
|
|
|
|
if (iter.error) {
|
2012-09-14 13:04:46 -07:00
|
|
|
NS_WARNING("couldn't create metadata object!");
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
2012-09-14 13:04:46 -07:00
|
|
|
}
|
2012-07-30 17:14:29 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
return tags;
|
2012-07-30 17:14:29 -07:00
|
|
|
}
|
|
|
|
|
2010-08-25 06:10:00 -07:00
|
|
|
NS_IMETHODIMP
|
2013-03-19 05:25:19 -07:00
|
|
|
HTMLMediaElement::MozGetMetadata(JSContext* cx, JS::Value* aValue)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
|
|
|
|
JSObject* obj = MozGetMetadata(cx, rv);
|
|
|
|
if (!rv.Failed()) {
|
|
|
|
MOZ_ASSERT(obj);
|
|
|
|
*aValue = JS::ObjectValue(*obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
HTMLMediaElement::GetMozFrameBufferLength(ErrorResult& aRv) const
|
2010-08-25 06:10:00 -07:00
|
|
|
{
|
|
|
|
// The framebuffer (via MozAudioAvailable events) is only available
|
|
|
|
// when reading vs. writing audio directly.
|
|
|
|
if (!mDecoder) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return 0;
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
return mDecoder->GetFrameBufferLength();
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-19 05:25:19 -07:00
|
|
|
HTMLMediaElement::GetMozFrameBufferLength(uint32_t* aMozFrameBufferLength)
|
2010-08-25 06:10:00 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
ErrorResult rv;
|
|
|
|
*aMozFrameBufferLength = GetMozFrameBufferLength(rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
2010-08-25 06:10:00 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::SetMozFrameBufferLength(uint32_t aMozFrameBufferLength, ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
if (!mDecoder) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aRv = mDecoder->RequestFrameBufferLength(aMozFrameBufferLength);
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLMediaElement::SetMozFrameBufferLength(uint32_t aMozFrameBufferLength)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
ErrorResult rv;
|
|
|
|
SetMozFrameBufferLength(aMozFrameBufferLength, rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
/* attribute boolean muted; */
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetMuted(bool* aMuted)
|
|
|
|
{
|
|
|
|
*aMuted = Muted();
|
2008-07-09 01:22:20 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-05-21 10:49:17 -07:00
|
|
|
void HTMLMediaElement::SetMutedInternal(uint32_t aMuted)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-05-21 10:49:17 -07:00
|
|
|
uint32_t oldMuted = mMuted;
|
|
|
|
mMuted = aMuted;
|
|
|
|
|
|
|
|
if (!!aMuted == !!oldMuted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-26 22:13:05 -07:00
|
|
|
SetVolumeInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLMediaElement::SetVolumeInternal()
|
|
|
|
{
|
2013-09-02 02:45:44 -07:00
|
|
|
float effectiveVolume = mMuted ? 0.0f :
|
|
|
|
mAudioChannelFaded ? float(mVolume) * FADED_VOLUME_RATIO : float(mVolume);
|
2012-12-04 11:46:07 -08:00
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
if (mDecoder) {
|
2012-04-29 20:12:28 -07:00
|
|
|
mDecoder->SetVolume(effectiveVolume);
|
2010-08-25 06:10:00 -07:00
|
|
|
} else if (mAudioStream) {
|
2012-04-29 20:12:28 -07:00
|
|
|
mAudioStream->SetVolume(effectiveVolume);
|
2012-08-19 21:52:59 -07:00
|
|
|
} else if (mSrcStream) {
|
|
|
|
GetSrcMediaStream()->SetAudioOutputVolume(this, effectiveVolume);
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
2012-11-22 02:38:28 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::SetMuted(bool aMuted)
|
2012-11-22 02:38:28 -08:00
|
|
|
{
|
2013-05-24 05:04:20 -07:00
|
|
|
if (aMuted == Muted()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-05-21 10:49:17 -07:00
|
|
|
if (aMuted) {
|
|
|
|
SetMutedInternal(mMuted | MUTED_BY_CONTENT);
|
|
|
|
} else {
|
|
|
|
SetMutedInternal(mMuted & ~MUTED_BY_CONTENT);
|
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("volumechange"));
|
2008-07-09 01:22:20 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
already_AddRefed<DOMMediaStream>
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
|
2012-04-29 20:12:42 -07:00
|
|
|
{
|
2013-02-15 00:04:11 -08:00
|
|
|
nsIDOMWindow* window = OwnerDoc()->GetInnerWindow();
|
|
|
|
if (!window) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2012-04-29 20:12:42 -07:00
|
|
|
OutputMediaStream* out = mOutputStreams.AppendElement();
|
2013-02-15 00:04:11 -08:00
|
|
|
out->mStream = DOMMediaStream::CreateTrackUnionStream(window);
|
2012-04-29 20:12:42 -07:00
|
|
|
nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
|
|
|
|
out->mStream->CombineWithPrincipal(principal);
|
|
|
|
out->mFinishWhenEnded = aFinishWhenEnded;
|
|
|
|
|
|
|
|
mAudioCaptured = true;
|
2012-07-31 05:17:22 -07:00
|
|
|
// Block the output stream initially.
|
|
|
|
// Decoders are responsible for removing the block while they are playing
|
|
|
|
// back into the output stream.
|
|
|
|
out->mStream->GetStream()->ChangeExplicitBlockerCount(1);
|
2012-04-29 20:12:42 -07:00
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->SetAudioCaptured(true);
|
|
|
|
mDecoder->AddOutputStream(
|
2012-07-31 05:17:22 -07:00
|
|
|
out->mStream->GetStream()->AsProcessedStream(), aFinishWhenEnded);
|
2012-04-29 20:12:42 -07:00
|
|
|
}
|
2013-02-15 00:01:58 -08:00
|
|
|
nsRefPtr<DOMMediaStream> result = out->mStream;
|
2012-04-29 20:12:42 -07:00
|
|
|
return result.forget();
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
already_AddRefed<DOMMediaStream>
|
|
|
|
HTMLMediaElement::MozCaptureStream(ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
nsRefPtr<DOMMediaStream> stream = CaptureStreamInternal(false);
|
|
|
|
if (!stream) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stream.forget();
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::MozCaptureStream(nsIDOMMediaStream** aStream)
|
2012-04-29 20:12:42 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
ErrorResult rv;
|
|
|
|
*aStream = MozCaptureStream(rv).get();
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<DOMMediaStream>
|
|
|
|
HTMLMediaElement::MozCaptureStreamUntilEnded(ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
nsRefPtr<DOMMediaStream> stream = CaptureStreamInternal(true);
|
|
|
|
if (!stream) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return nullptr;
|
2013-02-15 00:04:11 -08:00
|
|
|
}
|
2013-03-19 05:25:19 -07:00
|
|
|
|
|
|
|
return stream.forget();
|
2012-04-29 20:12:42 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::MozCaptureStreamUntilEnded(nsIDOMMediaStream** aStream)
|
2012-04-29 20:12:42 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
ErrorResult rv;
|
|
|
|
*aStream = MozCaptureStreamUntilEnded(rv).get();
|
|
|
|
return rv.ErrorCode();
|
2012-04-29 20:12:42 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetMozAudioCaptured(bool* aCaptured)
|
2012-04-29 20:12:42 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
*aCaptured = MozAudioCaptured();
|
2012-04-29 20:12:42 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-11-24 18:06:22 -08:00
|
|
|
class MediaElementSetForURI : public nsURIHashKey {
|
|
|
|
public:
|
|
|
|
MediaElementSetForURI(const nsIURI* aKey) : nsURIHashKey(aKey) {}
|
|
|
|
MediaElementSetForURI(const MediaElementSetForURI& toCopy)
|
|
|
|
: nsURIHashKey(toCopy), mElements(toCopy.mElements) {}
|
2013-03-19 05:23:54 -07:00
|
|
|
nsTArray<HTMLMediaElement*> mElements;
|
2011-11-24 18:06:22 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef nsTHashtable<MediaElementSetForURI> MediaElementURITable;
|
|
|
|
// Elements in this table must have non-null mDecoder and mLoadingSrc, and those
|
|
|
|
// can't change while the element is in the table. The table is keyed by
|
|
|
|
// the element's mLoadingSrc. Each entry has a list of all elements with the
|
|
|
|
// same mLoadingSrc.
|
|
|
|
static MediaElementURITable* gElementTable;
|
|
|
|
|
2012-01-10 14:58:43 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
// Returns the number of times aElement appears in the media element table
|
|
|
|
// for aURI. If this returns other than 0 or 1, there's a bug somewhere!
|
|
|
|
static unsigned
|
2013-03-19 05:23:54 -07:00
|
|
|
MediaElementTableCount(HTMLMediaElement* aElement, nsIURI* aURI)
|
2012-01-10 14:58:43 -08:00
|
|
|
{
|
|
|
|
if (!gElementTable || !aElement || !aURI) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
MediaElementSetForURI* entry = gElementTable->GetEntry(aURI);
|
|
|
|
if (!entry) {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t count = 0;
|
|
|
|
for (uint32_t i = 0; i < entry->mElements.Length(); ++i) {
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement* elem = entry->mElements[i];
|
2012-01-10 14:58:43 -08:00
|
|
|
if (elem == aElement) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-11-24 18:06:22 -08:00
|
|
|
void
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::AddMediaElementToURITable()
|
2011-11-24 18:06:22 -08:00
|
|
|
{
|
2012-02-14 20:35:01 -08:00
|
|
|
NS_ASSERTION(mDecoder && mDecoder->GetResource(), "Call this only with decoder Load called");
|
2012-01-10 14:58:43 -08:00
|
|
|
NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 0,
|
|
|
|
"Should not have entry for element in element table before addition");
|
2011-11-24 18:06:22 -08:00
|
|
|
if (!gElementTable) {
|
|
|
|
gElementTable = new MediaElementURITable();
|
|
|
|
}
|
|
|
|
MediaElementSetForURI* entry = gElementTable->PutEntry(mLoadingSrc);
|
|
|
|
entry->mElements.AppendElement(this);
|
2012-01-10 14:58:43 -08:00
|
|
|
NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 1,
|
|
|
|
"Should have a single entry for element in element table after addition");
|
2011-11-24 18:06:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::RemoveMediaElementFromURITable()
|
2011-11-24 18:06:22 -08:00
|
|
|
{
|
2012-01-10 14:58:43 -08:00
|
|
|
NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 1,
|
|
|
|
"Before remove, should have a single entry for element in element table");
|
2011-11-24 18:06:22 -08:00
|
|
|
NS_ASSERTION(mDecoder, "Don't call this without decoder!");
|
|
|
|
NS_ASSERTION(mLoadingSrc, "Can't have decoder without source!");
|
|
|
|
if (!gElementTable)
|
|
|
|
return;
|
|
|
|
MediaElementSetForURI* entry = gElementTable->GetEntry(mLoadingSrc);
|
|
|
|
if (!entry)
|
|
|
|
return;
|
|
|
|
entry->mElements.RemoveElement(this);
|
|
|
|
if (entry->mElements.IsEmpty()) {
|
|
|
|
gElementTable->RemoveEntry(mLoadingSrc);
|
|
|
|
if (gElementTable->Count() == 0) {
|
|
|
|
delete gElementTable;
|
2012-07-30 07:20:58 -07:00
|
|
|
gElementTable = nullptr;
|
2011-11-24 18:06:22 -08:00
|
|
|
}
|
|
|
|
}
|
2012-01-10 14:58:43 -08:00
|
|
|
NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 0,
|
|
|
|
"After remove, should no longer have an entry in element table");
|
2011-11-24 18:06:22 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement*
|
|
|
|
HTMLMediaElement::LookupMediaElementURITable(nsIURI* aURI)
|
2011-11-24 18:06:22 -08:00
|
|
|
{
|
|
|
|
if (!gElementTable)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2011-11-24 18:06:22 -08:00
|
|
|
MediaElementSetForURI* entry = gElementTable->GetEntry(aURI);
|
|
|
|
if (!entry)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < entry->mElements.Length(); ++i) {
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement* elem = entry->mElements[i];
|
2011-11-24 18:06:22 -08:00
|
|
|
bool equal;
|
2012-01-25 14:31:30 -08:00
|
|
|
// Look for elements that have the same principal and CORS mode.
|
|
|
|
// Ditto for anything else that could cause us to send different headers.
|
|
|
|
if (NS_SUCCEEDED(elem->NodePrincipal()->Equals(NodePrincipal(), &equal)) && equal &&
|
|
|
|
elem->mCORSMode == mCORSMode) {
|
2012-02-14 20:35:01 -08:00
|
|
|
NS_ASSERTION(elem->mDecoder && elem->mDecoder->GetResource(), "Decoder gone");
|
2012-03-20 00:55:40 -07:00
|
|
|
MediaResource* resource = elem->mDecoder->GetResource();
|
|
|
|
if (resource->CanClone()) {
|
|
|
|
return elem;
|
|
|
|
}
|
2011-11-24 18:06:22 -08:00
|
|
|
}
|
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2011-11-24 18:06:22 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::HTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
2008-07-09 01:22:20 -07:00
|
|
|
: nsGenericHTMLElement(aNodeInfo),
|
2012-08-19 21:52:59 -07:00
|
|
|
mSrcStreamListener(nullptr),
|
2009-03-15 23:05:28 -07:00
|
|
|
mCurrentLoadID(0),
|
2008-12-14 19:38:16 -08:00
|
|
|
mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
|
|
|
|
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING),
|
2009-03-15 23:05:28 -07:00
|
|
|
mLoadWaitStatus(NOT_WAITING),
|
2009-02-25 02:59:00 -08:00
|
|
|
mVolume(1.0),
|
2010-08-25 06:10:00 -07:00
|
|
|
mChannels(0),
|
|
|
|
mRate(0),
|
2010-09-14 16:24:47 -07:00
|
|
|
mPreloadAction(PRELOAD_UNDEFINED),
|
2008-10-19 00:39:21 -07:00
|
|
|
mMediaSize(-1,-1),
|
2010-11-24 10:34:57 -08:00
|
|
|
mLastCurrentTime(0.0),
|
2011-08-24 16:42:23 -07:00
|
|
|
mFragmentStart(-1.0),
|
|
|
|
mFragmentEnd(-1.0),
|
2012-11-22 02:38:28 -08:00
|
|
|
mDefaultPlaybackRate(1.0),
|
|
|
|
mPlaybackRate(1.0),
|
|
|
|
mPreservesPitch(true),
|
2013-04-22 16:45:00 -07:00
|
|
|
mPlayed(new TimeRanges),
|
2012-04-30 17:29:24 -07:00
|
|
|
mCurrentPlayRangeStart(-1.0),
|
2011-09-29 16:34:37 -07:00
|
|
|
mAllowAudioData(false),
|
|
|
|
mBegun(false),
|
|
|
|
mLoadedFirstFrame(false),
|
|
|
|
mAutoplaying(true),
|
|
|
|
mAutoplayEnabled(true),
|
|
|
|
mPaused(true),
|
2013-05-21 10:49:17 -07:00
|
|
|
mMuted(0),
|
2012-04-29 20:12:42 -07:00
|
|
|
mAudioCaptured(false),
|
2011-09-29 16:34:37 -07:00
|
|
|
mPlayingBeforeSeek(false),
|
2012-12-11 17:58:07 -08:00
|
|
|
mPausedForInactiveDocumentOrChannel(false),
|
|
|
|
mEventDeliveryPaused(false),
|
2011-09-29 16:34:37 -07:00
|
|
|
mWaitingFired(false),
|
|
|
|
mIsRunningLoadMethod(false),
|
|
|
|
mIsLoadingFromSourceChildren(false),
|
|
|
|
mDelayingLoadEvent(false),
|
|
|
|
mIsRunningSelectResource(false),
|
2012-02-19 13:02:08 -08:00
|
|
|
mHaveQueuedSelectResource(false),
|
2011-09-29 16:34:37 -07:00
|
|
|
mSuspendedAfterFirstFrame(false),
|
|
|
|
mAllowSuspendAfterFirstFrame(true),
|
|
|
|
mHasPlayedOrSeeked(false),
|
|
|
|
mHasSelfReference(false),
|
|
|
|
mShuttingDown(false),
|
2012-05-27 15:40:06 -07:00
|
|
|
mSuspendedForPreloadNone(false),
|
2012-01-25 14:31:30 -08:00
|
|
|
mMediaSecurityVerified(false),
|
2012-04-28 08:01:10 -07:00
|
|
|
mCORSMode(CORS_NONE),
|
2012-05-27 15:40:06 -07:00
|
|
|
mHasAudio(false),
|
2012-11-15 19:25:26 -08:00
|
|
|
mDownloadSuspendedByCache(false),
|
2012-12-04 11:46:07 -08:00
|
|
|
mAudioChannelType(AUDIO_CHANNEL_NORMAL),
|
2013-09-02 02:45:44 -07:00
|
|
|
mAudioChannelFaded(false),
|
2013-07-09 10:30:18 -07:00
|
|
|
mPlayingThroughTheAudioChannel(false)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2009-09-29 14:32:44 -07:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
if (!gMediaElementLog) {
|
|
|
|
gMediaElementLog = PR_NewLogModule("nsMediaElement");
|
|
|
|
}
|
|
|
|
if (!gMediaElementEventsLog) {
|
|
|
|
gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-11-01 05:47:51 -07:00
|
|
|
mPaused.SetOuter(this);
|
|
|
|
|
2009-05-07 18:32:32 -07:00
|
|
|
RegisterFreezableElement();
|
2009-10-01 07:10:13 -07:00
|
|
|
NotifyOwnerDocumentActivityChanged();
|
2013-05-21 09:14:00 -07:00
|
|
|
|
|
|
|
mTextTracks = new TextTrackList(OwnerDoc()->GetParentObject());
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::~HTMLMediaElement()
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2009-10-01 07:10:13 -07:00
|
|
|
NS_ASSERTION(!mHasSelfReference,
|
|
|
|
"How can we be destroyed if we're still holding a self reference?");
|
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
if (mVideoFrameContainer) {
|
|
|
|
mVideoFrameContainer->ForgetElement();
|
|
|
|
}
|
2009-05-07 18:32:32 -07:00
|
|
|
UnregisterFreezableElement();
|
2008-10-19 00:39:21 -07:00
|
|
|
if (mDecoder) {
|
2012-04-29 20:13:09 -07:00
|
|
|
ShutdownDecoder();
|
2008-10-19 00:39:21 -07:00
|
|
|
}
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
|
|
|
EndSrcMediaStreamPlayback();
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-06-20 20:15:47 -07:00
|
|
|
if (mMediaSource) {
|
2013-09-26 22:22:37 -07:00
|
|
|
mMediaSource->Detach();
|
2013-06-20 20:15:47 -07:00
|
|
|
mMediaSource = nullptr;
|
|
|
|
}
|
2012-01-10 14:58:43 -08:00
|
|
|
|
|
|
|
NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 0,
|
|
|
|
"Destroyed media element should no longer be in element table");
|
|
|
|
|
2008-12-15 19:32:03 -08:00
|
|
|
if (mChannel) {
|
|
|
|
mChannel->Cancel(NS_BINDING_ABORTED);
|
|
|
|
}
|
2010-08-25 06:10:00 -07:00
|
|
|
if (mAudioStream) {
|
|
|
|
mAudioStream->Shutdown();
|
|
|
|
}
|
2013-05-28 10:30:17 -07:00
|
|
|
|
|
|
|
WakeLockRelease();
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2012-10-28 19:09:07 -07:00
|
|
|
void
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::GetItemValueText(nsAString& aValue)
|
2012-10-28 19:09:07 -07:00
|
|
|
{
|
|
|
|
// Can't call GetSrc because we don't have a JSContext
|
|
|
|
GetURIAttr(nsGkAtoms::src, nullptr, aValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::SetItemValueText(const nsAString& aValue)
|
2012-10-28 19:09:07 -07:00
|
|
|
{
|
|
|
|
// Can't call SetSrc because we don't have a JSContext
|
|
|
|
SetAttr(kNameSpaceID_None, nsGkAtoms::src, aValue, true);
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::StopSuspendingAfterFirstFrame()
|
2009-05-17 19:00:44 -07:00
|
|
|
{
|
2011-09-29 16:34:37 -07:00
|
|
|
mAllowSuspendAfterFirstFrame = false;
|
2009-05-17 19:00:44 -07:00
|
|
|
if (!mSuspendedAfterFirstFrame)
|
|
|
|
return;
|
2011-09-29 16:34:37 -07:00
|
|
|
mSuspendedAfterFirstFrame = false;
|
2009-05-17 19:00:44 -07:00
|
|
|
if (mDecoder) {
|
2011-09-29 16:34:37 -07:00
|
|
|
mDecoder->Resume(true);
|
2009-05-17 19:00:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SetPlayedOrSeeked(bool aValue)
|
2009-06-26 00:25:17 -07:00
|
|
|
{
|
2011-11-15 23:50:19 -08:00
|
|
|
if (aValue == mHasPlayedOrSeeked) {
|
2009-06-26 00:25:17 -07:00
|
|
|
return;
|
2011-11-15 23:50:19 -08:00
|
|
|
}
|
2009-06-26 00:25:17 -07:00
|
|
|
|
|
|
|
mHasPlayedOrSeeked = aValue;
|
|
|
|
|
|
|
|
// Force a reflow so that the poster frame hides or shows immediately.
|
2009-12-24 13:20:05 -08:00
|
|
|
nsIFrame* frame = GetPrimaryFrame();
|
2011-11-15 23:50:19 -08:00
|
|
|
if (!frame) {
|
|
|
|
return;
|
|
|
|
}
|
2009-12-24 13:20:05 -08:00
|
|
|
frame->PresContext()->PresShell()->FrameNeedsReflow(frame,
|
|
|
|
nsIPresShell::eTreeChange,
|
|
|
|
NS_FRAME_IS_DIRTY);
|
2009-06-26 00:25:17 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::Play(ErrorResult& aRv)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2009-05-17 19:00:44 -07:00
|
|
|
StopSuspendingAfterFirstFrame();
|
2011-09-29 16:34:37 -07:00
|
|
|
SetPlayedOrSeeked(true);
|
2009-05-17 19:00:44 -07:00
|
|
|
|
2008-12-14 19:38:16 -08:00
|
|
|
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv = Load();
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
2011-11-24 18:06:22 -08:00
|
|
|
}
|
2012-05-27 15:40:06 -07:00
|
|
|
if (mSuspendedForPreloadNone) {
|
2010-08-19 15:50:37 -07:00
|
|
|
ResumeLoad(PRELOAD_ENOUGH);
|
2011-11-24 18:06:22 -08:00
|
|
|
}
|
|
|
|
// Even if we just did Load() or ResumeLoad(), we could already have a decoder
|
|
|
|
// here if we managed to clone an existing decoder.
|
|
|
|
if (mDecoder) {
|
2009-02-10 17:23:19 -08:00
|
|
|
if (mDecoder->IsEnded()) {
|
|
|
|
SetCurrentTime(0);
|
|
|
|
}
|
2012-12-11 17:58:07 -08:00
|
|
|
if (!mPausedForInactiveDocumentOrChannel) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv = mDecoder->Play();
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
2009-10-01 07:10:13 -07:00
|
|
|
}
|
2008-10-21 02:19:33 -07:00
|
|
|
}
|
|
|
|
|
2012-04-30 17:29:24 -07:00
|
|
|
if (mCurrentPlayRangeStart == -1.0) {
|
2013-03-19 05:25:19 -07:00
|
|
|
mCurrentPlayRangeStart = CurrentTime();
|
2012-04-30 17:29:24 -07:00
|
|
|
}
|
|
|
|
|
2009-11-05 23:32:52 -08:00
|
|
|
// TODO: If the playback has ended, then the user agent must set
|
2009-03-08 13:59:08 -07:00
|
|
|
// seek to the effective start.
|
2009-02-10 17:23:19 -08:00
|
|
|
if (mPaused) {
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
|
|
|
GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("play"));
|
2009-02-10 17:23:19 -08:00
|
|
|
switch (mReadyState) {
|
2011-03-23 15:28:57 -07:00
|
|
|
case nsIDOMHTMLMediaElement::HAVE_NOTHING:
|
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
|
|
|
|
break;
|
2009-02-10 17:23:19 -08:00
|
|
|
case nsIDOMHTMLMediaElement::HAVE_METADATA:
|
|
|
|
case nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA:
|
2011-09-29 16:34:37 -07:00
|
|
|
FireTimeUpdate(false);
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
|
2009-02-10 17:23:19 -08:00
|
|
|
break;
|
|
|
|
case nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA:
|
|
|
|
case nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA:
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("playing"));
|
2009-02-10 17:23:19 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
mPaused = false;
|
|
|
|
mAutoplaying = false;
|
2009-10-01 07:10:13 -07:00
|
|
|
// We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
|
2010-10-16 11:41:53 -07:00
|
|
|
// and our preload status.
|
2009-10-01 07:10:13 -07:00
|
|
|
AddRemoveSelfReference();
|
2010-10-16 11:41:53 -07:00
|
|
|
UpdatePreloadAction();
|
2013-03-19 05:25:19 -07:00
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::Play()
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
Play(rv);
|
|
|
|
return rv.ErrorCode();
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-05-02 09:45:35 -07:00
|
|
|
HTMLMediaElement::WakeLockBoolWrapper&
|
2013-05-28 10:30:17 -07:00
|
|
|
HTMLMediaElement::WakeLockBoolWrapper::operator=(bool val)
|
|
|
|
{
|
2013-05-02 09:45:35 -07:00
|
|
|
if (mValue == val) {
|
2012-11-01 05:47:51 -07:00
|
|
|
return *this;
|
2013-05-02 09:45:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mValue = val;
|
|
|
|
UpdateWakeLock();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2013-05-28 10:30:17 -07:00
|
|
|
HTMLMediaElement::WakeLockBoolWrapper::~WakeLockBoolWrapper()
|
|
|
|
{
|
|
|
|
if (mTimer) {
|
|
|
|
mTimer->Cancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-02 09:45:35 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::WakeLockBoolWrapper::SetCanPlay(bool aCanPlay)
|
|
|
|
{
|
|
|
|
mCanPlay = aCanPlay;
|
|
|
|
UpdateWakeLock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HTMLMediaElement::WakeLockBoolWrapper::UpdateWakeLock()
|
|
|
|
{
|
|
|
|
if (!mOuter) {
|
|
|
|
return;
|
|
|
|
}
|
2013-05-10 05:42:39 -07:00
|
|
|
|
2013-05-02 09:45:35 -07:00
|
|
|
bool playing = (!mValue && mCanPlay);
|
|
|
|
|
|
|
|
if (playing) {
|
2013-05-28 10:30:17 -07:00
|
|
|
if (mTimer) {
|
|
|
|
mTimer->Cancel();
|
|
|
|
mTimer = nullptr;
|
|
|
|
}
|
2013-05-10 05:42:39 -07:00
|
|
|
mOuter->WakeLockCreate();
|
2013-05-28 10:30:17 -07:00
|
|
|
} else if (!mTimer) {
|
|
|
|
// Don't release the wake lock immediately; instead, release it after a
|
|
|
|
// grace period.
|
|
|
|
int timeout = Preferences::GetInt("media.wakelock_timeout", 2000);
|
|
|
|
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
2013-05-30 08:26:12 -07:00
|
|
|
if (mTimer) {
|
|
|
|
mTimer->InitWithFuncCallback(TimerCallback, this, timeout,
|
|
|
|
nsITimer::TYPE_ONE_SHOT);
|
|
|
|
}
|
2013-05-10 05:42:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-28 10:30:17 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::WakeLockBoolWrapper::TimerCallback(nsITimer* aTimer,
|
|
|
|
void* aClosure)
|
|
|
|
{
|
|
|
|
WakeLockBoolWrapper* wakeLock = static_cast<WakeLockBoolWrapper*>(aClosure);
|
|
|
|
wakeLock->mOuter->WakeLockRelease();
|
|
|
|
wakeLock->mTimer = nullptr;
|
|
|
|
}
|
|
|
|
|
2013-05-10 05:42:39 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::WakeLockCreate()
|
|
|
|
{
|
|
|
|
if (!mWakeLock) {
|
2012-11-01 05:47:51 -07:00
|
|
|
nsCOMPtr<nsIPowerManagerService> pmService =
|
|
|
|
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
|
2013-05-02 09:45:35 -07:00
|
|
|
NS_ENSURE_TRUE_VOID(pmService);
|
2012-11-01 05:47:51 -07:00
|
|
|
|
2013-05-10 05:42:39 -07:00
|
|
|
pmService->NewWakeLock(NS_LITERAL_STRING("cpu"),
|
|
|
|
OwnerDoc()->GetWindow(),
|
|
|
|
getter_AddRefs(mWakeLock));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HTMLMediaElement::WakeLockRelease()
|
|
|
|
{
|
|
|
|
if (mWakeLock) {
|
2013-05-07 07:54:16 -07:00
|
|
|
mWakeLock->Unlock();
|
2013-04-02 18:14:24 -07:00
|
|
|
mWakeLock = nullptr;
|
2012-11-01 05:47:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
bool HTMLMediaElement::ParseAttribute(int32_t aNamespaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsAttrValue& aResult)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2010-08-19 15:50:37 -07:00
|
|
|
// Mappings from 'preload' attribute strings to an enumeration.
|
|
|
|
static const nsAttrValue::EnumTable kPreloadTable[] = {
|
2013-03-19 05:23:54 -07:00
|
|
|
{ "", HTMLMediaElement::PRELOAD_ATTR_EMPTY },
|
|
|
|
{ "none", HTMLMediaElement::PRELOAD_ATTR_NONE },
|
|
|
|
{ "metadata", HTMLMediaElement::PRELOAD_ATTR_METADATA },
|
|
|
|
{ "auto", HTMLMediaElement::PRELOAD_ATTR_AUTO },
|
2010-08-19 15:50:37 -07:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2012-12-04 11:46:07 -08:00
|
|
|
// Mappings from 'mozaudiochannel' attribute strings to an enumeration.
|
|
|
|
static const nsAttrValue::EnumTable kMozAudioChannelAttributeTable[] = {
|
|
|
|
{ "normal", AUDIO_CHANNEL_NORMAL },
|
|
|
|
{ "content", AUDIO_CHANNEL_CONTENT },
|
|
|
|
{ "notification", AUDIO_CHANNEL_NOTIFICATION },
|
|
|
|
{ "alarm", AUDIO_CHANNEL_ALARM },
|
|
|
|
{ "telephony", AUDIO_CHANNEL_TELEPHONY },
|
2012-12-06 01:11:19 -08:00
|
|
|
{ "ringer", AUDIO_CHANNEL_RINGER },
|
2012-12-04 11:46:07 -08:00
|
|
|
{ "publicnotification", AUDIO_CHANNEL_PUBLICNOTIFICATION },
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
2011-11-15 23:50:19 -08:00
|
|
|
if (ParseImageAttribute(aAttribute, aValue, aResult)) {
|
2011-09-29 16:34:37 -07:00
|
|
|
return true;
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
2012-01-25 14:31:30 -08:00
|
|
|
if (aAttribute == nsGkAtoms::crossorigin) {
|
2012-03-10 08:13:51 -08:00
|
|
|
ParseCORSValue(aValue, aResult);
|
|
|
|
return true;
|
2012-01-25 14:31:30 -08:00
|
|
|
}
|
2011-11-15 23:50:19 -08:00
|
|
|
if (aAttribute == nsGkAtoms::preload) {
|
2011-09-29 16:34:37 -07:00
|
|
|
return aResult.ParseEnumValue(aValue, kPreloadTable, false);
|
2010-08-19 15:50:37 -07:00
|
|
|
}
|
2012-12-04 11:46:07 -08:00
|
|
|
|
|
|
|
if (aAttribute == nsGkAtoms::mozaudiochannel) {
|
|
|
|
bool parsed = aResult.ParseEnumValue(aValue, kMozAudioChannelAttributeTable, false,
|
|
|
|
&kMozAudioChannelAttributeTable[0]);
|
|
|
|
if (!parsed) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioChannelType audioChannelType = static_cast<AudioChannelType>(aResult.GetEnumValue());
|
|
|
|
|
|
|
|
if (audioChannelType != mAudioChannelType &&
|
|
|
|
!mDecoder &&
|
|
|
|
CheckAudioChannelPermissions(aValue)) {
|
|
|
|
mAudioChannelType = audioChannelType;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
|
|
|
aResult);
|
|
|
|
}
|
2008-10-19 00:39:21 -07:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
bool HTMLMediaElement::CheckAudioChannelPermissions(const nsAString& aString)
|
2012-12-04 11:46:07 -08:00
|
|
|
{
|
2013-04-25 17:53:25 -07:00
|
|
|
if (!UseAudioChannelService()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-12-04 11:46:07 -08:00
|
|
|
// Only normal channel doesn't need permission.
|
|
|
|
if (!aString.EqualsASCII("normal")) {
|
|
|
|
nsCOMPtr<nsIPermissionManager> permissionManager =
|
|
|
|
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
|
|
|
if (!permissionManager) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
|
|
|
|
permissionManager->TestExactPermissionFromPrincipal(NodePrincipal(),
|
|
|
|
nsCString(NS_LITERAL_CSTRING("audio-channel-") + NS_ConvertUTF16toUTF8(aString)).get(), &perm);
|
|
|
|
if (perm != nsIPermissionManager::ALLOW_ACTION) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-04-25 17:53:25 -07:00
|
|
|
|
2012-12-04 11:46:07 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::DoneCreatingElement()
|
2011-12-15 11:36:46 -08:00
|
|
|
{
|
2013-05-21 10:49:17 -07:00
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::muted)) {
|
|
|
|
mMuted |= MUTED_BY_CONTENT;
|
|
|
|
}
|
2011-12-15 11:36:46 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
bool HTMLMediaElement::IsHTMLFocusable(bool aWithMouse,
|
2013-03-19 05:25:19 -07:00
|
|
|
bool* aIsFocusable,
|
|
|
|
int32_t* aTabIndex)
|
2013-02-11 20:56:03 -08:00
|
|
|
{
|
|
|
|
if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aIsFocusable = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
int32_t HTMLMediaElement::TabIndexDefault()
|
2013-02-11 20:56:03 -08:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|
|
|
nsIAtom* aPrefix, const nsAString& aValue,
|
|
|
|
bool aNotify)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2009-11-05 23:32:52 -08:00
|
|
|
nsresult rv =
|
2008-07-09 01:22:20 -07:00
|
|
|
nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
|
2011-11-15 23:50:19 -08:00
|
|
|
aNotify);
|
2010-08-19 15:50:37 -07:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2010-09-02 17:03:03 -07:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
|
|
|
|
Load();
|
|
|
|
}
|
2009-05-17 19:00:44 -07:00
|
|
|
if (aNotify && aNameSpaceID == kNameSpaceID_None) {
|
2010-09-02 17:03:03 -07:00
|
|
|
if (aName == nsGkAtoms::autoplay) {
|
2009-05-17 19:00:44 -07:00
|
|
|
StopSuspendingAfterFirstFrame();
|
2013-03-20 04:11:48 -07:00
|
|
|
CheckAutoplayDataReady();
|
2009-10-01 07:10:13 -07:00
|
|
|
// This attribute can affect AddRemoveSelfReference
|
|
|
|
AddRemoveSelfReference();
|
2010-08-19 15:50:37 -07:00
|
|
|
UpdatePreloadAction();
|
|
|
|
} else if (aName == nsGkAtoms::preload) {
|
|
|
|
UpdatePreloadAction();
|
2009-05-17 19:00:44 -07:00
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
|
|
|
|
bool aNotify)
|
2009-10-01 07:10:13 -07:00
|
|
|
{
|
|
|
|
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttr, aNotify);
|
2010-08-19 15:50:37 -07:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2009-10-01 07:10:13 -07:00
|
|
|
if (aNotify && aNameSpaceID == kNameSpaceID_None) {
|
|
|
|
if (aAttr == nsGkAtoms::autoplay) {
|
|
|
|
// This attribute can affect AddRemoveSelfReference
|
|
|
|
AddRemoveSelfReference();
|
2010-08-19 15:50:37 -07:00
|
|
|
UpdatePreloadAction();
|
|
|
|
} else if (aAttr == nsGkAtoms::preload) {
|
|
|
|
UpdatePreloadAction();
|
2009-10-01 07:10:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|
|
|
nsIContent* aBindingParent,
|
|
|
|
bool aCompileEventHandlers)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2010-10-14 17:13:29 -07:00
|
|
|
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument,
|
|
|
|
aParent,
|
|
|
|
aBindingParent,
|
|
|
|
aCompileEventHandlers);
|
2010-02-24 11:14:14 -08:00
|
|
|
if (aDocument) {
|
|
|
|
mAutoplayEnabled =
|
2010-10-14 17:13:29 -07:00
|
|
|
IsAutoplayEnabled() && (!aDocument || !aDocument->IsStaticDocument()) &&
|
|
|
|
!IsEditable();
|
2010-08-19 15:50:37 -07:00
|
|
|
// The preload action depends on the value of the autoplay attribute.
|
|
|
|
// It's value may have changed, so update it.
|
|
|
|
UpdatePreloadAction();
|
2011-11-21 16:34:21 -08:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
2010-02-24 11:14:14 -08:00
|
|
|
}
|
2009-02-15 17:05:28 -08:00
|
|
|
|
2008-07-09 01:22:20 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::UnbindFromTree(bool aDeep,
|
|
|
|
bool aNullParent)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-07-09 10:30:18 -07:00
|
|
|
if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY)
|
2008-08-03 18:51:01 -07:00
|
|
|
Pause();
|
2008-07-09 01:22:20 -07:00
|
|
|
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
|
|
|
}
|
|
|
|
|
2010-06-08 16:31:27 -07:00
|
|
|
/* static */
|
2012-11-21 19:10:41 -08:00
|
|
|
CanPlayStatus
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::GetCanPlay(const nsAString& aType)
|
2008-12-16 18:11:07 -08:00
|
|
|
{
|
|
|
|
nsContentTypeParser parser(aType);
|
|
|
|
nsAutoString mimeType;
|
|
|
|
nsresult rv = parser.GetType(mimeType);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return CANPLAY_NO;
|
|
|
|
|
|
|
|
nsAutoString codecs;
|
|
|
|
rv = parser.GetParameter("codecs", codecs);
|
|
|
|
|
2012-11-22 10:49:37 -08:00
|
|
|
NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
|
|
|
|
return DecoderTraits::CanHandleMediaType(mimeTypeUTF8.get(),
|
|
|
|
NS_SUCCEEDED(rv),
|
|
|
|
codecs);
|
2008-12-16 18:11:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::CanPlayType(const nsAString& aType, nsAString& aResult)
|
2008-12-16 18:11:07 -08:00
|
|
|
{
|
|
|
|
switch (GetCanPlay(aType)) {
|
2011-11-15 23:50:19 -08:00
|
|
|
case CANPLAY_NO:
|
|
|
|
aResult.Truncate();
|
|
|
|
break;
|
|
|
|
case CANPLAY_YES:
|
|
|
|
aResult.AssignLiteral("probably");
|
|
|
|
break;
|
2008-12-16 18:11:07 -08:00
|
|
|
default:
|
2011-11-15 23:50:19 -08:00
|
|
|
case CANPLAY_MAYBE:
|
|
|
|
aResult.AssignLiteral("maybe");
|
|
|
|
break;
|
2008-12-16 18:11:07 -08:00
|
|
|
}
|
2013-02-26 12:27:43 -08:00
|
|
|
|
|
|
|
LOG(PR_LOG_DEBUG, ("%p CanPlayType(%s) = \"%s\"", this,
|
|
|
|
NS_ConvertUTF16toUTF8(aType).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(aResult).get()));
|
|
|
|
|
2008-12-16 18:11:07 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal)
|
2009-09-14 19:30:44 -07:00
|
|
|
{
|
2011-11-24 18:06:22 -08:00
|
|
|
NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set");
|
2012-07-30 07:20:58 -07:00
|
|
|
NS_ASSERTION(mDecoder == nullptr, "Shouldn't have a decoder");
|
2011-11-24 18:06:22 -08:00
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
MediaResource* originalResource = aOriginal->GetResource();
|
|
|
|
if (!originalResource)
|
2009-09-14 19:30:44 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
2012-11-14 11:46:40 -08:00
|
|
|
nsRefPtr<MediaDecoder> decoder = aOriginal->Clone();
|
2009-10-01 07:10:13 -07:00
|
|
|
if (!decoder)
|
2009-09-14 19:30:44 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2009-11-05 23:32:52 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
|
2009-09-29 14:32:44 -07:00
|
|
|
|
2009-10-01 07:10:13 -07:00
|
|
|
if (!decoder->Init(this)) {
|
2012-01-19 10:30:29 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p Failed to init cloned decoder %p", this, decoder.get()));
|
2009-09-14 19:30:44 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2011-01-16 19:03:00 -08:00
|
|
|
double duration = aOriginal->GetDuration();
|
2009-10-14 18:28:59 -07:00
|
|
|
if (duration >= 0) {
|
2011-04-13 15:12:23 -07:00
|
|
|
decoder->SetDuration(duration);
|
2012-11-30 05:17:54 -08:00
|
|
|
decoder->SetTransportSeekable(aOriginal->IsTransportSeekable());
|
|
|
|
decoder->SetMediaSeekable(aOriginal->IsMediaSeekable());
|
2009-10-14 18:28:59 -07:00
|
|
|
}
|
|
|
|
|
2013-05-02 15:59:18 -07:00
|
|
|
nsRefPtr<MediaResource> resource = originalResource->CloneData(decoder);
|
2012-02-14 20:35:01 -08:00
|
|
|
if (!resource) {
|
2012-01-19 10:30:29 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p Failed to cloned stream for decoder %p", this, decoder.get()));
|
2009-09-14 19:30:44 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
return FinishDecoderSetup(decoder, resource, nullptr, aOriginal);
|
2009-09-14 19:30:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel* aChannel,
|
|
|
|
nsIStreamListener** aListener)
|
2008-10-29 22:20:08 -07:00
|
|
|
{
|
2011-11-24 18:06:22 -08:00
|
|
|
NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set");
|
2012-07-30 07:20:58 -07:00
|
|
|
NS_ASSERTION(mDecoder == nullptr, "Shouldn't have a decoder");
|
2011-11-24 18:06:22 -08:00
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString mimeType;
|
2008-10-29 22:20:08 -07:00
|
|
|
|
2013-02-14 17:10:58 -08:00
|
|
|
aChannel->GetContentType(mimeType);
|
|
|
|
NS_ASSERTION(!mimeType.IsEmpty(), "We should have the Content-Type.");
|
2012-09-04 17:49:46 -07:00
|
|
|
|
2013-03-05 06:56:34 -08:00
|
|
|
nsRefPtr<MediaDecoder> decoder = DecoderTraits::CreateDecoder(mimeType, this);
|
2009-10-01 07:10:13 -07:00
|
|
|
if (!decoder) {
|
2011-12-21 15:33:39 -08:00
|
|
|
nsAutoString src;
|
|
|
|
GetCurrentSrc(src);
|
2013-02-14 17:10:58 -08:00
|
|
|
NS_ConvertUTF8toUTF16 mimeUTF16(mimeType);
|
2011-12-21 15:33:39 -08:00
|
|
|
const PRUnichar* params[] = { mimeUTF16.get(), src.get() };
|
|
|
|
ReportLoadError("MediaLoadUnsupportedMimeType", params, ArrayLength(params));
|
2008-10-29 22:20:08 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
2009-10-01 07:10:13 -07:00
|
|
|
}
|
2008-10-29 22:20:08 -07:00
|
|
|
|
2013-02-14 17:10:58 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p Created decoder %p for type %s", this, decoder.get(), mimeType.get()));
|
2009-09-29 14:32:44 -07:00
|
|
|
|
2013-05-02 15:59:18 -07:00
|
|
|
nsRefPtr<MediaResource> resource = MediaResource::Create(decoder, aChannel);
|
2012-02-14 20:35:01 -08:00
|
|
|
if (!resource)
|
2009-09-14 19:30:43 -07:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
2012-04-29 20:12:28 -07:00
|
|
|
// stream successfully created, the stream now owns the channel.
|
2012-07-30 07:20:58 -07:00
|
|
|
mChannel = nullptr;
|
2012-04-29 20:12:28 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
return FinishDecoderSetup(decoder, resource, aListener, nullptr);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
|
|
|
MediaResource* aStream,
|
2013-03-19 05:25:19 -07:00
|
|
|
nsIStreamListener** aListener,
|
2013-03-19 05:23:54 -07:00
|
|
|
MediaDecoder* aCloneDonor)
|
2012-04-29 20:12:28 -07:00
|
|
|
{
|
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
|
|
|
|
|
|
|
|
// Force a same-origin check before allowing events for this media resource.
|
|
|
|
mMediaSecurityVerified = false;
|
|
|
|
|
|
|
|
// The new stream has not been suspended by us.
|
2012-12-11 17:58:07 -08:00
|
|
|
mPausedForInactiveDocumentOrChannel = false;
|
|
|
|
mEventDeliveryPaused = false;
|
2013-01-13 14:46:50 -08:00
|
|
|
mPendingEvents.Clear();
|
2013-07-24 02:55:23 -07:00
|
|
|
// Set mDecoder now so if methods like GetCurrentSrc get called between
|
|
|
|
// here and Load(), they work.
|
|
|
|
mDecoder = aDecoder;
|
2012-04-29 20:12:28 -07:00
|
|
|
|
2013-07-24 02:55:23 -07:00
|
|
|
// Tell aDecoder about its MediaResource now so things like principals are
|
|
|
|
// available immediately.
|
|
|
|
aDecoder->SetResource(aStream);
|
2012-11-15 19:25:26 -08:00
|
|
|
aDecoder->SetAudioChannelType(mAudioChannelType);
|
2012-04-29 20:12:42 -07:00
|
|
|
aDecoder->SetAudioCaptured(mAudioCaptured);
|
2012-04-29 20:12:28 -07:00
|
|
|
aDecoder->SetVolume(mMuted ? 0.0 : mVolume);
|
2013-02-26 00:52:23 -08:00
|
|
|
aDecoder->SetPreservesPitch(mPreservesPitch);
|
|
|
|
aDecoder->SetPlaybackRate(mPlaybackRate);
|
2013-07-24 02:55:23 -07:00
|
|
|
// Update decoder principal before we start decoding, since it
|
|
|
|
// can affect how we feed data to MediaStreams
|
|
|
|
NotifyDecoderPrincipalChanged();
|
2013-02-26 00:52:23 -08:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
|
2012-04-29 20:12:42 -07:00
|
|
|
OutputMediaStream* ms = &mOutputStreams[i];
|
2012-07-31 05:17:22 -07:00
|
|
|
aDecoder->AddOutputStream(ms->mStream->GetStream()->AsProcessedStream(),
|
2012-04-29 20:12:42 -07:00
|
|
|
ms->mFinishWhenEnded);
|
|
|
|
}
|
2012-04-29 20:12:28 -07:00
|
|
|
|
2013-07-24 02:55:23 -07:00
|
|
|
nsresult rv = aDecoder->Load(aListener, aCloneDonor);
|
2009-09-14 19:30:44 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
2013-07-24 02:55:23 -07:00
|
|
|
mDecoder = nullptr;
|
2012-04-29 20:12:28 -07:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p Failed to load for decoder %p", this, aDecoder));
|
2009-02-10 17:23:19 -08:00
|
|
|
return rv;
|
2009-09-14 19:30:44 -07:00
|
|
|
}
|
2009-02-10 17:23:19 -08:00
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
// Decoder successfully created, the decoder now owns the MediaResource
|
2009-09-14 19:30:43 -07:00
|
|
|
// which owns the channel.
|
2012-07-30 07:20:58 -07:00
|
|
|
mChannel = nullptr;
|
2009-04-09 18:28:24 -07:00
|
|
|
|
2011-11-24 18:06:22 -08:00
|
|
|
AddMediaElementToURITable();
|
2010-09-02 17:03:03 -07:00
|
|
|
|
2012-04-29 20:12:28 -07:00
|
|
|
// We may want to suspend the new stream now.
|
2009-10-01 07:10:13 -07:00
|
|
|
// This will also do an AddRemoveSelfReference.
|
|
|
|
NotifyOwnerDocumentActivityChanged();
|
|
|
|
|
2009-02-10 17:23:19 -08:00
|
|
|
if (!mPaused) {
|
2011-09-29 16:34:37 -07:00
|
|
|
SetPlayedOrSeeked(true);
|
2012-12-11 17:58:07 -08:00
|
|
|
if (!mPausedForInactiveDocumentOrChannel) {
|
2009-10-01 07:10:13 -07:00
|
|
|
rv = mDecoder->Play();
|
|
|
|
}
|
2009-02-10 17:23:19 -08:00
|
|
|
}
|
|
|
|
|
2011-11-21 16:34:21 -08:00
|
|
|
if (OwnerDoc()->HasAudioAvailableListeners()) {
|
|
|
|
NotifyAudioAvailableListener();
|
|
|
|
}
|
|
|
|
|
2012-01-10 14:58:43 -08:00
|
|
|
if (NS_FAILED(rv)) {
|
2012-04-29 20:13:09 -07:00
|
|
|
ShutdownDecoder();
|
2012-01-10 14:58:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv) == (MediaElementTableCount(this, mLoadingSrc) == 1),
|
|
|
|
"Media element should have single table entry if decode initialized");
|
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
mBegun = true;
|
2009-02-10 17:23:19 -08:00
|
|
|
return rv;
|
2008-10-29 22:20:08 -07:00
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
class HTMLMediaElement::StreamListener : public MediaStreamListener {
|
2012-04-29 20:12:28 -07:00
|
|
|
public:
|
2013-03-19 05:23:54 -07:00
|
|
|
StreamListener(HTMLMediaElement* aElement) :
|
2012-04-29 20:12:28 -07:00
|
|
|
mElement(aElement),
|
2012-09-19 17:47:50 -07:00
|
|
|
mHaveCurrentData(false),
|
|
|
|
mBlocked(false),
|
2013-03-19 05:23:54 -07:00
|
|
|
mMutex("HTMLMediaElement::StreamListener"),
|
2013-03-20 04:19:39 -07:00
|
|
|
mPendingNotifyOutput(false)
|
2012-04-29 20:12:28 -07:00
|
|
|
{}
|
2012-07-30 07:20:58 -07:00
|
|
|
void Forget() { mElement = nullptr; }
|
2012-04-29 20:12:28 -07:00
|
|
|
|
|
|
|
// Main thread
|
|
|
|
void DoNotifyFinished()
|
|
|
|
{
|
|
|
|
if (mElement) {
|
2013-08-14 21:23:52 -07:00
|
|
|
nsRefPtr<HTMLMediaElement> deathGrip = mElement;
|
2012-04-29 20:12:28 -07:00
|
|
|
mElement->PlaybackEnded();
|
|
|
|
}
|
|
|
|
}
|
2012-09-19 17:47:50 -07:00
|
|
|
void UpdateReadyStateForData()
|
2012-04-29 20:12:28 -07:00
|
|
|
{
|
2012-09-19 17:47:50 -07:00
|
|
|
if (mElement && mHaveCurrentData) {
|
2013-08-14 21:23:52 -07:00
|
|
|
nsRefPtr<HTMLMediaElement> deathGrip = mElement;
|
2012-09-19 17:47:50 -07:00
|
|
|
mElement->UpdateReadyStateForData(
|
2012-11-14 11:45:31 -08:00
|
|
|
mBlocked ? MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING :
|
|
|
|
MediaDecoderOwner::NEXT_FRAME_AVAILABLE);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
}
|
2012-09-19 17:47:50 -07:00
|
|
|
void DoNotifyBlocked()
|
|
|
|
{
|
|
|
|
mBlocked = true;
|
|
|
|
UpdateReadyStateForData();
|
|
|
|
}
|
2012-04-29 20:12:28 -07:00
|
|
|
void DoNotifyUnblocked()
|
|
|
|
{
|
2012-09-19 17:47:50 -07:00
|
|
|
mBlocked = false;
|
|
|
|
UpdateReadyStateForData();
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
void DoNotifyOutput()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
mPendingNotifyOutput = false;
|
|
|
|
}
|
2012-09-19 17:47:50 -07:00
|
|
|
if (mElement && mHaveCurrentData) {
|
2013-08-14 21:23:52 -07:00
|
|
|
nsRefPtr<HTMLMediaElement> deathGrip = mElement;
|
2012-04-29 20:12:28 -07:00
|
|
|
mElement->FireTimeUpdate(true);
|
|
|
|
}
|
|
|
|
}
|
2012-09-19 17:47:50 -07:00
|
|
|
void DoNotifyHaveCurrentData()
|
|
|
|
{
|
|
|
|
mHaveCurrentData = true;
|
|
|
|
if (mElement) {
|
2013-08-14 21:23:52 -07:00
|
|
|
nsRefPtr<HTMLMediaElement> deathGrip = mElement;
|
2012-09-19 17:47:50 -07:00
|
|
|
mElement->FirstFrameLoaded(false);
|
|
|
|
}
|
|
|
|
UpdateReadyStateForData();
|
|
|
|
DoNotifyOutput();
|
|
|
|
}
|
2012-04-29 20:12:28 -07:00
|
|
|
|
|
|
|
// These notifications run on the media graph thread so we need to
|
|
|
|
// dispatch events to the main thread.
|
|
|
|
virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRunnable> event;
|
|
|
|
if (aBlocked == BLOCKED) {
|
|
|
|
event = NS_NewRunnableMethod(this, &StreamListener::DoNotifyBlocked);
|
|
|
|
} else {
|
|
|
|
event = NS_NewRunnableMethod(this, &StreamListener::DoNotifyUnblocked);
|
|
|
|
}
|
2013-02-04 02:04:24 -08:00
|
|
|
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
virtual void NotifyFinished(MediaStreamGraph* aGraph)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
NS_NewRunnableMethod(this, &StreamListener::DoNotifyFinished);
|
2013-02-04 02:04:24 -08:00
|
|
|
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-03-20 04:19:39 -07:00
|
|
|
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph)
|
2012-09-19 17:47:50 -07:00
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
2013-03-20 04:19:39 -07:00
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
NS_NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData);
|
|
|
|
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
2012-09-19 17:47:50 -07:00
|
|
|
}
|
2012-04-29 20:12:28 -07:00
|
|
|
virtual void NotifyOutput(MediaStreamGraph* aGraph)
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
if (mPendingNotifyOutput)
|
|
|
|
return;
|
|
|
|
mPendingNotifyOutput = true;
|
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
NS_NewRunnableMethod(this, &StreamListener::DoNotifyOutput);
|
2013-02-04 02:04:24 -08:00
|
|
|
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2012-09-19 17:47:50 -07:00
|
|
|
// These fields may only be accessed on the main thread
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement* mElement;
|
2012-09-19 17:47:50 -07:00
|
|
|
bool mHaveCurrentData;
|
|
|
|
bool mBlocked;
|
2012-04-29 20:12:28 -07:00
|
|
|
|
2012-09-19 17:47:50 -07:00
|
|
|
// mMutex protects the fields below; they can be accessed on any thread
|
2012-04-29 20:12:28 -07:00
|
|
|
Mutex mMutex;
|
|
|
|
bool mPendingNotifyOutput;
|
|
|
|
};
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
|
2012-04-29 20:12:28 -07:00
|
|
|
{
|
2012-08-19 21:52:59 -07:00
|
|
|
NS_ASSERTION(!mSrcStream && !mSrcStreamListener, "Should have been ended already");
|
2012-04-29 20:12:28 -07:00
|
|
|
|
2012-09-24 20:25:43 -07:00
|
|
|
mSrcStream = aStream;
|
2012-04-29 20:12:42 -07:00
|
|
|
// XXX if we ever support capturing the output of a media element which is
|
|
|
|
// playing a stream, we'll need to add a CombineWithPrincipal call here.
|
2012-08-19 21:52:59 -07:00
|
|
|
mSrcStreamListener = new StreamListener(this);
|
|
|
|
GetSrcMediaStream()->AddListener(mSrcStreamListener);
|
2012-04-29 20:12:28 -07:00
|
|
|
if (mPaused) {
|
2012-08-19 21:52:59 -07:00
|
|
|
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2012-12-11 17:58:07 -08:00
|
|
|
if (mPausedForInactiveDocumentOrChannel) {
|
2012-08-19 21:52:59 -07:00
|
|
|
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
ChangeDelayLoadStatus(false);
|
2012-08-19 21:52:59 -07:00
|
|
|
GetSrcMediaStream()->AddAudioOutput(this);
|
|
|
|
GetSrcMediaStream()->SetAudioOutputVolume(this, float(mMuted ? 0.0 : mVolume));
|
2012-04-29 20:12:28 -07:00
|
|
|
VideoFrameContainer* container = GetVideoFrameContainer();
|
|
|
|
if (container) {
|
2012-08-19 21:52:59 -07:00
|
|
|
GetSrcMediaStream()->AddVideoOutput(container);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-08-19 15:30:15 -07:00
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
|
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
|
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
|
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
|
2012-09-19 17:47:50 -07:00
|
|
|
AddRemoveSelfReference();
|
|
|
|
// FirstFrameLoaded(false) will be called when the stream has current data,
|
|
|
|
// to complete the setup by entering the HAVE_CURRENT_DATA state.
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::EndSrcMediaStreamPlayback()
|
2012-04-29 20:12:28 -07:00
|
|
|
{
|
2013-05-01 04:24:16 -07:00
|
|
|
MediaStream* stream = GetSrcMediaStream();
|
|
|
|
if (stream) {
|
|
|
|
stream->RemoveListener(mSrcStreamListener);
|
|
|
|
}
|
2012-04-29 20:12:28 -07:00
|
|
|
// Kill its reference to this element
|
2012-08-19 21:52:59 -07:00
|
|
|
mSrcStreamListener->Forget();
|
2012-08-26 16:33:56 -07:00
|
|
|
mSrcStreamListener = nullptr;
|
2013-05-01 04:24:16 -07:00
|
|
|
if (stream) {
|
|
|
|
stream->RemoveAudioOutput(this);
|
|
|
|
}
|
2012-04-29 20:12:28 -07:00
|
|
|
VideoFrameContainer* container = GetVideoFrameContainer();
|
|
|
|
if (container) {
|
2013-05-01 04:24:16 -07:00
|
|
|
if (stream) {
|
|
|
|
stream->RemoveVideoOutput(container);
|
|
|
|
}
|
2012-10-19 17:18:31 -07:00
|
|
|
container->ClearCurrentFrame();
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-05-01 04:24:16 -07:00
|
|
|
if (mPaused && stream) {
|
|
|
|
stream->ChangeExplicitBlockerCount(-1);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2013-05-01 04:24:16 -07:00
|
|
|
if (mPausedForInactiveDocumentOrChannel && stream) {
|
|
|
|
stream->ChangeExplicitBlockerCount(-1);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2012-08-19 21:52:59 -07:00
|
|
|
mSrcStream = nullptr;
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::ProcessMediaFragmentURI()
|
2011-08-24 16:42:23 -07:00
|
|
|
{
|
2012-12-20 17:04:50 -08:00
|
|
|
nsMediaFragmentURIParser parser(mLoadingSrc);
|
|
|
|
|
|
|
|
if (mDecoder && parser.HasEndTime()) {
|
|
|
|
mFragmentEnd = parser.GetEndTime();
|
2011-08-24 16:42:23 -07:00
|
|
|
}
|
2012-12-20 17:04:50 -08:00
|
|
|
|
|
|
|
if (parser.HasStartTime()) {
|
|
|
|
SetCurrentTime(parser.GetStartTime());
|
|
|
|
mFragmentStart = parser.GetStartTime();
|
2011-08-24 16:42:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::MetadataLoaded(int aChannels,
|
|
|
|
int aRate,
|
|
|
|
bool aHasAudio,
|
|
|
|
bool aHasVideo,
|
|
|
|
const MetadataTags* aTags)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2010-08-25 06:10:00 -07:00
|
|
|
mChannels = aChannels;
|
|
|
|
mRate = aRate;
|
2012-04-28 08:01:10 -07:00
|
|
|
mHasAudio = aHasAudio;
|
2012-07-30 17:14:29 -07:00
|
|
|
mTags = aTags;
|
2008-12-14 19:38:16 -08:00
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
|
2012-11-30 05:17:54 -08:00
|
|
|
if (mDecoder && mDecoder->IsTransportSeekable() && mDecoder->IsMediaSeekable()) {
|
2011-08-24 16:42:23 -07:00
|
|
|
ProcessMediaFragmentURI();
|
2012-11-19 07:11:21 -08:00
|
|
|
mDecoder->SetFragmentEndTime(mFragmentEnd);
|
2011-08-24 16:42:23 -07:00
|
|
|
}
|
2012-12-27 07:21:30 -08:00
|
|
|
|
|
|
|
// If this element had a video track, but consists only of an audio track now,
|
|
|
|
// delete the VideoFrameContainer. This happens when the src is changed to an
|
|
|
|
// audio only file.
|
|
|
|
if (!aHasVideo) {
|
|
|
|
mVideoFrameContainer = nullptr;
|
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::FirstFrameLoaded(bool aResourceFullyLoaded)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2013-08-19 15:30:15 -07:00
|
|
|
ChangeReadyState(aResourceFullyLoaded ?
|
|
|
|
nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA :
|
|
|
|
nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(false);
|
2009-05-17 19:00:44 -07:00
|
|
|
|
|
|
|
NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
|
|
|
|
|
|
|
|
if (mDecoder && mAllowSuspendAfterFirstFrame && mPaused &&
|
2009-05-18 16:06:10 -07:00
|
|
|
!aResourceFullyLoaded &&
|
2009-05-17 19:00:44 -07:00
|
|
|
!HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
|
2013-03-19 05:23:54 -07:00
|
|
|
mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
|
2011-09-29 16:34:37 -07:00
|
|
|
mSuspendedAfterFirstFrame = true;
|
2009-05-17 19:00:44 -07:00
|
|
|
mDecoder->Suspend();
|
2012-05-27 15:40:06 -07:00
|
|
|
} else if (mLoadedFirstFrame &&
|
2012-11-15 19:25:26 -08:00
|
|
|
mDownloadSuspendedByCache &&
|
2012-05-27 15:40:06 -07:00
|
|
|
mDecoder &&
|
|
|
|
!mDecoder->IsEnded()) {
|
|
|
|
// We've already loaded the first frame, and the decoder has signalled
|
|
|
|
// that the download has been suspended by the media cache. So move
|
|
|
|
// readyState into HAVE_ENOUGH_DATA, in case there's script waiting
|
|
|
|
// for a "canplaythrough" event; without this forced transition, we will
|
|
|
|
// never fire the "canplaythrough" event if the media cache is so small
|
|
|
|
// that the download was suspended before the first frame was loaded.
|
|
|
|
// Don't force this transition if the decoder is in ended state; the
|
|
|
|
// readyState should remain at HAVE_CURRENT_DATA in this case.
|
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
|
|
|
|
return;
|
2009-05-17 19:00:44 -07:00
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::ResourceLoaded()
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2012-09-19 17:47:50 -07:00
|
|
|
NS_ASSERTION(!mSrcStream, "Don't call this for streams");
|
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
mBegun = false;
|
2009-10-09 04:48:55 -07:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
|
2009-10-01 07:10:13 -07:00
|
|
|
AddRemoveSelfReference();
|
2011-05-08 14:10:44 -07:00
|
|
|
if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA) {
|
2012-05-24 03:37:14 -07:00
|
|
|
// MediaStream sources are put into HAVE_CURRENT_DATA state here on setup. If the
|
|
|
|
// stream is not blocked, we will receive a notification that will put it
|
|
|
|
// into HAVE_ENOUGH_DATA state.
|
2012-08-19 21:52:59 -07:00
|
|
|
ChangeReadyState(mSrcStream ? nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA
|
2012-05-24 03:37:14 -07:00
|
|
|
: nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
|
2011-05-08 14:10:44 -07:00
|
|
|
}
|
2010-09-02 17:03:03 -07:00
|
|
|
// Ensure a progress event is dispatched at the end of download.
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
|
2010-09-02 17:03:03 -07:00
|
|
|
// The download has stopped.
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NetworkError()
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2010-09-02 17:03:03 -07:00
|
|
|
Error(nsIDOMMediaError::MEDIA_ERR_NETWORK);
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::DecodeError()
|
2009-09-21 17:08:13 -07:00
|
|
|
{
|
2011-12-21 15:33:39 -08:00
|
|
|
nsAutoString src;
|
|
|
|
GetCurrentSrc(src);
|
|
|
|
const PRUnichar* params[] = { src.get() };
|
|
|
|
ReportLoadError("MediaLoadDecodeError", params, ArrayLength(params));
|
|
|
|
|
2011-07-11 20:39:34 -07:00
|
|
|
if (mDecoder) {
|
2012-04-29 20:13:09 -07:00
|
|
|
ShutdownDecoder();
|
2011-07-11 20:39:34 -07:00
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
mLoadingSrc = nullptr;
|
2010-10-16 12:57:50 -07:00
|
|
|
if (mIsLoadingFromSourceChildren) {
|
2012-07-30 07:20:58 -07:00
|
|
|
mError = nullptr;
|
2011-04-28 07:08:03 -07:00
|
|
|
if (mSourceLoadCandidate) {
|
|
|
|
DispatchAsyncSourceError(mSourceLoadCandidate);
|
|
|
|
QueueLoadFromSourceTask();
|
|
|
|
} else {
|
|
|
|
NS_WARNING("Should know the source we were loading from!");
|
|
|
|
}
|
2010-10-06 15:58:36 -07:00
|
|
|
} else {
|
|
|
|
Error(nsIDOMMediaError::MEDIA_ERR_DECODE);
|
|
|
|
}
|
2010-09-02 17:03:03 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::LoadAborted()
|
2010-09-02 17:03:03 -07:00
|
|
|
{
|
|
|
|
Error(nsIDOMMediaError::MEDIA_ERR_ABORTED);
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::Error(uint16_t aErrorCode)
|
2010-09-02 17:03:03 -07:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aErrorCode == nsIDOMMediaError::MEDIA_ERR_DECODE ||
|
|
|
|
aErrorCode == nsIDOMMediaError::MEDIA_ERR_NETWORK ||
|
|
|
|
aErrorCode == nsIDOMMediaError::MEDIA_ERR_ABORTED,
|
|
|
|
"Only use nsIDOMMediaError codes!");
|
2013-02-14 07:59:21 -08:00
|
|
|
mError = new MediaError(this, aErrorCode);
|
2011-09-29 16:34:37 -07:00
|
|
|
mBegun = false;
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("error"));
|
2010-09-02 17:03:03 -07:00
|
|
|
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
|
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
|
2010-09-02 17:03:03 -07:00
|
|
|
} else {
|
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
|
|
|
|
}
|
2009-10-01 07:10:13 -07:00
|
|
|
AddRemoveSelfReference();
|
2011-09-29 16:34:37 -07:00
|
|
|
ChangeDelayLoadStatus(false);
|
2009-09-21 17:08:13 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::PlaybackEnded()
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2012-04-29 20:12:28 -07:00
|
|
|
// We changed state which can affect AddRemoveSelfReference
|
2009-10-01 07:10:13 -07:00
|
|
|
AddRemoveSelfReference();
|
|
|
|
|
2012-04-29 20:12:28 -07:00
|
|
|
NS_ASSERTION(!mDecoder || mDecoder->IsEnded(),
|
|
|
|
"Decoder fired ended, but not in ended state");
|
2012-07-31 05:17:22 -07:00
|
|
|
|
|
|
|
// Discard all output streams that have finished now.
|
|
|
|
for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
|
|
|
|
if (mOutputStreams[i].mFinishWhenEnded) {
|
|
|
|
mOutputStreams.RemoveElementAt(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream || (mDecoder && mDecoder->IsInfinite())) {
|
2012-02-14 20:35:01 -08:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p, got duration by reaching the end of the resource", this));
|
2011-08-01 11:11:20 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
|
|
|
}
|
|
|
|
|
2011-11-20 14:59:01 -08:00
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::loop)) {
|
|
|
|
SetCurrentTime(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-06 10:27:55 -07:00
|
|
|
Pause();
|
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
FireTimeUpdate(false);
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SeekStarted()
|
2008-10-19 00:39:21 -07:00
|
|
|
{
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
|
2012-05-27 15:40:06 -07:00
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
|
2011-09-29 16:34:37 -07:00
|
|
|
FireTimeUpdate(false);
|
2008-10-19 00:39:21 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SeekCompleted()
|
2008-10-19 00:39:21 -07:00
|
|
|
{
|
2011-09-29 16:34:37 -07:00
|
|
|
mPlayingBeforeSeek = false;
|
|
|
|
SetPlayedOrSeeked(true);
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("seeked"));
|
2009-10-01 07:10:13 -07:00
|
|
|
// We changed whether we're seeking so we need to AddRemoveSelfReference
|
|
|
|
AddRemoveSelfReference();
|
2013-06-14 13:10:36 -07:00
|
|
|
mTextTracks->DidSeek();
|
2008-10-19 00:39:21 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
|
2012-05-27 15:40:06 -07:00
|
|
|
{
|
|
|
|
mDownloadSuspendedByCache = aIsSuspended;
|
2013-03-20 04:11:48 -07:00
|
|
|
// If this is an autoplay element, we may need to kick off its autoplaying
|
|
|
|
// now so we consume data and hopefully free up cache space.
|
|
|
|
CheckAutoplayDataReady();
|
2012-05-27 15:40:06 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::DownloadSuspended()
|
2009-05-17 19:03:37 -07:00
|
|
|
{
|
2011-07-23 14:45:37 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
|
2009-05-17 19:03:37 -07:00
|
|
|
if (mBegun) {
|
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
|
2009-10-01 07:10:13 -07:00
|
|
|
AddRemoveSelfReference();
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
|
2009-05-17 19:03:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::DownloadResumed(bool aForceNetworkLoading)
|
2009-05-17 19:03:37 -07:00
|
|
|
{
|
2012-05-30 19:30:23 -07:00
|
|
|
if (mBegun || aForceNetworkLoading) {
|
2009-05-17 19:03:37 -07:00
|
|
|
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
|
2009-10-01 07:10:13 -07:00
|
|
|
AddRemoveSelfReference();
|
2009-05-17 19:03:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::DownloadStalled()
|
2009-05-17 19:03:37 -07:00
|
|
|
{
|
|
|
|
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
|
2009-05-17 19:03:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
bool HTMLMediaElement::ShouldCheckAllowOrigin()
|
2009-01-24 03:00:17 -08:00
|
|
|
{
|
2012-01-25 14:31:30 -08:00
|
|
|
return mCORSMode != CORS_NONE;
|
2009-01-24 03:00:17 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
|
2009-02-05 00:02:21 -08:00
|
|
|
{
|
|
|
|
if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
|
2009-03-31 17:52:56 -07:00
|
|
|
// aNextFrame might have a next frame because the decoder can advance
|
|
|
|
// on its own thread before ResourceLoaded or MetadataLoaded gets
|
|
|
|
// a chance to run.
|
|
|
|
// The arrival of more data can't change us out of this readyState.
|
2009-02-05 00:02:21 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-05-27 15:40:06 -07:00
|
|
|
if (mReadyState > nsIDOMHTMLMediaElement::HAVE_METADATA &&
|
|
|
|
mDownloadSuspendedByCache &&
|
|
|
|
mDecoder &&
|
|
|
|
!mDecoder->IsEnded()) {
|
|
|
|
// The decoder has signalled that the download has been suspended by the
|
|
|
|
// media cache. So move readyState into HAVE_ENOUGH_DATA, in case there's
|
|
|
|
// script waiting for a "canplaythrough" event; without this forced
|
|
|
|
// transition, we will never fire the "canplaythrough" event if the
|
|
|
|
// media cache is too small, and scripts are bound to fail. Don't force
|
|
|
|
// this transition if the decoder is in ended state; the readyState
|
|
|
|
// should remain at HAVE_CURRENT_DATA in this case.
|
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-11-14 11:45:31 -08:00
|
|
|
if (aNextFrame != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
|
2009-02-05 00:02:21 -08:00
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
|
2012-11-14 11:45:31 -08:00
|
|
|
if (!mWaitingFired && aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
|
2011-09-29 16:34:37 -07:00
|
|
|
FireTimeUpdate(false);
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
|
2011-09-29 16:34:37 -07:00
|
|
|
mWaitingFired = true;
|
2009-02-10 17:43:45 -08:00
|
|
|
}
|
2009-02-05 00:02:21 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
2012-04-29 20:12:28 -07:00
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-18 22:14:20 -07:00
|
|
|
// Now see if we should set HAVE_ENOUGH_DATA.
|
|
|
|
// If it's something we don't know the size of, then we can't
|
|
|
|
// make a real estimate, so we go straight to HAVE_ENOUGH_DATA once
|
|
|
|
// we've downloaded enough data that our download rate is considered
|
|
|
|
// reliable. We have to move to HAVE_ENOUGH_DATA at some point or
|
2010-07-22 15:48:32 -07:00
|
|
|
// autoplay elements for live streams will never play. Otherwise we
|
|
|
|
// move to HAVE_ENOUGH_DATA if we can play through the entire media
|
|
|
|
// without stopping to buffer.
|
2012-11-14 11:46:40 -08:00
|
|
|
MediaDecoder::Statistics stats = mDecoder->GetStatistics();
|
2013-04-24 02:19:02 -07:00
|
|
|
if (stats.mTotalBytes < 0 ? stats.mDownloadRateReliable
|
|
|
|
: stats.mTotalBytes == stats.mDownloadPosition ||
|
|
|
|
mDecoder->CanPlayThrough())
|
2010-07-22 15:48:32 -07:00
|
|
|
{
|
2009-02-05 00:02:21 -08:00
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA);
|
|
|
|
}
|
|
|
|
|
2009-09-29 14:32:44 -07:00
|
|
|
#ifdef PR_LOGGING
|
2009-03-18 16:59:34 -07:00
|
|
|
static const char* gReadyStateToString[] = {
|
|
|
|
"HAVE_NOTHING",
|
|
|
|
"HAVE_METADATA",
|
|
|
|
"HAVE_CURRENT_DATA",
|
|
|
|
"HAVE_FUTURE_DATA",
|
|
|
|
"HAVE_ENOUGH_DATA"
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2009-02-05 00:02:21 -08:00
|
|
|
nsMediaReadyState oldState = mReadyState;
|
2009-03-18 16:59:34 -07:00
|
|
|
mReadyState = aState;
|
|
|
|
|
2009-11-05 23:32:52 -08:00
|
|
|
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY ||
|
2009-03-18 16:59:34 -07:00
|
|
|
oldState == mReadyState) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-29 14:32:44 -07:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p Ready state changed to %s", this, gReadyStateToString[aState]));
|
2009-02-05 00:02:21 -08:00
|
|
|
|
2012-12-11 17:58:07 -08:00
|
|
|
UpdateAudioChannelPlayingState();
|
|
|
|
|
2008-12-14 19:38:16 -08:00
|
|
|
// Handle raising of "waiting" event during seek (see 4.8.10.9)
|
2009-03-18 16:59:34 -07:00
|
|
|
if (mPlayingBeforeSeek &&
|
|
|
|
oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
|
2009-02-05 00:02:21 -08:00
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
|
2009-03-18 16:59:34 -07:00
|
|
|
if (oldState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
|
2009-11-05 23:32:52 -08:00
|
|
|
mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
|
2009-03-18 16:59:34 -07:00
|
|
|
!mLoadedFirstFrame)
|
|
|
|
{
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("loadeddata"));
|
2011-09-29 16:34:37 -07:00
|
|
|
mLoadedFirstFrame = true;
|
2009-03-18 16:59:34 -07:00
|
|
|
}
|
2009-02-05 02:51:24 -08:00
|
|
|
|
2009-03-18 16:59:34 -07:00
|
|
|
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
|
2011-09-29 16:34:37 -07:00
|
|
|
mWaitingFired = false;
|
2009-03-18 16:59:34 -07:00
|
|
|
}
|
|
|
|
|
2009-11-05 23:32:52 -08:00
|
|
|
if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
|
2009-03-18 16:59:34 -07:00
|
|
|
mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("canplay"));
|
2009-03-18 16:59:34 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 04:11:48 -07:00
|
|
|
CheckAutoplayDataReady();
|
2009-11-05 23:32:52 -08:00
|
|
|
|
|
|
|
if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
|
2009-03-18 16:59:34 -07:00
|
|
|
mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
|
|
|
|
IsPotentiallyPlaying()) {
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("playing"));
|
2009-03-18 16:59:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (oldState < nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA &&
|
|
|
|
mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("canplaythrough"));
|
2008-12-15 19:32:03 -08:00
|
|
|
}
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
bool HTMLMediaElement::CanActivateAutoplay()
|
2009-10-01 07:10:13 -07:00
|
|
|
{
|
2013-03-20 04:11:48 -07:00
|
|
|
// For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
|
|
|
|
// this element itself might be blocking the stream from making progress by
|
|
|
|
// being paused.
|
2012-10-20 20:48:10 -07:00
|
|
|
return !mPausedForInactiveDocumentOrChannel &&
|
|
|
|
mAutoplaying &&
|
2009-10-01 07:10:13 -07:00
|
|
|
mPaused &&
|
2013-03-20 04:11:48 -07:00
|
|
|
(mDownloadSuspendedByCache ||
|
|
|
|
(mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
|
|
|
|
(mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)) &&
|
2009-10-01 07:10:13 -07:00
|
|
|
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
|
2010-10-14 17:13:29 -07:00
|
|
|
mAutoplayEnabled &&
|
|
|
|
!IsEditable();
|
2009-10-01 07:10:13 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 04:11:48 -07:00
|
|
|
void HTMLMediaElement::CheckAutoplayDataReady()
|
2009-03-31 17:52:56 -07:00
|
|
|
{
|
2009-10-01 07:10:13 -07:00
|
|
|
if (CanActivateAutoplay()) {
|
2011-09-29 16:34:37 -07:00
|
|
|
mPaused = false;
|
2009-10-01 07:10:13 -07:00
|
|
|
// We changed mPaused which can affect AddRemoveSelfReference
|
|
|
|
AddRemoveSelfReference();
|
|
|
|
|
2009-03-31 17:52:56 -07:00
|
|
|
if (mDecoder) {
|
2011-09-29 16:34:37 -07:00
|
|
|
SetPlayedOrSeeked(true);
|
2012-04-30 17:29:24 -07:00
|
|
|
if (mCurrentPlayRangeStart == -1.0) {
|
2013-03-19 05:25:19 -07:00
|
|
|
mCurrentPlayRangeStart = CurrentTime();
|
2012-04-30 17:29:24 -07:00
|
|
|
}
|
2009-03-31 17:52:56 -07:00
|
|
|
mDecoder->Play();
|
2012-08-19 21:52:59 -07:00
|
|
|
} else if (mSrcStream) {
|
2012-04-29 20:12:28 -07:00
|
|
|
SetPlayedOrSeeked(true);
|
2012-08-19 21:52:59 -07:00
|
|
|
GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
|
2009-03-31 17:52:56 -07:00
|
|
|
}
|
2010-09-09 20:29:06 -07:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("play"));
|
2009-03-31 17:52:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer()
|
2010-03-01 15:41:49 -08:00
|
|
|
{
|
2013-08-19 15:30:15 -07:00
|
|
|
// If we have loaded the metadata, and the size of the video is still
|
|
|
|
// (-1, -1), the media has no video. Don't go a create a video frame
|
|
|
|
// container.
|
|
|
|
if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA &&
|
|
|
|
mMediaSize == nsIntSize(-1, -1)) {
|
|
|
|
return nullptr;
|
2013-08-05 05:15:23 -07:00
|
|
|
}
|
2010-03-01 15:41:49 -08:00
|
|
|
|
2013-08-19 15:30:15 -07:00
|
|
|
if (mVideoFrameContainer)
|
|
|
|
return mVideoFrameContainer;
|
|
|
|
|
2010-03-01 15:41:49 -08:00
|
|
|
// If we have a print surface, this is just a static image so
|
|
|
|
// no image container is required
|
2013-08-19 15:30:15 -07:00
|
|
|
if (mPrintSurface)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2010-03-01 15:41:49 -08:00
|
|
|
|
|
|
|
// Only video frames need an image container.
|
2011-08-30 14:45:31 -07:00
|
|
|
nsCOMPtr<nsIDOMHTMLVideoElement> video = do_QueryObject(this);
|
2013-08-19 15:30:15 -07:00
|
|
|
if (!video)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2010-03-01 15:41:49 -08:00
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
mVideoFrameContainer =
|
2012-07-13 12:38:09 -07:00
|
|
|
new VideoFrameContainer(this, LayerManager::CreateAsynchronousImageContainer());
|
|
|
|
|
2012-02-14 20:35:01 -08:00
|
|
|
return mVideoFrameContainer;
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::DispatchAudioAvailableEvent(float* aFrameBuffer,
|
|
|
|
uint32_t aFrameBufferLength,
|
|
|
|
float aTime)
|
2010-08-25 06:10:00 -07:00
|
|
|
{
|
2010-09-05 19:14:50 -07:00
|
|
|
// Auto manage the memory for the frame buffer. If we fail and return
|
|
|
|
// an error, this ensures we free the memory in the frame buffer. Otherwise
|
|
|
|
// we hand off ownership of the frame buffer to the audioavailable event,
|
|
|
|
// which frees the memory when it's destroyed.
|
|
|
|
nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
|
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(OwnerDoc());
|
2013-04-05 17:44:15 -07:00
|
|
|
nsRefPtr<HTMLMediaElement> kungFuDeathGrip = this;
|
|
|
|
NS_ENSURE_TRUE(domDoc, NS_ERROR_INVALID_ARG);
|
2010-08-25 06:10:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
2011-05-23 09:46:36 -07:00
|
|
|
nsresult rv = domDoc->CreateEvent(NS_LITERAL_STRING("MozAudioAvailableEvent"),
|
|
|
|
getter_AddRefs(event));
|
2010-08-25 06:10:00 -07:00
|
|
|
nsCOMPtr<nsIDOMNotifyAudioAvailableEvent> audioavailableEvent(do_QueryInterface(event));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = audioavailableEvent->InitAudioAvailableEvent(NS_LITERAL_STRING("MozAudioAvailable"),
|
2012-08-16 21:52:08 -07:00
|
|
|
false, false, frameBuffer.forget(), aFrameBufferLength,
|
2010-10-06 15:58:36 -07:00
|
|
|
aTime, mAllowAudioData);
|
2010-08-25 06:10:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool dummy;
|
2013-04-05 17:44:15 -07:00
|
|
|
return DispatchEvent(event, &dummy);
|
2010-08-25 06:10:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::DispatchEvent(const nsAString& aName)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2010-09-09 20:29:06 -07:00
|
|
|
LOG_EVENT(PR_LOG_DEBUG, ("%p Dispatching event %s", this,
|
2009-09-29 14:32:44 -07:00
|
|
|
NS_ConvertUTF16toUTF8(aName).get()));
|
|
|
|
|
2010-09-09 21:20:10 -07:00
|
|
|
// Save events that occur while in the bfcache. These will be dispatched
|
|
|
|
// if the page comes out of the bfcache.
|
2012-12-11 17:58:07 -08:00
|
|
|
if (mEventDeliveryPaused) {
|
2010-09-09 21:20:10 -07:00
|
|
|
mPendingEvents.AppendElement(aName);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-10-18 03:53:36 -07:00
|
|
|
return nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
2009-11-05 23:32:52 -08:00
|
|
|
static_cast<nsIContent*>(this),
|
|
|
|
aName,
|
2011-09-29 16:34:37 -07:00
|
|
|
false,
|
2012-08-13 20:26:43 -07:00
|
|
|
false);
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::DispatchAsyncEvent(const nsAString& aName)
|
2008-07-09 01:22:20 -07:00
|
|
|
{
|
2010-09-09 20:29:06 -07:00
|
|
|
LOG_EVENT(PR_LOG_DEBUG, ("%p Queuing event %s", this,
|
|
|
|
NS_ConvertUTF16toUTF8(aName).get()));
|
2009-09-29 14:32:44 -07:00
|
|
|
|
2010-09-09 20:29:06 -07:00
|
|
|
nsCOMPtr<nsIRunnable> event = new nsAsyncEventRunner(aName, this);
|
2009-11-05 23:32:52 -08:00
|
|
|
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
|
|
|
return NS_OK;
|
2008-07-09 01:22:20 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::DispatchPendingMediaEvents()
|
2010-09-09 21:20:10 -07:00
|
|
|
{
|
2012-12-11 17:58:07 -08:00
|
|
|
NS_ASSERTION(!mEventDeliveryPaused,
|
2010-09-09 21:20:10 -07:00
|
|
|
"Must not be in bfcache when dispatching pending media events");
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t count = mPendingEvents.Length();
|
|
|
|
for (uint32_t i = 0; i < count; ++i) {
|
2010-09-09 21:20:10 -07:00
|
|
|
DispatchAsyncEvent(mPendingEvents[i]);
|
|
|
|
}
|
|
|
|
mPendingEvents.Clear();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
bool HTMLMediaElement::IsPotentiallyPlaying() const
|
2008-10-19 00:39:21 -07:00
|
|
|
{
|
2009-11-05 23:32:52 -08:00
|
|
|
// TODO:
|
|
|
|
// playback has not stopped due to errors,
|
2008-10-19 00:39:21 -07:00
|
|
|
// and the element has not paused for user interaction
|
2009-10-01 07:10:13 -07:00
|
|
|
return
|
2009-11-05 23:32:52 -08:00
|
|
|
!mPaused &&
|
2008-12-14 19:38:16 -08:00
|
|
|
(mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA ||
|
|
|
|
mReadyState == nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) &&
|
2008-10-19 00:39:21 -07:00
|
|
|
!IsPlaybackEnded();
|
|
|
|
}
|
2008-12-14 10:02:54 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
bool HTMLMediaElement::IsPlaybackEnded() const
|
2008-10-19 00:39:21 -07:00
|
|
|
{
|
|
|
|
// TODO:
|
2009-03-08 13:59:08 -07:00
|
|
|
// the current playback position is equal to the effective end of the media resource.
|
2008-10-19 00:39:21 -07:00
|
|
|
// See bug 449157.
|
2008-12-14 19:38:16 -08:00
|
|
|
return mNetworkState >= nsIDOMHTMLMediaElement::HAVE_METADATA &&
|
2011-09-29 16:34:37 -07:00
|
|
|
mDecoder ? mDecoder->IsEnded() : false;
|
2008-10-19 00:39:21 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
already_AddRefed<nsIPrincipal> HTMLMediaElement::GetCurrentPrincipal()
|
2008-09-06 16:47:28 -07:00
|
|
|
{
|
2012-04-29 20:12:28 -07:00
|
|
|
if (mDecoder) {
|
|
|
|
return mDecoder->GetCurrentPrincipal();
|
|
|
|
}
|
2012-08-19 21:52:59 -07:00
|
|
|
if (mSrcStream) {
|
|
|
|
nsRefPtr<nsIPrincipal> principal = mSrcStream->GetPrincipal();
|
2012-04-29 20:12:28 -07:00
|
|
|
return principal.forget();
|
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2008-09-06 16:47:28 -07:00
|
|
|
}
|
2008-09-26 05:56:21 -07:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NotifyDecoderPrincipalChanged()
|
2012-04-29 20:12:42 -07:00
|
|
|
{
|
2013-07-24 02:55:23 -07:00
|
|
|
nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
|
|
|
|
|
|
|
|
bool subsumes;
|
|
|
|
mDecoder->UpdateSameOriginStatus(
|
|
|
|
NS_SUCCEEDED(NodePrincipal()->Subsumes(principal, &subsumes)) && subsumes);
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
|
2012-04-29 20:12:42 -07:00
|
|
|
OutputMediaStream* ms = &mOutputStreams[i];
|
|
|
|
ms->mStream->CombineWithPrincipal(principal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
|
2008-10-19 00:39:21 -07:00
|
|
|
{
|
|
|
|
mMediaSize = size;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents)
|
2008-09-26 05:56:21 -07:00
|
|
|
{
|
2012-12-11 17:58:07 -08:00
|
|
|
if (aPauseElement != mPausedForInactiveDocumentOrChannel) {
|
|
|
|
mPausedForInactiveDocumentOrChannel = aPauseElement;
|
|
|
|
if (aPauseElement) {
|
2012-04-29 20:12:28 -07:00
|
|
|
if (mDecoder) {
|
2009-10-01 07:10:13 -07:00
|
|
|
mDecoder->Pause();
|
|
|
|
mDecoder->Suspend();
|
2012-08-19 21:52:59 -07:00
|
|
|
} else if (mSrcStream) {
|
|
|
|
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
|
2012-04-29 20:12:28 -07:00
|
|
|
}
|
2012-12-11 17:58:07 -08:00
|
|
|
mEventDeliveryPaused = aSuspendEvents;
|
2012-04-29 20:12:28 -07:00
|
|
|
} else {
|
|
|
|
if (mDecoder) {
|
2011-09-29 16:34:37 -07:00
|
|
|
mDecoder->Resume(false);
|
2010-01-06 17:13:27 -08:00
|
|
|
if (!mPaused && !mDecoder->IsEnded()) {
|
2009-10-01 07:10:13 -07:00
|
|
|
mDecoder->Play();
|
|
|
|
}
|
2012-08-19 21:52:59 -07:00
|
|
|
} else if (mSrcStream) {
|
|
|
|
GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
|
2009-10-01 07:10:13 -07:00
|
|
|
}
|
2012-12-11 17:58:07 -08:00
|
|
|
if (mEventDeliveryPaused) {
|
|
|
|
mEventDeliveryPaused = false;
|
2013-01-13 14:46:50 -08:00
|
|
|
DispatchPendingMediaEvents();
|
2012-12-11 17:58:07 -08:00
|
|
|
}
|
2009-10-01 07:10:13 -07:00
|
|
|
}
|
2008-10-28 11:48:39 -07:00
|
|
|
}
|
2012-12-11 17:58:07 -08:00
|
|
|
}
|
2009-01-21 15:54:40 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
|
2012-12-11 17:58:07 -08:00
|
|
|
{
|
|
|
|
nsIDocument* ownerDoc = OwnerDoc();
|
2013-06-10 05:22:05 -07:00
|
|
|
|
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->SetDormantIfNecessary(ownerDoc->Hidden());
|
|
|
|
}
|
|
|
|
|
2013-05-21 10:49:17 -07:00
|
|
|
// SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the
|
|
|
|
// CanPlayChanged callback.
|
2013-05-05 00:03:15 -07:00
|
|
|
if (UseAudioChannelService() && mPlayingThroughTheAudioChannel &&
|
|
|
|
mAudioChannelAgent) {
|
|
|
|
mAudioChannelAgent->SetVisibilityState(!ownerDoc->Hidden());
|
2012-12-04 11:46:07 -08:00
|
|
|
}
|
2012-12-11 17:58:07 -08:00
|
|
|
bool suspendEvents = !ownerDoc->IsActive() || !ownerDoc->IsVisible();
|
2013-05-21 10:49:17 -07:00
|
|
|
bool pauseElement = suspendEvents || (mMuted & MUTED_BY_AUDIO_CHANNEL);
|
2012-12-11 17:58:07 -08:00
|
|
|
|
|
|
|
SuspendOrResumeElement(pauseElement, suspendEvents);
|
2012-12-04 11:46:07 -08:00
|
|
|
|
2009-10-01 07:10:13 -07:00
|
|
|
AddRemoveSelfReference();
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::AddRemoveSelfReference()
|
2009-10-01 07:10:13 -07:00
|
|
|
{
|
|
|
|
// XXX we could release earlier here in many situations if we examined
|
|
|
|
// which event listeners are attached. Right now we assume there is a
|
|
|
|
// potential listener for every event. We would also have to keep the
|
|
|
|
// element alive if it was playing and producing audio output --- right now
|
|
|
|
// that's covered by the !mPaused check.
|
2011-10-18 03:53:36 -07:00
|
|
|
nsIDocument* ownerDoc = OwnerDoc();
|
2009-10-01 07:10:13 -07:00
|
|
|
|
|
|
|
// See the comment at the top of this file for the explanation of this
|
|
|
|
// boolean expression.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool needSelfReference = !mShuttingDown &&
|
2011-10-18 04:19:44 -07:00
|
|
|
ownerDoc->IsActive() &&
|
2009-10-01 07:10:13 -07:00
|
|
|
(mDelayingLoadEvent ||
|
|
|
|
(!mPaused && mDecoder && !mDecoder->IsEnded()) ||
|
2012-08-19 21:52:59 -07:00
|
|
|
(!mPaused && mSrcStream && !mSrcStream->IsFinished()) ||
|
2009-10-01 07:10:13 -07:00
|
|
|
(mDecoder && mDecoder->IsSeeking()) ||
|
|
|
|
CanActivateAutoplay() ||
|
|
|
|
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
|
|
|
|
|
|
|
|
if (needSelfReference != mHasSelfReference) {
|
|
|
|
mHasSelfReference = needSelfReference;
|
|
|
|
if (needSelfReference) {
|
2010-02-24 11:14:14 -08:00
|
|
|
// The observer service will hold a strong reference to us. This
|
|
|
|
// will do to keep us alive. We need to know about shutdown so that
|
|
|
|
// we can release our self-reference.
|
|
|
|
nsContentUtils::RegisterShutdownObserver(this);
|
2009-10-01 07:10:13 -07:00
|
|
|
} else {
|
|
|
|
// Dispatch Release asynchronously so that we don't destroy this object
|
|
|
|
// inside a call stack of method calls on this object
|
|
|
|
nsCOMPtr<nsIRunnable> event =
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_NewRunnableMethod(this, &HTMLMediaElement::DoRemoveSelfReference);
|
2009-10-01 07:10:13 -07:00
|
|
|
NS_DispatchToMainThread(event);
|
|
|
|
}
|
2009-01-21 15:54:40 -08:00
|
|
|
}
|
2012-12-04 11:46:07 -08:00
|
|
|
|
|
|
|
UpdateAudioChannelPlayingState();
|
2008-10-28 11:48:39 -07:00
|
|
|
}
|
2009-02-15 17:05:28 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::DoRemoveSelfReference()
|
2010-02-24 11:14:14 -08:00
|
|
|
{
|
|
|
|
// We don't need the shutdown observer anymore. Unregistering releases
|
|
|
|
// its reference to us, which we were using as our self-reference.
|
|
|
|
nsContentUtils::UnregisterShutdownObserver(this);
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsresult HTMLMediaElement::Observe(nsISupports* aSubject,
|
|
|
|
const char* aTopic, const PRUnichar* aData)
|
2010-02-24 11:14:14 -08:00
|
|
|
{
|
2011-02-12 10:04:15 -08:00
|
|
|
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
|
2012-11-15 19:25:26 -08:00
|
|
|
|
2010-02-24 11:14:14 -08:00
|
|
|
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
2011-09-29 16:34:37 -07:00
|
|
|
mShuttingDown = true;
|
2010-02-24 11:14:14 -08:00
|
|
|
AddRemoveSelfReference();
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::IsNodeOfType(uint32_t aFlags) const
|
2009-02-15 17:05:28 -08:00
|
|
|
{
|
2010-04-30 06:12:06 -07:00
|
|
|
return !(aFlags & ~(eCONTENT | eMEDIA));
|
2009-02-15 17:05:28 -08:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::DispatchAsyncSourceError(nsIContent* aSourceElement)
|
2010-09-02 17:03:03 -07:00
|
|
|
{
|
|
|
|
LOG_EVENT(PR_LOG_DEBUG, ("%p Queuing simple source error event", this));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIRunnable> event = new nsSourceErrorEventRunner(this, aSourceElement);
|
|
|
|
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NotifyAddedSource()
|
2009-02-15 17:05:28 -08:00
|
|
|
{
|
2010-09-02 17:03:03 -07:00
|
|
|
// If a source element is inserted as a child of a media element
|
|
|
|
// that has no src attribute and whose networkState has the value
|
|
|
|
// NETWORK_EMPTY, the user agent must invoke the media element's
|
|
|
|
// resource selection algorithm.
|
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
|
|
|
|
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY)
|
|
|
|
{
|
2009-03-08 13:59:08 -07:00
|
|
|
QueueSelectResourceTask();
|
2010-09-02 17:03:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// A load was paused in the resource selection algorithm, waiting for
|
2012-04-30 17:29:24 -07:00
|
|
|
// a new source child to be added, resume the resource selection algorithm.
|
2010-09-02 17:03:03 -07:00
|
|
|
if (mLoadWaitStatus == WAITING_FOR_SOURCE) {
|
2009-03-08 13:59:08 -07:00
|
|
|
QueueLoadFromSourceTask();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
nsIContent* HTMLMediaElement::GetNextSource()
|
2009-03-08 13:59:08 -07:00
|
|
|
{
|
2011-08-30 14:45:31 -07:00
|
|
|
nsCOMPtr<nsIDOMNode> thisDomNode = do_QueryObject(this);
|
2009-03-08 13:59:08 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
mSourceLoadCandidate = nullptr;
|
2010-09-02 17:03:03 -07:00
|
|
|
|
2011-11-15 23:50:19 -08:00
|
|
|
nsresult rv = NS_OK;
|
2009-03-08 13:59:08 -07:00
|
|
|
if (!mSourcePointer) {
|
|
|
|
// First time this has been run, create a selection to cover children.
|
2013-02-07 04:09:41 -08:00
|
|
|
mSourcePointer = new nsRange(this);
|
2013-06-06 21:26:55 -07:00
|
|
|
// If this media element is removed from the DOM, don't gravitate the
|
|
|
|
// range up to its ancestor, leave it attached to the media element.
|
|
|
|
mSourcePointer->SetEnableGravitationOnElementRemoval(false);
|
2009-03-08 13:59:08 -07:00
|
|
|
|
|
|
|
rv = mSourcePointer->SelectNodeContents(thisDomNode);
|
2012-07-30 07:20:58 -07:00
|
|
|
if (NS_FAILED(rv)) return nullptr;
|
2009-03-08 13:59:08 -07:00
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
rv = mSourcePointer->Collapse(true);
|
2012-07-30 07:20:58 -07:00
|
|
|
if (NS_FAILED(rv)) return nullptr;
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
|
|
|
|
2011-09-29 16:34:37 -07:00
|
|
|
while (true) {
|
2009-03-08 13:59:08 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsCOMPtr<nsIDOMNode> startContainer;
|
|
|
|
rv = mSourcePointer->GetStartContainer(getter_AddRefs(startContainer));
|
2012-07-30 07:20:58 -07:00
|
|
|
if (NS_FAILED(rv)) return nullptr;
|
2009-03-08 13:59:08 -07:00
|
|
|
NS_ASSERTION(startContainer == thisDomNode,
|
|
|
|
"Should only iterate over direct children");
|
|
|
|
#endif
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t startOffset = 0;
|
2009-03-08 13:59:08 -07:00
|
|
|
rv = mSourcePointer->GetStartOffset(&startOffset);
|
2012-07-30 07:20:58 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2009-03-08 13:59:08 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
if (uint32_t(startOffset) == GetChildCount())
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr; // No more children.
|
2009-03-08 13:59:08 -07:00
|
|
|
|
|
|
|
// Advance the range to the next child.
|
2011-11-15 23:50:19 -08:00
|
|
|
rv = mSourcePointer->SetStart(thisDomNode, startOffset + 1);
|
2012-07-30 07:20:58 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2009-03-08 13:59:08 -07:00
|
|
|
|
|
|
|
nsIContent* child = GetChildAt(startOffset);
|
|
|
|
|
2010-09-02 17:03:03 -07:00
|
|
|
// If child is a <source> element, it is the next candidate.
|
2011-11-15 23:50:19 -08:00
|
|
|
if (child && child->IsHTML(nsGkAtoms::source)) {
|
2010-09-02 17:03:03 -07:00
|
|
|
mSourceLoadCandidate = child;
|
|
|
|
return child;
|
2009-03-08 13:59:08 -07:00
|
|
|
}
|
2009-02-15 17:05:28 -08:00
|
|
|
}
|
2009-03-08 13:59:08 -07:00
|
|
|
NS_NOTREACHED("Execution should not reach here!");
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2009-02-15 17:05:28 -08:00
|
|
|
}
|
2009-03-08 14:01:03 -07:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::ChangeDelayLoadStatus(bool aDelay)
|
2011-11-15 23:50:19 -08:00
|
|
|
{
|
2009-03-08 14:01:03 -07:00
|
|
|
if (mDelayingLoadEvent == aDelay)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mDelayingLoadEvent = aDelay;
|
|
|
|
|
|
|
|
if (aDelay) {
|
2011-10-18 03:53:36 -07:00
|
|
|
mLoadBlockedDoc = OwnerDoc();
|
2009-03-08 14:01:03 -07:00
|
|
|
mLoadBlockedDoc->BlockOnload();
|
2009-09-29 14:32:44 -07:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p ChangeDelayLoadStatus(%d) doc=0x%p", this, aDelay, mLoadBlockedDoc.get()));
|
2009-03-08 14:01:03 -07:00
|
|
|
} else {
|
2009-04-09 18:28:24 -07:00
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->MoveLoadsToBackground();
|
|
|
|
}
|
2009-09-29 14:32:44 -07:00
|
|
|
LOG(PR_LOG_DEBUG, ("%p ChangeDelayLoadStatus(%d) doc=0x%p", this, aDelay, mLoadBlockedDoc.get()));
|
2010-02-24 11:14:14 -08:00
|
|
|
// mLoadBlockedDoc might be null due to GC unlinking
|
|
|
|
if (mLoadBlockedDoc) {
|
2011-09-29 16:34:37 -07:00
|
|
|
mLoadBlockedDoc->UnblockOnload(false);
|
2012-07-30 07:20:58 -07:00
|
|
|
mLoadBlockedDoc = nullptr;
|
2010-02-24 11:14:14 -08:00
|
|
|
}
|
2009-03-08 14:01:03 -07:00
|
|
|
}
|
2009-10-01 07:10:13 -07:00
|
|
|
|
|
|
|
// We changed mDelayingLoadEvent which can affect AddRemoveSelfReference
|
|
|
|
AddRemoveSelfReference();
|
2009-03-08 14:01:03 -07:00
|
|
|
}
|
2009-04-09 18:28:24 -07:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
already_AddRefed<nsILoadGroup> HTMLMediaElement::GetDocumentLoadGroup()
|
2009-04-09 18:28:24 -07:00
|
|
|
{
|
2012-02-23 17:07:35 -08:00
|
|
|
if (!OwnerDoc()->IsActive()) {
|
|
|
|
NS_WARNING("Load group requested for media element in inactive document.");
|
|
|
|
}
|
2011-10-18 04:19:44 -07:00
|
|
|
return OwnerDoc()->GetDocumentLoadGroup();
|
2009-04-09 18:28:24 -07:00
|
|
|
}
|
2009-12-10 20:02:13 -08:00
|
|
|
|
|
|
|
nsresult
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement::CopyInnerTo(Element* aDest)
|
2009-12-10 20:02:13 -08:00
|
|
|
{
|
|
|
|
nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2011-10-18 03:53:36 -07:00
|
|
|
if (aDest->OwnerDoc()->IsStaticDocument()) {
|
2013-03-19 05:23:54 -07:00
|
|
|
HTMLMediaElement* dest = static_cast<HTMLMediaElement*>(aDest);
|
2009-12-10 20:02:13 -08:00
|
|
|
if (mPrintSurface) {
|
|
|
|
dest->mPrintSurface = mPrintSurface;
|
|
|
|
dest->mMediaSize = mMediaSize;
|
|
|
|
} else {
|
2009-12-24 13:20:05 -08:00
|
|
|
nsIFrame* frame = GetPrimaryFrame();
|
2011-12-03 13:50:16 -08:00
|
|
|
Element* element;
|
2009-12-10 20:02:13 -08:00
|
|
|
if (frame && frame->GetType() == nsGkAtoms::HTMLVideoFrame &&
|
|
|
|
static_cast<nsVideoFrame*>(frame)->ShouldDisplayPoster()) {
|
2011-12-03 13:50:16 -08:00
|
|
|
nsIContent* content = static_cast<nsVideoFrame*>(frame)->GetPosterImage();
|
2013-04-02 18:14:24 -07:00
|
|
|
element = content ? content->AsElement() : nullptr;
|
2009-12-10 20:02:13 -08:00
|
|
|
} else {
|
2013-03-19 05:23:54 -07:00
|
|
|
element = const_cast<HTMLMediaElement*>(this);
|
2009-12-10 20:02:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
nsLayoutUtils::SurfaceFromElementResult res =
|
2011-12-03 13:50:16 -08:00
|
|
|
nsLayoutUtils::SurfaceFromElement(element,
|
2009-12-10 20:02:13 -08:00
|
|
|
nsLayoutUtils::SFE_WANT_NEW_SURFACE);
|
|
|
|
dest->mPrintSurface = res.mSurface;
|
|
|
|
dest->mMediaSize = nsIntSize(res.mSize.width, res.mSize.height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
2010-08-05 00:40:35 -07:00
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
already_AddRefed<TimeRanges>
|
|
|
|
HTMLMediaElement::Buffered() const
|
2010-08-05 00:40:35 -07:00
|
|
|
{
|
2013-03-02 11:14:44 -08:00
|
|
|
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
2013-06-20 20:15:47 -07:00
|
|
|
if (mMediaSource) {
|
|
|
|
mMediaSource->GetBuffered(ranges);
|
|
|
|
} else if (mDecoder && mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) {
|
2010-09-09 20:29:06 -07:00
|
|
|
// If GetBuffered fails we ignore the error result and just return the
|
|
|
|
// time ranges we found up till the error.
|
|
|
|
mDecoder->GetBuffered(ranges);
|
2010-08-05 00:40:35 -07:00
|
|
|
}
|
2013-09-26 22:22:38 -07:00
|
|
|
ranges->Normalize();
|
2013-03-19 05:25:19 -07:00
|
|
|
return ranges.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult HTMLMediaElement::GetBuffered(nsIDOMTimeRanges** aBuffered)
|
|
|
|
{
|
|
|
|
nsRefPtr<TimeRanges> ranges = Buffered();
|
2011-11-15 23:50:19 -08:00
|
|
|
ranges.forget(aBuffered);
|
2010-08-05 00:40:35 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-09-16 10:36:23 -07:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::SetRequestHeaders(nsIHttpChannel* aChannel)
|
2010-09-16 10:36:23 -07:00
|
|
|
{
|
|
|
|
// Send Accept header for video and audio types only (Bug 489071)
|
|
|
|
SetAcceptHeader(aChannel);
|
|
|
|
|
2012-03-22 16:39:31 -07:00
|
|
|
// Media elements are likely candidates for HTTP Pipeline head of line
|
|
|
|
// blocking problems, so disable pipelines.
|
|
|
|
nsLoadFlags loadflags;
|
|
|
|
aChannel->GetLoadFlags(&loadflags);
|
|
|
|
loadflags |= nsIRequest::INHIBIT_PIPELINE;
|
|
|
|
aChannel->SetLoadFlags(loadflags);
|
|
|
|
|
2010-11-28 13:21:27 -08:00
|
|
|
// Apache doesn't send Content-Length when gzip transfer encoding is used,
|
|
|
|
// which prevents us from estimating the video length (if explicit Content-Duration
|
|
|
|
// and a length spec in the container are not present either) and from seeking.
|
|
|
|
// So, disable the standard "Accept-Encoding: gzip,deflate" that we usually send.
|
|
|
|
// See bug 614760.
|
|
|
|
aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Encoding"),
|
2011-11-15 23:50:19 -08:00
|
|
|
EmptyCString(), false);
|
2010-11-28 13:21:27 -08:00
|
|
|
|
2010-09-16 10:36:23 -07:00
|
|
|
// Set the Referer header
|
2011-10-18 04:19:44 -07:00
|
|
|
aChannel->SetReferrer(OwnerDoc()->GetDocumentURI());
|
2010-09-16 10:36:23 -07:00
|
|
|
}
|
2010-11-24 10:34:57 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::FireTimeUpdate(bool aPeriodic)
|
2010-11-24 10:34:57 -08:00
|
|
|
{
|
|
|
|
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
|
|
|
|
|
|
|
TimeStamp now = TimeStamp::Now();
|
2013-03-19 05:25:19 -07:00
|
|
|
double time = CurrentTime();
|
2010-11-24 10:34:57 -08:00
|
|
|
|
2012-04-29 20:12:28 -07:00
|
|
|
// Fire a timeupdate event if this is not a periodic update (i.e. it's a
|
2010-11-24 10:34:57 -08:00
|
|
|
// timeupdate event mandated by the spec), or if it's a periodic update
|
|
|
|
// and TIMEUPDATE_MS has passed since the last timeupdate event fired and
|
|
|
|
// the time has changed.
|
|
|
|
if (!aPeriodic ||
|
|
|
|
(mLastCurrentTime != time &&
|
|
|
|
(mTimeUpdateTime.IsNull() ||
|
|
|
|
now - mTimeUpdateTime >= TimeDuration::FromMilliseconds(TIMEUPDATE_MS)))) {
|
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("timeupdate"));
|
|
|
|
mTimeUpdateTime = now;
|
|
|
|
mLastCurrentTime = time;
|
|
|
|
}
|
2011-08-24 16:42:23 -07:00
|
|
|
if (mFragmentEnd >= 0.0 && time >= mFragmentEnd) {
|
|
|
|
Pause();
|
|
|
|
mFragmentEnd = -1.0;
|
|
|
|
mFragmentStart = -1.0;
|
2012-11-19 07:11:21 -08:00
|
|
|
mDecoder->SetFragmentEndTime(mFragmentEnd);
|
2011-08-24 16:42:23 -07:00
|
|
|
}
|
2013-05-21 09:14:00 -07:00
|
|
|
|
|
|
|
// Update visible text tracks.
|
|
|
|
// Here mTextTracks can be null if the cycle collector has unlinked
|
|
|
|
// us before our parent. In that case UnbindFromTree will call us
|
|
|
|
// when our parent is unlinked.
|
|
|
|
if (mTextTracks) {
|
|
|
|
mTextTracks->Update(time);
|
|
|
|
}
|
2011-08-24 16:42:23 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::GetCurrentSpec(nsCString& aString)
|
2011-08-24 16:42:23 -07:00
|
|
|
{
|
2011-11-24 18:06:22 -08:00
|
|
|
if (mLoadingSrc) {
|
2011-08-24 16:42:23 -07:00
|
|
|
mLoadingSrc->GetSpec(aString);
|
2011-11-24 18:06:22 -08:00
|
|
|
} else {
|
|
|
|
aString.Truncate();
|
2011-08-24 16:42:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute double mozFragmentEnd; */
|
2013-03-19 05:25:19 -07:00
|
|
|
double
|
|
|
|
HTMLMediaElement::MozFragmentEnd()
|
2011-08-24 16:42:23 -07:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
double duration = Duration();
|
2011-08-24 16:42:23 -07:00
|
|
|
|
|
|
|
// If there is no end fragment, or the fragment end is greater than the
|
|
|
|
// duration, return the duration.
|
2013-03-19 05:25:19 -07:00
|
|
|
return (mFragmentEnd < 0.0 || mFragmentEnd > duration) ? duration : mFragmentEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetMozFragmentEnd(double* aTime)
|
|
|
|
{
|
|
|
|
*aTime = MozFragmentEnd();
|
2011-08-24 16:42:23 -07:00
|
|
|
return NS_OK;
|
2010-11-24 10:34:57 -08:00
|
|
|
}
|
2011-11-21 16:34:21 -08:00
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::NotifyAudioAvailableListener()
|
2011-11-21 16:34:21 -08:00
|
|
|
{
|
2013-05-19 20:13:26 -07:00
|
|
|
OwnerDoc()->WarnOnceAbout(nsIDocument::eMozAudioData);
|
2011-11-21 16:34:21 -08:00
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->NotifyAudioAvailableListener();
|
|
|
|
}
|
|
|
|
}
|
2012-11-14 11:45:31 -08:00
|
|
|
|
2012-11-22 02:38:28 -08:00
|
|
|
static double ClampPlaybackRate(double aPlaybackRate)
|
|
|
|
{
|
|
|
|
if (aPlaybackRate == 0.0) {
|
|
|
|
return aPlaybackRate;
|
|
|
|
}
|
2013-03-05 15:43:44 -08:00
|
|
|
if (Abs(aPlaybackRate) < MIN_PLAYBACKRATE) {
|
2012-11-22 02:38:28 -08:00
|
|
|
return aPlaybackRate < 0 ? -MIN_PLAYBACKRATE : MIN_PLAYBACKRATE;
|
|
|
|
}
|
2013-03-05 15:43:44 -08:00
|
|
|
if (Abs(aPlaybackRate) > MAX_PLAYBACKRATE) {
|
2012-11-22 02:38:28 -08:00
|
|
|
return aPlaybackRate < 0 ? -MAX_PLAYBACKRATE : MAX_PLAYBACKRATE;
|
|
|
|
}
|
|
|
|
return aPlaybackRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute double defaultPlaybackRate; */
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetDefaultPlaybackRate(double* aDefaultPlaybackRate)
|
2012-11-22 02:38:28 -08:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
*aDefaultPlaybackRate = DefaultPlaybackRate();
|
2012-11-22 02:38:28 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::SetDefaultPlaybackRate(double aDefaultPlaybackRate, ErrorResult& aRv)
|
2012-11-22 02:38:28 -08:00
|
|
|
{
|
|
|
|
if (aDefaultPlaybackRate < 0) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
|
|
|
return;
|
2012-11-22 02:38:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
mDefaultPlaybackRate = ClampPlaybackRate(aDefaultPlaybackRate);
|
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("ratechange"));
|
2013-03-19 05:25:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::SetDefaultPlaybackRate(double aDefaultPlaybackRate)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
SetDefaultPlaybackRate(aDefaultPlaybackRate, rv);
|
|
|
|
return rv.ErrorCode();
|
2012-11-22 02:38:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute double playbackRate; */
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetPlaybackRate(double* aPlaybackRate)
|
2012-11-22 02:38:28 -08:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
*aPlaybackRate = PlaybackRate();
|
2012-11-22 02:38:28 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:25:19 -07:00
|
|
|
void
|
|
|
|
HTMLMediaElement::SetPlaybackRate(double aPlaybackRate, ErrorResult& aRv)
|
2012-11-22 02:38:28 -08:00
|
|
|
{
|
2013-03-04 06:48:58 -08:00
|
|
|
// Changing the playback rate of a media that has more than two channels is
|
|
|
|
// not supported.
|
|
|
|
if (aPlaybackRate < 0 || (mChannels > 2 && aPlaybackRate != 1.0)) {
|
2013-03-19 05:25:19 -07:00
|
|
|
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
|
|
|
return;
|
2012-11-22 02:38:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
mPlaybackRate = ClampPlaybackRate(aPlaybackRate);
|
|
|
|
|
2013-05-21 10:49:17 -07:00
|
|
|
if (mPlaybackRate < 0 ||
|
|
|
|
mPlaybackRate > THRESHOLD_HIGH_PLAYBACKRATE_AUDIO ||
|
|
|
|
mPlaybackRate < THRESHOLD_LOW_PLAYBACKRATE_AUDIO) {
|
|
|
|
SetMutedInternal(mMuted | MUTED_BY_INVALID_PLAYBACK_RATE);
|
|
|
|
} else {
|
|
|
|
SetMutedInternal(mMuted & ~MUTED_BY_INVALID_PLAYBACK_RATE);
|
2012-11-22 02:38:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->SetPlaybackRate(mPlaybackRate);
|
|
|
|
}
|
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("ratechange"));
|
2013-03-19 05:25:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP HTMLMediaElement::SetPlaybackRate(double aPlaybackRate)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
SetPlaybackRate(aPlaybackRate, rv);
|
|
|
|
return rv.ErrorCode();
|
2012-11-22 02:38:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute bool mozPreservesPitch; */
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::GetMozPreservesPitch(bool* aPreservesPitch)
|
2012-11-22 02:38:28 -08:00
|
|
|
{
|
2013-03-19 05:25:19 -07:00
|
|
|
*aPreservesPitch = MozPreservesPitch();
|
2012-11-22 02:38:28 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::SetMozPreservesPitch(bool aPreservesPitch)
|
2012-11-22 02:38:28 -08:00
|
|
|
{
|
|
|
|
mPreservesPitch = aPreservesPitch;
|
2013-02-26 00:51:59 -08:00
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->SetPreservesPitch(mPreservesPitch);
|
|
|
|
}
|
2012-11-22 02:38:28 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
ImageContainer* HTMLMediaElement::GetImageContainer()
|
2012-11-14 11:45:31 -08:00
|
|
|
{
|
|
|
|
VideoFrameContainer* container = GetVideoFrameContainer();
|
|
|
|
return container ? container->GetImageContainer() : nullptr;
|
|
|
|
}
|
|
|
|
|
2013-09-02 02:45:44 -07:00
|
|
|
nsresult HTMLMediaElement::UpdateChannelMuteState(AudioChannelState aCanPlay)
|
2012-12-04 11:46:07 -08:00
|
|
|
{
|
2013-04-25 17:53:25 -07:00
|
|
|
if (!UseAudioChannelService()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-09-02 02:45:44 -07:00
|
|
|
if ((aCanPlay == AUDIO_CHANNEL_STATE_FADED && !mAudioChannelFaded) ||
|
|
|
|
(aCanPlay != AUDIO_CHANNEL_STATE_FADED && mAudioChannelFaded)) {
|
|
|
|
mAudioChannelFaded = !mAudioChannelFaded;
|
|
|
|
SetVolumeInternal();
|
|
|
|
}
|
|
|
|
|
2013-05-21 10:49:17 -07:00
|
|
|
// We have to mute this channel.
|
2013-09-02 02:45:44 -07:00
|
|
|
if (aCanPlay == AUDIO_CHANNEL_STATE_MUTED && !(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
|
2013-05-21 10:49:17 -07:00
|
|
|
SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL);
|
2012-12-04 11:46:07 -08:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
|
2013-09-02 02:45:44 -07:00
|
|
|
} else if (aCanPlay != AUDIO_CHANNEL_STATE_MUTED &&
|
|
|
|
(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
|
2013-05-21 10:49:17 -07:00
|
|
|
SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL);
|
2012-12-04 11:46:07 -08:00
|
|
|
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
|
|
|
|
}
|
2012-12-04 13:51:13 -08:00
|
|
|
|
2013-05-21 10:49:17 -07:00
|
|
|
SuspendOrResumeElement(mMuted & MUTED_BY_AUDIO_CHANNEL, false);
|
2012-12-04 11:46:07 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
void HTMLMediaElement::UpdateAudioChannelPlayingState()
|
2012-12-04 11:46:07 -08:00
|
|
|
{
|
2013-04-25 17:53:25 -07:00
|
|
|
if (!UseAudioChannelService()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-04 11:46:07 -08:00
|
|
|
bool playingThroughTheAudioChannel =
|
2013-01-07 00:40:50 -08:00
|
|
|
(!mPaused &&
|
|
|
|
(HasAttr(kNameSpaceID_None, nsGkAtoms::loop) ||
|
2013-01-08 15:57:28 -08:00
|
|
|
(mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
|
|
|
|
!IsPlaybackEnded())));
|
2012-12-04 11:46:07 -08:00
|
|
|
if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
|
|
|
|
mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;
|
|
|
|
|
2012-12-06 07:25:18 -08:00
|
|
|
if (!mAudioChannelAgent) {
|
|
|
|
nsresult rv;
|
|
|
|
mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv);
|
|
|
|
if (!mAudioChannelAgent) {
|
|
|
|
return;
|
|
|
|
}
|
2013-09-17 20:46:22 -07:00
|
|
|
nsCOMPtr<nsIDOMHTMLVideoElement> video = do_QueryObject(this);
|
2013-04-03 13:35:05 -07:00
|
|
|
// Use a weak ref so the audio channel agent can't leak |this|.
|
2013-09-17 20:46:22 -07:00
|
|
|
if (AUDIO_CHANNEL_NORMAL == mAudioChannelType && video) {
|
|
|
|
mAudioChannelAgent->InitWithVideo(mAudioChannelType, this, true);
|
|
|
|
} else {
|
|
|
|
mAudioChannelAgent->InitWithWeakCallback(mAudioChannelType, this);
|
|
|
|
}
|
2013-05-05 00:03:15 -07:00
|
|
|
mAudioChannelAgent->SetVisibilityState(!OwnerDoc()->Hidden());
|
2012-12-04 11:46:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mPlayingThroughTheAudioChannel) {
|
2013-09-02 02:45:44 -07:00
|
|
|
int32_t canPlay;
|
2012-12-06 07:25:18 -08:00
|
|
|
mAudioChannelAgent->StartPlaying(&canPlay);
|
2013-05-21 10:49:17 -07:00
|
|
|
CanPlayChanged(canPlay);
|
2012-12-04 11:46:07 -08:00
|
|
|
} else {
|
2012-12-06 07:25:18 -08:00
|
|
|
mAudioChannelAgent->StopPlaying();
|
|
|
|
mAudioChannelAgent = nullptr;
|
2012-12-04 11:46:07 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-06 07:25:18 -08:00
|
|
|
/* void canPlayChanged (in boolean canPlay); */
|
2013-09-02 02:45:44 -07:00
|
|
|
NS_IMETHODIMP HTMLMediaElement::CanPlayChanged(int32_t canPlay)
|
|
|
|
{
|
|
|
|
static_assert(static_cast<AudioChannelState>(
|
|
|
|
nsIAudioChannelAgent::AUDIO_AGENT_STATE_NORMAL) ==
|
|
|
|
AUDIO_CHANNEL_STATE_NORMAL &&
|
|
|
|
static_cast<AudioChannelState>(
|
|
|
|
nsIAudioChannelAgent::AUDIO_AGENT_STATE_MUTED) ==
|
|
|
|
AUDIO_CHANNEL_STATE_MUTED &&
|
|
|
|
static_cast<AudioChannelState>(
|
|
|
|
nsIAudioChannelAgent::AUDIO_AGENT_STATE_FADED) ==
|
|
|
|
AUDIO_CHANNEL_STATE_FADED,
|
|
|
|
"Enum of channel state on nsIAudioChannelAgent.idl should be "
|
|
|
|
"the same with AudioChannelCommon.h");
|
|
|
|
|
2013-01-07 00:40:02 -08:00
|
|
|
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
|
|
|
|
|
2013-09-02 02:45:44 -07:00
|
|
|
UpdateChannelMuteState(static_cast<AudioChannelState>(canPlay));
|
|
|
|
mPaused.SetCanPlay(canPlay != AUDIO_CHANNEL_STATE_MUTED);
|
2012-12-06 07:25:18 -08:00
|
|
|
return NS_OK;
|
2012-12-04 11:46:07 -08:00
|
|
|
}
|
2013-03-19 05:23:54 -07:00
|
|
|
|
2013-05-21 09:14:00 -07:00
|
|
|
/* readonly attribute TextTrackList textTracks; */
|
|
|
|
TextTrackList*
|
|
|
|
HTMLMediaElement::TextTracks() const
|
|
|
|
{
|
|
|
|
return mTextTracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<TextTrack>
|
|
|
|
HTMLMediaElement::AddTextTrack(TextTrackKind aKind,
|
|
|
|
const nsAString& aLabel,
|
|
|
|
const nsAString& aLanguage)
|
|
|
|
{
|
2013-06-14 13:10:36 -07:00
|
|
|
return mTextTracks->AddTextTrack(this, aKind, aLabel, aLanguage);
|
2013-05-21 09:14:00 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 05:23:54 -07:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|