Home | History | Annotate | Download | only in webaudio
      1 /*
      2  * Copyright (C) 2010, Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1.  Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #if ENABLE(WEB_AUDIO)
     28 
     29 #include "AudioBasicProcessorNode.h"
     30 
     31 #include "AudioBus.h"
     32 #include "AudioContext.h"
     33 #include "AudioNodeInput.h"
     34 #include "AudioNodeOutput.h"
     35 #include "AudioProcessor.h"
     36 
     37 namespace WebCore {
     38 
     39 AudioBasicProcessorNode::AudioBasicProcessorNode(AudioContext* context, double sampleRate)
     40     : AudioNode(context, sampleRate)
     41 {
     42     addInput(adoptPtr(new AudioNodeInput(this)));
     43     addOutput(adoptPtr(new AudioNodeOutput(this, 0)));
     44 
     45     // The subclass must create m_processor.
     46 }
     47 
     48 void AudioBasicProcessorNode::initialize()
     49 {
     50     if (isInitialized())
     51         return;
     52 
     53     ASSERT(processor());
     54     processor()->initialize();
     55 
     56     AudioNode::initialize();
     57 }
     58 
     59 void AudioBasicProcessorNode::uninitialize()
     60 {
     61     if (!isInitialized())
     62         return;
     63 
     64     ASSERT(processor());
     65     processor()->uninitialize();
     66 
     67     AudioNode::uninitialize();
     68 }
     69 
     70 void AudioBasicProcessorNode::process(size_t framesToProcess)
     71 {
     72     AudioBus* destinationBus = output(0)->bus();
     73 
     74     // The realtime thread can't block on this lock, so we call tryLock() instead.
     75     if (m_processLock.tryLock()) {
     76         if (!isInitialized() || !processor())
     77             destinationBus->zero();
     78         else {
     79             AudioBus* sourceBus = input(0)->bus();
     80 
     81             // FIXME: if we take "tail time" into account, then we can avoid calling processor()->process() once the tail dies down.
     82             if (!input(0)->isConnected())
     83                 sourceBus->zero();
     84 
     85             processor()->process(sourceBus, destinationBus, framesToProcess);
     86         }
     87 
     88         m_processLock.unlock();
     89     } else {
     90         // Too bad - the tryLock() failed.  We must be in the middle of re-connecting and were already outputting silence anyway...
     91         destinationBus->zero();
     92     }
     93 }
     94 
     95 // Nice optimization in the very common case allowing for "in-place" processing
     96 void AudioBasicProcessorNode::pullInputs(size_t framesToProcess)
     97 {
     98     // Render input stream - suggest to the input to render directly into output bus for in-place processing in process() if possible.
     99     input(0)->pull(output(0)->bus(), framesToProcess);
    100 }
    101 
    102 void AudioBasicProcessorNode::reset()
    103 {
    104     if (processor())
    105         processor()->reset();
    106 }
    107 
    108 // As soon as we know the channel count of our input, we can lazily initialize.
    109 // Sometimes this may be called more than once with different channel counts, in which case we must safely
    110 // uninitialize and then re-initialize with the new channel count.
    111 void AudioBasicProcessorNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
    112 {
    113     ASSERT(context()->isAudioThread() && context()->isGraphOwner());
    114 
    115     ASSERT(input == this->input(0));
    116     if (input != this->input(0))
    117         return;
    118 
    119     ASSERT(processor());
    120     if (!processor())
    121         return;
    122 
    123     unsigned numberOfChannels = input->numberOfChannels();
    124 
    125     if (isInitialized() && numberOfChannels != output(0)->numberOfChannels()) {
    126         // We're already initialized but the channel count has changed.
    127         // We need to be careful since we may be actively processing right now, so synchronize with process().
    128         MutexLocker locker(m_processLock);
    129         uninitialize();
    130     }
    131 
    132     if (!isInitialized()) {
    133         // This will propagate the channel count to any nodes connected further down the chain...
    134         output(0)->setNumberOfChannels(numberOfChannels);
    135 
    136         // Re-initialize the processor with the new channel count.
    137         processor()->setNumberOfChannels(numberOfChannels);
    138         initialize();
    139     }
    140 }
    141 
    142 unsigned AudioBasicProcessorNode::numberOfChannels()
    143 {
    144     return output(0)->numberOfChannels();
    145 }
    146 
    147 } // namespace WebCore
    148 
    149 #endif // ENABLE(WEB_AUDIO)
    150