/* * 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_coding/neteq/comfort_noise.h" #include #include "webrtc/base/logging.h" #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" #include "webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h" #include "webrtc/modules/audio_coding/neteq/decoder_database.h" #include "webrtc/modules/audio_coding/neteq/dsp_helper.h" #include "webrtc/modules/audio_coding/neteq/sync_buffer.h" namespace webrtc { void ComfortNoise::Reset() { first_call_ = true; internal_error_code_ = 0; } int ComfortNoise::UpdateParameters(Packet* packet) { assert(packet); // Existence is verified by caller. // Get comfort noise decoder. AudioDecoder* cng_decoder = decoder_database_->GetDecoder( packet->header.payloadType); if (!cng_decoder) { delete [] packet->payload; delete packet; return kUnknownPayloadType; } decoder_database_->SetActiveCngDecoder(packet->header.payloadType); CNG_dec_inst* cng_inst = cng_decoder->CngDecoderInstance(); int16_t ret = WebRtcCng_UpdateSid(cng_inst, packet->payload, packet->payload_length); delete [] packet->payload; delete packet; if (ret < 0) { internal_error_code_ = WebRtcCng_GetErrorCodeDec(cng_inst); LOG(LS_ERROR) << "WebRtcCng_UpdateSid produced " << internal_error_code_; return kInternalError; } return kOK; } int ComfortNoise::Generate(size_t requested_length, AudioMultiVector* output) { // TODO(hlundin): Change to an enumerator and skip assert. assert(fs_hz_ == 8000 || fs_hz_ == 16000 || fs_hz_ == 32000 || fs_hz_ == 48000); // Not adapted for multi-channel yet. if (output->Channels() != 1) { LOG(LS_ERROR) << "No multi-channel support"; return kMultiChannelNotSupported; } size_t number_of_samples = requested_length; int16_t new_period = 0; if (first_call_) { // Generate noise and overlap slightly with old data. number_of_samples = requested_length + overlap_length_; new_period = 1; } output->AssertSize(number_of_samples); // Get the decoder from the database. AudioDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); if (!cng_decoder) { LOG(LS_ERROR) << "Unknwown payload type"; return kUnknownPayloadType; } CNG_dec_inst* cng_inst = cng_decoder->CngDecoderInstance(); // The expression &(*output)[0][0] is a pointer to the first element in // the first channel. if (WebRtcCng_Generate(cng_inst, &(*output)[0][0], number_of_samples, new_period) < 0) { // Error returned. output->Zeros(requested_length); internal_error_code_ = WebRtcCng_GetErrorCodeDec(cng_inst); LOG(LS_ERROR) << "WebRtcCng_Generate produced " << internal_error_code_; return kInternalError; } if (first_call_) { // Set tapering window parameters. Values are in Q15. int16_t muting_window; // Mixing factor for overlap data. int16_t muting_window_increment; // Mixing factor increment (negative). int16_t unmuting_window; // Mixing factor for comfort noise. int16_t unmuting_window_increment; // Mixing factor increment. if (fs_hz_ == 8000) { muting_window = DspHelper::kMuteFactorStart8kHz; muting_window_increment = DspHelper::kMuteFactorIncrement8kHz; unmuting_window = DspHelper::kUnmuteFactorStart8kHz; unmuting_window_increment = DspHelper::kUnmuteFactorIncrement8kHz; } else if (fs_hz_ == 16000) { muting_window = DspHelper::kMuteFactorStart16kHz; muting_window_increment = DspHelper::kMuteFactorIncrement16kHz; unmuting_window = DspHelper::kUnmuteFactorStart16kHz; unmuting_window_increment = DspHelper::kUnmuteFactorIncrement16kHz; } else if (fs_hz_ == 32000) { muting_window = DspHelper::kMuteFactorStart32kHz; muting_window_increment = DspHelper::kMuteFactorIncrement32kHz; unmuting_window = DspHelper::kUnmuteFactorStart32kHz; unmuting_window_increment = DspHelper::kUnmuteFactorIncrement32kHz; } else { // fs_hz_ == 48000 muting_window = DspHelper::kMuteFactorStart48kHz; muting_window_increment = DspHelper::kMuteFactorIncrement48kHz; unmuting_window = DspHelper::kUnmuteFactorStart48kHz; unmuting_window_increment = DspHelper::kUnmuteFactorIncrement48kHz; } // Do overlap-add between new vector and overlap. size_t start_ix = sync_buffer_->Size() - overlap_length_; for (size_t i = 0; i < overlap_length_; i++) { /* overlapVec[i] = WinMute * overlapVec[i] + WinUnMute * outData[i] */ // The expression (*output)[0][i] is the i-th element in the first // channel. (*sync_buffer_)[0][start_ix + i] = (((*sync_buffer_)[0][start_ix + i] * muting_window) + ((*output)[0][i] * unmuting_window) + 16384) >> 15; muting_window += muting_window_increment; unmuting_window += unmuting_window_increment; } // Remove |overlap_length_| samples from the front of |output| since they // were mixed into |sync_buffer_| above. output->PopFront(overlap_length_); } first_call_ = false; return kOK; } } // namespace webrtc