|  | /* | 
|  | *  Copyright (c) 2013 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/decision_logic_normal.h" | 
|  |  | 
|  | #include <assert.h> | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "webrtc/modules/audio_coding/neteq/buffer_level_filter.h" | 
|  | #include "webrtc/modules/audio_coding/neteq/decoder_database.h" | 
|  | #include "webrtc/modules/audio_coding/neteq/delay_manager.h" | 
|  | #include "webrtc/modules/audio_coding/neteq/expand.h" | 
|  | #include "webrtc/modules/audio_coding/neteq/packet_buffer.h" | 
|  | #include "webrtc/modules/audio_coding/neteq/sync_buffer.h" | 
|  | #include "webrtc/modules/interface/module_common_types.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | Operations DecisionLogicNormal::GetDecisionSpecialized( | 
|  | const SyncBuffer& sync_buffer, | 
|  | const Expand& expand, | 
|  | int decoder_frame_length, | 
|  | const RTPHeader* packet_header, | 
|  | Modes prev_mode, | 
|  | bool play_dtmf, | 
|  | bool* reset_decoder) { | 
|  | assert(playout_mode_ == kPlayoutOn || playout_mode_ == kPlayoutStreaming); | 
|  | // Guard for errors, to avoid getting stuck in error mode. | 
|  | if (prev_mode == kModeError) { | 
|  | if (!packet_header) { | 
|  | return kExpand; | 
|  | } else { | 
|  | return kUndefined;  // Use kUndefined to flag for a reset. | 
|  | } | 
|  | } | 
|  |  | 
|  | uint32_t target_timestamp = sync_buffer.end_timestamp(); | 
|  | uint32_t available_timestamp = 0; | 
|  | bool is_cng_packet = false; | 
|  | if (packet_header) { | 
|  | available_timestamp = packet_header->timestamp; | 
|  | is_cng_packet = | 
|  | decoder_database_->IsComfortNoise(packet_header->payloadType); | 
|  | } | 
|  |  | 
|  | if (is_cng_packet) { | 
|  | return CngOperation(prev_mode, target_timestamp, available_timestamp); | 
|  | } | 
|  |  | 
|  | // Handle the case with no packet at all available (except maybe DTMF). | 
|  | if (!packet_header) { | 
|  | return NoPacket(play_dtmf); | 
|  | } | 
|  |  | 
|  | // If the expand period was very long, reset NetEQ since it is likely that the | 
|  | // sender was restarted. | 
|  | if (num_consecutive_expands_ > kReinitAfterExpands) { | 
|  | *reset_decoder = true; | 
|  | return kNormal; | 
|  | } | 
|  |  | 
|  | const uint32_t five_seconds_samples = 5 * 8000 * fs_mult_; | 
|  | // Check if the required packet is available. | 
|  | if (target_timestamp == available_timestamp) { | 
|  | return ExpectedPacketAvailable(prev_mode, play_dtmf); | 
|  | } else if (!PacketBuffer::IsObsoleteTimestamp( | 
|  | available_timestamp, target_timestamp, five_seconds_samples)) { | 
|  | return FuturePacketAvailable(sync_buffer, expand, decoder_frame_length, | 
|  | prev_mode, target_timestamp, | 
|  | available_timestamp, play_dtmf); | 
|  | } else { | 
|  | // This implies that available_timestamp < target_timestamp, which can | 
|  | // happen when a new stream or codec is received. Signal for a reset. | 
|  | return kUndefined; | 
|  | } | 
|  | } | 
|  |  | 
|  | Operations DecisionLogicNormal::CngOperation(Modes prev_mode, | 
|  | uint32_t target_timestamp, | 
|  | uint32_t available_timestamp) { | 
|  | // Signed difference between target and available timestamp. | 
|  | int32_t timestamp_diff = (generated_noise_samples_ + target_timestamp) - | 
|  | available_timestamp; | 
|  | int32_t optimal_level_samp = | 
|  | (delay_manager_->TargetLevel() * packet_length_samples_) >> 8; | 
|  | int32_t excess_waiting_time_samp = -timestamp_diff - optimal_level_samp; | 
|  |  | 
|  | if (excess_waiting_time_samp > optimal_level_samp / 2) { | 
|  | // The waiting time for this packet will be longer than 1.5 | 
|  | // times the wanted buffer delay. Advance the clock to cut | 
|  | // waiting time down to the optimal. | 
|  | generated_noise_samples_ += excess_waiting_time_samp; | 
|  | timestamp_diff += excess_waiting_time_samp; | 
|  | } | 
|  |  | 
|  | if (timestamp_diff < 0 && prev_mode == kModeRfc3389Cng) { | 
|  | // Not time to play this packet yet. Wait another round before using this | 
|  | // packet. Keep on playing CNG from previous CNG parameters. | 
|  | return kRfc3389CngNoPacket; | 
|  | } else { | 
|  | // Otherwise, go for the CNG packet now. | 
|  | return kRfc3389Cng; | 
|  | } | 
|  | } | 
|  |  | 
|  | Operations DecisionLogicNormal::NoPacket(bool play_dtmf) { | 
|  | if (cng_state_ == kCngRfc3389On) { | 
|  | // Keep on playing comfort noise. | 
|  | return kRfc3389CngNoPacket; | 
|  | } else if (cng_state_ == kCngInternalOn) { | 
|  | // Keep on playing codec internal comfort noise. | 
|  | return kCodecInternalCng; | 
|  | } else if (play_dtmf) { | 
|  | return kDtmf; | 
|  | } else { | 
|  | // Nothing to play, do expand. | 
|  | return kExpand; | 
|  | } | 
|  | } | 
|  |  | 
|  | Operations DecisionLogicNormal::ExpectedPacketAvailable(Modes prev_mode, | 
|  | bool play_dtmf) { | 
|  | if (prev_mode != kModeExpand && !play_dtmf) { | 
|  | // Check criterion for time-stretching. | 
|  | int low_limit, high_limit; | 
|  | delay_manager_->BufferLimits(&low_limit, &high_limit); | 
|  | if ((buffer_level_filter_->filtered_current_level() >= high_limit && | 
|  | TimescaleAllowed()) || | 
|  | buffer_level_filter_->filtered_current_level() >= high_limit << 2) { | 
|  | // Buffer level higher than limit and time-scaling allowed, | 
|  | // or buffer level really high. | 
|  | return kAccelerate; | 
|  | } else if ((buffer_level_filter_->filtered_current_level() < low_limit) | 
|  | && TimescaleAllowed()) { | 
|  | return kPreemptiveExpand; | 
|  | } | 
|  | } | 
|  | return kNormal; | 
|  | } | 
|  |  | 
|  | Operations DecisionLogicNormal::FuturePacketAvailable( | 
|  | const SyncBuffer& sync_buffer, | 
|  | const Expand& expand, | 
|  | int decoder_frame_length, | 
|  | Modes prev_mode, | 
|  | uint32_t target_timestamp, | 
|  | uint32_t available_timestamp, | 
|  | bool play_dtmf) { | 
|  | // Required packet is not available, but a future packet is. | 
|  | // Check if we should continue with an ongoing expand because the new packet | 
|  | // is too far into the future. | 
|  | uint32_t timestamp_leap = available_timestamp - target_timestamp; | 
|  | if ((prev_mode == kModeExpand) && | 
|  | !ReinitAfterExpands(timestamp_leap) && | 
|  | !MaxWaitForPacket() && | 
|  | PacketTooEarly(timestamp_leap) && | 
|  | UnderTargetLevel()) { | 
|  | if (play_dtmf) { | 
|  | // Still have DTMF to play, so do not do expand. | 
|  | return kDtmf; | 
|  | } else { | 
|  | // Nothing to play. | 
|  | return kExpand; | 
|  | } | 
|  | } | 
|  |  | 
|  | const int samples_left = static_cast<int>(sync_buffer.FutureLength() - | 
|  | expand.overlap_length()); | 
|  | const int cur_size_samples = samples_left + | 
|  | packet_buffer_.NumPacketsInBuffer() * decoder_frame_length; | 
|  |  | 
|  | // If previous was comfort noise, then no merge is needed. | 
|  | if (prev_mode == kModeRfc3389Cng || | 
|  | prev_mode == kModeCodecInternalCng) { | 
|  | // Keep the same delay as before the CNG (or maximum 70 ms in buffer as | 
|  | // safety precaution), but make sure that the number of samples in buffer | 
|  | // is no higher than 4 times the optimal level. (Note that TargetLevel() | 
|  | // is in Q8.) | 
|  | int32_t timestamp_diff = (generated_noise_samples_ + target_timestamp) - | 
|  | available_timestamp; | 
|  | if (timestamp_diff >= 0 || | 
|  | cur_size_samples > | 
|  | 4 * ((delay_manager_->TargetLevel() * packet_length_samples_) >> 8)) { | 
|  | // Time to play this new packet. | 
|  | return kNormal; | 
|  | } else { | 
|  | // Too early to play this new packet; keep on playing comfort noise. | 
|  | if (prev_mode == kModeRfc3389Cng) { | 
|  | return kRfc3389CngNoPacket; | 
|  | } else {  // prevPlayMode == kModeCodecInternalCng. | 
|  | return kCodecInternalCng; | 
|  | } | 
|  | } | 
|  | } | 
|  | // Do not merge unless we have done an expand before. | 
|  | // (Convert kAllowMergeWithoutExpand from ms to samples by multiplying with | 
|  | // fs_mult_ * 8 = fs / 1000.) | 
|  | if (prev_mode == kModeExpand || | 
|  | (decoder_frame_length < output_size_samples_ && | 
|  | cur_size_samples > kAllowMergeWithoutExpandMs * fs_mult_ * 8)) { | 
|  | return kMerge; | 
|  | } else if (play_dtmf) { | 
|  | // Play DTMF instead of expand. | 
|  | return kDtmf; | 
|  | } else { | 
|  | return kExpand; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool DecisionLogicNormal::UnderTargetLevel() const { | 
|  | return buffer_level_filter_->filtered_current_level() <= | 
|  | delay_manager_->TargetLevel(); | 
|  | } | 
|  |  | 
|  | bool DecisionLogicNormal::ReinitAfterExpands(uint32_t timestamp_leap) const { | 
|  | return timestamp_leap >= | 
|  | static_cast<uint32_t>(output_size_samples_ * kReinitAfterExpands); | 
|  | } | 
|  |  | 
|  | bool DecisionLogicNormal::PacketTooEarly(uint32_t timestamp_leap) const { | 
|  | return timestamp_leap > | 
|  | static_cast<uint32_t>(output_size_samples_ * num_consecutive_expands_); | 
|  | } | 
|  |  | 
|  | bool DecisionLogicNormal::MaxWaitForPacket() const { | 
|  | return num_consecutive_expands_ >= kMaxWaitForPacket; | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |