Bug 841493 - HTMLAudioElement to WebIDL, r=Ms2ger
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 19 Mar 2013 13:26:39 +0100
changeset 135786 8a12afcc09bbb69b5d4058eb08f0d791e3832102
parent 135785 d5884ca6c0d7c458c152db2cbf1454614d1935e9
child 135787 e90c1e76bd3069607dfdaf196ab7ecf1d04af9c2
push idunknown
push userunknown
push dateunknown
reviewersMs2ger
bugs841493
milestone22.0a1
Bug 841493 - HTMLAudioElement to WebIDL, r=Ms2ger
content/html/content/public/HTMLAudioElement.h
content/html/content/src/HTMLAudioElement.cpp
dom/webidl/HTMLAudioElement.webidl
dom/webidl/WebIDL.mk
--- a/content/html/content/public/HTMLAudioElement.h
+++ b/content/html/content/public/HTMLAudioElement.h
@@ -48,14 +48,31 @@ public:
                         JSObject* aObj, uint32_t argc, jsval* argv);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel);
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+  // WebIDL
+
+  static already_AddRefed<HTMLAudioElement> Audio(const GlobalObject& global,
+                                                  ErrorResult& aRv);
+  static already_AddRefed<HTMLAudioElement> Audio(const GlobalObject& global,
+                                                  const nsAString& src,
+                                                  ErrorResult& aRv);
+
+  void MozSetup(uint32_t aChannels, uint32_t aRate, ErrorResult& aRv);
+
+  uint32_t MozWriteAudio(JSContext* aCx, JS::Value aData, ErrorResult& aRv);
+
+  uint64_t MozCurrentSampleOffset(ErrorResult& aRv);
+
+protected:
+  virtual JSObject* WrapNode(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLAudioElement_h
--- a/content/html/content/src/HTMLAudioElement.cpp
+++ b/content/html/content/src/HTMLAudioElement.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/. */
+
+#include "mozilla/dom/HTMLAudioElement.h"
+#include "mozilla/dom/HTMLAudioElementBinding.h"
 #include "nsError.h"
 #include "nsIDOMHTMLAudioElement.h"
-#include "mozilla/dom/HTMLAudioElement.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "jsfriendapi.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "AudioSampleFormat.h"
 #include "AudioChannelCommon.h"
@@ -63,22 +65,24 @@ NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_S
 NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLAudioElement)
 
 NS_IMPL_ELEMENT_CLONE(HTMLAudioElement)
 
 
 HTMLAudioElement::HTMLAudioElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : HTMLMediaElement(aNodeInfo)
 {
+  SetIsDOMBinding();
 }
 
 HTMLAudioElement::~HTMLAudioElement()
 {
 }
 
