diff -r ccf3b452d0f4 browser/app/profile/firefox.js --- a/browser/app/profile/firefox.js Tue May 25 18:40:45 2010 -0500 +++ b/browser/app/profile/firefox.js Tue May 25 21:21:43 2010 -0500 @@ -160,17 +160,17 @@ pref("xpinstall.whitelist.add.36", "getp pref("lightweightThemes.update.enabled", true); pref("keyword.enabled", true); pref("keyword.URL", "chrome://browser-region/locale/region.properties"); pref("general.useragent.locale", "@AB_CD@"); pref("general.skins.selectedSkin", "classic/1.0"); -pref("general.useragent.extra.firefox", "@APP_UA_NAME@/@APP_VERSION@"); +pref("general.useragent.extra.firefox", "Audio/13 @APP_UA_NAME@/@APP_VERSION@"); pref("general.smoothScroll", false); #ifdef UNIX_BUT_NOT_MAC pref("general.autoScroll", false); #else pref("general.autoScroll", true); #endif diff -r ccf3b452d0f4 content/base/src/nsContentUtils.cpp --- a/content/base/src/nsContentUtils.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/base/src/nsContentUtils.cpp Tue May 25 21:21:43 2010 -0500 @@ -567,16 +567,17 @@ nsContentUtils::InitializeEventTable() { { &nsGkAtoms::oncanplaythrough, { NS_CANPLAYTHROUGH, EventNameType_HTML }}, { &nsGkAtoms::onseeking, { NS_SEEKING, EventNameType_HTML }}, { &nsGkAtoms::onseeked, { NS_SEEKED, EventNameType_HTML }}, { &nsGkAtoms::ontimeupdate, { NS_TIMEUPDATE, EventNameType_HTML }}, { &nsGkAtoms::onended, { NS_ENDED, EventNameType_HTML }}, { &nsGkAtoms::onratechange, { NS_RATECHANGE, EventNameType_HTML }}, { &nsGkAtoms::ondurationchange, { NS_DURATIONCHANGE, EventNameType_HTML }}, { &nsGkAtoms::onvolumechange, { NS_VOLUMECHANGE, EventNameType_HTML }}, + { &nsGkAtoms::onaudiowritten, { NS_AUDIOWRITTEN, EventNameType_HTML }}, #endif //MOZ_MEDIA { &nsGkAtoms::onMozAfterPaint, { NS_AFTERPAINT, EventNameType_None }}, { &nsGkAtoms::onMozScrolledAreaChanged, { NS_SCROLLEDAREACHANGED, EventNameType_None }}, // Simple gesture events { &nsGkAtoms::onMozSwipeGesture, { NS_SIMPLE_GESTURE_SWIPE, EventNameType_None } }, { &nsGkAtoms::onMozMagnifyGestureStart, { NS_SIMPLE_GESTURE_MAGNIFY_START, EventNameType_None } }, { &nsGkAtoms::onMozMagnifyGestureUpdate, { NS_SIMPLE_GESTURE_MAGNIFY_UPDATE, EventNameType_None } }, diff -r ccf3b452d0f4 content/base/src/nsGkAtomList.h --- a/content/base/src/nsGkAtomList.h Tue May 25 18:40:45 2010 -0500 +++ b/content/base/src/nsGkAtomList.h Tue May 25 21:21:43 2010 -0500 @@ -1648,16 +1648,18 @@ GK_ATOM(seeking, "seeking") GK_ATOM(seeked, "seeked") GK_ATOM(timeupdate, "timeupdate") GK_ATOM(ended, "ended") GK_ATOM(canplay, "canplay") GK_ATOM(canplaythrough, "canplaythrough") GK_ATOM(ratechange, "ratechange") GK_ATOM(durationchange, "durationchange") GK_ATOM(volumechange, "volumechange") +GK_ATOM(onaudiowritten, "onaudiowritten") +GK_ATOM(audiowritten, "audiowritten") #endif // Content property names GK_ATOM(transitionsProperty, "TransitionsProperty") // FrameTransitions* GK_ATOM(transitionsOfBeforeProperty, "TransitionsOfBeforeProperty") // FrameTransitions* GK_ATOM(transitionsOfAfterProperty, "TransitionsOfAfterProperty") // FrameTransitions* GK_ATOM(genConInitializerProperty, "QuoteNodeProperty") GK_ATOM(labelMouseDownPtProperty, "LabelMouseDownPtProperty") diff -r ccf3b452d0f4 content/events/public/nsIPrivateDOMEvent.h --- a/content/events/public/nsIPrivateDOMEvent.h Tue May 25 18:40:45 2010 -0500 +++ b/content/events/public/nsIPrivateDOMEvent.h Tue May 25 21:21:43 2010 -0500 @@ -107,14 +107,28 @@ nsresult NS_NewDOMProgressEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent); // This empties aInvalidateRequests. nsresult NS_NewDOMNotifyPaintEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent, PRUint32 aEventType = 0, nsInvalidateRequestList* aInvalidateRequests = nsnull); nsresult +NS_NewDOMAudioWrittenEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, + nsEvent* aEvent, + PRUint32 aEventType = 0, + float* aFrameBuffer = nsnull, + PRUint32 aFrameBufferLen = 0, + PRUint32 aTime = 0); +nsresult +NS_NewDOMAudioMetadataEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, + nsEvent* aEvent, + PRUint32 aEventType = 0, + PRUint32 aChannels = 0, + PRUint32 aRate = 0, + PRUint32 aFrameBufferLength = 0); +nsresult NS_NewDOMSimpleGestureEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsSimpleGestureEvent* aEvent); nsresult NS_NewDOMScrollAreaEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsScrollAreaEvent* aEvent); nsresult NS_NewDOMTransitionEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsTransitionEvent* aEvent); #endif // nsIPrivateDOMEvent_h__ diff -r ccf3b452d0f4 content/events/src/Makefile.in --- a/content/events/src/Makefile.in Tue May 25 18:40:45 2010 -0500 +++ b/content/events/src/Makefile.in Tue May 25 21:21:43 2010 -0500 @@ -73,16 +73,18 @@ CPPSRCS = \ nsPLDOMEvent.cpp \ nsEventDispatcher.cpp \ nsIMEStateManager.cpp \ nsContentEventHandler.cpp \ nsEventListenerService.cpp \ nsDOMProgressEvent.cpp \ nsDOMDataTransfer.cpp \ nsDOMNotifyPaintEvent.cpp \ + nsDOMNotifyAudioWrittenEvent.cpp \ + nsDOMNotifyAudioMetadataEvent.cpp \ nsDOMSimpleGestureEvent.cpp \ nsDOMEventTargetHelper.cpp \ nsDOMScrollAreaEvent.cpp \ nsDOMTransitionEvent.cpp \ nsDOMPopStateEvent.cpp \ $(NULL) # we don't want the shared lib, but we want to force the creation of a static lib. diff -r ccf3b452d0f4 content/events/src/nsDOMEvent.cpp --- a/content/events/src/nsDOMEvent.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/events/src/nsDOMEvent.cpp Tue May 25 21:21:43 2010 -0500 @@ -75,17 +75,17 @@ static const char* const sEventNames[] = #ifdef MOZ_SVG "SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll", "SVGZoom", #endif // MOZ_SVG #ifdef MOZ_MEDIA "loadstart", "progress", "suspend", "emptied", "stalled", "play", "pause", "loadedmetadata", "loadeddata", "waiting", "playing", "canplay", "canplaythrough", "seeking", "seeked", "timeupdate", "ended", "ratechange", - "durationchange", "volumechange", + "durationchange", "volumechange", "audiowritten", #endif // MOZ_MEDIA "MozAfterPaint", "MozSwipeGesture", "MozMagnifyGestureStart", "MozMagnifyGestureUpdate", "MozMagnifyGesture", "MozRotateGestureStart", "MozRotateGestureUpdate", @@ -678,16 +678,18 @@ nsDOMEvent::SetEventType(const nsAString else if (atom == nsGkAtoms::onvolumechange) mEvent->message = NS_VOLUMECHANGE; else if (atom == nsGkAtoms::onload) mEvent->message = NS_LOAD; else if (atom == nsGkAtoms::onabort) mEvent->message = NS_MEDIA_ABORT; else if (atom == nsGkAtoms::onerror) mEvent->message = NS_MEDIA_ERROR; + else if (atom == nsGkAtoms::onaudiowritten) + mEvent->message = NS_AUDIOWRITTEN; } #endif // MOZ_MEDIA else if (mEvent->eventStructType == NS_SIMPLE_GESTURE_EVENT) { if (atom == nsGkAtoms::onMozSwipeGesture) mEvent->message = NS_SIMPLE_GESTURE_SWIPE; else if (atom == nsGkAtoms::onMozMagnifyGestureStart) mEvent->message = NS_SIMPLE_GESTURE_MAGNIFY_START; else if (atom == nsGkAtoms::onMozMagnifyGestureUpdate) @@ -1482,16 +1484,18 @@ const char* nsDOMEvent::GetEventName(PRU case NS_ENDED: return sEventNames[eDOMEvents_ended]; case NS_RATECHANGE: return sEventNames[eDOMEvents_ratechange]; case NS_DURATIONCHANGE: return sEventNames[eDOMEvents_durationchange]; case NS_VOLUMECHANGE: return sEventNames[eDOMEvents_volumechange]; + case NS_AUDIOWRITTEN: + return sEventNames[eDOMEvents_audiowritten]; #endif case NS_AFTERPAINT: return sEventNames[eDOMEvents_afterpaint]; case NS_SIMPLE_GESTURE_SWIPE: return sEventNames[eDOMEvents_MozSwipeGesture]; case NS_SIMPLE_GESTURE_MAGNIFY_START: return sEventNames[eDOMEvents_MozMagnifyGestureStart]; case NS_SIMPLE_GESTURE_MAGNIFY_UPDATE: diff -r ccf3b452d0f4 content/events/src/nsDOMEvent.h --- a/content/events/src/nsDOMEvent.h Tue May 25 18:40:45 2010 -0500 +++ b/content/events/src/nsDOMEvent.h Tue May 25 21:21:43 2010 -0500 @@ -156,16 +156,17 @@ public: eDOMEvents_canplaythrough, eDOMEvents_seeking, eDOMEvents_seeked, eDOMEvents_timeupdate, eDOMEvents_ended, eDOMEvents_ratechange, eDOMEvents_durationchange, eDOMEvents_volumechange, + eDOMEvents_audiowritten, #endif eDOMEvents_afterpaint, eDOMEvents_MozSwipeGesture, eDOMEvents_MozMagnifyGestureStart, eDOMEvents_MozMagnifyGestureUpdate, eDOMEvents_MozMagnifyGesture, eDOMEvents_MozRotateGestureStart, eDOMEvents_MozRotateGestureUpdate, diff -r ccf3b452d0f4 content/events/src/nsDOMNotifyAudioMetadataEvent.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/events/src/nsDOMNotifyAudioMetadataEvent.cpp Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsDOMNotifyAudioMetadataEvent.h" + +nsDOMNotifyAudioMetadataEvent::nsDOMNotifyAudioMetadataEvent(nsPresContext* aPresContext, + nsEvent* aEvent, + PRUint32 aEventType, + PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength) + : nsDOMEvent(aPresContext, aEvent), + mChannels(aChannels), + mRate(aRate), + mFrameBufferLength(aFrameBufferLength) +{ + if (mEvent) { + mEvent->message = aEventType; + } +} + +DOMCI_DATA(NotifyAudioMetadataEvent, nsDOMNotifyAudioMetadataEvent) + +NS_INTERFACE_MAP_BEGIN(nsDOMNotifyAudioMetadataEvent) + NS_INTERFACE_MAP_ENTRY(nsIDOMNotifyAudioMetadataEvent) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NotifyAudioMetadataEvent) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) + +NS_IMPL_ADDREF_INHERITED(nsDOMNotifyAudioMetadataEvent, nsDOMEvent) +NS_IMPL_RELEASE_INHERITED(nsDOMNotifyAudioMetadataEvent, nsDOMEvent) + +nsDOMNotifyAudioMetadataEvent::~nsDOMNotifyAudioMetadataEvent() +{ +} + +NS_IMETHODIMP +nsDOMNotifyAudioMetadataEvent::GetMozChannels(PRUint32 *_retval NS_OUTPARAM) +{ + *_retval = mChannels; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMNotifyAudioMetadataEvent::GetMozRate(PRUint32 *_retval NS_OUTPARAM) +{ + *_retval = mRate; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMNotifyAudioMetadataEvent::GetMozFrameBufferLength(PRUint32 *_retval NS_OUTPARAM) +{ + *_retval = mFrameBufferLength; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMNotifyAudioMetadataEvent::InitAudioMetadataEvent(const nsAString& aType, + PRBool aCanBubble, + PRBool aCancelable, + PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength) +{ + nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable); + NS_ENSURE_SUCCESS(rv, rv); + + mChannels = aChannels; + mRate = aRate; + mFrameBufferLength = aFrameBufferLength; + return NS_OK; +} + +nsresult NS_NewDOMAudioMetadataEvent(nsIDOMEvent** aInstancePtrResult, + nsPresContext* aPresContext, + nsEvent *aEvent, + PRUint32 aEventType, + PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength) +{ + nsDOMNotifyAudioMetadataEvent* it = + new nsDOMNotifyAudioMetadataEvent(aPresContext, aEvent, aEventType, + aChannels, aRate, aFrameBufferLength); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return CallQueryInterface(it, aInstancePtrResult); +} diff -r ccf3b452d0f4 content/events/src/nsDOMNotifyAudioMetadataEvent.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/events/src/nsDOMNotifyAudioMetadataEvent.h Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ******/ + +#ifndef nsDOMNotifyAudioMetadataEvent_h_ +#define nsDOMNotifyAudioMetadataEvent_h_ + +#include "nsIDOMNotifyAudioMetadataEvent.h" +#include "nsDOMEvent.h" +#include "nsPresContext.h" + +class nsDOMNotifyAudioMetadataEvent : public nsDOMEvent, + public nsIDOMNotifyAudioMetadataEvent +{ +public: + nsDOMNotifyAudioMetadataEvent(nsPresContext* aPresContext, nsEvent* aEvent, + PRUint32 aEventType, PRUint32 aChannels, + PRUint32 aRate, PRUint32 aFrameBufferLength); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIDOMNOTIFYAUDIOMETADATAEVENT + + // Forward to base class + NS_FORWARD_TO_NSDOMEVENT + +nsresult NS_NewDOMAudioMetadataEvent(nsIDOMEvent** aInstancePtrResult, + nsPresContext* aPresContext, + nsEvent *aEvent, + PRUint32 aEventType, + PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength); + +private: + ~nsDOMNotifyAudioMetadataEvent(); + PRUint32 mChannels; + PRUint32 mRate; + PRUint32 mFrameBufferLength; +}; + +#endif // nsDOMNotifyAudioMetadataEvent_h_ diff -r ccf3b452d0f4 content/events/src/nsDOMNotifyAudioWrittenEvent.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/events/src/nsDOMNotifyAudioWrittenEvent.cpp Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsDOMNotifyAudioWrittenEvent.h" + +nsDOMNotifyAudioWrittenEvent::nsDOMNotifyAudioWrittenEvent(nsPresContext* aPresContext, + nsEvent* aEvent, + PRUint32 aEventType, + float* aFrameBuffer, + PRUint32 aFrameBufferLen, + PRUint32 aTime) + : nsDOMEvent(aPresContext, aEvent), + mFrameBuffer(aFrameBuffer), + mFrameBufferLen(aFrameBufferLen), + mTime(aTime) +{ + if (mEvent) { + mEvent->message = aEventType; + } +} + +DOMCI_DATA(NotifyAudioWrittenEvent, nsDOMNotifyAudioWrittenEvent) + +NS_INTERFACE_MAP_BEGIN(nsDOMNotifyAudioWrittenEvent) + NS_INTERFACE_MAP_ENTRY(nsIDOMNotifyAudioWrittenEvent) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NotifyAudioWrittenEvent) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) + +NS_IMPL_ADDREF_INHERITED(nsDOMNotifyAudioWrittenEvent, nsDOMEvent) +NS_IMPL_RELEASE_INHERITED(nsDOMNotifyAudioWrittenEvent, nsDOMEvent) + +nsDOMNotifyAudioWrittenEvent::~nsDOMNotifyAudioWrittenEvent() +{ +} + +NS_IMETHODIMP +nsDOMNotifyAudioWrittenEvent::GetMozFrameBuffer(nsIVariant**) +{ + /* Should never be called -- GetMozFrameBuffer_explicit is the QS entry point */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDOMNotifyAudioWrittenEvent::GetMozFrameBuffer_explicit(float *aData, PRUint32 aDataLen) +{ + NS_ENSURE_ARG_POINTER(aData); + NS_ASSERTION(mFrameBufferLen == aDataLen, "array sizes don't match"); + + // XXX: should we avoid this copy so array returned to content is always the same? + memcpy(aData, mFrameBuffer.get(), aDataLen * sizeof(float)); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMNotifyAudioWrittenEvent::GetMozFrameBufferLength(PRUint32 *_retval NS_OUTPARAM) +{ + *_retval = mFrameBufferLen; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMNotifyAudioWrittenEvent::GetMozTime(PRUint32 *_retval NS_OUTPARAM) +{ + *_retval = mTime; + return NS_OK; +} + +NS_IMETHODIMP +nsDOMNotifyAudioWrittenEvent::InitAudioWrittenEvent(const nsAString& aType, + PRBool aCanBubble, + PRBool aCancelable, + float* aFrameBuffer, + PRUint32 aFrameBufferLen, + PRUint32 aTime) +{ + nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable); + NS_ENSURE_SUCCESS(rv, rv); + + mFrameBuffer = aFrameBuffer; + mFrameBufferLen = aFrameBufferLen; + mTime = aTime; + return NS_OK; +} + +nsresult NS_NewDOMAudioWrittenEvent(nsIDOMEvent** aInstancePtrResult, + nsPresContext* aPresContext, + nsEvent *aEvent, + PRUint32 aEventType, + float* aFrameBuffer, + PRUint32 aFrameBufferLen, + PRUint32 aTime) +{ + nsDOMNotifyAudioWrittenEvent* it = + new nsDOMNotifyAudioWrittenEvent(aPresContext, aEvent, aEventType, + aFrameBuffer, aFrameBufferLen, aTime); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return CallQueryInterface(it, aInstancePtrResult); +} diff -r ccf3b452d0f4 content/events/src/nsDOMNotifyAudioWrittenEvent.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/events/src/nsDOMNotifyAudioWrittenEvent.h Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsDOMNotifyAudioWrittenEvent_h_ +#define nsDOMNotifyAudioWrittenEvent_h_ + +#include "nsIDOMNotifyAudioWrittenEvent.h" +#include "nsDOMEvent.h" +#include "nsPresContext.h" + +class nsDOMNotifyAudioWrittenEvent : public nsDOMEvent, + public nsIDOMNotifyAudioWrittenEvent +{ +public: + nsDOMNotifyAudioWrittenEvent(nsPresContext* aPresContext, nsEvent* aEvent, + PRUint32 aEventType, float * aFrameBuffer, + PRUint32 aFrameBufferLen, PRUint32 aTime); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIDOMNOTIFYAUDIOWRITTENEVENT + + // Forward to base class + NS_FORWARD_TO_NSDOMEVENT + +nsresult NS_NewDOMAudioWrittenEvent(nsIDOMEvent** aInstancePtrResult, + nsPresContext* aPresContext, + nsEvent *aEvent, + PRUint32 aEventType, + float * aFrameBuffer, + PRUint32 aFrameBufferLen, + PRUint32 aTime); + +private: + ~nsDOMNotifyAudioWrittenEvent(); + nsAutoArrayPtr mFrameBuffer; + PRUint32 mFrameBufferLen; + PRUint32 mTime; +}; + +#endif // nsDOMNotifyAudioWrittenEvent_h_ diff -r ccf3b452d0f4 content/events/src/nsEventDispatcher.cpp --- a/content/events/src/nsEventDispatcher.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/events/src/nsEventDispatcher.cpp Tue May 25 21:21:43 2010 -0500 @@ -821,11 +821,15 @@ nsEventDispatcher::CreateEvent(nsPresCon if (aEventType.LowerCaseEqualsLiteral("scrollareaevent")) return NS_NewDOMScrollAreaEvent(aDOMEvent, aPresContext, nsnull); // FIXME: Should get spec to say what the right string is here! This // is probably wrong! if (aEventType.LowerCaseEqualsLiteral("transitionevent")) return NS_NewDOMTransitionEvent(aDOMEvent, aPresContext, nsnull); if (aEventType.LowerCaseEqualsLiteral("popstateevent")) return NS_NewDOMPopStateEvent(aDOMEvent, aPresContext, nsnull); + if (aEventType.LowerCaseEqualsLiteral("audiowrittenevent")) + return NS_NewDOMAudioWrittenEvent(aDOMEvent, aPresContext, nsnull); + if (aEventType.LowerCaseEqualsLiteral("loadedmetadata")) + return NS_NewDOMAudioMetadataEvent(aDOMEvent, aPresContext, nsnull); return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } diff -r ccf3b452d0f4 content/html/content/public/nsHTMLAudioElement.h --- a/content/html/content/public/nsHTMLAudioElement.h Tue May 25 18:40:45 2010 -0500 +++ b/content/html/content/public/nsHTMLAudioElement.h Tue May 25 21:21:43 2010 -0500 @@ -36,16 +36,17 @@ * * ***** END LICENSE BLOCK ***** */ #if !defined(nsHTMLAudioElement_h__) #define nsHTMLAudioElement_h__ #include "nsIDOMHTMLAudioElement.h" #include "nsIJSNativeInitializer.h" #include "nsHTMLMediaElement.h" +#include "nsAudioStream.h" typedef PRUint16 nsMediaNetworkState; typedef PRUint16 nsMediaReadyState; class nsHTMLAudioElement : public nsHTMLMediaElement, public nsIDOMHTMLAudioElement, public nsIJSNativeInitializer { @@ -71,11 +72,23 @@ public: // nsIDOMHTMLAudioElement NS_DECL_NSIDOMHTMLAUDIOELEMENT // nsIJSNativeInitializer NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aContext, JSObject* aObj, PRUint32 argc, jsval* argv); virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; + +protected: + + /** + * An audio stream for writing audio directly from JS. + */ + nsAutoPtr mAudioStream; + + /** + * Number of channels set for mAudioStream. + */ + PRUint32 mChannels; }; #endif diff -r ccf3b452d0f4 content/html/content/public/nsHTMLMediaElement.h --- a/content/html/content/public/nsHTMLMediaElement.h Tue May 25 18:40:45 2010 -0500 +++ b/content/html/content/public/nsHTMLMediaElement.h Tue May 25 21:21:43 2010 -0500 @@ -44,16 +44,18 @@ #include "nsIChannel.h" #include "nsThreadUtils.h" #include "nsIDOMRange.h" #include "nsCycleCollectionParticipant.h" #include "nsILoadGroup.h" #include "nsIObserver.h" #include "ImageLayers.h" +#include "nsAudioStream.h" + // Define to output information on decoding and painting framerate /* #define DEBUG_FRAME_RATE 1 */ typedef PRUint16 nsMediaNetworkState; typedef PRUint16 nsMediaReadyState; class nsHTMLMediaElement : public nsGenericHTMLElement, public nsIObserver @@ -113,18 +115,20 @@ public: /** * Call this to reevaluate whether we should start/stop due to our owner * document being active or inactive. */ void NotifyOwnerDocumentActivityChanged(); // Called by the video decoder object, on the main thread, // when it has read the metadata containing video dimensions, - // etc. - void MetadataLoaded(); + // etc. Also used to give audio stream info for processing. + void MetadataLoaded(PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength); // Called by the video decoder object, on the main thread, // when it has read the first frame of the video // aResourceFullyLoaded should be true if the resource has been // fully loaded and the caller will call ResourceLoaded next. void FirstFrameLoaded(PRBool aResourceFullyLoaded); // Called by the video decoder object, on the main thread, @@ -173,16 +177,22 @@ public: // a static document and we're not actually playing video gfxASurface* GetPrintSurface() { return mPrintSurface; } // Dispatch events nsresult DispatchSimpleEvent(const nsAString& aName); nsresult DispatchProgressEvent(const nsAString& aName); nsresult DispatchAsyncSimpleEvent(const nsAString& aName); nsresult DispatchAsyncProgressEvent(const nsAString& aName); + nsresult DispatchAudioWrittenEvent(float* aFrameBuffer, + PRUint32 aFrameBufferLen, + PRUint32 aTime); + nsresult DispatchAudioMetadataEvent(PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength); // Called by the decoder when some data has been downloaded or // buffering/seeking has ended. aNextFrameAvailable is true when // the data for the next frame is available. This method will // decide whether to set the ready state to HAVE_CURRENT_DATA, // HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA. enum NextFrameStatus { // The next frame of audio/video is available @@ -255,16 +265,22 @@ public: void NotifyAddedSource(); /** * Called when there's been an error fetching the resource. This decides * whether it's appropriate to fire an error event. */ void NotifyLoadError(); + /** + * Called when data has been written to the underlying audio stream. + */ + void NotifyAudioWritten(float* aFrameBuffer, PRUint32 aFrameBufferLen, + PRUint32 aTime); + virtual PRBool IsNodeOfType(PRUint32 aFlags) const; /** * Returns the current load ID. Asynchronous events store the ID that was * current when they were enqueued, and if it has changed when they come to * fire, they consider themselves cancelled, and don't fire. */ PRUint32 GetCurrentLoadID() { return mCurrentLoadID; } diff -r ccf3b452d0f4 content/html/content/src/nsHTMLAudioElement.cpp --- a/content/html/content/src/nsHTMLAudioElement.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/html/content/src/nsHTMLAudioElement.cpp Tue May 25 21:21:43 2010 -0500 @@ -139,8 +139,74 @@ nsHTMLAudioElement::Initialize(nsISuppor if (NS_FAILED(rv)) return rv; // We have been specified with a src URL. Begin a load. QueueSelectResourceTask(); return NS_OK; } + +NS_IMETHODIMP +nsHTMLAudioElement::MozSetup(PRUint32 aChannels, PRUint32 aRate, float aVolume) +{ + // XXX: what should happen if this gets called more than once? Recreating for now... + if (mAudioStream) + mAudioStream->Shutdown(); + + mAudioStream = new nsAudioStream(); + nsresult rv = mAudioStream->Init(aChannels, aRate, nsAudioStream::FORMAT_FLOAT32); + if (NS_FAILED(rv)) + return rv; + + if (!mAudioStream) + return NS_ERROR_FAILURE; + + mChannels = aChannels; + mAudioStream->SetVolume(aVolume); + return NS_OK; +} + + +NS_IMETHODIMP +nsHTMLAudioElement::MozWriteAudio() +{ + /* Should never be called -- MozWriteAudio_explicit is the QS entry point */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsHTMLAudioElement::MozWriteAudio_explicit(float *aDataPtr, PRUint32 aDataLen, PRUint32 *_retval NS_OUTPARAM) +{ + *_retval = 0; + if (mAudioStream) { + // Make sure that we are going to write the correct amount of data based on number of channels + if (aDataLen % mChannels != 0) + return NS_ERROR_FAILURE; // XXX: better error? + else { + // Don't write more than can be written without blocking. + PRUint32 available = mAudioStream->Available(); + PRUint32 writeLen = aDataLen; + if (writeLen > available) + writeLen = available; + + nsresult rv = mAudioStream->Write(aDataPtr, writeLen, PR_TRUE); + if (NS_FAILED(rv)) + return rv; + + // Return the actual amount written. + *_retval = writeLen; + return rv; + } + } else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsHTMLAudioElement::MozCurrentSampleOffset(PRUint64 *_retval NS_OUTPARAM) +{ + if (mAudioStream) + *_retval = mAudioStream->GetSampleOffset(); + else + return NS_ERROR_FAILURE; // XXX: better error? + + return NS_OK; +} diff -r ccf3b452d0f4 content/html/content/src/nsHTMLMediaElement.cpp --- a/content/html/content/src/nsHTMLMediaElement.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/html/content/src/nsHTMLMediaElement.cpp Tue May 25 21:21:43 2010 -0500 @@ -82,16 +82,21 @@ #include "nsCycleCollectionParticipant.h" #include "nsICachingChannel.h" #include "nsLayoutUtils.h" #include "nsVideoFrame.h" #include "BasicLayers.h" #include #include "nsIDocShellTreeItem.h" +#include "nsEventDispatcher.h" +#include "nsIPrivateDOMEvent.h" +#include "nsIDOMNotifyAudioWrittenEvent.h" +#include "nsIDOMNotifyAudioMetadataEvent.h" + #ifdef MOZ_OGG #include "nsOggDecoder.h" #endif #ifdef MOZ_WAVE #include "nsWaveDecoder.h" #endif #ifdef PR_LOGGING @@ -604,16 +609,23 @@ void nsHTMLMediaElement::NotifyLoadError { if (mIsLoadingFromSrcAttribute) { NoSupportedMediaSourceError(); } else { QueueLoadFromSourceTask(); } } +void nsHTMLMediaElement::NotifyAudioWritten(float* aFrameBuffer, + PRUint32 aFrameBufferLen, + PRUint32 aTime) +{ + DispatchAudioWrittenEvent(aFrameBuffer, aFrameBufferLen, aTime); +} + void nsHTMLMediaElement::LoadFromSourceChildren() { NS_ASSERTION(mDelayingLoadEvent, "Should delay load event (if in document) during load"); while (PR_TRUE) { nsresult rv; nsCOMPtr uri = GetNextSource(); if (!uri) { @@ -1345,16 +1357,26 @@ nsHTMLMediaElement::CanPlayType(const ns case CANPLAY_NO: aResult.AssignLiteral(""); break; case CANPLAY_YES: aResult.AssignLiteral("probably"); break; default: case CANPLAY_MAYBE: aResult.AssignLiteral("maybe"); break; } return NS_OK; } +NS_IMETHODIMP +nsHTMLMediaElement::MozSetFrameBufferSize(PRUint32 aRequestedSize, PRUint32 *aActualSize) +{ + if (!mDecoder) + return NS_ERROR_FAILURE; // XXX: what's the best error here? + + *aActualSize = mDecoder->RequestFrameBufferSize(aRequestedSize); + return NS_OK; +} + /* static */ void nsHTMLMediaElement::InitMediaTypes() { nsresult rv; nsCOMPtr catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { #ifdef MOZ_OGG if (IsOggEnabled()) { @@ -1530,21 +1552,23 @@ nsresult nsHTMLMediaElement::NewURIFromS // decode it. NS_RELEASE(*aURI); return NS_ERROR_DOM_INVALID_STATE_ERR; } return NS_OK; } -void nsHTMLMediaElement::MetadataLoaded() +void nsHTMLMediaElement::MetadataLoaded(PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength) { ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA); DispatchAsyncSimpleEvent(NS_LITERAL_STRING("durationchange")); - DispatchAsyncSimpleEvent(NS_LITERAL_STRING("loadedmetadata")); + DispatchAudioMetadataEvent(aChannels, aRate, aFrameBufferLength); } void nsHTMLMediaElement::FirstFrameLoaded(PRBool aResourceFullyLoaded) { ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA); ChangeDelayLoadStatus(PR_FALSE); NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended"); @@ -1799,16 +1823,52 @@ ImageContainer* nsHTMLMediaElement::GetI nsRefPtr manager = nsContentUtils::LayerManagerForDocument(GetOwnerDoc()); if (!manager) return nsnull; mImageContainer = manager->CreateImageContainer(); return mImageContainer; } +nsresult nsHTMLMediaElement::DispatchAudioWrittenEvent(float* aFrameBuffer, + PRUint32 aFrameBufferLen, + PRUint32 aTime) +{ + nsCOMPtr docEvent(do_QueryInterface(GetOwnerDoc())); + nsCOMPtr target(do_QueryInterface(static_cast(this))); + nsCOMPtr event; + + docEvent->CreateEvent(NS_LITERAL_STRING("AudioWrittenEvent"), getter_AddRefs(event)); + nsCOMPtr audioWrittenEvent(do_QueryInterface(event)); + + audioWrittenEvent->InitAudioWrittenEvent(NS_LITERAL_STRING("audiowritten"), PR_TRUE, + PR_TRUE, aFrameBuffer, aFrameBufferLen, aTime); + + PRBool dummy; + return target->DispatchEvent(event, &dummy); +} + +nsresult nsHTMLMediaElement::DispatchAudioMetadataEvent(PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength) +{ + nsCOMPtr docEvent(do_QueryInterface(GetOwnerDoc())); + nsCOMPtr target(do_QueryInterface(static_cast(this))); + nsCOMPtr event; + + docEvent->CreateEvent(NS_LITERAL_STRING("loadedmetadata"), getter_AddRefs(event)); + nsCOMPtr audioMetadataEvent(do_QueryInterface(event)); + + audioMetadataEvent->InitAudioMetadataEvent(NS_LITERAL_STRING("loadedmetadata"), PR_TRUE, + PR_TRUE, aChannels, aRate, aFrameBufferLength); + + PRBool dummy; + return target->DispatchEvent(event, &dummy); +} + nsresult nsHTMLMediaElement::DispatchSimpleEvent(const nsAString& aName) { LOG_EVENT(PR_LOG_DEBUG, ("%p Dispatching simple event %s", this, NS_ConvertUTF16toUTF8(aName).get())); return nsContentUtils::DispatchTrustedEvent(GetOwnerDoc(), static_cast(this), aName, diff -r ccf3b452d0f4 content/media/CustomQS_Audio.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/media/CustomQS_Audio.h Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIDOMNotifyAudioWrittenEvent.h" + +static JSBool +nsIDOMNotifyAudioWrittenEvent_GetMozFrameBuffer(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ + XPC_QS_ASSERT_CONTEXT_OK(cx); + + nsIDOMNotifyAudioWrittenEvent *self; + xpc_qsSelfRef selfref; + js::AutoValueRooter tvr(cx); + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + return JS_FALSE; + + PRUint32 len; + nsresult rv = self->GetMozFrameBufferLength(&len); + if (NS_FAILED(rv)) + return JS_FALSE; // XXX: better error? + JSObject *darray = js_CreateTypedArray(cx, js::TypedArray::TYPE_FLOAT32, len); + + js::AutoValueRooter rd(cx, darray); + if (!darray) + return JS_FALSE; + + js::TypedArray *tdest = js::TypedArray::fromJSObject(darray); + + rv = self->GetMozFrameBuffer_explicit((float*) tdest->data, len); + + if (NS_FAILED(rv)) + return xpc_qsThrowMethodFailed(cx, rv, vp); + + // XXX: should we be caching this array so we don't recreate on next call? + *vp = OBJECT_TO_JSVAL(darray); + return JS_TRUE; +} + +static JSBool +nsIDOMHTMLAudioElement_MozWriteAudio(JSContext *cx, uintN argc, jsval *vp) +{ + XPC_QS_ASSERT_CONTEXT_OK(cx); + + JSObject *obj = JS_THIS_OBJECT(cx, vp); + if (!obj) + return JS_FALSE; + + nsIDOMHTMLAudioElement *self; + xpc_qsSelfRef selfref; + js::AutoValueRooter tvr(cx); + + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + return JS_FALSE; + if (argc < 1) + return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS); + + jsval *argv = JS_ARGV(cx, vp); + + if (JSVAL_IS_PRIMITIVE(argv[0])) + return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR); + + JSObject *darray = JSVAL_TO_OBJECT(argv[0]); + js::AutoValueRooter tsrc_tvr(cx); + js::TypedArray *tsrc = NULL; + + // Allow either Float32Array or [] + if (darray->getClass() == &js::TypedArray::fastClasses[js::TypedArray::TYPE_FLOAT32]) + { + tsrc = js::TypedArray::fromJSObject(darray); + } else if (JS_IsArrayObject(cx, darray)) { + JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, darray); + if (!nobj) + return JS_FALSE; + + *tsrc_tvr.addr() = OBJECT_TO_JSVAL(nobj); + tsrc = js::TypedArray::fromJSObject(nobj); + } else { + return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR); + } + + PRUint32 written; + nsresult rv = self->MozWriteAudio_explicit((float*) tsrc->data, tsrc->length, &written); + if (NS_FAILED(rv)) + return xpc_qsThrowMethodFailed(cx, rv, vp); + + *vp = INT_TO_JSVAL(jsint(written)); + return JS_TRUE; +} diff -r ccf3b452d0f4 content/media/Makefile.in --- a/content/media/Makefile.in Tue May 25 18:40:45 2010 -0500 +++ b/content/media/Makefile.in Tue May 25 21:21:43 2010 -0500 @@ -48,25 +48,28 @@ LIBXUL_LIBRARY = 1 EXPORTS = \ nsMediaDecoder.h \ nsMediaStream.h \ nsMediaCache.h \ nsBuiltinDecoder.h \ nsBuiltinDecoderStateMachine.h \ nsBuiltinDecoderReader.h \ VideoUtils.h \ + nsAudioWrittenEventManager.h \ + CustomQS_Audio.h \ $(NULL) CPPSRCS = \ nsMediaDecoder.cpp \ nsMediaCache.cpp \ nsMediaStream.cpp \ nsBuiltinDecoder.cpp \ nsBuiltinDecoderStateMachine.cpp \ nsBuiltinDecoderReader.cpp \ + nsAudioWrittenEventManager.cpp \ $(NULL) ifdef MOZ_SYDNEYAUDIO EXPORTS += \ nsAudioStream.h \ $(NULL) CPPSRCS += \ nsAudioStream.cpp \ diff -r ccf3b452d0f4 content/media/nsAudioStream.cpp --- a/content/media/nsAudioStream.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/media/nsAudioStream.cpp Tue May 25 21:21:43 2010 -0500 @@ -76,60 +76,62 @@ nsAudioStream::nsAudioStream() : { } nsAudioStream::~nsAudioStream() { Shutdown(); } -void nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat) +nsresult nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat) { mRate = aRate; mChannels = aNumChannels; mFormat = aFormat; if (sa_stream_create_pcm(reinterpret_cast(&mAudioHandle), NULL, SA_MODE_WRONLY, SA_PCM_FORMAT_S16_NE, aRate, aNumChannels) != SA_SUCCESS) { mAudioHandle = nsnull; PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_create_pcm error")); - return; + return NS_ERROR_FAILURE; } - + if (sa_stream_open(static_cast(mAudioHandle)) != SA_SUCCESS) { sa_stream_destroy(static_cast(mAudioHandle)); mAudioHandle = nsnull; PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_open error")); - return; + return NS_ERROR_FAILURE; } + + return NS_OK; } void nsAudioStream::Shutdown() { if (!mAudioHandle) return; sa_stream_destroy(static_cast(mAudioHandle)); mAudioHandle = nsnull; } -void nsAudioStream::Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking) +nsresult nsAudioStream::Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking) { NS_ABORT_IF_FALSE(aCount % mChannels == 0, "Buffer size must be divisible by channel count"); NS_ASSERTION(!mPaused, "Don't write audio when paused, you'll block"); PRUint32 offset = mBufferOverflow.Length(); PRUint32 count = aCount + offset; if (!mAudioHandle) - return; + return NS_ERROR_FAILURE; nsAutoArrayPtr s_data(new short[count]); if (s_data) { for (PRUint32 i=0; i < offset; ++i) { s_data[i] = mBufferOverflow.ElementAt(i); } mBufferOverflow.Clear(); @@ -185,18 +187,21 @@ void nsAudioStream::Write(const void* aB } if (sa_stream_write(static_cast(mAudioHandle), s_data.get(), count * sizeof(short)) != SA_SUCCESS) { PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error")); Shutdown(); + return NS_ERROR_FAILURE; } } + + return NS_OK; } PRUint32 nsAudioStream::Available() { // If the audio backend failed to open, lie and say we'll accept some // data. if (!mAudioHandle) return FAKE_BUFFER_SIZE; @@ -263,8 +268,25 @@ PRInt64 nsAudioStream::GetPosition() if (sa_stream_get_position(static_cast(mAudioHandle), positionType, &position) == SA_SUCCESS) { return ((1000 * position) / mRate / mChannels / sizeof(short)); } return -1; } +PRInt64 nsAudioStream::GetSampleOffset() +{ + if (!mAudioHandle) + return -1; + + sa_position_t positionType = SA_POSITION_WRITE_SOFTWARE; +#if defined(XP_WIN) + positionType = SA_POSITION_WRITE_HARDWARE; +#endif + PRInt64 position = 0; + if (sa_stream_get_position(static_cast(mAudioHandle), + positionType, &position) == SA_SUCCESS) { + return (position / sizeof(short)); + } + + return 0; +} diff -r ccf3b452d0f4 content/media/nsAudioStream.h --- a/content/media/nsAudioStream.h Tue May 25 18:40:45 2010 -0500 +++ b/content/media/nsAudioStream.h Tue May 25 21:21:43 2010 -0500 @@ -63,28 +63,28 @@ class nsAudioStream static void ShutdownLibrary(); nsAudioStream(); ~nsAudioStream(); // Initialize the audio stream. aNumChannels is the number of audio channels // (1 for mono, 2 for stereo, etc) and aRate is the frequency of the sound // samples (22050, 44100, etc). - void Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat); + nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat); // Closes the stream. All future use of the stream is an error. void Shutdown(); // Write sound data to the audio hardware. aBuf is an array of samples in // the format specified by mFormat of length aCount. aCount should be // evenly divisible by the number of channels in this audio stream. // When aBlocking is PR_TRUE, we'll block until the write has completed, // otherwise we'll buffer any data we can't write immediately, and write // it in a later call. - void Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking); + nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking); // Return the number of sound samples that can be written to the audio device // without blocking. PRUint32 Available(); // Set the current volume of the audio playback. This is a value from // 0 (meaning muted) to 1 (meaning full volume). void SetVolume(float aVolume); @@ -97,16 +97,20 @@ class nsAudioStream // Resume audio playback void Resume(); // Return the position in milliseconds of the sample being played by the // audio hardware. PRInt64 GetPosition(); + // Return the position, measured in samples played since the start, by + // the audio hardware. + PRInt64 GetSampleOffset(); + // Returns PR_TRUE when the audio stream is paused. PRBool IsPaused() { return mPaused; } private: double mVolume; void* mAudioHandle; int mRate; int mChannels; diff -r ccf3b452d0f4 content/media/nsAudioWrittenEventManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/media/nsAudioWrittenEventManager.cpp Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * Yury Delendik + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsTArray.h" +#include "nsAudioWrittenEventManager.h" + +using namespace mozilla; + +class nsAudioWrittenEventRunner : public nsRunnable +{ +private: + nsCOMPtr mDecoder; + nsAutoArrayPtr mFrameBuffer; +public: + nsAudioWrittenEventRunner(nsBuiltinDecoder* aDecoder, float* aFrameBuffer, + PRUint32 aFrameBufferLen, PRUint32 aTime) : + mDecoder(aDecoder), + mFrameBuffer(aFrameBuffer), + mFrameBufferLen(aFrameBufferLen), + mTime(aTime) + { + } + NS_IMETHOD Run() { + mDecoder->AudioWritten(mFrameBuffer.forget(), mFrameBufferLen, mTime); + return NS_OK; + } + const PRUint32 mFrameBufferLen; + const PRUint32 mTime; +}; + + +nsAudioWrittenEventManager::nsAudioWrittenEventManager(nsBuiltinDecoder* aDecoder, + nsBuiltinDecoderReader* aReader) : + mDecoder(aDecoder), + mReader(aReader), + mSignalBuffer(new float[mDecoder->GetFrameBufferSize()]), + mSignalBufferPosition(0), + mSignalBufferLen(mDecoder->GetFrameBufferSize()) +{ +} + +void nsAudioWrittenEventManager::DispatchPendingEvents(PRInt64 aCurrentTime) +{ + if(mPendingEvents.Length() > 0) { + do { + nsAudioWrittenEventRunner* e = + (nsAudioWrittenEventRunner*)mPendingEvents[0].get(); + if (e->mTime <= aCurrentTime) { + nsCOMPtr event = mPendingEvents[0]; + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + mPendingEvents.RemoveElementAt(0); + } else { + break; + } + } while (mPendingEvents.Length() > 0); + } +} + +void nsAudioWrittenEventManager::QueueWrittenAudioData(float* aAudioData, + PRUint32 aAudioDataLength, + PRUint32 aAudioEndTime) +{ + // XXX: should I skip all this work (and event) if there are no listeners? + // http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsContentUtils.cpp#3391 + PRUint32 currentBufferSize = mDecoder->GetFrameBufferSize(); + if (mSignalBufferPosition == 0 && mSignalBufferLen != currentBufferSize) { + if(mSignalBufferLen < currentBufferSize) { + // resize only if buffer smaller -- saving memory allow cycles + mSignalBuffer = new float[currentBufferSize]; + } + mSignalBufferLen = currentBufferSize; + } + + float * audioData = aAudioData; + PRUint32 audioDataLength = aAudioDataLength; + PRUint32 signalBufferTail = mSignalBufferLen - mSignalBufferPosition; + + // Group audio samples into optimal size for event dispatch, and queue. + while (signalBufferTail <= audioDataLength) { + PRUint32 time = 1 + (PRUint32) aAudioEndTime - + (1000 * (mSignalBufferPosition + audioDataLength)) / + mReader->GetInfo().mAudioChannels / mReader->GetInfo().mAudioRate; + + // Fill the signalBuffer. + memcpy(mSignalBuffer.get() + mSignalBufferPosition, + audioData, sizeof(float) * signalBufferTail); + audioData += signalBufferTail; + audioDataLength -= signalBufferTail; + + if(mPendingEvents.Length() > 0) { + // Check last event timecode to make sure that all queued events + // are in non-decending sequence. + nsAudioWrittenEventRunner* lastPendingEvent = + (nsAudioWrittenEventRunner*)mPendingEvents[mPendingEvents.Length() - 1].get(); + if(lastPendingEvent->mTime > time) { + // Clearing the queue to start fresh sequence. + mPendingEvents.Clear(); + } + } + + // Inform the element that we've written sound data. + nsCOMPtr event = + new nsAudioWrittenEventRunner(mDecoder, mSignalBuffer.forget(), + mSignalBufferLen, time); + mPendingEvents.AppendElement(event); + + // Reset the buffer + mSignalBufferLen = currentBufferSize; + mSignalBuffer = new float[currentBufferSize]; + mSignalBufferPosition = 0; + signalBufferTail = currentBufferSize; + NS_ASSERTION(audioDataLength >= 0, "Past new signal data length."); + } + + NS_ASSERTION(mSignalBufferPosition + audioDataLength < mSignalBufferLen, + "Intermediate signal buffer must fit at least one more item."); + if (audioDataLength > 0) { + // Add data to the signalBuffer + memcpy(mSignalBuffer.get() + mSignalBufferPosition, + audioData, sizeof(float) * audioDataLength); + mSignalBufferPosition += audioDataLength; + } +} + +void nsAudioWrittenEventManager::Clear() +{ + mPendingEvents.Clear(); +} diff -r ccf3b452d0f4 content/media/nsAudioWrittenEventManager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/media/nsAudioWrittenEventManager.h Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * Yury Delendik + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* +Additional support for audiowritten event manger needed +by nsBuiltinDecoderStateMachine. +*/ +#if !defined(nsAudioWrittenEventManager_h__) +#define nsAudioWrittenEventManager_h__ + +#include "nsCOMPtr.h" +#include "nsIRunnable.h" +#include "nsBuiltinDecoder.h" +#include "nsBuiltinDecoderReader.h" + +class nsAudioWrittenEventManager +{ +public: + nsAudioWrittenEventManager(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader); + + // Dispatches pending events in state machine thread + void DispatchPendingEvents(PRInt64 aCurrentTime); + + // Queues the data and re-packages into same size packages + void QueueWrittenAudioData(float* aAudioData, PRUint32 aAudioDataLength, + PRUint32 aAudioEndTime); + + // Clears the queue + void Clear(); + +private: + nsBuiltinDecoder* mDecoder; + + nsBuiltinDecoderReader* mReader; + + // A buffer for audio data to be dispatched in DOM events. + nsAutoArrayPtr mSignalBuffer; + + // The current size of the signal buffer, may change due to DOM calls. + PRUint32 mSignalBufferLen; + + // A position of first available item in mSignalBuffer + PRUint32 mSignalBufferPosition; + + // Stores audiowritten events to be dispatched in state machine thread. + nsTArray< nsCOMPtr > mPendingEvents; +}; + +#endif diff -r ccf3b452d0f4 content/media/nsBuiltinDecoder.cpp --- a/content/media/nsBuiltinDecoder.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/media/nsBuiltinDecoder.cpp Tue May 25 21:21:43 2010 -0500 @@ -286,36 +286,49 @@ nsMediaStream* nsBuiltinDecoder::GetCurr } already_AddRefed nsBuiltinDecoder::GetCurrentPrincipal() { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); return mStream ? mStream->GetCurrentPrincipal() : nsnull; } -void nsBuiltinDecoder::MetadataLoaded() +void nsBuiltinDecoder::AudioWritten(float* aFrameBuffer, + PRUint32 aFrameBufferLen, + PRUint32 aTime) +{ + NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); + if (mShuttingDown) + return; + + mElement->NotifyAudioWritten(aFrameBuffer, aFrameBufferLen, aTime); +} + +void nsBuiltinDecoder::MetadataLoaded(PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength) { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); if (mShuttingDown) return; // Only inform the element of MetadataLoaded if not doing a load() in order // to fulfill a seek, otherwise we'll get multiple metadataloaded events. PRBool notifyElement = PR_TRUE; { MonitorAutoEnter mon(mMonitor); mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1; notifyElement = mNextState != PLAY_STATE_SEEKING; } if (mElement && notifyElement) { // Make sure the element and the frame (if any) are told about - // our new size. + // our new size and update with audio stream info Invalidate(); - mElement->MetadataLoaded(); + mElement->MetadataLoaded(aChannels, aRate, aFrameBufferLength); } if (!mResourceLoaded) { StartProgress(); } else if (mElement) { // Resource was loaded during metadata loading, when progress // events are being ignored. Fire the final progress event. diff -r ccf3b452d0f4 content/media/nsBuiltinDecoder.h --- a/content/media/nsBuiltinDecoder.h Tue May 25 18:40:45 2010 -0500 +++ b/content/media/nsBuiltinDecoder.h Tue May 25 21:21:43 2010 -0500 @@ -396,16 +396,18 @@ class nsBuiltinDecoder : public nsMediaD // Tells our nsMediaStream to put all loads in the background. virtual void MoveLoadsToBackground(); // Stop the state machine thread and drop references to the thread and // state machine. void Stop(); + void AudioWritten(float* aFrameBuffer, PRUint32 aFrameBufferLen, PRUint32 aTime); + // Called by the state machine to notify the decoder that the duration // has changed. void DurationChanged(); PRBool OnStateMachineThread() { return IsCurrentThread(mStateMachineThread); } @@ -458,17 +460,19 @@ class nsBuiltinDecoder : public nsMediaD // Change to a new play state. This updates the mState variable and // notifies any thread blocking on this object's monitor of the // change. Call on the main thread only. void ChangeState(PlayState aState); // Called when the metadata from the media file has been read. // Call on the main thread only. - void MetadataLoaded(); + void MetadataLoaded(PRUint32 aChannels, + PRUint32 aRate, + PRUint32 aFrameBufferLength); // Called when the first frame has been loaded. // Call on the main thread only. void FirstFrameLoaded(); // Called when the video has completed playing. // Call on the main thread only. void PlaybackEnded(); diff -r ccf3b452d0f4 content/media/nsBuiltinDecoderStateMachine.cpp --- a/content/media/nsBuiltinDecoderStateMachine.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/media/nsBuiltinDecoderStateMachine.cpp Tue May 25 21:21:43 2010 -0500 @@ -87,16 +87,38 @@ const unsigned AMPLE_AUDIO_MS = 2000; // which is at or after the current playback position. // // Also if the decode catches up with the end of the downloaded data, // we'll only go into BUFFERING state if we've got audio and have queued // less than LOW_AUDIO_MS of audio, or if we've got video and have queued // less than LOW_VIDEO_FRAMES frames. static const PRUint32 LOW_VIDEO_FRAMES = 1; +class nsAudioMetadataEventRunner : public nsRunnable +{ +private: + nsCOMPtr mDecoder; +public: + nsAudioMetadataEventRunner(nsBuiltinDecoder* aDecoder, PRUint32 aChannels, + PRUint32 aRate, PRUint32 aFrameBufferLength) : + mDecoder(aDecoder), + mChannels(aChannels), + mRate(aRate), + mFrameBufferLength(aFrameBufferLength) + { + } + NS_IMETHOD Run() { + mDecoder->MetadataLoaded(mChannels, mRate, mFrameBufferLength); + return NS_OK; + } + const PRUint32 mChannels; + const PRUint32 mRate; + const PRUint32 mFrameBufferLength; +}; + nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader) : mDecoder(aDecoder), mState(DECODER_STATE_DECODING_METADATA), mAudioMonitor("media.audiostream"), mCbCrSize(0), mPlayDuration(0), mBufferingEndOffset(0), @@ -109,17 +131,18 @@ nsBuiltinDecoderStateMachine::nsBuiltinD mAudioEndTime(-1), mVideoFrameTime(-1), mVolume(1.0), mSeekable(PR_TRUE), mPositionChangeQueued(PR_FALSE), mAudioCompleted(PR_FALSE), mBufferExhausted(PR_FALSE), mGotDurationFromHeader(PR_FALSE), - mStopDecodeThreads(PR_TRUE) + mStopDecodeThreads(PR_TRUE), + mEventManager(aDecoder, aReader) { MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine); } nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine() { MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine); } @@ -382,16 +405,20 @@ void nsBuiltinDecoderStateMachine::Audio // able to acquire the audio monitor in order to resume or destroy the // audio stream. if (!mAudioStream->IsPaused()) { mAudioStream->Write(sound->mAudioData, sound->AudioDataLength(), PR_TRUE); audioEndTime = sound->mTime + sound->mDuration; mDecoder->UpdatePlaybackOffset(sound->mOffset); + + mEventManager.QueueWrittenAudioData(sound->mAudioData.get(), + sound->AudioDataLength(), + audioEndTime); } else { mReader->mAudioQueue.PushFront(sound); sound.forget(); } } } sound = nsnull; @@ -464,16 +491,17 @@ void nsBuiltinDecoderStateMachine::StopP MonitorAutoExit exitMon(mDecoder->GetMonitor()); MonitorAutoEnter audioMon(mAudioMonitor); if (mAudioStream) { if (aMode == AUDIO_PAUSE) { mAudioStream->Pause(); } else if (aMode == AUDIO_SHUTDOWN) { mAudioStream->Shutdown(); mAudioStream = nsnull; + mEventManager.Clear(); } } } } void nsBuiltinDecoderStateMachine::StartPlayback() { NS_ASSERTION(IsCurrentThread(mDecoder->mStateMachineThread), @@ -520,16 +548,19 @@ void nsBuiltinDecoderStateMachine::Updat NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); } if (!mPositionChangeQueued) { mPositionChangeQueued = PR_TRUE; nsCOMPtr event = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::PlaybackPositionChanged); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); } + + // Notify DOM of any queued up audiowritten events + mEventManager.DispatchPendingEvents(mCurrentFrameTime + mStartTime); } void nsBuiltinDecoderStateMachine::ClearPositionChangeFlag() { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); mDecoder->GetMonitor().AssertCurrentThreadIn(); mPositionChangeQueued = PR_FALSE; @@ -765,17 +796,18 @@ nsresult nsBuiltinDecoderStateMachine::R mDecoder, mStartTime, mEndTime, GetDuration(), mSeekable)); if (mState == DECODER_STATE_SHUTDOWN) continue; // Inform the element that we've loaded the metadata and the // first frame. nsCOMPtr metadataLoadedEvent = - NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::MetadataLoaded); + new nsAudioMetadataEventRunner(mDecoder, mReader->GetInfo().mAudioChannels, + mReader->GetInfo().mAudioRate, mDecoder->GetFrameBufferSize()); NS_DispatchToMainThread(metadataLoadedEvent, NS_DISPATCH_NORMAL); if (mState == DECODER_STATE_DECODING_METADATA) { LOG(PR_LOG_DEBUG, ("%p Changed state from DECODING_METADATA to DECODING", mDecoder)); mState = DECODER_STATE_DECODING; } // Start playback. diff -r ccf3b452d0f4 content/media/nsBuiltinDecoderStateMachine.h --- a/content/media/nsBuiltinDecoderStateMachine.h Tue May 25 18:40:45 2010 -0500 +++ b/content/media/nsBuiltinDecoderStateMachine.h Tue May 25 21:21:43 2010 -0500 @@ -111,16 +111,17 @@ not yet time to display the next frame. */ #if !defined(nsBuiltinDecoderStateMachine_h__) #define nsBuiltinDecoderStateMachine_h__ #include "prmem.h" #include "nsThreadUtils.h" #include "nsBuiltinDecoder.h" #include "nsBuiltinDecoderReader.h" +#include "nsAudioWrittenEventManager.h" #include "nsHTMLMediaElement.h" #include "mozilla/Monitor.h" /* The playback state machine class. This manages the decoding in the nsBuiltinDecoderReader on the decode thread, seeking and in-sync-playback on the state machine thread, and controls the audio "push" thread. @@ -430,12 +431,15 @@ protected: // PR_TRUE if mDuration has a value obtained from an HTTP header. // Accessed on the state machine thread. PRPackedBool mGotDurationFromHeader; // PR_FALSE while decode threads should be running. Accessed on audio, // state machine and decode threads. Syncrhonised by decoder monitor. PRPackedBool mStopDecodeThreads; + +private: + // Manager audiowritten events + nsAudioWrittenEventManager mEventManager; }; - #endif diff -r ccf3b452d0f4 content/media/nsMediaDecoder.cpp --- a/content/media/nsMediaDecoder.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/media/nsMediaDecoder.cpp Tue May 25 21:21:43 2010 -0500 @@ -67,17 +67,18 @@ nsMediaDecoder::nsMediaDecoder() : mElement(0), mRGBWidth(-1), mRGBHeight(-1), mProgressTime(), mDataTime(), mVideoUpdateLock(nsnull), mPixelAspectRatio(1.0), mSizeChanged(PR_FALSE), - mShuttingDown(PR_FALSE) + mShuttingDown(PR_FALSE), + mFrameBufferSize(FRAMEBUFFER_SIZE) { MOZ_COUNT_CTOR(nsMediaDecoder); } nsMediaDecoder::~nsMediaDecoder() { if (mVideoUpdateLock) { PR_DestroyLock(mVideoUpdateLock); @@ -100,16 +101,23 @@ void nsMediaDecoder::Shutdown() mElement = nsnull; } nsHTMLMediaElement* nsMediaDecoder::GetMediaElement() { return mElement; } +PRUint32 nsMediaDecoder::RequestFrameBufferSize(PRUint32 aSize) +{ + // TODO: threadsafety, check size, etc. + mFrameBufferSize = aSize; + return mFrameBufferSize; +} + static PRInt32 ConditionDimension(float aValue, PRInt32 aDefault) { // This will exclude NaNs and infinities if (aValue >= 1.0 && aValue <= 10000.0) return PRInt32(NS_round(aValue)); return aDefault; } diff -r ccf3b452d0f4 content/media/nsMediaDecoder.h --- a/content/media/nsMediaDecoder.h Tue May 25 18:40:45 2010 -0500 +++ b/content/media/nsMediaDecoder.h Tue May 25 21:21:43 2010 -0500 @@ -47,16 +47,22 @@ #include "gfxRect.h" #include "nsITimer.h" #include "ImageLayers.h" class nsHTMLMediaElement; class nsMediaStream; class nsIStreamListener; +/* The size to use for audio data frames in audiowritten events. + * XXXdh: This assumes a few things about sizes, needs to be thought through. + * Have tested with these sizes: 64, 128, 512, 1024, 2048 -- all crash. + */ +#define FRAMEBUFFER_SIZE 4096 // XXX: need to consider channel/rate + // All methods of nsMediaDecoder must be called from the main thread only // with the exception of GetImageContainer, SetVideoData and GetStatistics, // which can be called from any thread. class nsMediaDecoder : public nsIObserver { public: typedef mozilla::TimeStamp TimeStamp; typedef mozilla::TimeDuration TimeDuration; @@ -211,16 +217,23 @@ public: // The download will only actually resume once as many Resume calls // have been made as Suspend calls. virtual void Resume() = 0; // Returns a weak reference to the media element we're decoding for, // if it's available. nsHTMLMediaElement* GetMediaElement(); + // XXX: Gets the current size of the framebuffer used in audiowritten events. + PRUint32 GetFrameBufferSize() { return mFrameBufferSize; }; + + // XXX: Attempts to set the size of the framebuffer used in audiowritten events. + // Returns the acutal size that will be used. + PRUint32 RequestFrameBufferSize(PRUint32 aSize); + // Moves any existing channel loads into the background, so that they don't // block the load event. This is called when we stop delaying the load // event. Any new loads initiated (for example to seek) will also be in the // background. Implementations of this must call MoveLoadsToBackground() on // their nsMediaStream. virtual void MoveLoadsToBackground()=0; // Gets the image container for the media element. Will return null if @@ -288,11 +301,14 @@ protected: // Has our size changed since the last repaint? PRPackedBool mSizeChanged; // True if the decoder is being shutdown. At this point all events that // are currently queued need to return immediately to prevent javascript // being run that operates on the element and decoder during shutdown. // Read/Write from the main thread only. PRPackedBool mShuttingDown; + + // XXX: The framebuffer size to use for audiowritten events. + PRUint32 mFrameBufferSize; }; #endif diff -r ccf3b452d0f4 content/media/wave/nsWaveDecoder.cpp --- a/content/media/wave/nsWaveDecoder.cpp Tue May 25 18:40:45 2010 -0500 +++ b/content/media/wave/nsWaveDecoder.cpp Tue May 25 21:21:43 2010 -0500 @@ -141,16 +141,25 @@ public: void Seek(float aTime); void Shutdown(); // Returns the playback length of the audio data in seconds, calculated // from the length extracted from the metadata. Returns NaN if called // before metadata validation has completed. Threadsafe. float GetDuration(); + // Returns the number of channels extracted from the metadata. Returns 0 + // if called before metadata validation has completed. Threadsafe. + PRUint32 GetChannels(); + + // Returns the audio sample rate (number of samples per second) extracted + // from the metadata. Returns 0 if called before metadata validation has + // completed. Threadsafe. + PRUint32 GetSampleRate(); + // Returns true if the state machine is seeking. Threadsafe. PRBool IsSeeking(); // Returns true if the state machine has reached the end of playback. Threadsafe. PRBool IsEnded(); // Main state machine loop. Runs forever, until shutdown state is reached. NS_IMETHOD Run(); @@ -463,16 +472,36 @@ nsWaveStateMachine::GetDuration() { nsAutoMonitor monitor(mMonitor); if (mMetadataValid) { return BytesToTime(GetDataLength()); } return std::numeric_limits::quiet_NaN(); } +PRUint32 +nsWaveStateMachine::GetChannels() +{ + nsAutoMonitor monitor(mMonitor); + if (mMetadataValid) { + return mChannels; + } + return 0; +} + +PRUint32 +nsWaveStateMachine::GetSampleRate() +{ + nsAutoMonitor monitor(mMonitor); + if (mMetadataValid) { + return mSampleRate; + } + return 0; +} + PRBool nsWaveStateMachine::IsSeeking() { nsAutoMonitor monitor(mMonitor); return mState == STATE_SEEKING || mNextState == STATE_SEEKING; } PRBool @@ -1348,17 +1377,19 @@ nsWaveDecoder::Load(nsMediaStream* aStre void nsWaveDecoder::MetadataLoaded() { if (mShuttingDown) { return; } if (mElement) { - mElement->MetadataLoaded(); + mElement->MetadataLoaded(mPlaybackStateMachine->GetChannels(), + mPlaybackStateMachine->GetSampleRate(), + FRAMEBUFFER_SIZE); mElement->FirstFrameLoaded(mResourceLoaded); } mMetadataLoadedReported = PR_TRUE; if (mResourceLoaded) { ResourceLoaded(); } else { diff -r ccf3b452d0f4 dom/base/nsDOMClassInfo.cpp --- a/dom/base/nsDOMClassInfo.cpp Tue May 25 18:40:45 2010 -0500 +++ b/dom/base/nsDOMClassInfo.cpp Tue May 25 21:21:43 2010 -0500 @@ -229,16 +229,18 @@ #include "nsIDOMBeforeUnloadEvent.h" #include "nsIDOMMutationEvent.h" #include "nsIDOMSmartCardEvent.h" #include "nsIDOMXULCommandEvent.h" #include "nsIDOMPageTransitionEvent.h" #include "nsIDOMMessageEvent.h" #include "nsPaintRequest.h" #include "nsIDOMNotifyPaintEvent.h" +#include "nsIDOMNotifyAudioWrittenEvent.h" +#include "nsIDOMNotifyAudioMetadataEvent.h" #include "nsIDOMScrollAreaEvent.h" #include "nsIDOMTransitionEvent.h" #include "nsIDOMNSDocumentStyle.h" #include "nsIDOMDocumentRange.h" #include "nsIDOMDocumentTraversal.h" #include "nsIDOMDocumentXBL.h" #include "nsIDOMDocumentView.h" #include "nsIDOMElementCSSInlineStyle.h" @@ -1340,16 +1342,22 @@ static nsDOMClassInfoData sClassInfoData // data transfer for drag and drop NS_DEFINE_CLASSINFO_DATA(DataTransfer, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(NotifyPaintEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(NotifyAudioWrittenEvent, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) + + NS_DEFINE_CLASSINFO_DATA(NotifyAudioMetadataEvent, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(SimpleGestureEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) #ifdef MOZ_MATHML NS_DEFINE_CLASSINFO_DATA_WITH_NAME(MathMLElement, Element, nsElementSH, ELEMENT_SCRIPTABLE_FLAGS) #endif @@ -3750,16 +3758,26 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSDataTransfer) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(NotifyPaintEvent, nsIDOMNotifyPaintEvent) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNotifyPaintEvent) DOM_CLASSINFO_EVENT_MAP_ENTRIES DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(NotifyAudioWrittenEvent, nsIDOMNotifyAudioWrittenEvent) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMNotifyAudioWrittenEvent) + DOM_CLASSINFO_EVENT_MAP_ENTRIES + DOM_CLASSINFO_MAP_END + + DOM_CLASSINFO_MAP_BEGIN(NotifyAudioMetadataEvent, nsIDOMNotifyAudioMetadataEvent) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMNotifyAudioMetadataEvent) + DOM_CLASSINFO_EVENT_MAP_ENTRIES + DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(SimpleGestureEvent, nsIDOMSimpleGestureEvent) DOM_CLASSINFO_MAP_ENTRY(nsIDOMSimpleGestureEvent) DOM_CLASSINFO_MAP_ENTRY(nsIDOMMouseEvent) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSMouseEvent) DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES DOM_CLASSINFO_MAP_END #ifdef MOZ_MATHML diff -r ccf3b452d0f4 dom/base/nsDOMClassInfoClasses.h --- a/dom/base/nsDOMClassInfoClasses.h Tue May 25 18:40:45 2010 -0500 +++ b/dom/base/nsDOMClassInfoClasses.h Tue May 25 21:21:43 2010 -0500 @@ -435,16 +435,20 @@ DOMCI_CLASS(XMLHttpRequestUpload) // DOM Traversal NodeIterator class DOMCI_CLASS(NodeIterator) DOMCI_CLASS(DataTransfer) DOMCI_CLASS(NotifyPaintEvent) +DOMCI_CLASS(NotifyAudioWrittenEvent) + +DOMCI_CLASS(NotifyAudioMetadataEvent) + DOMCI_CLASS(SimpleGestureEvent) #ifdef MOZ_MATHML DOMCI_CLASS(MathMLElement) #endif DOMCI_CLASS(Worker) DOMCI_CLASS(ChromeWorker) diff -r ccf3b452d0f4 dom/interfaces/events/Makefile.in --- a/dom/interfaces/events/Makefile.in Tue May 25 18:40:45 2010 -0500 +++ b/dom/interfaces/events/Makefile.in Tue May 25 21:21:43 2010 -0500 @@ -71,16 +71,18 @@ XPIDLSRCS = \ nsIDOMPopupBlockedEvent.idl \ nsIDOMBeforeUnloadEvent.idl \ nsIDOMNSEventTarget.idl \ nsIDOMSmartCardEvent.idl \ nsIDOMPageTransitionEvent.idl \ nsIDOMCommandEvent.idl \ nsIDOMMessageEvent.idl \ nsIDOMNotifyPaintEvent.idl \ + nsIDOMNotifyAudioWrittenEvent.idl \ + nsIDOMNotifyAudioMetadataEvent.idl \ nsIDOMPaintRequest.idl \ nsIDOMPaintRequestList.idl \ nsIDOMSimpleGestureEvent.idl \ nsIDOMNSMouseEvent.idl \ nsIDOMOrientationEvent.idl \ nsIDOMScrollAreaEvent.idl \ nsIDOMTransitionEvent.idl \ nsIDOMPopStateEvent.idl \ diff -r ccf3b452d0f4 dom/interfaces/events/nsIDOMNotifyAudioMetadataEvent.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/interfaces/events/nsIDOMNotifyAudioMetadataEvent.idl Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIDOMEvent.idl" +#include "domstubs.idl" + +[scriptable, uuid(c208ebed-3c97-4a37-8f5b-33dffecd1103)] +interface nsIDOMNotifyAudioMetadataEvent : nsIDOMEvent +{ + readonly attribute unsigned long mozChannels; + readonly attribute unsigned long mozRate; + readonly attribute unsigned long mozFrameBufferLength; + + [noscript] void initAudioMetadataEvent(in DOMString typeArg, + in boolean canBubbleArg, + in boolean cancelableArg, + in unsigned long channels, + in unsigned long rate, + in unsigned long frameBufferLength); +}; diff -r ccf3b452d0f4 dom/interfaces/events/nsIDOMNotifyAudioWrittenEvent.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/interfaces/events/nsIDOMNotifyAudioWrittenEvent.idl Tue May 25 21:21:43 2010 -0500 @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Humphrey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIDOMEvent.idl" +#include "nsIVariant.idl" +#include "domstubs.idl" + +[scriptable, uuid(6250652d-7a6a-49a4-a2ee-9114e1e83427)] +interface nsIDOMNotifyAudioWrittenEvent : nsIDOMEvent +{ + readonly attribute nsIVariant mozFrameBuffer; + readonly attribute unsigned long mozTime; + + [noscript] void getMozFrameBuffer_explicit([array, size_is(dataLen)] in float dataPtr, + in unsigned long dataLen); + + [noscript] unsigned long getMozFrameBufferLength(); + + [noscript] void initAudioWrittenEvent(in DOMString typeArg, + in boolean canBubbleArg, + in boolean cancelableArg, + [array, size_is(frameBufferLen)] in float frameBufferPtr, + in unsigned long frameBufferLen, + in unsigned long time); +}; diff -r ccf3b452d0f4 dom/interfaces/html/nsIDOMHTMLAudioElement.idl --- a/dom/interfaces/html/nsIDOMHTMLAudioElement.idl Tue May 25 18:40:45 2010 -0500 +++ b/dom/interfaces/html/nsIDOMHTMLAudioElement.idl Tue May 25 21:21:43 2010 -0500 @@ -46,10 +46,22 @@ * http://www.whatwg.org/specs/web-apps/current-work/#audio * * @status UNDER_DEVELOPMENT */ [scriptable, uuid(5ecd8913-a738-41be-8597-7f3a4ffba017)] interface nsIDOMHTMLAudioElement : nsIDOMHTMLMediaElement { + // This is a dummy function; for JS it is implemented as a quickstub + // that calls the _explicit method. + void mozWriteAudio(); + + [noscript] unsigned long mozWriteAudio_explicit([array, size_is(dataLen)] in float dataPtr, + in unsigned long dataLen); + + // Setup the audio stream for writing + void mozSetup(in PRUint32 channels, in PRUint32 rate, in float volume); + + // Get the current offset (measured in samples since the start) of the audio + // stream created using mozWriteAudio(). + unsigned long long mozCurrentSampleOffset(); }; - diff -r ccf3b452d0f4 dom/interfaces/html/nsIDOMHTMLMediaElement.idl --- a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl Tue May 25 18:40:45 2010 -0500 +++ b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl Tue May 25 21:21:43 2010 -0500 @@ -101,9 +101,12 @@ interface nsIDOMHTMLMediaElement : nsIDO // 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. void mozLoadFrom(in nsIDOMHTMLMediaElement other); + + // XXX: experimenting with allowing the user to set a framebuffer length. + unsigned long mozSetFrameBufferSize(in unsigned long size); }; diff -r ccf3b452d0f4 js/src/xpconnect/src/dom_quickstubs.qsconf --- a/js/src/xpconnect/src/dom_quickstubs.qsconf Tue May 25 18:40:45 2010 -0500 +++ b/js/src/xpconnect/src/dom_quickstubs.qsconf Tue May 25 21:21:43 2010 -0500 @@ -461,16 +461,20 @@ members = [ '-nsICanvasRenderingContextWebGL.getRenderbufferParameter', '-nsICanvasRenderingContextWebGL.getProgramParameter', '-nsICanvasRenderingContextWebGL.texParameterf', '-nsICanvasRenderingContextWebGL.texParameteri', '-nsICanvasRenderingContextWebGL.getUniform', '-nsICanvasRenderingContextWebGL.getVertexAttrib', '-nsICanvasRenderingContextWebGL.readPixels', '-nsICanvasRenderingContextWebGL.getShaderParameter', + + # Audio + 'nsIDOMNotifyAudioWrittenEvent.mozFrameBuffer', + 'nsIDOMHTMLAudioElement.mozWriteAudio' ] # Most interfaces can be found by searching the includePath; to find # nsIDOMEvent, for example, just look for nsIDOMEvent.idl. But IDL filenames # for very long interface names are slightly abbreviated, and many interfaces # don't have their own files, just for extra wackiness. So qsgen.py needs # a little help. # @@ -487,33 +491,34 @@ irregularFilenames = { 'nsIWebGLTexture': 'nsICanvasRenderingContextWebGL', 'nsIWebGLBuffer': 'nsICanvasRenderingContextWebGL', 'nsIWebGLProgram': 'nsICanvasRenderingContextWebGL', 'nsIWebGLShader': 'nsICanvasRenderingContextWebGL', 'nsIWebGLShaderArray': 'nsICanvasRenderingContextWebGL', 'nsIWebGLFramebuffer': 'nsICanvasRenderingContextWebGL', 'nsIWebGLRenderbuffer': 'nsICanvasRenderingContextWebGL', - 'nsIWebGLActiveInfo': 'nsICanvasRenderingContextWebGL', + 'nsIWebGLActiveInfo': 'nsICanvasRenderingContextWebGL' } customIncludes = [ 'nsINode.h', 'nsIContent.h', 'nsIDocument.h', 'nsINodeList.h', 'nsCSSPropertiesQS.h', 'nsGenericDOMDataNode.h', 'nsGenericElement.h', 'nsDOMQS.h', ] customQuickStubs = [ 'CustomQS_WebGL.h', - 'CustomQS_Canvas2D.h' + 'CustomQS_Canvas2D.h', + 'CustomQS_Audio.h' ] customReturnInterfaces = [ 'nsIDOMCanvasPattern', 'nsIDOMCanvasGradient', ] nsIDOMNode_GetChildNodes_customMethodCallCode = """ @@ -787,10 +792,13 @@ customMethodCalls = { 'nsICanvasRenderingContextWebGL_VertexAttrib1fv': CUSTOM_QS, 'nsICanvasRenderingContextWebGL_VertexAttrib2fv': CUSTOM_QS, 'nsICanvasRenderingContextWebGL_VertexAttrib3fv': CUSTOM_QS, 'nsICanvasRenderingContextWebGL_VertexAttrib4fv': CUSTOM_QS, # Canvas 2D 'nsIDOMCanvasRenderingContext2D_CreateImageData': CUSTOM_QS, 'nsIDOMCanvasRenderingContext2D_GetImageData': CUSTOM_QS, 'nsIDOMCanvasRenderingContext2D_PutImageData': CUSTOM_QS, + # Audio + 'nsIDOMNotifyAudioWrittenEvent_MozFrameBuffer': CUSTOM_QS, + 'nsIDOMHTMLAudioElement_MozWriteAudio': CUSTOM_QS } diff -r ccf3b452d0f4 widget/public/nsGUIEvent.h --- a/widget/public/nsGUIEvent.h Tue May 25 18:40:45 2010 -0500 +++ b/widget/public/nsGUIEvent.h Tue May 25 21:21:43 2010 -0500 @@ -396,18 +396,19 @@ class nsHashKey; #define NS_CANPLAYTHROUGH (NS_MEDIA_EVENT_START+12) #define NS_SEEKING (NS_MEDIA_EVENT_START+13) #define NS_SEEKED (NS_MEDIA_EVENT_START+14) #define NS_TIMEUPDATE (NS_MEDIA_EVENT_START+15) #define NS_ENDED (NS_MEDIA_EVENT_START+16) #define NS_RATECHANGE (NS_MEDIA_EVENT_START+17) #define NS_DURATIONCHANGE (NS_MEDIA_EVENT_START+18) #define NS_VOLUMECHANGE (NS_MEDIA_EVENT_START+19) -#define NS_MEDIA_ABORT (NS_MEDIA_EVENT_START+20) -#define NS_MEDIA_ERROR (NS_MEDIA_EVENT_START+21) +#define NS_AUDIOWRITTEN (NS_MEDIA_EVENT_START+20) +#define NS_MEDIA_ABORT (NS_MEDIA_EVENT_START+21) +#define NS_MEDIA_ERROR (NS_MEDIA_EVENT_START+22) #endif // MOZ_MEDIA // paint notification events #define NS_NOTIFYPAINT_START 3400 #define NS_AFTERPAINT (NS_NOTIFYPAINT_START) // Simple gesture events #define NS_SIMPLE_GESTURE_EVENT_START 3500