Removed sync packet support from NetEq.
I could not find a single place it was used, outside of the unittests for the sync packet support itself. Review-Url: https://codereview.webrtc.org/2309303002 Cr-Commit-Position: refs/heads/master@{#14130}
This commit is contained in:
@ -128,8 +128,7 @@ class NetEq {
|
||||
kDecodedTooMuch,
|
||||
kFrameSplitError,
|
||||
kRedundancySplitError,
|
||||
kPacketBufferCorruption,
|
||||
kSyncPacketNotAccepted
|
||||
kPacketBufferCorruption
|
||||
};
|
||||
|
||||
// Creates a new NetEq object, with parameters set in |config|. The |config|
|
||||
@ -149,18 +148,6 @@ class NetEq {
|
||||
rtc::ArrayView<const uint8_t> payload,
|
||||
uint32_t receive_timestamp) = 0;
|
||||
|
||||
// Inserts a sync-packet into packet queue. Sync-packets are decoded to
|
||||
// silence and are intended to keep AV-sync intact in an event of long packet
|
||||
// losses when Video NACK is enabled but Audio NACK is not. Clients of NetEq
|
||||
// might insert sync-packet when they observe that buffer level of NetEq is
|
||||
// decreasing below a certain threshold, defined by the application.
|
||||
// Sync-packets should have the same payload type as the last audio payload
|
||||
// type, i.e. they cannot have DTMF or CNG payload type, nor a codec change
|
||||
// can be implied by inserting a sync-packet.
|
||||
// Returns kOk on success, kFail on failure.
|
||||
virtual int InsertSyncPacket(const WebRtcRTPHeader& rtp_header,
|
||||
uint32_t receive_timestamp) = 0;
|
||||
|
||||
// Instructs NetEq to deliver 10 ms of audio data. The data is written to
|
||||
// |audio_frame|. All data in |audio_frame| is wiped; |data_|, |speech_type_|,
|
||||
// |num_channels_|, |sample_rate_hz_|, |samples_per_channel_|, and
|
||||
|
||||
@ -137,21 +137,7 @@ int NetEqImpl::InsertPacket(const WebRtcRTPHeader& rtp_header,
|
||||
TRACE_EVENT0("webrtc", "NetEqImpl::InsertPacket");
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
int error =
|
||||
InsertPacketInternal(rtp_header, payload, receive_timestamp, false);
|
||||
if (error != 0) {
|
||||
error_code_ = error;
|
||||
return kFail;
|
||||
}
|
||||
return kOK;
|
||||
}
|
||||
|
||||
int NetEqImpl::InsertSyncPacket(const WebRtcRTPHeader& rtp_header,
|
||||
uint32_t receive_timestamp) {
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
const uint8_t kSyncPayload[] = { 's', 'y', 'n', 'c' };
|
||||
int error =
|
||||
InsertPacketInternal(rtp_header, kSyncPayload, receive_timestamp, true);
|
||||
|
||||
InsertPacketInternal(rtp_header, payload, receive_timestamp);
|
||||
if (error != 0) {
|
||||
error_code_ = error;
|
||||
return kFail;
|
||||
@ -522,31 +508,12 @@ Operations NetEqImpl::last_operation_for_test() const {
|
||||
|
||||
int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
||||
rtc::ArrayView<const uint8_t> payload,
|
||||
uint32_t receive_timestamp,
|
||||
bool is_sync_packet) {
|
||||
uint32_t receive_timestamp) {
|
||||
if (payload.empty()) {
|
||||
LOG_F(LS_ERROR) << "payload is empty";
|
||||
return kInvalidPointer;
|
||||
}
|
||||
// Sanity checks for sync-packets.
|
||||
if (is_sync_packet) {
|
||||
if (decoder_database_->IsDtmf(rtp_header.header.payloadType) ||
|
||||
decoder_database_->IsRed(rtp_header.header.payloadType) ||
|
||||
decoder_database_->IsComfortNoise(rtp_header.header.payloadType)) {
|
||||
LOG_F(LS_ERROR) << "Sync-packet with an unacceptable payload type "
|
||||
<< static_cast<int>(rtp_header.header.payloadType);
|
||||
return kSyncPacketNotAccepted;
|
||||
}
|
||||
if (first_packet_ || !current_rtp_payload_type_ ||
|
||||
rtp_header.header.payloadType != *current_rtp_payload_type_ ||
|
||||
rtp_header.header.ssrc != ssrc_) {
|
||||
// Even if |current_rtp_payload_type_| is empty, sync-packet isn't
|
||||
// accepted.
|
||||
LOG_F(LS_ERROR)
|
||||
<< "Changing codec, SSRC or first packet with sync-packet.";
|
||||
return kSyncPacketNotAccepted;
|
||||
}
|
||||
}
|
||||
|
||||
PacketList packet_list;
|
||||
RTPHeader main_header;
|
||||
{
|
||||
@ -565,7 +532,6 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
||||
packet->primary = true;
|
||||
// Waiting time will be set upon inserting the packet in the buffer.
|
||||
RTC_DCHECK(!packet->waiting_time);
|
||||
packet->sync_packet = is_sync_packet;
|
||||
// Insert packet in a packet list.
|
||||
packet_list.push_back(packet);
|
||||
// Save main payloads header for later.
|
||||
@ -601,12 +567,10 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
||||
}
|
||||
|
||||
// Update RTCP statistics, only for regular packets.
|
||||
if (!is_sync_packet)
|
||||
rtcp_.Update(main_header, receive_timestamp);
|
||||
|
||||
// Check for RED payload type, and separate payloads into several packets.
|
||||
if (decoder_database_->IsRed(main_header.payloadType)) {
|
||||
assert(!is_sync_packet); // We had a sanity check for this.
|
||||
if (payload_splitter_->SplitRed(&packet_list) != PayloadSplitter::kOK) {
|
||||
PacketBuffer::DeleteAllPackets(&packet_list);
|
||||
return kRedundancySplitError;
|
||||
@ -637,7 +601,6 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
||||
assert(current_packet);
|
||||
assert(!current_packet->payload.empty());
|
||||
if (decoder_database_->IsDtmf(current_packet->header.payloadType)) {
|
||||
assert(!current_packet->sync_packet); // We had a sanity check for this.
|
||||
DtmfEvent event;
|
||||
int ret = DtmfBuffer::ParseEvent(current_packet->header.timestamp,
|
||||
current_packet->payload.data(),
|
||||
@ -670,8 +633,7 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
||||
}
|
||||
|
||||
// Split payloads into smaller chunks. This also verifies that all payloads
|
||||
// are of a known payload type. SplitAudio() method is protected against
|
||||
// sync-packets.
|
||||
// are of a known payload type.
|
||||
ret = payload_splitter_->SplitAudio(&packet_list, *decoder_database_);
|
||||
if (ret != PayloadSplitter::kOK) {
|
||||
PacketBuffer::DeleteAllPackets(&packet_list);
|
||||
@ -685,9 +647,8 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
||||
}
|
||||
}
|
||||
|
||||
// Update bandwidth estimate, if the packet is not sync-packet nor comfort
|
||||
// noise.
|
||||
if (!packet_list.empty() && !packet_list.front()->sync_packet &&
|
||||
// Update bandwidth estimate, if the packet is not comfort noise.
|
||||
if (!packet_list.empty() &&
|
||||
!decoder_database_->IsComfortNoise(main_header.payloadType)) {
|
||||
// The list can be empty here if we got nothing but DTMF payloads.
|
||||
AudioDecoder* decoder =
|
||||
@ -1462,13 +1423,7 @@ int NetEqImpl::DecodeLoop(PacketList* packet_list, const Operations& operation,
|
||||
packet_list->pop_front();
|
||||
const size_t payload_length = packet->payload.size();
|
||||
int decode_length;
|
||||
if (packet->sync_packet) {
|
||||
// Decode to silence with the same frame size as the last decode.
|
||||
memset(&decoded_buffer_[*decoded_length], 0,
|
||||
decoder_frame_length_ * decoder->Channels() *
|
||||
sizeof(decoded_buffer_[0]));
|
||||
decode_length = rtc::checked_cast<int>(decoder_frame_length_);
|
||||
} else if (!packet->primary) {
|
||||
if (!packet->primary) {
|
||||
// This is a redundant payload; call the special decoder method.
|
||||
decode_length = decoder->DecodeRedundant(
|
||||
packet->payload.data(), packet->payload.size(), fs_hz_,
|
||||
@ -1974,9 +1929,6 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
|
||||
AudioDecoder* decoder = decoder_database_->GetDecoder(
|
||||
packet->header.payloadType);
|
||||
if (decoder) {
|
||||
if (packet->sync_packet) {
|
||||
packet_duration = rtc::checked_cast<int>(decoder_frame_length_);
|
||||
} else {
|
||||
if (packet->primary) {
|
||||
packet_duration = decoder->PacketDuration(packet->payload.data(),
|
||||
packet->payload.size());
|
||||
@ -1985,7 +1937,6 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
|
||||
packet->payload.data(), packet->payload.size());
|
||||
stats_.SecondaryDecodedSamples(packet_duration);
|
||||
}
|
||||
}
|
||||
} else if (!decoder_database_->IsComfortNoise(packet->header.payloadType)) {
|
||||
LOG(LS_WARNING) << "Unknown payload type "
|
||||
<< static_cast<int>(packet->header.payloadType);
|
||||
|
||||
@ -108,18 +108,6 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
rtc::ArrayView<const uint8_t> payload,
|
||||
uint32_t receive_timestamp) override;
|
||||
|
||||
// Inserts a sync-packet into packet queue. Sync-packets are decoded to
|
||||
// silence and are intended to keep AV-sync intact in an event of long packet
|
||||
// losses when Video NACK is enabled but Audio NACK is not. Clients of NetEq
|
||||
// might insert sync-packet when they observe that buffer level of NetEq is
|
||||
// decreasing below a certain threshold, defined by the application.
|
||||
// Sync-packets should have the same payload type as the last audio payload
|
||||
// type, i.e. they cannot have DTMF or CNG payload type, nor a codec change
|
||||
// can be implied by inserting a sync-packet.
|
||||
// Returns kOk on success, kFail on failure.
|
||||
int InsertSyncPacket(const WebRtcRTPHeader& rtp_header,
|
||||
uint32_t receive_timestamp) override;
|
||||
|
||||
int GetAudio(AudioFrame* audio_frame, bool* muted) override;
|
||||
|
||||
int RegisterPayloadType(NetEqDecoder codec,
|
||||
@ -223,8 +211,7 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
// TODO(hlundin): Merge this with InsertPacket above?
|
||||
int InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
||||
rtc::ArrayView<const uint8_t> payload,
|
||||
uint32_t receive_timestamp,
|
||||
bool is_sync_packet)
|
||||
uint32_t receive_timestamp)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
|
||||
|
||||
// Delivers 10 ms of audio data. The data is written to |audio_frame|.
|
||||
|
||||
@ -61,20 +61,6 @@ const std::string& PlatformChecksum(const std::string& checksum_general,
|
||||
#endif // WEBRTC_WIN
|
||||
}
|
||||
|
||||
bool IsAllZero(const int16_t* buf, size_t buf_length) {
|
||||
bool all_zero = true;
|
||||
for (size_t n = 0; n < buf_length && all_zero; ++n)
|
||||
all_zero = buf[n] == 0;
|
||||
return all_zero;
|
||||
}
|
||||
|
||||
bool IsAllNonZero(const int16_t* buf, size_t buf_length) {
|
||||
bool all_non_zero = true;
|
||||
for (size_t n = 0; n < buf_length && all_non_zero; ++n)
|
||||
all_non_zero = buf[n] != 0;
|
||||
return all_non_zero;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_NETEQ_UNITTEST_BITEXACT
|
||||
void Convert(const webrtc::NetEqNetworkStatistics& stats_raw,
|
||||
webrtc::neteq_unittest::NetEqNetworkStatistics* stats) {
|
||||
@ -1079,232 +1065,6 @@ TEST_F(NetEqBgnTestFade, RunTest) {
|
||||
CheckBgn(32000);
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
|
||||
#define MAYBE_SyncPacketInsert SyncPacketInsert
|
||||
#else
|
||||
#define MAYBE_SyncPacketInsert DISABLED_SyncPacketInsert
|
||||
#endif
|
||||
TEST_F(NetEqDecodingTest, MAYBE_SyncPacketInsert) {
|
||||
WebRtcRTPHeader rtp_info;
|
||||
uint32_t receive_timestamp = 0;
|
||||
// For the readability use the following payloads instead of the defaults of
|
||||
// this test.
|
||||
uint8_t kPcm16WbPayloadType = 1;
|
||||
uint8_t kCngNbPayloadType = 2;
|
||||
uint8_t kCngWbPayloadType = 3;
|
||||
uint8_t kCngSwb32PayloadType = 4;
|
||||
uint8_t kCngSwb48PayloadType = 5;
|
||||
uint8_t kAvtPayloadType = 6;
|
||||
uint8_t kRedPayloadType = 7;
|
||||
uint8_t kIsacPayloadType = 9; // Payload type 8 is already registered.
|
||||
|
||||
// Register decoders.
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderPCM16Bwb,
|
||||
"pcm16-wb", kPcm16WbPayloadType));
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderCNGnb,
|
||||
"cng-nb", kCngNbPayloadType));
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderCNGwb,
|
||||
"cng-wb", kCngWbPayloadType));
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderCNGswb32kHz,
|
||||
"cng-swb32", kCngSwb32PayloadType));
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderCNGswb48kHz,
|
||||
"cng-swb48", kCngSwb48PayloadType));
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderAVT, "avt",
|
||||
kAvtPayloadType));
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderRED, "red",
|
||||
kRedPayloadType));
|
||||
ASSERT_EQ(0, neteq_->RegisterPayloadType(NetEqDecoder::kDecoderISAC, "isac",
|
||||
kIsacPayloadType));
|
||||
|
||||
PopulateRtpInfo(0, 0, &rtp_info);
|
||||
rtp_info.header.payloadType = kPcm16WbPayloadType;
|
||||
|
||||
// The first packet injected cannot be sync-packet.
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
// Payload length of 10 ms PCM16 16 kHz.
|
||||
const size_t kPayloadBytes = kBlockSize16kHz * sizeof(int16_t);
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, receive_timestamp));
|
||||
|
||||
// Next packet. Last packet contained 10 ms audio.
|
||||
rtp_info.header.sequenceNumber++;
|
||||
rtp_info.header.timestamp += kBlockSize16kHz;
|
||||
receive_timestamp += kBlockSize16kHz;
|
||||
|
||||
// Unacceptable payload types CNG, AVT (DTMF), RED.
|
||||
rtp_info.header.payloadType = kCngNbPayloadType;
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
rtp_info.header.payloadType = kCngWbPayloadType;
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
rtp_info.header.payloadType = kCngSwb32PayloadType;
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
rtp_info.header.payloadType = kCngSwb48PayloadType;
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
rtp_info.header.payloadType = kAvtPayloadType;
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
rtp_info.header.payloadType = kRedPayloadType;
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
// Change of codec cannot be initiated with a sync packet.
|
||||
rtp_info.header.payloadType = kIsacPayloadType;
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
// Change of SSRC is not allowed with a sync packet.
|
||||
rtp_info.header.payloadType = kPcm16WbPayloadType;
|
||||
++rtp_info.header.ssrc;
|
||||
EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
|
||||
--rtp_info.header.ssrc;
|
||||
EXPECT_EQ(0, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
}
|
||||
|
||||
// First insert several noise like packets, then sync-packets. Decoding all
|
||||
// packets should not produce error, statistics should not show any packet loss
|
||||
// and sync-packets should decode to zero.
|
||||
// TODO(turajs) we will have a better test if we have a referece NetEq, and
|
||||
// when Sync packets are inserted in "test" NetEq we insert all-zero payload
|
||||
// in reference NetEq and compare the output of those two.
|
||||
TEST_F(NetEqDecodingTest, SyncPacketDecode) {
|
||||
WebRtcRTPHeader rtp_info;
|
||||
PopulateRtpInfo(0, 0, &rtp_info);
|
||||
const size_t kPayloadBytes = kBlockSize16kHz * sizeof(int16_t);
|
||||
uint8_t payload[kPayloadBytes];
|
||||
AudioFrame output;
|
||||
int algorithmic_frame_delay = algorithmic_delay_ms_ / 10 + 1;
|
||||
for (size_t n = 0; n < kPayloadBytes; ++n) {
|
||||
payload[n] = (rand() & 0xF0) + 1; // Non-zero random sequence.
|
||||
}
|
||||
// Insert some packets which decode to noise. We are not interested in
|
||||
// actual decoded values.
|
||||
uint32_t receive_timestamp = 0;
|
||||
bool muted;
|
||||
for (int n = 0; n < 100; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, receive_timestamp));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
|
||||
rtp_info.header.sequenceNumber++;
|
||||
rtp_info.header.timestamp += kBlockSize16kHz;
|
||||
receive_timestamp += kBlockSize16kHz;
|
||||
}
|
||||
const int kNumSyncPackets = 10;
|
||||
|
||||
// Make sure sufficient number of sync packets are inserted that we can
|
||||
// conduct a test.
|
||||
ASSERT_GT(kNumSyncPackets, algorithmic_frame_delay);
|
||||
// Insert sync-packets, the decoded sequence should be all-zero.
|
||||
for (int n = 0; n < kNumSyncPackets; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
if (n > algorithmic_frame_delay) {
|
||||
EXPECT_TRUE(IsAllZero(
|
||||
output.data_, output.samples_per_channel_ * output.num_channels_));
|
||||
}
|
||||
rtp_info.header.sequenceNumber++;
|
||||
rtp_info.header.timestamp += kBlockSize16kHz;
|
||||
receive_timestamp += kBlockSize16kHz;
|
||||
}
|
||||
|
||||
// We insert regular packets, if sync packet are not correctly buffered then
|
||||
// network statistics would show some packet loss.
|
||||
for (int n = 0; n <= algorithmic_frame_delay + 10; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, receive_timestamp));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
if (n >= algorithmic_frame_delay + 1) {
|
||||
// Expect that this frame contain samples from regular RTP.
|
||||
EXPECT_TRUE(IsAllNonZero(
|
||||
output.data_, output.samples_per_channel_ * output.num_channels_));
|
||||
}
|
||||
rtp_info.header.sequenceNumber++;
|
||||
rtp_info.header.timestamp += kBlockSize16kHz;
|
||||
receive_timestamp += kBlockSize16kHz;
|
||||
}
|
||||
NetEqNetworkStatistics network_stats;
|
||||
ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
|
||||
// Expecting a "clean" network.
|
||||
EXPECT_EQ(0, network_stats.packet_loss_rate);
|
||||
EXPECT_EQ(0, network_stats.expand_rate);
|
||||
EXPECT_EQ(0, network_stats.accelerate_rate);
|
||||
EXPECT_LE(network_stats.preemptive_rate, 150);
|
||||
}
|
||||
|
||||
// Test if the size of the packet buffer reported correctly when containing
|
||||
// sync packets. Also, test if network packets override sync packets. That is to
|
||||
// prefer decoding a network packet to a sync packet, if both have same sequence
|
||||
// number and timestamp.
|
||||
TEST_F(NetEqDecodingTest, SyncPacketBufferSizeAndOverridenByNetworkPackets) {
|
||||
WebRtcRTPHeader rtp_info;
|
||||
PopulateRtpInfo(0, 0, &rtp_info);
|
||||
const size_t kPayloadBytes = kBlockSize16kHz * sizeof(int16_t);
|
||||
uint8_t payload[kPayloadBytes];
|
||||
AudioFrame output;
|
||||
for (size_t n = 0; n < kPayloadBytes; ++n) {
|
||||
payload[n] = (rand() & 0xF0) + 1; // Non-zero random sequence.
|
||||
}
|
||||
// Insert some packets which decode to noise. We are not interested in
|
||||
// actual decoded values.
|
||||
uint32_t receive_timestamp = 0;
|
||||
int algorithmic_frame_delay = algorithmic_delay_ms_ / 10 + 1;
|
||||
bool muted;
|
||||
for (int n = 0; n < algorithmic_frame_delay; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, receive_timestamp));
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
rtp_info.header.sequenceNumber++;
|
||||
rtp_info.header.timestamp += kBlockSize16kHz;
|
||||
receive_timestamp += kBlockSize16kHz;
|
||||
}
|
||||
const int kNumSyncPackets = 10;
|
||||
|
||||
WebRtcRTPHeader first_sync_packet_rtp_info;
|
||||
memcpy(&first_sync_packet_rtp_info, &rtp_info, sizeof(rtp_info));
|
||||
|
||||
// Insert sync-packets, but no decoding.
|
||||
for (int n = 0; n < kNumSyncPackets; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
|
||||
rtp_info.header.sequenceNumber++;
|
||||
rtp_info.header.timestamp += kBlockSize16kHz;
|
||||
receive_timestamp += kBlockSize16kHz;
|
||||
}
|
||||
NetEqNetworkStatistics network_stats;
|
||||
ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
|
||||
EXPECT_EQ(kNumSyncPackets * 10 + algorithmic_delay_ms_,
|
||||
network_stats.current_buffer_size_ms);
|
||||
|
||||
// Rewind |rtp_info| to that of the first sync packet.
|
||||
memcpy(&rtp_info, &first_sync_packet_rtp_info, sizeof(rtp_info));
|
||||
|
||||
// Insert.
|
||||
for (int n = 0; n < kNumSyncPackets; ++n) {
|
||||
ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, receive_timestamp));
|
||||
rtp_info.header.sequenceNumber++;
|
||||
rtp_info.header.timestamp += kBlockSize16kHz;
|
||||
receive_timestamp += kBlockSize16kHz;
|
||||
}
|
||||
|
||||
// Decode.
|
||||
for (int n = 0; n < kNumSyncPackets; ++n) {
|
||||
ASSERT_EQ(0, neteq_->GetAudio(&output, &muted));
|
||||
ASSERT_FALSE(muted);
|
||||
ASSERT_EQ(kBlockSize16kHz, output.samples_per_channel_);
|
||||
ASSERT_EQ(1u, output.num_channels_);
|
||||
EXPECT_TRUE(IsAllNonZero(
|
||||
output.data_, output.samples_per_channel_ * output.num_channels_));
|
||||
}
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::WrapTest(uint16_t start_seq_no,
|
||||
uint32_t start_timestamp,
|
||||
const std::set<uint16_t>& drop_seq_numbers,
|
||||
|
||||
@ -27,44 +27,28 @@ struct Packet {
|
||||
// Datagram excluding RTP header and header extension.
|
||||
rtc::Buffer payload;
|
||||
bool primary = true; // Primary, i.e., not redundant payload.
|
||||
bool sync_packet = false;
|
||||
std::unique_ptr<TickTimer::Stopwatch> waiting_time;
|
||||
|
||||
Packet();
|
||||
~Packet();
|
||||
|
||||
// Comparison operators. Establish a packet ordering based on (1) timestamp,
|
||||
// (2) sequence number, (3) regular packet vs sync-packet and (4) redundancy.
|
||||
// (2) sequence number and (3) redundancy.
|
||||
// Timestamp and sequence numbers are compared taking wrap-around into
|
||||
// account. If both timestamp and sequence numbers are identical and one of
|
||||
// the packets is sync-packet, the regular packet is considered earlier. For
|
||||
// two regular packets with the same sequence number and timestamp a primary
|
||||
// payload is considered "smaller" than a secondary.
|
||||
// account. For two packets with the same sequence number and timestamp a
|
||||
// primary payload is considered "smaller" than a secondary.
|
||||
bool operator==(const Packet& rhs) const {
|
||||
return (this->header.timestamp == rhs.header.timestamp &&
|
||||
this->header.sequenceNumber == rhs.header.sequenceNumber &&
|
||||
this->primary == rhs.primary &&
|
||||
this->sync_packet == rhs.sync_packet);
|
||||
this->primary == rhs.primary);
|
||||
}
|
||||
bool operator!=(const Packet& rhs) const { return !operator==(rhs); }
|
||||
bool operator<(const Packet& rhs) const {
|
||||
if (this->header.timestamp == rhs.header.timestamp) {
|
||||
if (this->header.sequenceNumber == rhs.header.sequenceNumber) {
|
||||
// Timestamp and sequence numbers are identical. A sync packet should
|
||||
// be recognized "larger" (i.e. "later") compared to a "network packet"
|
||||
// (regular packet from network not sync-packet). If none of the packets
|
||||
// are sync-packets, then deem the left hand side to be "smaller"
|
||||
// (i.e., "earlier") if it is primary, and right hand side is not.
|
||||
//
|
||||
// The condition on sync packets to be larger than "network packets,"
|
||||
// given same RTP sequence number and timestamp, guarantees that a
|
||||
// "network packet" to be inserted in an earlier position into
|
||||
// |packet_buffer_| compared to a sync packet of same timestamp and
|
||||
// sequence number.
|
||||
if (rhs.sync_packet)
|
||||
return true;
|
||||
if (this->sync_packet)
|
||||
return false;
|
||||
// Timestamp and sequence numbers are identical - deem the left
|
||||
// hand side to be "smaller" (i.e., "earlier") if it is primary, and
|
||||
// right hand side is not.
|
||||
return (this->primary && !rhs.primary);
|
||||
}
|
||||
return (static_cast<uint16_t>(rhs.header.sequenceNumber
|
||||
|
||||
@ -273,7 +273,7 @@ size_t PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
|
||||
Packet* packet = (*it);
|
||||
AudioDecoder* decoder =
|
||||
decoder_database->GetDecoder(packet->header.payloadType);
|
||||
if (decoder && !packet->sync_packet) {
|
||||
if (decoder) {
|
||||
if (!packet->primary) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -137,11 +137,6 @@ int PayloadSplitter::SplitFec(PacketList* packet_list,
|
||||
LOG(LS_WARNING) << "SplitFec unknown payload type";
|
||||
return kUnknownPayloadType;
|
||||
}
|
||||
// No splitting for a sync-packet.
|
||||
if (packet->sync_packet) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not an FEC packet.
|
||||
AudioDecoder* decoder = decoder_database->GetDecoder(payload_type);
|
||||
@ -169,7 +164,6 @@ int PayloadSplitter::SplitFec(PacketList* packet_list,
|
||||
new_packet->header.timestamp -= duration;
|
||||
new_packet->payload.SetData(packet->payload);
|
||||
new_packet->primary = false;
|
||||
new_packet->sync_packet = packet->sync_packet;
|
||||
// Waiting time should not be set here.
|
||||
RTC_DCHECK(!packet->waiting_time);
|
||||
|
||||
@ -231,11 +225,6 @@ int PayloadSplitter::SplitAudio(PacketList* packet_list,
|
||||
LOG(LS_WARNING) << "SplitAudio unknown payload type";
|
||||
return kUnknownPayloadType;
|
||||
}
|
||||
// No splitting for a sync-packet.
|
||||
if (packet->sync_packet) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
PacketList new_packets;
|
||||
switch (info->codec_type) {
|
||||
case NetEqDecoder::kDecoderPCMu:
|
||||
|
||||
Reference in New Issue
Block a user