OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "platform/audio/PushPullFIFO.h" | 5 #include "platform/audio/PushPullFIFO.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include "platform/audio/AudioUtilities.h" | 8 #include "platform/audio/AudioUtilities.h" |
9 #include "platform/wtf/PtrUtil.h" | 9 #include "platform/wtf/PtrUtil.h" |
10 | 10 |
11 namespace blink { | 11 namespace blink { |
12 | 12 |
13 namespace { | 13 namespace { |
14 | 14 |
15 // Suppress the warning log if over/underflow happens more than 100 times. | 15 // Suppress the warning log if over/underflow happens more than 100 times. |
16 const unsigned kMaxMessagesToLog = 100; | 16 const unsigned kMaxMessagesToLog = 100; |
17 } | 17 } |
18 | 18 |
19 const size_t PushPullFIFO::kMaxFIFOLength = 65536; | 19 const size_t PushPullFIFO::kMaxFIFOLength = 65536; |
20 | 20 |
21 PushPullFIFO::PushPullFIFO(unsigned number_of_channels, size_t fifo_length) | 21 PushPullFIFO::PushPullFIFO(unsigned number_of_channels, |
22 : fifo_length_(fifo_length), | 22 size_t fifo_length, |
23 ThreadIdentifier rendering_thread_id, | |
24 AudioIOCallback& web_audio_render_callback) | |
25 : rendering_thread_id_(rendering_thread_id), | |
o1ka
2017/04/13 08:36:53
This is too much information for a FIFO.
Also, we
hongchan
2017/04/14 16:31:48
Done.
| |
26 web_audio_render_callback_(web_audio_render_callback), | |
27 fifo_length_(fifo_length), | |
23 frames_available_(0), | 28 frames_available_(0), |
24 index_read_(0), | 29 index_read_(0), |
25 index_write_(0), | 30 index_write_(0), |
26 overflow_count_(0), | 31 overflow_count_(0), |
27 underflow_count_(0) { | 32 underflow_count_(0) { |
28 CHECK_LE(fifo_length_, kMaxFIFOLength); | 33 CHECK_LE(fifo_length_, kMaxFIFOLength); |
29 fifo_bus_ = AudioBus::Create(number_of_channels, fifo_length_); | 34 fifo_bus_ = AudioBus::Create(number_of_channels, fifo_length_); |
35 render_bus_ = AudioBus::Create(number_of_channels, | |
36 AudioUtilities::kRenderQuantumFrames); | |
30 } | 37 } |
31 | 38 |
32 PushPullFIFO::~PushPullFIFO() {} | 39 PushPullFIFO::~PushPullFIFO() {} |
33 | 40 |
34 // Push the data from |inputBus| to FIFO. The size of push is determined by | 41 void PushPullFIFO::FillRequestedFrames(size_t frames_requested, |
35 // the length of |inputBus|. | 42 size_t callback_buffer_size, |
36 void PushPullFIFO::Push(const AudioBus* input_bus) { | 43 AudioIOPosition output_position) { |
37 CHECK(input_bus); | 44 DCHECK(IsRenderingThread()); |
38 CHECK_EQ(input_bus->length(), AudioUtilities::kRenderQuantumFrames); | |
39 SECURITY_CHECK(input_bus->length() <= fifo_length_); | |
40 SECURITY_CHECK(index_write_ < fifo_length_); | |
41 | 45 |
42 const size_t input_bus_length = input_bus->length(); | 46 MutexLocker lock(lock_); |
43 const size_t remainder = fifo_length_ - index_write_; | |
44 | 47 |
45 for (unsigned i = 0; i < fifo_bus_->NumberOfChannels(); ++i) { | 48 base::TimeTicks output_position_received_timestamp = base::TimeTicks::Now(); |
46 float* fifo_bus_channel = fifo_bus_->Channel(i)->MutableData(); | 49 |
47 const float* input_bus_channel = input_bus->Channel(i)->Data(); | 50 size_t frames_to_render = frames_requested > frames_available_ |
48 if (remainder >= input_bus_length) { | 51 ? frames_requested - frames_available_ |
49 // The remainder is big enough for the input data. | 52 : 0; |
50 memcpy(fifo_bus_channel + index_write_, input_bus_channel, | 53 |
51 input_bus_length * sizeof(*fifo_bus_channel)); | 54 for (size_t pushed_frames = 0; pushed_frames < frames_to_render; |
52 } else { | 55 pushed_frames += AudioUtilities::kRenderQuantumFrames) { |
53 // The input data overflows the remainder size. Wrap around the index. | 56 // If platform buffer is more than two times longer than |framesToProcess| |
54 memcpy(fifo_bus_channel + index_write_, input_bus_channel, | 57 // we do not want output position to get stuck so we promote it |
55 remainder * sizeof(*fifo_bus_channel)); | 58 // using the elapsed time from the moment it was initially obtained. |
56 memcpy(fifo_bus_channel, input_bus_channel + remainder, | 59 if (callback_buffer_size > AudioUtilities::kRenderQuantumFrames * 2) { |
57 (input_bus_length - remainder) * sizeof(*fifo_bus_channel)); | 60 double delta = |
61 (base::TimeTicks::Now() - output_position_received_timestamp) | |
62 .InSecondsF(); | |
63 output_position.position += delta; | |
64 output_position.timestamp += delta; | |
58 } | 65 } |
66 | |
67 // Some implementations give only rough estimation of |delay| so | |
68 // we might have negative estimation |outputPosition| value. | |
69 if (output_position.position < 0.0) | |
70 output_position.position = 0.0; | |
71 | |
72 // Process WebAudio graph and push the rendered output to FIFO. | |
73 web_audio_render_callback_.Render(nullptr, | |
74 render_bus_.Get(), | |
75 AudioUtilities::kRenderQuantumFrames, | |
76 output_position); | |
77 Push(render_bus_.Get()); | |
59 } | 78 } |
60 | |
61 // Update the write index; wrap it around if necessary. | |
62 index_write_ = (index_write_ + input_bus_length) % fifo_length_; | |
63 | |
64 // In case of overflow, move the |indexRead| to the updated |indexWrite| to | |
65 // avoid reading overwritten frames by the next pull. | |
66 if (input_bus_length > fifo_length_ - frames_available_) { | |
67 index_read_ = index_write_; | |
68 if (++overflow_count_ < kMaxMessagesToLog) { | |
69 LOG(WARNING) << "PushPullFIFO: overflow while pushing (" | |
70 << "overflowCount=" << overflow_count_ | |
71 << ", availableFrames=" << frames_available_ | |
72 << ", inputFrames=" << input_bus_length | |
73 << ", fifoLength=" << fifo_length_ << ")"; | |
74 } | |
75 } | |
76 | |
77 // Update the number of frames available in FIFO. | |
78 frames_available_ = | |
79 std::min(frames_available_ + input_bus_length, fifo_length_); | |
80 DCHECK_EQ((index_read_ + frames_available_) % fifo_length_, index_write_); | |
81 } | 79 } |
82 | 80 |
83 // Pull the data out of FIFO to |outputBus|. If remaining frame in the FIFO | 81 // Pull the data out of FIFO to |outputBus|. If remaining frame in the FIFO |
84 // is less than the frames to pull, provides remaining frame plus the silence. | 82 // is less than the frames to pull, provides remaining frame plus the silence. |
85 void PushPullFIFO::Pull(AudioBus* output_bus, size_t frames_requested) { | 83 void PushPullFIFO::Pull(AudioBus* output_bus, size_t frames_requested) { |
84 // This runs on audio device thread. | |
85 DCHECK(!IsRenderingThread()); | |
86 | |
87 MutexLocker lock(lock_); | |
88 | |
86 #if OS(ANDROID) | 89 #if OS(ANDROID) |
87 if (!output_bus) { | 90 if (!output_bus) { |
88 // Log when outputBus or FIFO object is invalid. (crbug.com/692423) | 91 // Log when outputBus or FIFO object is invalid. (crbug.com/692423) |
89 LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) | 92 LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) |
90 << ">] |outputBus| is invalid."; | 93 << ">] |outputBus| is invalid."; |
91 // Silently return to avoid crash. | 94 // Silently return to avoid crash. |
92 return; | 95 return; |
93 } | 96 } |
94 | 97 |
95 // The following checks are in place to catch the inexplicable crash. | 98 // The following checks are in place to catch the inexplicable crash. |
96 // (crbug.com/692423) | 99 // (crbug.com/692423) |
97 if (frames_requested > output_bus->length()) { | 100 if (frames_requested > output_bus->length()) { |
98 LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) | 101 LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) |
99 << ">] framesRequested > outputBus->length() (" | 102 << ">] framesRequested > outputBus->length() (" |
100 << frames_requested << " > " << output_bus->length() << ")"; | 103 << frames_requested << " > " << output_bus->length() << ")"; |
101 } | 104 } |
102 if (frames_requested > fifo_length_) { | 105 if (frames_requested > fifo_length_) { |
103 LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) | 106 LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) |
104 << ">] framesRequested > m_fifoLength (" << frames_requested | 107 << ">] framesRequested > m_fifoLength (" << frames_requested |
105 << " > " << fifo_length_ << ")"; | 108 << " > " << fifo_length_ << ")"; |
106 } | 109 } |
107 if (index_read_ >= fifo_length_) { | 110 if (index_read_ >= fifo_length_) { |
108 LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) | 111 LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) |
109 << ">] m_indexRead >= m_fifoLength (" << index_read_ | 112 << ">] m_indexRead >= m_fifoLength (" << index_read_ |
110 << " >= " << fifo_length_ << ")"; | 113 << " >= " << fifo_length_ << ")"; |
111 } | 114 } |
112 #endif | 115 #endif |
116 | |
113 CHECK(output_bus); | 117 CHECK(output_bus); |
114 SECURITY_CHECK(frames_requested <= output_bus->length()); | 118 SECURITY_CHECK(frames_requested <= output_bus->length()); |
115 SECURITY_CHECK(frames_requested <= fifo_length_); | 119 SECURITY_CHECK(frames_requested <= fifo_length_); |
116 SECURITY_CHECK(index_read_ < fifo_length_); | 120 SECURITY_CHECK(index_read_ < fifo_length_); |
117 | 121 |
118 const size_t remainder = fifo_length_ - index_read_; | 122 const size_t remainder = fifo_length_ - index_read_; |
119 const size_t frames_to_fill = std::min(frames_available_, frames_requested); | 123 const size_t frames_to_fill = std::min(frames_available_, frames_requested); |
120 | 124 |
121 for (unsigned i = 0; i < fifo_bus_->NumberOfChannels(); ++i) { | 125 for (unsigned i = 0; i < fifo_bus_->NumberOfChannels(); ++i) { |
122 const float* fifo_bus_channel = fifo_bus_->Channel(i)->Data(); | 126 const float* fifo_bus_channel = fifo_bus_->Channel(i)->Data(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
157 << ", requestedFrames=" << frames_requested | 161 << ", requestedFrames=" << frames_requested |
158 << ", fifoLength=" << fifo_length_ << ")"; | 162 << ", fifoLength=" << fifo_length_ << ")"; |
159 } | 163 } |
160 } | 164 } |
161 | 165 |
162 // Update the number of frames in FIFO. | 166 // Update the number of frames in FIFO. |
163 frames_available_ -= frames_to_fill; | 167 frames_available_ -= frames_to_fill; |
164 DCHECK_EQ((index_read_ + frames_available_) % fifo_length_, index_write_); | 168 DCHECK_EQ((index_read_ + frames_available_) % fifo_length_, index_write_); |
165 } | 169 } |
166 | 170 |
171 AudioBus* PushPullFIFO::GetFIFOBusForTest() const { | |
172 MutexLocker lock(lock_); | |
173 return fifo_bus_.Get(); | |
174 } | |
175 | |
167 const PushPullFIFOStateForTest PushPullFIFO::GetStateForTest() const { | 176 const PushPullFIFOStateForTest PushPullFIFO::GetStateForTest() const { |
168 return {length(), NumberOfChannels(), FramesAvailable(), index_read_, | 177 return {length(), NumberOfChannels(), frames_available_, index_read_, |
169 index_write_, overflow_count_, underflow_count_}; | 178 index_write_, overflow_count_, underflow_count_}; |
179 | |
180 } | |
181 | |
182 bool PushPullFIFO::IsRenderingThread() { | |
183 return rendering_thread_id_ == CurrentThread(); | |
184 } | |
185 | |
186 // Push the data from |inputBus| to FIFO. The size of push is determined by | |
187 // the length of |inputBus|. | |
188 void PushPullFIFO::Push(const AudioBus* input_bus) { | |
189 // This runs on WebAudio rendering thread. | |
190 DCHECK(IsRenderingThread()); | |
191 | |
192 CHECK(input_bus); | |
193 CHECK_EQ(input_bus->length(), AudioUtilities::kRenderQuantumFrames); | |
194 SECURITY_CHECK(input_bus->length() <= fifo_length_); | |
195 SECURITY_CHECK(index_write_ < fifo_length_); | |
196 | |
197 const size_t input_bus_length = input_bus->length(); | |
198 const size_t remainder = fifo_length_ - index_write_; | |
199 | |
200 for (unsigned i = 0; i < fifo_bus_->NumberOfChannels(); ++i) { | |
201 float* fifo_bus_channel = fifo_bus_->Channel(i)->MutableData(); | |
202 const float* input_bus_channel = input_bus->Channel(i)->Data(); | |
203 if (remainder >= input_bus_length) { | |
204 // The remainder is big enough for the input data. | |
205 memcpy(fifo_bus_channel + index_write_, input_bus_channel, | |
206 input_bus_length * sizeof(*fifo_bus_channel)); | |
207 } else { | |
208 // The input data overflows the remainder size. Wrap around the index. | |
209 memcpy(fifo_bus_channel + index_write_, input_bus_channel, | |
210 remainder * sizeof(*fifo_bus_channel)); | |
211 memcpy(fifo_bus_channel, input_bus_channel + remainder, | |
212 (input_bus_length - remainder) * sizeof(*fifo_bus_channel)); | |
213 } | |
214 } | |
215 | |
216 // Update the write index; wrap it around if necessary. | |
217 index_write_ = (index_write_ + input_bus_length) % fifo_length_; | |
218 | |
219 // In case of overflow, move the |indexRead| to the updated |indexWrite| to | |
220 // avoid reading overwritten frames by the next pull. | |
221 if (input_bus_length > fifo_length_ - frames_available_) { | |
222 index_read_ = index_write_; | |
223 if (++overflow_count_ < kMaxMessagesToLog) { | |
224 LOG(WARNING) << "PushPullFIFO: overflow while pushing (" | |
225 << "overflowCount=" << overflow_count_ | |
226 << ", availableFrames=" << frames_available_ | |
227 << ", inputFrames=" << input_bus_length | |
228 << ", fifoLength=" << fifo_length_ << ")"; | |
229 } | |
230 } | |
231 | |
232 // Update the number of frames available in FIFO. | |
233 frames_available_ = | |
234 std::min(frames_available_ + input_bus_length, fifo_length_); | |
235 DCHECK_EQ((index_read_ + frames_available_) % fifo_length_, index_write_); | |
170 } | 236 } |
171 | 237 |
172 } // namespace blink | 238 } // namespace blink |
OLD | NEW |