diff options
Diffstat (limited to 'Source/WebCore/webaudio')
-rw-r--r-- | Source/WebCore/webaudio/AudioContext.cpp | 95 | ||||
-rw-r--r-- | Source/WebCore/webaudio/AudioContext.h | 39 | ||||
-rw-r--r-- | Source/WebCore/webaudio/AudioContext.idl | 11 | ||||
-rw-r--r-- | Source/WebCore/webaudio/AudioDestinationNode.cpp | 35 | ||||
-rw-r--r-- | Source/WebCore/webaudio/AudioDestinationNode.h | 23 | ||||
-rw-r--r-- | Source/WebCore/webaudio/ConvolverNode.cpp | 4 | ||||
-rw-r--r-- | Source/WebCore/webaudio/DefaultAudioDestinationNode.cpp | 82 | ||||
-rw-r--r-- | Source/WebCore/webaudio/DefaultAudioDestinationNode.h | 61 | ||||
-rw-r--r-- | Source/WebCore/webaudio/OfflineAudioCompletionEvent.cpp | 58 | ||||
-rw-r--r-- | Source/WebCore/webaudio/OfflineAudioCompletionEvent.h | 55 | ||||
-rw-r--r-- | Source/WebCore/webaudio/OfflineAudioCompletionEvent.idl | 32 | ||||
-rw-r--r-- | Source/WebCore/webaudio/OfflineAudioDestinationNode.cpp | 166 | ||||
-rw-r--r-- | Source/WebCore/webaudio/OfflineAudioDestinationNode.h | 78 |
13 files changed, 679 insertions, 60 deletions
diff --git a/Source/WebCore/webaudio/AudioContext.cpp b/Source/WebCore/webaudio/AudioContext.cpp index f25b494..0d23cf5 100644 --- a/Source/WebCore/webaudio/AudioContext.cpp +++ b/Source/WebCore/webaudio/AudioContext.cpp @@ -39,6 +39,7 @@ #include "AudioNodeOutput.h" #include "AudioPannerNode.h" #include "ConvolverNode.h" +#include "DefaultAudioDestinationNode.h" #include "DelayNode.h" #include "Document.h" #include "FFTFrame.h" @@ -47,9 +48,15 @@ #include "HighPass2FilterNode.h" #include "JavaScriptAudioNode.h" #include "LowPass2FilterNode.h" +#include "OfflineAudioCompletionEvent.h" +#include "OfflineAudioDestinationNode.h" #include "PlatformString.h" #include "RealtimeAnalyserNode.h" +#if DEBUG_AUDIONODE_REFERENCES +#include <stdio.h> +#endif + #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> #include <wtf/RefCounted.h> @@ -66,6 +73,12 @@ PassRefPtr<AudioContext> AudioContext::create(Document* document) return adoptRef(new AudioContext(document)); } +PassRefPtr<AudioContext> AudioContext::createOfflineContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, double sampleRate) +{ + return adoptRef(new AudioContext(document, numberOfChannels, numberOfFrames, sampleRate)); +} + +// Constructor for rendering to the audio hardware. AudioContext::AudioContext(Document* document) : ActiveDOMObject(document, this) , m_isInitialized(false) @@ -75,6 +88,46 @@ AudioContext::AudioContext(Document* document) , m_connectionCount(0) , m_audioThread(0) , m_graphOwnerThread(UndefinedThreadIdentifier) + , m_isOfflineContext(false) +{ + constructCommon(); + + m_destinationNode = DefaultAudioDestinationNode::create(this); + + // This sets in motion an asynchronous loading mechanism on another thread. + // We can check m_hrtfDatabaseLoader->isLoaded() to find out whether or not it has been fully loaded. + // It's not that useful to have a callback function for this since the audio thread automatically starts rendering on the graph + // when this has finished (see AudioDestinationNode). + m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate()); + + // FIXME: for now default AudioContext does not need an explicit startRendering() call. + // We may want to consider requiring it for symmetry with OfflineAudioContext + m_destinationNode->startRendering(); +} + +// Constructor for offline (non-realtime) rendering. +AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, double sampleRate) + : ActiveDOMObject(document, this) + , m_isInitialized(false) + , m_isAudioThreadFinished(false) + , m_document(document) + , m_destinationNode(0) + , m_connectionCount(0) + , m_audioThread(0) + , m_graphOwnerThread(UndefinedThreadIdentifier) + , m_isOfflineContext(true) +{ + constructCommon(); + + // FIXME: the passed in sampleRate MUST match the hardware sample-rate since HRTFDatabaseLoader is a singleton. + m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate); + + // Create a new destination for offline rendering. + m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate); + m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTarget.get()); +} + +void AudioContext::constructCommon() { // Note: because adoptRef() won't be called until we leave this constructor, but code in this constructor needs to reference this context, // relax the check. @@ -82,16 +135,9 @@ AudioContext::AudioContext(Document* document) FFTFrame::initialize(); - m_destinationNode = AudioDestinationNode::create(this); m_listener = AudioListener::create(); m_temporaryMonoBus = adoptPtr(new AudioBus(1, AudioNode::ProcessingSizeInFrames)); m_temporaryStereoBus = adoptPtr(new AudioBus(2, AudioNode::ProcessingSizeInFrames)); - - // This sets in motion an asynchronous loading mechanism on another thread. - // We can check m_hrtfDatabaseLoader->isLoaded() to find out whether or not it has been fully loaded. - // It's not that useful to have a callback function for this since the audio thread automatically starts rendering on the graph - // when this has finished (see AudioDestinationNode). - m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate()); } AudioContext::~AudioContext() @@ -167,7 +213,7 @@ void AudioContext::stop() uninitialize(); } -Document* AudioContext::document() +Document* AudioContext::document() const { ASSERT(m_document); return m_document; @@ -526,6 +572,39 @@ void AudioContext::handleDirtyAudioNodeOutputs() m_dirtyAudioNodeOutputs.clear(); } +ScriptExecutionContext* AudioContext::scriptExecutionContext() const +{ + return document(); +} + +AudioContext* AudioContext::toAudioContext() +{ + return this; +} + +void AudioContext::startRendering() +{ + destination()->startRendering(); +} + +void AudioContext::fireCompletionEvent() +{ + ASSERT(isMainThread()); + if (!isMainThread()) + return; + + AudioBuffer* renderedBuffer = m_renderTarget.get(); + + ASSERT(renderedBuffer); + if (!renderedBuffer) + return; + + // Avoid firing the event if the document has already gone away. + if (hasDocument()) { + // Call the offline rendering completion event listener. + dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); + } +} } // namespace WebCore diff --git a/Source/WebCore/webaudio/AudioContext.h b/Source/WebCore/webaudio/AudioContext.h index ddd474c..4f89091 100644 --- a/Source/WebCore/webaudio/AudioContext.h +++ b/Source/WebCore/webaudio/AudioContext.h @@ -28,6 +28,8 @@ #include "ActiveDOMObject.h" #include "AudioBus.h" #include "AudioDestinationNode.h" +#include "EventListener.h" +#include "EventTarget.h" #include "HRTFDatabaseLoader.h" #include <wtf/HashSet.h> #include <wtf/OwnPtr.h> @@ -59,13 +61,19 @@ class JavaScriptAudioNode; // AudioContext is the cornerstone of the web audio API and all AudioNodes are created from it. // For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism. -class AudioContext : public ActiveDOMObject, public RefCounted<AudioContext> { +class AudioContext : public ActiveDOMObject, public RefCounted<AudioContext>, public EventTarget { public: + // Create an AudioContext for rendering to the audio hardware. static PassRefPtr<AudioContext> create(Document*); + // Create an AudioContext for offline (non-realtime) rendering. + static PassRefPtr<AudioContext> createOfflineContext(Document*, unsigned numberOfChannels, size_t numberOfFrames, double sampleRate); + virtual ~AudioContext(); bool isInitialized() const; + + bool isOfflineContext() { return m_isOfflineContext; } // Returns true when initialize() was called AND all asynchronous initialization has completed. bool isRunnable() const; @@ -73,7 +81,7 @@ public: // Document notification virtual void stop(); - Document* document(); // ASSERTs if document no longer exists. + Document* document() const; // ASSERTs if document no longer exists. bool hasDocument(); AudioDestinationNode* destination() { return m_destinationNode.get(); } @@ -180,9 +188,27 @@ public: // Only accessed when the graph lock is held. void markAudioNodeInputDirty(AudioNodeInput*); void markAudioNodeOutputDirty(AudioNodeOutput*); + + // EventTarget + virtual ScriptExecutionContext* scriptExecutionContext() const; + virtual AudioContext* toAudioContext(); + virtual EventTargetData* eventTargetData() { return &m_eventTargetData; } + virtual EventTargetData* ensureEventTargetData() { return &m_eventTargetData; } + + DEFINE_ATTRIBUTE_EVENT_LISTENER(complete); + + // Reconcile ref/deref which are defined both in AudioNode and EventTarget. + using RefCounted<AudioContext>::ref; + using RefCounted<AudioContext>::deref; + + void startRendering(); + void fireCompletionEvent(); private: AudioContext(Document*); + AudioContext(Document*, unsigned numberOfChannels, size_t numberOfFrames, double sampleRate); + void constructCommon(); + void lazyInitialize(); void uninitialize(); @@ -252,6 +278,15 @@ private: // HRTF Database loader RefPtr<HRTFDatabaseLoader> m_hrtfDatabaseLoader; + + // EventTarget + virtual void refEventTarget() { ref(); } + virtual void derefEventTarget() { deref(); } + EventTargetData m_eventTargetData; + + RefPtr<AudioBuffer> m_renderTarget; + + bool m_isOfflineContext; }; } // WebCore diff --git a/Source/WebCore/webaudio/AudioContext.idl b/Source/WebCore/webaudio/AudioContext.idl index 531774e..39b36c1 100644 --- a/Source/WebCore/webaudio/AudioContext.idl +++ b/Source/WebCore/webaudio/AudioContext.idl @@ -27,7 +27,10 @@ module webaudio { Conditional=WEB_AUDIO, CanBeConstructed, CustomConstructFunction, - V8CustomConstructor + V8CustomConstructor, +#if defined(V8_BINDING) && V8_BINDING + EventTarget +#endif ] AudioContext { // All rendered audio ultimately connects to destination, which represents the audio hardware. readonly attribute AudioDestinationNode destination; @@ -62,5 +65,11 @@ module webaudio { // Channel splitting and merging AudioChannelSplitter createChannelSplitter(); AudioChannelMerger createChannelMerger(); + + // Offline rendering + // void prepareOfflineBufferRendering(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate); + attribute EventListener oncomplete; + void startRendering(); + }; } diff --git a/Source/WebCore/webaudio/AudioDestinationNode.cpp b/Source/WebCore/webaudio/AudioDestinationNode.cpp index d2f4928..8c46b44 100644 --- a/Source/WebCore/webaudio/AudioDestinationNode.cpp +++ b/Source/WebCore/webaudio/AudioDestinationNode.cpp @@ -32,19 +32,16 @@ #include "AudioContext.h" #include "AudioNodeInput.h" #include "AudioNodeOutput.h" -#include <wtf/Threading.h> namespace WebCore { - -AudioDestinationNode::AudioDestinationNode(AudioContext* context) - : AudioNode(context, AudioDestination::hardwareSampleRate()) + +AudioDestinationNode::AudioDestinationNode(AudioContext* context, double sampleRate) + : AudioNode(context, sampleRate) , m_currentTime(0.0) { addInput(adoptPtr(new AudioNodeInput(this))); setType(NodeTypeDestination); - - initialize(); } AudioDestinationNode::~AudioDestinationNode() @@ -52,32 +49,6 @@ AudioDestinationNode::~AudioDestinationNode() uninitialize(); } -void AudioDestinationNode::initialize() -{ - if (isInitialized()) - return; - - double hardwareSampleRate = AudioDestination::hardwareSampleRate(); -#ifndef NDEBUG - fprintf(stderr, ">>>> hardwareSampleRate = %f\n", hardwareSampleRate); -#endif - - m_destination = AudioDestination::create(*this, hardwareSampleRate); - m_destination->start(); - - AudioNode::initialize(); -} - -void AudioDestinationNode::uninitialize() -{ - if (!isInitialized()) - return; - - m_destination->stop(); - - AudioNode::uninitialize(); -} - // The audio hardware calls us back here to gets its input stream. void AudioDestinationNode::provideInput(AudioBus* destinationBus, size_t numberOfFrames) { diff --git a/Source/WebCore/webaudio/AudioDestinationNode.h b/Source/WebCore/webaudio/AudioDestinationNode.h index 4c21bb8..5913205 100644 --- a/Source/WebCore/webaudio/AudioDestinationNode.h +++ b/Source/WebCore/webaudio/AudioDestinationNode.h @@ -25,11 +25,9 @@ #ifndef AudioDestinationNode_h #define AudioDestinationNode_h -#include "AudioDestination.h" +#include "AudioBuffer.h" #include "AudioNode.h" #include "AudioSourceProvider.h" -#include <wtf/OwnPtr.h> -#include <wtf/PassRefPtr.h> namespace WebCore { @@ -38,32 +36,25 @@ class AudioContext; class AudioDestinationNode : public AudioNode, public AudioSourceProvider { public: - static PassRefPtr<AudioDestinationNode> create(AudioContext* context) - { - return adoptRef(new AudioDestinationNode(context)); - } - + AudioDestinationNode(AudioContext*, double sampleRate); virtual ~AudioDestinationNode(); // AudioNode virtual void process(size_t) { }; // we're pulled by hardware so this is never called virtual void reset() { m_currentTime = 0.0; }; - virtual void initialize(); - virtual void uninitialize(); // The audio hardware calls here periodically to gets its input stream. virtual void provideInput(AudioBus*, size_t numberOfFrames); double currentTime() { return m_currentTime; } - double sampleRate() const { return m_destination->sampleRate(); } + virtual double sampleRate() const = 0; - unsigned numberOfChannels() const { return 2; } // FIXME: update when multi-channel (more than stereo) is supported - -private: - AudioDestinationNode(AudioContext*); + virtual unsigned numberOfChannels() const { return 2; } // FIXME: update when multi-channel (more than stereo) is supported - OwnPtr<AudioDestination> m_destination; + virtual void startRendering() = 0; + +protected: double m_currentTime; }; diff --git a/Source/WebCore/webaudio/ConvolverNode.cpp b/Source/WebCore/webaudio/ConvolverNode.cpp index c778a41..91f6dc6 100644 --- a/Source/WebCore/webaudio/ConvolverNode.cpp +++ b/Source/WebCore/webaudio/ConvolverNode.cpp @@ -29,6 +29,7 @@ #include "ConvolverNode.h" #include "AudioBuffer.h" +#include "AudioContext.h" #include "AudioNodeInput.h" #include "AudioNodeOutput.h" #include "Reverb.h" @@ -131,7 +132,8 @@ void ConvolverNode::setBuffer(AudioBuffer* buffer) bufferBus.setChannelMemory(i, buffer->getChannelData(i)->data(), bufferLength); // Create the reverb with the given impulse response. - OwnPtr<Reverb> reverb = adoptPtr(new Reverb(&bufferBus, AudioNode::ProcessingSizeInFrames, MaxFFTSize, 2, true)); + bool useBackgroundThreads = !context()->isOfflineContext(); + OwnPtr<Reverb> reverb = adoptPtr(new Reverb(&bufferBus, AudioNode::ProcessingSizeInFrames, MaxFFTSize, 2, useBackgroundThreads)); { // Synchronize with process(). diff --git a/Source/WebCore/webaudio/DefaultAudioDestinationNode.cpp b/Source/WebCore/webaudio/DefaultAudioDestinationNode.cpp new file mode 100644 index 0000000..f1a7263 --- /dev/null +++ b/Source/WebCore/webaudio/DefaultAudioDestinationNode.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "DefaultAudioDestinationNode.h" + +#ifndef NDEBUG +#include <stdio.h> +#endif + +namespace WebCore { + +DefaultAudioDestinationNode::DefaultAudioDestinationNode(AudioContext* context) + : AudioDestinationNode(context, AudioDestination::hardwareSampleRate()) +{ + initialize(); +} + +DefaultAudioDestinationNode::~DefaultAudioDestinationNode() +{ + uninitialize(); +} + +void DefaultAudioDestinationNode::initialize() +{ + if (isInitialized()) + return; + + double hardwareSampleRate = AudioDestination::hardwareSampleRate(); +#ifndef NDEBUG + fprintf(stderr, ">>>> hardwareSampleRate = %f\n", hardwareSampleRate); +#endif + + m_destination = AudioDestination::create(*this, hardwareSampleRate); + + AudioNode::initialize(); +} + +void DefaultAudioDestinationNode::uninitialize() +{ + if (!isInitialized()) + return; + + m_destination->stop(); + + AudioNode::uninitialize(); +} + +void DefaultAudioDestinationNode::startRendering() +{ + ASSERT(isInitialized()); + if (isInitialized()) + m_destination->start(); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/webaudio/DefaultAudioDestinationNode.h b/Source/WebCore/webaudio/DefaultAudioDestinationNode.h new file mode 100644 index 0000000..f1d689d --- /dev/null +++ b/Source/WebCore/webaudio/DefaultAudioDestinationNode.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DefaultAudioDestinationNode_h +#define DefaultAudioDestinationNode_h + +#include "AudioDestination.h" +#include "AudioDestinationNode.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class AudioContext; + +class DefaultAudioDestinationNode : public AudioDestinationNode { +public: + static PassRefPtr<DefaultAudioDestinationNode> create(AudioContext* context) + { + return adoptRef(new DefaultAudioDestinationNode(context)); + } + + virtual ~DefaultAudioDestinationNode(); + + // AudioNode + virtual void initialize(); + virtual void uninitialize(); + + double sampleRate() const { return m_destination->sampleRate(); } + + virtual void startRendering(); + +private: + DefaultAudioDestinationNode(AudioContext*); + + OwnPtr<AudioDestination> m_destination; +}; + +} // namespace WebCore + +#endif // DefaultAudioDestinationNode_h diff --git a/Source/WebCore/webaudio/OfflineAudioCompletionEvent.cpp b/Source/WebCore/webaudio/OfflineAudioCompletionEvent.cpp new file mode 100644 index 0000000..6160c82 --- /dev/null +++ b/Source/WebCore/webaudio/OfflineAudioCompletionEvent.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "OfflineAudioCompletionEvent.h" + +#include "AudioBuffer.h" +#include "EventNames.h" + +namespace WebCore { + +PassRefPtr<OfflineAudioCompletionEvent> OfflineAudioCompletionEvent::create(PassRefPtr<AudioBuffer> renderedBuffer) +{ + return adoptRef(new OfflineAudioCompletionEvent(renderedBuffer)); +} + +OfflineAudioCompletionEvent::OfflineAudioCompletionEvent(PassRefPtr<AudioBuffer> renderedBuffer) + : Event(eventNames().completeEvent, true, false) + , m_renderedBuffer(renderedBuffer) +{ +} + +OfflineAudioCompletionEvent::~OfflineAudioCompletionEvent() +{ +} + +bool OfflineAudioCompletionEvent::isOfflineAudioCompletionEvent() const +{ + return true; +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/webaudio/OfflineAudioCompletionEvent.h b/Source/WebCore/webaudio/OfflineAudioCompletionEvent.h new file mode 100644 index 0000000..bd700e8 --- /dev/null +++ b/Source/WebCore/webaudio/OfflineAudioCompletionEvent.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OfflineAudioCompletionEvent_h +#define OfflineAudioCompletionEvent_h + +#include "AudioBuffer.h" +#include "Event.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class AudioBuffer; + +class OfflineAudioCompletionEvent : public Event { +public: + static PassRefPtr<OfflineAudioCompletionEvent> create(PassRefPtr<AudioBuffer> renderedBuffer); + + virtual ~OfflineAudioCompletionEvent(); + + virtual bool isOfflineAudioCompletionEvent() const; + + AudioBuffer* renderedBuffer() { return m_renderedBuffer.get(); } + +private: + OfflineAudioCompletionEvent(PassRefPtr<AudioBuffer> renderedBuffer); + + RefPtr<AudioBuffer> m_renderedBuffer; +}; + +} // namespace WebCore + +#endif // OfflineAudioCompletionEvent_h diff --git a/Source/WebCore/webaudio/OfflineAudioCompletionEvent.idl b/Source/WebCore/webaudio/OfflineAudioCompletionEvent.idl new file mode 100644 index 0000000..cd5ccb0 --- /dev/null +++ b/Source/WebCore/webaudio/OfflineAudioCompletionEvent.idl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module audio { + interface [ + Conditional=WEB_AUDIO, + GenerateToJS + ] OfflineAudioCompletionEvent : Event { + readonly attribute AudioBuffer renderedBuffer; + }; +} diff --git a/Source/WebCore/webaudio/OfflineAudioDestinationNode.cpp b/Source/WebCore/webaudio/OfflineAudioDestinationNode.cpp new file mode 100644 index 0000000..e3a0758 --- /dev/null +++ b/Source/WebCore/webaudio/OfflineAudioDestinationNode.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEB_AUDIO) + +#include "OfflineAudioDestinationNode.h" + +#include "AudioBus.h" +#include "AudioContext.h" +#include "HRTFDatabaseLoader.h" +#include <algorithm> +#include <wtf/Threading.h> + +using namespace std; + +namespace WebCore { + +const size_t renderQuantumSize = 128; + +OfflineAudioDestinationNode::OfflineAudioDestinationNode(AudioContext* context, AudioBuffer* renderTarget) + : AudioDestinationNode(context, renderTarget->sampleRate()) + , m_renderTarget(renderTarget) + , m_startedRendering(false) +{ + m_renderBus = adoptPtr(new AudioBus(renderTarget->numberOfChannels(), renderQuantumSize)); + + initialize(); +} + +OfflineAudioDestinationNode::~OfflineAudioDestinationNode() +{ + uninitialize(); +} + +void OfflineAudioDestinationNode::initialize() +{ + if (isInitialized()) + return; + + AudioNode::initialize(); +} + +void OfflineAudioDestinationNode::uninitialize() +{ + if (!isInitialized()) + return; + + AudioNode::uninitialize(); +} + +void OfflineAudioDestinationNode::startRendering() +{ + ASSERT(isMainThread()); + ASSERT(m_renderTarget.get()); + if (!m_renderTarget.get()) + return; + + if (!m_startedRendering) { + m_startedRendering = true; + m_renderThread = createThread(OfflineAudioDestinationNode::renderEntry, this, "offline renderer"); + } +} + +// Do offline rendering in this thread. +void* OfflineAudioDestinationNode::renderEntry(void* threadData) +{ + OfflineAudioDestinationNode* destinationNode = reinterpret_cast<OfflineAudioDestinationNode*>(threadData); + ASSERT(destinationNode); + destinationNode->render(); + + return 0; +} + +void OfflineAudioDestinationNode::render() +{ + ASSERT(!isMainThread()); + ASSERT(m_renderBus.get()); + if (!m_renderBus.get()) + return; + + bool channelsMatch = m_renderBus->numberOfChannels() == m_renderTarget->numberOfChannels(); + ASSERT(channelsMatch); + if (!channelsMatch) + return; + + bool isRenderBusAllocated = m_renderBus->length() >= renderQuantumSize; + ASSERT(isRenderBusAllocated); + if (!isRenderBusAllocated) + return; + + // Synchronize with HRTFDatabaseLoader. + // The database must be loaded before we can proceed. + HRTFDatabaseLoader* loader = HRTFDatabaseLoader::loader(); + ASSERT(loader); + if (!loader) + return; + + loader->waitForLoaderThreadCompletion(); + + // Break up the render target into smaller "render quantize" sized pieces. + // Render until we're finished. + size_t framesToProcess = m_renderTarget->length(); + unsigned numberOfChannels = m_renderTarget->numberOfChannels(); + + unsigned n = 0; + while (framesToProcess > 0) { + // Render one render quantum. + provideInput(m_renderBus.get(), renderQuantumSize); + + size_t framesAvailableToCopy = min(framesToProcess, renderQuantumSize); + + for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) { + float* source = m_renderBus->channel(channelIndex)->data(); + float* destination = m_renderTarget->getChannelData(channelIndex)->data(); + memcpy(destination + n, source, sizeof(float) * framesAvailableToCopy); + } + + n += framesAvailableToCopy; + framesToProcess -= framesAvailableToCopy; + } + + // Our work is done. Let the AudioContext know. + callOnMainThread(notifyCompleteDispatch, this); +} + +void OfflineAudioDestinationNode::notifyCompleteDispatch(void* userData) +{ + OfflineAudioDestinationNode* destinationNode = static_cast<OfflineAudioDestinationNode*>(userData); + ASSERT(destinationNode); + if (!destinationNode) + return; + + destinationNode->notifyComplete(); +} + +void OfflineAudioDestinationNode::notifyComplete() +{ + context()->fireCompletionEvent(); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/webaudio/OfflineAudioDestinationNode.h b/Source/WebCore/webaudio/OfflineAudioDestinationNode.h new file mode 100644 index 0000000..714c120 --- /dev/null +++ b/Source/WebCore/webaudio/OfflineAudioDestinationNode.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OfflineAudioDestinationNode_h +#define OfflineAudioDestinationNode_h + +#include "AudioBuffer.h" +#include "AudioDestinationNode.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Threading.h> + +namespace WebCore { + +class AudioBus; +class AudioContext; + +class OfflineAudioDestinationNode : public AudioDestinationNode { +public: + static PassRefPtr<OfflineAudioDestinationNode> create(AudioContext* context, AudioBuffer* renderTarget) + { + return adoptRef(new OfflineAudioDestinationNode(context, renderTarget)); + } + + virtual ~OfflineAudioDestinationNode(); + + // AudioNode + virtual void initialize(); + virtual void uninitialize(); + + double sampleRate() const { return m_renderTarget->sampleRate(); } + + void startRendering(); + +private: + OfflineAudioDestinationNode(AudioContext*, AudioBuffer* renderTarget); + + // This AudioNode renders into this AudioBuffer. + RefPtr<AudioBuffer> m_renderTarget; + + // Temporary AudioBus for each render quantum. + OwnPtr<AudioBus> m_renderBus; + + // Rendering thread. + volatile ThreadIdentifier m_renderThread; + bool m_startedRendering; + static void* renderEntry(void* threadData); + void render(); + + // For completion callback on main thread. + static void notifyCompleteDispatch(void* userData); + void notifyComplete(); +}; + +} // namespace WebCore + +#endif // OfflineAudioDestinationNode_h |