⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 100210 in webkit


Ignore:
Timestamp:
Nov 14, 2011, 4:18:44 PM (15 years ago)
Author:
commit-queue@webkit.org
Message:

Add buffering to handle mismatch between hardware buffer size and webaudio render size
https://bugs.webkit.org/show_bug.cgi?id=71949

Patch by Raymond Toy <Raymond Toy> on 2011-11-14
Reviewed by Kenneth Russell.

  • src/AudioDestinationChromium.cpp:

(WebCore::AudioDestinationChromium::AudioDestinationChromium):
Create the FIFO for buffering.
(WebCore::AudioDestinationChromium::render): Get rid of
m_renderCountPerCallback and let the FIFO consume function produce
the appropriate nubmer of calls to the webaudio producer. Also
remove the rounding of the callback size so we use whatever the
hardware returns. Removed maximumCallbackBufferSize and use
fifoSize to set the FIFO size.
(WebCore::AudioDestinationChromium::FIFO::FIFO):
(WebCore::AudioDestinationChromium::FIFO::consume):
(WebCore::AudioDestinationChromium::FIFO::findWrapLengths):
(WebCore::AudioDestinationChromium::FIFO::fillBuffer):
Implementation of new FIFO class.

  • src/AudioDestinationChromium.h:

(WebCore::AudioDestinationChromium::FIFO::updateIndex):
Define new FIFO class.

