From f1041ff584b61b72edbeb43cc8b7bd030eae6c2d Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 19 Mar 2013 13:25:19 +0100 Subject: [PATCH] Bug 841493 - Move HTMLMediaElement to WebIDL, r=Ms2ger --- .../html/content/public/HTMLMediaElement.h | 198 ++++++- content/html/content/src/HTMLMediaElement.cpp | 530 ++++++++++++------ content/html/content/test/Makefile.in | 5 + .../html/content/test/test_mozLoadFrom.html | 19 + content/media/test/test_constants.html | 18 +- .../media/test/test_streams_srcObject.html | 2 +- content/media/test/test_volume.html | 18 +- dom/webidl/HTMLMediaElement.webidl | 181 ++++++ dom/webidl/WebIDL.mk | 1 + 9 files changed, 786 insertions(+), 186 deletions(-) create mode 100644 content/html/content/test/test_mozLoadFrom.html create mode 100644 dom/webidl/HTMLMediaElement.webidl diff --git a/content/html/content/public/HTMLMediaElement.h b/content/html/content/public/HTMLMediaElement.h index 18b846859498..1c279333e6ac 100644 --- a/content/html/content/public/HTMLMediaElement.h +++ b/content/html/content/public/HTMLMediaElement.h @@ -27,6 +27,8 @@ #include "DecoderTraits.h" #include "MediaMetadataManager.h" #include "AudioChannelAgent.h" +#include "mozilla/Attributes.h" +#include "mozilla/ErrorResult.h" // Define to output information on decoding and painting framerate /* #define DEBUG_FRAME_RATE 1 */ @@ -42,6 +44,8 @@ class MediaDecoder; namespace mozilla { namespace dom { +class MediaError; + class HTMLMediaElement : public nsGenericHTMLElement, public nsIObserver, public MediaDecoderOwner, @@ -86,9 +90,9 @@ public: nsGenericHTMLElement) virtual bool ParseAttribute(int32_t aNamespaceID, - nsIAtom* aAttribute, - const nsAString& aValue, - nsAttrValue& aResult); + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult); // SetAttr override. C++ is stupid, so have to override both // overloaded methods. nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, @@ -318,12 +322,194 @@ public: */ virtual void FireTimeUpdate(bool aPeriodic) MOZ_FINAL MOZ_OVERRIDE; - MediaStream* GetSrcMediaStream() + MediaStream* GetSrcMediaStream() const { NS_ASSERTION(mSrcStream, "Don't call this when not playing a stream"); return mSrcStream->GetStream(); } + // WebIDL + + MediaError* GetError() const + { + return mError; + } + + // XPCOM GetSrc() is OK + void SetSrc(const nsAString& aSrc, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::src, aSrc, aRv); + } + + // XPCOM GetCurrentSrc() is OK + + // XPCOM GetCrossorigin() is OK + void SetCrossorigin(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::crossorigin, aValue, aRv); + } + + uint16_t NetworkState() const + { + return mNetworkState; + } + + // XPCOM GetPreload() is OK + void SetPreload(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::preload, aValue, aRv); + } + + already_AddRefed Buffered() const; + + // XPCOM Load() is OK + + // XPCOM CanPlayType() is OK + + uint16_t ReadyState() const + { + return mReadyState; + } + + bool Seeking() const; + + double CurrentTime() const; + + void SetCurrentTime(double aCurrentTime, ErrorResult& aRv); + + double Duration() const; + + bool Paused() const + { + return mPaused; + } + + double DefaultPlaybackRate() const + { + return mDefaultPlaybackRate; + } + + void SetDefaultPlaybackRate(double aDefaultPlaybackRate, ErrorResult& aRv); + + double PlaybackRate() const + { + return mPlaybackRate; + } + + void SetPlaybackRate(double aPlaybackRate, ErrorResult& aRv); + + already_AddRefed Played(); + + already_AddRefed Seekable() const; + + bool Ended(); + + bool Autoplay() const + { + return GetBoolAttr(nsGkAtoms::autoplay); + } + + void SetAutoplay(bool aValue, ErrorResult& aRv) + { + SetHTMLBoolAttr(nsGkAtoms::autoplay, aValue, aRv); + } + + bool Loop() const + { + return GetBoolAttr(nsGkAtoms::loop); + } + + void SetLoop(bool aValue, ErrorResult& aRv) + { + SetHTMLBoolAttr(nsGkAtoms::loop, aValue, aRv); + } + + void Play(ErrorResult& aRv); + + void Pause(ErrorResult& aRv); + + bool Controls() const + { + return GetBoolAttr(nsGkAtoms::controls); + } + + void SetControls(bool aValue, ErrorResult& aRv) + { + SetHTMLBoolAttr(nsGkAtoms::controls, aValue, aRv); + } + + double Volume() const + { + return mVolume; + } + + void SetVolume(double aVolume, ErrorResult& aRv); + + bool Muted() const + { + return mMuted; + } + + // XPCOM SetMuted() is OK + + bool DefaultMuted() const + { + return GetBoolAttr(nsGkAtoms::muted); + } + + void SetDefaultMuted(bool aMuted, ErrorResult& aRv) + { + SetHTMLBoolAttr(nsGkAtoms::muted, aMuted, aRv); + } + + already_AddRefed GetMozSrcObject() const; + + void SetMozSrcObject(DOMMediaStream& aValue); + + double InitialTime(); + + bool MozPreservesPitch() const + { + return mPreservesPitch; + } + + // XPCOM MozPreservesPitch() is OK + + bool MozAutoplayEnabled() const + { + return mAutoplayEnabled; + } + + already_AddRefed MozCaptureStream(ErrorResult& aRv); + + already_AddRefed MozCaptureStreamUntilEnded(ErrorResult& aRv); + + bool MozAudioCaptured() const + { + return mAudioCaptured; + } + + uint32_t GetMozChannels(ErrorResult& aRv) const; + + uint32_t GetMozSampleRate(ErrorResult& aRv) const; + + uint32_t GetMozFrameBufferLength(ErrorResult& aRv) const; + + void SetMozFrameBufferLength(uint32_t aValue, ErrorResult& aRv); + + JSObject* MozGetMetadata(JSContext* aCx, ErrorResult& aRv); + + void MozLoadFrom(HTMLMediaElement& aOther, ErrorResult& aRv); + + double MozFragmentEnd(); + + // XPCOM GetMozAudioChannelType() is OK + + void SetMozAudioChannelType(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::mozaudiochannel, aValue, aRv); + } + protected: class MediaLoadListener; class StreamListener; @@ -335,7 +521,7 @@ protected: public: WakeLockBoolWrapper(bool val = false) : mValue(val), mOuter(NULL), mWakeLock(NULL) {} void SetOuter(HTMLMediaElement* outer) { mOuter = outer; } - operator bool() { return mValue; } + operator bool() const { return mValue; } WakeLockBoolWrapper& operator=(bool val); bool operator !() const { return !mValue; } private: @@ -654,7 +840,7 @@ protected: nsCOMPtr mChannel; // Error attribute - nsCOMPtr mError; + nsRefPtr mError; // The current media load ID. This is incremented every time we start a // new load. Async events note the ID when they're first sent, and only fire diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp index 61d5d7f229c8..5436719aaf44 100644 --- a/content/html/content/src/HTMLMediaElement.cpp +++ b/content/html/content/src/HTMLMediaElement.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/HTMLMediaElement.h" +#include "mozilla/dom/HTMLMediaElementBinding.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/Util.h" @@ -442,21 +443,35 @@ NS_IMPL_BOOL_ATTR(HTMLMediaElement, DefaultMuted, muted) NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMediaElement, Preload, preload, NULL) NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMediaElement, MozAudioChannelType, mozaudiochannel, "normal") -NS_IMETHODIMP -HTMLMediaElement::GetMozSrcObject(nsIDOMMediaStream** aStream) +already_AddRefed +HTMLMediaElement::GetMozSrcObject() const { NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetStream(), "MediaStream should have been set up properly"); nsRefPtr stream = mSrcAttrStream; + return stream.forget(); +} + +NS_IMETHODIMP +HTMLMediaElement::GetMozSrcObject(nsIDOMMediaStream** aStream) +{ + nsRefPtr stream = GetMozSrcObject(); stream.forget(aStream); return NS_OK; } +void +HTMLMediaElement::SetMozSrcObject(DOMMediaStream& aValue) +{ + mSrcAttrStream = &aValue; + Load(); +} + NS_IMETHODIMP HTMLMediaElement::SetMozSrcObject(nsIDOMMediaStream* aStream) { - mSrcAttrStream = static_cast(aStream); - Load(); + DOMMediaStream* stream = static_cast(aStream); + SetMozSrcObject(*stream); return NS_OK; } @@ -477,13 +492,23 @@ NS_IMETHODIMP HTMLMediaElement::GetError(nsIDOMMediaError * *aError) } /* readonly attribute boolean ended; */ -NS_IMETHODIMP HTMLMediaElement::GetEnded(bool *aEnded) +bool +HTMLMediaElement::Ended() { if (mSrcStream) { - *aEnded = GetSrcMediaStream()->IsFinished(); - } else if (mDecoder) { - *aEnded = mDecoder->IsEnded(); + return GetSrcMediaStream()->IsFinished(); } + + if (mDecoder) { + return mDecoder->IsEnded(); + } + + return false; +} + +NS_IMETHODIMP HTMLMediaElement::GetEnded(bool* aEnded) +{ + *aEnded = Ended(); return NS_OK; } @@ -497,16 +522,15 @@ NS_IMETHODIMP HTMLMediaElement::GetCurrentSrc(nsAString & aCurrentSrc) } /* readonly attribute unsigned short networkState; */ -NS_IMETHODIMP HTMLMediaElement::GetNetworkState(uint16_t *aNetworkState) +NS_IMETHODIMP HTMLMediaElement::GetNetworkState(uint16_t* aNetworkState) { - *aNetworkState = mNetworkState; - + *aNetworkState = NetworkState(); return NS_OK; } nsresult -HTMLMediaElement::OnChannelRedirect(nsIChannel *aChannel, - nsIChannel *aNewChannel, +HTMLMediaElement::OnChannelRedirect(nsIChannel* aChannel, + nsIChannel* aNewChannel, uint32_t aFlags) { NS_ASSERTION(aChannel == mChannel, "Channels should match!"); @@ -682,6 +706,7 @@ NS_IMETHODIMP HTMLMediaElement::Load() { if (mIsRunningLoadMethod) return NS_OK; + SetPlayedOrSeeked(false); mIsRunningLoadMethod = true; AbortExistingLoads(); @@ -689,6 +714,7 @@ NS_IMETHODIMP HTMLMediaElement::Load() QueueSelectResourceTask(); ResetState(); mIsRunningLoadMethod = false; + return NS_OK; } @@ -701,7 +727,7 @@ void HTMLMediaElement::ResetState() } } -static bool HasSourceChildren(nsIContent *aElement) +static bool HasSourceChildren(nsIContent* aElement) { for (nsIContent* child = aElement->GetFirstChild(); child; @@ -1142,8 +1168,8 @@ nsresult HTMLMediaElement::LoadResource() return NS_OK; } -nsresult HTMLMediaElement::LoadWithChannel(nsIChannel *aChannel, - nsIStreamListener **aListener) +nsresult HTMLMediaElement::LoadWithChannel(nsIChannel* aChannel, + nsIStreamListener** aListener) { NS_ENSURE_ARG_POINTER(aChannel); NS_ENSURE_ARG_POINTER(aListener); @@ -1173,79 +1199,110 @@ nsresult HTMLMediaElement::LoadWithChannel(nsIChannel *aChannel, return NS_OK; } -NS_IMETHODIMP HTMLMediaElement::MozLoadFrom(nsIDOMHTMLMediaElement* aOther) +void +HTMLMediaElement::MozLoadFrom(HTMLMediaElement& aOther, ErrorResult& aRv) { - NS_ENSURE_ARG_POINTER(aOther); - // Make sure we don't reenter during synchronous abort events. - if (mIsRunningLoadMethod) - return NS_OK; + if (mIsRunningLoadMethod) { + return; + } + mIsRunningLoadMethod = true; AbortExistingLoads(); mIsRunningLoadMethod = false; - nsCOMPtr content = do_QueryInterface(aOther); - HTMLMediaElement* other = static_cast(content.get()); - if (!other || !other->mDecoder) - return NS_OK; + if (!aOther.mDecoder) { + return; + } ChangeDelayLoadStatus(true); - mLoadingSrc = other->mLoadingSrc; - nsresult rv = InitializeDecoderAsClone(other->mDecoder); - if (NS_FAILED(rv)) { + mLoadingSrc = aOther.mLoadingSrc; + aRv = InitializeDecoderAsClone(aOther.mDecoder); + if (aRv.Failed()) { ChangeDelayLoadStatus(false); - return rv; + return; } SetPlaybackRate(mDefaultPlaybackRate); DispatchAsyncEvent(NS_LITERAL_STRING("loadstart")); +} - return NS_OK; +NS_IMETHODIMP HTMLMediaElement::MozLoadFrom(nsIDOMHTMLMediaElement* aOther) +{ + NS_ENSURE_ARG_POINTER(aOther); + + nsCOMPtr content = do_QueryInterface(aOther); + HTMLMediaElement* other = static_cast(content.get()); + + if (!other) { + return NS_ERROR_FAILURE; + } + + ErrorResult rv; + MozLoadFrom(*other, rv); + + return rv.ErrorCode(); } /* readonly attribute unsigned short readyState; */ -NS_IMETHODIMP HTMLMediaElement::GetReadyState(uint16_t *aReadyState) +NS_IMETHODIMP HTMLMediaElement::GetReadyState(uint16_t* aReadyState) { - *aReadyState = mReadyState; + *aReadyState = ReadyState(); return NS_OK; } /* readonly attribute boolean seeking; */ -NS_IMETHODIMP HTMLMediaElement::GetSeeking(bool *aSeeking) +bool +HTMLMediaElement::Seeking() const { - *aSeeking = mDecoder && mDecoder->IsSeeking(); + return mDecoder && mDecoder->IsSeeking(); +} +NS_IMETHODIMP HTMLMediaElement::GetSeeking(bool* aSeeking) +{ + *aSeeking = Seeking(); return NS_OK; } /* attribute double currentTime; */ -NS_IMETHODIMP HTMLMediaElement::GetCurrentTime(double *aCurrentTime) +double +HTMLMediaElement::CurrentTime() const { if (mSrcStream) { - *aCurrentTime = MediaTimeToSeconds(GetSrcMediaStream()->GetCurrentTime()); - } else if (mDecoder) { - *aCurrentTime = mDecoder->GetCurrentTime(); - } else { - *aCurrentTime = 0.0; + return MediaTimeToSeconds(GetSrcMediaStream()->GetCurrentTime()); } + + if (mDecoder) { + return mDecoder->GetCurrentTime(); + } + + return 0.0; +} + +NS_IMETHODIMP HTMLMediaElement::GetCurrentTime(double* aCurrentTime) +{ + *aCurrentTime = CurrentTime(); return NS_OK; } -NS_IMETHODIMP HTMLMediaElement::SetCurrentTime(double aCurrentTime) +void +HTMLMediaElement::SetCurrentTime(double aCurrentTime, ErrorResult& aRv) { + MOZ_ASSERT(aCurrentTime == aCurrentTime); + StopSuspendingAfterFirstFrame(); if (mSrcStream) { // do nothing since streams aren't seekable; we effectively clamp to // the current time. - return NS_ERROR_DOM_INVALID_STATE_ERR; + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; } if (mCurrentPlayRangeStart != -1.0) { - double rangeEndTime = 0; - GetCurrentTime(&rangeEndTime); + double rangeEndTime = CurrentTime(); 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) { @@ -1255,18 +1312,14 @@ NS_IMETHODIMP HTMLMediaElement::SetCurrentTime(double aCurrentTime) if (!mDecoder) { LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: no decoder", this, aCurrentTime)); - return NS_ERROR_DOM_INVALID_STATE_ERR; + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; } if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) { LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: no source", this, aCurrentTime)); - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - // 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; + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; } // Clamp the time to [0, duration] as required by the spec. @@ -1280,54 +1333,78 @@ NS_IMETHODIMP HTMLMediaElement::SetCurrentTime(double aCurrentTime) // The media backend is responsible for dispatching the timeupdate // event if it changes the playback position as a result of the seek. LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) starting seek", this, aCurrentTime)); - nsresult rv = mDecoder->Seek(clampedTime); + aRv = mDecoder->Seek(clampedTime); // Start a new range at position we seeked to. mCurrentPlayRangeStart = mDecoder->GetCurrentTime(); // We changed whether we're seeking so we need to AddRemoveSelfReference. AddRemoveSelfReference(); +} - return rv; +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(); } /* readonly attribute double duration; */ -NS_IMETHODIMP HTMLMediaElement::GetDuration(double *aDuration) +double +HTMLMediaElement::Duration() const { if (mSrcStream) { - *aDuration = std::numeric_limits::infinity(); - } else if (mDecoder) { - *aDuration = mDecoder->GetDuration(); - } else { - *aDuration = std::numeric_limits::quiet_NaN(); + return std::numeric_limits::infinity(); } + + if (mDecoder) { + return mDecoder->GetDuration(); + } + + return std::numeric_limits::quiet_NaN(); +} + +NS_IMETHODIMP HTMLMediaElement::GetDuration(double* aDuration) +{ + *aDuration = Duration(); return NS_OK; } -/* readonly attribute nsIDOMHTMLTimeRanges seekable; */ -NS_IMETHODIMP HTMLMediaElement::GetSeekable(nsIDOMTimeRanges** aSeekable) +already_AddRefed +HTMLMediaElement::Seekable() const { nsRefPtr ranges = new TimeRanges(); if (mDecoder && mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) { mDecoder->GetSeekable(ranges); } + return ranges.forget(); +} + +/* readonly attribute nsIDOMHTMLTimeRanges seekable; */ +NS_IMETHODIMP HTMLMediaElement::GetSeekable(nsIDOMTimeRanges** aSeekable) +{ + nsRefPtr ranges = Seekable(); ranges.forget(aSeekable); return NS_OK; } - /* readonly attribute boolean paused; */ -NS_IMETHODIMP HTMLMediaElement::GetPaused(bool *aPaused) +NS_IMETHODIMP HTMLMediaElement::GetPaused(bool* aPaused) { - *aPaused = mPaused; + *aPaused = Paused(); return NS_OK; } -/* readonly attribute nsIDOMHTMLTimeRanges played; */ -NS_IMETHODIMP HTMLMediaElement::GetPlayed(nsIDOMTimeRanges** aPlayed) +already_AddRefed +HTMLMediaElement::Played() { - TimeRanges* ranges = new TimeRanges(); - NS_ADDREF(*aPlayed = ranges); + nsRefPtr ranges = new TimeRanges(); uint32_t timeRangeCount = 0; mPlayed.GetLength(&timeRangeCount); @@ -1340,25 +1417,34 @@ NS_IMETHODIMP HTMLMediaElement::GetPlayed(nsIDOMTimeRanges** aPlayed) } if (mCurrentPlayRangeStart != -1.0) { - double now = 0.0; - GetCurrentTime(&now); + double now = CurrentTime(); if (mCurrentPlayRangeStart != now) { ranges->Add(mCurrentPlayRangeStart, now); } } ranges->Normalize(); + return ranges.forget(); +} +/* readonly attribute nsIDOMHTMLTimeRanges played; */ +NS_IMETHODIMP HTMLMediaElement::GetPlayed(nsIDOMTimeRanges** aPlayed) +{ + nsRefPtr ranges = Played(); + ranges.forget(aPlayed); return NS_OK; } /* void pause (); */ -NS_IMETHODIMP HTMLMediaElement::Pause() +void +HTMLMediaElement::Pause(ErrorResult& aRv) { if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) { LOG(PR_LOG_DEBUG, ("Loading due to Pause()")); - nsresult rv = Load(); - NS_ENSURE_SUCCESS(rv, rv); + aRv = Load(); + if (aRv.Failed()) { + return; + } } else if (mDecoder) { mDecoder->Pause(); } @@ -1376,25 +1462,32 @@ NS_IMETHODIMP HTMLMediaElement::Pause() FireTimeUpdate(false); DispatchAsyncEvent(NS_LITERAL_STRING("pause")); } +} - return NS_OK; +NS_IMETHODIMP HTMLMediaElement::Pause() +{ + ErrorResult rv; + Pause(rv); + return rv.ErrorCode(); } /* attribute double volume; */ -NS_IMETHODIMP HTMLMediaElement::GetVolume(double *aVolume) +NS_IMETHODIMP HTMLMediaElement::GetVolume(double* aVolume) { - *aVolume = mVolume; - + *aVolume = Volume(); return NS_OK; } -NS_IMETHODIMP HTMLMediaElement::SetVolume(double aVolume) +void +HTMLMediaElement::SetVolume(double aVolume, ErrorResult& aRv) { - if (!(aVolume >= 0.0 && aVolume <= 1.0)) - return NS_ERROR_DOM_INDEX_SIZE_ERR; + if (aVolume < 0.0 || aVolume > 1.0) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return; + } if (aVolume == mVolume) - return NS_OK; + return; mVolume = aVolume; @@ -1409,30 +1502,51 @@ NS_IMETHODIMP HTMLMediaElement::SetVolume(double aVolume) } DispatchAsyncEvent(NS_LITERAL_STRING("volumechange")); +} - return NS_OK; +NS_IMETHODIMP HTMLMediaElement::SetVolume(double aVolume) +{ + ErrorResult rv; + SetVolume(aVolume, rv); + return rv.ErrorCode(); +} + +uint32_t +HTMLMediaElement::GetMozChannels(ErrorResult& aRv) const +{ + if (!mDecoder && !mAudioStream) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return 0; + } + + return mChannels; } NS_IMETHODIMP -HTMLMediaElement::GetMozChannels(uint32_t *aMozChannels) +HTMLMediaElement::GetMozChannels(uint32_t* aMozChannels) +{ + ErrorResult rv; + *aMozChannels = GetMozChannels(rv); + return rv.ErrorCode(); +} + +uint32_t +HTMLMediaElement::GetMozSampleRate(ErrorResult& aRv) const { if (!mDecoder && !mAudioStream) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return 0; } - *aMozChannels = mChannels; - return NS_OK; + return mRate; } NS_IMETHODIMP -HTMLMediaElement::GetMozSampleRate(uint32_t *aMozSampleRate) +HTMLMediaElement::GetMozSampleRate(uint32_t* aMozSampleRate) { - if (!mDecoder && !mAudioStream) { - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - *aMozSampleRate = mRate; - return NS_OK; + ErrorResult rv; + *aMozSampleRate = GetMozSampleRate(rv); + return rv.ErrorCode(); } // Helper struct with arguments for our hash iterator. @@ -1467,57 +1581,90 @@ HTMLMediaElement::BuildObjectFromTags(nsCStringHashKey::KeyType aKey, return PL_DHASH_NEXT; } -NS_IMETHODIMP -HTMLMediaElement::MozGetMetadata(JSContext* cx, JS::Value* aValue) +JSObject* +HTMLMediaElement::MozGetMetadata(JSContext* cx, ErrorResult& aRv) { if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; } JSObject* tags = JS_NewObject(cx, NULL, NULL, NULL); if (!tags) { - return NS_ERROR_FAILURE; + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; } if (mTags) { MetadataIterCx iter = {cx, tags, false}; mTags->EnumerateRead(BuildObjectFromTags, static_cast(&iter)); if (iter.error) { NS_WARNING("couldn't create metadata object!"); - return NS_ERROR_FAILURE; + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; } } - *aValue = OBJECT_TO_JSVAL(tags); - return NS_OK; + return tags; } NS_IMETHODIMP -HTMLMediaElement::GetMozFrameBufferLength(uint32_t *aMozFrameBufferLength) +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 { // The framebuffer (via MozAudioAvailable events) is only available // when reading vs. writing audio directly. if (!mDecoder) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return 0; } - *aMozFrameBufferLength = mDecoder->GetFrameBufferLength(); - return NS_OK; + return mDecoder->GetFrameBufferLength(); +} + +NS_IMETHODIMP +HTMLMediaElement::GetMozFrameBufferLength(uint32_t* aMozFrameBufferLength) +{ + ErrorResult rv; + *aMozFrameBufferLength = GetMozFrameBufferLength(rv); + return rv.ErrorCode(); +} + +void +HTMLMediaElement::SetMozFrameBufferLength(uint32_t aMozFrameBufferLength, ErrorResult& aRv) +{ + if (!mDecoder) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + + aRv = mDecoder->RequestFrameBufferLength(aMozFrameBufferLength); } NS_IMETHODIMP HTMLMediaElement::SetMozFrameBufferLength(uint32_t aMozFrameBufferLength) { - if (!mDecoder) - return NS_ERROR_DOM_INVALID_STATE_ERR; - - return mDecoder->RequestFrameBufferLength(aMozFrameBufferLength); + ErrorResult rv; + SetMozFrameBufferLength(aMozFrameBufferLength, rv); + return rv.ErrorCode(); } /* attribute boolean muted; */ -NS_IMETHODIMP HTMLMediaElement::GetMuted(bool *aMuted) +NS_IMETHODIMP HTMLMediaElement::GetMuted(bool* aMuted) { - *aMuted = mMuted; - + *aMuted = Muted(); return NS_OK; } @@ -1543,7 +1690,6 @@ NS_IMETHODIMP HTMLMediaElement::SetMuted(bool aMuted) SetMutedInternal(aMuted); DispatchAsyncEvent(NS_LITERAL_STRING("volumechange")); - return NS_OK; } @@ -1575,27 +1721,47 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded) return result.forget(); } +already_AddRefed +HTMLMediaElement::MozCaptureStream(ErrorResult& aRv) +{ + nsRefPtr stream = CaptureStreamInternal(false); + if (!stream) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + return stream.forget(); +} + NS_IMETHODIMP HTMLMediaElement::MozCaptureStream(nsIDOMMediaStream** aStream) { - *aStream = CaptureStreamInternal(false).get(); - if (!*aStream) { - return NS_ERROR_FAILURE; + ErrorResult rv; + *aStream = MozCaptureStream(rv).get(); + return rv.ErrorCode(); +} + +already_AddRefed +HTMLMediaElement::MozCaptureStreamUntilEnded(ErrorResult& aRv) +{ + nsRefPtr stream = CaptureStreamInternal(true); + if (!stream) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; } - return NS_OK; + + return stream.forget(); } NS_IMETHODIMP HTMLMediaElement::MozCaptureStreamUntilEnded(nsIDOMMediaStream** aStream) { - *aStream = CaptureStreamInternal(true).get(); - if (!*aStream) { - return NS_ERROR_FAILURE; - } - return NS_OK; + ErrorResult rv; + *aStream = MozCaptureStreamUntilEnded(rv).get(); + return rv.ErrorCode(); } -NS_IMETHODIMP HTMLMediaElement::GetMozAudioCaptured(bool *aCaptured) +NS_IMETHODIMP HTMLMediaElement::GetMozAudioCaptured(bool* aCaptured) { - *aCaptured = mAudioCaptured; + *aCaptured = MozAudioCaptured(); return NS_OK; } @@ -1838,14 +2004,17 @@ void HTMLMediaElement::SetPlayedOrSeeked(bool aValue) NS_FRAME_IS_DIRTY); } -NS_IMETHODIMP HTMLMediaElement::Play() +void +HTMLMediaElement::Play(ErrorResult& aRv) { StopSuspendingAfterFirstFrame(); SetPlayedOrSeeked(true); if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) { - nsresult rv = Load(); - NS_ENSURE_SUCCESS(rv, rv); + aRv = Load(); + if (aRv.Failed()) { + return; + } } if (mSuspendedForPreloadNone) { ResumeLoad(PRELOAD_ENOUGH); @@ -1857,13 +2026,15 @@ NS_IMETHODIMP HTMLMediaElement::Play() SetCurrentTime(0); } if (!mPausedForInactiveDocumentOrChannel) { - nsresult rv = mDecoder->Play(); - NS_ENSURE_SUCCESS(rv, rv); + aRv = mDecoder->Play(); + if (aRv.Failed()) { + return; + } } } if (mCurrentPlayRangeStart == -1.0) { - GetCurrentTime(&mCurrentPlayRangeStart); + mCurrentPlayRangeStart = CurrentTime(); } // TODO: If the playback has ended, then the user agent must set @@ -1897,8 +2068,13 @@ NS_IMETHODIMP HTMLMediaElement::Play() // and our preload status. AddRemoveSelfReference(); UpdatePreloadAction(); +} - return NS_OK; +NS_IMETHODIMP HTMLMediaElement::Play() +{ + ErrorResult rv; + Play(rv); + return rv.ErrorCode(); } HTMLMediaElement::WakeLockBoolWrapper& HTMLMediaElement::WakeLockBoolWrapper::operator=(bool val) { @@ -2008,8 +2184,8 @@ void HTMLMediaElement::DoneCreatingElement() } bool HTMLMediaElement::IsHTMLFocusable(bool aWithMouse, - bool *aIsFocusable, - int32_t *aTabIndex) + bool* aIsFocusable, + int32_t* aTabIndex) { if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) { return true; @@ -2184,8 +2360,8 @@ nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal) return FinishDecoderSetup(decoder, resource, nullptr, aOriginal); } -nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel, - nsIStreamListener **aListener) +nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel* aChannel, + nsIStreamListener** aListener) { NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set"); NS_ASSERTION(mDecoder == nullptr, "Shouldn't have a decoder"); @@ -2219,7 +2395,7 @@ nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel, nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder, MediaResource* aStream, - nsIStreamListener **aListener, + nsIStreamListener** aListener, MediaDecoder* aCloneDonor) { mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; @@ -2851,7 +3027,7 @@ void HTMLMediaElement::NotifyAutoplayDataReady() if (mDecoder) { SetPlayedOrSeeked(true); if (mCurrentPlayRangeStart == -1.0) { - GetCurrentTime(&mCurrentPlayRangeStart); + mCurrentPlayRangeStart = CurrentTime(); } mDecoder->Play(); } else if (mSrcStream) { @@ -3268,7 +3444,8 @@ HTMLMediaElement::CopyInnerTo(Element* aDest) return rv; } -nsresult HTMLMediaElement::GetBuffered(nsIDOMTimeRanges** aBuffered) +already_AddRefed +HTMLMediaElement::Buffered() const { nsRefPtr ranges = new TimeRanges(); if (mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING && mDecoder) { @@ -3276,6 +3453,12 @@ nsresult HTMLMediaElement::GetBuffered(nsIDOMTimeRanges** aBuffered) // time ranges we found up till the error. mDecoder->GetBuffered(ranges); } + return ranges.forget(); +} + +nsresult HTMLMediaElement::GetBuffered(nsIDOMTimeRanges** aBuffered) +{ + nsRefPtr ranges = Buffered(); ranges.forget(aBuffered); return NS_OK; } @@ -3309,8 +3492,7 @@ void HTMLMediaElement::FireTimeUpdate(bool aPeriodic) NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); TimeStamp now = TimeStamp::Now(); - double time = 0; - GetCurrentTime(&time); + double time = CurrentTime(); // Fire a timeupdate event if this is not a periodic update (i.e. it's a // timeupdate event mandated by the spec), or if it's a periodic update @@ -3342,31 +3524,41 @@ void HTMLMediaElement::GetCurrentSpec(nsCString& aString) } /* attribute double initialTime; */ -NS_IMETHODIMP HTMLMediaElement::GetInitialTime(double *aTime) +double +HTMLMediaElement::InitialTime() { // If there is no start fragment then the initalTime is zero. // Clamp to duration if it is greater than duration. - double duration = 0.0; - nsresult rv = GetDuration(&duration); - NS_ENSURE_SUCCESS(rv, rv); + double duration = Duration(); - *aTime = mFragmentStart < 0.0 ? 0.0 : mFragmentStart; - if (*aTime > duration) { - *aTime = duration; + double time = mFragmentStart < 0.0 ? 0.0 : mFragmentStart; + if (time > duration) { + time = duration; } + + return time; +} + +NS_IMETHODIMP HTMLMediaElement::GetInitialTime(double* aTime) +{ + *aTime = InitialTime(); return NS_OK; } /* attribute double mozFragmentEnd; */ -NS_IMETHODIMP HTMLMediaElement::GetMozFragmentEnd(double *aTime) +double +HTMLMediaElement::MozFragmentEnd() { - double duration = 0.0; - nsresult rv = GetDuration(&duration); - NS_ENSURE_SUCCESS(rv, rv); + double duration = Duration(); // If there is no end fragment, or the fragment end is greater than the // duration, return the duration. - *aTime = (mFragmentEnd < 0.0 || mFragmentEnd > duration) ? duration : mFragmentEnd; + return (mFragmentEnd < 0.0 || mFragmentEnd > duration) ? duration : mFragmentEnd; +} + +NS_IMETHODIMP HTMLMediaElement::GetMozFragmentEnd(double* aTime) +{ + *aTime = MozFragmentEnd(); return NS_OK; } @@ -3394,34 +3586,44 @@ static double ClampPlaybackRate(double aPlaybackRate) /* attribute double defaultPlaybackRate; */ NS_IMETHODIMP HTMLMediaElement::GetDefaultPlaybackRate(double* aDefaultPlaybackRate) { - *aDefaultPlaybackRate = mDefaultPlaybackRate; + *aDefaultPlaybackRate = DefaultPlaybackRate(); return NS_OK; } -NS_IMETHODIMP HTMLMediaElement::SetDefaultPlaybackRate(double aDefaultPlaybackRate) +void +HTMLMediaElement::SetDefaultPlaybackRate(double aDefaultPlaybackRate, ErrorResult& aRv) { if (aDefaultPlaybackRate < 0) { - return NS_ERROR_NOT_IMPLEMENTED; + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); + return; } mDefaultPlaybackRate = ClampPlaybackRate(aDefaultPlaybackRate); DispatchAsyncEvent(NS_LITERAL_STRING("ratechange")); - return NS_OK; +} + +NS_IMETHODIMP HTMLMediaElement::SetDefaultPlaybackRate(double aDefaultPlaybackRate) +{ + ErrorResult rv; + SetDefaultPlaybackRate(aDefaultPlaybackRate, rv); + return rv.ErrorCode(); } /* attribute double playbackRate; */ NS_IMETHODIMP HTMLMediaElement::GetPlaybackRate(double* aPlaybackRate) { - *aPlaybackRate = mPlaybackRate; + *aPlaybackRate = PlaybackRate(); return NS_OK; } -NS_IMETHODIMP HTMLMediaElement::SetPlaybackRate(double aPlaybackRate) +void +HTMLMediaElement::SetPlaybackRate(double aPlaybackRate, ErrorResult& aRv) { // Changing the playback rate of a media that has more than two channels is // not supported. if (aPlaybackRate < 0 || (mChannels > 2 && aPlaybackRate != 1.0)) { - return NS_ERROR_NOT_IMPLEMENTED; + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); + return; } mPlaybackRate = ClampPlaybackRate(aPlaybackRate); @@ -3440,13 +3642,19 @@ NS_IMETHODIMP HTMLMediaElement::SetPlaybackRate(double aPlaybackRate) mDecoder->SetPlaybackRate(mPlaybackRate); } DispatchAsyncEvent(NS_LITERAL_STRING("ratechange")); - return NS_OK; +} + +NS_IMETHODIMP HTMLMediaElement::SetPlaybackRate(double aPlaybackRate) +{ + ErrorResult rv; + SetPlaybackRate(aPlaybackRate, rv); + return rv.ErrorCode(); } /* attribute bool mozPreservesPitch; */ NS_IMETHODIMP HTMLMediaElement::GetMozPreservesPitch(bool* aPreservesPitch) { - *aPreservesPitch = mPreservesPitch; + *aPreservesPitch = MozPreservesPitch(); return NS_OK; } diff --git a/content/html/content/test/Makefile.in b/content/html/content/test/Makefile.in index 77b796a85d05..292987354d0c 100644 --- a/content/html/content/test/Makefile.in +++ b/content/html/content/test/Makefile.in @@ -353,6 +353,11 @@ MOCHITEST_FILES = \ test_formData.html \ $(NULL) +ifdef MOZ_MEDIA +MOCHITEST_FILES += \ + test_mozLoadFrom.html \ + $(NULL) +endif MOCHITEST_BROWSER_FILES = \ browser_bug649778.js \ diff --git a/content/html/content/test/test_mozLoadFrom.html b/content/html/content/test/test_mozLoadFrom.html new file mode 100644 index 000000000000..3b100be41a11 --- /dev/null +++ b/content/html/content/test/test_mozLoadFrom.html @@ -0,0 +1,19 @@ + + + + Test for mozLoadFrom + + + + + + + diff --git a/content/media/test/test_constants.html b/content/media/test/test_constants.html index 21044e836fdb..bbc1b1fffcae 100644 --- a/content/media/test/test_constants.html +++ b/content/media/test/test_constants.html @@ -156,15 +156,15 @@ is(HTMLElement.prototype.MEDIA_ERR_ABORTED, undefined); is(HTMLElement.prototype.MEDIA_ERR_NETWORK, undefined); is(HTMLElement.prototype.MEDIA_ERR_DECODE, undefined); is(HTMLElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined); -todo_is(HTMLMediaElement.prototype.NETWORK_EMPTY, 0, "HTMLMediaElement.prototype.NETWORK_EMPTY"); -todo_is(HTMLMediaElement.prototype.NETWORK_IDLE, 1, "HTMLMediaElement.prototype.NETWORK_IDLE"); -todo_is(HTMLMediaElement.prototype.NETWORK_LOADING, 2, "HTMLMediaElement.prototype.NETWORK_LOADING"); -todo_is(HTMLMediaElement.prototype.NETWORK_NO_SOURCE, 3, "HTMLMediaElement.prototype.NETWORK_NO_SOURCE"); -todo_is(HTMLMediaElement.prototype.HAVE_NOTHING, 0, "HTMLMediaElement.prototype.HAVE_NOTHING"); -todo_is(HTMLMediaElement.prototype.HAVE_METADATA, 1, "HTMLMediaElement.prototype.HAVE_METADATA"); -todo_is(HTMLMediaElement.prototype.HAVE_CURRENT_DATA, 2, "HTMLMediaElement.prototype.HAVE_CURRENT_DATA"); -todo_is(HTMLMediaElement.prototype.HAVE_FUTURE_DATA, 3, "HTMLMediaElement.prototype.HAVE_FUTURE_DATA"); -todo_is(HTMLMediaElement.prototype.HAVE_ENOUGH_DATA, 4, "HTMLMediaElement.prototype.HAVE_ENOUGH_DATA"); +is(HTMLMediaElement.prototype.NETWORK_EMPTY, 0, "HTMLMediaElement.prototype.NETWORK_EMPTY"); +is(HTMLMediaElement.prototype.NETWORK_IDLE, 1, "HTMLMediaElement.prototype.NETWORK_IDLE"); +is(HTMLMediaElement.prototype.NETWORK_LOADING, 2, "HTMLMediaElement.prototype.NETWORK_LOADING"); +is(HTMLMediaElement.prototype.NETWORK_NO_SOURCE, 3, "HTMLMediaElement.prototype.NETWORK_NO_SOURCE"); +is(HTMLMediaElement.prototype.HAVE_NOTHING, 0, "HTMLMediaElement.prototype.HAVE_NOTHING"); +is(HTMLMediaElement.prototype.HAVE_METADATA, 1, "HTMLMediaElement.prototype.HAVE_METADATA"); +is(HTMLMediaElement.prototype.HAVE_CURRENT_DATA, 2, "HTMLMediaElement.prototype.HAVE_CURRENT_DATA"); +is(HTMLMediaElement.prototype.HAVE_FUTURE_DATA, 3, "HTMLMediaElement.prototype.HAVE_FUTURE_DATA"); +is(HTMLMediaElement.prototype.HAVE_ENOUGH_DATA, 4, "HTMLMediaElement.prototype.HAVE_ENOUGH_DATA"); is(HTMLMediaElement.prototype.MEDIA_ERR_ABORTED, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_ABORTED"); is(HTMLMediaElement.prototype.MEDIA_ERR_NETWORK, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_NETWORK"); is(HTMLMediaElement.prototype.MEDIA_ERR_DECODE, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_DECODE"); diff --git a/content/media/test/test_streams_srcObject.html b/content/media/test/test_streams_srcObject.html index e2d98347afd2..446c5466b41a 100644 --- a/content/media/test/test_streams_srcObject.html +++ b/content/media/test/test_streams_srcObject.html @@ -28,7 +28,7 @@ function doTest() { b.mozSrcObject = "invalid"; ok(false, "Setting mozSrcObject to an invalid value should throw."); } catch (e) { - todo(e instanceof TypeError, "Exception should be a TypeError"); + ok(e instanceof TypeError, "Exception should be a TypeError"); } is(b.mozSrcObject, stream, "Stream not set to invalid value"); is(b.src, newSrc, "src attribute not affected by setting srcObject"); diff --git a/content/media/test/test_volume.html b/content/media/test/test_volume.html index 9e2262237eaa..07f51f52ab24 100644 --- a/content/media/test/test_volume.html +++ b/content/media/test/test_volume.html @@ -13,11 +13,11 @@ diff --git a/dom/webidl/HTMLMediaElement.webidl b/dom/webidl/HTMLMediaElement.webidl new file mode 100644 index 000000000000..c52d03effcba --- /dev/null +++ b/dom/webidl/HTMLMediaElement.webidl @@ -0,0 +1,181 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://www.whatwg.org/specs/web-apps/current-work/#media-elements + * + * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and + * Opera Software ASA. You are granted a license to use, reproduce + * and create derivative works of this document. + */ + +interface HTMLMediaElement : HTMLElement { + + // error state + readonly attribute MediaError? error; + + // network state + [SetterThrows] + attribute DOMString src; + readonly attribute DOMString currentSrc; + + // Bug 847370 - crossOrigin vs crossorigin. + [SetterThrows] + attribute DOMString crossorigin; + const unsigned short NETWORK_EMPTY = 0; + const unsigned short NETWORK_IDLE = 1; + const unsigned short NETWORK_LOADING = 2; + const unsigned short NETWORK_NO_SOURCE = 3; + readonly attribute unsigned short networkState; + [SetterThrows] + attribute DOMString preload; + [Creator] + readonly attribute TimeRanges buffered; + void load(); + DOMString canPlayType(DOMString type); + + // ready state + const unsigned short HAVE_NOTHING = 0; + const unsigned short HAVE_METADATA = 1; + const unsigned short HAVE_CURRENT_DATA = 2; + const unsigned short HAVE_FUTURE_DATA = 3; + const unsigned short HAVE_ENOUGH_DATA = 4; + readonly attribute unsigned short readyState; + readonly attribute boolean seeking; + + // playback state + [SetterThrows] + attribute double currentTime; + // TODO: Bug 847375 - void fastSeek(double time); + readonly attribute unrestricted double duration; + // TODO: Bug 847376 - readonly attribute any startDate; + readonly attribute boolean paused; + [SetterThrows] + attribute double defaultPlaybackRate; + [SetterThrows] + attribute double playbackRate; + [Creator] + readonly attribute TimeRanges played; + [Creator] + readonly attribute TimeRanges seekable; + readonly attribute boolean ended; + [SetterThrows] + attribute boolean autoplay; + [SetterThrows] + attribute boolean loop; + [Throws] + void play(); + [Throws] + void pause(); + + // TODO: Bug 847377 - mediaGroup and MediaController + // media controller + // attribute DOMString mediaGroup; + // attribute MediaController? controller; + + // controls + [SetterThrows] + attribute boolean controls; + [SetterThrows] + attribute double volume; + attribute boolean muted; + [SetterThrows] + attribute boolean defaultMuted; + + // TODO: Bug 847379 + // tracks + //readonly attribute AudioTrackList audioTracks; + //readonly attribute VideoTrackList videoTracks; + //readonly attribute TextTrackList textTracks; + //TextTrack addTextTrack(DOMString kind, optional DOMString label, optional DOMString language); +}; + +// Mozilla extensions: +partial interface HTMLMediaElement { + attribute MediaStream? mozSrcObject; + readonly attribute double initialTime; + attribute boolean mozPreservesPitch; + readonly attribute boolean mozAutoplayEnabled; + + // Mozilla extension: stream capture + [Throws] + MediaStream mozCaptureStream(); + [Throws] + MediaStream mozCaptureStreamUntilEnded(); + readonly attribute boolean mozAudioCaptured; + + // Mozilla extension: extra stream metadata information, used as part + // of MozAudioAvailable events and the mozWriteAudio() method. The + // mozFrameBufferLength method allows for the size of the framebuffer + // used within MozAudioAvailable events to be changed. The new size must + // be between 512 and 16384. The default size, for a media element with + // audio is (mozChannels * 1024). + [GetterThrows] + readonly attribute unsigned long mozChannels; + [GetterThrows] + readonly attribute unsigned long mozSampleRate; + [Throws] + attribute unsigned long mozFrameBufferLength; + + // Mozilla extension: return embedded metadata from the stream as a + // JSObject with key:value pairs for each tag. This can be used by + // player interfaces to display the song title, artist, etc. + [Throws] + object? mozGetMetadata(); + + // Mozilla extension: load data from another media element. This is like + // load() but we don't run the resource selection algorithm; instead + // we just set our source to other's currentSrc. This is optimized + // so that this element will get access to all of other's cached/ + // buffered data. In fact any future data downloaded by this element or + // other will be sharable by both elements. + [Throws] + void mozLoadFrom(HTMLMediaElement other); + + // Mozilla extension: provides access to the fragment end time if + // the media element has a fragment URI for the currentSrc, otherwise + // it is equal to the media duration. + readonly attribute double mozFragmentEnd; + + // Mozilla extension: an audio channel type for media elements. + // An exception is thrown if the app tries to change the audio channel type + // without the permission (manifest file for B2G apps). + // The supported values are: + // * normal (default value) + // Automatically paused if "notification" or higher priority channel + // is played + // Use case: normal applications + // * content + // Automatically paused if "notification" or higher priority channel + // is played. Also paused if another app starts using "content" + // channel. Using this channel never affects applications using + // the "normal" channel. + // Use case: video/audio players + // * notification + // Automatically paused if "alarm" or higher priority channel is played. + // Use case: New email, incoming SMS + // * alarm + // Automatically paused if "telephony" or higher priority channel is + // played. + // User case: Alarm clock, calendar alarms + // * telephony + // Automatically paused if "ringer" or higher priority + // channel is played. + // Use case: dialer, voip + // * ringer + // Automatically paused if "publicnotification" or higher priority + // channel is played. + // Use case: dialer, voip + // * publicnotification + // Always plays in speaker, even when headphones are plugged in. + // Use case: Camera shutter sound. + [SetterThrows] + attribute DOMString mozAudioChannelType; + + // In addition the media element has this new events: + // * onmozinterruptbegin - called when the media element is interrupted + // because of the audiochannel manager. + // * onmozinterruptend - called when the interruption is concluded +}; diff --git a/dom/webidl/WebIDL.mk b/dom/webidl/WebIDL.mk index 1c44ac323f6b..073b7941b104 100644 --- a/dom/webidl/WebIDL.mk +++ b/dom/webidl/WebIDL.mk @@ -96,6 +96,7 @@ webidl_files = \ HTMLLIElement.webidl \ HTMLLinkElement.webidl \ HTMLMapElement.webidl \ + HTMLMediaElement.webidl \ HTMLMenuElement.webidl \ HTMLMenuItemElement.webidl \ HTMLMetaElement.webidl \