Index: webrtc/modules/audio_coding/neteq/neteq_impl.cc |
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc |
index ef1e6cbf4a69773436f7e3eacc71fedea99ca56f..3bd20cbd134c4aa3098ffb4c5c9d5b00e761f2cd 100644 |
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc |
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc |
@@ -827,6 +827,11 @@ int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame) { |
vad_->Update(decoded_buffer_.get(), static_cast<size_t>(length), speech_type, |
sid_frame_available, fs_hz_); |
+ if (sid_frame_available || speech_type == AudioDecoder::kComfortNoise) { |
+ // Start a new stopwatch since we are decoding a new CNG packet. |
+ generated_noise_stopwatch_ = tick_timer_->GetNewStopwatch(); |
+ } |
+ |
algorithm_buffer_->Clear(); |
switch (operation) { |
case kNormal: { |
@@ -999,6 +1004,12 @@ int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame) { |
: timestamp_scaler_->ToExternal(playout_timestamp_) - |
static_cast<uint32_t>(audio_frame->samples_per_channel_); |
+ if (!(last_mode_ == kModeRfc3389Cng || |
+ last_mode_ == kModeCodecInternalCng || |
+ last_mode_ == kModeExpand)) { |
+ generated_noise_stopwatch_.reset(); |
+ } |
+ |
if (decode_return_value) return decode_return_value; |
return return_value; |
} |
@@ -1022,14 +1033,22 @@ int NetEqImpl::GetDecision(Operations* operation, |
} |
const RTPHeader* header = packet_buffer_->NextRtpHeader(); |
+ RTC_DCHECK(!generated_noise_stopwatch_ || |
+ generated_noise_stopwatch_->ElapsedTicks() >= 1); |
+ uint64_t generated_noise_samples = |
+ generated_noise_stopwatch_ |
+ ? (generated_noise_stopwatch_->ElapsedTicks() - 1) * |
+ output_size_samples_ + |
+ decision_logic_->noise_fast_forward() |
+ : 0; |
+ |
if (decision_logic_->CngRfc3389On() || last_mode_ == kModeRfc3389Cng) { |
// Because of timestamp peculiarities, we have to "manually" disallow using |
// a CNG packet with the same timestamp as the one that was last played. |
// This can happen when using redundancy and will cause the timing to shift. |
while (header && decoder_database_->IsComfortNoise(header->payloadType) && |
(end_timestamp >= header->timestamp || |
- end_timestamp + decision_logic_->generated_noise_samples() > |
- header->timestamp)) { |
+ end_timestamp + generated_noise_samples > header->timestamp)) { |
// Don't use this packet, discard it. |
if (packet_buffer_->DiscardNextPacket() != PacketBuffer::kOK) { |
assert(false); // Must be ok by design. |
@@ -1057,7 +1076,7 @@ int NetEqImpl::GetDecision(Operations* operation, |
// Check if it is time to play a DTMF event. |
if (dtmf_buffer_->GetEvent( |
static_cast<uint32_t>( |
- end_timestamp + decision_logic_->generated_noise_samples()), |
+ end_timestamp + generated_noise_samples), |
dtmf_event)) { |
*play_dtmf = true; |
} |
@@ -1065,13 +1084,14 @@ int NetEqImpl::GetDecision(Operations* operation, |
// Get instruction. |
assert(sync_buffer_.get()); |
assert(expand_.get()); |
- *operation = decision_logic_->GetDecision(*sync_buffer_, |
- *expand_, |
- decoder_frame_length_, |
- header, |
- last_mode_, |
- *play_dtmf, |
- &reset_decoder_); |
+ generated_noise_samples = |
+ generated_noise_stopwatch_ |
+ ? generated_noise_stopwatch_->ElapsedTicks() * output_size_samples_ + |
+ decision_logic_->noise_fast_forward() |
+ : 0; |
+ *operation = decision_logic_->GetDecision( |
+ *sync_buffer_, *expand_, decoder_frame_length_, header, last_mode_, |
+ *play_dtmf, generated_noise_samples, &reset_decoder_); |
// Check if we already have enough samples in the |sync_buffer_|. If so, |
// change decision to normal, unless the decision was merge, accelerate, or |
@@ -1144,15 +1164,19 @@ int NetEqImpl::GetDecision(Operations* operation, |
// TODO(hlundin): Write test for this. |
// Update timestamp. |
timestamp_ = end_timestamp; |
- if (decision_logic_->generated_noise_samples() > 0 && |
- last_mode_ != kModeDtmf) { |
+ const uint64_t generated_noise_samples = |
+ generated_noise_stopwatch_ |
+ ? generated_noise_stopwatch_->ElapsedTicks() * |
+ output_size_samples_ + |
+ decision_logic_->noise_fast_forward() |
+ : 0; |
+ if (generated_noise_samples > 0 && last_mode_ != kModeDtmf) { |
// Make a jump in timestamp due to the recently played comfort noise. |
uint32_t timestamp_jump = |
- static_cast<uint32_t>(decision_logic_->generated_noise_samples()); |
+ static_cast<uint32_t>(generated_noise_samples); |
sync_buffer_->IncreaseEndTimestamp(timestamp_jump); |
timestamp_ += timestamp_jump; |
} |
- decision_logic_->set_generated_noise_samples(0); |
return 0; |
} |
case kAccelerate: |
@@ -1235,9 +1259,6 @@ int NetEqImpl::GetDecision(Operations* operation, |
// We are about to decode and use a non-CNG packet. |
decision_logic_->SetCngOff(); |
} |
- // Reset CNG timestamp as a new packet will be delivered. |
- // (Also if this is a CNG packet, since playedOutTS is updated.) |
- decision_logic_->set_generated_noise_samples(0); |
extracted_samples = ExtractPackets(required_samples, packet_list); |
if (extracted_samples < 0) { |
@@ -1570,6 +1591,12 @@ int NetEqImpl::DoExpand(bool play_dtmf) { |
if (!play_dtmf) { |
dtmf_tone_generator_->Reset(); |
} |
+ |
+ if (!generated_noise_stopwatch_) { |
+ // Start a new stopwatch since we may be covering for a lost CNG packet. |
+ generated_noise_stopwatch_ = tick_timer_->GetNewStopwatch(); |
+ } |
+ |
return 0; |
} |