henrik.lundin@webrtc.org | 9a40081 | 2013-01-29 12:09:21 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013 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/decision_logic_normal.h" |
| 12 | |
| 13 | #include <assert.h> |
| 14 | |
| 15 | #include <algorithm> |
| 16 | |
| 17 | #include "webrtc/modules/audio_coding/neteq4/buffer_level_filter.h" |
| 18 | #include "webrtc/modules/audio_coding/neteq4/decoder_database.h" |
| 19 | #include "webrtc/modules/audio_coding/neteq4/delay_manager.h" |
| 20 | #include "webrtc/modules/audio_coding/neteq4/expand.h" |
| 21 | #include "webrtc/modules/audio_coding/neteq4/packet_buffer.h" |
| 22 | #include "webrtc/modules/audio_coding/neteq4/sync_buffer.h" |
| 23 | #include "webrtc/modules/interface/module_common_types.h" |
| 24 | |
| 25 | namespace webrtc { |
| 26 | |
| 27 | Operations DecisionLogicNormal::GetDecisionSpecialized( |
| 28 | const SyncBuffer& sync_buffer, |
| 29 | const Expand& expand, |
| 30 | int decoder_frame_length, |
| 31 | const RTPHeader* packet_header, |
| 32 | Modes prev_mode, |
| 33 | bool play_dtmf, |
| 34 | bool* reset_decoder) { |
| 35 | assert(playout_mode_ == kPlayoutOn || playout_mode_ == kPlayoutStreaming); |
| 36 | // Guard for errors, to avoid getting stuck in error mode. |
| 37 | if (prev_mode == kModeError) { |
| 38 | if (!packet_header) { |
| 39 | return kExpand; |
| 40 | } else { |
| 41 | return kUndefined; // Use kUndefined to flag for a reset. |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | uint32_t target_timestamp = sync_buffer.end_timestamp(); |
| 46 | uint32_t available_timestamp = 0; |
| 47 | int is_cng_packet = 0; |
| 48 | if (packet_header) { |
| 49 | available_timestamp = packet_header->timestamp; |
| 50 | is_cng_packet = |
| 51 | decoder_database_->IsComfortNoise(packet_header->payloadType); |
| 52 | } |
| 53 | |
| 54 | if (is_cng_packet) { |
| 55 | return CngOperation(prev_mode, target_timestamp, available_timestamp); |
| 56 | } |
| 57 | |
| 58 | // Handle the case with no packet at all available (except maybe DTMF). |
| 59 | if (!packet_header) { |
| 60 | return NoPacket(play_dtmf); |
| 61 | } |
| 62 | |
| 63 | // If the expand period was very long, reset NetEQ since it is likely that the |
| 64 | // sender was restarted. |
| 65 | if (num_consecutive_expands_ > kReinitAfterExpands) { |
| 66 | *reset_decoder = true; |
| 67 | return kNormal; |
| 68 | } |
| 69 | |
| 70 | // Check if the required packet is available. |
| 71 | if (target_timestamp == available_timestamp) { |
| 72 | return ExpectedPacketAvailable(prev_mode, play_dtmf); |
turaj@webrtc.org | bda9cbe | 2013-10-06 02:21:24 +0000 | [diff] [blame^] | 73 | } else if (IsNewerTimestamp(available_timestamp, target_timestamp)) { |
henrik.lundin@webrtc.org | 9a40081 | 2013-01-29 12:09:21 +0000 | [diff] [blame] | 74 | return FuturePacketAvailable(sync_buffer, expand, decoder_frame_length, |
| 75 | prev_mode, target_timestamp, |
| 76 | available_timestamp, play_dtmf); |
| 77 | } else { |
| 78 | // This implies that available_timestamp < target_timestamp, which can |
| 79 | // happen when a new stream or codec is received. Signal for a reset. |
| 80 | return kUndefined; |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | Operations DecisionLogicNormal::CngOperation(Modes prev_mode, |
| 85 | uint32_t target_timestamp, |
| 86 | uint32_t available_timestamp) { |
| 87 | // Signed difference between target and available timestamp. |
| 88 | int32_t timestamp_diff = (generated_noise_samples_ + target_timestamp) - |
| 89 | available_timestamp; |
| 90 | int32_t optimal_level_samp = |
| 91 | (delay_manager_->TargetLevel() * packet_length_samples_) >> 8; |
| 92 | int32_t excess_waiting_time_samp = -timestamp_diff - optimal_level_samp; |
| 93 | |
| 94 | if (excess_waiting_time_samp > optimal_level_samp / 2) { |
| 95 | // The waiting time for this packet will be longer than 1.5 |
| 96 | // times the wanted buffer delay. Advance the clock to cut |
| 97 | // waiting time down to the optimal. |
| 98 | generated_noise_samples_ += excess_waiting_time_samp; |
| 99 | timestamp_diff += excess_waiting_time_samp; |
| 100 | } |
| 101 | |
| 102 | if (timestamp_diff < 0 && prev_mode == kModeRfc3389Cng) { |
| 103 | // Not time to play this packet yet. Wait another round before using this |
| 104 | // packet. Keep on playing CNG from previous CNG parameters. |
| 105 | return kRfc3389CngNoPacket; |
| 106 | } else { |
| 107 | // Otherwise, go for the CNG packet now. |
| 108 | return kRfc3389Cng; |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | Operations DecisionLogicNormal::NoPacket(bool play_dtmf) { |
| 113 | if (cng_state_ == kCngRfc3389On) { |
| 114 | // Keep on playing comfort noise. |
| 115 | return kRfc3389CngNoPacket; |
| 116 | } else if (cng_state_ == kCngInternalOn) { |
| 117 | // Keep on playing codec internal comfort noise. |
| 118 | return kCodecInternalCng; |
| 119 | } else if (play_dtmf) { |
| 120 | return kDtmf; |
| 121 | } else { |
| 122 | // Nothing to play, do expand. |
| 123 | return kExpand; |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | Operations DecisionLogicNormal::ExpectedPacketAvailable(Modes prev_mode, |
| 128 | bool play_dtmf) { |
| 129 | if (prev_mode != kModeExpand && !play_dtmf) { |
| 130 | // Check criterion for time-stretching. |
| 131 | int low_limit, high_limit; |
| 132 | delay_manager_->BufferLimits(&low_limit, &high_limit); |
| 133 | if ((buffer_level_filter_->filtered_current_level() >= high_limit && |
| 134 | TimescaleAllowed()) || |
| 135 | buffer_level_filter_->filtered_current_level() >= high_limit << 2) { |
| 136 | // Buffer level higher than limit and time-scaling allowed, |
| 137 | // or buffer level really high. |
| 138 | return kAccelerate; |
| 139 | } else if ((buffer_level_filter_->filtered_current_level() < low_limit) |
| 140 | && TimescaleAllowed()) { |
| 141 | return kPreemptiveExpand; |
| 142 | } |
| 143 | } |
| 144 | return kNormal; |
| 145 | } |
| 146 | |
| 147 | Operations DecisionLogicNormal::FuturePacketAvailable( |
| 148 | const SyncBuffer& sync_buffer, |
| 149 | const Expand& expand, |
| 150 | int decoder_frame_length, |
| 151 | Modes prev_mode, |
| 152 | uint32_t target_timestamp, |
| 153 | uint32_t available_timestamp, |
| 154 | bool play_dtmf) { |
| 155 | // Required packet is not available, but a future packet is. |
| 156 | // Check if we should continue with an ongoing expand because the new packet |
| 157 | // is too far into the future. |
| 158 | uint32_t timestamp_leap = available_timestamp - target_timestamp; |
| 159 | if ((prev_mode == kModeExpand) && |
| 160 | !ReinitAfterExpands(timestamp_leap) && |
| 161 | !MaxWaitForPacket() && |
| 162 | PacketTooEarly(timestamp_leap) && |
| 163 | UnderTargetLevel()) { |
| 164 | if (play_dtmf) { |
| 165 | // Still have DTMF to play, so do not do expand. |
| 166 | return kDtmf; |
| 167 | } else { |
| 168 | // Nothing to play. |
| 169 | return kExpand; |
| 170 | } |
| 171 | } |
| 172 | |
turaj@webrtc.org | 045e45e | 2013-09-20 16:25:28 +0000 | [diff] [blame] | 173 | const int samples_left = static_cast<int>(sync_buffer.FutureLength() - |
| 174 | expand.overlap_length()); |
henrik.lundin@webrtc.org | 9a40081 | 2013-01-29 12:09:21 +0000 | [diff] [blame] | 175 | const int cur_size_samples = samples_left + |
| 176 | packet_buffer_.NumPacketsInBuffer() * decoder_frame_length; |
| 177 | |
| 178 | // If previous was comfort noise, then no merge is needed. |
| 179 | if (prev_mode == kModeRfc3389Cng || |
| 180 | prev_mode == kModeCodecInternalCng) { |
| 181 | // Keep the same delay as before the CNG (or maximum 70 ms in buffer as |
| 182 | // safety precaution), but make sure that the number of samples in buffer |
| 183 | // is no higher than 4 times the optimal level. (Note that TargetLevel() |
| 184 | // is in Q8.) |
| 185 | int32_t timestamp_diff = (generated_noise_samples_ + target_timestamp) - |
| 186 | available_timestamp; |
| 187 | if (timestamp_diff >= 0 || |
| 188 | cur_size_samples > |
| 189 | 4 * ((delay_manager_->TargetLevel() * packet_length_samples_) >> 8)) { |
| 190 | // Time to play this new packet. |
| 191 | return kNormal; |
| 192 | } else { |
| 193 | // Too early to play this new packet; keep on playing comfort noise. |
| 194 | if (prev_mode == kModeRfc3389Cng) { |
| 195 | return kRfc3389CngNoPacket; |
| 196 | } else { // prevPlayMode == kModeCodecInternalCng. |
| 197 | return kCodecInternalCng; |
| 198 | } |
| 199 | } |
| 200 | } |
| 201 | // Do not merge unless we have done an expand before. |
| 202 | // (Convert kAllowMergeWithoutExpand from ms to samples by multiplying with |
| 203 | // fs_mult_ * 8 = fs / 1000.) |
| 204 | if (prev_mode == kModeExpand || |
| 205 | (decoder_frame_length < output_size_samples_ && |
| 206 | cur_size_samples > kAllowMergeWithoutExpandMs * fs_mult_ * 8)) { |
| 207 | return kMerge; |
| 208 | } else if (play_dtmf) { |
| 209 | // Play DTMF instead of expand. |
| 210 | return kDtmf; |
| 211 | } else { |
| 212 | return kExpand; |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | bool DecisionLogicNormal::UnderTargetLevel() const { |
| 217 | return buffer_level_filter_->filtered_current_level() <= |
| 218 | delay_manager_->TargetLevel(); |
| 219 | } |
| 220 | |
| 221 | bool DecisionLogicNormal::ReinitAfterExpands(uint32_t timestamp_leap) const { |
| 222 | return timestamp_leap >= |
| 223 | static_cast<uint32_t>(output_size_samples_ * kReinitAfterExpands); |
| 224 | } |
| 225 | |
| 226 | bool DecisionLogicNormal::PacketTooEarly(uint32_t timestamp_leap) const { |
| 227 | return timestamp_leap > |
| 228 | static_cast<uint32_t>(output_size_samples_ * num_consecutive_expands_); |
| 229 | } |
| 230 | |
| 231 | bool DecisionLogicNormal::MaxWaitForPacket() const { |
| 232 | return num_consecutive_expands_ >= kMaxWaitForPacket; |
| 233 | } |
| 234 | |
| 235 | } // namespace webrtc |