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