[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc
crogers at google.com
crogers at google.com
Wed Dec 22 13:41:46 UTC 2010
The following commit has been merged in the debian/experimental branch:
commit c6e1a8d52cc469338f95cd7f037abe4f2ad105e8
Author: crogers at google.com <crogers at google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Thu Sep 23 17:49:52 2010 +0000
2010-09-23 Chris Rogers <crogers at google.com>
Reviewed by Kenneth Russell.
Add AudioContext files
https://bugs.webkit.org/show_bug.cgi?id=44890
No new tests since audio API is not yet implemented.
* webaudio/AudioContext.cpp: Added.
(WebCore::AudioContext::createAudioRequest):
(WebCore::AudioContext::create):
(WebCore::AudioContext::AudioContext):
(WebCore::AudioContext::~AudioContext):
(WebCore::AudioContext::lazyInitialize):
(WebCore::AudioContext::uninitialize):
(WebCore::AudioContext::isInitialized):
(WebCore::AudioContext::isRunnable):
(WebCore::AudioContext::stop):
(WebCore::AudioContext::document):
(WebCore::AudioContext::hasDocument):
(WebCore::AudioContext::refBuffer):
(WebCore::AudioContext::createBuffer):
(WebCore::AudioContext::createBufferSource):
(WebCore::AudioContext::createJavaScriptNode):
(WebCore::AudioContext::createLowPass2Filter):
(WebCore::AudioContext::createHighPass2Filter):
(WebCore::AudioContext::createPanner):
(WebCore::AudioContext::createConvolver):
(WebCore::AudioContext::createAnalyser):
(WebCore::AudioContext::createGainNode):
(WebCore::AudioContext::createDelayNode):
(WebCore::AudioContext::createChannelSplitter):
(WebCore::AudioContext::createChannelMerger):
(WebCore::AudioContext::notifyNodeFinishedProcessing):
(WebCore::AudioContext::derefFinishedSourceNodes):
(WebCore::AudioContext::refNode):
(WebCore::AudioContext::derefNode):
(WebCore::AudioContext::derefUnfinishedSourceNodes):
(WebCore::AudioContext::lock):
(WebCore::AudioContext::tryLock):
(WebCore::AudioContext::unlock):
(WebCore::AudioContext::isAudioThread):
(WebCore::AudioContext::isGraphOwner):
(WebCore::AudioContext::addDeferredFinishDeref):
(WebCore::AudioContext::handlePostRenderTasks):
(WebCore::AudioContext::handleDeferredFinishDerefs):
(WebCore::AudioContext::markForDeletion):
(WebCore::AudioContext::deleteMarkedNodes):
* webaudio/AudioContext.h: Added.
(WebCore::AudioContext::destination):
(WebCore::AudioContext::currentTime):
(WebCore::AudioContext::sampleRate):
(WebCore::AudioContext::listener):
(WebCore::AudioContext::temporaryMonoBus):
(WebCore::AudioContext::temporaryStereoBus):
(WebCore::AudioContext::incrementConnectionCount):
(WebCore::AudioContext::connectionCount):
(WebCore::AudioContext::setAudioThread):
(WebCore::AudioContext::audioThread):
(WebCore::AudioContext::isAudioThreadFinished):
(WebCore::AudioContext::AutoLocker::AutoLocker):
(WebCore::AudioContext::AutoLocker::~AutoLocker):
(WebCore::AudioContext::RefInfo::RefInfo):
* webaudio/AudioContext.idl: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@68163 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 9a39267..9ef07e9 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,69 @@
+2010-09-23 Chris Rogers <crogers at google.com>
+
+ Reviewed by Kenneth Russell.
+
+ Add AudioContext files
+ https://bugs.webkit.org/show_bug.cgi?id=44890
+
+ No new tests since audio API is not yet implemented.
+
+ * webaudio/AudioContext.cpp: Added.
+ (WebCore::AudioContext::createAudioRequest):
+ (WebCore::AudioContext::create):
+ (WebCore::AudioContext::AudioContext):
+ (WebCore::AudioContext::~AudioContext):
+ (WebCore::AudioContext::lazyInitialize):
+ (WebCore::AudioContext::uninitialize):
+ (WebCore::AudioContext::isInitialized):
+ (WebCore::AudioContext::isRunnable):
+ (WebCore::AudioContext::stop):
+ (WebCore::AudioContext::document):
+ (WebCore::AudioContext::hasDocument):
+ (WebCore::AudioContext::refBuffer):
+ (WebCore::AudioContext::createBuffer):
+ (WebCore::AudioContext::createBufferSource):
+ (WebCore::AudioContext::createJavaScriptNode):
+ (WebCore::AudioContext::createLowPass2Filter):
+ (WebCore::AudioContext::createHighPass2Filter):
+ (WebCore::AudioContext::createPanner):
+ (WebCore::AudioContext::createConvolver):
+ (WebCore::AudioContext::createAnalyser):
+ (WebCore::AudioContext::createGainNode):
+ (WebCore::AudioContext::createDelayNode):
+ (WebCore::AudioContext::createChannelSplitter):
+ (WebCore::AudioContext::createChannelMerger):
+ (WebCore::AudioContext::notifyNodeFinishedProcessing):
+ (WebCore::AudioContext::derefFinishedSourceNodes):
+ (WebCore::AudioContext::refNode):
+ (WebCore::AudioContext::derefNode):
+ (WebCore::AudioContext::derefUnfinishedSourceNodes):
+ (WebCore::AudioContext::lock):
+ (WebCore::AudioContext::tryLock):
+ (WebCore::AudioContext::unlock):
+ (WebCore::AudioContext::isAudioThread):
+ (WebCore::AudioContext::isGraphOwner):
+ (WebCore::AudioContext::addDeferredFinishDeref):
+ (WebCore::AudioContext::handlePostRenderTasks):
+ (WebCore::AudioContext::handleDeferredFinishDerefs):
+ (WebCore::AudioContext::markForDeletion):
+ (WebCore::AudioContext::deleteMarkedNodes):
+ * webaudio/AudioContext.h: Added.
+ (WebCore::AudioContext::destination):
+ (WebCore::AudioContext::currentTime):
+ (WebCore::AudioContext::sampleRate):
+ (WebCore::AudioContext::listener):
+ (WebCore::AudioContext::temporaryMonoBus):
+ (WebCore::AudioContext::temporaryStereoBus):
+ (WebCore::AudioContext::incrementConnectionCount):
+ (WebCore::AudioContext::connectionCount):
+ (WebCore::AudioContext::setAudioThread):
+ (WebCore::AudioContext::audioThread):
+ (WebCore::AudioContext::isAudioThreadFinished):
+ (WebCore::AudioContext::AutoLocker::AutoLocker):
+ (WebCore::AudioContext::AutoLocker::~AutoLocker):
+ (WebCore::AudioContext::RefInfo::RefInfo):
+ * webaudio/AudioContext.idl: Added.
+
2010-09-23 Jeremy Orlow <jorlow at chromium.org>
Reviewed by Steve Block.
diff --git a/WebCore/webaudio/AudioContext.cpp b/WebCore/webaudio/AudioContext.cpp
new file mode 100644
index 0000000..6ca8ee1
--- /dev/null
+++ b/WebCore/webaudio/AudioContext.cpp
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2010 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "AudioContext.h"
+
+#include "AudioBuffer.h"
+#include "AudioBufferSourceNode.h"
+#include "AudioChannelMerger.h"
+#include "AudioChannelSplitter.h"
+#include "AudioGainNode.h"
+#include "AudioListener.h"
+#include "AudioPannerNode.h"
+#include "CachedAudio.h"
+#include "ConvolverNode.h"
+#include "DelayNode.h"
+#include "Document.h"
+#include "HRTFDatabaseLoader.h"
+#include "HRTFPanner.h"
+#include "HTMLNames.h"
+#include "HighPass2FilterNode.h"
+#include "JavaScriptAudioNode.h"
+#include "LowPass2FilterNode.h"
+#include "PlatformString.h"
+#include "RealtimeAnalyserNode.h"
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+
+// FIXME: check the proper way to reference an undefined thread ID
+const int UndefinedThreadIdentifier = 0xffffffff;
+
+namespace WebCore {
+
+PassRefPtr<CachedAudio> AudioContext::createAudioRequest(const String &url, bool mixToMono)
+{
+ lazyInitialize();
+
+ // Convert relative URL to absolute
+ KURL completedURL = document()->completeURL(url);
+ String completedURLString = completedURL.string();
+
+ RefPtr<CachedAudio> cachedAudio = CachedAudio::create(completedURLString, this, document(), sampleRate(), mixToMono);
+ CachedAudio* c = cachedAudio.get();
+
+ m_cachedAudioReferences.append(c);
+
+ return cachedAudio;
+}
+
+PassRefPtr<AudioContext> AudioContext::create(Document* document)
+{
+ return adoptRef(new AudioContext(document));
+}
+
+AudioContext::AudioContext(Document* document)
+ : ActiveDOMObject(document, this)
+ , m_isInitialized(false)
+ , m_isAudioThreadFinished(false)
+ , m_document(document)
+ , m_destinationNode(0)
+ , m_connectionCount(0)
+ , m_audioThread(0)
+ , m_graphOwnerThread(UndefinedThreadIdentifier)
+{
+ // 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.
+ relaxAdoptionRequirement();
+
+ 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 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).
+ hrtfDatabaseLoader()->loadAsynchronously(sampleRate());
+}
+
+AudioContext::~AudioContext()
+{
+#if DEBUG_AUDIONODE_REFERENCES
+ printf("%p: AudioContext::~AudioContext()\n", this);
+#endif
+ // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
+ ASSERT(!m_nodesToDelete.size());
+ ASSERT(!m_referencedNodes.size());
+ ASSERT(!m_finishedNodes.size());
+}
+
+void AudioContext::lazyInitialize()
+{
+ if (!m_isInitialized) {
+ // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
+ ASSERT(!m_isAudioThreadFinished);
+ if (!m_isAudioThreadFinished) {
+ if (m_destinationNode.get()) {
+ // This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
+ // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum".
+ m_destinationNode->initialize();
+ }
+ m_isInitialized = true;
+ }
+ }
+}
+
+void AudioContext::uninitialize()
+{
+ if (m_isInitialized) {
+ // This stops the audio thread and all audio rendering.
+ m_destinationNode->uninitialize();
+
+ // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
+ m_isAudioThreadFinished = true;
+
+ // We have to release our reference to the destination node before the context will ever be deleted since the destination node holds a reference to the context.
+ m_destinationNode.clear();
+
+ // Get rid of the sources which may still be playing.
+ derefUnfinishedSourceNodes();
+
+ // Because the AudioBuffers are garbage collected, we can't delete them here.
+ // Instead, at least release the potentially large amount of allocated memory for the audio data.
+ // Note that we do this *after* the context is uninitialized and stops processing audio.
+ for (unsigned i = 0; i < m_allocatedBuffers.size(); ++i)
+ m_allocatedBuffers[i]->releaseMemory();
+ m_allocatedBuffers.clear();
+
+ m_isInitialized = false;
+ }
+}
+
+bool AudioContext::isInitialized() const
+{
+ return m_isInitialized;
+}
+
+bool AudioContext::isRunnable() const
+{
+ if (!isInitialized())
+ return false;
+
+ // Check with the HRTF spatialization system to see if it's finished loading.
+ return hrtfDatabaseLoader()->isLoaded();
+}
+
+void AudioContext::stop()
+{
+ m_document = 0; // document is going away
+ uninitialize();
+}
+
+Document* AudioContext::document()
+{
+ ASSERT(m_document);
+ return m_document;
+}
+
+bool AudioContext::hasDocument()
+{
+ return m_document;
+}
+
+void AudioContext::refBuffer(PassRefPtr<AudioBuffer> buffer)
+{
+ m_allocatedBuffers.append(buffer);
+}
+
+PassRefPtr<AudioBuffer> AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, double sampleRate)
+{
+ return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
+}
+
+PassRefPtr<AudioBufferSourceNode> AudioContext::createBufferSource()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate());
+
+ refNode(node.get()); // context keeps reference until source has finished playing
+ return node;
+}
+
+PassRefPtr<JavaScriptAudioNode> AudioContext::createJavaScriptNode(size_t bufferSize)
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ RefPtr<JavaScriptAudioNode> node = JavaScriptAudioNode::create(this, m_destinationNode->sampleRate(), bufferSize);
+
+ refNode(node.get()); // context keeps reference until we stop making javascript rendering callbacks
+ return node;
+}
+
+PassRefPtr<LowPass2FilterNode> AudioContext::createLowPass2Filter()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return LowPass2FilterNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<HighPass2FilterNode> AudioContext::createHighPass2Filter()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return HighPass2FilterNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<AudioPannerNode> AudioContext::createPanner()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return AudioPannerNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<ConvolverNode> AudioContext::createConvolver()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return ConvolverNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<RealtimeAnalyserNode> AudioContext::createAnalyser()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return RealtimeAnalyserNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<AudioGainNode> AudioContext::createGainNode()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return AudioGainNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<DelayNode> AudioContext::createDelayNode()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return DelayNode::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<AudioChannelSplitter> AudioContext::createChannelSplitter()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return AudioChannelSplitter::create(this, m_destinationNode->sampleRate());
+}
+
+PassRefPtr<AudioChannelMerger> AudioContext::createChannelMerger()
+{
+ ASSERT(isMainThread());
+ lazyInitialize();
+ return AudioChannelMerger::create(this, m_destinationNode->sampleRate());
+}
+
+void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
+{
+ ASSERT(isAudioThread());
+ m_finishedNodes.append(node);
+}
+
+void AudioContext::derefFinishedSourceNodes()
+{
+ ASSERT(isGraphOwner());
+ ASSERT(isAudioThread() || isAudioThreadFinished());
+ for (unsigned i = 0; i < m_finishedNodes.size(); i++)
+ derefNode(m_finishedNodes[i]);
+
+ m_finishedNodes.clear();
+}
+
+void AudioContext::refNode(AudioNode* node)
+{
+ ASSERT(isMainThread());
+ AutoLocker locker(this);
+
+ node->ref(AudioNode::RefTypeConnection);
+ m_referencedNodes.append(node);
+}
+
+void AudioContext::derefNode(AudioNode* node)
+{
+ ASSERT(isGraphOwner());
+
+ node->deref(AudioNode::RefTypeConnection);
+
+ for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
+ if (node == m_referencedNodes[i]) {
+ m_referencedNodes.remove(i);
+ break;
+ }
+ }
+}
+
+void AudioContext::derefUnfinishedSourceNodes()
+{
+ ASSERT(isMainThread() && isAudioThreadFinished());
+ for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
+ m_referencedNodes[i]->deref(AudioNode::RefTypeConnection);
+
+ m_referencedNodes.clear();
+}
+
+void AudioContext::lock(bool& mustReleaseLock)
+{
+ // Don't allow regular lock in real-time audio thread.
+ ASSERT(isMainThread());
+
+ ThreadIdentifier thisThread = currentThread();
+
+ if (thisThread == m_graphOwnerThread) {
+ // We already have the lock.
+ mustReleaseLock = false;
+ } else {
+ // Acquire the lock.
+ m_contextGraphMutex.lock();
+ mustReleaseLock = true;
+ }
+
+ m_graphOwnerThread = thisThread;
+}
+
+bool AudioContext::tryLock(bool& mustReleaseLock)
+{
+ ThreadIdentifier thisThread = currentThread();
+ bool isAudioThread = thisThread == audioThread();
+
+ // Try to catch cases of using try lock on main thread - it should use regular lock.
+ ASSERT(isAudioThread || isAudioThreadFinished());
+
+ if (!isAudioThread) {
+ // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
+ lock(mustReleaseLock);
+ return true;
+ }
+
+ bool hasLock;
+
+ if (thisThread == m_graphOwnerThread) {
+ // Thread already has the lock.
+ hasLock = true;
+ mustReleaseLock = false;
+ } else {
+ // Don't already have the lock - try to acquire it.
+ hasLock = m_contextGraphMutex.tryLock();
+
+ if (hasLock)
+ m_graphOwnerThread = thisThread;
+
+ mustReleaseLock = hasLock;
+ }
+
+ return hasLock;
+}
+
+void AudioContext::unlock()
+{
+ ASSERT(currentThread() == m_graphOwnerThread);
+
+ m_graphOwnerThread = UndefinedThreadIdentifier;
+ m_contextGraphMutex.unlock();
+}
+
+bool AudioContext::isAudioThread()
+{
+ return currentThread() == m_audioThread;
+}
+
+bool AudioContext::isGraphOwner()
+{
+ return currentThread() == m_graphOwnerThread;
+}
+
+void AudioContext::addDeferredFinishDeref(AudioNode* node, AudioNode::RefType refType)
+{
+ ASSERT(isAudioThread());
+ m_deferredFinishDerefList.append(AudioContext::RefInfo(node, refType));
+}
+
+void AudioContext::handlePostRenderTasks()
+{
+ ASSERT(isAudioThread());
+
+ // Must use a tryLock() here too. Don't worry, the lock will very rarely be contended and this method is called frequently.
+ // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
+ // from the render graph (in which case they'll render silence).
+ bool mustReleaseLock;
+ if (tryLock(mustReleaseLock)) {
+ // Take care of finishing any derefs where the tryLock() failed previously.
+ handleDeferredFinishDerefs();
+
+ // Dynamically clean up nodes which are no longer needed.
+ derefFinishedSourceNodes();
+
+ // Finally actually delete.
+ deleteMarkedNodes();
+
+ if (mustReleaseLock)
+ unlock();
+ }
+}
+
+void AudioContext::handleDeferredFinishDerefs()
+{
+ ASSERT(isAudioThread());
+ for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i) {
+ AudioNode* node = m_deferredFinishDerefList[i].m_node;
+ AudioNode::RefType refType = m_deferredFinishDerefList[i].m_refType;
+ node->finishDeref(refType);
+ }
+
+ m_deferredFinishDerefList.clear();
+}
+
+void AudioContext::markForDeletion(AudioNode* node)
+{
+ ASSERT(isGraphOwner());
+ m_nodesToDelete.append(node);
+}
+
+void AudioContext::deleteMarkedNodes()
+{
+ ASSERT(isGraphOwner() || isAudioThreadFinished());
+
+ // Note: deleting an AudioNode can cause m_nodesToDelete to grow.
+ while (size_t n = m_nodesToDelete.size()) {
+ AudioNode* node = m_nodesToDelete[n - 1];
+ m_nodesToDelete.removeLast();
+ delete node;
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/webaudio/AudioContext.h b/WebCore/webaudio/AudioContext.h
new file mode 100644
index 0000000..f175bfe
--- /dev/null
+++ b/WebCore/webaudio/AudioContext.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2010 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 AudioContext_h
+#define AudioContext_h
+
+#include "ActiveDOMObject.h"
+#include "AudioBus.h"
+#include "AudioDestinationNode.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+#include <wtf/text/AtomicStringHash.h>
+
+namespace WebCore {
+
+class AudioBuffer;
+class AudioBufferSourceNode;
+class AudioChannelMerger;
+class AudioChannelSplitter;
+class AudioGainNode;
+class AudioPannerNode;
+class AudioListener;
+class CachedAudio;
+class DelayNode;
+class Document;
+class LowPass2FilterNode;
+class HighPass2FilterNode;
+class ConvolverNode;
+class RealtimeAnalyserNode;
+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> {
+public:
+ static PassRefPtr<AudioContext> create(Document*);
+
+ virtual ~AudioContext();
+
+ bool isInitialized() const;
+
+ // Returns true when initialize() was called AND all asynchronous initialization has completed.
+ bool isRunnable() const;
+
+ // Document notification
+ virtual void stop();
+
+ Document* document(); // ASSERTs if document no longer exists.
+ bool hasDocument();
+
+ AudioDestinationNode* destination() { return m_destinationNode.get(); }
+ double currentTime() { return m_destinationNode->currentTime(); }
+ double sampleRate() { return m_destinationNode->sampleRate(); }
+
+ PassRefPtr<AudioBuffer> createBuffer(unsigned numberOfChannels, size_t numberOfFrames, double sampleRate);
+
+ PassRefPtr<CachedAudio> createAudioRequest(const String &url, bool mixToMono);
+
+ // Keep track of this buffer so we can release memory after the context is shut down...
+ void refBuffer(PassRefPtr<AudioBuffer> buffer);
+
+ AudioListener* listener() { return m_listener.get(); }
+
+ // The AudioNode create methods are called on the main thread (from JavaScript).
+ PassRefPtr<AudioBufferSourceNode> createBufferSource();
+ PassRefPtr<AudioGainNode> createGainNode();
+ PassRefPtr<DelayNode> createDelayNode();
+ PassRefPtr<LowPass2FilterNode> createLowPass2Filter();
+ PassRefPtr<HighPass2FilterNode> createHighPass2Filter();
+ PassRefPtr<AudioPannerNode> createPanner();
+ PassRefPtr<ConvolverNode> createConvolver();
+ PassRefPtr<RealtimeAnalyserNode> createAnalyser();
+ PassRefPtr<JavaScriptAudioNode> createJavaScriptNode(size_t bufferSize);
+ PassRefPtr<AudioChannelSplitter> createChannelSplitter();
+ PassRefPtr<AudioChannelMerger> createChannelMerger();
+
+ AudioBus* temporaryMonoBus() { return m_temporaryMonoBus.get(); }
+ AudioBus* temporaryStereoBus() { return m_temporaryStereoBus.get(); }
+
+ // When a source node has no more processing to do (has finished playing), then it tells the context to dereference it.
+ void notifyNodeFinishedProcessing(AudioNode*);
+
+ // Called at the end of each render quantum.
+ void handlePostRenderTasks();
+
+ // Called periodically at the end of each render quantum to dereference finished source nodes.
+ void derefFinishedSourceNodes();
+
+ // We reap all marked nodes at the end of each realtime render quantum in deleteMarkedNodes().
+ void markForDeletion(AudioNode*);
+ void deleteMarkedNodes();
+
+ // Keeps track of the number of connections made.
+ void incrementConnectionCount()
+ {
+ ASSERT(isMainThread());
+ m_connectionCount++;
+ }
+
+ unsigned connectionCount() const { return m_connectionCount; }
+
+ //
+ // Thread Safety and Graph Locking:
+ //
+
+ void setAudioThread(ThreadIdentifier thread) { m_audioThread = thread; } // FIXME: check either not initialized or the same
+ ThreadIdentifier audioThread() const { return m_audioThread; }
+ bool isAudioThread();
+
+ // Returns true only after the audio thread has been started and then shutdown.
+ bool isAudioThreadFinished() { return m_isAudioThreadFinished; }
+
+ // mustReleaseLock is set to true if we acquired the lock in this method call and caller must unlock(), false if it was previously acquired.
+ void lock(bool& mustReleaseLock);
+
+ // Returns true if we own the lock.
+ // mustReleaseLock is set to true if we acquired the lock in this method call and caller must unlock(), false if it was previously acquired.
+ bool tryLock(bool& mustReleaseLock);
+
+ void unlock();
+
+ // Returns true if this thread owns the context's lock.
+ bool isGraphOwner();
+
+ class AutoLocker {
+ public:
+ AutoLocker(AudioContext* context)
+ : m_context(context)
+ {
+ ASSERT(context);
+ context->lock(m_mustReleaseLock);
+ }
+
+ ~AutoLocker()
+ {
+ if (m_mustReleaseLock)
+ m_context->unlock();
+ }
+ private:
+ AudioContext* m_context;
+ bool m_mustReleaseLock;
+ };
+
+ // In AudioNode::deref() a tryLock() is used for calling finishDeref(), but if it fails keep track here.
+ void addDeferredFinishDeref(AudioNode*, AudioNode::RefType);
+
+ // In the audio thread at the start of each render cycle, we'll call handleDeferredFinishDerefs().
+ void handleDeferredFinishDerefs();
+
+private:
+ AudioContext(Document*);
+ void lazyInitialize();
+ void uninitialize();
+
+ bool m_isInitialized;
+ bool m_isAudioThreadFinished;
+ bool m_isAudioThreadShutdown;
+
+ Document* m_document;
+
+ // The context itself keeps a reference to all source nodes. The source nodes, then reference all nodes they're connected to.
+ // In turn, these nodes reference all nodes they're connected to. All nodes are ultimately connected to the AudioDestinationNode.
+ // When the context dereferences a source node, it will be deactivated from the rendering graph along with all other nodes it is
+ // uniquely connected to. See the AudioNode::ref() and AudioNode::deref() methods for more details.
+ void refNode(AudioNode*);
+ void derefNode(AudioNode*);
+
+ // When the context goes away, there might still be some sources which haven't finished playing.
+ // Make sure to dereference them here.
+ void derefUnfinishedSourceNodes();
+
+ RefPtr<AudioDestinationNode> m_destinationNode;
+ RefPtr<AudioListener> m_listener;
+
+ // Only accessed in the main thread.
+ Vector<RefPtr<AudioBuffer> > m_allocatedBuffers;
+
+ // Only accessed in the audio thread.
+ Vector<AudioNode*> m_finishedNodes;
+
+ // We don't use RefPtr<AudioNode> here because AudioNode has a more complex ref() / deref() implementation
+ // with an optional argument for refType. We need to use the special refType: RefTypeConnection
+ // Either accessed when the graph lock is held, or on the main thread when the audio thread has finished.
+ Vector<AudioNode*> m_referencedNodes;
+
+ // Accumulate nodes which need to be deleted at the end of a render cycle (in realtime thread) here.
+ Vector<AudioNode*> m_nodesToDelete;
+
+ Vector<RefPtr<CachedAudio> > m_cachedAudioReferences;
+
+ OwnPtr<AudioBus> m_temporaryMonoBus;
+ OwnPtr<AudioBus> m_temporaryStereoBus;
+
+ unsigned m_connectionCount;
+
+ // Graph locking.
+ Mutex m_contextGraphMutex;
+ volatile ThreadIdentifier m_audioThread;
+ volatile ThreadIdentifier m_graphOwnerThread; // if the lock is held then this is the thread which owns it, otherwise == UndefinedThreadIdentifier
+
+ // Deferred de-referencing.
+ struct RefInfo {
+ RefInfo(AudioNode* node, AudioNode::RefType refType)
+ : m_node(node)
+ , m_refType(refType)
+ {
+ }
+ AudioNode* m_node;
+ AudioNode::RefType m_refType;
+ };
+
+ // Only accessed in the audio thread.
+ Vector<RefInfo> m_deferredFinishDerefList;
+};
+
+} // WebCore
+
+#endif // AudioContext_h
diff --git a/WebCore/webaudio/AudioContext.idl b/WebCore/webaudio/AudioContext.idl
new file mode 100644
index 0000000..8951121
--- /dev/null
+++ b/WebCore/webaudio/AudioContext.idl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 webaudio {
+ interface [
+ Conditional=WEB_AUDIO,
+ CanBeConstructed,
+ CustomConstructFunction,
+ V8CustomConstructor
+ ] AudioContext {
+ // All rendered audio ultimately connects to destination, which represents the audio hardware.
+ readonly attribute AudioDestinationNode destination;
+
+ // All scheduled times are relative to this time in seconds.
+ readonly attribute float currentTime;
+
+ // All AudioNodes in the context run at this sample-rate (in sample-frames per second).
+ readonly attribute float sampleRate;
+
+ // All panning is relative to this listener.
+ readonly attribute AudioListener listener;
+
+ AudioBuffer createBuffer(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate);
+
+ // Source
+ AudioBufferSourceNode createBufferSource();
+
+ // Processing nodes
+ AudioGainNode createGainNode();
+ DelayNode createDelayNode();
+ LowPass2FilterNode createLowPass2Filter();
+ HighPass2FilterNode createHighPass2Filter();
+ AudioPannerNode createPanner();
+ ConvolverNode createConvolver();
+ RealtimeAnalyserNode createAnalyser();
+ JavaScriptAudioNode createJavaScriptNode(in unsigned long bufferSize);
+
+ // Channel splitting and merging
+ AudioChannelSplitter createChannelSplitter();
+ AudioChannelMerger createChannelMerger();
+
+ // FIXME: Temporary - to be replaced with XHR.
+ CachedAudio createAudioRequest(in DOMString url, in boolean mixToMono);
+ };
+}
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list