2008-07-09 08:22:20 +00: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 11:12:37 +00: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/. */
|
2012-07-27 14:03:27 +00:00
|
|
|
#include "nsError.h"
|
2008-07-09 08:22:20 +00:00
|
|
|
#include "nsIDOMHTMLAudioElement.h"
|
|
|
|
#include "nsHTMLAudioElement.h"
|
|
|
|
#include "nsGenericHTMLElement.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsIDocument.h"
|
2011-10-04 14:06:54 +00:00
|
|
|
#include "jsfriendapi.h"
|
2011-08-11 13:29:50 +00:00
|
|
|
#include "nsContentUtils.h"
|
2012-09-24 03:47:30 +00:00
|
|
|
#include "nsJSUtils.h"
|
2012-10-25 10:09:40 +00:00
|
|
|
#include "AudioSampleFormat.h"
|
2012-11-16 03:25:26 +00:00
|
|
|
#include "AudioChannelCommon.h"
|
2008-07-09 08:22:20 +00:00
|
|
|
|
2012-10-25 10:09:40 +00:00
|
|
|
using namespace mozilla;
|
2010-10-25 12:17:38 +00:00
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
2009-05-19 05:18:41 +00:00
|
|
|
nsGenericHTMLElement*
|
2010-07-23 09:49:57 +00:00
|
|
|
NS_NewHTMLAudioElement(already_AddRefed<nsINodeInfo> aNodeInfo,
|
2010-10-25 12:17:38 +00:00
|
|
|
FromParser aFromParser)
|
2009-05-19 05:18:41 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* nsHTMLAudioElement's will be created without a nsINodeInfo passed in
|
|
|
|
* if someone says "var audio = new Audio();" in JavaScript, in a case like
|
|
|
|
* that we request the nsINodeInfo from the document's nodeinfo list.
|
|
|
|
*/
|
|
|
|
nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo);
|
|
|
|
if (!nodeInfo) {
|
|
|
|
nsCOMPtr<nsIDocument> doc =
|
|
|
|
do_QueryInterface(nsContentUtils::GetDocumentFromCaller());
|
2012-07-30 14:20:58 +00:00
|
|
|
NS_ENSURE_TRUE(doc, nullptr);
|
2009-05-19 05:18:41 +00:00
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::audio, nullptr,
|
2011-06-14 07:56:49 +00:00
|
|
|
kNameSpaceID_XHTML,
|
|
|
|
nsIDOMNode::ELEMENT_NODE);
|
2012-07-30 14:20:58 +00:00
|
|
|
NS_ENSURE_TRUE(nodeInfo, nullptr);
|
2009-05-19 05:18:41 +00:00
|
|
|
}
|
|
|
|
|
2011-09-18 09:22:18 +00:00
|
|
|
return new nsHTMLAudioElement(nodeInfo.forget());
|
2009-05-19 05:18:41 +00:00
|
|
|
}
|
2008-07-09 08:22:20 +00:00
|
|
|
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsHTMLAudioElement, nsHTMLMediaElement)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(nsHTMLAudioElement, nsHTMLMediaElement)
|
|
|
|
|
2010-07-23 09:49:57 +00:00
|
|
|
DOMCI_NODE_DATA(HTMLAudioElement, nsHTMLAudioElement)
|
2010-01-12 13:08:43 +00:00
|
|
|
|
2008-11-03 10:31:47 +00:00
|
|
|
NS_INTERFACE_TABLE_HEAD(nsHTMLAudioElement)
|
2009-05-19 05:18:41 +00:00
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE3(nsHTMLAudioElement, nsIDOMHTMLMediaElement,
|
|
|
|
nsIDOMHTMLAudioElement, nsIJSNativeInitializer)
|
2010-07-23 09:49:57 +00:00
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLAudioElement,
|
2008-11-03 10:31:47 +00:00
|
|
|
nsHTMLMediaElement)
|
2008-07-09 08:22:20 +00:00
|
|
|
NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLAudioElement)
|
|
|
|
|
|
|
|
NS_IMPL_ELEMENT_CLONE(nsHTMLAudioElement)
|
|
|
|
|
|
|
|
|
2011-09-18 09:22:18 +00:00
|
|
|
nsHTMLAudioElement::nsHTMLAudioElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
|
|
|
: nsHTMLMediaElement(aNodeInfo)
|
2008-07-09 08:22:20 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsHTMLAudioElement::~nsHTMLAudioElement()
|
|
|
|
{
|
|
|
|
}
|
2009-05-19 05:18:41 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsHTMLAudioElement::Initialize(nsISupports* aOwner, JSContext* aContext,
|
2012-08-22 15:56:38 +00:00
|
|
|
JSObject *aObj, uint32_t argc, jsval *argv)
|
2009-05-19 05:18:41 +00:00
|
|
|
{
|
2009-07-26 21:31:11 +00:00
|
|
|
// Audio elements created using "new Audio(...)" should have
|
2010-08-19 22:50:37 +00:00
|
|
|
// 'preload' set to 'auto' (since the script must intend to
|
|
|
|
// play the audio)
|
|
|
|
nsresult rv = SetAttr(kNameSpaceID_None, nsGkAtoms::preload,
|
2011-09-29 23:34:37 +00:00
|
|
|
NS_LITERAL_STRING("auto"), true);
|
2009-07-26 21:31:11 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
|
2009-05-19 05:18:41 +00:00
|
|
|
if (argc <= 0) {
|
2009-07-26 21:31:11 +00:00
|
|
|
// Nothing more to do here if we don't get any arguments.
|
2009-05-19 05:18:41 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-09-24 03:47:30 +00:00
|
|
|
// The only (optional) argument is the url of the audio
|
|
|
|
JSString* jsstr = JS_ValueToString(aContext, argv[0]);
|
|
|
|
if (!jsstr)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsDependentJSString str;
|
|
|
|
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);
|
2009-05-19 05:18:41 +00:00
|
|
|
}
|
2010-07-29 04:58:07 +00:00
|
|
|
|
2010-08-25 13:10:00 +00:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 15:56:38 +00:00
|
|
|
nsHTMLAudioElement::MozSetup(uint32_t aChannels, uint32_t aRate)
|
2010-08-25 13:10:00 +00:00
|
|
|
{
|
|
|
|
// If there is already a src provided, don't setup another stream
|
|
|
|
if (mDecoder) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// MozWriteAudio divides by mChannels, so validate now.
|
|
|
|
if (0 == aChannels) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mAudioStream) {
|
|
|
|
mAudioStream->Shutdown();
|
|
|
|
}
|
|
|
|
|
2012-11-14 19:46:40 +00:00
|
|
|
mAudioStream = AudioStream::AllocateStream();
|
2012-11-16 03:25:26 +00:00
|
|
|
nsresult rv = mAudioStream->Init(aChannels, aRate, mAudioChannelType);
|
2010-08-25 13:10:00 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mAudioStream->Shutdown();
|
2012-07-30 14:20:58 +00:00
|
|
|
mAudioStream = nullptr;
|
2010-08-25 13:10:00 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-07-31 00:14:29 +00:00
|
|
|
MetadataLoaded(aChannels, aRate, true, nullptr);
|
2010-08-25 13:10:00 +00:00
|
|
|
mAudioStream->SetVolume(mVolume);
|
2012-11-30 13:17:54 +00:00
|
|
|
|
2010-08-25 13:10:00 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 15:56:38 +00:00
|
|
|
nsHTMLAudioElement::MozWriteAudio(const JS::Value& aData, JSContext* aCx, uint32_t* aRetVal)
|
2010-08-25 13:10:00 +00:00
|
|
|
{
|
|
|
|
if (!mAudioStream) {
|
|
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
|
|
}
|
|
|
|
|
2012-01-14 17:43:00 +00:00
|
|
|
if (!aData.isObject()) {
|
2010-08-25 13:10:00 +00:00
|
|
|
return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
|
|
|
|
}
|
|
|
|
|
2012-01-14 17:43:00 +00:00
|
|
|
JSObject* darray = &aData.toObject();
|
|
|
|
JS::AutoObjectRooter tvr(aCx);
|
|
|
|
JSObject* tsrc = NULL;
|
2010-08-25 13:10:00 +00:00
|
|
|
|
|
|
|
// Allow either Float32Array or plain JS Array
|
2012-11-14 17:56:26 +00:00
|
|
|
if (JS_IsFloat32Array(darray)) {
|
2012-01-14 17:43:00 +00:00
|
|
|
tsrc = darray;
|
2010-08-25 13:10:00 +00:00
|
|
|
} else if (JS_IsArrayObject(aCx, darray)) {
|
2012-01-14 17:43:00 +00:00
|
|
|
JSObject* nobj = JS_NewFloat32ArrayFromArray(aCx, darray);
|
2010-08-25 13:10:00 +00:00
|
|
|
if (!nobj) {
|
|
|
|
return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
|
|
|
|
}
|
2012-01-14 17:43:00 +00:00
|
|
|
tsrc = nobj;
|
2010-08-25 13:10:00 +00:00
|
|
|
} else {
|
|
|
|
return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
|
|
|
|
}
|
2012-01-14 17:43:00 +00:00
|
|
|
tvr.setObject(tsrc);
|
2010-08-25 13:10:00 +00:00
|
|
|
|
2012-11-14 17:56:26 +00:00
|
|
|
uint32_t dataLength = JS_GetTypedArrayLength(tsrc);
|
2010-08-25 13:10:00 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't write more than can be written without blocking.
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t writeLen = NS_MIN(mAudioStream->Available(), dataLength / mChannels);
|
2010-08-25 13:10:00 +00:00
|
|
|
|
2012-11-14 17:56:26 +00:00
|
|
|
float* frames = JS_GetFloat32ArrayData(tsrc);
|
2012-10-25 10:10:51 +00:00
|
|
|
// Convert the samples back to integers as we are using fixed point audio in
|
2012-11-14 19:46:40 +00:00
|
|
|
// the AudioStream.
|
2012-10-25 10:10:51 +00:00
|
|
|
// 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);
|
2012-08-17 01:10:36 +00:00
|
|
|
|
2010-08-25 13:10:00 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the actual amount written.
|
2011-09-27 03:31:18 +00:00
|
|
|
*aRetVal = writeLen * mChannels;
|
2010-08-25 13:10:00 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 15:56:38 +00:00
|
|
|
nsHTMLAudioElement::MozCurrentSampleOffset(uint64_t *aRetVal)
|
2010-08-25 13:10:00 +00:00
|
|
|
{
|
|
|
|
if (!mAudioStream) {
|
|
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int64_t position = mAudioStream->GetPositionInFrames();
|
2012-07-16 21:21:04 +00:00
|
|
|
if (position < 0) {
|
|
|
|
*aRetVal = 0;
|
|
|
|
} else {
|
2012-07-31 09:11:52 +00:00
|
|
|
*aRetVal = position * mChannels;
|
2012-07-16 21:21:04 +00:00
|
|
|
}
|
2010-08-25 13:10:00 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-07-29 04:58:07 +00:00
|
|
|
nsresult nsHTMLAudioElement::SetAcceptHeader(nsIHttpChannel* aChannel)
|
|
|
|
{
|
2012-09-02 02:35:17 +00:00
|
|
|
nsAutoCString value(
|
2010-07-29 04:58:07 +00:00
|
|
|
#ifdef MOZ_WEBM
|
|
|
|
"audio/webm,"
|
|
|
|
#endif
|
|
|
|
#ifdef MOZ_OGG
|
|
|
|
"audio/ogg,"
|
|
|
|
#endif
|
|
|
|
#ifdef MOZ_WAVE
|
|
|
|
"audio/wav,"
|
|
|
|
#endif
|
|
|
|
"audio/*;q=0.9,"
|
|
|
|
#ifdef MOZ_OGG
|
|
|
|
"application/ogg;q=0.7,"
|
|
|
|
#endif
|
|
|
|
"video/*;q=0.6,*/*;q=0.5");
|
|
|
|
|
|
|
|
return aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
|
|
|
|
value,
|
2011-09-29 23:34:37 +00:00
|
|
|
false);
|
2010-07-29 04:58:07 +00:00
|
|
|
}
|