Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / webaudio / AudioContext.cpp
index a77c998..97000f9 100644 (file)
@@ -28,8 +28,8 @@
 
 #include "modules/webaudio/AudioContext.h"
 
-#include "bindings/v8/ExceptionMessages.h"
-#include "bindings/v8/ExceptionState.h"
+#include "bindings/core/v8/ExceptionMessages.h"
+#include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/html/HTMLMediaElement.h"
@@ -74,9 +74,9 @@
 #include "wtf/text/WTFString.h"
 
 // FIXME: check the proper way to reference an undefined thread ID
-const int UndefinedThreadIdentifier = 0xffffffff;
+const WTF::ThreadIdentifier UndefinedThreadIdentifier = 0xffffffff;
 
-namespace WebCore {
+namespace blink {
 
 bool AudioContext::isSampleRateRangeGood(float sampleRate)
 {
@@ -111,7 +111,9 @@ AudioContext::AudioContext(Document* document)
     , m_isCleared(false)
     , m_isInitialized(false)
     , m_destinationNode(nullptr)
+#if !ENABLE(OILPAN)
     , m_isDeletionScheduled(false)
+#endif
     , m_automaticPullNodesNeedUpdating(false)
     , m_connectionCount(0)
     , m_audioThread(0)
@@ -123,6 +125,9 @@ AudioContext::AudioContext(Document* document)
     m_destinationNode = DefaultAudioDestinationNode::create(this);
 
     initialize();
+#if DEBUG_AUDIONODE_REFERENCES
+    fprintf(stderr, "%p: AudioContext::AudioContext() #%u\n", this, AudioContext::s_hardwareContextCount);
+#endif
 }
 
 // Constructor for offline (non-realtime) rendering.
@@ -132,7 +137,9 @@ AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t
     , m_isCleared(false)
     , m_isInitialized(false)
     , m_destinationNode(nullptr)
+#if !ENABLE(OILPAN)
     , m_isDeletionScheduled(false)
+#endif
     , m_automaticPullNodesNeedUpdating(false)
     , m_connectionCount(0)
     , m_audioThread(0)
@@ -156,8 +163,10 @@ AudioContext::~AudioContext()
 #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_isInitialized);
+#if !ENABLE(OILPAN)
     ASSERT(!m_nodesToDelete.size());
     ASSERT(!m_referencedNodes.size());
+#endif
     ASSERT(!m_finishedNodes.size());
     ASSERT(!m_automaticPullNodes.size());
     if (m_automaticPullNodesNeedUpdating)
@@ -191,6 +200,12 @@ void AudioContext::initialize()
 
 void AudioContext::clear()
 {
+#if ENABLE(OILPAN)
+    // We need to run disposers before destructing m_contextGraphMutex.
+    m_liveAudioSummingJunctions.clear();
+    m_liveNodes.clear();
+#else
+
     // 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.
     if (m_destinationNode)
         m_destinationNode.clear();
@@ -201,6 +216,7 @@ void AudioContext::clear()
         m_nodesMarkedForDeletion.clear();
         deleteMarkedNodes();
     } while (m_nodesToDelete.size());
+#endif
 
     m_isCleared = true;
 }
@@ -224,17 +240,7 @@ void AudioContext::uninitialize()
     derefUnfinishedSourceNodes();
 
     m_isInitialized = false;
-}
-
-void AudioContext::stopDispatch(void* userData)
-{
-    AudioContext* context = reinterpret_cast<AudioContext*>(userData);
-    ASSERT(context);
-    if (!context)
-        return;
-
-    context->uninitialize();
-    context->clear();
+    clear();
 }
 
 void AudioContext::stop()
@@ -248,7 +254,7 @@ void AudioContext::stop()
     // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other
     // ActiveDOMObjects so let's schedule uninitialize() to be called later.
     // FIXME: see if there's a more direct way to handle this issue.
-    callOnMainThread(stopDispatch, this);
+    callOnMainThread(bind(&AudioContext::uninitialize, PassRefPtrWillBeRawPtr<AudioContext>(this)));
 }
 
 bool AudioContext::hasPendingActivity() const
@@ -332,9 +338,9 @@ PassRefPtrWillBeRawPtr<MediaStreamAudioSourceNode> AudioContext::createMediaStre
     }
 
     // Use the first audio track in the media stream.
