[webkit-reviews] review granted: [Bug 34452] Initial patch for audio engine: AudioBus and helper classes : [Attachment 65995] Patch

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Tue Aug 31 18:22:38 PDT 2010


Kenneth Russell <kbr at google.com> has granted Chris Rogers
<crogers at google.com>'s request for review:
Bug 34452: Initial patch for audio engine: AudioBus and helper classes
https://bugs.webkit.org/show_bug.cgi?id=34452

Attachment 65995: Patch
https://bugs.webkit.org/attachment.cgi?id=65995&action=review

------- Additional Comments from Kenneth Russell <kbr at google.com>
This looks good to me; r=me. A couple of minor issues which you can fix upon
commit if you're using webkit-patch land, or upload a new patch if you're going
to use the commit queue.


> Index: WebCore/platform/audio/AudioBus.cpp
> ===================================================================
> --- WebCore/platform/audio/AudioBus.cpp	(revision 0)
> +++ WebCore/platform/audio/AudioBus.cpp	(revision 0)
> @@ -0,0 +1,364 @@
> +/*
> + * 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 "AudioBus.h"
> +
> +#include "Accelerate.h"
> +#include <assert.h>
> +#include <math.h>
> +#include <wtf/OwnPtr.h>
> +#include <wtf/PassOwnPtr.h>
> +
> +namespace WebCore {
> +
> +AudioBus::AudioBus(unsigned numberOfChannels, size_t length, bool allocate)
> +    : m_length(length)
> +    , m_busGain(1.0)
> +    , m_isFirstTime(true)
> +    , m_sampleRate(0.0)
> +{
> +    m_channels.reserveInitialCapacity(numberOfChannels);
> +
> +    for (unsigned i = 0; i < numberOfChannels; ++i) {
> +	   PassOwnPtr<AudioChannel> channel = allocate ? adoptPtr(new
AudioChannel(length)) : adoptPtr(new AudioChannel(0, length));
> +	   m_channels.append(channel);
> +    }
> +
> +    m_layout = LayoutCanonical; // for now this is the only layout we define

> +}
> +
> +void AudioBus::setChannelMemory(unsigned channelIndex, float* storage,
size_t length)
> +{
> +    if (channelIndex < m_channels.size()) {
> +	   channel(channelIndex)->set(storage, length);
> +	   m_length = length;

This still looks fishy to me; only one of the channels is having its storage
set, but the overall length of the AudioBus is being updated.

> +    }
> +}
> +
> +void AudioBus::zero()
> +{
> +    for (unsigned i = 0; i < m_channels.size(); ++i)
> +	   m_channels[i]->zero();
> +}
> +
> +AudioChannel* AudioBus::channelByType(unsigned channelType)
> +{
> +    // For now we only support canonical channel layouts...
> +    if (m_layout != LayoutCanonical)
> +	   return 0;
> +
> +    switch (numberOfChannels()) {
> +    case 1: // mono
> +	   if (channelType == ChannelMono || channelType == ChannelLeft)
> +	       return channel(0);
> +	   return 0;
> +
> +    case 2: // stereo
> +	   switch (channelType) {
> +	   case ChannelLeft: return channel(0);
> +	   case ChannelRight: return channel(1);
> +	   default: return 0;
> +	   }
> +
> +    case 4: // quad
> +	   switch (channelType) {
> +	   case ChannelLeft: return channel(0);
> +	   case ChannelRight: return channel(1);
> +	   case ChannelSurroundLeft: return channel(2);
> +	   case ChannelSurroundRight: return channel(3);
> +	   default: return 0;
> +	   }
> +
> +    case 5: // 5.0
> +	   switch (channelType) {
> +	   case ChannelLeft: return channel(0);
> +	   case ChannelRight: return channel(1);
> +	   case ChannelCenter: return channel(2);
> +	   case ChannelSurroundLeft: return channel(3);
> +	   case ChannelSurroundRight: return channel(4);
> +	   default: return 0;
> +	   }
> +
> +    case 6: // 5.1
> +	   switch (channelType) {
> +	   case ChannelLeft: return channel(0);
> +	   case ChannelRight: return channel(1);
> +	   case ChannelCenter: return channel(2);
> +	   case ChannelLFE: return channel(3);
> +	   case ChannelSurroundLeft: return channel(4);
> +	   case ChannelSurroundRight: return channel(5);
> +	   default: return 0;
> +	   }
> +    }
> +    
> +    ASSERT_NOT_REACHED();
> +    return 0;
> +}
> +
> +// Returns true if the channel count and frame-size match.
> +bool AudioBus::topologyMatches(const AudioBus& bus) const
> +{
> +    if (numberOfChannels() != bus.numberOfChannels())
> +	   return false; // channel mismatch
> +
> +    // Make sure source bus has enough frames.
> +    if (length() > bus.length())
> +	   return false; // frame-size mismatch
> +
> +    return true;
> +}
> +
> +PassOwnPtr<AudioBus> AudioBus::createBufferFromRange(AudioBus* sourceBuffer,
unsigned startFrame, unsigned endFrame)
> +{
> +    size_t numberOfSourceFrames = sourceBuffer->length();
> +    unsigned numberOfChannels = sourceBuffer->numberOfChannels();
> +
> +    // Sanity checking
> +    bool isRangeSafe = startFrame < endFrame && endFrame <=
numberOfSourceFrames;
> +    ASSERT(isRangeSafe);
> +    if (!isRangeSafe)
> +	   return 0;
> +
> +    size_t rangeLength = endFrame - startFrame;
> +
> +    PassOwnPtr<AudioBus> audioBus = adoptPtr(new AudioBus(numberOfChannels,
rangeLength));

If this were a PassRefPtr, holding on to it as one instead of as a RefPtr would
be incorrect. To match the preferred style, use OwnPtr<AudioBus> here; see
below for the return value.

> +    audioBus->setSampleRate(sourceBuffer->sampleRate());
> +
> +    for (unsigned i = 0; i < numberOfChannels; ++i)
> +	   audioBus->channel(i)->copyFromRange(sourceBuffer->channel(i),
startFrame, endFrame);
> +
> +    return audioBus;

Here, use "return audioBus.release()".

> +}
> +
> +float AudioBus::maxAbsValue() const
> +{
> +    float max = 0.0f;
> +    for (unsigned i = 0; i < numberOfChannels(); ++i) {
> +	   AudioChannel* channel = const_cast<AudioBus*>(this)->channel(i);

Shouldn't you be able to write "const AudioChannel* channel = ..." now, and get
rid of the const_cast?

> +	   float channelMax = channel->maxAbsValue();
> +	   if (channelMax > max)
> +	       max = channelMax;

Could just write "max = std::max(max, channel->maxAbsValue()".

> +    }
> +
> +    return max;
> +}
> +
> +void AudioBus::normalize()
> +{
> +    float max = maxAbsValue();
> +    if (max)
> +	   scale(1.0f / max);
> +}
> +
> +void AudioBus::scale(double scale)
> +{
> +    for (unsigned i = 0; i < numberOfChannels(); ++i)
> +	   channel(i)->scale(scale);
> +}
> +
> +// Just copies the samples from the source bus to this one.
> +// This is just a simple copy if the number of channels match, otherwise a
mixup or mixdown is done.
> +// For now, we just support a mixup from mono -> stereo.
> +void AudioBus::copyFrom(const AudioBus& sourceBus)
> +{
> +    if (&sourceBus == this)
> +	   return;
> +
> +    if (numberOfChannels() == sourceBus.numberOfChannels()) {
> +	   for (unsigned i = 0; i < numberOfChannels(); ++i)
> +	       channel(i)->copyFrom(sourceBus.channel(i));
> +    } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1)
{
> +	   // Handle mono -> stereo case (for now simply copy mono channel into
both left and right)
> +	   // FIXME: Really we should apply an equal-power scaling factor here,
since we're effectively panning center...
> +	   const AudioChannel* sourceChannel = sourceBus.channel(0);
> +	   channel(0)->copyFrom(sourceChannel);
> +	   channel(1)->copyFrom(sourceChannel);
> +    } else {
> +	   // Case not handled
> +	   ASSERT_NOT_REACHED();
> +    }
> +}
> +
> +void AudioBus::sumFrom(const AudioBus &sourceBus)
> +{
> +    if (numberOfChannels() == sourceBus.numberOfChannels()) {
> +	   for (unsigned i = 0; i < numberOfChannels(); ++i)
> +	       channel(i)->sumFrom(sourceBus.channel(i));
> +    } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1)
{
> +	   // Handle mono -> stereo case (for now simply sum mono channel into
both left and right)
> +	   // FIXME: Really we should apply an equal-power scaling factor here,
since we're effectively panning center...
> +	   const AudioChannel* sourceChannel = sourceBus.channel(0);
> +	   channel(0)->sumFrom(sourceChannel);
> +	   channel(1)->sumFrom(sourceChannel);
> +    } else {
> +	   // Case not handled
> +	   ASSERT_NOT_REACHED();
> +    }
> +}
> +
> +void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus,
double* lastMixGain, double targetGain, bool sumToBus)
> +{
> +    // We don't want to suddenly change the gain from mixing one time slice
to the next,
> +    // so we "de-zipper" by slowly changing the gain each sample-frame until
we've achieved the target gain.
> +
> +    // FIXME: optimize this method (SSE, etc.)
> +    // FIXME: Need fast path here when gain has converged on targetGain. In
this case, de-zippering is no longer needed.
> +    // FIXME: Need fast path when this==sourceBus &&
lastMixGain==targetGain==1.0 && sumToBus==false (this is a NOP)
> +
> +    // Take master bus gain into account as well as the targetGain.
> +    double totalDesiredGain = m_busGain * targetGain;
> +
> +    // First time, snap directly to totalDesiredGain.
> +    double gain = m_isFirstTime ? totalDesiredGain : *lastMixGain;
> +    m_isFirstTime = false;
> +
> +    int numberOfSourceChannels = sourceBus.numberOfChannels();
> +    int numberOfDestinationChannels = numberOfChannels();
> +
> +    AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
> +    const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();

> +    const float* sourceR = numberOfSourceChannels > 1 ?
sourceBusSafe.channelByType(ChannelRight)->data() : 0;
> +
> +    float* destinationL = channelByType(ChannelLeft)->data();
> +    float* destinationR = numberOfDestinationChannels > 1 ?
channelByType(ChannelRight)->data() : 0;
> +
> +    const double DezipperRate = 0.005;
> +    int framesToProcess = length();
> +
> +    if (sumToBus) {
> +	   // Sum to our bus
> +	   if (sourceR && destinationR) {
> +	       // Stereo
> +	       while (framesToProcess--) {
> +		   float sampleL = *sourceL++;
> +		   float sampleR = *sourceR++;
> +		   *destinationL++ += static_cast<float>(gain * sampleL);
> +		   *destinationR++ += static_cast<float>(gain * sampleR);
> +
> +		   // Slowly change gain to desired gain.
> +		   gain += (totalDesiredGain - gain) * DezipperRate;
> +	       }
> +	   } else if (destinationR) {
> +	       // Mono -> stereo (mix equally into L and R)
> +	       // FIXME: Really we should apply an equal-power scaling factor
here, since we're effectively panning center...
> +	       while (framesToProcess--) {
> +		   float sample = *sourceL++;
> +		   *destinationL++ += static_cast<float>(gain * sample);
> +		   *destinationR++ += static_cast<float>(gain * sample);
> +
> +		   // Slowly change gain to desired gain.
> +		   gain += (totalDesiredGain - gain) * DezipperRate;
> +	       }
> +	   } else {
> +	       // Mono
> +	       while (framesToProcess--) {
> +		   float sampleL = *sourceL++;
> +		   *destinationL++ += static_cast<float>(gain * sampleL);
> +
> +		   // Slowly change gain to desired gain.
> +		   gain += (totalDesiredGain - gain) * DezipperRate;
> +	       }
> +	   }
> +    } else {
> +	   // Process directly (without summing) to our bus
> +	   if (sourceR && destinationR) {
> +	       // Stereo
> +	       while (framesToProcess--) {
> +		   float sampleL = *sourceL++;
> +		   float sampleR = *sourceR++;
> +		   *destinationL++ = static_cast<float>(gain * sampleL);
> +		   *destinationR++ = static_cast<float>(gain * sampleR);
> +
> +		   // Slowly change gain to desired gain.
> +		   gain += (totalDesiredGain - gain) * DezipperRate;
> +	       }
> +	   } else if (destinationR) {
> +	       // Mono -> stereo (mix equally into L and R)
> +	       // FIXME: Really we should apply an equal-power scaling factor
here, since we're effectively panning center...
> +	       while (framesToProcess--) {
> +		   float sample = *sourceL++;
> +		   *destinationL++ = static_cast<float>(gain * sample);
> +		   *destinationR++ = static_cast<float>(gain * sample);
> +
> +		   // Slowly change gain to desired gain.
> +		   gain += (totalDesiredGain - gain) * DezipperRate;
> +	       }
> +	   } else {
> +	       // Mono
> +	       while (framesToProcess--) {
> +		   float sampleL = *sourceL++;
> +		   *destinationL++ = static_cast<float>(gain * sampleL);
> +
> +		   // Slowly change gain to desired gain.
> +		   gain += (totalDesiredGain - gain) * DezipperRate;
> +	       }
> +	   }
> +    }
> +
> +    // Save the target gain as the starting point for next time around.
> +    *lastMixGain = gain;
> +}
> +
> +void AudioBus::processWithGainFrom(const AudioBus &sourceBus, double*
lastMixGain, double targetGain, bool sumToBus)
> +{
> +    // Make sure we're summing from same type of bus.
> +    // We *are* able to sum from mono -> stereo
> +    if (sourceBus.numberOfChannels() != 1 && !topologyMatches(sourceBus))
> +	   return;
> +
> +    // Dispatch for different channel layouts
> +    switch (numberOfChannels()) {
> +    case 1: // mono
> +    case 2: // stereo
> +	   processWithGainFromMonoStereo(sourceBus, lastMixGain, targetGain,
sumToBus);
> +	   break;
> +    case 4: // FIXME: implement quad
> +    case 5: // FIXME: implement 5.0
> +    default:
> +	   ASSERT_NOT_REACHED();
> +	   break;
> +    }
> +}
> +
> +void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, double*
lastMixGain, double targetGain)
> +{
> +    processWithGainFrom(sourceBus, lastMixGain, targetGain, false);
> +}
> +
> +void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double*
lastMixGain, double targetGain)
> +{
> +    processWithGainFrom(sourceBus, lastMixGain, targetGain, true);
> +}
> +
> +} // WebCore
> +
> +#endif // ENABLE(WEB_AUDIO)
> Index: WebCore/platform/audio/AudioBus.h
> ===================================================================
> --- WebCore/platform/audio/AudioBus.h (revision 0)
> +++ WebCore/platform/audio/AudioBus.h (revision 0)
> @@ -0,0 +1,139 @@
> +/*
> + * 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 AudioBus_h
> +#define AudioBus_h
> +
> +#include "AudioChannel.h"
> +#include <wtf/Noncopyable.h>
> +#include <wtf/PassOwnPtr.h>
> +#include <wtf/Vector.h>
> +
> +namespace WebCore {
> +
> +// An AudioBus represents a collection of one or more AudioChannels.
> +// The data layout is "planar" as opposed to "interleaved".
> +// An AudioBus with one channel is mono, an AudioBus with two channels is
stereo, etc.
> +class AudioBus  : public Noncopyable {
> +public:
> +    enum {
> +	   ChannelLeft = 0,
> +	   ChannelRight = 1,
> +	   ChannelCenter = 2, // center and mono are the same
> +	   ChannelMono = 2,
> +	   ChannelLFE = 3,
> +	   ChannelSurroundLeft = 4,
> +	   ChannelSurroundRight = 5,
> +    };
> +
> +    enum {
> +	   LayoutCanonical = 0
> +	   // Can define non-standard layouts here
> +    };
> +
> +    // allocate indicates whether or not to initially have the AudioChannels
created with managed storage.
> +    // Normal usage is to pass true here, in which case the AudioChannels
will memory-manage their own storage.
> +    // If allocate is false then setChannelMemory() has to be called later
on for each channel before the AudioBus is useable...
> +    AudioBus(unsigned numberOfChannels, size_t length, bool allocate =
true);
> +
> +    // Tells the given channel to use an externally allocated buffer.
> +    void setChannelMemory(unsigned channelIndex, float* storage, size_t
length);
> +
> +    // Channels
> +    unsigned numberOfChannels() const { return m_channels.size(); }
> +
> +    AudioChannel* channel(unsigned channel) { return
m_channels[channel].get(); }
> +    const AudioChannel* channel(unsigned channel) const { return
const_cast<AudioBus*>(this)->m_channels[channel].get(); }
> +    AudioChannel* channelByType(unsigned type);
> +
> +    // Number of sample-frames
> +    size_t length() const { return m_length; }
> +
> +    // Sample-rate : 0.0 if unknown or "don't care"
> +    double sampleRate() const { return m_sampleRate; }
> +    void setSampleRate(double sampleRate) { m_sampleRate = sampleRate; }
> +
> +    // Zeroes all channels.
> +    void zero();
> +
> +    // Returns true if the channel count and frame-size match.
> +    bool topologyMatches(const AudioBus &sourceBus) const;
> +
> +    // Creates a new buffer from a range in the source buffer.
> +    // 0 may be returned if the range does not fit in the sourceBuffer
> +    static PassOwnPtr<AudioBus> createBufferFromRange(AudioBus*
sourceBuffer, unsigned startFrame, unsigned endFrame);
> +
> +    // Scales all samples by the same amount.
> +    void scale(double scale);
> +
> +    // Master gain for this bus - used with sumWithGainFrom() below
> +    void setGain(double gain) { m_busGain = gain; }
> +    double gain() { return m_busGain; }
> +
> +    void reset() { m_isFirstTime = true; } // for de-zippering
> +
> +    // Assuming sourceBus has the same topology, copies sample data from
each channel of sourceBus to our corresponding channel.
> +    void copyFrom(const AudioBus &sourceBus);
> +
> +    // Sums the sourceBus into our bus with unity gain.
> +    // Our own internal gain m_busGain is ignored.
> +    void sumFrom(const AudioBus &sourceBus);
> +
> +    // Copy or sum each channel from sourceBus into our corresponding
channel.
> +    // We scale by targetGain (and our own internal gain m_busGain),
performing "de-zippering" to smoothly change from *lastMixGain to
(targetGain*m_busGain).
> +    // The caller is responsible for setting up lastMixGain to point to
storage which is unique for every "stream" which will be summed to this bus.
> +    // This represents the dezippering memory.
> +    void copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain,
double targetGain);
> +    void sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain,
double targetGain);
> +
> +    // Returns maximum absolute value across all channels (useful for
normalization).
> +    float maxAbsValue() const;
> +
> +    // Makes maximum absolute value == 1.0 (if possible).
> +    void normalize();
> +
> +protected:
> +    AudioBus() { };
> +
> +    void processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain,
double targetGain, bool sumToBus);
> +    void processWithGainFromMonoStereo(const AudioBus &sourceBus, double*
lastMixGain, double targetGain, bool sumToBus);
> +
> +    size_t m_length;
> +
> +    Vector<OwnPtr<AudioChannel> > m_channels;
> +
> +    int m_layout;
> +
> +    double m_busGain;
> +    bool m_isFirstTime;
> +    double m_sampleRate; // 0.0 if unknown or N/A
> +};
> +
> +} // WebCore
> +
> +#endif // AudioBus_h
> Index: WebCore/platform/audio/AudioSourceProvider.h
> ===================================================================
> --- WebCore/platform/audio/AudioSourceProvider.h	(revision 0)
> +++ WebCore/platform/audio/AudioSourceProvider.h	(revision 0)
> @@ -0,0 +1,46 @@
> +/*
> + * 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 AudioSourceProvider_h
> +#define AudioSourceProvider_h
> +
> +namespace WebCore {
> +
> +class AudioBus;
> +    
> +// Abstract base-class for a pull-model client.
> +// provideInput() gets called repeatedly to render time-slices of a
continuous audio stream.
> +class AudioSourceProvider {
> +public:
> +    virtual void provideInput(AudioBus* bus, size_t framesToProcess) = 0;
> +    virtual ~AudioSourceProvider() { }
> +};
> +
> +} // WebCore
> +
> +#endif // AudioSourceProvider_h


More information about the webkit-reviews mailing list