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:
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -581,21 +581,18 @@ int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header,
|
|||||||
}
|
}
|
||||||
|
|
||||||
PacketList packet_list;
|
PacketList packet_list;
|
||||||
{
|
// Insert packet in a packet list.
|
||||||
|
packet_list.push_back([&rtp_header, &payload] {
|
||||||
// Convert to Packet.
|
// Convert to Packet.
|
||||||
// Create |packet| within this separate scope, since it should not be used
|
Packet packet;
|
||||||
// directly once it's been inserted in the packet list. This way, |packet|
|
packet.payload_type = rtp_header.header.payloadType;
|
||||||
// is not defined outside of this block.
|
packet.sequence_number = rtp_header.header.sequenceNumber;
|
||||||
Packet* packet = new Packet;
|
packet.timestamp = rtp_header.header.timestamp;
|
||||||
packet->payload_type = rtp_header.header.payloadType;
|
packet.payload.SetData(payload.data(), payload.size());
|
||||||
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.
|
// Waiting time will be set upon inserting the packet in the buffer.
|
||||||
RTC_DCHECK(!packet->waiting_time);
|
RTC_DCHECK(!packet.waiting_time);
|
||||||
// Insert packet in a packet list.
|
return packet;
|
||||||
packet_list.push_back(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 {
|
||||||
for (auto& result : results) {
|
bool first = true;
|
||||||
RTC_DCHECK(result.frame);
|
for (auto& result : results) {
|
||||||
// Reuse the packet if possible.
|
RTC_DCHECK(result.frame);
|
||||||
if (!packet) {
|
RTC_DCHECK_GE(result.priority, 0);
|
||||||
packet.reset(new Packet);
|
if (first) {
|
||||||
packet->sequence_number = sequence_number;
|
// Re-use the node and move it to parsed_packet_list.
|
||||||
packet->payload_type = payload_type;
|
packet_list.front() = packet_from_result(result);
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
packet->timestamp = result.timestamp;
|
|
||||||
RTC_DCHECK_GE(result.priority, 0);
|
|
||||||
packet->priority.codec_level = result.priority;
|
|
||||||
packet->priority.red_level = original_priority.red_level;
|
|
||||||
packet->frame = std::move(result.frame);
|
|
||||||
parsed_packet_list.push_back(packet.release());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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_
|
||||||
|
|||||||
@ -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_);
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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);
|
{
|
||||||
// Manually change timestamp and sequence number of second packet.
|
Packet packet = CreateRedPayload(1, payload_types, kTimestampOffset);
|
||||||
packet->timestamp += kTimestampOffset;
|
// Manually change timestamp and sequence number of second packet.
|
||||||
packet->sequence_number++;
|
packet.timestamp += kTimestampOffset;
|
||||||
packet_list.push_back(packet);
|
packet.sequence_number++;
|
||||||
|
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);
|
{
|
||||||
// Manually change timestamp and sequence number of second packet.
|
Packet packet = CreateRedPayload(3, payload_types, kTimestampOffset);
|
||||||
packet->timestamp += kTimestampOffset;
|
// Manually change timestamp and sequence number of second packet.
|
||||||
packet->sequence_number++;
|
packet.timestamp += kTimestampOffset;
|
||||||
packet_list.push_back(packet);
|
packet.sequence_number++;
|
||||||
|
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);
|
|
||||||
// Manually tamper with the payload length of the packet.
|
|
||||||
// This is one byte too short for the second payload (out of three).
|
|
||||||
// We expect only the first payload to be returned.
|
|
||||||
packet->payload.SetSize(packet->payload.size() - (kPayloadLength + 1));
|
|
||||||
PacketList packet_list;
|
PacketList packet_list;
|
||||||
packet_list.push_back(packet);
|
{
|
||||||
|
Packet packet = CreateRedPayload(3, payload_types, kTimestampOffset);
|
||||||
|
// Manually tamper with the payload length of the packet.
|
||||||
|
// This is one byte too short for the second payload (out of three).
|
||||||
|
// We expect only the first payload to be returned.
|
||||||
|
packet.payload.SetSize(packet.payload.size() - (kPayloadLength + 1));
|
||||||
|
packet_list.push_back(std::move(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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
Packet packet1;
|
|
||||||
packet1.payload_type = kRtpPayloadType;
|
|
||||||
packet1.timestamp = external_timestamp;
|
|
||||||
Packet packet2;
|
|
||||||
packet2.payload_type = kRtpPayloadType;
|
|
||||||
packet2.timestamp = external_timestamp + 10;
|
|
||||||
PacketList packet_list;
|
PacketList packet_list;
|
||||||
packet_list.push_back(&packet1);
|
{
|
||||||
packet_list.push_back(&packet2);
|
Packet packet1;
|
||||||
|
packet1.payload_type = kRtpPayloadType;
|
||||||
|
packet1.timestamp = external_timestamp;
|
||||||
|
Packet packet2;
|
||||||
|
packet2.payload_type = kRtpPayloadType;
|
||||||
|
packet2.timestamp = external_timestamp + 10;
|
||||||
|
packet_list.push_back(std::move(packet1));
|
||||||
|
packet_list.push_back(std::move(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.
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user