OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 16 matching lines...) Expand all Loading... |
27 */ | 27 */ |
28 | 28 |
29 #include "platform/audio/AudioDestination.h" | 29 #include "platform/audio/AudioDestination.h" |
30 | 30 |
31 #include <memory> | 31 #include <memory> |
32 #include "platform/Histogram.h" | 32 #include "platform/Histogram.h" |
33 #include "platform/audio/AudioUtilities.h" | 33 #include "platform/audio/AudioUtilities.h" |
34 #include "platform/audio/PushPullFIFO.h" | 34 #include "platform/audio/PushPullFIFO.h" |
35 #include "platform/weborigin/SecurityOrigin.h" | 35 #include "platform/weborigin/SecurityOrigin.h" |
36 #include "public/platform/Platform.h" | 36 #include "public/platform/Platform.h" |
| 37 #include "public/platform/WebAudioLatencyHint.h" |
37 #include "public/platform/WebSecurityOrigin.h" | 38 #include "public/platform/WebSecurityOrigin.h" |
38 #include "wtf/PtrUtil.h" | 39 #include "wtf/PtrUtil.h" |
39 | 40 |
40 namespace blink { | 41 namespace blink { |
41 | 42 |
42 // FIFO Size. | 43 // FIFO Size. |
43 // | 44 // |
44 // TODO(hongchan): This was estimated based on the largest callback buffer size | 45 // TODO(hongchan): This was estimated based on the largest callback buffer size |
45 // that we would ever need. The current UMA stats indicates that this is, in | 46 // that we would ever need. The current UMA stats indicates that this is, in |
46 // fact, probably too small. There are Android devices out there with a size of | 47 // fact, probably too small. There are Android devices out there with a size of |
47 // 8000 or so. We might need to make this larger. See: crbug.com/670747 | 48 // 8000 or so. We might need to make this larger. See: crbug.com/670747 |
48 const size_t kFIFOSize = 8192; | 49 const size_t kFIFOSize = 8192; |
49 | 50 |
50 std::unique_ptr<AudioDestination> AudioDestination::create( | 51 std::unique_ptr<AudioDestination> AudioDestination::create( |
51 AudioIOCallback& callback, | 52 AudioIOCallback& callback, |
52 unsigned numberOfOutputChannels, | 53 unsigned numberOfOutputChannels, |
53 float sampleRate, | 54 const WebAudioLatencyHint& latencyHint, |
54 PassRefPtr<SecurityOrigin> securityOrigin) { | 55 PassRefPtr<SecurityOrigin> securityOrigin) { |
55 return WTF::wrapUnique(new AudioDestination( | 56 return WTF::wrapUnique(new AudioDestination(callback, numberOfOutputChannels, |
56 callback, numberOfOutputChannels, sampleRate, std::move(securityOrigin))); | 57 latencyHint, |
| 58 std::move(securityOrigin))); |
57 } | 59 } |
58 | 60 |
59 AudioDestination::AudioDestination(AudioIOCallback& callback, | 61 AudioDestination::AudioDestination(AudioIOCallback& callback, |
60 unsigned numberOfOutputChannels, | 62 unsigned numberOfOutputChannels, |
61 float sampleRate, | 63 const WebAudioLatencyHint& latencyHint, |
62 PassRefPtr<SecurityOrigin> securityOrigin) | 64 PassRefPtr<SecurityOrigin> securityOrigin) |
63 : m_numberOfOutputChannels(numberOfOutputChannels), | 65 : m_numberOfOutputChannels(numberOfOutputChannels), |
64 m_sampleRate(sampleRate), | |
65 m_isPlaying(false), | 66 m_isPlaying(false), |
66 m_callback(callback), | 67 m_callback(callback), |
67 m_outputBus(AudioBus::create(numberOfOutputChannels, | 68 m_outputBus(AudioBus::create(numberOfOutputChannels, |
68 AudioUtilities::kRenderQuantumFrames, | 69 AudioUtilities::kRenderQuantumFrames, |
69 false)), | 70 false)), |
70 m_renderBus(AudioBus::create(numberOfOutputChannels, | 71 m_renderBus(AudioBus::create(numberOfOutputChannels, |
71 AudioUtilities::kRenderQuantumFrames)), | 72 AudioUtilities::kRenderQuantumFrames)), |
72 m_framesElapsed(0) { | 73 m_framesElapsed(0) { |
73 // Calculate the optimum buffer size first. | 74 // Create WebAudioDevice. blink::WebAudioDevice is designed to support the |
74 if (calculateBufferSize()) { | 75 // local input (e.g. loopback from OS audio system), but Chromium's media |
75 // Create WebAudioDevice. blink::WebAudioDevice is designed to support the | 76 // renderer does not support it currently. Thus, we use zero for the number |
76 // local input (e.g. loopback from OS audio system), but Chromium's media | 77 // of input channels. |
77 // renderer does not support it currently. Thus, we use zero for the number | 78 m_webAudioDevice = WTF::wrapUnique(Platform::current()->createAudioDevice( |
78 // of input channels. | 79 0, numberOfOutputChannels, latencyHint, this, String(), |
79 m_webAudioDevice = WTF::wrapUnique(Platform::current()->createAudioDevice( | 80 std::move(securityOrigin))); |
80 m_callbackBufferSize, 0, numberOfOutputChannels, sampleRate, this, | 81 DCHECK(m_webAudioDevice); |
81 String(), std::move(securityOrigin))); | |
82 DCHECK(m_webAudioDevice); | |
83 | 82 |
84 // Create a FIFO. | 83 m_callbackBufferSize = m_webAudioDevice->framesPerBuffer(); |
85 m_fifo = | 84 |
86 WTF::wrapUnique(new PushPullFIFO(numberOfOutputChannels, kFIFOSize)); | 85 if (!checkBufferSize()) { |
87 } else { | |
88 NOTREACHED(); | 86 NOTREACHED(); |
89 } | 87 } |
| 88 |
| 89 // Create a FIFO. |
| 90 m_fifo = WTF::wrapUnique(new PushPullFIFO(numberOfOutputChannels, kFIFOSize)); |
90 } | 91 } |
91 | 92 |
92 AudioDestination::~AudioDestination() { | 93 AudioDestination::~AudioDestination() { |
93 stop(); | 94 stop(); |
94 } | 95 } |
95 | 96 |
96 void AudioDestination::render(const WebVector<float*>& destinationData, | 97 void AudioDestination::render(const WebVector<float*>& destinationData, |
97 size_t numberOfFrames, | 98 size_t numberOfFrames, |
98 double delay, | 99 double delay, |
99 double delayTimestamp, | 100 double delayTimestamp, |
100 size_t priorFramesSkipped) { | 101 size_t priorFramesSkipped) { |
101 CHECK_EQ(destinationData.size(), m_numberOfOutputChannels); | 102 CHECK_EQ(destinationData.size(), m_numberOfOutputChannels); |
102 CHECK_EQ(numberOfFrames, m_callbackBufferSize); | 103 CHECK_EQ(numberOfFrames, m_callbackBufferSize); |
103 | 104 |
104 m_framesElapsed -= std::min(m_framesElapsed, priorFramesSkipped); | 105 m_framesElapsed -= std::min(m_framesElapsed, priorFramesSkipped); |
105 double outputPosition = | 106 double outputPosition = |
106 m_framesElapsed / static_cast<double>(m_sampleRate) - delay; | 107 m_framesElapsed / static_cast<double>(m_webAudioDevice->sampleRate()) - |
| 108 delay; |
107 m_outputPosition.position = outputPosition; | 109 m_outputPosition.position = outputPosition; |
108 m_outputPosition.timestamp = delayTimestamp; | 110 m_outputPosition.timestamp = delayTimestamp; |
109 m_outputPositionReceivedTimestamp = base::TimeTicks::Now(); | 111 m_outputPositionReceivedTimestamp = base::TimeTicks::Now(); |
110 | 112 |
111 // Associate the destination data array with the output bus then fill the | 113 // Associate the destination data array with the output bus then fill the |
112 // FIFO. | 114 // FIFO. |
113 for (unsigned i = 0; i < m_numberOfOutputChannels; ++i) | 115 for (unsigned i = 0; i < m_numberOfOutputChannels; ++i) |
114 m_outputBus->setChannelMemory(i, destinationData[i], numberOfFrames); | 116 m_outputBus->setChannelMemory(i, destinationData[i], numberOfFrames); |
115 | 117 |
116 // Number of frames to render via WebAudio graph. |framesToRender > 0| means | 118 // Number of frames to render via WebAudio graph. |framesToRender > 0| means |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 | 171 |
170 float AudioDestination::hardwareSampleRate() { | 172 float AudioDestination::hardwareSampleRate() { |
171 return static_cast<float>(Platform::current()->audioHardwareSampleRate()); | 173 return static_cast<float>(Platform::current()->audioHardwareSampleRate()); |
172 } | 174 } |
173 | 175 |
174 unsigned long AudioDestination::maxChannelCount() { | 176 unsigned long AudioDestination::maxChannelCount() { |
175 return static_cast<unsigned long>( | 177 return static_cast<unsigned long>( |
176 Platform::current()->audioHardwareOutputChannels()); | 178 Platform::current()->audioHardwareOutputChannels()); |
177 } | 179 } |
178 | 180 |
179 bool AudioDestination::calculateBufferSize() { | 181 bool AudioDestination::checkBufferSize() { |
180 // Use the optimal buffer size recommended by the audio backend. | |
181 size_t recommendedHardwareBufferSize = hardwareBufferSize(); | |
182 m_callbackBufferSize = recommendedHardwareBufferSize; | |
183 | |
184 #if OS(ANDROID) | |
185 // The optimum low-latency hardware buffer size is usually too small on | |
186 // Android for WebAudio to render without glitching. So, if it is small, use a | |
187 // larger size. If it was already large, use the requested size. | |
188 // | |
189 // Since WebAudio renders in 128-frame blocks, the small buffer sizes (144 for | |
190 // a Galaxy Nexus), cause significant processing jitter. Sometimes multiple | |
191 // blocks will processed, but other times will not be since the FIFO can | |
192 // satisfy the request. By using a larger callbackBufferSize, we smooth out | |
193 // the jitter. | |
194 const size_t kSmallBufferSize = 1024; | |
195 const size_t kDefaultCallbackBufferSize = 2048; | |
196 | |
197 if (m_callbackBufferSize <= kSmallBufferSize) | |
198 m_callbackBufferSize = kDefaultCallbackBufferSize; | |
199 | |
200 LOG(INFO) << "audioHardwareBufferSize = " << recommendedHardwareBufferSize; | |
201 LOG(INFO) << "callbackBufferSize = " << m_callbackBufferSize; | |
202 #endif | |
203 | |
204 // Histogram for audioHardwareBufferSize | 182 // Histogram for audioHardwareBufferSize |
205 DEFINE_STATIC_LOCAL(SparseHistogram, hardwareBufferSizeHistogram, | 183 DEFINE_STATIC_LOCAL(SparseHistogram, hardwareBufferSizeHistogram, |
206 ("WebAudio.AudioDestination.HardwareBufferSize")); | 184 ("WebAudio.AudioDestination.HardwareBufferSize")); |
207 | 185 |
208 // Histogram for the actual callback size used. Typically, this is the same | 186 // Histogram for the actual callback size used. Typically, this is the same |
209 // as audioHardwareBufferSize, but can be adjusted depending on some | 187 // as audioHardwareBufferSize, but can be adjusted depending on some |
210 // heuristics below. | 188 // heuristics below. |
211 DEFINE_STATIC_LOCAL(SparseHistogram, callbackBufferSizeHistogram, | 189 DEFINE_STATIC_LOCAL(SparseHistogram, callbackBufferSizeHistogram, |
212 ("WebAudio.AudioDestination.CallbackBufferSize")); | 190 ("WebAudio.AudioDestination.CallbackBufferSize")); |
213 | 191 |
214 // Record the sizes if we successfully created an output device. | 192 // Record the sizes if we successfully created an output device. |
215 hardwareBufferSizeHistogram.sample(recommendedHardwareBufferSize); | 193 hardwareBufferSizeHistogram.sample(hardwareBufferSize()); |
216 callbackBufferSizeHistogram.sample(m_callbackBufferSize); | 194 callbackBufferSizeHistogram.sample(m_callbackBufferSize); |
217 | 195 |
218 // Check if the requested buffer size is too large. | 196 // Check if the requested buffer size is too large. |
219 bool isBufferSizeValid = | 197 bool isBufferSizeValid = |
220 m_callbackBufferSize + AudioUtilities::kRenderQuantumFrames <= kFIFOSize; | 198 m_callbackBufferSize + AudioUtilities::kRenderQuantumFrames <= kFIFOSize; |
221 DCHECK(isBufferSizeValid); | 199 DCHECK(isBufferSizeValid); |
222 return isBufferSizeValid; | 200 return isBufferSizeValid; |
223 } | 201 } |
224 | 202 |
225 } // namespace blink | 203 } // namespace blink |
OLD | NEW |