1 | /* |
2 | * Copyright (C) 2012 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 | * |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
14 | * its contributors may be used to endorse or promote products derived |
15 | * from this software without specific prior written permission. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include "config.h" |
30 | |
31 | #if ENABLE(WEB_AUDIO) |
32 | |
33 | #include "AudioFIFO.h" |
34 | |
35 | namespace WebCore { |
36 | |
37 | AudioFIFO::AudioFIFO(unsigned numberOfChannels, size_t fifoLength) |
38 | : m_fifoAudioBus(AudioBus::create(numberOfChannels, fifoLength)) |
39 | , m_fifoLength(fifoLength) |
40 | , m_framesInFifo(0) |
41 | , m_readIndex(0) |
42 | , m_writeIndex(0) |
43 | { |
44 | } |
45 | |
46 | void AudioFIFO::consume(AudioBus* destination, size_t framesToConsume) |
47 | { |
48 | bool isGood = destination && (framesToConsume <= m_fifoLength) && (framesToConsume <= m_framesInFifo) && (destination->length() >= framesToConsume); |
49 | ASSERT(isGood); |
50 | if (!isGood) |
51 | return; |
52 | |
53 | // Copy the requested number of samples to the destination. |
54 | |
55 | size_t part1Length; |
56 | size_t part2Length; |
57 | findWrapLengths(m_readIndex, framesToConsume, part1Length, part2Length); |
58 | |
59 | size_t numberOfChannels = m_fifoAudioBus->numberOfChannels(); |
60 | |
61 | for (size_t channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) { |
62 | float* destinationData = destination->channel(channelIndex)->mutableData(); |
63 | const float* sourceData = m_fifoAudioBus->channel(channelIndex)->data(); |
64 | |
65 | bool isCopyGood = ((m_readIndex < m_fifoLength) |
66 | && (m_readIndex + part1Length) <= m_fifoLength |
67 | && (part1Length <= destination->length()) |
68 | && (part1Length + part2Length) <= destination->length()); |
69 | ASSERT(isCopyGood); |
70 | if (!isCopyGood) |
71 | return; |
72 | |
73 | memcpy(destinationData, sourceData + m_readIndex, part1Length * sizeof(*sourceData)); |
74 | // Handle wrap around of the FIFO, if needed. |
75 | if (part2Length) |
76 | memcpy(destinationData + part1Length, sourceData, part2Length * sizeof(*sourceData)); |
77 | } |
78 | m_readIndex = updateIndex(m_readIndex, framesToConsume); |
79 | ASSERT(m_framesInFifo >= framesToConsume); |
80 | m_framesInFifo -= framesToConsume; |
81 | } |
82 | |
83 | void AudioFIFO::push(const AudioBus* sourceBus) |
84 | { |
85 | // Copy the sourceBus into the FIFO buffer. |
86 | |
87 | bool isGood = sourceBus && (m_framesInFifo + sourceBus->length() <= m_fifoLength); |
88 | if (!isGood) |
89 | return; |
90 | |
91 | size_t sourceLength = sourceBus->length(); |
92 | size_t part1Length; |
93 | size_t part2Length; |
94 | findWrapLengths(m_writeIndex, sourceLength, part1Length, part2Length); |
95 | |
96 | size_t numberOfChannels = m_fifoAudioBus->numberOfChannels(); |
97 | |
98 | for (size_t channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) { |
99 | float* destination = m_fifoAudioBus->channel(channelIndex)->mutableData(); |
100 | const float* source = sourceBus->channel(channelIndex)->data(); |
101 | |
102 | bool isCopyGood = ((m_writeIndex < m_fifoLength) |
103 | && (m_writeIndex + part1Length) <= m_fifoLength |
104 | && part2Length < m_fifoLength |
105 | && part1Length + part2Length <= sourceLength); |
106 | ASSERT(isCopyGood); |
107 | if (!isCopyGood) |
108 | return; |
109 | |
110 | memcpy(destination + m_writeIndex, source, part1Length * sizeof(*destination)); |
111 | |
112 | // Handle wrap around of the FIFO, if needed. |
113 | if (part2Length) |
114 | memcpy(destination, source + part1Length, part2Length * sizeof(*destination)); |
115 | } |
116 | |
117 | m_framesInFifo += sourceLength; |
118 | ASSERT(m_framesInFifo <= m_fifoLength); |
119 | m_writeIndex = updateIndex(m_writeIndex, sourceLength); |
120 | } |
121 | |
122 | void AudioFIFO::findWrapLengths(size_t index, size_t size, size_t& part1Length, size_t& part2Length) |
123 | { |
124 | ASSERT_WITH_SECURITY_IMPLICATION(index < m_fifoLength && size <= m_fifoLength); |
125 | if (index < m_fifoLength && size <= m_fifoLength) { |
126 | if (index + size > m_fifoLength) { |
127 | // Need to wrap. Figure out the length of each piece. |
128 | part1Length = m_fifoLength - index; |
129 | part2Length = size - part1Length; |
130 | } else { |
131 | // No wrap needed. |
132 | part1Length = size; |
133 | part2Length = 0; |
134 | } |
135 | } else { |
136 | // Invalid values for index or size. Set the part lengths to zero so nothing is copied. |
137 | part1Length = 0; |
138 | part2Length = 0; |
139 | } |
140 | } |
141 | |
142 | } // namespace WebCore |
143 | |
144 | #endif // ENABLE(WEB_AUDIO) |
145 | |