NetEq now works with packets as values, rather than pointers.

PacketList is now list<Packet> instead of list<Packet*>.
Splicing the lists in NetEqImpl::InsertPacketInternal instead of
moving packets. Avoid moving the packet when doing Rfc3389Cng.
Removed PacketBuffer::DeleteFirstPacket and DeleteAllPackets.

BUG=chromium:657300

Review-Url: https://codereview.webrtc.org/2425223002
Cr-Commit-Position: refs/heads/master@{#14747}
This commit is contained in:
ossu
2016-10-24 08:25:28 -07:00
committed by Commit bot
parent d312713e61
commit a73f6c9726
16 changed files with 429 additions and 505 deletions

View File

@ -24,17 +24,14 @@ void ComfortNoise::Reset() {
first_call_ = true; first_call_ = true;
} }
int ComfortNoise::UpdateParameters(Packet* packet) { int ComfortNoise::UpdateParameters(const Packet& packet) {
assert(packet); // Existence is verified by caller.
// Get comfort noise decoder. // Get comfort noise decoder.
if (decoder_database_->SetActiveCngDecoder(packet->payload_type) != kOK) { if (decoder_database_->SetActiveCngDecoder(packet.payload_type) != kOK) {
delete packet;
return kUnknownPayloadType; return kUnknownPayloadType;
} }
ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder(); ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder();
RTC_DCHECK(cng_decoder); RTC_DCHECK(cng_decoder);
cng_decoder->UpdateSid(packet->payload); cng_decoder->UpdateSid(packet.payload);
delete packet;
return kOK; return kOK;
} }

View File

