/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "level_estimator_impl.h" #include <assert.h> #include <math.h> #include <string.h> #include "audio_processing_impl.h" #include "audio_buffer.h" #include "critical_section_wrapper.h" namespace webrtc { namespace { const double kMaxSquaredLevel = 32768.0 * 32768.0; class Level { public: static const int kMinLevel = 127; Level() : sum_square_(0.0), sample_count_(0) {} ~Level() {} void Init() { sum_square_ = 0.0; sample_count_ = 0; } void Process(int16_t* data, int length) { assert(data != NULL); assert(length > 0); sum_square_ += SumSquare(data, length); sample_count_ += length; } void ProcessMuted(int length) { assert(length > 0); sample_count_ += length; } int RMS() { if (sample_count_ == 0 || sum_square_ == 0.0) { Init(); return kMinLevel; } // Normalize by the max level. double rms = sum_square_ / (sample_count_ * kMaxSquaredLevel); // 20log_10(x^0.5) = 10log_10(x) rms = 10 * log10(rms); if (rms > 0) rms = 0; else if (rms < -kMinLevel) rms = -kMinLevel; rms = -rms; Init(); return static_cast<int>(rms + 0.5); } private: static double SumSquare(int16_t* data, int length) { double sum_square = 0.0; for (int i = 0; i < length; ++i) { double data_d = static_cast<double>(data[i]); sum_square += data_d * data_d; } return sum_square; } double sum_square_; int sample_count_; }; } // namespace LevelEstimatorImpl::LevelEstimatorImpl(const AudioProcessingImpl* apm) : ProcessingComponent(apm), apm_(apm) {} LevelEstimatorImpl::~LevelEstimatorImpl() {} int LevelEstimatorImpl::ProcessStream(AudioBuffer* audio) { if (!is_component_enabled()) { return apm_->kNoError; } Level* level = static_cast<Level*>(handle(0)); if (audio->is_muted()) { level->ProcessMuted(audio->samples_per_channel()); return apm_->kNoError; } int16_t* mixed_data = audio->data(0); if (audio->num_channels() > 1) { audio->CopyAndMix(1); mixed_data = audio->mixed_data(0); } level->Process(mixed_data, audio->samples_per_channel()); return apm_->kNoError; } int LevelEstimatorImpl::Enable(bool enable) { CriticalSectionScoped crit_scoped(*apm_->crit()); return EnableComponent(enable); } bool LevelEstimatorImpl::is_enabled() const { return is_component_enabled(); } int LevelEstimatorImpl::RMS() { if (!is_component_enabled()) { return apm_->kNotEnabledError; } Level* level = static_cast<Level*>(handle(0)); return level->RMS(); } int LevelEstimatorImpl::get_version(char* version, int version_len_bytes) const { // An empty string is used to indicate no version information. memset(version, 0, version_len_bytes); return apm_->kNoError; } void* LevelEstimatorImpl::CreateHandle() const { return new Level; } int LevelEstimatorImpl::DestroyHandle(void* handle) const { assert(handle != NULL); Level* level = static_cast<Level*>(handle); delete level; return apm_->kNoError; } int LevelEstimatorImpl::InitializeHandle(void* handle) const { assert(handle != NULL); Level* level = static_cast<Level*>(handle); level->Init(); return apm_->kNoError; } int LevelEstimatorImpl::ConfigureHandle(void* /*handle*/) const { return apm_->kNoError; } int LevelEstimatorImpl::num_handles_required() const { return 1; } int LevelEstimatorImpl::GetHandleError(void* handle) const { // The component has no detailed errors. assert(handle != NULL); return apm_->kUnspecifiedError; } } // namespace webrtc