NetEq: Deprecate playout modes Fax, Off and Streaming
The playout modes other than Normal have not been reachable for a long time, other than through tests. It is time to deprecate them. The only meaningful use was that Fax mode was sometimes set from tests, in order to avoid time-stretching operations (accelerate and pre-emptive expand) from messing with the test results. With this CL, a new config is added instead, which lets the user specify exactly this: don't do time-stretching. As a result of Fax and Off modes being removed, the following code clean-up was done: - Fold DecisionLogicNormal into DecisionLogic. - Remove AudioRepetition and AlternativePlc operations, since they can no longer be reached. Bug: webrtc:9421 Change-Id: I651458e9c1931a99f3b07e242817d303bac119df Reviewed-on: https://webrtc-review.googlesource.com/84123 Commit-Queue: Henrik Lundin <henrik.lundin@webrtc.org> Reviewed-by: Ivo Creusen <ivoc@webrtc.org> Reviewed-by: Minyue Li <minyue@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23704}
This commit is contained in:

committed by
Commit Bot

parent
c0260b4f2b
commit
80c4cca491
@ -1057,10 +1057,6 @@ rtc_static_library("neteq") {
|
|||||||
"neteq/cross_correlation.h",
|
"neteq/cross_correlation.h",
|
||||||
"neteq/decision_logic.cc",
|
"neteq/decision_logic.cc",
|
||||||
"neteq/decision_logic.h",
|
"neteq/decision_logic.h",
|
||||||
"neteq/decision_logic_fax.cc",
|
|
||||||
"neteq/decision_logic_fax.h",
|
|
||||||
"neteq/decision_logic_normal.cc",
|
|
||||||
"neteq/decision_logic_normal.h",
|
|
||||||
"neteq/decoder_database.cc",
|
"neteq/decoder_database.cc",
|
||||||
"neteq/decoder_database.h",
|
"neteq/decoder_database.h",
|
||||||
"neteq/defines.h",
|
"neteq/defines.h",
|
||||||
|
@ -292,7 +292,7 @@ TEST_F(AcmReceiverTestOldApi, MAYBE_SampleRate) {
|
|||||||
class AcmReceiverTestFaxModeOldApi : public AcmReceiverTestOldApi {
|
class AcmReceiverTestFaxModeOldApi : public AcmReceiverTestOldApi {
|
||||||
protected:
|
protected:
|
||||||
AcmReceiverTestFaxModeOldApi() {
|
AcmReceiverTestFaxModeOldApi() {
|
||||||
config_.neteq_config.playout_mode = kPlayoutFax;
|
config_.neteq_config.for_test_no_time_stretching = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunVerifyAudioFrame(RentACodec::CodecId codec_id) {
|
void RunVerifyAudioFrame(RentACodec::CodecId codec_id) {
|
||||||
@ -301,7 +301,7 @@ class AcmReceiverTestFaxModeOldApi : public AcmReceiverTestOldApi {
|
|||||||
// timestamp increments predictable; in normal mode, NetEq may decide to do
|
// timestamp increments predictable; in normal mode, NetEq may decide to do
|
||||||
// accelerate or pre-emptive expand operations after some time, offsetting
|
// accelerate or pre-emptive expand operations after some time, offsetting
|
||||||
// the timestamp.
|
// the timestamp.
|
||||||
EXPECT_EQ(kPlayoutFax, config_.neteq_config.playout_mode);
|
EXPECT_TRUE(config_.neteq_config.for_test_no_time_stretching);
|
||||||
|
|
||||||
const RentACodec::CodecId kCodecId[] = {codec_id};
|
const RentACodec::CodecId kCodecId[] = {codec_id};
|
||||||
AddSetOfCodecs(kCodecId);
|
AddSetOfCodecs(kCodecId);
|
||||||
|
@ -10,47 +10,37 @@
|
|||||||
|
|
||||||
#include "modules/audio_coding/neteq/decision_logic.h"
|
#include "modules/audio_coding/neteq/decision_logic.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "modules/audio_coding/neteq/buffer_level_filter.h"
|
#include "modules/audio_coding/neteq/buffer_level_filter.h"
|
||||||
#include "modules/audio_coding/neteq/decision_logic_fax.h"
|
#include "modules/audio_coding/neteq/decoder_database.h"
|
||||||
#include "modules/audio_coding/neteq/decision_logic_normal.h"
|
|
||||||
#include "modules/audio_coding/neteq/delay_manager.h"
|
#include "modules/audio_coding/neteq/delay_manager.h"
|
||||||
#include "modules/audio_coding/neteq/expand.h"
|
#include "modules/audio_coding/neteq/expand.h"
|
||||||
#include "modules/audio_coding/neteq/packet_buffer.h"
|
#include "modules/audio_coding/neteq/packet_buffer.h"
|
||||||
#include "modules/audio_coding/neteq/sync_buffer.h"
|
#include "modules/audio_coding/neteq/sync_buffer.h"
|
||||||
#include "modules/include/module_common_types.h"
|
#include "modules/include/module_common_types.h"
|
||||||
|
#include "system_wrappers/include/field_trial.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
DecisionLogic* DecisionLogic::Create(int fs_hz,
|
DecisionLogic* DecisionLogic::Create(int fs_hz,
|
||||||
size_t output_size_samples,
|
size_t output_size_samples,
|
||||||
NetEqPlayoutMode playout_mode,
|
bool disallow_time_stretching,
|
||||||
DecoderDatabase* decoder_database,
|
DecoderDatabase* decoder_database,
|
||||||
const PacketBuffer& packet_buffer,
|
const PacketBuffer& packet_buffer,
|
||||||
DelayManager* delay_manager,
|
DelayManager* delay_manager,
|
||||||
BufferLevelFilter* buffer_level_filter,
|
BufferLevelFilter* buffer_level_filter,
|
||||||
const TickTimer* tick_timer) {
|
const TickTimer* tick_timer) {
|
||||||
switch (playout_mode) {
|
return new DecisionLogic(fs_hz, output_size_samples, disallow_time_stretching,
|
||||||
case kPlayoutOn:
|
decoder_database, packet_buffer, delay_manager,
|
||||||
case kPlayoutStreaming:
|
buffer_level_filter, tick_timer);
|
||||||
return new DecisionLogicNormal(
|
|
||||||
fs_hz, output_size_samples, playout_mode, decoder_database,
|
|
||||||
packet_buffer, delay_manager, buffer_level_filter, tick_timer);
|
|
||||||
case kPlayoutFax:
|
|
||||||
case kPlayoutOff:
|
|
||||||
return new DecisionLogicFax(
|
|
||||||
fs_hz, output_size_samples, playout_mode, decoder_database,
|
|
||||||
packet_buffer, delay_manager, buffer_level_filter, tick_timer);
|
|
||||||
}
|
|
||||||
// This line cannot be reached, but must be here to avoid compiler errors.
|
|
||||||
assert(false);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DecisionLogic::DecisionLogic(int fs_hz,
|
DecisionLogic::DecisionLogic(int fs_hz,
|
||||||
size_t output_size_samples,
|
size_t output_size_samples,
|
||||||
NetEqPlayoutMode playout_mode,
|
bool disallow_time_stretching,
|
||||||
DecoderDatabase* decoder_database,
|
DecoderDatabase* decoder_database,
|
||||||
const PacketBuffer& packet_buffer,
|
const PacketBuffer& packet_buffer,
|
||||||
DelayManager* delay_manager,
|
DelayManager* delay_manager,
|
||||||
@ -65,11 +55,13 @@ DecisionLogic::DecisionLogic(int fs_hz,
|
|||||||
packet_length_samples_(0),
|
packet_length_samples_(0),
|
||||||
sample_memory_(0),
|
sample_memory_(0),
|
||||||
prev_time_scale_(false),
|
prev_time_scale_(false),
|
||||||
|
disallow_time_stretching_(disallow_time_stretching),
|
||||||
timescale_countdown_(
|
timescale_countdown_(
|
||||||
tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1)),
|
tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1)),
|
||||||
num_consecutive_expands_(0),
|
num_consecutive_expands_(0),
|
||||||
playout_mode_(playout_mode) {
|
postpone_decoding_after_expand_(field_trial::IsEnabled(
|
||||||
delay_manager_->set_streaming_mode(playout_mode_ == kPlayoutStreaming);
|
"WebRTC-Audio-NetEqPostponeDecodingAfterExpand")) {
|
||||||
|
delay_manager_->set_streaming_mode(false);
|
||||||
SetSampleRate(fs_hz, output_size_samples);
|
SetSampleRate(fs_hz, output_size_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,4 +160,228 @@ void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operations DecisionLogic::GetDecisionSpecialized(const SyncBuffer& sync_buffer,
|
||||||
|
const Expand& expand,
|
||||||
|
size_t decoder_frame_length,
|
||||||
|
const Packet* next_packet,
|
||||||
|
Modes prev_mode,
|
||||||
|
bool play_dtmf,
|
||||||
|
bool* reset_decoder,
|
||||||
|
size_t generated_noise_samples,
|
||||||
|
size_t cur_size_samples) {
|
||||||
|
// Guard for errors, to avoid getting stuck in error mode.
|
||||||
|
if (prev_mode == kModeError) {
|
||||||
|
if (!next_packet) {
|
||||||
|
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 (next_packet) {
|
||||||
|
available_timestamp = next_packet->timestamp;
|
||||||
|
is_cng_packet =
|
||||||
|
decoder_database_->IsComfortNoise(next_packet->payload_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_cng_packet) {
|
||||||
|
return CngOperation(prev_mode, target_timestamp, available_timestamp,
|
||||||
|
generated_noise_samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the case with no packet at all available (except maybe DTMF).
|
||||||
|
if (!next_packet) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we don't restart audio too soon after an expansion to avoid
|
||||||
|
// running out of data right away again. We should only wait if there are no
|
||||||
|
// DTX or CNG packets in the buffer (otherwise we should just play out what we
|
||||||
|
// have, since we cannot know the exact duration of DTX or CNG packets), and
|
||||||
|
// if the mute factor is low enough (otherwise the expansion was short enough
|
||||||
|
// to not be noticable).
|
||||||
|
// Note that the MuteFactor is in Q14, so a value of 16384 corresponds to 1.
|
||||||
|
if (postpone_decoding_after_expand_ && prev_mode == kModeExpand &&
|
||||||
|
!packet_buffer_.ContainsDtxOrCngPacket(decoder_database_) &&
|
||||||
|
cur_size_samples<static_cast<size_t>(delay_manager_->TargetLevel() *
|
||||||
|
packet_length_samples_)>> 8 &&
|
||||||
|
expand.MuteFactor(0) < 16384 / 2) {
|
||||||
|
return kExpand;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t five_seconds_samples =
|
||||||
|
static_cast<uint32_t>(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, generated_noise_samples);
|
||||||
|
} 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 DecisionLogic::CngOperation(Modes prev_mode,
|
||||||
|
uint32_t target_timestamp,
|
||||||
|
uint32_t available_timestamp,
|
||||||
|
size_t generated_noise_samples) {
|
||||||
|
// Signed difference between target and available timestamp.
|
||||||
|
int32_t timestamp_diff = static_cast<int32_t>(
|
||||||
|
static_cast<uint32_t>(generated_noise_samples + target_timestamp) -
|
||||||
|
available_timestamp);
|
||||||
|
int32_t optimal_level_samp = static_cast<int32_t>(
|
||||||
|
(delay_manager_->TargetLevel() * packet_length_samples_) >> 8);
|
||||||
|
const int64_t excess_waiting_time_samp =
|
||||||
|
-static_cast<int64_t>(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. Apply fast-forward to cut the
|
||||||
|
// waiting time down to the optimal.
|
||||||
|
noise_fast_forward_ = rtc::dchecked_cast<size_t>(noise_fast_forward_ +
|
||||||
|
excess_waiting_time_samp);
|
||||||
|
timestamp_diff =
|
||||||
|
rtc::saturated_cast<int32_t>(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.
|
||||||
|
noise_fast_forward_ = 0;
|
||||||
|
return kRfc3389Cng;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Operations DecisionLogic::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 DecisionLogic::ExpectedPacketAvailable(Modes prev_mode,
|
||||||
|
bool play_dtmf) {
|
||||||
|
if (!disallow_time_stretching_ && 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 << 2)
|
||||||
|
return kFastAccelerate;
|
||||||
|
if (TimescaleAllowed()) {
|
||||||
|
if (buffer_level_filter_->filtered_current_level() >= high_limit)
|
||||||
|
return kAccelerate;
|
||||||
|
if (buffer_level_filter_->filtered_current_level() < low_limit)
|
||||||
|
return kPreemptiveExpand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operations DecisionLogic::FuturePacketAvailable(
|
||||||
|
const SyncBuffer& sync_buffer,
|
||||||
|
const Expand& expand,
|
||||||
|
size_t decoder_frame_length,
|
||||||
|
Modes prev_mode,
|
||||||
|
uint32_t target_timestamp,
|
||||||
|
uint32_t available_timestamp,
|
||||||
|
bool play_dtmf,
|
||||||
|
size_t generated_noise_samples) {
|
||||||
|
// 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 size_t samples_left =
|
||||||
|
sync_buffer.FutureLength() - expand.overlap_length();
|
||||||
|
const size_t 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, 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.)
|
||||||
|
if (static_cast<uint32_t>(generated_noise_samples + target_timestamp) >=
|
||||||
|
available_timestamp ||
|
||||||
|
cur_size_samples >
|
||||||
|
((delay_manager_->TargetLevel() * packet_length_samples_) >> 8) *
|
||||||
|
4) {
|
||||||
|
// 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.
|
||||||
|
if (prev_mode == kModeExpand) {
|
||||||
|
return kMerge;
|
||||||
|
} else if (play_dtmf) {
|
||||||
|
// Play DTMF instead of expand.
|
||||||
|
return kDtmf;
|
||||||
|
} else {
|
||||||
|
return kExpand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecisionLogic::UnderTargetLevel() const {
|
||||||
|
return buffer_level_filter_->filtered_current_level() <=
|
||||||
|
delay_manager_->TargetLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecisionLogic::ReinitAfterExpands(uint32_t timestamp_leap) const {
|
||||||
|
return timestamp_leap >=
|
||||||
|
static_cast<uint32_t>(output_size_samples_ * kReinitAfterExpands);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecisionLogic::PacketTooEarly(uint32_t timestamp_leap) const {
|
||||||
|
return timestamp_leap >
|
||||||
|
static_cast<uint32_t>(output_size_samples_ * num_consecutive_expands_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecisionLogic::MaxWaitForPacket() const {
|
||||||
|
return num_consecutive_expands_ >= kMaxWaitForPacket;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -28,32 +28,34 @@ class PacketBuffer;
|
|||||||
class SyncBuffer;
|
class SyncBuffer;
|
||||||
struct Packet;
|
struct Packet;
|
||||||
|
|
||||||
// This is the base class for the decision tree implementations. Derived classes
|
// This is the class for the decision tree implementation.
|
||||||
// must implement the method GetDecisionSpecialized().
|
|
||||||
class DecisionLogic {
|
class DecisionLogic {
|
||||||
public:
|
public:
|
||||||
// Static factory function which creates different types of objects depending
|
// Static factory function which creates different types of objects depending
|
||||||
// on the |playout_mode|.
|
// on the |playout_mode|.
|
||||||
static DecisionLogic* Create(int fs_hz,
|
static DecisionLogic* Create(int fs_hz,
|
||||||
size_t output_size_samples,
|
size_t output_size_samples,
|
||||||
NetEqPlayoutMode playout_mode,
|
bool disallow_time_stretching,
|
||||||
DecoderDatabase* decoder_database,
|
DecoderDatabase* decoder_database,
|
||||||
const PacketBuffer& packet_buffer,
|
const PacketBuffer& packet_buffer,
|
||||||
DelayManager* delay_manager,
|
DelayManager* delay_manager,
|
||||||
BufferLevelFilter* buffer_level_filter,
|
BufferLevelFilter* buffer_level_filter,
|
||||||
const TickTimer* tick_timer);
|
const TickTimer* tick_timer);
|
||||||
|
|
||||||
|
static const int kReinitAfterExpands = 100;
|
||||||
|
static const int kMaxWaitForPacket = 10;
|
||||||
|
|
||||||
// Constructor.
|
// Constructor.
|
||||||
DecisionLogic(int fs_hz,
|
DecisionLogic(int fs_hz,
|
||||||
size_t output_size_samples,
|
size_t output_size_samples,
|
||||||
NetEqPlayoutMode playout_mode,
|
bool disallow_time_stretching,
|
||||||
DecoderDatabase* decoder_database,
|
DecoderDatabase* decoder_database,
|
||||||
const PacketBuffer& packet_buffer,
|
const PacketBuffer& packet_buffer,
|
||||||
DelayManager* delay_manager,
|
DelayManager* delay_manager,
|
||||||
BufferLevelFilter* buffer_level_filter,
|
BufferLevelFilter* buffer_level_filter,
|
||||||
const TickTimer* tick_timer);
|
const TickTimer* tick_timer);
|
||||||
|
|
||||||
virtual ~DecisionLogic();
|
~DecisionLogic();
|
||||||
|
|
||||||
// Resets object to a clean state.
|
// Resets object to a clean state.
|
||||||
void Reset();
|
void Reset();
|
||||||
@ -94,7 +96,7 @@ class DecisionLogic {
|
|||||||
// not. Note that this is necessary, since an expand decision can be changed
|
// not. Note that this is necessary, since an expand decision can be changed
|
||||||
// to kNormal in NetEqImpl::GetDecision if there is still enough data in the
|
// to kNormal in NetEqImpl::GetDecision if there is still enough data in the
|
||||||
// sync buffer.
|
// sync buffer.
|
||||||
virtual void ExpandDecision(Operations operation);
|
void ExpandDecision(Operations operation);
|
||||||
|
|
||||||
// Adds |value| to |sample_memory_|.
|
// Adds |value| to |sample_memory_|.
|
||||||
void AddSampleMemory(int32_t value) { sample_memory_ += value; }
|
void AddSampleMemory(int32_t value) { sample_memory_ += value; }
|
||||||
@ -107,14 +109,17 @@ class DecisionLogic {
|
|||||||
packet_length_samples_ = value;
|
packet_length_samples_ = value;
|
||||||
}
|
}
|
||||||
void set_prev_time_scale(bool value) { prev_time_scale_ = value; }
|
void set_prev_time_scale(bool value) { prev_time_scale_ = value; }
|
||||||
NetEqPlayoutMode playout_mode() const { return playout_mode_; }
|
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
// The value 5 sets maximum time-stretch rate to about 100 ms/s.
|
// The value 5 sets maximum time-stretch rate to about 100 ms/s.
|
||||||
static const int kMinTimescaleInterval = 5;
|
static const int kMinTimescaleInterval = 5;
|
||||||
|
|
||||||
enum CngState { kCngOff, kCngRfc3389On, kCngInternalOn };
|
enum CngState { kCngOff, kCngRfc3389On, kCngInternalOn };
|
||||||
|
|
||||||
|
// Updates the |buffer_level_filter_| with the current buffer level
|
||||||
|
// |buffer_size_packets|.
|
||||||
|
void FilterBufferLevel(size_t buffer_size_packets, Modes prev_mode);
|
||||||
|
|
||||||
// Returns the operation that should be done next. |sync_buffer| and |expand|
|
// Returns the operation that should be done next. |sync_buffer| and |expand|
|
||||||
// are provided for reference. |decoder_frame_length| is the number of samples
|
// are provided for reference. |decoder_frame_length| is the number of samples
|
||||||
// obtained from the last decoded frame. If there is a packet available, it
|
// obtained from the last decoded frame. If there is a packet available, it
|
||||||
@ -123,8 +128,9 @@ class DecisionLogic {
|
|||||||
// |prev_mode|. If there is a DTMF event to play, |play_dtmf| should be set to
|
// |prev_mode|. If there is a DTMF event to play, |play_dtmf| should be set to
|
||||||
// true. The output variable |reset_decoder| will be set to true if a reset is
|
// true. The output variable |reset_decoder| will be set to true if a reset is
|
||||||
// required; otherwise it is left unchanged (i.e., it can remain true if it
|
// required; otherwise it is left unchanged (i.e., it can remain true if it
|
||||||
// was true before the call). Should be implemented by derived classes.
|
// was true before the call).
|
||||||
virtual Operations GetDecisionSpecialized(const SyncBuffer& sync_buffer,
|
// TODO(henrik.lundin) Fold this method into GetDecision.
|
||||||
|
Operations GetDecisionSpecialized(const SyncBuffer& sync_buffer,
|
||||||
const Expand& expand,
|
const Expand& expand,
|
||||||
size_t decoder_frame_length,
|
size_t decoder_frame_length,
|
||||||
const Packet* next_packet,
|
const Packet* next_packet,
|
||||||
@ -132,11 +138,53 @@ class DecisionLogic {
|
|||||||
bool play_dtmf,
|
bool play_dtmf,
|
||||||
bool* reset_decoder,
|
bool* reset_decoder,
|
||||||
size_t generated_noise_samples,
|
size_t generated_noise_samples,
|
||||||
size_t cur_size_samples) = 0;
|
size_t cur_size_samples);
|
||||||
|
|
||||||
// Updates the |buffer_level_filter_| with the current buffer level
|
// Returns the operation given that the next available packet is a comfort
|
||||||
// |buffer_size_packets|.
|
// noise payload (RFC 3389 only, not codec-internal).
|
||||||
void FilterBufferLevel(size_t buffer_size_packets, Modes prev_mode);
|
Operations CngOperation(Modes prev_mode,
|
||||||
|
uint32_t target_timestamp,
|
||||||
|
uint32_t available_timestamp,
|
||||||
|
size_t generated_noise_samples);
|
||||||
|
|
||||||
|
// Returns the operation given that no packets are available (except maybe
|
||||||
|
// a DTMF event, flagged by setting |play_dtmf| true).
|
||||||
|
Operations NoPacket(bool play_dtmf);
|
||||||
|
|
||||||
|
// Returns the operation to do given that the expected packet is available.
|
||||||
|
Operations ExpectedPacketAvailable(Modes prev_mode, bool play_dtmf);
|
||||||
|
|
||||||
|
// Returns the operation to do given that the expected packet is not
|
||||||
|
// available, but a packet further into the future is at hand.
|
||||||
|
Operations FuturePacketAvailable(const SyncBuffer& sync_buffer,
|
||||||
|
const Expand& expand,
|
||||||
|
size_t decoder_frame_length,
|
||||||
|
Modes prev_mode,
|
||||||
|
uint32_t target_timestamp,
|
||||||
|
uint32_t available_timestamp,
|
||||||
|
bool play_dtmf,
|
||||||
|
size_t generated_noise_samples);
|
||||||
|
|
||||||
|
// Checks if enough time has elapsed since the last successful timescale
|
||||||
|
// operation was done (i.e., accelerate or preemptive expand).
|
||||||
|
bool TimescaleAllowed() const {
|
||||||
|
return !timescale_countdown_ || timescale_countdown_->Finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if the current (filtered) buffer level is under the target level.
|
||||||
|
bool UnderTargetLevel() const;
|
||||||
|
|
||||||
|
// Checks if |timestamp_leap| is so long into the future that a reset due
|
||||||
|
// to exceeding kReinitAfterExpands will be done.
|
||||||
|
bool ReinitAfterExpands(uint32_t timestamp_leap) const;
|
||||||
|
|
||||||
|
// Checks if we still have not done enough expands to cover the distance from
|
||||||
|
// the last decoded packet to the next available packet, the distance beeing
|
||||||
|
// conveyed in |timestamp_leap|.
|
||||||
|
bool PacketTooEarly(uint32_t timestamp_leap) const;
|
||||||
|
|
||||||
|
// Checks if num_consecutive_expands_ >= kMaxWaitForPacket.
|
||||||
|
bool MaxWaitForPacket() const;
|
||||||
|
|
||||||
DecoderDatabase* decoder_database_;
|
DecoderDatabase* decoder_database_;
|
||||||
const PacketBuffer& packet_buffer_;
|
const PacketBuffer& packet_buffer_;
|
||||||
@ -151,11 +199,11 @@ class DecisionLogic {
|
|||||||
size_t packet_length_samples_;
|
size_t packet_length_samples_;
|
||||||
int sample_memory_;
|
int sample_memory_;
|
||||||
bool prev_time_scale_;
|
bool prev_time_scale_;
|
||||||
|
bool disallow_time_stretching_;
|
||||||
std::unique_ptr<TickTimer::Countdown> timescale_countdown_;
|
std::unique_ptr<TickTimer::Countdown> timescale_countdown_;
|
||||||
int num_consecutive_expands_;
|
int num_consecutive_expands_;
|
||||||
const NetEqPlayoutMode playout_mode_;
|
const bool postpone_decoding_after_expand_;
|
||||||
|
|
||||||
private:
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogic);
|
RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogic);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "modules/audio_coding/neteq/decision_logic_fax.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "modules/audio_coding/neteq/decoder_database.h"
|
|
||||||
#include "modules/audio_coding/neteq/sync_buffer.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
Operations DecisionLogicFax::GetDecisionSpecialized(
|
|
||||||
const SyncBuffer& sync_buffer,
|
|
||||||
const Expand& expand,
|
|
||||||
size_t decoder_frame_length,
|
|
||||||
const Packet* next_packet,
|
|
||||||
Modes prev_mode,
|
|
||||||
bool play_dtmf,
|
|
||||||
bool* reset_decoder,
|
|
||||||
size_t generated_noise_samples,
|
|
||||||
size_t /*cur_size_samples*/) {
|
|
||||||
assert(playout_mode_ == kPlayoutFax || playout_mode_ == kPlayoutOff);
|
|
||||||
uint32_t target_timestamp = sync_buffer.end_timestamp();
|
|
||||||
uint32_t available_timestamp = 0;
|
|
||||||
int is_cng_packet = 0;
|
|
||||||
if (next_packet) {
|
|
||||||
available_timestamp = next_packet->timestamp;
|
|
||||||
is_cng_packet =
|
|
||||||
decoder_database_->IsComfortNoise(next_packet->payload_type);
|
|
||||||
}
|
|
||||||
if (is_cng_packet) {
|
|
||||||
if (static_cast<int32_t>((generated_noise_samples + target_timestamp) -
|
|
||||||
available_timestamp) >= 0) {
|
|
||||||
// Time to play this packet now.
|
|
||||||
return kRfc3389Cng;
|
|
||||||
} else {
|
|
||||||
// Wait before playing this packet.
|
|
||||||
return kRfc3389CngNoPacket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!next_packet) {
|
|
||||||
// No packet. If in CNG mode, play as usual. Otherwise, use other method to
|
|
||||||
// generate data.
|
|
||||||
if (cng_state_ == kCngRfc3389On) {
|
|
||||||
// Continue playing comfort noise.
|
|
||||||
return kRfc3389CngNoPacket;
|
|
||||||
} else if (cng_state_ == kCngInternalOn) {
|
|
||||||
// Continue playing codec-internal comfort noise.
|
|
||||||
return kCodecInternalCng;
|
|
||||||
} else {
|
|
||||||
// Nothing to play. Generate some data to play out.
|
|
||||||
switch (playout_mode_) {
|
|
||||||
case kPlayoutOff:
|
|
||||||
return kAlternativePlc;
|
|
||||||
case kPlayoutFax:
|
|
||||||
return kAudioRepetition;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
return kUndefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (target_timestamp == available_timestamp) {
|
|
||||||
return kNormal;
|
|
||||||
} else {
|
|
||||||
if (static_cast<int32_t>((generated_noise_samples + target_timestamp) -
|
|
||||||
available_timestamp) >= 0) {
|
|
||||||
return kNormal;
|
|
||||||
} else {
|
|
||||||
// If currently playing comfort noise, continue with that. Do not
|
|
||||||
// increase the timestamp counter since generated_noise_stopwatch_ in
|
|
||||||
// NetEqImpl will take care of the time-keeping.
|
|
||||||
if (cng_state_ == kCngRfc3389On) {
|
|
||||||
return kRfc3389CngNoPacket;
|
|
||||||
} else if (cng_state_ == kCngInternalOn) {
|
|
||||||
return kCodecInternalCng;
|
|
||||||
} else {
|
|
||||||
// Otherwise, do packet-loss concealment and increase the
|
|
||||||
// timestamp while waiting for the time to play this packet.
|
|
||||||
switch (playout_mode_) {
|
|
||||||
case kPlayoutOff:
|
|
||||||
return kAlternativePlcIncreaseTimestamp;
|
|
||||||
case kPlayoutFax:
|
|
||||||
return kAudioRepetitionIncreaseTimestamp;
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
return kUndefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_FAX_H_
|
|
||||||
#define MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_FAX_H_
|
|
||||||
|
|
||||||
#include "modules/audio_coding/neteq/decision_logic.h"
|
|
||||||
#include "rtc_base/constructormagic.h"
|
|
||||||
#include "typedefs.h" // NOLINT(build/include)
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
// Implementation of the DecisionLogic class for playout modes kPlayoutFax and
|
|
||||||
// kPlayoutOff.
|
|
||||||
class DecisionLogicFax : public DecisionLogic {
|
|
||||||
public:
|
|
||||||
// Constructor.
|
|
||||||
DecisionLogicFax(int fs_hz,
|
|
||||||
size_t output_size_samples,
|
|
||||||
NetEqPlayoutMode playout_mode,
|
|
||||||
DecoderDatabase* decoder_database,
|
|
||||||
const PacketBuffer& packet_buffer,
|
|
||||||
DelayManager* delay_manager,
|
|
||||||
BufferLevelFilter* buffer_level_filter,
|
|
||||||
const TickTimer* tick_timer)
|
|
||||||
: DecisionLogic(fs_hz,
|
|
||||||
output_size_samples,
|
|
||||||
playout_mode,
|
|
||||||
decoder_database,
|
|
||||||
packet_buffer,
|
|
||||||
delay_manager,
|
|
||||||
buffer_level_filter,
|
|
||||||
tick_timer) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Operations GetDecisionSpecialized(const SyncBuffer& sync_buffer,
|
|
||||||
const Expand& expand,
|
|
||||||
size_t decoder_frame_length,
|
|
||||||
const Packet* next_packet,
|
|
||||||
Modes prev_mode,
|
|
||||||
bool play_dtmf,
|
|
||||||
bool* reset_decoder,
|
|
||||||
size_t generated_noise_samples,
|
|
||||||
size_t cur_size_samples) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogicFax);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
#endif // MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_FAX_H_
|
|
@ -1,253 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "modules/audio_coding/neteq/decision_logic_normal.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include "modules/audio_coding/neteq/buffer_level_filter.h"
|
|
||||||
#include "modules/audio_coding/neteq/decoder_database.h"
|
|
||||||
#include "modules/audio_coding/neteq/delay_manager.h"
|
|
||||||
#include "modules/audio_coding/neteq/expand.h"
|
|
||||||
#include "modules/audio_coding/neteq/packet_buffer.h"
|
|
||||||
#include "modules/audio_coding/neteq/sync_buffer.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
Operations DecisionLogicNormal::GetDecisionSpecialized(
|
|
||||||
const SyncBuffer& sync_buffer,
|
|
||||||
const Expand& expand,
|
|
||||||
size_t decoder_frame_length,
|
|
||||||
const Packet* next_packet,
|
|
||||||
Modes prev_mode,
|
|
||||||
bool play_dtmf,
|
|
||||||
bool* reset_decoder,
|
|
||||||
size_t generated_noise_samples,
|
|
||||||
size_t cur_size_samples) {
|
|
||||||
assert(playout_mode_ == kPlayoutOn || playout_mode_ == kPlayoutStreaming);
|
|
||||||
// Guard for errors, to avoid getting stuck in error mode.
|
|
||||||
if (prev_mode == kModeError) {
|
|
||||||
if (!next_packet) {
|
|
||||||
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 (next_packet) {
|
|
||||||
available_timestamp = next_packet->timestamp;
|
|
||||||
is_cng_packet =
|
|
||||||
decoder_database_->IsComfortNoise(next_packet->payload_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_cng_packet) {
|
|
||||||
return CngOperation(prev_mode, target_timestamp, available_timestamp,
|
|
||||||
generated_noise_samples);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the case with no packet at all available (except maybe DTMF).
|
|
||||||
if (!next_packet) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we don't restart audio too soon after an expansion to avoid
|
|
||||||
// running out of data right away again. We should only wait if there are no
|
|
||||||
// DTX or CNG packets in the buffer (otherwise we should just play out what we
|
|
||||||
// have, since we cannot know the exact duration of DTX or CNG packets), and
|
|
||||||
// if the mute factor is low enough (otherwise the expansion was short enough
|
|
||||||
// to not be noticable).
|
|
||||||
// Note that the MuteFactor is in Q14, so a value of 16384 corresponds to 1.
|
|
||||||
if (postpone_decoding_after_expand_ && prev_mode == kModeExpand &&
|
|
||||||
!packet_buffer_.ContainsDtxOrCngPacket(decoder_database_) &&
|
|
||||||
cur_size_samples<static_cast<size_t>(delay_manager_->TargetLevel() *
|
|
||||||
packet_length_samples_)>> 8 &&
|
|
||||||
expand.MuteFactor(0) < 16384 / 2) {
|
|
||||||
return kExpand;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32_t five_seconds_samples =
|
|
||||||
static_cast<uint32_t>(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, generated_noise_samples);
|
|
||||||
} 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,
|
|
||||||
size_t generated_noise_samples) {
|
|
||||||
// Signed difference between target and available timestamp.
|
|
||||||
int32_t timestamp_diff = static_cast<int32_t>(
|
|
||||||
static_cast<uint32_t>(generated_noise_samples + target_timestamp) -
|
|
||||||
available_timestamp);
|
|
||||||
int32_t optimal_level_samp = static_cast<int32_t>(
|
|
||||||
(delay_manager_->TargetLevel() * packet_length_samples_) >> 8);
|
|
||||||
const int64_t excess_waiting_time_samp =
|
|
||||||
-static_cast<int64_t>(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. Apply fast-forward to cut the
|
|
||||||
// waiting time down to the optimal.
|
|
||||||
noise_fast_forward_ = rtc::dchecked_cast<size_t>(noise_fast_forward_ +
|
|
||||||
excess_waiting_time_samp);
|
|
||||||
timestamp_diff =
|
|
||||||
rtc::saturated_cast<int32_t>(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.
|
|
||||||
noise_fast_forward_ = 0;
|
|
||||||
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 << 2)
|
|
||||||
return kFastAccelerate;
|
|
||||||
if (TimescaleAllowed()) {
|
|
||||||
if (buffer_level_filter_->filtered_current_level() >= high_limit)
|
|
||||||
return kAccelerate;
|
|
||||||
if (buffer_level_filter_->filtered_current_level() < low_limit)
|
|
||||||
return kPreemptiveExpand;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return kNormal;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operations DecisionLogicNormal::FuturePacketAvailable(
|
|
||||||
const SyncBuffer& sync_buffer,
|
|
||||||
const Expand& expand,
|
|
||||||
size_t decoder_frame_length,
|
|
||||||
Modes prev_mode,
|
|
||||||
uint32_t target_timestamp,
|
|
||||||
uint32_t available_timestamp,
|
|
||||||
bool play_dtmf,
|
|
||||||
size_t generated_noise_samples) {
|
|
||||||
// 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 size_t samples_left =
|
|
||||||
sync_buffer.FutureLength() - expand.overlap_length();
|
|
||||||
const size_t 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, 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.)
|
|
||||||
if (static_cast<uint32_t>(generated_noise_samples + target_timestamp) >=
|
|
||||||
available_timestamp ||
|
|
||||||
cur_size_samples >
|
|
||||||
((delay_manager_->TargetLevel() * packet_length_samples_) >> 8) *
|
|
||||||
4) {
|
|
||||||
// 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.
|
|
||||||
if (prev_mode == kModeExpand) {
|
|
||||||
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
|
|
@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_NORMAL_H_
|
|
||||||
#define MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_NORMAL_H_
|
|
||||||
|
|
||||||
#include "modules/audio_coding/neteq/decision_logic.h"
|
|
||||||
#include "rtc_base/constructormagic.h"
|
|
||||||
#include "system_wrappers/include/field_trial.h"
|
|
||||||
#include "typedefs.h" // NOLINT(build/include)
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
// Implementation of the DecisionLogic class for playout modes kPlayoutOn and
|
|
||||||
// kPlayoutStreaming.
|
|
||||||
class DecisionLogicNormal : public DecisionLogic {
|
|
||||||
public:
|
|
||||||
// Constructor.
|
|
||||||
DecisionLogicNormal(int fs_hz,
|
|
||||||
size_t output_size_samples,
|
|
||||||
NetEqPlayoutMode playout_mode,
|
|
||||||
DecoderDatabase* decoder_database,
|
|
||||||
const PacketBuffer& packet_buffer,
|
|
||||||
DelayManager* delay_manager,
|
|
||||||
BufferLevelFilter* buffer_level_filter,
|
|
||||||
const TickTimer* tick_timer)
|
|
||||||
: DecisionLogic(fs_hz,
|
|
||||||
output_size_samples,
|
|
||||||
playout_mode,
|
|
||||||
decoder_database,
|
|
||||||
packet_buffer,
|
|
||||||
delay_manager,
|
|
||||||
buffer_level_filter,
|
|
||||||
tick_timer),
|
|
||||||
postpone_decoding_after_expand_(field_trial::IsEnabled(
|
|
||||||
"WebRTC-Audio-NetEqPostponeDecodingAfterExpand")) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static const int kReinitAfterExpands = 100;
|
|
||||||
static const int kMaxWaitForPacket = 10;
|
|
||||||
|
|
||||||
Operations GetDecisionSpecialized(const SyncBuffer& sync_buffer,
|
|
||||||
const Expand& expand,
|
|
||||||
size_t decoder_frame_length,
|
|
||||||
const Packet* next_packet,
|
|
||||||
Modes prev_mode,
|
|
||||||
bool play_dtmf,
|
|
||||||
bool* reset_decoder,
|
|
||||||
size_t generated_noise_samples,
|
|
||||||
size_t cur_size_samples) override;
|
|
||||||
|
|
||||||
// Returns the operation to do given that the expected packet is not
|
|
||||||
// available, but a packet further into the future is at hand.
|
|
||||||
virtual Operations FuturePacketAvailable(const SyncBuffer& sync_buffer,
|
|
||||||
const Expand& expand,
|
|
||||||
size_t decoder_frame_length,
|
|
||||||
Modes prev_mode,
|
|
||||||
uint32_t target_timestamp,
|
|
||||||
uint32_t available_timestamp,
|
|
||||||
bool play_dtmf,
|
|
||||||
size_t generated_noise_samples);
|
|
||||||
|
|
||||||
// Returns the operation to do given that the expected packet is available.
|
|
||||||
virtual Operations ExpectedPacketAvailable(Modes prev_mode, bool play_dtmf);
|
|
||||||
|
|
||||||
// Returns the operation given that no packets are available (except maybe
|
|
||||||
// a DTMF event, flagged by setting |play_dtmf| true).
|
|
||||||
virtual Operations NoPacket(bool play_dtmf);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Returns the operation given that the next available packet is a comfort
|
|
||||||
// noise payload (RFC 3389 only, not codec-internal).
|
|
||||||
Operations CngOperation(Modes prev_mode,
|
|
||||||
uint32_t target_timestamp,
|
|
||||||
uint32_t available_timestamp,
|
|
||||||
size_t generated_noise_samples);
|
|
||||||
|
|
||||||
// Checks if enough time has elapsed since the last successful timescale
|
|
||||||
// operation was done (i.e., accelerate or preemptive expand).
|
|
||||||
bool TimescaleAllowed() const {
|
|
||||||
return !timescale_countdown_ || timescale_countdown_->Finished();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if the current (filtered) buffer level is under the target level.
|
|
||||||
bool UnderTargetLevel() const;
|
|
||||||
|
|
||||||
// Checks if |timestamp_leap| is so long into the future that a reset due
|
|
||||||
// to exceeding kReinitAfterExpands will be done.
|
|
||||||
bool ReinitAfterExpands(uint32_t timestamp_leap) const;
|
|
||||||
|
|
||||||
// Checks if we still have not done enough expands to cover the distance from
|
|
||||||
// the last decoded packet to the next available packet, the distance beeing
|
|
||||||
// conveyed in |timestamp_leap|.
|
|
||||||
bool PacketTooEarly(uint32_t timestamp_leap) const;
|
|
||||||
|
|
||||||
// Checks if num_consecutive_expands_ >= kMaxWaitForPacket.
|
|
||||||
bool MaxWaitForPacket() const;
|
|
||||||
|
|
||||||
const bool postpone_decoding_after_expand_;
|
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogicNormal);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
#endif // MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_NORMAL_H_
|
|
@ -33,19 +33,7 @@ TEST(DecisionLogic, CreateAndDestroy) {
|
|||||||
DelayManager delay_manager(240, &delay_peak_detector, &tick_timer);
|
DelayManager delay_manager(240, &delay_peak_detector, &tick_timer);
|
||||||
BufferLevelFilter buffer_level_filter;
|
BufferLevelFilter buffer_level_filter;
|
||||||
DecisionLogic* logic = DecisionLogic::Create(
|
DecisionLogic* logic = DecisionLogic::Create(
|
||||||
fs_hz, output_size_samples, kPlayoutOn, &decoder_database, packet_buffer,
|
fs_hz, output_size_samples, false, &decoder_database, packet_buffer,
|
||||||
&delay_manager, &buffer_level_filter, &tick_timer);
|
|
||||||
delete logic;
|
|
||||||
logic = DecisionLogic::Create(
|
|
||||||
fs_hz, output_size_samples, kPlayoutStreaming, &decoder_database,
|
|
||||||
packet_buffer, &delay_manager, &buffer_level_filter, &tick_timer);
|
|
||||||
delete logic;
|
|
||||||
logic = DecisionLogic::Create(
|
|
||||||
fs_hz, output_size_samples, kPlayoutFax, &decoder_database, packet_buffer,
|
|
||||||
&delay_manager, &buffer_level_filter, &tick_timer);
|
|
||||||
delete logic;
|
|
||||||
logic = DecisionLogic::Create(
|
|
||||||
fs_hz, output_size_samples, kPlayoutOff, &decoder_database, packet_buffer,
|
|
||||||
&delay_manager, &buffer_level_filter, &tick_timer);
|
&delay_manager, &buffer_level_filter, &tick_timer);
|
||||||
delete logic;
|
delete logic;
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,6 @@ enum Operations {
|
|||||||
kRfc3389CngNoPacket,
|
kRfc3389CngNoPacket,
|
||||||
kCodecInternalCng,
|
kCodecInternalCng,
|
||||||
kDtmf,
|
kDtmf,
|
||||||
kAlternativePlc,
|
|
||||||
kAlternativePlcIncreaseTimestamp,
|
|
||||||
kAudioRepetition,
|
|
||||||
kAudioRepetitionIncreaseTimestamp,
|
|
||||||
kUndefined = -1
|
kUndefined = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,13 +74,6 @@ struct NetEqLifetimeStatistics {
|
|||||||
uint64_t voice_concealed_samples = 0;
|
uint64_t voice_concealed_samples = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NetEqPlayoutMode {
|
|
||||||
kPlayoutOn,
|
|
||||||
kPlayoutOff,
|
|
||||||
kPlayoutFax,
|
|
||||||
kPlayoutStreaming
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is the interface class for NetEq.
|
// This is the interface class for NetEq.
|
||||||
class NetEq {
|
class NetEq {
|
||||||
public:
|
public:
|
||||||
@ -98,10 +91,10 @@ class NetEq {
|
|||||||
bool enable_post_decode_vad = false;
|
bool enable_post_decode_vad = false;
|
||||||
size_t max_packets_in_buffer = 50;
|
size_t max_packets_in_buffer = 50;
|
||||||
int max_delay_ms = 2000;
|
int max_delay_ms = 2000;
|
||||||
NetEqPlayoutMode playout_mode = kPlayoutOn;
|
|
||||||
bool enable_fast_accelerate = false;
|
bool enable_fast_accelerate = false;
|
||||||
bool enable_muted_state = false;
|
bool enable_muted_state = false;
|
||||||
absl::optional<AudioCodecPairId> codec_pair_id;
|
absl::optional<AudioCodecPairId> codec_pair_id;
|
||||||
|
bool for_test_no_time_stretching = false; // Use only for testing.
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ReturnCodes { kOK = 0, kFail = -1, kNotImplemented = -2 };
|
enum ReturnCodes { kOK = 0, kFail = -1, kNotImplemented = -2 };
|
||||||
@ -209,16 +202,6 @@ class NetEq {
|
|||||||
// The packet buffer part of the delay is not updated during DTX/CNG periods.
|
// The packet buffer part of the delay is not updated during DTX/CNG periods.
|
||||||
virtual int FilteredCurrentDelayMs() const = 0;
|
virtual int FilteredCurrentDelayMs() const = 0;
|
||||||
|
|
||||||
// Sets the playout mode to |mode|.
|
|
||||||
// Deprecated. Set the mode in the Config struct passed to the constructor.
|
|
||||||
// TODO(henrik.lundin) Delete.
|
|
||||||
virtual void SetPlayoutMode(NetEqPlayoutMode mode) = 0;
|
|
||||||
|
|
||||||
// Returns the current playout mode.
|
|
||||||
// Deprecated.
|
|
||||||
// TODO(henrik.lundin) Delete.
|
|
||||||
virtual NetEqPlayoutMode PlayoutMode() const = 0;
|
|
||||||
|
|
||||||
// Writes the current network statistics to |stats|. The statistics are reset
|
// Writes the current network statistics to |stats|. The statistics are reset
|
||||||
// after the call.
|
// after the call.
|
||||||
virtual int NetworkStatistics(NetEqNetworkStatistics* stats) = 0;
|
virtual int NetworkStatistics(NetEqNetworkStatistics* stats) = 0;
|
||||||
|
@ -30,7 +30,7 @@ std::string NetEq::Config::ToString() const {
|
|||||||
ss << "sample_rate_hz=" << sample_rate_hz << ", enable_post_decode_vad="
|
ss << "sample_rate_hz=" << sample_rate_hz << ", enable_post_decode_vad="
|
||||||
<< (enable_post_decode_vad ? "true" : "false")
|
<< (enable_post_decode_vad ? "true" : "false")
|
||||||
<< ", max_packets_in_buffer=" << max_packets_in_buffer
|
<< ", max_packets_in_buffer=" << max_packets_in_buffer
|
||||||
<< ", playout_mode=" << playout_mode << ", enable_fast_accelerate="
|
<< ", enable_fast_accelerate="
|
||||||
<< (enable_fast_accelerate ? " true" : "false")
|
<< (enable_fast_accelerate ? " true" : "false")
|
||||||
<< ", enable_muted_state=" << (enable_muted_state ? " true" : "false");
|
<< ", enable_muted_state=" << (enable_muted_state ? " true" : "false");
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
@ -101,7 +101,6 @@ NetEqImpl::NetEqImpl(const NetEq::Config& config,
|
|||||||
reset_decoder_(false),
|
reset_decoder_(false),
|
||||||
ssrc_(0),
|
ssrc_(0),
|
||||||
first_packet_(true),
|
first_packet_(true),
|
||||||
playout_mode_(config.playout_mode),
|
|
||||||
enable_fast_accelerate_(config.enable_fast_accelerate),
|
enable_fast_accelerate_(config.enable_fast_accelerate),
|
||||||
nack_enabled_(false),
|
nack_enabled_(false),
|
||||||
enable_muted_state_(config.enable_muted_state),
|
enable_muted_state_(config.enable_muted_state),
|
||||||
@ -110,7 +109,8 @@ NetEqImpl::NetEqImpl(const NetEq::Config& config,
|
|||||||
tick_timer_.get()),
|
tick_timer_.get()),
|
||||||
speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent",
|
speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent",
|
||||||
10, // Report once every 10 s.
|
10, // Report once every 10 s.
|
||||||
tick_timer_.get()) {
|
tick_timer_.get()),
|
||||||
|
no_time_stretching_(config.for_test_no_time_stretching) {
|
||||||
RTC_LOG(LS_INFO) << "NetEq config: " << config.ToString();
|
RTC_LOG(LS_INFO) << "NetEq config: " << config.ToString();
|
||||||
int fs = config.sample_rate_hz;
|
int fs = config.sample_rate_hz;
|
||||||
if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
|
if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
|
||||||
@ -358,23 +358,6 @@ int NetEqImpl::FilteredCurrentDelayMs() const {
|
|||||||
return static_cast<int>(delay_samples) / rtc::CheckedDivExact(fs_hz_, 1000);
|
return static_cast<int>(delay_samples) / rtc::CheckedDivExact(fs_hz_, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated.
|
|
||||||
// TODO(henrik.lundin) Delete.
|
|
||||||
void NetEqImpl::SetPlayoutMode(NetEqPlayoutMode mode) {
|
|
||||||
rtc::CritScope lock(&crit_sect_);
|
|
||||||
if (mode != playout_mode_) {
|
|
||||||
playout_mode_ = mode;
|
|
||||||
CreateDecisionLogic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated.
|
|
||||||
// TODO(henrik.lundin) Delete.
|
|
||||||
NetEqPlayoutMode NetEqImpl::PlayoutMode() const {
|
|
||||||
rtc::CritScope lock(&crit_sect_);
|
|
||||||
return playout_mode_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) {
|
int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) {
|
||||||
rtc::CritScope lock(&crit_sect_);
|
rtc::CritScope lock(&crit_sect_);
|
||||||
assert(decoder_database_.get());
|
assert(decoder_database_.get());
|
||||||
@ -937,33 +920,6 @@ int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame, bool* muted) {
|
|||||||
return_value = DoDtmf(dtmf_event, &play_dtmf);
|
return_value = DoDtmf(dtmf_event, &play_dtmf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kAlternativePlc: {
|
|
||||||
// TODO(hlundin): Write test for this.
|
|
||||||
DoAlternativePlc(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kAlternativePlcIncreaseTimestamp: {
|
|
||||||
// TODO(hlundin): Write test for this.
|
|
||||||
DoAlternativePlc(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kAudioRepetitionIncreaseTimestamp: {
|
|
||||||
// TODO(hlundin): Write test for this.
|
|
||||||
sync_buffer_->IncreaseEndTimestamp(
|
|
||||||
static_cast<uint32_t>(output_size_samples_));
|
|
||||||
// Skipping break on purpose. Execution should move on into the
|
|
||||||
// next case.
|
|
||||||
RTC_FALLTHROUGH();
|
|
||||||
}
|
|
||||||
case kAudioRepetition: {
|
|
||||||
// TODO(hlundin): Write test for this.
|
|
||||||
// Copy last |output_size_samples_| from |sync_buffer_| to
|
|
||||||
// |algorithm_buffer|.
|
|
||||||
algorithm_buffer_->PushBackFromIndex(
|
|
||||||
*sync_buffer_, sync_buffer_->Size() - output_size_samples_);
|
|
||||||
expand_->Reset();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kUndefined: {
|
case kUndefined: {
|
||||||
RTC_LOG(LS_ERROR) << "Invalid operation kUndefined.";
|
RTC_LOG(LS_ERROR) << "Invalid operation kUndefined.";
|
||||||
assert(false); // This should not happen.
|
assert(false); // This should not happen.
|
||||||
@ -1291,10 +1247,7 @@ int NetEqImpl::GetDecision(Operations* operation,
|
|||||||
|
|
||||||
// Get packets from buffer.
|
// Get packets from buffer.
|
||||||
int extracted_samples = 0;
|
int extracted_samples = 0;
|
||||||
if (packet && *operation != kAlternativePlc &&
|
if (packet) {
|
||||||
*operation != kAlternativePlcIncreaseTimestamp &&
|
|
||||||
*operation != kAudioRepetition &&
|
|
||||||
*operation != kAudioRepetitionIncreaseTimestamp) {
|
|
||||||
sync_buffer_->IncreaseEndTimestamp(packet->timestamp - end_timestamp);
|
sync_buffer_->IncreaseEndTimestamp(packet->timestamp - end_timestamp);
|
||||||
if (decision_logic_->CngOff()) {
|
if (decision_logic_->CngOff()) {
|
||||||
// Adjustment of timestamp only corresponds to an actual packet loss
|
// Adjustment of timestamp only corresponds to an actual packet loss
|
||||||
@ -1883,29 +1836,6 @@ int NetEqImpl::DoDtmf(const DtmfEvent& dtmf_event, bool* play_dtmf) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetEqImpl::DoAlternativePlc(bool increase_timestamp) {
|
|
||||||
AudioDecoder* decoder = decoder_database_->GetActiveDecoder();
|
|
||||||
size_t length;
|
|
||||||
if (decoder && decoder->HasDecodePlc()) {
|
|
||||||
// Use the decoder's packet-loss concealment.
|
|
||||||
// TODO(hlundin): Will probably need a longer buffer for multi-channel.
|
|
||||||
int16_t decoded_buffer[kMaxFrameSize];
|
|
||||||
length = decoder->DecodePlc(1, decoded_buffer);
|
|
||||||
if (length > 0)
|
|
||||||
algorithm_buffer_->PushBackInterleaved(decoded_buffer, length);
|
|
||||||
} else {
|
|
||||||
// Do simple zero-stuffing.
|
|
||||||
length = output_size_samples_;
|
|
||||||
algorithm_buffer_->Zeros(length);
|
|
||||||
// By not advancing the timestamp, NetEq inserts samples.
|
|
||||||
stats_.AddZeros(length);
|
|
||||||
}
|
|
||||||
if (increase_timestamp) {
|
|
||||||
sync_buffer_->IncreaseEndTimestamp(static_cast<uint32_t>(length));
|
|
||||||
}
|
|
||||||
expand_->Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
int NetEqImpl::DtmfOverdub(const DtmfEvent& dtmf_event,
|
int NetEqImpl::DtmfOverdub(const DtmfEvent& dtmf_event,
|
||||||
size_t num_channels,
|
size_t num_channels,
|
||||||
int16_t* output) const {
|
int16_t* output) const {
|
||||||
@ -2130,8 +2060,8 @@ NetEqImpl::OutputType NetEqImpl::LastOutputType() {
|
|||||||
|
|
||||||
void NetEqImpl::CreateDecisionLogic() {
|
void NetEqImpl::CreateDecisionLogic() {
|
||||||
decision_logic_.reset(DecisionLogic::Create(
|
decision_logic_.reset(DecisionLogic::Create(
|
||||||
fs_hz_, output_size_samples_, playout_mode_, decoder_database_.get(),
|
fs_hz_, output_size_samples_, no_time_stretching_,
|
||||||
*packet_buffer_.get(), delay_manager_.get(), buffer_level_filter_.get(),
|
decoder_database_.get(), *packet_buffer_.get(), delay_manager_.get(),
|
||||||
tick_timer_.get()));
|
buffer_level_filter_.get(), tick_timer_.get()));
|
||||||
}
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -168,16 +168,6 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
|
|
||||||
int FilteredCurrentDelayMs() const override;
|
int FilteredCurrentDelayMs() const override;
|
||||||
|
|
||||||
// Sets the playout mode to |mode|.
|
|
||||||
// Deprecated.
|
|
||||||
// TODO(henrik.lundin) Delete.
|
|
||||||
void SetPlayoutMode(NetEqPlayoutMode mode) override;
|
|
||||||
|
|
||||||
// Returns the current playout mode.
|
|
||||||
// Deprecated.
|
|
||||||
// TODO(henrik.lundin) Delete.
|
|
||||||
NetEqPlayoutMode PlayoutMode() const override;
|
|
||||||
|
|
||||||
// Writes the current network statistics to |stats|. The statistics are reset
|
// Writes the current network statistics to |stats|. The statistics are reset
|
||||||
// after the call.
|
// after the call.
|
||||||
int NetworkStatistics(NetEqNetworkStatistics* stats) override;
|
int NetworkStatistics(NetEqNetworkStatistics* stats) override;
|
||||||
@ -336,12 +326,6 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
int DoDtmf(const DtmfEvent& dtmf_event, bool* play_dtmf)
|
int DoDtmf(const DtmfEvent& dtmf_event, bool* play_dtmf)
|
||||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
|
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
|
||||||
|
|
||||||
// Produces packet-loss concealment using alternative methods. If the codec
|
|
||||||
// has an internal PLC, it is called to generate samples. Otherwise, the
|
|
||||||
// method performs zero-stuffing.
|
|
||||||
void DoAlternativePlc(bool increase_timestamp)
|
|
||||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
|
|
||||||
|
|
||||||
// Overdub DTMF on top of |output|.
|
// Overdub DTMF on top of |output|.
|
||||||
int DtmfOverdub(const DtmfEvent& dtmf_event,
|
int DtmfOverdub(const DtmfEvent& dtmf_event,
|
||||||
size_t num_channels,
|
size_t num_channels,
|
||||||
@ -429,7 +413,6 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
RTC_GUARDED_BY(crit_sect_);
|
RTC_GUARDED_BY(crit_sect_);
|
||||||
uint32_t ssrc_ RTC_GUARDED_BY(crit_sect_);
|
uint32_t ssrc_ RTC_GUARDED_BY(crit_sect_);
|
||||||
bool first_packet_ RTC_GUARDED_BY(crit_sect_);
|
bool first_packet_ RTC_GUARDED_BY(crit_sect_);
|
||||||
NetEqPlayoutMode playout_mode_ RTC_GUARDED_BY(crit_sect_);
|
|
||||||
bool enable_fast_accelerate_ RTC_GUARDED_BY(crit_sect_);
|
bool enable_fast_accelerate_ RTC_GUARDED_BY(crit_sect_);
|
||||||
std::unique_ptr<NackTracker> nack_ RTC_GUARDED_BY(crit_sect_);
|
std::unique_ptr<NackTracker> nack_ RTC_GUARDED_BY(crit_sect_);
|
||||||
bool nack_enabled_ RTC_GUARDED_BY(crit_sect_);
|
bool nack_enabled_ RTC_GUARDED_BY(crit_sect_);
|
||||||
@ -441,6 +424,7 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
std::vector<uint32_t> last_decoded_timestamps_ RTC_GUARDED_BY(crit_sect_);
|
std::vector<uint32_t> last_decoded_timestamps_ RTC_GUARDED_BY(crit_sect_);
|
||||||
ExpandUmaLogger expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
|
ExpandUmaLogger expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
|
||||||
ExpandUmaLogger speech_expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
|
ExpandUmaLogger speech_expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
|
||||||
|
bool no_time_stretching_ RTC_GUARDED_BY(crit_sect_); // Only used for test.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(NetEqImpl);
|
RTC_DISALLOW_COPY_AND_ASSIGN(NetEqImpl);
|
||||||
|
@ -1377,32 +1377,6 @@ class NetEqImplTest120ms : public NetEqImplTest {
|
|||||||
uint16_t sequence_number_ = 1;
|
uint16_t sequence_number_ = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(NetEqImplTest120ms, AudioRepetition) {
|
|
||||||
config_.playout_mode = kPlayoutFax;
|
|
||||||
CreateInstanceNoMocks();
|
|
||||||
Register120msCodec(AudioDecoder::kSpeech);
|
|
||||||
|
|
||||||
InsertPacket(first_timestamp());
|
|
||||||
GetFirstPacket();
|
|
||||||
|
|
||||||
bool muted;
|
|
||||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
|
||||||
EXPECT_EQ(kAudioRepetition, neteq_->last_operation_for_test());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(NetEqImplTest120ms, AlternativePlc) {
|
|
||||||
config_.playout_mode = kPlayoutOff;
|
|
||||||
CreateInstanceNoMocks();
|
|
||||||
Register120msCodec(AudioDecoder::kSpeech);
|
|
||||||
|
|
||||||
InsertPacket(first_timestamp());
|
|
||||||
GetFirstPacket();
|
|
||||||
|
|
||||||
bool muted;
|
|
||||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
|
|
||||||
EXPECT_EQ(kAlternativePlc, neteq_->last_operation_for_test());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(NetEqImplTest120ms, CodecInternalCng) {
|
TEST_F(NetEqImplTest120ms, CodecInternalCng) {
|
||||||
CreateInstanceNoMocks();
|
CreateInstanceNoMocks();
|
||||||
Register120msCodec(AudioDecoder::kComfortNoise);
|
Register120msCodec(AudioDecoder::kComfortNoise);
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include "common_types.h" // NOLINT(build/include)
|
#include "common_types.h" // NOLINT(build/include)
|
||||||
#include "modules/audio_coding/codecs/pcm16b/pcm16b.h"
|
#include "modules/audio_coding/codecs/pcm16b/pcm16b.h"
|
||||||
#include "modules/audio_coding/neteq/tools/audio_loop.h"
|
#include "modules/audio_coding/neteq/tools/audio_loop.h"
|
||||||
|
#include "modules/audio_coding/neteq/tools/neteq_packet_source_input.h"
|
||||||
|
#include "modules/audio_coding/neteq/tools/neteq_test.h"
|
||||||
#include "modules/audio_coding/neteq/tools/rtp_file_source.h"
|
#include "modules/audio_coding/neteq/tools/rtp_file_source.h"
|
||||||
#include "rtc_base/ignore_wundef.h"
|
#include "rtc_base/ignore_wundef.h"
|
||||||
#include "rtc_base/messagedigest.h"
|
#include "rtc_base/messagedigest.h"
|
||||||
@ -555,7 +557,7 @@ TEST_F(NetEqDecodingTest, MAYBE_TestOpusDtxBitExactness) {
|
|||||||
class NetEqDecodingTestFaxMode : public NetEqDecodingTest {
|
class NetEqDecodingTestFaxMode : public NetEqDecodingTest {
|
||||||
protected:
|
protected:
|
||||||
NetEqDecodingTestFaxMode() : NetEqDecodingTest() {
|
NetEqDecodingTestFaxMode() : NetEqDecodingTest() {
|
||||||
config_.playout_mode = kPlayoutFax;
|
config_.for_test_no_time_stretching = true;
|
||||||
}
|
}
|
||||||
void TestJitterBufferDelay(bool apply_packet_loss);
|
void TestJitterBufferDelay(bool apply_packet_loss);
|
||||||
};
|
};
|
||||||
@ -1723,4 +1725,37 @@ TEST_F(NetEqDecodingTestFaxMode, TestJitterBufferDelayWithLoss) {
|
|||||||
TestJitterBufferDelay(true);
|
TestJitterBufferDelay(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace test {
|
||||||
|
// TODO(henrik.lundin) NetEqRtpDumpInput requires protobuf support. It shouldn't
|
||||||
|
// need it, but because it is bundled with NetEqEventLogInput, it is neded.
|
||||||
|
// This should be refactored.
|
||||||
|
#if WEBRTC_ENABLE_PROTOBUF
|
||||||
|
TEST(NetEqNoTimeStretchingMode, RunTest) {
|
||||||
|
NetEq::Config config;
|
||||||
|
config.for_test_no_time_stretching = true;
|
||||||
|
auto codecs = NetEqTest::StandardDecoderMap();
|
||||||
|
NetEqTest::ExtDecoderMap ext_codecs;
|
||||||
|
NetEqPacketSourceInput::RtpHeaderExtensionMap rtp_ext_map = {
|
||||||
|
{1, kRtpExtensionAudioLevel},
|
||||||
|
{3, kRtpExtensionAbsoluteSendTime},
|
||||||
|
{5, kRtpExtensionTransportSequenceNumber},
|
||||||
|
{7, kRtpExtensionVideoContentType},
|
||||||
|
{8, kRtpExtensionVideoTiming}};
|
||||||
|
std::unique_ptr<NetEqInput> input(new NetEqRtpDumpInput(
|
||||||
|
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"),
|
||||||
|
rtp_ext_map));
|
||||||
|
std::unique_ptr<TimeLimitedNetEqInput> input_time_limit(
|
||||||
|
new TimeLimitedNetEqInput(std::move(input), 20000));
|
||||||
|
std::unique_ptr<AudioSink> output(new VoidAudioSink);
|
||||||
|
NetEqTest::Callbacks callbacks;
|
||||||
|
NetEqTest test(config, codecs, ext_codecs, std::move(input_time_limit),
|
||||||
|
std::move(output), callbacks);
|
||||||
|
test.Run();
|
||||||
|
const auto stats = test.SimulationStats();
|
||||||
|
EXPECT_EQ(0, stats.accelerate_rate);
|
||||||
|
EXPECT_EQ(0, stats.preemptive_rate);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -28,5 +28,50 @@ std::string NetEqInput::PacketData::ToString() const {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimeLimitedNetEqInput::TimeLimitedNetEqInput(std::unique_ptr<NetEqInput> input,
|
||||||
|
int64_t duration_ms)
|
||||||
|
: input_(std::move(input)),
|
||||||
|
start_time_ms_(input_->NextEventTime()),
|
||||||
|
duration_ms_(duration_ms) {}
|
||||||
|
|
||||||
|
rtc::Optional<int64_t> TimeLimitedNetEqInput::NextPacketTime() const {
|
||||||
|
return ended_ ? rtc::Optional<int64_t>() : input_->NextPacketTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::Optional<int64_t> TimeLimitedNetEqInput::NextOutputEventTime() const {
|
||||||
|
return ended_ ? rtc::Optional<int64_t>() : input_->NextOutputEventTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<NetEqInput::PacketData> TimeLimitedNetEqInput::PopPacket() {
|
||||||
|
if (ended_) {
|
||||||
|
return std::unique_ptr<PacketData>();
|
||||||
|
}
|
||||||
|
auto packet = input_->PopPacket();
|
||||||
|
MaybeSetEnded();
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeLimitedNetEqInput::AdvanceOutputEvent() {
|
||||||
|
if (!ended_) {
|
||||||
|
input_->AdvanceOutputEvent();
|
||||||
|
MaybeSetEnded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeLimitedNetEqInput::ended() const {
|
||||||
|
return ended_ || input_->ended();
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::Optional<RTPHeader> TimeLimitedNetEqInput::NextHeader() const {
|
||||||
|
return ended_ ? rtc::Optional<RTPHeader>() : input_->NextHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeLimitedNetEqInput::MaybeSetEnded() {
|
||||||
|
if (NextEventTime() && start_time_ms_ &&
|
||||||
|
*NextEventTime() - *start_time_ms_ > duration_ms_) {
|
||||||
|
ended_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -78,6 +78,28 @@ class NetEqInput {
|
|||||||
virtual absl::optional<RTPHeader> NextHeader() const = 0;
|
virtual absl::optional<RTPHeader> NextHeader() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Wrapper class to impose a time limit on a NetEqInput object, typically
|
||||||
|
// another time limit than what the object itself provides. For example, an
|
||||||
|
// input taken from a file can be cut shorter by wrapping it in this class.
|
||||||
|
class TimeLimitedNetEqInput : public NetEqInput {
|
||||||
|
public:
|
||||||
|
TimeLimitedNetEqInput(std::unique_ptr<NetEqInput> input, int64_t duration_ms);
|
||||||
|
rtc::Optional<int64_t> NextPacketTime() const override;
|
||||||
|
rtc::Optional<int64_t> NextOutputEventTime() const override;
|
||||||
|
std::unique_ptr<PacketData> PopPacket() override;
|
||||||
|
void AdvanceOutputEvent() override;
|
||||||
|
bool ended() const override;
|
||||||
|
rtc::Optional<RTPHeader> NextHeader() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void MaybeSetEnded();
|
||||||
|
|
||||||
|
std::unique_ptr<NetEqInput> input_;
|
||||||
|
const rtc::Optional<int64_t> start_time_ms_;
|
||||||
|
const int64_t duration_ms_;
|
||||||
|
bool ended_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
#endif // MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_INPUT_H_
|
#endif // MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_INPUT_H_
|
||||||
|
@ -115,6 +115,34 @@ NetEqLifetimeStatistics NetEqTest::LifetimeStats() const {
|
|||||||
return neteq_->GetLifetimeStatistics();
|
return neteq_->GetLifetimeStatistics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetEqTest::DecoderMap NetEqTest::StandardDecoderMap() {
|
||||||
|
DecoderMap codecs = {
|
||||||
|
{0, std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu")},
|
||||||
|
{8, std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma")},
|
||||||
|
{102, std::make_pair(NetEqDecoder::kDecoderILBC, "ilbc")},
|
||||||
|
{103, std::make_pair(NetEqDecoder::kDecoderISAC, "isac")},
|
||||||
|
#if !defined(WEBRTC_ANDROID)
|
||||||
|
{104, std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb")},
|
||||||
|
#endif
|
||||||
|
{111, std::make_pair(NetEqDecoder::kDecoderOpus, "opus")},
|
||||||
|
{93, std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb")},
|
||||||
|
{94, std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb")},
|
||||||
|
{95, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32")},
|
||||||
|
{96, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48")},
|
||||||
|
{9, std::make_pair(NetEqDecoder::kDecoderG722, "g722")},
|
||||||
|
{106, std::make_pair(NetEqDecoder::kDecoderAVT, "avt")},
|
||||||
|
{114, std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16")},
|
||||||
|
{115, std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32")},
|
||||||
|
{116, std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48")},
|
||||||
|
{117, std::make_pair(NetEqDecoder::kDecoderRED, "red")},
|
||||||
|
{13, std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb")},
|
||||||
|
{98, std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb")},
|
||||||
|
{99, std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32")},
|
||||||
|
{100, std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48")}
|
||||||
|
};
|
||||||
|
return codecs;
|
||||||
|
}
|
||||||
|
|
||||||
void NetEqTest::RegisterDecoders(const DecoderMap& codecs) {
|
void NetEqTest::RegisterDecoders(const DecoderMap& codecs) {
|
||||||
for (const auto& c : codecs) {
|
for (const auto& c : codecs) {
|
||||||
RTC_CHECK_EQ(
|
RTC_CHECK_EQ(
|
||||||
|
@ -91,6 +91,8 @@ class NetEqTest {
|
|||||||
NetEqNetworkStatistics SimulationStats();
|
NetEqNetworkStatistics SimulationStats();
|
||||||
NetEqLifetimeStatistics LifetimeStats() const;
|
NetEqLifetimeStatistics LifetimeStats() const;
|
||||||
|
|
||||||
|
static DecoderMap StandardDecoderMap();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RegisterDecoders(const DecoderMap& codecs);
|
void RegisterDecoders(const DecoderMap& codecs);
|
||||||
void RegisterExternalDecoders(const ExtDecoderMap& codecs);
|
void RegisterExternalDecoders(const ExtDecoderMap& codecs);
|
||||||
|
@ -40,8 +40,9 @@ TwoWayCommunication::TwoWayCommunication(int testMode)
|
|||||||
AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
|
AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
|
||||||
_testMode(testMode) {
|
_testMode(testMode) {
|
||||||
AudioCodingModule::Config config;
|
AudioCodingModule::Config config;
|
||||||
// The clicks will be more obvious in FAX mode. TODO(henrik.lundin) Really?
|
// The clicks will be more obvious if time-stretching is not allowed.
|
||||||
config.neteq_config.playout_mode = kPlayoutFax;
|
// TODO(henrik.lundin) Really?
|
||||||
|
config.neteq_config.for_test_no_time_stretching = true;
|
||||||
config.decoder_factory = CreateBuiltinAudioDecoderFactory();
|
config.decoder_factory = CreateBuiltinAudioDecoderFactory();
|
||||||
_acmB.reset(AudioCodingModule::Create(config));
|
_acmB.reset(AudioCodingModule::Create(config));
|
||||||
_acmRefB.reset(AudioCodingModule::Create(config));
|
_acmRefB.reset(AudioCodingModule::Create(config));
|
||||||
|
@ -133,29 +133,13 @@ void FuzzOneInputTest(const uint8_t* data, size_t size) {
|
|||||||
std::unique_ptr<AudioChecksum> output(new AudioChecksum);
|
std::unique_ptr<AudioChecksum> output(new AudioChecksum);
|
||||||
NetEqTest::Callbacks callbacks;
|
NetEqTest::Callbacks callbacks;
|
||||||
NetEq::Config config;
|
NetEq::Config config;
|
||||||
NetEqTest::DecoderMap codecs;
|
auto codecs = NetEqTest::StandardDecoderMap();
|
||||||
codecs[0] = std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu");
|
// kPayloadType is the payload type that will be used for encoding. Verify
|
||||||
codecs[8] = std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma");
|
// that it is included in the standard decoder map, and that it points to the
|
||||||
codecs[103] = std::make_pair(NetEqDecoder::kDecoderISAC, "isac");
|
// expected decoder type.
|
||||||
codecs[104] = std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb");
|
RTC_CHECK_EQ(codecs.count(kPayloadType), 1);
|
||||||
codecs[111] = std::make_pair(NetEqDecoder::kDecoderOpus, "opus");
|
RTC_CHECK(codecs[kPayloadType].first == NetEqDecoder::kDecoderPCM16Bswb32kHz);
|
||||||
codecs[93] = std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb");
|
|
||||||
codecs[94] = std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb");
|
|
||||||
codecs[96] =
|
|
||||||
std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48");
|
|
||||||
codecs[9] = std::make_pair(NetEqDecoder::kDecoderG722, "g722");
|
|
||||||
codecs[106] = std::make_pair(NetEqDecoder::kDecoderAVT, "avt");
|
|
||||||
codecs[114] = std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16");
|
|
||||||
codecs[115] = std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32");
|
|
||||||
codecs[116] = std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48");
|
|
||||||
codecs[117] = std::make_pair(NetEqDecoder::kDecoderRED, "red");
|
|
||||||
codecs[13] = std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb");
|
|
||||||
codecs[98] = std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb");
|
|
||||||
codecs[99] = std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32");
|
|
||||||
codecs[100] = std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48");
|
|
||||||
// This is the payload type that will be used for encoding.
|
|
||||||
codecs[kPayloadType] =
|
|
||||||
std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32");
|
|
||||||
NetEqTest::ExtDecoderMap ext_codecs;
|
NetEqTest::ExtDecoderMap ext_codecs;
|
||||||
|
|
||||||
NetEqTest test(config, codecs, ext_codecs, std::move(input),
|
NetEqTest test(config, codecs, ext_codecs, std::move(input),
|
||||||
|
@ -167,31 +167,22 @@ void FuzzOneInputTest(const uint8_t* data, size_t size) {
|
|||||||
NetEq::Config config;
|
NetEq::Config config;
|
||||||
config.enable_post_decode_vad = true;
|
config.enable_post_decode_vad = true;
|
||||||
config.enable_fast_accelerate = true;
|
config.enable_fast_accelerate = true;
|
||||||
NetEqTest::DecoderMap codecs;
|
auto codecs = NetEqTest::StandardDecoderMap();
|
||||||
codecs[0] = std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu");
|
// rate_types contains the payload types that will be used for encoding.
|
||||||
codecs[8] = std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma");
|
// Verify that they all are included in the standard decoder map, and that
|
||||||
codecs[103] = std::make_pair(NetEqDecoder::kDecoderISAC, "isac");
|
// they point to the expected decoder types.
|
||||||
codecs[104] = std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb");
|
RTC_CHECK_EQ(codecs.count(rate_types[0].second), 1);
|
||||||
codecs[111] = std::make_pair(NetEqDecoder::kDecoderOpus, "opus");
|
RTC_CHECK(codecs[rate_types[0].second].first == NetEqDecoder::kDecoderPCM16B);
|
||||||
codecs[9] = std::make_pair(NetEqDecoder::kDecoderG722, "g722");
|
RTC_CHECK_EQ(codecs.count(rate_types[1].second), 1);
|
||||||
codecs[106] = std::make_pair(NetEqDecoder::kDecoderAVT, "avt");
|
RTC_CHECK(codecs[rate_types[1].second].first ==
|
||||||
codecs[114] = std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16");
|
NetEqDecoder::kDecoderPCM16Bwb);
|
||||||
codecs[115] = std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32");
|
RTC_CHECK_EQ(codecs.count(rate_types[2].second), 1);
|
||||||
codecs[116] = std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48");
|
RTC_CHECK(codecs[rate_types[2].second].first ==
|
||||||
codecs[117] = std::make_pair(NetEqDecoder::kDecoderRED, "red");
|
NetEqDecoder::kDecoderPCM16Bswb32kHz);
|
||||||
codecs[13] = std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb");
|
RTC_CHECK_EQ(codecs.count(rate_types[3].second), 1);
|
||||||
codecs[98] = std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb");
|
RTC_CHECK(codecs[rate_types[3].second].first ==
|
||||||
codecs[99] = std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32");
|
NetEqDecoder::kDecoderPCM16Bswb48kHz);
|
||||||
codecs[100] = std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48");
|
|
||||||
// One of these payload types will be used for encoding.
|
|
||||||
codecs[rate_types[0].second] =
|
|
||||||
std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb");
|
|
||||||
codecs[rate_types[1].second] =
|
|
||||||
std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb");
|
|
||||||
codecs[rate_types[2].second] =
|
|
||||||
std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32");
|
|
||||||
codecs[rate_types[3].second] =
|
|
||||||
std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48");
|
|
||||||
NetEqTest::ExtDecoderMap ext_codecs;
|
NetEqTest::ExtDecoderMap ext_codecs;
|
||||||
|
|
||||||
NetEqTest test(config, codecs, ext_codecs, std::move(input),
|
NetEqTest test(config, codecs, ext_codecs, std::move(input),
|
||||||
|
Reference in New Issue
Block a user