+
 NS_IMETHODIMP
 HTMLAudioElement::Initialize(nsISupports* aOwner, JSContext* aContext,
                              JSObject *aObj, uint32_t argc, jsval *argv)
 {
   // Audio elements created using "new Audio(...)" should have
   // 'preload' set to 'auto' (since the script must intend to
   // play the audio)
   nsresult rv = SetAttr(kNameSpaceID_None, nsGkAtoms::preload,
@@ -100,131 +104,201 @@ HTMLAudioElement::Initialize(nsISupports
   if (!str.init(aContext, jsstr))
     return NS_ERROR_FAILURE;
 
   // The only (optional) argument is the src of the audio (which must
   // be a URL string), used to initialize the 'src' attribute.
   return SetSrc(str);
 }
 
-NS_IMETHODIMP
-HTMLAudioElement::MozSetup(uint32_t aChannels, uint32_t aRate)
+already_AddRefed<HTMLAudioElement>
+HTMLAudioElement::Audio(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.Get());
+  nsIDocument* doc;
+  if (!win || !(doc = win->GetExtantDoc())) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsINodeInfo> nodeInfo =
+    doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::audio, nullptr,
+                                        kNameSpaceID_XHTML,
+                                        nsIDOMNode::ELEMENT_NODE);
+  if (!nodeInfo) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<HTMLAudioElement> audio = new HTMLAudioElement(nodeInfo.forget());
+  audio->SetHTMLAttr(nsGkAtoms::preload, NS_LITERAL_STRING("auto"), aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  return audio.forget();
+}
+
+already_AddRefed<HTMLAudioElement>
+HTMLAudioElement::Audio(const GlobalObject& aGlobal, const nsAString& aSrc, ErrorResult& aRv)
+{
+  nsRefPtr<HTMLAudioElement> audio = Audio(aGlobal, aRv);
+  if (audio) {
+    aRv = audio->SetSrc(aSrc);
+  }
+
+  return audio.forget();
+}
+
+void
+HTMLAudioElement::MozSetup(uint32_t aChannels, uint32_t aRate, ErrorResult& aRv)
 {
   if (!IsAudioAPIEnabled()) {
-    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
   }
 
   // If there is already a src provided, don't setup another stream
   if (mDecoder) {
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   // MozWriteAudio divides by mChannels, so validate now.
   if (0 == aChannels) {
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   if (mAudioStream) {
     mAudioStream->Shutdown();
   }
 
   mAudioStream = AudioStream::AllocateStream();
-  nsresult rv = mAudioStream->Init(aChannels, aRate, mAudioChannelType);
-  if (NS_FAILED(rv)) {
+  aRv = mAudioStream->Init(aChannels, aRate, mAudioChannelType);
+  if (aRv.Failed()) {
     mAudioStream->Shutdown();
     mAudioStream = nullptr;
-    return rv;
+    return;
   }
 
   MetadataLoaded(aChannels, aRate, true, false, nullptr);
   mAudioStream->SetVolume(mVolume);
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
-HTMLAudioElement::MozWriteAudio(const JS::Value& aData, JSContext* aCx, uint32_t* aRetVal)
+HTMLAudioElement::MozSetup(uint32_t aChannels, uint32_t aRate)
+{
+  ErrorResult rv;
+  MozSetup(aChannels, aRate, rv);
+  return rv.ErrorCode();
+}
+
+uint32_t
+HTMLAudioElement::MozWriteAudio(JSContext* aCx, JS::Value aData, ErrorResult& aRv)
 {
   if (!IsAudioAPIEnabled()) {
-    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return 0;
   }
 
   if (!mAudioStream) {
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return 0;
   }
 
   if (!aData.isObject()) {
-    return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
+    aRv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+    return 0;
   }
 
   JSObject* darray = &aData.toObject();
   JS::AutoObjectRooter tvr(aCx);
   JSObject* tsrc = NULL;
 
   // Allow either Float32Array or plain JS Array
   if (JS_IsFloat32Array(darray)) {
     tsrc = darray;
   } else if (JS_IsArrayObject(aCx, darray)) {
     JSObject* nobj = JS_NewFloat32ArrayFromArray(aCx, darray);
     if (!nobj) {
-      return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
+      aRv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+      return 0;
     }
     tsrc = nobj;
   } else {
-    return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
+    aRv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+    return 0;
   }
   tvr.setObject(tsrc);
 
   uint32_t dataLength = JS_GetTypedArrayLength(tsrc);
 
   // Make sure that we are going to write the correct amount of data based
   // on number of channels.
   if (dataLength % mChannels != 0) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return 0;
   }
 
   // Don't write more than can be written without blocking.
   uint32_t writeLen = std::min(mAudioStream->Available(), dataLength / mChannels);
 
   float* frames = JS_GetFloat32ArrayData(tsrc);
   // Convert the samples back to integers as we are using fixed point audio in
   // the AudioStream.
   // This could be optimized to avoid allocation and memcpy when
   // AudioDataValue is 'float', but it's not worth it for this deprecated API.
   nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[writeLen * mChannels]);
   ConvertAudioSamples(frames, audioData.get(), writeLen * mChannels);
-  nsresult rv = mAudioStream->Write(audioData.get(), writeLen);
-  if (NS_FAILED(rv)) {
-    return rv;
+  aRv = mAudioStream->Write(audioData.get(), writeLen);
+  if (aRv.Failed()) {
+    return 0;
   }
   mAudioStream->Start();
 
   // Return the actual amount written.
-  *aRetVal = writeLen * mChannels;
-  return rv;
+  return writeLen * mChannels;
+}
+
+NS_IMETHODIMP
+HTMLAudioElement::MozWriteAudio(const JS::Value& aData, JSContext* aCx, uint32_t* aRetVal)
+{
+  ErrorResult rv;
+  *aRetVal = MozWriteAudio(aCx, aData, rv);
+  return rv.ErrorCode();
+}
+
+uint64_t
+HTMLAudioElement::MozCurrentSampleOffset(ErrorResult& aRv)
+{
+  if (!IsAudioAPIEnabled()) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return 0;
+  }
+
+  if (!mAudioStream) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return 0;
+  }
+
+  int64_t position = mAudioStream->GetPositionInFrames();
+  if (position < 0) {
+    return 0;
+  }
+
+  return position * mChannels;
 }
 
 NS_IMETHODIMP
 HTMLAudioElement::MozCurrentSampleOffset(uint64_t *aRetVal)
 {
-  if (!IsAudioAPIEnabled()) {
-    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-  }
-
-  if (!mAudioStream) {
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
-  }
-
-  int64_t position = mAudioStream->GetPositionInFrames();
-  if (position < 0) {
-    *aRetVal = 0;
-  } else {
-    *aRetVal = position * mChannels;
-  }
-  return NS_OK;
+  ErrorResult rv;
+  *aRetVal = MozCurrentSampleOffset(rv);
+  return rv.ErrorCode();
 }
 
 nsresult HTMLAudioElement::SetAcceptHeader(nsIHttpChannel* aChannel)
 {
     nsAutoCString value(
 #ifdef MOZ_WEBM
       "audio/webm,"
 #endif
@@ -240,10 +314,16 @@ nsresult HTMLAudioElement::SetAcceptHead
 #endif
       "video/*;q=0.6,*/*;q=0.5");
 
     return aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
                                       value,
                                       false);
 }
 
+JSObject*
+HTMLAudioElement::WrapNode(JSContext* aCx, JSObject* aScope)
+{
+  return HTMLAudioElementBinding::Wrap(aCx, aScope, this);
+}
+
 } // namespace dom
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/webidl/HTMLAudioElement.webidl
@@ -0,0 +1,32 @@
+/* -*- 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/#the-audio-element
+ *
+ * © 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.
+ */
+
+[NamedConstructor=Audio(),
+ NamedConstructor=Audio(DOMString src)]
+interface HTMLAudioElement : HTMLMediaElement {};
+
+partial interface HTMLAudioElement
+{
+  // Setup the audio stream for writing
+  [Throws]
+  void mozSetup(unsigned long channels, unsigned long rate);
+
+  // Write audio to the audio stream
+  [Throws]
+  unsigned long mozWriteAudio(any data);
+
+  // Get the current offset (measured in samples since the start) of the audio
+  // stream created using mozWriteAudio().
+  [Throws]
+  unsigned long long mozCurrentSampleOffset();
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -64,16 +64,17 @@ webidl_files = \
   FileReaderSync.webidl \
   FileRequest.webidl \
   FormData.webidl \
   Function.webidl \
   GainNode.webidl \
   HTMLAnchorElement.webidl \
   HTMLAppletElement.webidl \
   HTMLAreaElement.webidl \
+  HTMLAudioElement.webidl \
   HTMLBaseElement.webidl \
   HTMLBodyElement.webidl \
   HTMLBRElement.webidl \
   HTMLButtonElement.webidl \
   HTMLCollection.webidl \
   HTMLDataElement.webidl \
   HTMLDataListElement.webidl \
   HTMLDirectoryElement.webidl \