|  | /* | 
|  | *  Copyright (c) 2012 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 "webrtc/modules/audio_processing/noise_suppression_impl.h" | 
|  |  | 
|  | #include "webrtc/base/constructormagic.h" | 
|  | #include "webrtc/modules/audio_processing/audio_buffer.h" | 
|  | #if defined(WEBRTC_NS_FLOAT) | 
|  | #include "webrtc/modules/audio_processing/ns/noise_suppression.h" | 
|  | #define NS_CREATE WebRtcNs_Create | 
|  | #define NS_FREE WebRtcNs_Free | 
|  | #define NS_INIT WebRtcNs_Init | 
|  | #define NS_SET_POLICY WebRtcNs_set_policy | 
|  | typedef NsHandle NsState; | 
|  | #elif defined(WEBRTC_NS_FIXED) | 
|  | #include "webrtc/modules/audio_processing/ns/noise_suppression_x.h" | 
|  | #define NS_CREATE WebRtcNsx_Create | 
|  | #define NS_FREE WebRtcNsx_Free | 
|  | #define NS_INIT WebRtcNsx_Init | 
|  | #define NS_SET_POLICY WebRtcNsx_set_policy | 
|  | typedef NsxHandle NsState; | 
|  | #endif | 
|  |  | 
|  | namespace webrtc { | 
|  | class NoiseSuppressionImpl::Suppressor { | 
|  | public: | 
|  | explicit Suppressor(int sample_rate_hz) { | 
|  | state_ = NS_CREATE(); | 
|  | RTC_CHECK(state_); | 
|  | int error = NS_INIT(state_, sample_rate_hz); | 
|  | RTC_DCHECK_EQ(0, error); | 
|  | } | 
|  | ~Suppressor() { | 
|  | NS_FREE(state_); | 
|  | } | 
|  | NsState* state() { return state_; } | 
|  | private: | 
|  | NsState* state_ = nullptr; | 
|  | RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Suppressor); | 
|  | }; | 
|  |  | 
|  | NoiseSuppressionImpl::NoiseSuppressionImpl(rtc::CriticalSection* crit) | 
|  | : crit_(crit) { | 
|  | RTC_DCHECK(crit); | 
|  | } | 
|  |  | 
|  | NoiseSuppressionImpl::~NoiseSuppressionImpl() {} | 
|  |  | 
|  | void NoiseSuppressionImpl::Initialize(size_t channels, int sample_rate_hz) { | 
|  | rtc::CritScope cs(crit_); | 
|  | channels_ = channels; | 
|  | sample_rate_hz_ = sample_rate_hz; | 
|  | std::vector<std::unique_ptr<Suppressor>> new_suppressors; | 
|  | if (enabled_) { | 
|  | new_suppressors.resize(channels); | 
|  | for (size_t i = 0; i < channels; i++) { | 
|  | new_suppressors[i].reset(new Suppressor(sample_rate_hz)); | 
|  | } | 
|  | } | 
|  | suppressors_.swap(new_suppressors); | 
|  | set_level(level_); | 
|  | } | 
|  |  | 
|  | void NoiseSuppressionImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { | 
|  | RTC_DCHECK(audio); | 
|  | #if defined(WEBRTC_NS_FLOAT) | 
|  | rtc::CritScope cs(crit_); | 
|  | if (!enabled_) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | RTC_DCHECK_GE(160, audio->num_frames_per_band()); | 
|  | RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels()); | 
|  | for (size_t i = 0; i < suppressors_.size(); i++) { | 
|  | WebRtcNs_Analyze(suppressors_[i]->state(), | 
|  | audio->split_bands_const_f(i)[kBand0To8kHz]); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void NoiseSuppressionImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 
|  | RTC_DCHECK(audio); | 
|  | rtc::CritScope cs(crit_); | 
|  | if (!enabled_) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | RTC_DCHECK_GE(160, audio->num_frames_per_band()); | 
|  | RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels()); | 
|  | for (size_t i = 0; i < suppressors_.size(); i++) { | 
|  | #if defined(WEBRTC_NS_FLOAT) | 
|  | WebRtcNs_Process(suppressors_[i]->state(), | 
|  | audio->split_bands_const_f(i), | 
|  | audio->num_bands(), | 
|  | audio->split_bands_f(i)); | 
|  | #elif defined(WEBRTC_NS_FIXED) | 
|  | WebRtcNsx_Process(suppressors_[i]->state(), | 
|  | audio->split_bands_const(i), | 
|  | audio->num_bands(), | 
|  | audio->split_bands(i)); | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | int NoiseSuppressionImpl::Enable(bool enable) { | 
|  | rtc::CritScope cs(crit_); | 
|  | if (enabled_ != enable) { | 
|  | enabled_ = enable; | 
|  | Initialize(channels_, sample_rate_hz_); | 
|  | } | 
|  | return AudioProcessing::kNoError; | 
|  | } | 
|  |  | 
|  | bool NoiseSuppressionImpl::is_enabled() const { | 
|  | rtc::CritScope cs(crit_); | 
|  | return enabled_; | 
|  | } | 
|  |  | 
|  | int NoiseSuppressionImpl::set_level(Level level) { | 
|  | int policy = 1; | 
|  | switch (level) { | 
|  | case NoiseSuppression::kLow: | 
|  | policy = 0; | 
|  | break; | 
|  | case NoiseSuppression::kModerate: | 
|  | policy = 1; | 
|  | break; | 
|  | case NoiseSuppression::kHigh: | 
|  | policy = 2; | 
|  | break; | 
|  | case NoiseSuppression::kVeryHigh: | 
|  | policy = 3; | 
|  | break; | 
|  | default: | 
|  | RTC_NOTREACHED(); | 
|  | } | 
|  | rtc::CritScope cs(crit_); | 
|  | level_ = level; | 
|  | for (auto& suppressor : suppressors_) { | 
|  | int error = NS_SET_POLICY(suppressor->state(), policy); | 
|  | RTC_DCHECK_EQ(0, error); | 
|  | } | 
|  | return AudioProcessing::kNoError; | 
|  | } | 
|  |  | 
|  | NoiseSuppression::Level NoiseSuppressionImpl::level() const { | 
|  | rtc::CritScope cs(crit_); | 
|  | return level_; | 
|  | } | 
|  |  | 
|  | float NoiseSuppressionImpl::speech_probability() const { | 
|  | rtc::CritScope cs(crit_); | 
|  | #if defined(WEBRTC_NS_FLOAT) | 
|  | float probability_average = 0.0f; | 
|  | for (auto& suppressor : suppressors_) { | 
|  | probability_average += | 
|  | WebRtcNs_prior_speech_probability(suppressor->state()); | 
|  | } | 
|  | if (!suppressors_.empty()) { | 
|  | probability_average /= suppressors_.size(); | 
|  | } | 
|  | return probability_average; | 
|  | #elif defined(WEBRTC_NS_FIXED) | 
|  | // TODO(peah): Returning error code as a float! Remove this. | 
|  | // Currently not available for the fixed point implementation. | 
|  | return AudioProcessing::kUnsupportedFunctionError; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | std::vector<float> NoiseSuppressionImpl::NoiseEstimate() { | 
|  | rtc::CritScope cs(crit_); | 
|  | std::vector<float> noise_estimate; | 
|  | #if defined(WEBRTC_NS_FLOAT) | 
|  | const float kNumChannelsFraction = 1.f / suppressors_.size(); | 
|  | noise_estimate.assign(WebRtcNs_num_freq(), 0.f); | 
|  | for (auto& suppressor : suppressors_) { | 
|  | const float* noise = WebRtcNs_noise_estimate(suppressor->state()); | 
|  | for (size_t i = 0; i < noise_estimate.size(); ++i) { | 
|  | noise_estimate[i] += kNumChannelsFraction * noise[i]; | 
|  | } | 
|  | } | 
|  | #elif defined(WEBRTC_NS_FIXED) | 
|  | noise_estimate.assign(WebRtcNsx_num_freq(), 0.f); | 
|  | for (auto& suppressor : suppressors_) { | 
|  | int q_noise; | 
|  | const uint32_t* noise = WebRtcNsx_noise_estimate(suppressor->state(), | 
|  | &q_noise); | 
|  | const float kNormalizationFactor = | 
|  | 1.f / ((1 << q_noise) * suppressors_.size()); | 
|  | for (size_t i = 0; i < noise_estimate.size(); ++i) { | 
|  | noise_estimate[i] += kNormalizationFactor * noise[i]; | 
|  | } | 
|  | } | 
|  | #endif | 
|  | return noise_estimate; | 
|  | } | 
|  |  | 
|  | size_t NoiseSuppressionImpl::num_noise_bins() { | 
|  | #if defined(WEBRTC_NS_FLOAT) | 
|  | return WebRtcNs_num_freq(); | 
|  | #elif defined(WEBRTC_NS_FIXED) | 
|  | return WebRtcNsx_num_freq(); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |