| Index: chromecast/media/cma/backend/alsa/slew_volume.cc
 | 
| diff --git a/chromecast/media/cma/backend/alsa/slew_volume.cc b/chromecast/media/cma/backend/alsa/slew_volume.cc
 | 
| index 38ce1a72a186e43f64ebc3b301fb627e2013a2e2..eabba92ce3bc5ae2885e1c7785f3fc252dcbc5b5 100644
 | 
| --- a/chromecast/media/cma/backend/alsa/slew_volume.cc
 | 
| +++ b/chromecast/media/cma/backend/alsa/slew_volume.cc
 | 
| @@ -14,7 +14,8 @@ namespace {
 | 
|  // The time to slew from current volume to target volume.
 | 
|  const int kMaxSlewTimeMs = 100;
 | 
|  const int kDefaultSampleRate = 44100;
 | 
| -}
 | 
| +
 | 
| +}  // namespace
 | 
|  
 | 
|  namespace chromecast {
 | 
|  namespace media {
 | 
| @@ -24,11 +25,11 @@ SlewVolume::SlewVolume() : SlewVolume(kMaxSlewTimeMs) {}
 | 
|  SlewVolume::SlewVolume(int max_slew_time_ms)
 | 
|      : sample_rate_(kDefaultSampleRate),
 | 
|        max_slew_time_ms_(max_slew_time_ms),
 | 
| -      max_slew_per_sample_(1000.0 / (max_slew_time_ms_ * sample_rate_)) {
 | 
| -  LOG(INFO) << "Creating a slew volume: " << max_slew_time_ms;
 | 
| -}
 | 
| +      max_slew_per_sample_(1000.0 / (max_slew_time_ms_ * sample_rate_)) {}
 | 
|  
 | 
|  void SlewVolume::SetSampleRate(int sample_rate) {
 | 
| +  DCHECK_GT(sample_rate, 0);
 | 
| +
 | 
|    sample_rate_ = sample_rate;
 | 
|    SetVolume(volume_scale_);
 | 
|  }
 | 
| @@ -49,6 +50,8 @@ void SlewVolume::SetVolume(double volume_scale) {
 | 
|  }
 | 
|  
 | 
|  void SlewVolume::SetMaxSlewTimeMs(int max_slew_time_ms) {
 | 
| +  DCHECK_GE(max_slew_time_ms, 0);
 | 
| +
 | 
|    max_slew_time_ms_ = max_slew_time_ms;
 | 
|  }
 | 
|  
 | 
| @@ -86,7 +89,9 @@ void SlewVolume::ProcessFMAC(bool repeat_transition,
 | 
|      }
 | 
|      ::media::vector_math::FMAC(src, current_volume_, frames, dest);
 | 
|      return;
 | 
| -  } else if (current_volume_ < volume_scale_) {
 | 
| +  }
 | 
| +
 | 
| +  if (current_volume_ < volume_scale_) {
 | 
|      do {
 | 
|        (*dest) += (*src) * current_volume_;
 | 
|        ++src;
 | 
| @@ -105,68 +110,90 @@ void SlewVolume::ProcessFMAC(bool repeat_transition,
 | 
|      } while (current_volume_ > volume_scale_ && frames);
 | 
|      current_volume_ = std::max(current_volume_, volume_scale_);
 | 
|    }
 | 
| -
 | 
| -  if (frames) {
 | 
| -    for (int f = 0; f < frames; ++f) {
 | 
| -      dest[f] += src[f] * current_volume_;
 | 
| -    }
 | 
| +  while (frames && (reinterpret_cast<uintptr_t>(src) &
 | 
| +                    (::media::vector_math::kRequiredAlignment - 1))) {
 | 
| +    (*dest) += (*src) * current_volume_;
 | 
| +    ++src;
 | 
| +    ++dest;
 | 
| +    --frames;
 | 
| +  }
 | 
| +  if (!frames) {
 | 
| +    return;
 | 
|    }
 | 
| +  ::media::vector_math::FMAC(src, current_volume_, frames, dest);
 | 
|  }
 | 
|  
 | 
| -// Scaling samples naively like this takes 0.2% of the CPU's time @ 44100hz
 | 
| -// on pineapple.
 | 
| -// Assumes 2 channel audio.
 | 
| -bool SlewVolume::ProcessInterleaved(int32_t* data, int frames) {
 | 
| -  DCHECK(data);
 | 
| +void SlewVolume::ProcessFMUL(bool repeat_transition,
 | 
| +                             const float* src,
 | 
| +                             int frames,
 | 
| +                             float* dest) {
 | 
| +  DCHECK(src);
 | 
| +  DCHECK(dest);
 | 
| +  // Ensure |src| and |dest| are 16-byte aligned.
 | 
| +  DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) &
 | 
| +                    (::media::vector_math::kRequiredAlignment - 1));
 | 
| +  DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) &
 | 
| +                    (::media::vector_math::kRequiredAlignment - 1));
 | 
|  
 | 
|    if (!frames) {
 | 
| -    return true;
 | 
| +    return;
 | 
|    }
 | 
|  
 | 
|    interrupted_ = false;
 | 
| +  if (repeat_transition) {
 | 
| +    current_volume_ = last_starting_volume_;
 | 
| +  } else {
 | 
| +    last_starting_volume_ = current_volume_;
 | 
| +  }
 | 
| +
 | 
|    if (current_volume_ == volume_scale_) {
 | 
| -    if (current_volume_ == 1.0) {
 | 
| -      return true;
 | 
| +    if (current_volume_ == 0.0) {
 | 
| +      memset(dest, 0, frames * sizeof(*dest));
 | 
| +      return;
 | 
|      }
 | 
| -    for (int i = 0; i < 2 * frames; ++i) {
 | 
| -      data[i] *= current_volume_;
 | 
| +    if (current_volume_ == 1.0) {
 | 
| +      if (src == dest) {
 | 
| +        return;
 | 
| +      }
 | 
| +      std::memcpy(dest, src, frames * sizeof(*dest));
 | 
| +      return;
 | 
|      }
 | 
| -    return true;
 | 
| -  } else if (current_volume_ < volume_scale_) {
 | 
| +    ::media::vector_math::FMUL(src, current_volume_, frames, dest);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  LOG(INFO) << "max slew per sample " << max_slew_per_sample_;
 | 
| +  if (current_volume_ < volume_scale_) {
 | 
|      do {
 | 
| -      (*data) *= current_volume_;
 | 
| -      ++data;
 | 
| -      (*data) *= current_volume_;
 | 
| -      ++data;
 | 
| +      (*dest) = (*src) * current_volume_;
 | 
| +      ++src;
 | 
| +      ++dest;
 | 
|        --frames;
 | 
|        current_volume_ += max_slew_per_sample_;
 | 
|      } while (current_volume_ < volume_scale_ && frames);
 | 
|      current_volume_ = std::min(current_volume_, volume_scale_);
 | 
| -  } else {
 | 
| +  } else {  // current_volume_ > volume_scale_
 | 
|      do {
 | 
| -      (*data) *= current_volume_;
 | 
| -      ++data;
 | 
| -      (*data) *= current_volume_;
 | 
| -      ++data;
 | 
| +      (*dest) = (*src) * current_volume_;
 | 
| +      ++src;
 | 
| +      ++dest;
 | 
|        --frames;
 | 
|        current_volume_ -= max_slew_per_sample_;
 | 
|      } while (current_volume_ > volume_scale_ && frames);
 | 
|      current_volume_ = std::max(current_volume_, volume_scale_);
 | 
|    }
 | 
|  
 | 
| -  if (current_volume_ == 1.0) {
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  if (current_volume_ == 0.0) {
 | 
| -    std::fill_n(data, frames * 2, 0);
 | 
| -    return true;
 | 
| +  while (frames && (reinterpret_cast<uintptr_t>(src) &
 | 
| +                    (::media::vector_math::kRequiredAlignment - 1))) {
 | 
| +    (*dest) = (*src) * current_volume_;
 | 
| +    ++src;
 | 
| +    ++dest;
 | 
| +    --frames;
 | 
|    }
 | 
| -
 | 
| -  for (int i = 0; i < 2 * frames; ++i) {
 | 
| -    data[i] *= current_volume_;
 | 
| +  if (!frames) {
 | 
| +    return;
 | 
|    }
 | 
| -  return true;
 | 
| +  ::media::vector_math::FMUL(src, current_volume_, frames, dest);
 | 
|  }
 | 
|  
 | 
|  }  // namespace media
 | 
| 
 |