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 db37e716d66dde966a4cac42f10dd47166c4f42c..1b6e0c0c3e13856ad9c334d0efbe3daba8f65716 100644 |
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc |
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc |
@@ -42,6 +42,7 @@ |
#include "webrtc/modules/audio_coding/neteq/post_decode_vad.h" |
#include "webrtc/modules/audio_coding/neteq/preemptive_expand.h" |
#include "webrtc/modules/audio_coding/neteq/sync_buffer.h" |
+#include "webrtc/modules/audio_coding/neteq/tick_timer.h" |
#include "webrtc/modules/audio_coding/neteq/timestamp_scaler.h" |
#include "webrtc/modules/include/module_common_types.h" |
@@ -53,6 +54,7 @@ |
namespace webrtc { |
NetEqImpl::NetEqImpl(const NetEq::Config& config, |
+ std::unique_ptr<TickTimer> tick_timer, |
BufferLevelFilter* buffer_level_filter, |
DecoderDatabase* decoder_database, |
DelayManager* delay_manager, |
@@ -66,7 +68,8 @@ NetEqImpl::NetEqImpl(const NetEq::Config& config, |
ExpandFactory* expand_factory, |
PreemptiveExpandFactory* preemptive_expand_factory, |
bool create_components) |
- : buffer_level_filter_(buffer_level_filter), |
+ : tick_timer_(std::move(tick_timer)), |
+ buffer_level_filter_(buffer_level_filter), |
decoder_database_(decoder_database), |
delay_manager_(delay_manager), |
delay_peak_detector_(delay_peak_detector), |
@@ -532,7 +535,8 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header, |
packet->header.numCSRCs = 0; |
packet->payload_length = payload.size(); |
packet->primary = true; |
- packet->waiting_time = 0; |
+ // Waiting time will be set upon inserting the packet in the buffer. |
+ RTC_DCHECK(!packet->waiting_time); |
packet->payload = new uint8_t[packet->payload_length]; |
packet->sync_packet = is_sync_packet; |
if (!packet->payload) { |
@@ -788,6 +792,8 @@ int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame) { |
DtmfEvent dtmf_event; |
Operations operation; |
bool play_dtmf; |
+ tick_timer_->Increment(); |
+ stats_.IncreaseCounter(output_size_samples_, fs_hz_); |
int return_value = GetDecision(&operation, &packet_list, &dtmf_event, |
&play_dtmf); |
if (return_value != 0) { |
@@ -806,6 +812,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: { |
@@ -978,6 +989,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; |
} |
@@ -990,10 +1007,6 @@ int NetEqImpl::GetDecision(Operations* operation, |
*play_dtmf = false; |
*operation = kUndefined; |
- // Increment time counters. |
- packet_buffer_->IncrementWaitingTimes(); |
- stats_.IncreaseCounter(output_size_samples_, fs_hz_); |
- |
assert(sync_buffer_.get()); |
uint32_t end_timestamp = sync_buffer_->end_timestamp(); |
if (!new_codec_) { |
@@ -1002,14 +1015,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. |
@@ -1037,7 +1058,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; |
} |
@@ -1045,13 +1066,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 |
@@ -1124,15 +1146,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: |
@@ -1215,9 +1241,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) { |
@@ -1550,6 +1573,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; |
} |
@@ -1920,8 +1949,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples, |
return -1; |
} |
stats_.PacketsDiscarded(discard_count); |
- // Store waiting time in ms; packets->waiting_time is in "output blocks". |
- stats_.StoreWaitingTime(packet->waiting_time * kOutputSizeMs); |
+ stats_.StoreWaitingTime(packet->waiting_time->ElapsedMs()); |
assert(packet->payload_length > 0); |
packet_list->push_back(packet); // Store packet in list. |
@@ -2094,11 +2122,9 @@ NetEqImpl::OutputType NetEqImpl::LastOutputType() { |
} |
void NetEqImpl::CreateDecisionLogic() { |
- decision_logic_.reset(DecisionLogic::Create(fs_hz_, output_size_samples_, |
- playout_mode_, |
- decoder_database_.get(), |
- *packet_buffer_.get(), |
- delay_manager_.get(), |
- buffer_level_filter_.get())); |
+ decision_logic_.reset(DecisionLogic::Create( |
+ fs_hz_, output_size_samples_, playout_mode_, decoder_database_.get(), |
+ *packet_buffer_.get(), delay_manager_.get(), buffer_level_filter_.get(), |
+ *tick_timer_)); |
} |
} // namespace webrtc |