Home | History | Annotate | Download | only in webaudio
      1 /*
      2  * Copyright (C) 2011, 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 "modules/webaudio/OfflineAudioDestinationNode.h"
     30 
     31 #include "core/dom/CrossThreadTask.h"
     32 #include "modules/webaudio/AudioContext.h"
     33 #include "platform/Task.h"
     34 #include "platform/audio/AudioBus.h"
     35 #include "platform/audio/HRTFDatabaseLoader.h"
     36 #include "public/platform/Platform.h"
     37 #include <algorithm>
     38 
     39 namespace blink {
     40 
     41 const size_t renderQuantumSize = 128;
     42 
     43 OfflineAudioDestinationNode::OfflineAudioDestinationNode(AudioContext* context, AudioBuffer* renderTarget)
     44     : AudioDestinationNode(context, renderTarget->sampleRate())
     45     , m_renderTarget(renderTarget)
     46     , m_startedRendering(false)
     47 {
     48     m_renderBus = AudioBus::create(renderTarget->numberOfChannels(), renderQuantumSize);
     49 }
     50 
     51 OfflineAudioDestinationNode::~OfflineAudioDestinationNode()
     52 {
     53     ASSERT(!isInitialized());
     54 }
     55 
     56 void OfflineAudioDestinationNode::dispose()
     57 {
     58     uninitialize();
     59     AudioDestinationNode::dispose();
     60 }
     61 
     62 void OfflineAudioDestinationNode::initialize()
     63 {
     64     if (isInitialized())
     65         return;
     66 
     67     AudioNode::initialize();
     68 }
     69 
     70 void OfflineAudioDestinationNode::uninitialize()
     71 {
     72     if (!isInitialized())
     73         return;
     74 
     75     if (m_renderThread)
     76         m_renderThread.clear();
     77 
     78     AudioNode::uninitialize();
     79 }
     80 
     81 void OfflineAudioDestinationNode::startRendering()
     82 {
     83     ASSERT(isMainThread());
     84     ASSERT(m_renderTarget.get());
     85     if (!m_renderTarget.get())
     86         return;
     87 
     88     if (!m_startedRendering) {
     89         m_startedRendering = true;
     90         m_renderThread = adoptPtr(blink::Platform::current()->createThread("Offline Audio Renderer"));
     91         m_renderThread->postTask(new Task(bind(&OfflineAudioDestinationNode::offlineRender, this)));
     92     }
     93 }
     94 
     95 void OfflineAudioDestinationNode::offlineRender()
     96 {
     97     ASSERT(!isMainThread());
     98     ASSERT(m_renderBus.get());
     99     if (!m_renderBus.get())
    100         return;
    101 
    102     bool isAudioContextInitialized = context()->isInitialized();
    103     ASSERT(isAudioContextInitialized);
    104     if (!isAudioContextInitialized)
    105         return;
    106 
    107     bool channelsMatch = m_renderBus->numberOfChannels() == m_renderTarget->numberOfChannels();
    108     ASSERT(channelsMatch);
    109     if (!channelsMatch)
    110         return;
    111 
    112     bool isRenderBusAllocated = m_renderBus->length() >= renderQuantumSize;
    113     ASSERT(isRenderBusAllocated);
    114     if (!isRenderBusAllocated)
    115         return;
    116 
    117     // Break up the render target into smaller "render quantize" sized pieces.
    118     // Render until we're finished.
    119     size_t framesToProcess = m_renderTarget->length();
    120     unsigned numberOfChannels = m_renderTarget->numberOfChannels();
    121 
    122     unsigned n = 0;
    123     while (framesToProcess > 0) {
    124         // Render one render quantum.
    125         render(0, m_renderBus.get(), renderQuantumSize);
    126 
    127         size_t framesAvailableToCopy = std::min(framesToProcess, renderQuantumSize);
    128 
    129         for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
    130             const float* source = m_renderBus->channel(channelIndex)->data();
    131             float* destination = m_renderTarget->getChannelData(channelIndex)->data();
    132             memcpy(destination + n, source, sizeof(float) * framesAvailableToCopy);
    133         }
    134 
    135         n += framesAvailableToCopy;
    136         framesToProcess -= framesAvailableToCopy;
    137     }
    138 
    139     // Our work is done. Let the AudioContext know.
    140     if (context()->executionContext())
    141         context()->executionContext()->postTask(createCrossThreadTask(&OfflineAudioDestinationNode::notifyComplete, this));
    142 }
    143 
    144 void OfflineAudioDestinationNode::notifyComplete()
    145 {
    146     context()->fireCompletionEvent();
    147 }
    148 
    149 void OfflineAudioDestinationNode::trace(Visitor* visitor)
    150 {
    151     visitor->trace(m_renderTarget);
    152     AudioDestinationNode::trace(visitor);
    153 }
    154 
    155 } // namespace blink
    156 
    157 #endif // ENABLE(WEB_AUDIO)
    158