Change JitterBuffer::GetNackList to return a std::vector<uint16_t>.

This fixed the problem with returning a pointer to an internal buffer
of a JitterBuffer.

R=stefan@webrtc.org
BUG=none
TEST=none

Review URL: https://webrtc-codereview.appspot.com/53639004

Cr-Commit-Position: refs/heads/master@{#9365}
This commit is contained in:
Wan-Teh Chang
2015-06-03 15:03:35 -07:00
parent 248b0b0790
commit b1825a4038
8 changed files with 82 additions and 162 deletions

View File

@ -142,7 +142,6 @@ VCMJitterBuffer::VCMJitterBuffer(Clock* clock, EventFactory* event_factory)
low_rtt_nack_threshold_ms_(-1),
high_rtt_nack_threshold_ms_(-1),
missing_sequence_numbers_(SequenceNumberLessThan()),
nack_seq_nums_(),
max_nack_list_size_(0),
max_packet_age_to_nack_(0),
max_incomplete_time_ms_(0),
@ -839,7 +838,6 @@ void VCMJitterBuffer::SetNackSettings(size_t max_nack_list_size,
max_nack_list_size_ = max_nack_list_size;
max_packet_age_to_nack_ = max_packet_age_to_nack;
max_incomplete_time_ms_ = max_incomplete_time_ms;
nack_seq_nums_.resize(max_nack_list_size_);
}
VCMNackMode VCMJitterBuffer::nack_mode() const {
@ -869,13 +867,11 @@ uint16_t VCMJitterBuffer::EstimatedLowSequenceNumber(
return frame.GetLowSeqNum() - 1;
}
uint16_t* VCMJitterBuffer::GetNackList(uint16_t* nack_list_size,
bool* request_key_frame) {
std::vector<uint16_t> VCMJitterBuffer::GetNackList(bool* request_key_frame) {
CriticalSectionScoped cs(crit_sect_);
*request_key_frame = false;
if (nack_mode_ == kNoNack) {
*nack_list_size = 0;
return NULL;
return std::vector<uint16_t>();
}
if (last_decoded_state_.in_initial_state()) {
VCMFrameBuffer* next_frame = NextFrame();
@ -894,8 +890,7 @@ uint16_t* VCMJitterBuffer::GetNackList(uint16_t* nack_list_size,
bool found_key_frame = RecycleFramesUntilKeyFrame();
if (!found_key_frame) {
*request_key_frame = have_non_empty_frame;
*nack_list_size = 0;
return NULL;
return std::vector<uint16_t>();
}
}
}
@ -914,8 +909,7 @@ uint16_t* VCMJitterBuffer::GetNackList(uint16_t* nack_list_size,
if (rit == incomplete_frames_.rend()) {
// Request a key frame if we don't have one already.
*request_key_frame = true;
*nack_list_size = 0;
return NULL;
return std::vector<uint16_t>();
} else {
// Skip to the last key frame. If it's incomplete we will start
// NACKing it.
@ -926,13 +920,9 @@ uint16_t* VCMJitterBuffer::GetNackList(uint16_t* nack_list_size,
}
}
}
unsigned int i = 0;
SequenceNumberSet::iterator it = missing_sequence_numbers_.begin();
for (; it != missing_sequence_numbers_.end(); ++it, ++i) {
nack_seq_nums_[i] = *it;
}
*nack_list_size = i;
return &nack_seq_nums_[0];
std::vector<uint16_t> nack_list(missing_sequence_numbers_.begin(),
missing_sequence_numbers_.end());
return nack_list;
}
void VCMJitterBuffer::SetDecodeErrorMode(VCMDecodeErrorMode error_mode) {

View File

@ -172,9 +172,7 @@ class VCMJitterBuffer {
VCMNackMode nack_mode() const;
// Returns a list of the sequence numbers currently missing.
// WARNING: GetNackList() returns a pointer to an internal buffer that is only
// valid until the next GetNackList() call.
uint16_t* GetNackList(uint16_t* nack_list_size, bool* request_key_frame);
std::vector<uint16_t> GetNackList(bool* request_key_frame);
// Set decode error mode - Should not be changed in the middle of the
// session. Changes will not influence frames already in the buffer.
@ -348,7 +346,6 @@ class VCMJitterBuffer {
// Holds the internal NACK list (the missing sequence numbers).
SequenceNumberSet missing_sequence_numbers_;
uint16_t latest_received_sequence_number_;
std::vector<uint16_t> nack_seq_nums_;
size_t max_nack_list_size_;
int max_packet_age_to_nack_; // Measured in sequence numbers.
int max_incomplete_time_ms_;

View File

@ -1910,21 +1910,14 @@ TEST_F(TestJitterBufferNack, NackTooOldPackets) {
kVideoFrameDelta));
EXPECT_FALSE(DecodeCompleteFrame());
uint16_t nack_list_length = max_nack_list_size_;
bool request_key_frame = false;
uint16_t* nack_list = jitter_buffer_->GetNackList(&nack_list_length,
&request_key_frame);
std::vector<uint16_t> nack_list =
jitter_buffer_->GetNackList(&request_key_frame);
// No key frame will be requested since the jitter buffer is empty.
EXPECT_FALSE(request_key_frame);
EXPECT_TRUE(nack_list == NULL);
EXPECT_EQ(0, nack_list_length);
EXPECT_EQ(0u, nack_list.size());
EXPECT_GE(InsertFrame(kVideoFrameDelta), kNoError);
// Verify that the jitter buffer requests a key frame since we need one to
// start decoding.
EXPECT_FALSE(request_key_frame);
EXPECT_TRUE(nack_list == NULL);
EXPECT_EQ(0, nack_list_length);
// Waiting for a key frame.
EXPECT_FALSE(DecodeCompleteFrame());
EXPECT_FALSE(DecodeIncompleteFrame());
@ -1945,13 +1938,13 @@ TEST_F(TestJitterBufferNack, NackLargeJitterBuffer) {
// Insert a frame which should trigger a recycle until the next key frame.
EXPECT_GE(InsertFrames(oldest_packet_to_nack_, kVideoFrameDelta), kNoError);
uint16_t nack_list_length = max_nack_list_size_;
bool request_key_frame = false;
jitter_buffer_->GetNackList(&nack_list_length, &request_key_frame);
std::vector<uint16_t> nack_list =
jitter_buffer_->GetNackList(&request_key_frame);
// Verify that the jitter buffer does not request a key frame.
EXPECT_FALSE(request_key_frame);
// Verify that no packets are NACKed.
EXPECT_EQ(0, nack_list_length);
EXPECT_EQ(0u, nack_list.size());
// Verify that we can decode the next frame.
EXPECT_TRUE(DecodeCompleteFrame());
}
@ -1967,9 +1960,8 @@ TEST_F(TestJitterBufferNack, NackListFull) {
EXPECT_EQ(kFlushIndicator, InsertFrame(kVideoFrameDelta));
EXPECT_FALSE(DecodeCompleteFrame());
uint16_t nack_list_length = max_nack_list_size_;
bool request_key_frame = false;
jitter_buffer_->GetNackList(&nack_list_length, &request_key_frame);
jitter_buffer_->GetNackList(&request_key_frame);
// The jitter buffer is empty, so we won't request key frames until we get a
// packet.
EXPECT_FALSE(request_key_frame);
@ -1977,7 +1969,7 @@ TEST_F(TestJitterBufferNack, NackListFull) {
EXPECT_GE(InsertFrame(kVideoFrameDelta), kNoError);
// Now we have a packet in the jitter buffer, a key frame will be requested
// since it's not a key frame.
jitter_buffer_->GetNackList(&nack_list_length, &request_key_frame);
jitter_buffer_->GetNackList(&request_key_frame);
// The jitter buffer is empty, so we won't request key frames until we get a
// packet.
EXPECT_TRUE(request_key_frame);
@ -1994,13 +1986,11 @@ TEST_F(TestJitterBufferNack, NoNackListReturnedBeforeFirstDecode) {
DropFrame(10);
// Insert a frame and try to generate a NACK list. Shouldn't get one.
EXPECT_GE(InsertFrame(kVideoFrameDelta), kNoError);
uint16_t nack_list_size = 0;
bool request_key_frame = false;
uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size,
&request_key_frame);
std::vector<uint16_t> nack_list =
jitter_buffer_->GetNackList(&request_key_frame);
// No list generated, and a key frame request is signaled.
EXPECT_TRUE(list == NULL);
EXPECT_EQ(0, nack_list_size);
EXPECT_EQ(0u, nack_list.size());
EXPECT_TRUE(request_key_frame);
}
@ -2012,11 +2002,9 @@ TEST_F(TestJitterBufferNack, NackListBuiltBeforeFirstDecode) {
stream_generator_->NextPacket(NULL); // Drop packet.
EXPECT_EQ(kIncomplete, InsertPacketAndPop(0));
EXPECT_TRUE(DecodeCompleteFrame());
uint16_t nack_list_size = 0;
bool extended = false;
uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size, &extended);
EXPECT_EQ(1, nack_list_size);
EXPECT_TRUE(list != NULL);
std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended);
EXPECT_EQ(1u, nack_list.size());
}
TEST_F(TestJitterBufferNack, VerifyRetransmittedFlag) {
@ -2033,13 +2021,11 @@ TEST_F(TestJitterBufferNack, VerifyRetransmittedFlag) {
EXPECT_EQ(kIncomplete, jitter_buffer_->InsertPacket(packet, &retransmitted));
EXPECT_FALSE(retransmitted);
EXPECT_FALSE(DecodeCompleteFrame());
uint16_t nack_list_size = 0;
bool extended = false;
uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size, &extended);
EXPECT_EQ(1, nack_list_size);
ASSERT_TRUE(list != NULL);
std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended);
EXPECT_EQ(1u, nack_list.size());
stream_generator_->PopPacket(&packet, 0);
EXPECT_EQ(packet.seqNum, list[0]);
EXPECT_EQ(packet.seqNum, nack_list[0]);
EXPECT_EQ(kCompleteSession, jitter_buffer_->InsertPacket(packet,
&retransmitted));
EXPECT_TRUE(retransmitted);
@ -2054,14 +2040,12 @@ TEST_F(TestJitterBufferNack, UseNackToRecoverFirstKeyFrame) {
// Drop second packet.
EXPECT_EQ(kIncomplete, InsertPacketAndPop(1));
EXPECT_FALSE(DecodeCompleteFrame());
uint16_t nack_list_size = 0;
bool extended = false;
uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size, &extended);
EXPECT_EQ(1, nack_list_size);
ASSERT_TRUE(list != NULL);
std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended);
EXPECT_EQ(1u, nack_list.size());
VCMPacket packet;
stream_generator_->GetPacket(&packet, 0);
EXPECT_EQ(packet.seqNum, list[0]);
EXPECT_EQ(packet.seqNum, nack_list[0]);
}
TEST_F(TestJitterBufferNack, UseNackToRecoverFirstKeyFrameSecondInQueue) {
@ -2081,13 +2065,11 @@ TEST_F(TestJitterBufferNack, UseNackToRecoverFirstKeyFrameSecondInQueue) {
// Drop second packet in frame.
EXPECT_EQ(kIncomplete, InsertPacketAndPop(1));
EXPECT_FALSE(DecodeCompleteFrame());
uint16_t nack_list_size = 0;
bool extended = false;
uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size, &extended);
EXPECT_EQ(1, nack_list_size);
ASSERT_TRUE(list != NULL);
std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended);
EXPECT_EQ(1u, nack_list.size());
stream_generator_->GetPacket(&packet, 0);
EXPECT_EQ(packet.seqNum, list[0]);
EXPECT_EQ(packet.seqNum, nack_list[0]);
}
TEST_F(TestJitterBufferNack, NormalOperation) {
@ -2117,15 +2099,14 @@ TEST_F(TestJitterBufferNack, NormalOperation) {
EXPECT_EQ(0, stream_generator_->PacketsRemaining());
EXPECT_FALSE(DecodeCompleteFrame());
EXPECT_FALSE(DecodeIncompleteFrame());
uint16_t nack_list_size = 0;
bool request_key_frame = false;
uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size,
&request_key_frame);
std::vector<uint16_t> nack_list =
jitter_buffer_->GetNackList(&request_key_frame);
// Verify the NACK list.
const int kExpectedNackSize = 9;
ASSERT_EQ(kExpectedNackSize, nack_list_size);
for (int i = 0; i < nack_list_size; ++i)
EXPECT_EQ((1 + i) * 10, list[i]);
const size_t kExpectedNackSize = 9;
ASSERT_EQ(kExpectedNackSize, nack_list.size());
for (size_t i = 0; i < nack_list.size(); ++i)
EXPECT_EQ((1 + i) * 10, nack_list[i]);
}
TEST_F(TestJitterBufferNack, NormalOperationWrap) {
@ -2153,14 +2134,13 @@ TEST_F(TestJitterBufferNack, NormalOperationWrap) {
EXPECT_EQ(0, stream_generator_->PacketsRemaining());
EXPECT_FALSE(DecodeCompleteFrame());
EXPECT_FALSE(DecodeCompleteFrame());
uint16_t nack_list_size = 0;
bool extended = false;
uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size, &extended);
std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended);
// Verify the NACK list.
const int kExpectedNackSize = 10;
ASSERT_EQ(kExpectedNackSize, nack_list_size);
for (int i = 0; i < nack_list_size; ++i)
EXPECT_EQ(i * 10, list[i]);
const size_t kExpectedNackSize = 10;
ASSERT_EQ(kExpectedNackSize, nack_list.size());
for (size_t i = 0; i < nack_list.size(); ++i)
EXPECT_EQ(i * 10, nack_list[i]);
}
TEST_F(TestJitterBufferNack, NormalOperationWrap2) {
@ -2188,22 +2168,20 @@ TEST_F(TestJitterBufferNack, NormalOperationWrap2) {
}
EXPECT_EQ(kCompleteSession, InsertPacketAndPop(0));
EXPECT_FALSE(request_key_frame);
uint16_t nack_list_size = 0;
bool extended = false;
uint16_t* list = jitter_buffer_->GetNackList(&nack_list_size, &extended);
std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended);
// Verify the NACK list.
ASSERT_EQ(1, nack_list_size);
EXPECT_EQ(65535, list[0]);
ASSERT_EQ(1u, nack_list.size());
EXPECT_EQ(65535, nack_list[0]);
}
TEST_F(TestJitterBufferNack, ResetByFutureKeyFrameDoesntError) {
stream_generator_->Init(0, 0, clock_->TimeInMilliseconds());
InsertFrame(kVideoFrameKey);
EXPECT_TRUE(DecodeCompleteFrame());
uint16_t nack_list_size = 0;
bool extended = false;
jitter_buffer_->GetNackList(&nack_list_size, &extended);
EXPECT_EQ(0, nack_list_size);
std::vector<uint16_t> nack_list = jitter_buffer_->GetNackList(&extended);
EXPECT_EQ(0u, nack_list.size());
// Far-into-the-future video frame, could be caused by resetting the encoder
// or otherwise restarting. This should not fail when error when the packet is
@ -2212,15 +2190,15 @@ TEST_F(TestJitterBufferNack, ResetByFutureKeyFrameDoesntError) {
clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs);
InsertFrame(kVideoFrameKey);
EXPECT_TRUE(DecodeCompleteFrame());
jitter_buffer_->GetNackList(&nack_list_size, &extended);
EXPECT_EQ(0, nack_list_size);
nack_list = jitter_buffer_->GetNackList(&extended);
EXPECT_EQ(0u, nack_list.size());
// Stream should be decodable from this point.
clock_->AdvanceTimeMilliseconds(kDefaultFramePeriodMs);
InsertFrame(kVideoFrameDelta);
EXPECT_TRUE(DecodeCompleteFrame());
jitter_buffer_->GetNackList(&nack_list_size, &extended);
EXPECT_EQ(0, nack_list_size);
nack_list = jitter_buffer_->GetNackList(&extended);
EXPECT_EQ(0u, nack_list.size());
}
} // namespace webrtc

