+2012-07-03 Raymond Toy <rtoy@google.com>
+
+ Add AudioFIFO class and simplify AudioPullFIFO
+ https://bugs.webkit.org/show_bug.cgi?id=90398
+
+ Reviewed by Chris Rogers.
+
+ No new tests. This code will be used in audio back-end implementation.
+
+ Add AudioFIFO class to implement main parts of FIFO. Simplify
+ implementation of AudioPushFIFO by using AudioFIFO.
+
+ * WebCore.gypi: Add new files.
+
+ New AudioFIFO class
+ * platform/audio/AudioFIFO.cpp: Copied from Source/WebCore/platform/audio/AudioPullFIFO.cpp.
+ (WebCore):
+ (WebCore::AudioFIFO::AudioFIFO):
+ (WebCore::AudioFIFO::consume):
+ (WebCore::AudioFIFO::push):
+ (WebCore::AudioFIFO::findWrapLengths):
+ * platform/audio/AudioFIFO.h: Copied from Source/WebCore/platform/audio/AudioPullFIFO.h.
+ (WebCore):
+ (AudioFIFO):
+ (WebCore::AudioFIFO::framesInFifo):
+ (WebCore::AudioFIFO::updateIndex):
+
+ Use AudioFIFO
+ * platform/audio/AudioPullFIFO.cpp:
+ (WebCore::AudioPullFIFO::AudioPullFIFO):
+ (WebCore::AudioPullFIFO::consume):
+ (WebCore::AudioPullFIFO::fillBuffer):
+ * platform/audio/AudioPullFIFO.h:
+ (AudioPullFIFO):
+
2012-07-03 Nate Chapin <japhet@chromium.org>
Protect this DocumentThreadableLoader in cancel() to handle reentrancy properly.
'platform/audio/AudioDSPKernelProcessor.cpp',
'platform/audio/AudioDSPKernelProcessor.h',
'platform/audio/AudioDestination.h',
+ 'platform/audio/AudioFIFO.cpp',
+ 'platform/audio/AudioFIFO.h',
'platform/audio/AudioFileReader.h',
'platform/audio/AudioProcessor.h',
'platform/audio/AudioPullFIFO.cpp',
--- /dev/null
+/*
+ * Copyright (C) 2012 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 "AudioFIFO.h"
+
+namespace WebCore {
+
+AudioFIFO::AudioFIFO(unsigned numberOfChannels, size_t fifoLength)
+ : m_fifoAudioBus(numberOfChannels, fifoLength)
+ , m_fifoLength(fifoLength)
+ , m_framesInFifo(0)
+ , m_readIndex(0)
+ , m_writeIndex(0)
+{
+}
+
+void AudioFIFO::consume(AudioBus* destination, size_t framesToConsume)
+{
+ bool isGood = destination && (framesToConsume <= m_fifoLength) && (framesToConsume <= m_framesInFifo) && (destination->length() >= framesToConsume);
+ ASSERT(isGood);
+ if (!isGood)
+ return;
+
+ // Copy the requested number of samples to the destination.
+
+ size_t part1Length;
+ size_t part2Length;
+ findWrapLengths(m_readIndex, framesToConsume, part1Length, part2Length);
+
+ size_t numberOfChannels = m_fifoAudioBus.numberOfChannels();
+
+ for (size_t channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
+ float* destinationData = destination->channel(channelIndex)->mutableData();
+ const float* sourceData = m_fifoAudioBus.channel(channelIndex)->data();
+
+ bool isCopyGood = ((m_readIndex < m_fifoLength)
+ && (m_readIndex + part1Length) <= m_fifoLength
+ && (part1Length <= destination->length())
+ && (part1Length + part2Length) <= destination->length());
+ ASSERT(isCopyGood);
+ if (!isCopyGood)
+ return;
+
+ memcpy(destinationData, sourceData + m_readIndex, part1Length * sizeof(*sourceData));
+ // Handle wrap around of the FIFO, if needed.
+ if (part2Length)
+ memcpy(destinationData + part1Length, sourceData, part2Length * sizeof(*sourceData));
+ }
+ m_readIndex = updateIndex(m_readIndex, framesToConsume);
+ ASSERT(m_framesInFifo >= framesToConsume);
+ m_framesInFifo -= framesToConsume;
+}
+
+void AudioFIFO::push(const AudioBus* sourceBus)
+{
+ // Copy the sourceBus into the FIFO buffer.
+
+ bool isGood = sourceBus && (m_framesInFifo + sourceBus->length() <= m_fifoLength);
+ if (!isGood)
+ return;
+
+ size_t sourceLength = sourceBus->length();
+ size_t part1Length;
+ size_t part2Length;
+ findWrapLengths(m_readIndex, sourceLength, part1Length, part2Length);
+
+ size_t numberOfChannels = m_fifoAudioBus.numberOfChannels();
+
+ for (size_t channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
+ float* destination = m_fifoAudioBus.channel(channelIndex)->mutableData();
+ const float* source = sourceBus->channel(channelIndex)->data();
+
+ bool isCopyGood = ((m_writeIndex < m_fifoLength)
+ && (m_writeIndex + part1Length) <= m_fifoLength
+ && part2Length < m_fifoLength
+ && part1Length + part2Length <= sourceLength);
+ ASSERT(isCopyGood);
+ if (!isCopyGood)
+ return;
+
+ memcpy(destination + m_writeIndex, source, part1Length * sizeof(*destination));
+
+ // Handle wrap around of the FIFO, if needed.
+ if (part2Length)
+ memcpy(destination, source + part1Length, part2Length * sizeof(*destination));
+ }
+
+ m_framesInFifo += sourceLength;
+ ASSERT(m_framesInFifo <= m_fifoLength);
+ m_writeIndex = updateIndex(m_writeIndex, sourceLength);
+}
+
+void AudioFIFO::findWrapLengths(size_t index, size_t size, size_t& part1Length, size_t& part2Length)
+{
+ ASSERT(index < m_fifoLength && size <= m_fifoLength);
+ if (index < m_fifoLength && size <= m_fifoLength) {
+ if (index + size > m_fifoLength) {
+ // Need to wrap. Figure out the length of each piece.
+ part1Length = m_fifoLength - index;
+ part2Length = size - part1Length;
+ } else {
+ // No wrap needed.
+ part1Length = size;
+ part2Length = 0;
+ }
+ } else {
+ // Invalid values for index or size. Set the part lengths to zero so nothing is copied.
+ part1Length = 0;
+ part2Length = 0;
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
--- /dev/null
+/*
+ * Copyright (C) 2012 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 AudioFIFO_h
+#define AudioFIFO_h
+
+#include "AudioBus.h"
+
+namespace WebCore {
+
+class AudioFIFO {
+public:
+ // Create a FIFO large enough to hold |fifoLength| frames of data of |numberOfChannels| channels.
+ AudioFIFO(unsigned numberOfChannels, size_t fifoLength);
+
+ // Push the data from the bus into the FIFO.
+ void push(const AudioBus*);
+
+ // Consume |framesToConsume| frames of data from the FIFO and put them in |destination|. The
+ // corresponding frames are removed from the FIFO.
+ void consume(AudioBus* destination, size_t framesToConsume);
+
+ // Number of frames of data that are currently in the FIFO.
+ size_t framesInFifo() const { return m_framesInFifo; }
+
+private:
+ // Update the FIFO index by the step, with appropriate wrapping around the endpoint.
+ int updateIndex(int index, int step) { return (index + step) % m_fifoLength; }
+
+ void findWrapLengths(size_t index, size_t providerSize, size_t& part1Length, size_t& part2Length);
+
+ // The FIFO itself. In reality, the FIFO is a circular buffer.
+ AudioBus m_fifoAudioBus;
+
+ // The total available space in the FIFO.
+ size_t m_fifoLength;
+
+ // The number of actual elements in the FIFO
+ size_t m_framesInFifo;
+
+ // Where to start reading from the FIFO.
+ size_t m_readIndex;
+
+ // Where to start writing to the FIFO.
+ size_t m_writeIndex;
+};
+
+} // namespace WebCore
+
+#endif // AudioFIFO.h
AudioPullFIFO::AudioPullFIFO(AudioSourceProvider& audioProvider, unsigned numberOfChannels, size_t fifoLength, size_t providerSize)
: m_provider(audioProvider)
- , m_fifoAudioBus(numberOfChannels, fifoLength)
- , m_fifoLength(fifoLength)
- , m_framesInFifo(0)
- , m_readIndex(0)
- , m_writeIndex(0)
+ , m_fifo(numberOfChannels, fifoLength)
, m_providerSize(providerSize)
, m_tempBus(numberOfChannels, providerSize)
{
void AudioPullFIFO::consume(AudioBus* destination, size_t framesToConsume)
{
- bool isGood = destination && (framesToConsume <= m_fifoLength);
- ASSERT(isGood);
- if (!isGood)
+ if (!destination)
return;
- if (framesToConsume > m_framesInFifo) {
+ if (framesToConsume > m_fifo.framesInFifo()) {
// We don't have enough data in the FIFO to fulfill the request. Ask for more data.
- fillBuffer(framesToConsume - m_framesInFifo);
+ fillBuffer(framesToConsume - m_fifo.framesInFifo());
}
- // We have enough data now. Copy the requested number of samples to the destination.
-
- size_t part1Length;
- size_t part2Length;
- findWrapLengths(m_readIndex, framesToConsume, part1Length, part2Length);
-
- size_t numberOfChannels = m_fifoAudioBus.numberOfChannels();
-
- for (size_t channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
- float* destinationData = destination->channel(channelIndex)->mutableData();
- const float* sourceData = m_fifoAudioBus.channel(channelIndex)->data();
-
- bool isCopyGood = ((m_readIndex < m_fifoLength)
- && (m_readIndex + part1Length) <= m_fifoLength
- && (part1Length <= destination->length())
- && (part1Length + part2Length) <= destination->length());
- ASSERT(isCopyGood);
- if (!isCopyGood)
- return;
-
- memcpy(destinationData, sourceData + m_readIndex, part1Length * sizeof(*sourceData));
- // Handle wrap around of the FIFO, if needed.
- if (part2Length > 0)
- memcpy(destinationData + part1Length, sourceData, part2Length * sizeof(*sourceData));
- }
- m_readIndex = updateIndex(m_readIndex, framesToConsume);
- m_framesInFifo -= framesToConsume;
- ASSERT(m_framesInFifo >= 0);
-}
-
-void AudioPullFIFO::findWrapLengths(size_t index, size_t size, size_t& part1Length, size_t& part2Length)
-{
- ASSERT(index < m_fifoLength && size <= m_fifoLength);
- if (index < m_fifoLength && size <= m_fifoLength) {
- if (index + size > m_fifoLength) {
- // Need to wrap. Figure out the length of each piece.
- part1Length = m_fifoLength - index;
- part2Length = size - part1Length;
- } else {
- // No wrap needed.
- part1Length = size;
- part2Length = 0;
- }
- } else {
- // Invalid values for index or size. Set the part lengths to zero so nothing is copied.
- part1Length = 0;
- part2Length = 0;
- }
+ m_fifo.consume(destination, framesToConsume);
}
void AudioPullFIFO::fillBuffer(size_t numberOfFrames)
while (framesProvided < numberOfFrames) {
m_provider.provideInput(&m_tempBus, m_providerSize);
- size_t part1Length;
- size_t part2Length;
- findWrapLengths(m_writeIndex, m_providerSize, part1Length, part2Length);
-
- size_t numberOfChannels = m_fifoAudioBus.numberOfChannels();
-
- for (size_t channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
- float* destination = m_fifoAudioBus.channel(channelIndex)->mutableData();
- const float* source = m_tempBus.channel(channelIndex)->data();
-
- bool isCopyGood = (part1Length <= m_providerSize
- && (part1Length + part2Length) <= m_providerSize
- && (m_writeIndex < m_fifoLength)
- && (m_writeIndex + part1Length) <= m_fifoLength
- && part2Length < m_fifoLength);
- ASSERT(isCopyGood);
- if (!isCopyGood)
- return;
-
- memcpy(destination + m_writeIndex, source, part1Length * sizeof(*destination));
- // Handle wrap around of the FIFO, if needed.
- if (part2Length > 0)
- memcpy(destination, source + part1Length, part2Length * sizeof(*destination));
- }
+ m_fifo.push(&m_tempBus);
- m_framesInFifo += m_providerSize;
- ASSERT(m_framesInFifo <= m_fifoLength);
- m_writeIndex = updateIndex(m_writeIndex, m_providerSize);
framesProvided += m_providerSize;
}
}
#define AudioPullFIFO_h
#include "AudioBus.h"
+#include "AudioFIFO.h"
#include "AudioSourceProvider.h"
namespace WebCore {
void consume(AudioBus* destination, size_t framesToConsume);
private:
- // Update the FIFO index by the step, with appropriate wrapping around the endpoint.
- int updateIndex(int index, int step) { return (index + step) % m_fifoLength; }
-
- void findWrapLengths(size_t index, size_t providerSize, size_t& part1Length, size_t& part2Length);
-
// Fill the FIFO buffer with at least |numberOfFrames| more data.
void fillBuffer(size_t numberOfFrames);
// The provider of the data in our FIFO.
AudioSourceProvider& m_provider;
- // The FIFO itself. In reality, the FIFO is a circular buffer.
- AudioBus m_fifoAudioBus;
-
- // The total available space in the FIFO.
- size_t m_fifoLength;
-
- // The number of actual elements in the FIFO
- size_t m_framesInFifo;
-
- // Where to start reading from the FIFO.
- size_t m_readIndex;
-
- // Where to start writing to the FIFO.
- size_t m_writeIndex;
+ // The actual FIFO
+ AudioFIFO m_fifo;
// Number of frames of data that the provider will produce per call.
unsigned int m_providerSize;