-    RefPtrWillBeRawPtr<MediaStreamTrack> audioTrack = audioTracks[0];
+    MediaStreamTrack* audioTrack = audioTracks[0];
     OwnPtr<AudioSourceProvider> provider = audioTrack->createWebAudioSource();
-    RefPtrWillBeRawPtr<MediaStreamAudioSourceNode> node = MediaStreamAudioSourceNode::create(this, mediaStream, audioTrack.get(), provider.release());
+    RefPtrWillBeRawPtr<MediaStreamAudioSourceNode> node = MediaStreamAudioSourceNode::create(this, mediaStream, audioTrack, provider.release());
 
     // FIXME: Only stereo streams are supported right now. We should be able to accept multi-channel streams.
     node->setFormat(2, sampleRate());
@@ -587,18 +593,17 @@ void AudioContext::refNode(AudioNode* node)
     ASSERT(isMainThread());
     AutoLocker locker(this);
 
-    node->ref(AudioNode::RefTypeConnection);
     m_referencedNodes.append(node);
+    node->makeConnection();
 }
 
 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]) {
+        if (node == m_referencedNodes[i].get()) {
+            node->breakConnection();
             m_referencedNodes.remove(i);
             break;
         }
@@ -609,7 +614,7 @@ void AudioContext::derefUnfinishedSourceNodes()
 {
     ASSERT(isMainThread());
     for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
-        m_referencedNodes[i]->deref(AudioNode::RefTypeConnection);
+        m_referencedNodes[i]->breakConnection();
 
     m_referencedNodes.clear();
 }
@@ -683,11 +688,19 @@ bool AudioContext::isGraphOwner() const
     return currentThread() == m_graphOwnerThread;
 }
 
+void AudioContext::addDeferredBreakConnection(AudioNode& node)
+{
+    ASSERT(isAudioThread());
+    m_deferredBreakConnectionList.append(&node);
+}
+
+#if !ENABLE(OILPAN)
 void AudioContext::addDeferredFinishDeref(AudioNode* node)
 {
     ASSERT(isAudioThread());
     m_deferredFinishDerefList.append(node);
 }
+#endif
 
 void AudioContext::handlePreRenderTasks()
 {
@@ -717,15 +730,17 @@ void AudioContext::handlePostRenderTasks()
     // 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();
+        // Take care of AudioNode tasks where the tryLock() failed previously.
+        handleDeferredAudioNodeTasks();
 
         // Dynamically clean up nodes which are no longer needed.
         derefFinishedSourceNodes();
 
+#if !ENABLE(OILPAN)
         // Don't delete in the real-time thread. Let the main thread do it.
         // Ref-counted objects held by certain AudioNodes may not be thread-safe.
         scheduleNodeDeletion();
+#endif
 
         // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
         handleDirtyAudioSummingJunctions();
@@ -738,17 +753,48 @@ void AudioContext::handlePostRenderTasks()
     }
 }
 
-void AudioContext::handleDeferredFinishDerefs()
+void AudioContext::handleDeferredAudioNodeTasks()
 {
     ASSERT(isAudioThread() && isGraphOwner());
-    for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i) {
-        AudioNode* node = m_deferredFinishDerefList[i];
-        node->finishDeref(AudioNode::RefTypeConnection);
-    }
 
+    for (unsigned i = 0; i < m_deferredBreakConnectionList.size(); ++i)
+        m_deferredBreakConnectionList[i]->breakConnectionWithLock();
+    m_deferredBreakConnectionList.clear();
+
+#if !ENABLE(OILPAN)
+    for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i)
+        m_deferredFinishDerefList[i]->finishDeref();
     m_deferredFinishDerefList.clear();
+#endif
 }
 