Location:
trunk/Source/WebKit/chromium
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/chromium/ChangeLog

    r100199 r100210  
     12011-11-14  Raymond Toy  <rtoy@google.com>
     2
     3        Add buffering to handle mismatch between hardware buffer size and webaudio render size
     4        https://bugs.webkit.org/show_bug.cgi?id=71949
     5
     6        Reviewed by Kenneth Russell.
     7
     8        * src/AudioDestinationChromium.cpp:
     9        (WebCore::AudioDestinationChromium::AudioDestinationChromium):
     10        Create the FIFO for buffering.
     11        (WebCore::AudioDestinationChromium::render):  Get rid of
     12        m_renderCountPerCallback and let the FIFO consume function produce
     13        the appropriate nubmer of calls to the webaudio producer.  Also
     14        remove the rounding of the callback size so we use whatever the
     15        hardware returns.  Removed maximumCallbackBufferSize and use
     16        fifoSize to set the FIFO size.
     17        (WebCore::AudioDestinationChromium::FIFO::FIFO):
     18        (WebCore::AudioDestinationChromium::FIFO::consume):
     19        (WebCore::AudioDestinationChromium::FIFO::findWrapLengths):
     20        (WebCore::AudioDestinationChromium::FIFO::fillBuffer):
     21        Implementation of new FIFO class.
     22        * src/AudioDestinationChromium.h:
     23        (WebCore::AudioDestinationChromium::FIFO::updateIndex):
     24        Define new FIFO class.
     25
    1262011-11-14  Adrienne Walker  <enne@google.com>
    227
  • trunk/Source/WebKit/chromium/src/AudioDestinationChromium.cpp

    r98837 r100210  
    3333#include "AudioDestinationChromium.h"
    3434
    35 #include "AudioSourceProvider.h"
    3635#include "WebKit.h"
    3736#include "WebKitPlatformSupport.h"
     
    4443const unsigned renderBufferSize = 128;
    4544
    46 // Maximum allowed buffer size
    47 const size_t maximumCallbackBufferSize = 16384;
     45// Size of the FIFO
     46const size_t fifoSize = 8192;
    4847
    4948// FIXME: add support for multi-channel.
     
    6261    , m_isPlaying(false)
    6362{
    64     // Get the minimum usable buffer size. We'll round this value up
    65     // to a multiple of our render size.
    66     size_t callbackSize = webKitPlatformSupport()->audioHardwareBufferSize();
    67 
    68     // Figure out how many render calls per call back, rounding up if needed.
    69     m_renderCountPerCallback = (callbackSize + renderBufferSize - 1) / renderBufferSize;
    70 
    71     m_callbackBufferSize = m_renderCountPerCallback * renderBufferSize;
    72 
    73     bool isSizeGood = m_callbackBufferSize >= renderBufferSize
    74         && m_callbackBufferSize <= maximumCallbackBufferSize;
    75     ASSERT(isSizeGood);
    76     if (!isSizeGood)
    77       return;
     63    // Use the optimal buffer size recommended by the audio backend.
     64    m_callbackBufferSize = webKitPlatformSupport()->audioHardwareBufferSize();
     65
     66    // Quick exit if the requested size is too large.
     67    ASSERT(m_callbackBufferSize + renderBufferSize <= fifoSize);
     68    if (m_callbackBufferSize + renderBufferSize > fifoSize)
     69        return;
    7870   
    7971    m_audioDevice = adoptPtr(webKitPlatformSupport()->createAudioDevice(m_callbackBufferSize, numberOfChannels, sampleRate, this));
    8072    ASSERT(m_audioDevice);
     73
     74    // Create a FIFO to handle the possibility of the callback size
     75    // not being a multiple of the render size. If the FIFO already
     76    // contains enough data, the data will be provided directly.
     77    // Otherwise, the FIFO will call the provider enough times to
     78    // satisfy the request for data.
     79    m_fifo = adoptPtr(new FIFO(provider, numberOfChannels, fifoSize, renderBufferSize));
    8180}
    8281
     
    122121    }
    123122
    124     // Split up the callback buffer into smaller chunks which we'll render one after the other.
    125     for (unsigned i = 0; i < m_renderCountPerCallback; ++i) {
    126         m_renderBus.setChannelMemory(0, audioData[0] + i * renderBufferSize, renderBufferSize);
    127         m_renderBus.setChannelMemory(1, audioData[1] + i * renderBufferSize, renderBufferSize);
    128         m_provider.provideInput(&m_renderBus, renderBufferSize);
     123    m_renderBus.setChannelMemory(0, audioData[0], numberOfFrames);
     124    m_renderBus.setChannelMemory(1, audioData[1], numberOfFrames);
     125    m_fifo->consume(&m_renderBus, numberOfFrames);
     126}
     127
     128AudioDestinationChromium::FIFO::FIFO(AudioSourceProvider& provider, unsigned numberOfChannels, size_t fifoLength, size_t providerSize)
     129    : m_provider(provider)
     130    , m_fifoAudioBus(numberOfChannels, fifoLength)
     131    , m_fifoLength(fifoLength)
     132    , m_framesInFifo(0)
     133    , m_readIndex(0)
     134    , m_writeIndex(0)
     135    , m_providerSize(providerSize)
     136    , m_tempBus(numberOfChannels, providerSize)
     137{
     138}
     139
     140void AudioDestinationChromium::FIFO::consume(AudioBus* destination, size_t framesToConsume)
     141{
     142    bool isGood = destination && (framesToConsume <= m_fifoLength);
     143    ASSERT(isGood);
     144    if (!isGood)
     145        return;
     146
     147    if (framesToConsume > m_framesInFifo) {
     148        // We don't have enough data in the FIFO to fulfill the
     149        // request. Ask for more data.
     150        fillBuffer(framesToConsume - m_framesInFifo);
     151    }
     152
     153    // We have enough data now. Copy the requested number of samples
     154    // to the destination.
     155
     156    size_t part1Length;
     157    size_t part2Length;
     158    findWrapLengths(m_readIndex, framesToConsume, part1Length, part2Length);
     159
     160    size_t numberOfChannels = m_fifoAudioBus.numberOfChannels();
     161
     162    for (size_t channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
     163        float* destinationData = destination->channel(channelIndex)->data();
     164        float* sourceData = m_fifoAudioBus.channel(channelIndex)->data();
     165
     166        bool isCopyGood = ((m_readIndex < m_fifoLength)
     167                           && (m_readIndex + part1Length) <= m_fifoLength
     168                           && (part1Length <= destination->length())
     169                           && (part1Length + part2Length) <= destination->length());
     170        ASSERT(isCopyGood);
     171        if (!isCopyGood)
     172            return;
     173
     174        memcpy(destinationData, sourceData + m_readIndex, part1Length * sizeof(*sourceData));
     175        // Handle wrap around of the FIFO, if needed.
     176        if (part2Length > 0)
     177            memcpy(destinationData + part1Length, sourceData, part2Length * sizeof(*sourceData));
     178    }
     179    m_readIndex = updateIndex(m_readIndex, framesToConsume);
     180    m_framesInFifo -= framesToConsume;
     181    ASSERT(m_framesInFifo >= 0);
     182}
     183
     184void AudioDestinationChromium::FIFO::findWrapLengths(size_t index, size_t size, size_t& part1Length, size_t& part2Length)
     185{
     186    ASSERT(index < m_fifoLength && size <= m_fifoLength);
     187    if (index < m_fifoLength && size <= m_fifoLength) {
     188        if (index + size > m_fifoLength) {
     189            // Need to wrap. Figure out the length of each piece.
     190            part1Length = m_fifoLength - index;
     191            part2Length = size - part1Length;
     192        } else {
     193            // No wrap needed.
     194            part1Length = size;
     195            part2Length = 0;
     196        }
     197    } else {
     198        // Invalid values for index or size. Set the part lengths to
     199        // zero so nothing is copied.
     200        part1Length = 0;
     201        part2Length = 0;
     202    }
     203}
     204
     205void AudioDestinationChromium::FIFO::fillBuffer(size_t numberOfFrames)
     206{
     207    // Keep asking the provider to give us data until we have received
     208    // at least |numberOfFrames| of data. Stuff the data into the
     209    // FIFO.
     210    size_t framesProvided = 0;
     211
     212    while (framesProvided < numberOfFrames) {
     213        m_provider.provideInput(&m_tempBus, m_providerSize);
     214
     215        size_t part1Length;
     216        size_t part2Length;
     217        findWrapLengths(m_writeIndex, m_providerSize, part1Length, part2Length);
     218
     219        size_t numberOfChannels = m_fifoAudioBus.numberOfChannels();
     220       
     221        for (size_t channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
     222            float* destination = m_fifoAudioBus.channel(channelIndex)->data();
     223            float* source = m_tempBus.channel(channelIndex)->data();
     224
     225            bool isCopyGood = (part1Length <= m_providerSize
     226                               && (part1Length + part2Length) <= m_providerSize
     227                               && (m_writeIndex < m_fifoLength)
     228                               && (m_writeIndex + part1Length) <= m_fifoLength
     229                               && part2Length < m_fifoLength);
     230            ASSERT(isCopyGood);
     231            if (!isCopyGood)
     232                return;
     233
     234            memcpy(destination + m_writeIndex, source, part1Length * sizeof(*destination));
     235            // Handle wrap around of the FIFO, if needed.
     236            if (part2Length > 0)
     237                memcpy(destination, source + part1Length, part2Length * sizeof(*destination));
     238        }
     239
     240        m_framesInFifo += m_providerSize;
     241        ASSERT(m_framesInFifo <= m_fifoLength);
     242        m_writeIndex = updateIndex(m_writeIndex, m_providerSize);
     243        framesProvided += m_providerSize;
    129244    }
    130245}
  • trunk/Source/WebKit/chromium/src/AudioDestinationChromium.h

    r96745 r100210  
    3232#include "AudioBus.h"
    3333#include "AudioDestination.h"
     34#include "AudioSourceProvider.h"
    3435#include "WebAudioDevice.h"
    3536#include "WebVector.h"
     
    5657
    5758private:
    58     AudioSourceProvider& m_provider;
     59    // A FIFO (First In First Out) buffer to handle mismatches in the
     60    // audio backend hardware buffer size and the Web Audio render size.
     61    class FIFO {
     62    public:
     63        // Create a FIFO that gets data from |provider|. The FIFO will
     64        // be large enough to hold |fifoLength| frames of data of
     65        // |numberOfChannels| channels. The AudioSourceProvider will
     66        // be asked to produce |providerSize| frames when the FIFO
     67        // needs more data.
     68        FIFO(AudioSourceProvider& provider, unsigned numberOfChannels, size_t fifoLength, size_t providerSize);
     69
     70        // Read |framesToConsume| frames from the FIFO into the
     71        // destination. If the FIFO does not have enough data, we ask
     72        // the |provider| to get more data to fulfill the request.
     73        void consume(AudioBus* destination, size_t framesToConsume);
     74
     75    private:
     76        // Update the FIFO index by the step, with appropriate
     77        // wrapping around the endpoint.
     78        int updateIndex(int index, int step) { return (index + step) % m_fifoLength; }
     79
     80        void findWrapLengths(size_t index, size_t providerSize, size_t& part1Length, size_t& part2Length);
     81       
     82        // Fill the FIFO buffer with at least |numberOfFrames| more data.
     83        void fillBuffer(size_t numberOfFrames);
     84
     85        // The provider of the data in our FIFO.
     86        AudioSourceProvider& m_provider;
     87
     88        // The FIFO itself. In reality, the FIFO is a circular buffer.
     89        AudioBus m_fifoAudioBus;
     90
     91        // The total available space in the FIFO.
     92        size_t m_fifoLength;
     93
     94        // The number of actual elements in the FIFO
     95        size_t m_framesInFifo;
     96
     97        // Where to start reading from the FIFO.
     98        size_t m_readIndex;
     99
     100        // Where to start writing to the FIFO.
     101        size_t m_writeIndex;
     102
     103        // Number of frames of data that the provider will produce per call.
     104        unsigned int m_providerSize;
     105
     106        // Temporary workspace to hold the data from the provider.
     107        AudioBus m_tempBus;
     108    };
     109
     110AudioSourceProvider& m_provider;
    59111    AudioBus m_renderBus;
    60112    float m_sampleRate;
     
    62114    OwnPtr<WebKit::WebAudioDevice> m_audioDevice;
    63115    size_t m_callbackBufferSize;
    64     unsigned m_renderCountPerCallback;
     116    OwnPtr<FIFO> m_fifo;
    65117};
    66118
Note: See TracChangeset for help on using the changeset viewer.