OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "media/base/audio_renderer_mixer.h" | 5 #include "media/base/audio_renderer_mixer.h" |
6 | 6 |
| 7 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) |
| 8 #include <xmmintrin.h> |
| 9 #endif |
| 10 |
7 #include "base/bind.h" | 11 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
| 13 #include "base/cpu.h" |
9 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/memory/aligned_memory.h" |
10 #include "media/audio/audio_util.h" | 16 #include "media/audio/audio_util.h" |
11 #include "media/base/limits.h" | 17 #include "media/base/limits.h" |
12 | 18 |
13 namespace media { | 19 namespace media { |
14 | 20 |
15 AudioRendererMixer::AudioRendererMixer( | 21 AudioRendererMixer::AudioRendererMixer( |
16 const AudioParameters& input_params, const AudioParameters& output_params, | 22 const AudioParameters& input_params, const AudioParameters& output_params, |
17 const scoped_refptr<AudioRendererSink>& sink) | 23 const scoped_refptr<AudioRendererSink>& sink) |
18 : audio_sink_(sink), | 24 : audio_sink_(sink), |
19 current_audio_delay_milliseconds_(0) { | 25 current_audio_delay_milliseconds_(0) { |
(...skipping 15 matching lines...) Expand all Loading... |
35 audio_sink_->Initialize(output_params, this); | 41 audio_sink_->Initialize(output_params, this); |
36 audio_sink_->Start(); | 42 audio_sink_->Start(); |
37 } | 43 } |
38 | 44 |
39 AudioRendererMixer::~AudioRendererMixer() { | 45 AudioRendererMixer::~AudioRendererMixer() { |
40 // AudioRendererSinks must be stopped before being destructed. | 46 // AudioRendererSinks must be stopped before being destructed. |
41 audio_sink_->Stop(); | 47 audio_sink_->Stop(); |
42 | 48 |
43 // Clean up |mixer_input_audio_data_|. | 49 // Clean up |mixer_input_audio_data_|. |
44 for (size_t i = 0; i < mixer_input_audio_data_.size(); ++i) | 50 for (size_t i = 0; i < mixer_input_audio_data_.size(); ++i) |
45 delete [] mixer_input_audio_data_[i]; | 51 base::AlignedFree(mixer_input_audio_data_[i]); |
46 mixer_input_audio_data_.clear(); | 52 mixer_input_audio_data_.clear(); |
47 | 53 |
48 // Ensures that all mixer inputs have stopped themselves prior to destruction | 54 // Ensures that all mixer inputs have stopped themselves prior to destruction |
49 // and have called RemoveMixerInput(). | 55 // and have called RemoveMixerInput(). |
50 DCHECK_EQ(mixer_inputs_.size(), 0U); | 56 DCHECK_EQ(mixer_inputs_.size(), 0U); |
51 } | 57 } |
52 | 58 |
53 void AudioRendererMixer::AddMixerInput( | 59 void AudioRendererMixer::AddMixerInput( |
54 const scoped_refptr<AudioRendererMixerInput>& input) { | 60 const scoped_refptr<AudioRendererMixerInput>& input) { |
55 base::AutoLock auto_lock(mixer_inputs_lock_); | 61 base::AutoLock auto_lock(mixer_inputs_lock_); |
(...skipping 21 matching lines...) Expand all Loading... |
77 return number_of_frames; | 83 return number_of_frames; |
78 } | 84 } |
79 | 85 |
80 void AudioRendererMixer::ProvideInput(const std::vector<float*>& audio_data, | 86 void AudioRendererMixer::ProvideInput(const std::vector<float*>& audio_data, |
81 int number_of_frames) { | 87 int number_of_frames) { |
82 base::AutoLock auto_lock(mixer_inputs_lock_); | 88 base::AutoLock auto_lock(mixer_inputs_lock_); |
83 | 89 |
84 // Allocate staging area for each mixer input's audio data on first call. We | 90 // Allocate staging area for each mixer input's audio data on first call. We |
85 // won't know how much to allocate until here because of resampling. | 91 // won't know how much to allocate until here because of resampling. |
86 if (mixer_input_audio_data_.size() == 0) { | 92 if (mixer_input_audio_data_.size() == 0) { |
87 // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to | |
88 // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes. | |
89 mixer_input_audio_data_.reserve(audio_data.size()); | 93 mixer_input_audio_data_.reserve(audio_data.size()); |
90 for (size_t i = 0; i < audio_data.size(); ++i) | 94 for (size_t i = 0; i < audio_data.size(); ++i) { |
91 mixer_input_audio_data_.push_back(new float[number_of_frames]); | 95 // Allocate audio data with a 16-byte alignment for SSE optimizations. |
| 96 mixer_input_audio_data_.push_back(static_cast<float*>( |
| 97 base::AlignedAlloc(sizeof(float) * number_of_frames, 16))); |
| 98 } |
92 mixer_input_audio_data_size_ = number_of_frames; | 99 mixer_input_audio_data_size_ = number_of_frames; |
93 } | 100 } |
94 | 101 |
95 // Sanity check our inputs. | 102 // Sanity check our inputs. |
96 DCHECK_LE(number_of_frames, mixer_input_audio_data_size_); | 103 DCHECK_LE(number_of_frames, mixer_input_audio_data_size_); |
97 DCHECK_EQ(audio_data.size(), mixer_input_audio_data_.size()); | 104 DCHECK_EQ(audio_data.size(), mixer_input_audio_data_.size()); |
98 | 105 |
99 // Zero |audio_data| so we're mixing into a clean buffer and return silence if | 106 // Zero |audio_data| so we're mixing into a clean buffer and return silence if |
100 // we couldn't get enough data from our inputs. | 107 // we couldn't get enough data from our inputs. |
101 for (size_t i = 0; i < audio_data.size(); ++i) | 108 for (size_t i = 0; i < audio_data.size(); ++i) |
(...skipping 11 matching lines...) Expand all Loading... |
113 if (!input->playing()) | 120 if (!input->playing()) |
114 continue; | 121 continue; |
115 | 122 |
116 int frames_filled = input->callback()->Render( | 123 int frames_filled = input->callback()->Render( |
117 mixer_input_audio_data_, number_of_frames, | 124 mixer_input_audio_data_, number_of_frames, |
118 current_audio_delay_milliseconds_); | 125 current_audio_delay_milliseconds_); |
119 if (frames_filled == 0) | 126 if (frames_filled == 0) |
120 continue; | 127 continue; |
121 | 128 |
122 // Volume adjust and mix each mixer input into |audio_data| after rendering. | 129 // Volume adjust and mix each mixer input into |audio_data| after rendering. |
123 // TODO(dalecurtis): Optimize with NEON/SSE/AVX vector_fmac from FFmpeg. | |
124 for (size_t j = 0; j < audio_data.size(); ++j) { | 130 for (size_t j = 0; j < audio_data.size(); ++j) { |
125 float* dest = audio_data[j]; | 131 VectorFMAC( |
126 float* source = mixer_input_audio_data_[j]; | 132 mixer_input_audio_data_[j], volume, frames_filled, audio_data[j]); |
127 for (int k = 0; k < frames_filled; ++k) | |
128 dest[k] += source[k] * static_cast<float>(volume); | |
129 } | 133 } |
130 | 134 |
131 // No need to clamp values as InterleaveFloatToInt() will take care of this | 135 // No need to clamp values as InterleaveFloatToInt() will take care of this |
132 // for us later when data is transferred to the browser process. | 136 // for us later when data is transferred to the browser process. |
133 } | 137 } |
134 } | 138 } |
135 | 139 |
136 void AudioRendererMixer::OnRenderError() { | 140 void AudioRendererMixer::OnRenderError() { |
137 base::AutoLock auto_lock(mixer_inputs_lock_); | 141 base::AutoLock auto_lock(mixer_inputs_lock_); |
138 | 142 |
139 // Call each mixer input and signal an error. | 143 // Call each mixer input and signal an error. |
140 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin(); | 144 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin(); |
141 it != mixer_inputs_.end(); ++it) { | 145 it != mixer_inputs_.end(); ++it) { |
142 (*it)->callback()->OnRenderError(); | 146 (*it)->callback()->OnRenderError(); |
143 } | 147 } |
144 } | 148 } |
145 | 149 |
| 150 void AudioRendererMixer::VectorFMAC(const float src[], float scale, int len, |
| 151 float dest[]) { |
| 152 // Rely on function level static initialization to keep VectorFMACProc |
| 153 // selection thread safe. |
| 154 typedef void (*VectorFMACProc)(const float src[], float scale, int len, |
| 155 float dest[]); |
| 156 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) |
| 157 static const VectorFMACProc kVectorFMACProc = |
| 158 base::CPU().has_sse() ? VectorFMAC_SSE : VectorFMAC_C; |
| 159 #else |
| 160 static const VectorFMACProc kVectorFMACProc = VectorFMAC_C; |
| 161 #endif |
| 162 |
| 163 return kVectorFMACProc(src, scale, len, dest); |
| 164 } |
| 165 |
| 166 void AudioRendererMixer::VectorFMAC_C(const float src[], float scale, int len, |
| 167 float dest[]) { |
| 168 for (int i = 0; i < len; ++i) |
| 169 dest[i] += src[i] * scale; |
| 170 } |
| 171 |
| 172 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) |
| 173 void AudioRendererMixer::VectorFMAC_SSE(const float src[], float scale, int len, |
| 174 float dest[]) { |
| 175 // Ensure |src| and |dest| are 16-byte aligned. |
| 176 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) & 0x0F); |
| 177 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) & 0x0F); |
| 178 |
| 179 __m128 m_scale = _mm_set_ps1(scale); |
| 180 int rem = len % 4; |
| 181 for (int i = 0; i < len - rem; i += 4) { |
| 182 _mm_store_ps(dest + i, _mm_add_ps(_mm_load_ps(dest + i), |
| 183 _mm_mul_ps(_mm_load_ps(src + i), m_scale))); |
| 184 } |
| 185 |
| 186 // Handle any remaining values that wouldn't fit in an SSE pass. |
| 187 if (rem) |
| 188 VectorFMAC_C(src + len - rem, scale, rem, dest + len - rem); |
| 189 } |
| 190 #endif |
| 191 |
146 } // namespace media | 192 } // namespace media |
OLD | NEW |