| 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 |