/*
 * 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.
 *
 * 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 "AudioNodeOutput.h"

#include "AudioBus.h"
#include "AudioContext.h"
#include "AudioNodeInput.h"
#include "AudioParam.h"
#include "AudioUtilities.h"
#include <wtf/Threading.h>

namespace WebCore {

AudioNodeOutput::AudioNodeOutput(AudioNode* node, unsigned numberOfChannels)
    : m_node(node)
    , m_numberOfChannels(numberOfChannels)
    , m_desiredNumberOfChannels(numberOfChannels)
{
    ASSERT(numberOfChannels <= AudioContext::maxNumberOfChannels);

    m_internalBus = AudioBus::create(numberOfChannels, AudioUtilities::renderQuantumSize);
}

void AudioNodeOutput::setNumberOfChannels(unsigned numberOfChannels)
{
    ASSERT(numberOfChannels <= AudioContext::maxNumberOfChannels);
    ASSERT(context().isGraphOwner());

    m_desiredNumberOfChannels = numberOfChannels;

    if (context().isAudioThread()) {
        // If we're in the audio thread then we can take care of it right away (we should be at the very start or end of a rendering quantum).
        updateNumberOfChannels();
    } else {
        // Let the context take care of it in the audio thread in the pre and post render tasks.
        context().markAudioNodeOutputDirty(this);
    }
}

void AudioNodeOutput::updateInternalBus()
{
    if (numberOfChannels() == m_internalBus->numberOfChannels())
        return;

    // Heap allocations are forbidden on the audio thread for performance reasons so we need to
    // explicitly allow the following allocation(s).
    DisableMallocRestrictionsForCurrentThreadScope disableMallocRestrictions;
    m_internalBus = AudioBus::create(numberOfChannels(), AudioUtilities::renderQuantumSize);
}

void AudioNodeOutput::updateRenderingState()
{
    updateNumberOfChannels();
    m_renderingFanOutCount = fanOutCount();
    m_renderingParamFanOutCount = paramFanOutCount();
}

void AudioNodeOutput::updateNumberOfChannels()
{
    ASSERT(context().isAudioThread() && context().isGraphOwner());

    if (m_numberOfChannels != m_desiredNumberOfChannels) {
        m_numberOfChannels = m_desiredNumberOfChannels;
        updateInternalBus();
        propagateChannelCount();
    }
}

void AudioNodeOutput::propagateChannelCount()
{
    ASSERT(context().isAudioThread() && context().isGraphOwner());
    
    if (isChannelCountKnown()) {
        // Announce to any nodes we're connected to that we changed our channel count for its input.
        for (auto& input : m_inputs.keys()) {
            AudioNode* connectionNode = input->node();
            connectionNode->checkNumberOfChannelsForInput(input);
        }
    }
}

AudioBus* AudioNodeOutput::pull(AudioBus* inPlaceBus, size_t framesToProcess)
{
    ASSERT(context().isAudioThread());
    ASSERT(m_renderingFanOutCount > 0 || m_renderingParamFanOutCount > 0);
    
    // Causes our AudioNode to process if it hasn't already for this render quantum.
    // We try to do in-place processing (using inPlaceBus) if at all possible,
    // but we can't process in-place if we're connected to more than one input (fan-out > 1).
    // In this case pull() is called multiple times per rendering quantum, and the processIfNecessary() call below will
    // cause our node to process() only the first time, caching the output in m_internalOutputBus for subsequent calls.    
    
    m_isInPlace = inPlaceBus && inPlaceBus->numberOfChannels() == numberOfChannels() && (m_renderingFanOutCount + m_renderingParamFanOutCount) == 1;

    m_inPlaceBus = m_isInPlace ? inPlaceBus : 0;

    node()->processIfNecessary(framesToProcess);
    return bus();
}

AudioBus* AudioNodeOutput::bus() const
{
    ASSERT(const_cast<AudioNodeOutput*>(this)->context().isAudioThread());
    return m_isInPlace ? m_inPlaceBus.get() : m_internalBus.get();
}

unsigned AudioNodeOutput::fanOutCount()
{
    ASSERT(context().isGraphOwner());
    return m_inputs.size();
}

unsigned AudioNodeOutput::paramFanOutCount()
{
    ASSERT(context().isGraphOwner());
    return m_params.size();
}

unsigned AudioNodeOutput::renderingFanOutCount() const
{
    return m_renderingFanOutCount;
}

unsigned AudioNodeOutput::renderingParamFanOutCount() const
{
    return m_renderingParamFanOutCount;
}

void AudioNodeOutput::addInput(AudioNodeInput* input)
{
    ASSERT(context().isGraphOwner());

    ASSERT(input);
    if (!input)
        return;

    m_inputs.add(input, input->node());
}

void AudioNodeOutput::removeInput(AudioNodeInput* input)
{
    ASSERT(context().isGraphOwner());

    ASSERT(input);
    if (!input)
        return;

    m_inputs.remove(input);
}

void AudioNodeOutput::disconnectAllInputs()
{
    ASSERT(context().isGraphOwner());
    
    // AudioNodeInput::disconnect() changes m_inputs by calling removeInput().
    while (!m_inputs.isEmpty()) {
        AudioNodeInput* input = m_inputs.begin()->key;
        input->disconnect(this);
    }
}

void AudioNodeOutput::addParam(AudioParam* param)
{
    ASSERT(context().isGraphOwner());

    ASSERT(param);
    if (!param)
        return;

    m_params.add(param);
}

void AudioNodeOutput::removeParam(AudioParam* param)
{
    ASSERT(context().isGraphOwner());

    ASSERT(param);
    if (!param)
        return;

    m_params.remove(param);
}

void AudioNodeOutput::disconnectAllParams()
{
    ASSERT(context().isGraphOwner());

    // AudioParam::disconnect() changes m_params by calling removeParam().
    while (!m_params.isEmpty()) {
        AudioParam* param = m_params.begin()->get();
        param->disconnect(this);
    }
}

void AudioNodeOutput::disconnectAll()
{
    disconnectAllInputs();
    disconnectAllParams();
}

void AudioNodeOutput::disable()
{
    ASSERT(context().isGraphOwner());

    if (m_isEnabled) {
        for (auto& input : m_inputs.keys())
            input->disable(this);
        m_isEnabled = false;
    }
}

void AudioNodeOutput::enable()
{
    ASSERT(context().isGraphOwner());

    if (!m_isEnabled) {
        for (auto& input : m_inputs.keys())
            input->enable(this);
        m_isEnabled = true;
    }
}

} // namespace WebCore

#endif // ENABLE(WEB_AUDIO)