@ -45,8 +45,7 @@ class ComfortNoise {
void Reset(); void Reset();
// Update the comfort noise generator with the parameters in |packet|. // Update the comfort noise generator with the parameters in |packet|.
// Will delete the packet. int UpdateParameters(const Packet& packet);
int UpdateParameters(Packet* packet);
// Generates |requested_length| samples of comfort noise and writes to // Generates |requested_length| samples of comfort noise and writes to
// |output|. If this is the first in call after Reset (or first after creating // |output|. If this is the first in call after Reset (or first after creating

View File

@ -310,10 +310,10 @@ bool DecoderDatabase::IsRed(uint8_t rtp_payload_type) const {
int DecoderDatabase::CheckPayloadTypes(const PacketList& packet_list) const { int DecoderDatabase::CheckPayloadTypes(const PacketList& packet_list) const {
PacketList::const_iterator it; PacketList::const_iterator it;
for (it = packet_list.begin(); it != packet_list.end(); ++it) { for (it = packet_list.begin(); it != packet_list.end(); ++it) {
if (!GetDecoderInfo((*it)->payload_type)) { if (!GetDecoderInfo(it->payload_type)) {
// Payload type is not found. // Payload type is not found.
LOG(LS_WARNING) << "CheckPayloadTypes: unknown RTP payload type " LOG(LS_WARNING) << "CheckPayloadTypes: unknown RTP payload type "
<< static_cast<int>((*it)->payload_type); << static_cast<int>(it->payload_type);
return kDecoderNotFound; return kDecoderNotFound;
} }
} }

View File

@ -175,16 +175,15 @@ TEST(DecoderDatabase, CheckPayloadTypes) {
for (int i = 0; i < kNumPayloads + 1; ++i) { for (int i = 0; i < kNumPayloads + 1; ++i) {
// Create packet with payload type |i|. The last packet will have a payload // Create packet with payload type |i|. The last packet will have a payload
// type that is not registered in the decoder database. // type that is not registered in the decoder database.
Packet* packet = new Packet; Packet packet;
packet->payload_type = i; packet.payload_type = i;
packet_list.push_back(packet); packet_list.push_back(std::move(packet));
} }
// Expect to return false, since the last packet is of an unknown type. // Expect to return false, since the last packet is of an unknown type.
EXPECT_EQ(DecoderDatabase::kDecoderNotFound, EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
db.CheckPayloadTypes(packet_list)); db.CheckPayloadTypes(packet_list));
delete packet_list.back();
packet_list.pop_back(); // Remove the unknown one. packet_list.pop_back(); // Remove the unknown one.
EXPECT_EQ(DecoderDatabase::kOK, db.CheckPayloadTypes(packet_list)); EXPECT_EQ(DecoderDatabase::kOK, db.CheckPayloadTypes(packet_list));
@ -192,7 +191,6 @@ TEST(DecoderDatabase, CheckPayloadTypes) {
// Delete all packets. // Delete all packets.
PacketList::iterator it = packet_list.begin(); PacketList::iterator it = packet_list.begin();
while (it != packet_list.end()) { while (it != packet_list.end()) {
delete packet_list.front();
it = packet_list.erase(it); it = packet_list.erase(it);
} }
} }

View File

@ -27,7 +27,13 @@ class MockPacketBuffer : public PacketBuffer {
void()); void());
MOCK_CONST_METHOD0(Empty, MOCK_CONST_METHOD0(Empty,
bool()); bool());
MOCK_METHOD1(InsertPacket, int InsertPacket(Packet&& packet) {
return InsertPacketWrapped(&packet);
}
// Since gtest does not properly support move-only types, InsertPacket is
// implemented as a wrapper. You'll have to implement InsertPacketWrapped
// instead and move from |*packet|.
MOCK_METHOD1(InsertPacketWrapped,
int(Packet* packet)); int(Packet* packet));
MOCK_METHOD4(InsertPacketList, MOCK_METHOD4(InsertPacketList,
int(PacketList* packet_list, int(PacketList* packet_list,
@ -40,8 +46,8 @@ class MockPacketBuffer : public PacketBuffer {
int(uint32_t timestamp, uint32_t* next_timestamp)); int(uint32_t timestamp, uint32_t* next_timestamp));
MOCK_CONST_METHOD0(PeekNextPacket, MOCK_CONST_METHOD0(PeekNextPacket,
const Packet*()); const Packet*());
MOCK_METHOD1(GetNextPacket, MOCK_METHOD0(GetNextPacket,
Packet*(size_t* discard_count)); rtc::Optional<Packet>());
MOCK_METHOD0(DiscardNextPacket, MOCK_METHOD0(DiscardNextPacket,
int()); int());
MOCK_METHOD2(DiscardOldPackets, MOCK_METHOD2(DiscardOldPackets,

View File

@ -581,21 +581,18 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
} }
PacketList packet_list; PacketList packet_list;
{
// Convert to Packet.
// Create |packet| within this separate scope, since it should not be used
// directly once it's been inserted in the packet list. This way, |packet|
// is not defined outside of this block.
Packet* packet = new Packet;
packet->payload_type = rtp_header.header.payloadType;
packet->sequence_number = rtp_header.header.sequenceNumber;
packet->timestamp = rtp_header.header.timestamp;
packet->payload.SetData(payload.data(), payload.size());
// Waiting time will be set upon inserting the packet in the buffer.
RTC_DCHECK(!packet->waiting_time);
// Insert packet in a packet list. // Insert packet in a packet list.
packet_list.push_back(packet); packet_list.push_back([&rtp_header, &payload] {
} // Convert to Packet.
Packet packet;
packet.payload_type = rtp_header.header.payloadType;
packet.sequence_number = rtp_header.header.sequenceNumber;
packet.timestamp = rtp_header.header.timestamp;
packet.payload.SetData(payload.data(), payload.size());
// Waiting time will be set upon inserting the packet in the buffer.
RTC_DCHECK(!packet.waiting_time);
return packet;
}());
bool update_sample_rate_and_channels = false; bool update_sample_rate_and_channels = false;
// Reinitialize NetEq if it's needed (changed SSRC or first call). // Reinitialize NetEq if it's needed (changed SSRC or first call).
@ -641,7 +638,6 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
// Check for RED payload type, and separate payloads into several packets. // Check for RED payload type, and separate payloads into several packets.
if (decoder_database_->IsRed(rtp_header.header.payloadType)) { if (decoder_database_->IsRed(rtp_header.header.payloadType)) {
if (!red_payload_splitter_->SplitRed(&packet_list)) { if (!red_payload_splitter_->SplitRed(&packet_list)) {
PacketBuffer::DeleteAllPackets(&packet_list);
return kRedundancySplitError; return kRedundancySplitError;
} }
// Only accept a few RED payloads of the same type as the main data, // Only accept a few RED payloads of the same type as the main data,
@ -652,16 +648,15 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
// Check payload types. // Check payload types.
if (decoder_database_->CheckPayloadTypes(packet_list) == if (decoder_database_->CheckPayloadTypes(packet_list) ==
DecoderDatabase::kDecoderNotFound) { DecoderDatabase::kDecoderNotFound) {
PacketBuffer::DeleteAllPackets(&packet_list);
return kUnknownRtpPayloadType; return kUnknownRtpPayloadType;
} }
RTC_DCHECK(!packet_list.empty()); RTC_DCHECK(!packet_list.empty());
// Store these for later use, since the first packet may very well disappear // Store these for later use, since the first packet may very well disappear
// before we need these values. // before we need these values.
const uint32_t main_timestamp = packet_list.front()->timestamp; const uint32_t main_timestamp = packet_list.front().timestamp;
const uint8_t main_payload_type = packet_list.front()->payload_type; const uint8_t main_payload_type = packet_list.front().payload_type;
const uint16_t main_sequence_number = packet_list.front()->sequence_number; const uint16_t main_sequence_number = packet_list.front().sequence_number;
// Scale timestamp to internal domain (only for some codecs). // Scale timestamp to internal domain (only for some codecs).
timestamp_scaler_->ToInternal(&packet_list); timestamp_scaler_->ToInternal(&packet_list);
@ -670,23 +665,19 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
// DTMF payloads found. // DTMF payloads found.
PacketList::iterator it = packet_list.begin(); PacketList::iterator it = packet_list.begin();
while (it != packet_list.end()) { while (it != packet_list.end()) {
Packet* current_packet = (*it); const Packet& current_packet = (*it);
assert(current_packet); RTC_DCHECK(!current_packet.payload.empty());
assert(!current_packet->payload.empty()); if (decoder_database_->IsDtmf(current_packet.payload_type)) {
if (decoder_database_->IsDtmf(current_packet->payload_type)) {
DtmfEvent event; DtmfEvent event;
int ret = DtmfBuffer::ParseEvent(current_packet->timestamp, int ret = DtmfBuffer::ParseEvent(current_packet.timestamp,
current_packet->payload.data(), current_packet.payload.data(),
current_packet->payload.size(), &event); current_packet.payload.size(), &event);
if (ret != DtmfBuffer::kOK) { if (ret != DtmfBuffer::kOK) {
PacketBuffer::DeleteAllPackets(&packet_list);
return kDtmfParsingError; return kDtmfParsingError;
} }
if (dtmf_buffer_->InsertEvent(event) != DtmfBuffer::kOK) { if (dtmf_buffer_->InsertEvent(event) != DtmfBuffer::kOK) {
PacketBuffer::DeleteAllPackets(&packet_list);
return kDtmfInsertError; return kDtmfInsertError;
} }
delete current_packet;
it = packet_list.erase(it); it = packet_list.erase(it);
} else { } else {
++it; ++it;
@ -700,19 +691,18 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
AudioDecoder* decoder = decoder_database_->GetDecoder(main_payload_type); AudioDecoder* decoder = decoder_database_->GetDecoder(main_payload_type);
RTC_DCHECK(decoder); // Should always get a valid object, since we have RTC_DCHECK(decoder); // Should always get a valid object, since we have
// already checked that the payload types are known. // already checked that the payload types are known.
decoder->IncomingPacket(packet_list.front()->payload.data(), decoder->IncomingPacket(packet_list.front().payload.data(),
packet_list.front()->payload.size(), packet_list.front().payload.size(),
packet_list.front()->sequence_number, packet_list.front().sequence_number,
packet_list.front()->timestamp, packet_list.front().timestamp,
receive_timestamp); receive_timestamp);
} }
PacketList parsed_packet_list; PacketList parsed_packet_list;
while (!packet_list.empty()) { while (!packet_list.empty()) {
std::unique_ptr<Packet> packet(packet_list.front()); Packet& packet = packet_list.front();
packet_list.pop_front();
const DecoderDatabase::DecoderInfo* info = const DecoderDatabase::DecoderInfo* info =
decoder_database_->GetDecoderInfo(packet->payload_type); decoder_database_->GetDecoderInfo(packet.payload_type);
if (!info) { if (!info) {
LOG(LS_WARNING) << "SplitAudio unknown payload type"; LOG(LS_WARNING) << "SplitAudio unknown payload type";
return kUnknownRtpPayloadType; return kUnknownRtpPayloadType;
@ -720,28 +710,43 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
if (info->IsComfortNoise()) { if (info->IsComfortNoise()) {
// Carry comfort noise packets along. // Carry comfort noise packets along.
parsed_packet_list.push_back(packet.release()); parsed_packet_list.splice(parsed_packet_list.end(), packet_list,
packet_list.begin());
} else { } else {
const auto sequence_number = packet.sequence_number;
const auto payload_type = packet.payload_type;
const Packet::Priority original_priority = packet.priority;
auto packet_from_result = [&] (AudioDecoder::ParseResult& result) {
Packet new_packet;
new_packet.sequence_number = sequence_number;
new_packet.payload_type = payload_type;
new_packet.timestamp = result.timestamp;
new_packet.priority.codec_level = result.priority;
new_packet.priority.red_level = original_priority.red_level;
new_packet.frame = std::move(result.frame);
return new_packet;
};
std::vector<AudioDecoder::ParseResult> results = std::vector<AudioDecoder::ParseResult> results =
info->GetDecoder()->ParsePayload(std::move(packet->payload), info->GetDecoder()->ParsePayload(std::move(packet.payload),
packet->timestamp); packet.timestamp);
const auto sequence_number = packet->sequence_number; if (results.empty()) {
const auto payload_type = packet->payload_type; packet_list.pop_front();
const Packet::Priority original_priority = packet->priority; } else {
bool first = true;
for (auto& result : results) { for (auto& result : results) {
RTC_DCHECK(result.frame); RTC_DCHECK(result.frame);
// Reuse the packet if possible.
if (!packet) {
packet.reset(new Packet);
packet->sequence_number = sequence_number;
packet->payload_type = payload_type;
}
packet->timestamp = result.timestamp;
RTC_DCHECK_GE(result.priority, 0); RTC_DCHECK_GE(result.priority, 0);
packet->priority.codec_level = result.priority; if (first) {
packet->priority.red_level = original_priority.red_level; // Re-use the node and move it to parsed_packet_list.
packet->frame = std::move(result.frame); packet_list.front() = packet_from_result(result);
parsed_packet_list.push_back(packet.release()); parsed_packet_list.splice(parsed_packet_list.end(), packet_list,
packet_list.begin());
first = false;
} else {
parsed_packet_list.push_back(packet_from_result(result));
}
}
} }
} }
} }
@ -757,7 +762,6 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
new_codec_ = true; new_codec_ = true;
update_sample_rate_and_channels = true; update_sample_rate_and_channels = true;
} else if (ret != PacketBuffer::kOK) { } else if (ret != PacketBuffer::kOK) {
PacketBuffer::DeleteAllPackets(&parsed_packet_list);
return kOtherError; return kOtherError;
} }
@ -1344,15 +1348,15 @@ int NetEqImpl::Decode(PacketList* packet_list, Operations* operation,
AudioDecoder* decoder = decoder_database_->GetActiveDecoder(); AudioDecoder* decoder = decoder_database_->GetActiveDecoder();
if (!packet_list->empty()) { if (!packet_list->empty()) {
const Packet* packet = packet_list->front(); const Packet& packet = packet_list->front();
uint8_t payload_type = packet->payload_type; uint8_t payload_type = packet.payload_type;
if (!decoder_database_->IsComfortNoise(payload_type)) { if (!decoder_database_->IsComfortNoise(payload_type)) {
decoder = decoder_database_->GetDecoder(payload_type); decoder = decoder_database_->GetDecoder(payload_type);
assert(decoder); assert(decoder);
if (!decoder) { if (!decoder) {
LOG(LS_WARNING) << "Unknown payload type " LOG(LS_WARNING) << "Unknown payload type "
<< static_cast<int>(payload_type); << static_cast<int>(payload_type);
PacketBuffer::DeleteAllPackets(packet_list); packet_list->clear();
return kDecoderNotFound; return kDecoderNotFound;
} }
bool decoder_changed; bool decoder_changed;
@ -1365,7 +1369,7 @@ int NetEqImpl::Decode(PacketList* packet_list, Operations* operation,
if (!decoder_info) { if (!decoder_info) {
LOG(LS_WARNING) << "Unknown payload type " LOG(LS_WARNING) << "Unknown payload type "
<< static_cast<int>(payload_type); << static_cast<int>(payload_type);
PacketBuffer::DeleteAllPackets(packet_list); packet_list->clear();
return kDecoderNotFound; return kDecoderNotFound;
} }
// If sampling rate or number of channels has changed, we need to make // If sampling rate or number of channels has changed, we need to make
@ -1475,13 +1479,10 @@ int NetEqImpl::DecodeCng(AudioDecoder* decoder, int* decoded_length,
int NetEqImpl::DecodeLoop(PacketList* packet_list, const Operations& operation, int NetEqImpl::DecodeLoop(PacketList* packet_list, const Operations& operation,
AudioDecoder* decoder, int* decoded_length, AudioDecoder* decoder, int* decoded_length,
AudioDecoder::SpeechType* speech_type) { AudioDecoder::SpeechType* speech_type) {
Packet* packet = NULL;
if (!packet_list->empty()) {
packet = packet_list->front();
}
// Do decoding. // Do decoding.
while (packet && !decoder_database_->IsComfortNoise(packet->payload_type)) { while (
!packet_list->empty() &&
!decoder_database_->IsComfortNoise(packet_list->front().payload_type)) {
assert(decoder); // At this point, we must have a decoder object. assert(decoder); // At this point, we must have a decoder object.
// The number of channels in the |sync_buffer_| should be the same as the // The number of channels in the |sync_buffer_| should be the same as the
// number decoder channels. // number decoder channels.
@ -1490,12 +1491,11 @@ int NetEqImpl::DecodeLoop(PacketList* packet_list, const Operations& operation,
assert(operation == kNormal || operation == kAccelerate || assert(operation == kNormal || operation == kAccelerate ||
operation == kFastAccelerate || operation == kMerge || operation == kFastAccelerate || operation == kMerge ||
operation == kPreemptiveExpand); operation == kPreemptiveExpand);
packet_list->pop_front();
auto opt_result = packet->frame->Decode( auto opt_result = packet_list->front().frame->Decode(
rtc::ArrayView<int16_t>(&decoded_buffer_[*decoded_length], rtc::ArrayView<int16_t>(&decoded_buffer_[*decoded_length],
decoded_buffer_length_ - *decoded_length)); decoded_buffer_length_ - *decoded_length));
delete packet; packet_list->pop_front();
packet = NULL;
if (opt_result) { if (opt_result) {
const auto& result = *opt_result; const auto& result = *opt_result;
*speech_type = result.speech_type; *speech_type = result.speech_type;
@ -1510,27 +1510,23 @@ int NetEqImpl::DecodeLoop(PacketList* packet_list, const Operations& operation,
// TODO(ossu): What to put here? // TODO(ossu): What to put here?
LOG(LS_WARNING) << "Decode error"; LOG(LS_WARNING) << "Decode error";
*decoded_length = -1; *decoded_length = -1;
PacketBuffer::DeleteAllPackets(packet_list); packet_list->clear();
break; break;
} }
if (*decoded_length > rtc::checked_cast<int>(decoded_buffer_length_)) { if (*decoded_length > rtc::checked_cast<int>(decoded_buffer_length_)) {
// Guard against overflow. // Guard against overflow.
LOG(LS_WARNING) << "Decoded too much."; LOG(LS_WARNING) << "Decoded too much.";
PacketBuffer::DeleteAllPackets(packet_list); packet_list->clear();
return kDecodedTooMuch; return kDecodedTooMuch;
} }
if (!packet_list->empty()) {
packet = packet_list->front();
} else {
packet = NULL;
}
} // End of decode loop. } // End of decode loop.
// If the list is not empty at this point, either a decoding error terminated // If the list is not empty at this point, either a decoding error terminated
// the while-loop, or list must hold exactly one CNG packet. // the while-loop, or list must hold exactly one CNG packet.
assert(packet_list->empty() || *decoded_length < 0 || assert(
(packet_list->size() == 1 && packet && packet_list->empty() || *decoded_length < 0 ||
decoder_database_->IsComfortNoise(packet->payload_type))); (packet_list->size() == 1 &&
decoder_database_->IsComfortNoise(packet_list->front().payload_type)));
return 0; return 0;
} }
@ -1770,13 +1766,11 @@ int NetEqImpl::DoRfc3389Cng(PacketList* packet_list, bool play_dtmf) {
if (!packet_list->empty()) { if (!packet_list->empty()) {
// Must have exactly one SID frame at this point. // Must have exactly one SID frame at this point.
assert(packet_list->size() == 1); assert(packet_list->size() == 1);
Packet* packet = packet_list->front(); const Packet& packet = packet_list->front();
packet_list->pop_front(); if (!decoder_database_->IsComfortNoise(packet.payload_type)) {
if (!decoder_database_->IsComfortNoise(packet->payload_type)) {
LOG(LS_ERROR) << "Trying to decode non-CNG payload as CNG."; LOG(LS_ERROR) << "Trying to decode non-CNG payload as CNG.";
return kOtherError; return kOtherError;
} }
// UpdateParameters() deletes |packet|.
if (comfort_noise_->UpdateParameters(packet) == if (comfort_noise_->UpdateParameters(packet) ==
ComfortNoise::kInternalError) { ComfortNoise::kInternalError) {
algorithm_buffer_->Zeros(output_size_samples_); algorithm_buffer_->Zeros(output_size_samples_);
@ -1960,19 +1954,16 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
// Packet extraction loop. // Packet extraction loop.
do { do {
timestamp_ = next_packet->timestamp; timestamp_ = next_packet->timestamp;
size_t discard_count = 0; rtc::Optional<Packet> packet = packet_buffer_->GetNextPacket();
Packet* packet = packet_buffer_->GetNextPacket(&discard_count);
// |next_packet| may be invalid after the |packet_buffer_| operation. // |next_packet| may be invalid after the |packet_buffer_| operation.
next_packet = NULL; next_packet = nullptr;
if (!packet) { if (!packet) {
LOG(LS_ERROR) << "Should always be able to extract a packet here"; LOG(LS_ERROR) << "Should always be able to extract a packet here";
assert(false); // Should always be able to extract a packet here. assert(false); // Should always be able to extract a packet here.
return -1; return -1;
} }
stats_.PacketsDiscarded(discard_count);
stats_.StoreWaitingTime(packet->waiting_time->ElapsedMs()); stats_.StoreWaitingTime(packet->waiting_time->ElapsedMs());
RTC_DCHECK(!packet->empty()); RTC_DCHECK(!packet->empty());
packet_list->push_back(packet); // Store packet in list.
if (first_packet) { if (first_packet) {
first_packet = false; first_packet = false;
@ -2008,6 +1999,9 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
} }
extracted_samples = packet->timestamp - first_timestamp + packet_duration; extracted_samples = packet->timestamp - first_timestamp + packet_duration;
packet_list->push_back(std::move(*packet)); // Store packet in list.
packet = rtc::Optional<Packet>(); // Ensure it's never used after the move.
// Check what packet is available next. // Check what packet is available next.
next_packet = packet_buffer_->PeekNextPacket(); next_packet = packet_buffer_->PeekNextPacket();
next_packet_available = false; next_packet_available = false;

View File

@ -52,7 +52,7 @@ namespace webrtc {
// buffer. The purpose is to delete all inserted packets properly, to avoid // buffer. The purpose is to delete all inserted packets properly, to avoid
// memory leaks in the test. // memory leaks in the test.
int DeletePacketsAndReturnOk(PacketList* packet_list) { int DeletePacketsAndReturnOk(PacketList* packet_list) {
PacketBuffer::DeleteAllPackets(packet_list); packet_list->clear();
return PacketBuffer::kOK; return PacketBuffer::kOK;
} }

View File

@ -13,7 +13,23 @@
namespace webrtc { namespace webrtc {
Packet::Packet() = default; Packet::Packet() = default;
Packet::Packet(Packet&& b) = default;
Packet::~Packet() = default; Packet::~Packet() = default;
Packet& Packet::operator=(Packet&& b) = default;
Packet Packet::Clone() const {
RTC_CHECK(!frame);
Packet clone;
clone.timestamp = timestamp;
clone.sequence_number = sequence_number;
clone.payload_type = payload_type;
clone.payload.SetData(payload.data(), payload.size());
clone.priority = priority;
return clone;
}
} // namespace webrtc } // namespace webrtc

View File

@ -75,8 +75,17 @@ struct Packet {
std::unique_ptr<AudioDecoder::EncodedAudioFrame> frame; std::unique_ptr<AudioDecoder::EncodedAudioFrame> frame;
Packet(); Packet();
Packet(Packet&& b);
~Packet(); ~Packet();
// Packets should generally be moved around but sometimes it's useful to make
// a copy, for example for testing purposes. NOTE: Will only work for
// un-parsed packets, i.e. |frame| must be unset. The payload will, however,
// be copied. |waiting_time| will also not be copied.
Packet Clone() const;
Packet& operator=(Packet&& b);
// Comparison operators. Establish a packet ordering based on (1) timestamp, // Comparison operators. Establish a packet ordering based on (1) timestamp,
// (2) sequence number and (3) redundancy. // (2) sequence number and (3) redundancy.
// Timestamp and sequence numbers are compared taking wrap-around into // Timestamp and sequence numbers are compared taking wrap-around into
@ -109,7 +118,7 @@ struct Packet {
}; };
// A list of packets. // A list of packets.
typedef std::list<Packet*> PacketList; typedef std::list<Packet> PacketList;
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_PACKET_H_ #endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_PACKET_H_

View File

@ -27,15 +27,15 @@ namespace {
// Operator() returns true when |packet| goes before |new_packet|. // Operator() returns true when |packet| goes before |new_packet|.
class NewTimestampIsLarger { class NewTimestampIsLarger {
public: public:
explicit NewTimestampIsLarger(const Packet* new_packet) explicit NewTimestampIsLarger(const Packet& new_packet)
: new_packet_(new_packet) { : new_packet_(new_packet) {
} }
bool operator()(Packet* packet) { bool operator()(const Packet& packet) {
return (*new_packet_ >= *packet); return (new_packet_ >= packet);
} }
private: private:
const Packet* new_packet_; const Packet& new_packet_;
}; };
// Returns true if both payload types are known to the decoder database, and // Returns true if both payload types are known to the decoder database, and
@ -60,28 +60,25 @@ PacketBuffer::~PacketBuffer() {
// Flush the buffer. All packets in the buffer will be destroyed. // Flush the buffer. All packets in the buffer will be destroyed.
void PacketBuffer::Flush() { void PacketBuffer::Flush() {
DeleteAllPackets(&buffer_); buffer_.clear();
} }
bool PacketBuffer::Empty() const { bool PacketBuffer::Empty() const {
return buffer_.empty(); return buffer_.empty();
} }
int PacketBuffer::InsertPacket(Packet* packet) { int PacketBuffer::InsertPacket(Packet&& packet) {
if (!packet || packet->empty()) { if (packet.empty()) {
if (packet) {
delete packet;
}
LOG(LS_WARNING) << "InsertPacket invalid packet"; LOG(LS_WARNING) << "InsertPacket invalid packet";
return kInvalidPacket; return kInvalidPacket;
} }
RTC_DCHECK_GE(packet->priority.codec_level, 0); RTC_DCHECK_GE(packet.priority.codec_level, 0);
RTC_DCHECK_GE(packet->priority.red_level, 0); RTC_DCHECK_GE(packet.priority.red_level, 0);
int return_val = kOK; int return_val = kOK;
packet->waiting_time = tick_timer_->GetNewStopwatch(); packet.waiting_time = tick_timer_->GetNewStopwatch();
if (buffer_.size() >= max_number_of_packets_) { if (buffer_.size() >= max_number_of_packets_) {
// Buffer is full. Flush it. // Buffer is full. Flush it.
@ -100,8 +97,7 @@ int PacketBuffer::InsertPacket(Packet* packet) {
// The new packet is to be inserted to the right of |rit|. If it has the same // The new packet is to be inserted to the right of |rit|. If it has the same
// timestamp as |rit|, which has a higher priority, do not insert the new // timestamp as |rit|, which has a higher priority, do not insert the new
// packet to list. // packet to list.
if (rit != buffer_.rend() && packet->timestamp == (*rit)->timestamp) { if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
delete packet;
return return_val; return return_val;
} }
@ -109,11 +105,10 @@ int PacketBuffer::InsertPacket(Packet* packet) {
// timestamp as |it|, which has a lower priority, replace |it| with the new // timestamp as |it|, which has a lower priority, replace |it| with the new
// packet. // packet.
PacketList::iterator it = rit.base(); PacketList::iterator it = rit.base();
if (it != buffer_.end() && packet->timestamp == (*it)->timestamp) { if (it != buffer_.end() && packet.timestamp == it->timestamp) {
delete *it;
it = buffer_.erase(it); it = buffer_.erase(it);
} }
buffer_.insert(it, packet); // Insert the packet at that position. buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
return return_val; return return_val;
} }
@ -124,43 +119,42 @@ int PacketBuffer::InsertPacketList(
rtc::Optional<uint8_t>* current_rtp_payload_type, rtc::Optional<uint8_t>* current_rtp_payload_type,
rtc::Optional<uint8_t>* current_cng_rtp_payload_type) { rtc::Optional<uint8_t>* current_cng_rtp_payload_type) {
bool flushed = false; bool flushed = false;
while (!packet_list->empty()) { for (auto& packet : *packet_list) {
Packet* packet = packet_list->front(); if (decoder_database.IsComfortNoise(packet.payload_type)) {
if (decoder_database.IsComfortNoise(packet->payload_type)) {
if (*current_cng_rtp_payload_type && if (*current_cng_rtp_payload_type &&
**current_cng_rtp_payload_type != packet->payload_type) { **current_cng_rtp_payload_type != packet.payload_type) {
// New CNG payload type implies new codec type. // New CNG payload type implies new codec type.
*current_rtp_payload_type = rtc::Optional<uint8_t>(); *current_rtp_payload_type = rtc::Optional<uint8_t>();
Flush(); Flush();
flushed = true; flushed = true;
} }
*current_cng_rtp_payload_type = *current_cng_rtp_payload_type =
rtc::Optional<uint8_t>(packet->payload_type); rtc::Optional<uint8_t>(packet.payload_type);
} else if (!decoder_database.IsDtmf(packet->payload_type)) { } else if (!decoder_database.IsDtmf(packet.payload_type)) {
// This must be speech. // This must be speech.
if ((*current_rtp_payload_type && if ((*current_rtp_payload_type &&
**current_rtp_payload_type != packet->payload_type) || **current_rtp_payload_type != packet.payload_type) ||
(*current_cng_rtp_payload_type && (*current_cng_rtp_payload_type &&
!EqualSampleRates(packet->payload_type, !EqualSampleRates(packet.payload_type,
**current_cng_rtp_payload_type, **current_cng_rtp_payload_type,
decoder_database))) { decoder_database))) {
*current_cng_rtp_payload_type = rtc::Optional<uint8_t>(); *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
Flush(); Flush();
flushed = true; flushed = true;
} }
*current_rtp_payload_type = rtc::Optional<uint8_t>(packet->payload_type); *current_rtp_payload_type = rtc::Optional<uint8_t>(packet.payload_type);
} }
int return_val = InsertPacket(packet); int return_val = InsertPacket(std::move(packet));
packet_list->pop_front();
if (return_val == kFlushed) { if (return_val == kFlushed) {
// The buffer flushed, but this is not an error. We can still continue. // The buffer flushed, but this is not an error. We can still continue.
flushed = true; flushed = true;
} else if (return_val != kOK) { } else if (return_val != kOK) {
// An error occurred. Delete remaining packets in list and return. // An error occurred. Delete remaining packets in list and return.
DeleteAllPackets(packet_list); packet_list->clear();
return return_val; return return_val;
} }
} }
packet_list->clear();
return flushed ? kFlushed : kOK; return flushed ? kFlushed : kOK;
} }
@ -171,7 +165,7 @@ int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
if (!next_timestamp) { if (!next_timestamp) {
return kInvalidPointer; return kInvalidPointer;
} }
*next_timestamp = buffer_.front()->timestamp; *next_timestamp = buffer_.front().timestamp;
return kOK; return kOK;
} }
@ -185,9 +179,9 @@ int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
} }
PacketList::const_iterator it; PacketList::const_iterator it;
for (it = buffer_.begin(); it != buffer_.end(); ++it) { for (it = buffer_.begin(); it != buffer_.end(); ++it) {
if ((*it)->timestamp >= timestamp) { if (it->timestamp >= timestamp) {
// Found a packet matching the search. // Found a packet matching the search.
*next_timestamp = (*it)->timestamp; *next_timestamp = it->timestamp;
return kOK; return kOK;
} }
} }
@ -195,36 +189,20 @@ int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
} }
const Packet* PacketBuffer::PeekNextPacket() const { const Packet* PacketBuffer::PeekNextPacket() const {
return buffer_.empty() ? nullptr : buffer_.front(); return buffer_.empty() ? nullptr : &buffer_.front();
} }
Packet* PacketBuffer::GetNextPacket(size_t* discard_count) { rtc::Optional<Packet> PacketBuffer::GetNextPacket() {
if (Empty()) { if (Empty()) {
// Buffer is empty. // Buffer is empty.
return NULL; return rtc::Optional<Packet>();
} }
Packet* packet = buffer_.front(); rtc::Optional<Packet> packet(std::move(buffer_.front()));
// Assert that the packet sanity checks in InsertPacket method works. // Assert that the packet sanity checks in InsertPacket method works.
RTC_DCHECK(packet && !packet->empty()); RTC_DCHECK(!packet->empty());
buffer_.pop_front(); buffer_.pop_front();
// Discard other packets with the same timestamp. These are duplicates or
// redundant payloads that should not be used.
size_t discards = 0;
while (!Empty() && buffer_.front()->timestamp == packet->timestamp) {
if (DiscardNextPacket() != kOK) {
assert(false); // Must be ok by design.
}
++discards;
}
// The way of inserting packet should not cause any packet discarding here.
// TODO(minyue): remove |discard_count|.
assert(discards == 0);
if (discard_count)
*discard_count = discards;
return packet; return packet;
} }
@ -233,16 +211,15 @@ int PacketBuffer::DiscardNextPacket() {
return kBufferEmpty; return kBufferEmpty;
} }
// Assert that the packet sanity checks in InsertPacket method works. // Assert that the packet sanity checks in InsertPacket method works.
RTC_DCHECK(buffer_.front()); RTC_DCHECK(!buffer_.front().empty());
RTC_DCHECK(!buffer_.front()->empty()); buffer_.pop_front();
DeleteFirstPacket(&buffer_);
return kOK; return kOK;
} }
int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit, int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
uint32_t horizon_samples) { uint32_t horizon_samples) {
while (!Empty() && timestamp_limit != buffer_.front()->timestamp && while (!Empty() && timestamp_limit != buffer_.front().timestamp &&
IsObsoleteTimestamp(buffer_.front()->timestamp, timestamp_limit, IsObsoleteTimestamp(buffer_.front().timestamp, timestamp_limit,
horizon_samples)) { horizon_samples)) {
if (DiscardNextPacket() != kOK) { if (DiscardNextPacket() != kOK) {
assert(false); // Must be ok by design. assert(false); // Must be ok by design.
@ -257,9 +234,8 @@ int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) { void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
for (auto it = buffer_.begin(); it != buffer_.end(); /* */) { for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
Packet* packet = *it; const Packet& packet = *it;
if (packet->payload_type == payload_type) { if (packet.payload_type == payload_type) {
delete packet;
it = buffer_.erase(it); it = buffer_.erase(it);
} else { } else {
++it; ++it;
@ -274,14 +250,14 @@ size_t PacketBuffer::NumPacketsInBuffer() const {
size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const { size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
size_t num_samples = 0; size_t num_samples = 0;
size_t last_duration = last_decoded_length; size_t last_duration = last_decoded_length;
for (Packet* packet : buffer_) { for (const Packet& packet : buffer_) {
if (packet->frame) { if (packet.frame) {
// TODO(hlundin): Verify that it's fine to count all packets and remove // TODO(hlundin): Verify that it's fine to count all packets and remove
// this check. // this check.
if (packet->priority != Packet::Priority(0, 0)) { if (packet.priority != Packet::Priority(0, 0)) {
continue; continue;
} }
size_t duration = packet->frame->Duration(); size_t duration = packet.frame->Duration();
if (duration > 0) { if (duration > 0) {
last_duration = duration; // Save the most up-to-date (valid) duration. last_duration = duration; // Save the most up-to-date (valid) duration.
} }
@ -291,22 +267,6 @@ size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
return num_samples; return num_samples;
} }
bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
if (packet_list->empty()) {
return false;
}
Packet* first_packet = packet_list->front();
delete first_packet;
packet_list->pop_front();
return true;
}
void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
while (DeleteFirstPacket(packet_list)) {
// Continue while the list is not empty.
}
}
void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const { void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
*num_packets = static_cast<int>(buffer_.size()); *num_packets = static_cast<int>(buffer_.size());
*max_num_packets = static_cast<int>(max_number_of_packets_); *max_num_packets = static_cast<int>(max_number_of_packets_);

View File

@ -51,7 +51,7 @@ class PacketBuffer {
// the packet object. // the packet object.
// Returns PacketBuffer::kOK on success, PacketBuffer::kFlushed if the buffer // Returns PacketBuffer::kOK on success, PacketBuffer::kFlushed if the buffer
// was flushed due to overfilling. // was flushed due to overfilling.
virtual int InsertPacket(Packet* packet); virtual int InsertPacket(Packet&& packet);
// Inserts a list of packets into the buffer. The buffer will take over // Inserts a list of packets into the buffer. The buffer will take over
// ownership of the packet objects. // ownership of the packet objects.
@ -85,13 +85,9 @@ class PacketBuffer {
// NULL if the buffer is empty. // NULL if the buffer is empty.
virtual const Packet* PeekNextPacket() const; virtual const Packet* PeekNextPacket() const;
// Extracts the first packet in the buffer and returns a pointer to it. // Extracts the first packet in the buffer and returns it.
// Returns NULL if the buffer is empty. The caller is responsible for deleting // Returns an empty optional if the buffer is empty.
// the packet. virtual rtc::Optional<Packet> GetNextPacket();
// Subsequent packets with the same timestamp as the one extracted will be
// discarded and properly deleted. The number of discarded packets will be
// written to the output variable |discard_count|.
virtual Packet* GetNextPacket(size_t* discard_count);
// Discards the first packet in the buffer. The packet is deleted. // Discards the first packet in the buffer. The packet is deleted.
// Returns PacketBuffer::kBufferEmpty if the buffer is empty, // Returns PacketBuffer::kBufferEmpty if the buffer is empty,
@ -123,15 +119,6 @@ class PacketBuffer {
virtual void BufferStat(int* num_packets, int* max_num_packets) const; virtual void BufferStat(int* num_packets, int* max_num_packets) const;
// Static method that properly deletes the first packet, and its payload
// array, in |packet_list|. Returns false if |packet_list| already was empty,
// otherwise true.
static bool DeleteFirstPacket(PacketList* packet_list);
// Static method that properly deletes all packets, and their payload arrays,
// in |packet_list|.
static void DeleteAllPackets(PacketList* packet_list);
// Static method returning true if |timestamp| is older than |timestamp_limit| // Static method returning true if |timestamp| is older than |timestamp_limit|
// but less than |horizon_samples| behind |timestamp_limit|. For instance, // but less than |horizon_samples| behind |timestamp_limit|. For instance,
// with timestamp_limit = 100 and horizon_samples = 10, a timestamp in the // with timestamp_limit = 100 and horizon_samples = 10, a timestamp in the

View File

@ -30,7 +30,7 @@ class PacketGenerator {
PacketGenerator(uint16_t seq_no, uint32_t ts, uint8_t pt, int frame_size); PacketGenerator(uint16_t seq_no, uint32_t ts, uint8_t pt, int frame_size);
virtual ~PacketGenerator() {} virtual ~PacketGenerator() {}
void Reset(uint16_t seq_no, uint32_t ts, uint8_t pt, int frame_size); void Reset(uint16_t seq_no, uint32_t ts, uint8_t pt, int frame_size);
Packet* NextPacket(int payload_size_bytes); Packet NextPacket(int payload_size_bytes);
uint16_t seq_no_; uint16_t seq_no_;
uint32_t ts_; uint32_t ts_;
@ -51,12 +51,12 @@ void PacketGenerator::Reset(uint16_t seq_no, uint32_t ts, uint8_t pt,
frame_size_ = frame_size; frame_size_ = frame_size;
} }
Packet* PacketGenerator::NextPacket(int payload_size_bytes) { Packet PacketGenerator::NextPacket(int payload_size_bytes) {
Packet* packet = new Packet; Packet packet;
packet->sequence_number = seq_no_; packet.sequence_number = seq_no_;
packet->timestamp = ts_; packet.timestamp = ts_;
packet->payload_type = pt_; packet.payload_type = pt_;
packet->payload.SetSize(payload_size_bytes); packet.payload.SetSize(payload_size_bytes);
++seq_no_; ++seq_no_;
ts_ += frame_size_; ts_ += frame_size_;
return packet; return packet;
@ -88,16 +88,15 @@ TEST(PacketBuffer, InsertPacket) {
PacketGenerator gen(17u, 4711u, 0, 10); PacketGenerator gen(17u, 4711u, 0, 10);
const int payload_len = 100; const int payload_len = 100;
Packet* packet = gen.NextPacket(payload_len); const Packet packet = gen.NextPacket(payload_len);
EXPECT_EQ(0, buffer.InsertPacket(packet.Clone()));
EXPECT_EQ(0, buffer.InsertPacket(packet));
uint32_t next_ts; uint32_t next_ts;
EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts)); EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts));
EXPECT_EQ(4711u, next_ts); EXPECT_EQ(4711u, next_ts);
EXPECT_FALSE(buffer.Empty()); EXPECT_FALSE(buffer.Empty());
EXPECT_EQ(1u, buffer.NumPacketsInBuffer()); EXPECT_EQ(1u, buffer.NumPacketsInBuffer());
const Packet* next_packet = buffer.PeekNextPacket(); const Packet* next_packet = buffer.PeekNextPacket();
EXPECT_EQ(packet, next_packet); // Compare pointer addresses. EXPECT_EQ(packet, *next_packet); // Compare contents.
// Do not explicitly flush buffer or delete packet to test that it is deleted // Do not explicitly flush buffer or delete packet to test that it is deleted
// with the buffer. (Tested with Valgrind or similar tool.) // with the buffer. (Tested with Valgrind or similar tool.)
@ -112,8 +111,8 @@ TEST(PacketBuffer, FlushBuffer) {
// Insert 10 small packets; should be ok. // Insert 10 small packets; should be ok.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
Packet* packet = gen.NextPacket(payload_len); EXPECT_EQ(PacketBuffer::kOK,
EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(packet)); buffer.InsertPacket(gen.NextPacket(payload_len)));
} }
EXPECT_EQ(10u, buffer.NumPacketsInBuffer()); EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
EXPECT_FALSE(buffer.Empty()); EXPECT_FALSE(buffer.Empty());
@ -134,21 +133,21 @@ TEST(PacketBuffer, OverfillBuffer) {
const int payload_len = 10; const int payload_len = 10;
int i; int i;
for (i = 0; i < 10; ++i) { for (i = 0; i < 10; ++i) {
Packet* packet = gen.NextPacket(payload_len); EXPECT_EQ(PacketBuffer::kOK,
EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(packet)); buffer.InsertPacket(gen.NextPacket(payload_len)));
} }
EXPECT_EQ(10u, buffer.NumPacketsInBuffer()); EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
uint32_t next_ts; uint32_t next_ts;
EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts)); EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts));
EXPECT_EQ(0u, next_ts); // Expect first inserted packet to be first in line. EXPECT_EQ(0u, next_ts); // Expect first inserted packet to be first in line.
const Packet packet = gen.NextPacket(payload_len);
// Insert 11th packet; should flush the buffer and insert it after flushing. // Insert 11th packet; should flush the buffer and insert it after flushing.
Packet* packet = gen.NextPacket(payload_len); EXPECT_EQ(PacketBuffer::kFlushed, buffer.InsertPacket(packet.Clone()));
EXPECT_EQ(PacketBuffer::kFlushed, buffer.InsertPacket(packet));
EXPECT_EQ(1u, buffer.NumPacketsInBuffer()); EXPECT_EQ(1u, buffer.NumPacketsInBuffer());
EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts)); EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts));
// Expect last inserted packet to be first in line. // Expect last inserted packet to be first in line.
EXPECT_EQ(packet->timestamp, next_ts); EXPECT_EQ(packet.timestamp, next_ts);
// Flush buffer to delete all packets. // Flush buffer to delete all packets.
buffer.Flush(); buffer.Flush();
@ -164,8 +163,7 @@ TEST(PacketBuffer, InsertPacketList) {
// Insert 10 small packets. // Insert 10 small packets.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
Packet* packet = gen.NextPacket(payload_len); list.push_back(gen.NextPacket(payload_len));
list.push_back(packet);
} }
MockDecoderDatabase decoder_database; MockDecoderDatabase decoder_database;
@ -202,14 +200,14 @@ TEST(PacketBuffer, InsertPacketListChangePayloadType) {
// Insert 10 small packets. // Insert 10 small packets.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
Packet* packet = gen.NextPacket(payload_len); list.push_back(gen.NextPacket(payload_len));
list.push_back(packet);
} }
// Insert 11th packet of another payload type (not CNG). // Insert 11th packet of another payload type (not CNG).
Packet* packet = gen.NextPacket(payload_len); {
packet->payload_type = 1; Packet packet = gen.NextPacket(payload_len);
list.push_back(packet); packet.payload_type = 1;
list.push_back(std::move(packet));
}
MockDecoderDatabase decoder_database; MockDecoderDatabase decoder_database;
auto factory = CreateBuiltinAudioDecoderFactory(); auto factory = CreateBuiltinAudioDecoderFactory();
@ -266,7 +264,7 @@ TEST(PacketBuffer, ExtractOrderRedundancy) {
const size_t kExpectPacketsInBuffer = 9; const size_t kExpectPacketsInBuffer = 9;
std::vector<Packet*> expect_order(kExpectPacketsInBuffer); std::vector<Packet> expect_order(kExpectPacketsInBuffer);
PacketGenerator gen(0, 0, 0, kFrameSize); PacketGenerator gen(0, 0, 0, kFrameSize);
@ -275,22 +273,19 @@ TEST(PacketBuffer, ExtractOrderRedundancy) {
packet_facts[i].timestamp, packet_facts[i].timestamp,
packet_facts[i].payload_type, packet_facts[i].payload_type,
kFrameSize); kFrameSize);
Packet* packet = gen.NextPacket(kPayloadLength); Packet packet = gen.NextPacket(kPayloadLength);
packet->priority.red_level = packet_facts[i].primary ? 0 : 1; packet.priority.red_level = packet_facts[i].primary ? 0 : 1;
EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(packet)); EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(packet.Clone()));
if (packet_facts[i].extract_order >= 0) { if (packet_facts[i].extract_order >= 0) {
expect_order[packet_facts[i].extract_order] = packet; expect_order[packet_facts[i].extract_order] = std::move(packet);
} }
} }
EXPECT_EQ(kExpectPacketsInBuffer, buffer.NumPacketsInBuffer()); EXPECT_EQ(kExpectPacketsInBuffer, buffer.NumPacketsInBuffer());
size_t drop_count;
for (size_t i = 0; i < kExpectPacketsInBuffer; ++i) { for (size_t i = 0; i < kExpectPacketsInBuffer; ++i) {
Packet* packet = buffer.GetNextPacket(&drop_count); const rtc::Optional<Packet> packet = buffer.GetNextPacket();
EXPECT_EQ(0u, drop_count); EXPECT_EQ(packet, expect_order[i]); // Compare contents.
EXPECT_EQ(packet, expect_order[i]); // Compare pointer addresses.
delete packet;
} }
EXPECT_TRUE(buffer.Empty()); EXPECT_TRUE(buffer.Empty());
} }
@ -307,8 +302,7 @@ TEST(PacketBuffer, DiscardPackets) {
// Insert 10 small packets. // Insert 10 small packets.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
Packet* packet = gen.NextPacket(payload_len); buffer.InsertPacket(gen.NextPacket(payload_len));
buffer.InsertPacket(packet);
} }
EXPECT_EQ(10u, buffer.NumPacketsInBuffer()); EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
@ -339,11 +333,11 @@ TEST(PacketBuffer, Reordering) {
// a (rather strange) reordering. // a (rather strange) reordering.
PacketList list; PacketList list;
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
Packet* packet = gen.NextPacket(payload_len); Packet packet = gen.NextPacket(payload_len);
if (i % 2) { if (i % 2) {
list.push_front(packet); list.push_front(std::move(packet));
} else { } else {
list.push_back(packet); list.push_back(std::move(packet));
} }
} }
@ -364,11 +358,10 @@ TEST(PacketBuffer, Reordering) {
// Extract them and make sure that come out in the right order. // Extract them and make sure that come out in the right order.
uint32_t current_ts = start_ts; uint32_t current_ts = start_ts;
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
Packet* packet = buffer.GetNextPacket(NULL); const rtc::Optional<Packet> packet = buffer.GetNextPacket();
ASSERT_FALSE(packet == NULL); ASSERT_TRUE(packet);
EXPECT_EQ(current_ts, packet->timestamp); EXPECT_EQ(current_ts, packet->timestamp);
current_ts += ts_increment; current_ts += ts_increment;
delete packet;
} }
EXPECT_TRUE(buffer.Empty()); EXPECT_TRUE(buffer.Empty());
@ -415,9 +408,11 @@ TEST(PacketBuffer, CngFirstThenSpeechWithNewSampleRate) {
current_cng_pt); // CNG payload type set. current_cng_pt); // CNG payload type set.
// Insert second packet, which is wide-band speech. // Insert second packet, which is wide-band speech.
Packet* packet = gen.NextPacket(kPayloadLen); {
packet->payload_type = kSpeechPt; Packet packet = gen.NextPacket(kPayloadLen);
list.push_back(packet); packet.payload_type = kSpeechPt;
list.push_back(std::move(packet));
}
// Expect the buffer to flush out the CNG packet, since it does not match the // Expect the buffer to flush out the CNG packet, since it does not match the
// new speech sample rate. // new speech sample rate.
EXPECT_EQ(PacketBuffer::kFlushed, EXPECT_EQ(PacketBuffer::kFlushed,
@ -445,26 +440,25 @@ TEST(PacketBuffer, Failures) {
TickTimer tick_timer; TickTimer tick_timer;
PacketBuffer* buffer = new PacketBuffer(100, &tick_timer); // 100 packets. PacketBuffer* buffer = new PacketBuffer(100, &tick_timer); // 100 packets.
Packet* packet = NULL; {
EXPECT_EQ(PacketBuffer::kInvalidPacket, buffer->InsertPacket(packet)); Packet packet = gen.NextPacket(payload_len);
packet = gen.NextPacket(payload_len); packet.payload.Clear();
packet->payload.Clear(); EXPECT_EQ(PacketBuffer::kInvalidPacket,
EXPECT_EQ(PacketBuffer::kInvalidPacket, buffer->InsertPacket(packet)); buffer->InsertPacket(std::move(packet)));
// Packet is deleted by the PacketBuffer. }
// Buffer should still be empty. Test all empty-checks. // Buffer should still be empty. Test all empty-checks.
uint32_t temp_ts; uint32_t temp_ts;
EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->NextTimestamp(&temp_ts)); EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->NextTimestamp(&temp_ts));
EXPECT_EQ(PacketBuffer::kBufferEmpty, EXPECT_EQ(PacketBuffer::kBufferEmpty,
buffer->NextHigherTimestamp(0, &temp_ts)); buffer->NextHigherTimestamp(0, &temp_ts));
EXPECT_EQ(NULL, buffer->PeekNextPacket()); EXPECT_EQ(NULL, buffer->PeekNextPacket());
EXPECT_EQ(NULL, buffer->GetNextPacket(NULL)); EXPECT_FALSE(buffer->GetNextPacket());
EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->DiscardNextPacket()); EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->DiscardNextPacket());
EXPECT_EQ(0, buffer->DiscardAllOldPackets(0)); // 0 packets discarded. EXPECT_EQ(0, buffer->DiscardAllOldPackets(0)); // 0 packets discarded.
// Insert one packet to make the buffer non-empty. // Insert one packet to make the buffer non-empty.
packet = gen.NextPacket(payload_len); EXPECT_EQ(PacketBuffer::kOK,
EXPECT_EQ(PacketBuffer::kOK, buffer->InsertPacket(packet)); buffer->InsertPacket(gen.NextPacket(payload_len)));
EXPECT_EQ(PacketBuffer::kInvalidPointer, buffer->NextTimestamp(NULL)); EXPECT_EQ(PacketBuffer::kInvalidPointer, buffer->NextTimestamp(NULL));
EXPECT_EQ(PacketBuffer::kInvalidPointer, EXPECT_EQ(PacketBuffer::kInvalidPointer,
buffer->NextHigherTimestamp(0, NULL)); buffer->NextHigherTimestamp(0, NULL));
@ -476,9 +470,11 @@ TEST(PacketBuffer, Failures) {
buffer = new PacketBuffer(100, &tick_timer); // 100 packets. buffer = new PacketBuffer(100, &tick_timer); // 100 packets.
PacketList list; PacketList list;
list.push_back(gen.NextPacket(payload_len)); // Valid packet. list.push_back(gen.NextPacket(payload_len)); // Valid packet.
packet = gen.NextPacket(payload_len); {
packet->payload.Clear(); // Invalid. Packet packet = gen.NextPacket(payload_len);
list.push_back(packet); packet.payload.Clear(); // Invalid.
list.push_back(std::move(packet));
}
list.push_back(gen.NextPacket(payload_len)); // Valid packet. list.push_back(gen.NextPacket(payload_len)); // Valid packet.
MockDecoderDatabase decoder_database; MockDecoderDatabase decoder_database;
auto factory = CreateBuiltinAudioDecoderFactory(); auto factory = CreateBuiltinAudioDecoderFactory();
@ -502,127 +498,109 @@ TEST(PacketBuffer, Failures) {
// The function should return true if the first packet "goes before" the second. // The function should return true if the first packet "goes before" the second.
TEST(PacketBuffer, ComparePackets) { TEST(PacketBuffer, ComparePackets) {
PacketGenerator gen(0, 0, 0, 10); PacketGenerator gen(0, 0, 0, 10);
std::unique_ptr<Packet> a(gen.NextPacket(10)); // SN = 0, TS = 0. Packet a(gen.NextPacket(10)); // SN = 0, TS = 0.
std::unique_ptr<Packet> b(gen.NextPacket(10)); // SN = 1, TS = 10. Packet b(gen.NextPacket(10)); // SN = 1, TS = 10.
EXPECT_FALSE(*a == *b); EXPECT_FALSE(a == b);
EXPECT_TRUE(*a != *b); EXPECT_TRUE(a != b);
EXPECT_TRUE(*a < *b); EXPECT_TRUE(a < b);
EXPECT_FALSE(*a > *b); EXPECT_FALSE(a > b);
EXPECT_TRUE(*a <= *b); EXPECT_TRUE(a <= b);
EXPECT_FALSE(*a >= *b); EXPECT_FALSE(a >= b);
// Testing wrap-around case; 'a' is earlier but has a larger timestamp value. // Testing wrap-around case; 'a' is earlier but has a larger timestamp value.
a->timestamp = 0xFFFFFFFF - 10; a.timestamp = 0xFFFFFFFF - 10;
EXPECT_FALSE(*a == *b); EXPECT_FALSE(a == b);
EXPECT_TRUE(*a != *b); EXPECT_TRUE(a != b);
EXPECT_TRUE(*a < *b); EXPECT_TRUE(a < b);
EXPECT_FALSE(*a > *b); EXPECT_FALSE(a > b);
EXPECT_TRUE(*a <= *b); EXPECT_TRUE(a <= b);
EXPECT_FALSE(*a >= *b); EXPECT_FALSE(a >= b);
// Test equal packets. // Test equal packets.
EXPECT_TRUE(*a == *a); EXPECT_TRUE(a == a);
EXPECT_FALSE(*a != *a); EXPECT_FALSE(a != a);
EXPECT_FALSE(*a < *a); EXPECT_FALSE(a < a);
EXPECT_FALSE(*a > *a); EXPECT_FALSE(a > a);
EXPECT_TRUE(*a <= *a); EXPECT_TRUE(a <= a);
EXPECT_TRUE(*a >= *a); EXPECT_TRUE(a >= a);
// Test equal timestamps but different sequence numbers (0 and 1). // Test equal timestamps but different sequence numbers (0 and 1).
a->timestamp = b->timestamp; a.timestamp = b.timestamp;
EXPECT_FALSE(*a == *b); EXPECT_FALSE(a == b);
EXPECT_TRUE(*a != *b); EXPECT_TRUE(a != b);
EXPECT_TRUE(*a < *b); EXPECT_TRUE(a < b);
EXPECT_FALSE(*a > *b); EXPECT_FALSE(a > b);
EXPECT_TRUE(*a <= *b); EXPECT_TRUE(a <= b);
EXPECT_FALSE(*a >= *b); EXPECT_FALSE(a >= b);
// Test equal timestamps but different sequence numbers (32767 and 1). // Test equal timestamps but different sequence numbers (32767 and 1).
a->sequence_number = 0xFFFF; a.sequence_number = 0xFFFF;
EXPECT_FALSE(*a == *b); EXPECT_FALSE(a == b);
EXPECT_TRUE(*a != *b); EXPECT_TRUE(a != b);
EXPECT_TRUE(*a < *b); EXPECT_TRUE(a < b);
EXPECT_FALSE(*a > *b); EXPECT_FALSE(a > b);
EXPECT_TRUE(*a <= *b); EXPECT_TRUE(a <= b);
EXPECT_FALSE(*a >= *b); EXPECT_FALSE(a >= b);
// Test equal timestamps and sequence numbers, but differing priorities. // Test equal timestamps and sequence numbers, but differing priorities.
a->sequence_number = b->sequence_number; a.sequence_number = b.sequence_number;
a->priority = {1, 0}; a.priority = {1, 0};
b->priority = {0, 0}; b.priority = {0, 0};
// a after b // a after b
EXPECT_FALSE(*a == *b); EXPECT_FALSE(a == b);
EXPECT_TRUE(*a != *b); EXPECT_TRUE(a != b);
EXPECT_FALSE(*a < *b); EXPECT_FALSE(a < b);
EXPECT_TRUE(*a > *b); EXPECT_TRUE(a > b);
EXPECT_FALSE(*a <= *b); EXPECT_FALSE(a <= b);
EXPECT_TRUE(*a >= *b); EXPECT_TRUE(a >= b);
std::unique_ptr<Packet> c(gen.NextPacket(0)); // SN = 2, TS = 20. Packet c(gen.NextPacket(0)); // SN = 2, TS = 20.
std::unique_ptr<Packet> d(gen.NextPacket(0)); // SN = 3, TS = 20. Packet d(gen.NextPacket(0)); // SN = 3, TS = 20.
c->timestamp = b->timestamp; c.timestamp = b.timestamp;
d->timestamp = b->timestamp; d.timestamp = b.timestamp;
c->sequence_number = b->sequence_number; c.sequence_number = b.sequence_number;
d->sequence_number = b->sequence_number; d.sequence_number = b.sequence_number;
c->priority = {1, 1}; c.priority = {1, 1};
d->priority = {0, 1}; d.priority = {0, 1};
// c after d // c after d
EXPECT_FALSE(*c == *d); EXPECT_FALSE(c == d);
EXPECT_TRUE(*c != *d); EXPECT_TRUE(c != d);
EXPECT_FALSE(*c < *d); EXPECT_FALSE(c < d);
EXPECT_TRUE(*c > *d); EXPECT_TRUE(c > d);
EXPECT_FALSE(*c <= *d); EXPECT_FALSE(c <= d);
EXPECT_TRUE(*c >= *d); EXPECT_TRUE(c >= d);
// c after a // c after a
EXPECT_FALSE(*c == *a); EXPECT_FALSE(c == a);
EXPECT_TRUE(*c != *a); EXPECT_TRUE(c != a);
EXPECT_FALSE(*c < *a); EXPECT_FALSE(c < a);
EXPECT_TRUE(*c > *a); EXPECT_TRUE(c > a);
EXPECT_FALSE(*c <= *a); EXPECT_FALSE(c <= a);
EXPECT_TRUE(*c >= *a); EXPECT_TRUE(c >= a);
// c after b // c after b
EXPECT_FALSE(*c == *b); EXPECT_FALSE(c == b);
EXPECT_TRUE(*c != *b); EXPECT_TRUE(c != b);
EXPECT_FALSE(*c < *b); EXPECT_FALSE(c < b);
EXPECT_TRUE(*c > *b); EXPECT_TRUE(c > b);
EXPECT_FALSE(*c <= *b); EXPECT_FALSE(c <= b);
EXPECT_TRUE(*c >= *b); EXPECT_TRUE(c >= b);
// a after d // a after d
EXPECT_FALSE(*a == *d); EXPECT_FALSE(a == d);
EXPECT_TRUE(*a != *d); EXPECT_TRUE(a != d);
EXPECT_FALSE(*a < *d); EXPECT_FALSE(a < d);
EXPECT_TRUE(*a > *d); EXPECT_TRUE(a > d);
EXPECT_FALSE(*a <= *d); EXPECT_FALSE(a <= d);
EXPECT_TRUE(*a >= *d); EXPECT_TRUE(a >= d);
// d after b // d after b
EXPECT_FALSE(*d == *b); EXPECT_FALSE(d == b);
EXPECT_TRUE(*d != *b); EXPECT_TRUE(d != b);
EXPECT_FALSE(*d < *b); EXPECT_FALSE(d < b);
EXPECT_TRUE(*d > *b); EXPECT_TRUE(d > b);
EXPECT_FALSE(*d <= *b); EXPECT_FALSE(d <= b);
EXPECT_TRUE(*d >= *b); EXPECT_TRUE(d >= b);
}
// Test the DeleteFirstPacket DeleteAllPackets methods.
TEST(PacketBuffer, DeleteAllPackets) {
PacketGenerator gen(0, 0, 0, 10);
PacketList list;
const int payload_len = 10;
// Insert 10 small packets.
for (int i = 0; i < 10; ++i) {
Packet* packet = gen.NextPacket(payload_len);
list.push_back(packet);
}
EXPECT_TRUE(PacketBuffer::DeleteFirstPacket(&list));
EXPECT_EQ(9u, list.size());
PacketBuffer::DeleteAllPackets(&list);
EXPECT_TRUE(list.empty());
EXPECT_FALSE(PacketBuffer::DeleteFirstPacket(&list));
} }
namespace { namespace {

View File

@ -34,9 +34,9 @@ bool RedPayloadSplitter::SplitRed(PacketList* packet_list) {
bool ret = true; bool ret = true;
PacketList::iterator it = packet_list->begin(); PacketList::iterator it = packet_list->begin();
while (it != packet_list->end()) { while (it != packet_list->end()) {
const Packet* red_packet = (*it); const Packet& red_packet = *it;
assert(!red_packet->payload.empty()); assert(!red_packet.payload.empty());
const uint8_t* payload_ptr = red_packet->payload.data(); const uint8_t* payload_ptr = red_packet.payload.data();
// Read RED headers (according to RFC 2198): // Read RED headers (according to RFC 2198):
// //
@ -69,14 +69,14 @@ bool RedPayloadSplitter::SplitRed(PacketList* packet_list) {
if (last_block) { if (last_block) {
// No more header data to read. // No more header data to read.
++sum_length; // Account for RED header size of 1 byte. ++sum_length; // Account for RED header size of 1 byte.
new_header.timestamp = red_packet->timestamp; new_header.timestamp = red_packet.timestamp;
new_header.payload_length = red_packet->payload.size() - sum_length; new_header.payload_length = red_packet.payload.size() - sum_length;
payload_ptr += 1; // Advance to first payload byte. payload_ptr += 1; // Advance to first payload byte.
} else { } else {
// Bits 8 through 21 are timestamp offset. // Bits 8 through 21 are timestamp offset.
int timestamp_offset = int timestamp_offset =
(payload_ptr[1] << 6) + ((payload_ptr[2] & 0xFC) >> 2); (payload_ptr[1] << 6) + ((payload_ptr[2] & 0xFC) >> 2);
new_header.timestamp = red_packet->timestamp - timestamp_offset; new_header.timestamp = red_packet.timestamp - timestamp_offset;
// Bits 22 through 31 are payload length. // Bits 22 through 31 are payload length.
new_header.payload_length = new_header.payload_length =
((payload_ptr[2] & 0x03) << 8) + payload_ptr[3]; ((payload_ptr[2] & 0x03) << 8) + payload_ptr[3];
@ -96,7 +96,7 @@ bool RedPayloadSplitter::SplitRed(PacketList* packet_list) {
const auto& new_header = new_headers[i]; const auto& new_header = new_headers[i];
size_t payload_length = new_header.payload_length; size_t payload_length = new_header.payload_length;
if (payload_ptr + payload_length > if (payload_ptr + payload_length >
red_packet->payload.data() + red_packet->payload.size()) { red_packet.payload.data() + red_packet.payload.size()) {
// The block lengths in the RED headers do not match the overall // The block lengths in the RED headers do not match the overall
// packet length. Something is corrupt. Discard this and the remaining // packet length. Something is corrupt. Discard this and the remaining
// payloads from this packet. // payloads from this packet.
@ -105,26 +105,23 @@ bool RedPayloadSplitter::SplitRed(PacketList* packet_list) {
break; break;
} }
Packet* new_packet = new Packet; Packet new_packet;
new_packet->timestamp = new_header.timestamp; new_packet.timestamp = new_header.timestamp;
new_packet->payload_type = new_header.payload_type; new_packet.payload_type = new_header.payload_type;
new_packet->sequence_number = red_packet->sequence_number; new_packet.sequence_number = red_packet.sequence_number;
new_packet->priority.red_level = new_packet.priority.red_level =
rtc::checked_cast<int>((new_headers.size() - 1) - i); rtc::checked_cast<int>((new_headers.size() - 1) - i);
new_packet->payload.SetData(payload_ptr, payload_length); new_packet.payload.SetData(payload_ptr, payload_length);
new_packets.push_front(new_packet); new_packets.push_front(std::move(new_packet));
payload_ptr += payload_length; payload_ptr += payload_length;
} }
// Insert new packets into original list, before the element pointed to by // Insert new packets into original list, before the element pointed to by
// iterator |it|. // iterator |it|.
packet_list->splice(it, new_packets, new_packets.begin(), packet_list->splice(it, std::move(new_packets));
new_packets.end());
} else { } else {
LOG(LS_WARNING) << "SplitRed too many blocks: " << new_headers.size(); LOG(LS_WARNING) << "SplitRed too many blocks: " << new_headers.size();
ret = false; ret = false;
} }
// Delete old packet payload.
delete (*it);
// Remove |it| from the packet list. This operation effectively moves the // Remove |it| from the packet list. This operation effectively moves the
// iterator |it| to the next packet in the list. Thus, we do not have to // iterator |it| to the next packet in the list. Thus, we do not have to
// increment it manually. // increment it manually.
@ -136,11 +133,10 @@ bool RedPayloadSplitter::SplitRed(PacketList* packet_list) {
int RedPayloadSplitter::CheckRedPayloads( int RedPayloadSplitter::CheckRedPayloads(
PacketList* packet_list, PacketList* packet_list,
const DecoderDatabase& decoder_database) { const DecoderDatabase& decoder_database) {
PacketList::iterator it = packet_list->begin();
int main_payload_type = -1; int main_payload_type = -1;
int num_deleted_packets = 0; int num_deleted_packets = 0;
while (it != packet_list->end()) { for (auto it = packet_list->begin(); it != packet_list->end(); /* */) {
uint8_t this_payload_type = (*it)->payload_type; uint8_t this_payload_type = it->payload_type;
if (!decoder_database.IsDtmf(this_payload_type) && if (!decoder_database.IsDtmf(this_payload_type) &&
!decoder_database.IsComfortNoise(this_payload_type)) { !decoder_database.IsComfortNoise(this_payload_type)) {
if (main_payload_type == -1) { if (main_payload_type == -1) {
@ -149,8 +145,6 @@ int RedPayloadSplitter::CheckRedPayloads(
} else { } else {
if (this_payload_type != main_payload_type) { if (this_payload_type != main_payload_type) {
// We do not allow redundant payloads of a different type. // We do not allow redundant payloads of a different type.
// Discard this payload.
delete (*it);
// Remove |it| from the packet list. This operation effectively // Remove |it| from the packet list. This operation effectively
// moves the iterator |it| to the next packet in the list. Thus, we // moves the iterator |it| to the next packet in the list. Thus, we
// do not have to increment it manually. // do not have to increment it manually.

View File

@ -75,18 +75,18 @@ void CreateOpusFecPayload(uint8_t* payload,
// by the values in array |payload_types| (which must be of length // by the values in array |payload_types| (which must be of length
// |num_payloads|). Each redundant payload is |timestamp_offset| samples // |num_payloads|). Each redundant payload is |timestamp_offset| samples
// "behind" the the previous payload. // "behind" the the previous payload.
Packet* CreateRedPayload(size_t num_payloads, Packet CreateRedPayload(size_t num_payloads,
uint8_t* payload_types, uint8_t* payload_types,
int timestamp_offset, int timestamp_offset,
bool embed_opus_fec = false) { bool embed_opus_fec = false) {
Packet* packet = new Packet; Packet packet;
packet->payload_type = kRedPayloadType; packet.payload_type = kRedPayloadType;
packet->timestamp = kBaseTimestamp; packet.timestamp = kBaseTimestamp;
packet->sequence_number = kSequenceNumber; packet.sequence_number = kSequenceNumber;
packet->payload.SetSize((kPayloadLength + 1) + packet.payload.SetSize((kPayloadLength + 1) +
(num_payloads - 1) * (num_payloads - 1) *
(kPayloadLength + kRedHeaderLength)); (kPayloadLength + kRedHeaderLength));
uint8_t* payload_ptr = packet->payload.data(); uint8_t* payload_ptr = packet.payload.data();
for (size_t i = 0; i < num_payloads; ++i) { for (size_t i = 0; i < num_payloads; ++i) {
// Write the RED headers. // Write the RED headers.
if (i == num_payloads - 1) { if (i == num_payloads - 1) {
@ -122,44 +122,44 @@ Packet* CreateRedPayload(size_t num_payloads,
} }
// Create a packet with all payload bytes set to |payload_value|. // Create a packet with all payload bytes set to |payload_value|.
Packet* CreatePacket(uint8_t payload_type, Packet CreatePacket(uint8_t payload_type,
size_t payload_length, size_t payload_length,
uint8_t payload_value, uint8_t payload_value,
bool opus_fec = false) { bool opus_fec = false) {
Packet* packet = new Packet; Packet packet;
packet->payload_type = payload_type; packet.payload_type = payload_type;
packet->timestamp = kBaseTimestamp; packet.timestamp = kBaseTimestamp;
packet->sequence_number = kSequenceNumber; packet.sequence_number = kSequenceNumber;
packet->payload.SetSize(payload_length); packet.payload.SetSize(payload_length);
if (opus_fec) { if (opus_fec) {
CreateOpusFecPayload(packet->payload.data(), packet->payload.size(), CreateOpusFecPayload(packet.payload.data(), packet.payload.size(),
payload_value); payload_value);
} else { } else {
memset(packet->payload.data(), payload_value, packet->payload.size()); memset(packet.payload.data(), payload_value, packet.payload.size());
} }
return packet; return packet;
} }
// Checks that |packet| has the attributes given in the remaining parameters. // Checks that |packet| has the attributes given in the remaining parameters.
void VerifyPacket(const Packet* packet, void VerifyPacket(const Packet& packet,
size_t payload_length, size_t payload_length,
uint8_t payload_type, uint8_t payload_type,
uint16_t sequence_number, uint16_t sequence_number,
uint32_t timestamp, uint32_t timestamp,
uint8_t payload_value, uint8_t payload_value,
Packet::Priority priority) { Packet::Priority priority) {
EXPECT_EQ(payload_length, packet->payload.size()); EXPECT_EQ(payload_length, packet.payload.size());
EXPECT_EQ(payload_type, packet->payload_type); EXPECT_EQ(payload_type, packet.payload_type);
EXPECT_EQ(sequence_number, packet->sequence_number); EXPECT_EQ(sequence_number, packet.sequence_number);
EXPECT_EQ(timestamp, packet->timestamp); EXPECT_EQ(timestamp, packet.timestamp);
EXPECT_EQ(priority, packet->priority); EXPECT_EQ(priority, packet.priority);
ASSERT_FALSE(packet->payload.empty()); ASSERT_FALSE(packet.payload.empty());
for (size_t i = 0; i < packet->payload.size(); ++i) { for (size_t i = 0; i < packet.payload.size(); ++i) {
ASSERT_EQ(payload_value, packet->payload.data()[i]); ASSERT_EQ(payload_value, packet.payload.data()[i]);
} }
} }
void VerifyPacket(const Packet* packet, void VerifyPacket(const Packet& packet,
size_t payload_length, size_t payload_length,
uint8_t payload_type, uint8_t payload_type,
uint16_t sequence_number, uint16_t sequence_number,
@ -182,23 +182,18 @@ TEST(RedPayloadSplitter, CreateAndDestroy) {
TEST(RedPayloadSplitter, OnePacketTwoPayloads) { TEST(RedPayloadSplitter, OnePacketTwoPayloads) {
uint8_t payload_types[] = {0, 0}; uint8_t payload_types[] = {0, 0};
const int kTimestampOffset = 160; const int kTimestampOffset = 160;
Packet* packet = CreateRedPayload(2, payload_types, kTimestampOffset);
PacketList packet_list; PacketList packet_list;
packet_list.push_back(packet); packet_list.push_back(CreateRedPayload(2, payload_types, kTimestampOffset));
RedPayloadSplitter splitter; RedPayloadSplitter splitter;
EXPECT_TRUE(splitter.SplitRed(&packet_list)); EXPECT_TRUE(splitter.SplitRed(&packet_list));
ASSERT_EQ(2u, packet_list.size()); ASSERT_EQ(2u, packet_list.size());
// Check first packet. The first in list should always be the primary payload. // Check first packet. The first in list should always be the primary payload.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
VerifyPacket(packet, kPayloadLength, payload_types[1], kSequenceNumber, kSequenceNumber, kBaseTimestamp, 1, true);
kBaseTimestamp, 1, true);
delete packet;
packet_list.pop_front(); packet_list.pop_front();
// Check second packet. // Check second packet.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber, kSequenceNumber, kBaseTimestamp - kTimestampOffset, 0, false);
kBaseTimestamp - kTimestampOffset, 0, false);
delete packet;
} }
// Packets A and B are not split at all. Only the RED header in each packet is // Packets A and B are not split at all. Only the RED header in each packet is
@ -207,29 +202,26 @@ TEST(RedPayloadSplitter, TwoPacketsOnePayload) {
uint8_t payload_types[] = {0}; uint8_t payload_types[] = {0};
const int kTimestampOffset = 160; const int kTimestampOffset = 160;
// Create first packet, with a single RED payload. // Create first packet, with a single RED payload.
Packet* packet = CreateRedPayload(1, payload_types, kTimestampOffset);
PacketList packet_list; PacketList packet_list;
packet_list.push_back(packet); packet_list.push_back(CreateRedPayload(1, payload_types, kTimestampOffset));
// Create second packet, with a single RED payload. // Create second packet, with a single RED payload.
packet = CreateRedPayload(1, payload_types, kTimestampOffset); {
Packet packet = CreateRedPayload(1, payload_types, kTimestampOffset);
// Manually change timestamp and sequence number of second packet. // Manually change timestamp and sequence number of second packet.
packet->timestamp += kTimestampOffset; packet.timestamp += kTimestampOffset;
packet->sequence_number++; packet.sequence_number++;
packet_list.push_back(packet); packet_list.push_back(std::move(packet));
}
RedPayloadSplitter splitter; RedPayloadSplitter splitter;
EXPECT_TRUE(splitter.SplitRed(&packet_list)); EXPECT_TRUE(splitter.SplitRed(&packet_list));
ASSERT_EQ(2u, packet_list.size()); ASSERT_EQ(2u, packet_list.size());
// Check first packet. // Check first packet.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber, kSequenceNumber, kBaseTimestamp, 0, true);
kBaseTimestamp, 0, true);
delete packet;
packet_list.pop_front(); packet_list.pop_front();
// Check second packet. // Check second packet.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber + 1, kSequenceNumber + 1, kBaseTimestamp + kTimestampOffset, 0, true);
kBaseTimestamp + kTimestampOffset, 0, true);
delete packet;
} }
// Packets A and B are split into packets A1, A2, A3, B1, B2, B3, with // Packets A and B are split into packets A1, A2, A3, B1, B2, B3, with
@ -245,53 +237,45 @@ TEST(RedPayloadSplitter, TwoPacketsThreePayloads) {
uint8_t payload_types[] = {2, 1, 0}; // Primary is the last one. uint8_t payload_types[] = {2, 1, 0}; // Primary is the last one.
const int kTimestampOffset = 160; const int kTimestampOffset = 160;
// Create first packet, with 3 RED payloads. // Create first packet, with 3 RED payloads.
Packet* packet = CreateRedPayload(3, payload_types, kTimestampOffset);
PacketList packet_list; PacketList packet_list;
packet_list.push_back(packet); packet_list.push_back(CreateRedPayload(3, payload_types, kTimestampOffset));
// Create first packet, with 3 RED payloads. // Create first packet, with 3 RED payloads.
packet = CreateRedPayload(3, payload_types, kTimestampOffset); {
Packet packet = CreateRedPayload(3, payload_types, kTimestampOffset);
// Manually change timestamp and sequence number of second packet. // Manually change timestamp and sequence number of second packet.
packet->timestamp += kTimestampOffset; packet.timestamp += kTimestampOffset;
packet->sequence_number++; packet.sequence_number++;
packet_list.push_back(packet); packet_list.push_back(std::move(packet));
}
RedPayloadSplitter splitter; RedPayloadSplitter splitter;
EXPECT_TRUE(splitter.SplitRed(&packet_list)); EXPECT_TRUE(splitter.SplitRed(&packet_list));
ASSERT_EQ(6u, packet_list.size()); ASSERT_EQ(6u, packet_list.size());
// Check first packet, A1. // Check first packet, A1.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[2],
VerifyPacket(packet, kPayloadLength, payload_types[2], kSequenceNumber, kSequenceNumber, kBaseTimestamp, 2, {0, 0});
kBaseTimestamp, 2, {0, 0});
delete packet;
packet_list.pop_front(); packet_list.pop_front();
// Check second packet, A2. // Check second packet, A2.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
VerifyPacket(packet, kPayloadLength, payload_types[1], kSequenceNumber, kSequenceNumber, kBaseTimestamp - kTimestampOffset, 1, {0, 1});
kBaseTimestamp - kTimestampOffset, 1, {0, 1});
delete packet;
packet_list.pop_front(); packet_list.pop_front();
// Check third packet, A3. // Check third packet, A3.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber, kSequenceNumber, kBaseTimestamp - 2 * kTimestampOffset, 0,
kBaseTimestamp - 2 * kTimestampOffset, 0, {0, 2}); {0, 2});
delete packet;
packet_list.pop_front(); packet_list.pop_front();
// Check fourth packet, B1. // Check fourth packet, B1.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[2],
VerifyPacket(packet, kPayloadLength, payload_types[2], kSequenceNumber + 1, kSequenceNumber + 1, kBaseTimestamp + kTimestampOffset, 2,
kBaseTimestamp + kTimestampOffset, 2, {0, 0}); {0, 0});
delete packet;
packet_list.pop_front(); packet_list.pop_front();
// Check fifth packet, B2. // Check fifth packet, B2.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[1],
VerifyPacket(packet, kPayloadLength, payload_types[1], kSequenceNumber + 1, kSequenceNumber + 1, kBaseTimestamp, 1, {0, 1});
kBaseTimestamp, 1, {0, 1});
delete packet;
packet_list.pop_front(); packet_list.pop_front();
// Check sixth packet, B3. // Check sixth packet, B3.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber + 1, kSequenceNumber + 1, kBaseTimestamp - kTimestampOffset, 0,
kBaseTimestamp - kTimestampOffset, 0, {0, 2}); {0, 2});
delete packet;
} }
// Creates a list with 4 packets with these payload types: // Creates a list with 4 packets with these payload types:
@ -306,8 +290,7 @@ TEST(RedPayloadSplitter, CheckRedPayloads) {
PacketList packet_list; PacketList packet_list;
for (uint8_t i = 0; i <= 3; ++i) { for (uint8_t i = 0; i <= 3; ++i) {
// Create packet with payload type |i|, payload length 10 bytes, all 0. // Create packet with payload type |i|, payload length 10 bytes, all 0.
Packet* packet = CreatePacket(i, 10, 0); packet_list.push_back(CreatePacket(i, 10, 0));
packet_list.push_back(packet);
} }
// Use a real DecoderDatabase object here instead of a mock, since it is // Use a real DecoderDatabase object here instead of a mock, since it is
@ -327,9 +310,8 @@ TEST(RedPayloadSplitter, CheckRedPayloads) {
// Verify packets. The loop verifies that payload types 0, 1, and 2 are in the // Verify packets. The loop verifies that payload types 0, 1, and 2 are in the
// list. // list.
for (int i = 0; i <= 2; ++i) { for (int i = 0; i <= 2; ++i) {
Packet* packet = packet_list.front(); VerifyPacket(packet_list.front(), 10, i, kSequenceNumber, kBaseTimestamp, 0,
VerifyPacket(packet, 10, i, kSequenceNumber, kBaseTimestamp, 0, true); true);
delete packet;
packet_list.pop_front(); packet_list.pop_front();
} }
EXPECT_TRUE(packet_list.empty()); EXPECT_TRUE(packet_list.empty());
@ -340,21 +322,22 @@ TEST(RedPayloadSplitter, CheckRedPayloads) {
TEST(RedPayloadSplitter, WrongPayloadLength) { TEST(RedPayloadSplitter, WrongPayloadLength) {
uint8_t payload_types[] = {0, 0, 0}; uint8_t payload_types[] = {0, 0, 0};
const int kTimestampOffset = 160; const int kTimestampOffset = 160;
Packet* packet = CreateRedPayload(3, payload_types, kTimestampOffset); PacketList packet_list;
{
Packet packet = CreateRedPayload(3, payload_types, kTimestampOffset);
// Manually tamper with the payload length of the packet. // Manually tamper with the payload length of the packet.
// This is one byte too short for the second payload (out of three). // This is one byte too short for the second payload (out of three).
// We expect only the first payload to be returned. // We expect only the first payload to be returned.
packet->payload.SetSize(packet->payload.size() - (kPayloadLength + 1)); packet.payload.SetSize(packet.payload.size() - (kPayloadLength + 1));
PacketList packet_list; packet_list.push_back(std::move(packet));
packet_list.push_back(packet); }
RedPayloadSplitter splitter; RedPayloadSplitter splitter;
EXPECT_FALSE(splitter.SplitRed(&packet_list)); EXPECT_FALSE(splitter.SplitRed(&packet_list));
ASSERT_EQ(1u, packet_list.size()); ASSERT_EQ(1u, packet_list.size());
// Check first packet. // Check first packet.
packet = packet_list.front(); VerifyPacket(packet_list.front(), kPayloadLength, payload_types[0],
VerifyPacket(packet, kPayloadLength, payload_types[0], kSequenceNumber, kSequenceNumber, kBaseTimestamp - 2 * kTimestampOffset, 0,
kBaseTimestamp - 2 * kTimestampOffset, 0, {0, 2}); {0, 2});
delete packet;
packet_list.pop_front(); packet_list.pop_front();
} }

View File

@ -29,7 +29,7 @@ void TimestampScaler::ToInternal(Packet* packet) {
void TimestampScaler::ToInternal(PacketList* packet_list) { void TimestampScaler::ToInternal(PacketList* packet_list) {
PacketList::iterator it; PacketList::iterator it;
for (it = packet_list->begin(); it != packet_list->end(); ++it) { for (it = packet_list->begin(); it != packet_list->end(); ++it) {
ToInternal(*it); ToInternal(&(*it));
} }
} }

View File

@ -209,19 +209,22 @@ TEST(TimestampScaler, TestG722PacketList) {
// Test both sides of the timestamp wrap-around. // Test both sides of the timestamp wrap-around.
uint32_t external_timestamp = 0xFFFFFFFF - 5; uint32_t external_timestamp = 0xFFFFFFFF - 5;
uint32_t internal_timestamp = external_timestamp; uint32_t internal_timestamp = external_timestamp;
PacketList packet_list;
{
Packet packet1; Packet packet1;
packet1.payload_type = kRtpPayloadType; packet1.payload_type = kRtpPayloadType;
packet1.timestamp = external_timestamp; packet1.timestamp = external_timestamp;
Packet packet2; Packet packet2;
packet2.payload_type = kRtpPayloadType; packet2.payload_type = kRtpPayloadType;
packet2.timestamp = external_timestamp + 10; packet2.timestamp = external_timestamp + 10;
PacketList packet_list; packet_list.push_back(std::move(packet1));
packet_list.push_back(&packet1); packet_list.push_back(std::move(packet2));
packet_list.push_back(&packet2); }
scaler.ToInternal(&packet_list); scaler.ToInternal(&packet_list);
EXPECT_EQ(internal_timestamp, packet1.timestamp); EXPECT_EQ(internal_timestamp, packet_list.front().timestamp);
EXPECT_EQ(internal_timestamp + 20, packet2.timestamp); packet_list.pop_front();
EXPECT_EQ(internal_timestamp + 20, packet_list.front().timestamp);
EXPECT_CALL(db, Die()); // Called when database object is deleted. EXPECT_CALL(db, Die()); // Called when database object is deleted.
} }