| 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
|
|
|