+#if ENABLE(OILPAN)
+void AudioContext::registerLiveNode(AudioNode& node)
+{
+    ASSERT(isMainThread());
+    m_liveNodes.add(&node, adoptPtr(new AudioNodeDisposer(node)));
+}
+
+AudioContext::AudioNodeDisposer::~AudioNodeDisposer()
+{
+    ASSERT(isMainThread());
+    AudioContext::AutoLocker locker(m_node.context());
+    m_node.dispose();
+}
+
+void AudioContext::registerLiveAudioSummingJunction(AudioSummingJunction& junction)
+{
+    ASSERT(isMainThread());
+    m_liveAudioSummingJunctions.add(&junction, adoptPtr(new AudioSummingJunctionDisposer(junction)));
+}
+
+AudioContext::AudioSummingJunctionDisposer::~AudioSummingJunctionDisposer()
+{
+    ASSERT(isMainThread());
+    m_junction.context()->removeMarkedSummingJunction(&m_junction);
+}
+#else
+
 void AudioContext::markForDeletion(AudioNode* node)
 {
     ASSERT(isGraphOwner());
@@ -757,12 +803,6 @@ void AudioContext::markForDeletion(AudioNode* node)
         m_nodesToDelete.append(node);
     else
         m_nodesMarkedForDeletion.append(node);
-
-    // This is probably the best time for us to remove the node from automatic pull list,
-    // since all connections are gone and we hold the graph lock. Then when handlePostRenderTasks()
-    // gets a chance to schedule the deletion work, updateAutomaticPullNodes() also gets a chance to
-    // modify m_renderingAutomaticPullNodes.
-    removeAutomaticPullNode(node);
 }
 
 void AudioContext::scheduleNodeDeletion()
@@ -810,27 +850,33 @@ void AudioContext::deleteMarkedNodes()
             AudioNode* node = m_nodesToDelete[n - 1];
             m_nodesToDelete.removeLast();
 
-            // Before deleting the node, clear out any AudioNodeInputs from m_dirtySummingJunctions.
-            unsigned numberOfInputs = node->numberOfInputs();
-            for (unsigned i = 0; i < numberOfInputs; ++i)
-                m_dirtySummingJunctions.remove(node->input(i));
+            node->dispose();
 
-            // Before deleting the node, clear out any AudioNodeOutputs from m_dirtyAudioNodeOutputs.
-            unsigned numberOfOutputs = node->numberOfOutputs();
-            for (unsigned i = 0; i < numberOfOutputs; ++i)
-                m_dirtyAudioNodeOutputs.remove(node->output(i));
-#if ENABLE(OILPAN)
-            // Finally, clear the keep alive handle that keeps this
-            // object from being collected.
-            node->clearKeepAlive();
-#else
             // Finally, delete it.
             delete node;
-#endif
         }
         m_isDeletionScheduled = false;
     }
 }
+#endif
+
+void AudioContext::unmarkDirtyNode(AudioNode& node)
+{
+    ASSERT(isGraphOwner());
+#if !ENABLE(OILPAN)
+    // Before deleting the node, clear out any AudioNodeInputs from
+    // m_dirtySummingJunctions.
+    unsigned numberOfInputs = node.numberOfInputs();
+    for (unsigned i = 0; i < numberOfInputs; ++i)
+        m_dirtySummingJunctions.remove(node.input(i));
+#endif
+
+    // Before deleting the node, clear out any AudioNodeOutputs from
+    // m_dirtyAudioNodeOutputs.
+    unsigned numberOfOutputs = node.numberOfOutputs();
+    for (unsigned i = 0; i < numberOfOutputs; ++i)
+        m_dirtyAudioNodeOutputs.remove(node.output(i));
+}
 
 void AudioContext::markSummingJunctionDirty(AudioSummingJunction* summingJunction)
 {
@@ -848,6 +894,7 @@ void AudioContext::removeMarkedSummingJunction(AudioSummingJunction* summingJunc
 void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
 {
     ASSERT(isGraphOwner());
+    ASSERT(isMainThread());
     m_dirtyAudioNodeOutputs.add(output);
 }
 
@@ -956,10 +1003,14 @@ void AudioContext::trace(Visitor* visitor)
     visitor->trace(m_renderTarget);
     visitor->trace(m_destinationNode);
     visitor->trace(m_listener);
-    visitor->trace(m_dirtySummingJunctions);
+#if ENABLE(OILPAN)
+    visitor->trace(m_referencedNodes);
+    visitor->trace(m_liveNodes);
+    visitor->trace(m_liveAudioSummingJunctions);
+#endif
     EventTargetWithInlineData::trace(visitor);
 }
 
-} // namespace WebCore
+} // namespace blink
 
 #endif // ENABLE(WEB_AUDIO)