View File

@ -209,23 +209,8 @@ VCMNackMode VCMReceiver::NackMode() const {
return jitter_buffer_.nack_mode();
}
VCMNackStatus VCMReceiver::NackList(uint16_t* nack_list,
uint16_t size,
uint16_t* nack_list_length) {
bool request_key_frame = false;
uint16_t* internal_nack_list = jitter_buffer_.GetNackList(
nack_list_length, &request_key_frame);
assert(*nack_list_length <= size);
if (*nack_list_length > size) {
*nack_list_length = size;
}
if (internal_nack_list != NULL && *nack_list_length > 0) {
memcpy(nack_list, internal_nack_list, *nack_list_length * sizeof(uint16_t));
}
if (request_key_frame) {
return kNackKeyFrameRequest;
}
return kNackOk;
std::vector<uint16_t> VCMReceiver::NackList(bool* request_key_frame) {
return jitter_buffer_.GetNackList(request_key_frame);
}
void VCMReceiver::SetDecodeErrorMode(VCMDecodeErrorMode decode_error_mode) {

View File

@ -23,11 +23,6 @@ namespace webrtc {
class Clock;
class VCMEncodedFrame;
enum VCMNackStatus {
kNackOk,
kNackKeyFrameRequest
};
class VCMReceiver {
public:
VCMReceiver(VCMTiming* timing,
@ -55,8 +50,7 @@ class VCMReceiver {
int max_packet_age_to_nack,
int max_incomplete_time_ms);
VCMNackMode NackMode() const;
VCMNackStatus NackList(uint16_t* nackList, uint16_t size,
uint16_t* nack_list_length);
std::vector<uint16_t> NackList(bool* request_key_frame);
// Receiver video delay.
int SetMinReceiverDelay(int desired_delay_ms);

View File

@ -163,11 +163,9 @@ TEST_F(TestVCMReceiver, NonDecodableDuration_Empty) {
// Advance time until it's time to decode the key frame.
clock_->AdvanceTimeMilliseconds(kMinDelayMs);
EXPECT_TRUE(DecodeNextFrame());
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackOk, ret);
bool request_key_frame = false;
std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
EXPECT_FALSE(request_key_frame);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_NoKeyFrame) {
@ -182,11 +180,9 @@ TEST_F(TestVCMReceiver, NonDecodableDuration_NoKeyFrame) {
for (int i = 0; i < kNumFrames; ++i) {
EXPECT_GE(InsertFrame(kVideoFrameDelta, true), kNoError);
}
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackKeyFrameRequest, ret);
bool request_key_frame = false;
std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
EXPECT_TRUE(request_key_frame);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_OneIncomplete) {
@ -215,11 +211,9 @@ TEST_F(TestVCMReceiver, NonDecodableDuration_OneIncomplete) {
key_frame_inserted);
EXPECT_TRUE(DecodeNextFrame());
// Make sure we get a key frame request.
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackKeyFrameRequest, ret);
bool request_key_frame = false;
std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
EXPECT_TRUE(request_key_frame);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger) {
@ -250,11 +244,9 @@ TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger) {
EXPECT_TRUE(DecodeNextFrame());
// Make sure we don't get a key frame request since we haven't generated
// enough frames.
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackOk, ret);
bool request_key_frame = false;
std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
EXPECT_FALSE(request_key_frame);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger2) {
@ -285,11 +277,9 @@ TEST_F(TestVCMReceiver, NonDecodableDuration_NoTrigger2) {
EXPECT_TRUE(DecodeNextFrame());
// Make sure we don't get a key frame request since the non-decodable duration
// is only one frame.
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackOk, ret);
bool request_key_frame = false;
std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
EXPECT_FALSE(request_key_frame);
}
TEST_F(TestVCMReceiver, NonDecodableDuration_KeyFrameAfterIncompleteFrames) {
@ -320,10 +310,8 @@ TEST_F(TestVCMReceiver, NonDecodableDuration_KeyFrameAfterIncompleteFrames) {
EXPECT_TRUE(DecodeNextFrame());
// Make sure we don't get a key frame request since we have a key frame
// in the list.
uint16_t nack_list[kMaxNackListSize];
uint16_t nack_list_length = 0;
VCMNackStatus ret = receiver_.NackList(nack_list, kMaxNackListSize,
&nack_list_length);
EXPECT_EQ(kNackOk, ret);
bool request_key_frame = false;
std::vector<uint16_t> nack_list = receiver_.NackList(&request_key_frame);
EXPECT_FALSE(request_key_frame);
}
} // namespace webrtc

View File

@ -194,7 +194,6 @@ class VideoReceiver {
EXCLUSIVE_LOCKS_REQUIRED(_receiveCritSect);
int32_t RequestKeyFrame();
int32_t RequestSliceLossIndication(const uint64_t pictureID) const;
int32_t NackList(uint16_t* nackList, uint16_t* size);
private:
enum VCMKeyRequestMode {

View File

@ -136,15 +136,20 @@ int32_t VideoReceiver::Process() {
callback_registered = _packetRequestCallback != NULL;
}
if (callback_registered && length > 0) {
std::vector<uint16_t> nackList(length);
const int32_t ret = NackList(&nackList[0], &length);
if (ret != VCM_OK && returnValue == VCM_OK) {
returnValue = ret;
// Collect sequence numbers from the default receiver.
bool request_key_frame = false;
std::vector<uint16_t> nackList = _receiver.NackList(&request_key_frame);
int32_t ret = VCM_OK;
if (request_key_frame) {
ret = RequestKeyFrame();
if (ret != VCM_OK && returnValue == VCM_OK) {
returnValue = ret;
}
}
if (ret == VCM_OK && length > 0) {
if (ret == VCM_OK && !nackList.empty()) {
CriticalSectionScoped cs(process_crit_sect_.get());
if (_packetRequestCallback != NULL) {
_packetRequestCallback->ResendPackets(&nackList[0], length);
_packetRequestCallback->ResendPackets(&nackList[0], nackList.size());
}
}
}
@ -549,22 +554,6 @@ int32_t VideoReceiver::SetRenderDelay(uint32_t timeMS) {
// Current video delay
int32_t VideoReceiver::Delay() const { return _timing.TargetVideoDelay(); }
// Nack list
int32_t VideoReceiver::NackList(uint16_t* nackList, uint16_t* size) {
VCMNackStatus nackStatus = kNackOk;
uint16_t nack_list_length = 0;
// Collect sequence numbers from the default receiver
// if in normal nack mode.
if (_receiver.NackMode() != kNoNack) {
nackStatus = _receiver.NackList(nackList, *size, &nack_list_length);
}
*size = nack_list_length;
if (nackStatus == kNackKeyFrameRequest) {
return RequestKeyFrame();
}
return VCM_OK;
}
uint32_t VideoReceiver::DiscardedPackets() const {
return _receiver.DiscardedPackets();
}