1/*
2 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "level_estimator_impl.h"
12
13#include <assert.h>
14#include <math.h>
15#include <string.h>
16
17#include "audio_processing_impl.h"
18#include "audio_buffer.h"
19#include "critical_section_wrapper.h"
20
21namespace webrtc {
22namespace {
23
24const double kMaxSquaredLevel = 32768.0 * 32768.0;
25
26class Level {
27 public:
28  static const int kMinLevel = 127;
29
30  Level()
31    : sum_square_(0.0),
32      sample_count_(0) {}
33  ~Level() {}
34
35  void Init() {
36    sum_square_ = 0.0;
37    sample_count_ = 0;
38  }
39
40  void Process(int16_t* data, int length) {
41    assert(data != NULL);
42    assert(length > 0);
43    sum_square_ += SumSquare(data, length);
44    sample_count_ += length;
45  }
46
47  void ProcessMuted(int length) {
48    assert(length > 0);
49    sample_count_ += length;
50  }
51
52  int RMS() {
53    if (sample_count_ == 0 || sum_square_ == 0.0) {
54      Init();
55      return kMinLevel;
56    }
57
58    // Normalize by the max level.
59    double rms = sum_square_ / (sample_count_ * kMaxSquaredLevel);
60    // 20log_10(x^0.5) = 10log_10(x)
61    rms = 10 * log10(rms);
62    if (rms > 0)
63      rms = 0;
64    else if (rms < -kMinLevel)
65      rms = -kMinLevel;
66
67    rms = -rms;
68    Init();
69    return static_cast<int>(rms + 0.5);
70  }
71
72 private:
73  static double SumSquare(int16_t* data, int length) {
74    double sum_square = 0.0;
75    for (int i = 0; i < length; ++i) {
76      double data_d = static_cast<double>(data[i]);
77      sum_square += data_d * data_d;
78    }
79    return sum_square;
80  }
81
82  double sum_square_;
83  int sample_count_;
84};
85}  // namespace
86
87LevelEstimatorImpl::LevelEstimatorImpl(const AudioProcessingImpl* apm)
88  : ProcessingComponent(apm),
89    apm_(apm) {}
90
91LevelEstimatorImpl::~LevelEstimatorImpl() {}
92
93int LevelEstimatorImpl::ProcessStream(AudioBuffer* audio) {
94  if (!is_component_enabled()) {
95    return apm_->kNoError;
96  }
97
98  Level* level = static_cast<Level*>(handle(0));
99  if (audio->is_muted()) {
100    level->ProcessMuted(audio->samples_per_channel());
101    return apm_->kNoError;
102  }
103
104  int16_t* mixed_data = audio->data(0);
105  if (audio->num_channels() > 1) {
106    audio->CopyAndMix(1);
107    mixed_data = audio->mixed_data(0);
108  }
109
110  level->Process(mixed_data, audio->samples_per_channel());
111
112  return apm_->kNoError;
113}
114
115int LevelEstimatorImpl::Enable(bool enable) {
116  CriticalSectionScoped crit_scoped(*apm_->crit());
117  return EnableComponent(enable);
118}
119
120bool LevelEstimatorImpl::is_enabled() const {
121  return is_component_enabled();
122}
123
124int LevelEstimatorImpl::RMS() {
125  if (!is_component_enabled()) {
126    return apm_->kNotEnabledError;
127  }
128
129  Level* level = static_cast<Level*>(handle(0));
130  return level->RMS();
131}
132
133int LevelEstimatorImpl::get_version(char* version,
134                                    int version_len_bytes) const {
135  // An empty string is used to indicate no version information.
136  memset(version, 0, version_len_bytes);
137  return apm_->kNoError;
138}
139
140void* LevelEstimatorImpl::CreateHandle() const {
141  return new Level;
142}
143
144int LevelEstimatorImpl::DestroyHandle(void* handle) const {
145  assert(handle != NULL);
146  Level* level = static_cast<Level*>(handle);
147  delete level;
148  return apm_->kNoError;
149}
150
151int LevelEstimatorImpl::InitializeHandle(void* handle) const {
152  assert(handle != NULL);
153  Level* level = static_cast<Level*>(handle);
154  level->Init();
155
156  return apm_->kNoError;
157}
158
159int LevelEstimatorImpl::ConfigureHandle(void* /*handle*/) const {
160  return apm_->kNoError;
161}
162
163int LevelEstimatorImpl::num_handles_required() const {
164  return 1;
165}
166
167int LevelEstimatorImpl::GetHandleError(void* handle) const {
168  // The component has no detailed errors.
169  assert(handle != NULL);
170  return apm_->kUnspecifiedError;
171}
172}  // namespace webrtc
173