henrik.lundin@webrtc.org | 9a40081 | 2013-01-29 12:09:21 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2012 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 "webrtc/modules/audio_coding/neteq4/comfort_noise.h" |
| 12 | |
| 13 | #include <assert.h> |
| 14 | |
| 15 | #include "webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h" |
| 16 | #include "webrtc/modules/audio_coding/neteq4/decoder_database.h" |
| 17 | #include "webrtc/modules/audio_coding/neteq4/dsp_helper.h" |
| 18 | #include "webrtc/modules/audio_coding/neteq4/interface/audio_decoder.h" |
| 19 | #include "webrtc/modules/audio_coding/neteq4/sync_buffer.h" |
| 20 | |
| 21 | namespace webrtc { |
| 22 | |
| 23 | void ComfortNoise::Reset() { |
| 24 | first_call_ = true; |
| 25 | internal_error_code_ = 0; |
| 26 | } |
| 27 | |
| 28 | int ComfortNoise::UpdateParameters(Packet* packet) { |
| 29 | assert(packet); // Existence is verified by caller. |
| 30 | // Get comfort noise decoder. |
| 31 | AudioDecoder* cng_decoder = decoder_database_->GetDecoder( |
| 32 | packet->header.payloadType); |
| 33 | if (!cng_decoder) { |
| 34 | delete [] packet->payload; |
| 35 | delete packet; |
| 36 | return kUnknownPayloadType; |
| 37 | } |
| 38 | decoder_database_->SetActiveCngDecoder(packet->header.payloadType); |
| 39 | CNG_dec_inst* cng_inst = static_cast<CNG_dec_inst*>(cng_decoder->state()); |
| 40 | int16_t ret = WebRtcCng_UpdateSid(cng_inst, |
| 41 | packet->payload, |
| 42 | packet->payload_length); |
| 43 | delete [] packet->payload; |
| 44 | delete packet; |
| 45 | if (ret < 0) { |
| 46 | internal_error_code_ = WebRtcCng_GetErrorCodeDec(cng_inst); |
| 47 | return kInternalError; |
| 48 | } |
| 49 | return kOK; |
| 50 | } |
| 51 | |
| 52 | int ComfortNoise::Generate(size_t requested_length, |
| 53 | AudioMultiVector<int16_t>* output) { |
| 54 | // TODO(hlundin): Change to an enumerator and skip assert. |
| 55 | assert(fs_hz_ == 8000 || fs_hz_ == 16000 || fs_hz_ == 32000 || |
| 56 | fs_hz_ == 48000); |
turaj@webrtc.org | 1aa0938 | 2013-08-30 15:37:08 +0000 | [diff] [blame] | 57 | // Not adapted for multi-channel yet. |
henrik.lundin@webrtc.org | 9a40081 | 2013-01-29 12:09:21 +0000 | [diff] [blame] | 58 | if (output->Channels() != 1) { |
| 59 | return kMultiChannelNotSupported; |
| 60 | } |
| 61 | |
| 62 | int16_t number_of_samples = requested_length; |
| 63 | int16_t new_period = 0; |
| 64 | if (first_call_) { |
| 65 | // Generate noise and overlap slightly with old data. |
| 66 | number_of_samples = requested_length + overlap_length_; |
| 67 | new_period = 1; |
| 68 | } |
| 69 | output->AssertSize(number_of_samples); |
| 70 | // Get the decoder from the database. |
| 71 | AudioDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); |
| 72 | if (!cng_decoder) { |
| 73 | return kUnknownPayloadType; |
| 74 | } |
| 75 | CNG_dec_inst* cng_inst = static_cast<CNG_dec_inst*>(cng_decoder->state()); |
| 76 | // The expression &(*output)[0][0] is a pointer to the first element in |
| 77 | // the first channel. |
| 78 | if (WebRtcCng_Generate(cng_inst, &(*output)[0][0], number_of_samples, |
| 79 | new_period) < 0) { |
| 80 | // Error returned. |
| 81 | output->Zeros(requested_length); |
| 82 | internal_error_code_ = WebRtcCng_GetErrorCodeDec(cng_inst); |
| 83 | return kInternalError; |
| 84 | } |
| 85 | |
| 86 | if (first_call_) { |
| 87 | // Set tapering window parameters. Values are in Q15. |
| 88 | int16_t muting_window; // Mixing factor for overlap data. |
| 89 | int16_t muting_window_increment; // Mixing factor increment (negative). |
| 90 | int16_t unmuting_window; // Mixing factor for comfort noise. |
| 91 | int16_t unmuting_window_increment; // Mixing factor increment. |
| 92 | if (fs_hz_ == 8000) { |
| 93 | muting_window = DspHelper::kMuteFactorStart8kHz; |
| 94 | muting_window_increment = DspHelper::kMuteFactorIncrement8kHz; |
| 95 | unmuting_window = DspHelper::kUnmuteFactorStart8kHz; |
| 96 | unmuting_window_increment = DspHelper::kUnmuteFactorIncrement8kHz; |
| 97 | } else if (fs_hz_ == 16000) { |
| 98 | muting_window = DspHelper::kMuteFactorStart16kHz; |
| 99 | muting_window_increment = DspHelper::kMuteFactorIncrement16kHz; |
| 100 | unmuting_window = DspHelper::kUnmuteFactorStart16kHz; |
| 101 | unmuting_window_increment = DspHelper::kUnmuteFactorIncrement16kHz; |
| 102 | } else if (fs_hz_ == 32000) { |
| 103 | muting_window = DspHelper::kMuteFactorStart32kHz; |
| 104 | muting_window_increment = DspHelper::kMuteFactorIncrement32kHz; |
| 105 | unmuting_window = DspHelper::kUnmuteFactorStart32kHz; |
| 106 | unmuting_window_increment = DspHelper::kUnmuteFactorIncrement32kHz; |
| 107 | } else { // fs_hz_ == 48000 |
| 108 | muting_window = DspHelper::kMuteFactorStart48kHz; |
| 109 | muting_window_increment = DspHelper::kMuteFactorIncrement48kHz; |
| 110 | unmuting_window = DspHelper::kUnmuteFactorStart48kHz; |
| 111 | unmuting_window_increment = DspHelper::kUnmuteFactorIncrement48kHz; |
| 112 | } |
| 113 | |
| 114 | // Do overlap-add between new vector and overlap. |
| 115 | size_t start_ix = sync_buffer_->Size() - overlap_length_; |
| 116 | for (size_t i = 0; i < overlap_length_; i++) { |
| 117 | /* overlapVec[i] = WinMute * overlapVec[i] + WinUnMute * outData[i] */ |
| 118 | // The expression (*output)[0][i] is the i-th element in the first |
| 119 | // channel. |
| 120 | (*sync_buffer_)[0][start_ix + i] = |
| 121 | (((*sync_buffer_)[0][start_ix + i] * muting_window) + |
| 122 | ((*output)[0][i] * unmuting_window) + 16384) >> 15; |
| 123 | muting_window += muting_window_increment; |
| 124 | unmuting_window += unmuting_window_increment; |
| 125 | } |
| 126 | // Remove |overlap_length_| samples from the front of |output| since they |
| 127 | // were mixed into |sync_buffer_| above. |
| 128 | output->PopFront(overlap_length_); |
| 129 | } |
| 130 | first_call_ = false; |
| 131 | return kOK; |
| 132 | } |
| 133 | |
| 134 | } // namespace webrtc |