Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(199)

Side by Side Diff: webrtc/modules/audio_coding/neteq/packet_buffer.cc

Issue 2425223002: NetEq now works with packets as values, rather than pointers. (Closed)
Patch Set: Compare packets better in test. One more const. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 // This is the implementation of the PacketBuffer class. It is mostly based on 11 // This is the implementation of the PacketBuffer class. It is mostly based on
12 // an STL list. The list is kept sorted at all times so that the next packet to 12 // an STL list. The list is kept sorted at all times so that the next packet to
13 // decode is at the beginning of the list. 13 // decode is at the beginning of the list.
14 14
15 #include "webrtc/modules/audio_coding/neteq/packet_buffer.h" 15 #include "webrtc/modules/audio_coding/neteq/packet_buffer.h"
16 16
17 #include <algorithm> // find_if() 17 #include <algorithm> // find_if()
18 18
19 #include "webrtc/base/logging.h" 19 #include "webrtc/base/logging.h"
20 #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" 20 #include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
21 #include "webrtc/modules/audio_coding/neteq/decoder_database.h" 21 #include "webrtc/modules/audio_coding/neteq/decoder_database.h"
22 #include "webrtc/modules/audio_coding/neteq/tick_timer.h" 22 #include "webrtc/modules/audio_coding/neteq/tick_timer.h"
23 23
24 namespace webrtc { 24 namespace webrtc {
25 namespace { 25 namespace {
26 // Predicate used when inserting packets in the buffer list. 26 // Predicate used when inserting packets in the buffer list.
27 // Operator() returns true when |packet| goes before |new_packet|. 27 // Operator() returns true when |packet| goes before |new_packet|.
28 class NewTimestampIsLarger { 28 class NewTimestampIsLarger {
29 public: 29 public:
30 explicit NewTimestampIsLarger(const Packet* new_packet) 30 explicit NewTimestampIsLarger(const Packet& new_packet)
31 : new_packet_(new_packet) { 31 : new_packet_(new_packet) {
32 } 32 }
33 bool operator()(Packet* packet) { 33 bool operator()(const Packet& packet) {
34 return (*new_packet_ >= *packet); 34 return (new_packet_ >= packet);
35 } 35 }
36 36
37 private: 37 private:
38 const Packet* new_packet_; 38 const Packet& new_packet_;
39 }; 39 };
40 40
41 // Returns true if both payload types are known to the decoder database, and 41 // Returns true if both payload types are known to the decoder database, and
42 // have the same sample rate. 42 // have the same sample rate.
43 bool EqualSampleRates(uint8_t pt1, 43 bool EqualSampleRates(uint8_t pt1,
44 uint8_t pt2, 44 uint8_t pt2,
45 const DecoderDatabase& decoder_database) { 45 const DecoderDatabase& decoder_database) {
46 auto di1 = decoder_database.GetDecoderInfo(pt1); 46 auto di1 = decoder_database.GetDecoderInfo(pt1);
47 auto di2 = decoder_database.GetDecoderInfo(pt2); 47 auto di2 = decoder_database.GetDecoderInfo(pt2);
48 return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz(); 48 return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
49 } 49 }
50 } // namespace 50 } // namespace
51 51
52 PacketBuffer::PacketBuffer(size_t max_number_of_packets, 52 PacketBuffer::PacketBuffer(size_t max_number_of_packets,
53 const TickTimer* tick_timer) 53 const TickTimer* tick_timer)
54 : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {} 54 : max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
55 55
56 // Destructor. All packets in the buffer will be destroyed. 56 // Destructor. All packets in the buffer will be destroyed.
57 PacketBuffer::~PacketBuffer() { 57 PacketBuffer::~PacketBuffer() {
58 Flush(); 58 Flush();
59 } 59 }
60 60
61 // Flush the buffer. All packets in the buffer will be destroyed. 61 // Flush the buffer. All packets in the buffer will be destroyed.
62 void PacketBuffer::Flush() { 62 void PacketBuffer::Flush() {
63 DeleteAllPackets(&buffer_); 63 buffer_.clear();
64 } 64 }
65 65
66 bool PacketBuffer::Empty() const { 66 bool PacketBuffer::Empty() const {
67 return buffer_.empty(); 67 return buffer_.empty();
68 } 68 }
69 69
70 int PacketBuffer::InsertPacket(Packet* packet) { 70 int PacketBuffer::InsertPacket(Packet&& packet) {
71 if (!packet || packet->empty()) { 71 if (packet.empty()) {
72 if (packet) {
73 delete packet;
74 }
75 LOG(LS_WARNING) << "InsertPacket invalid packet"; 72 LOG(LS_WARNING) << "InsertPacket invalid packet";
76 return kInvalidPacket; 73 return kInvalidPacket;
77 } 74 }
78 75
79 RTC_DCHECK_GE(packet->priority.codec_level, 0); 76 RTC_DCHECK_GE(packet.priority.codec_level, 0);
80 RTC_DCHECK_GE(packet->priority.red_level, 0); 77 RTC_DCHECK_GE(packet.priority.red_level, 0);
81 78
82 int return_val = kOK; 79 int return_val = kOK;
83 80
84 packet->waiting_time = tick_timer_->GetNewStopwatch(); 81 packet.waiting_time = tick_timer_->GetNewStopwatch();
85 82
86 if (buffer_.size() >= max_number_of_packets_) { 83 if (buffer_.size() >= max_number_of_packets_) {
87 // Buffer is full. Flush it. 84 // Buffer is full. Flush it.
88 Flush(); 85 Flush();
89 LOG(LS_WARNING) << "Packet buffer flushed"; 86 LOG(LS_WARNING) << "Packet buffer flushed";
90 return_val = kFlushed; 87 return_val = kFlushed;
91 } 88 }
92 89
93 // Get an iterator pointing to the place in the buffer where the new packet 90 // Get an iterator pointing to the place in the buffer where the new packet
94 // should be inserted. The list is searched from the back, since the most 91 // should be inserted. The list is searched from the back, since the most
95 // likely case is that the new packet should be near the end of the list. 92 // likely case is that the new packet should be near the end of the list.
96 PacketList::reverse_iterator rit = std::find_if( 93 PacketList::reverse_iterator rit = std::find_if(
97 buffer_.rbegin(), buffer_.rend(), 94 buffer_.rbegin(), buffer_.rend(),
98 NewTimestampIsLarger(packet)); 95 NewTimestampIsLarger(packet));
99 96
100 // The new packet is to be inserted to the right of |rit|. If it has the same 97 // The new packet is to be inserted to the right of |rit|. If it has the same
101 // timestamp as |rit|, which has a higher priority, do not insert the new 98 // timestamp as |rit|, which has a higher priority, do not insert the new
102 // packet to list. 99 // packet to list.
103 if (rit != buffer_.rend() && packet->timestamp == (*rit)->timestamp) { 100 if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
104 delete packet;
105 return return_val; 101 return return_val;
106 } 102 }
107 103
108 // The new packet is to be inserted to the left of |it|. If it has the same 104 // The new packet is to be inserted to the left of |it|. If it has the same
109 // timestamp as |it|, which has a lower priority, replace |it| with the new 105 // timestamp as |it|, which has a lower priority, replace |it| with the new
110 // packet. 106 // packet.
111 PacketList::iterator it = rit.base(); 107 PacketList::iterator it = rit.base();
112 if (it != buffer_.end() && packet->timestamp == (*it)->timestamp) { 108 if (it != buffer_.end() && packet.timestamp == it->timestamp) {
113 delete *it;
114 it = buffer_.erase(it); 109 it = buffer_.erase(it);
115 } 110 }
116 buffer_.insert(it, packet); // Insert the packet at that position. 111 buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
117 112
118 return return_val; 113 return return_val;
119 } 114 }
120 115
121 int PacketBuffer::InsertPacketList( 116 int PacketBuffer::InsertPacketList(
122 PacketList* packet_list, 117 PacketList* packet_list,
123 const DecoderDatabase& decoder_database, 118 const DecoderDatabase& decoder_database,
124 rtc::Optional<uint8_t>* current_rtp_payload_type, 119 rtc::Optional<uint8_t>* current_rtp_payload_type,
125 rtc::Optional<uint8_t>* current_cng_rtp_payload_type) { 120 rtc::Optional<uint8_t>* current_cng_rtp_payload_type) {
126 bool flushed = false; 121 bool flushed = false;
127 while (!packet_list->empty()) { 122 for (auto& packet : *packet_list) {
128 Packet* packet = packet_list->front(); 123 if (decoder_database.IsComfortNoise(packet.payload_type)) {
129 if (decoder_database.IsComfortNoise(packet->payload_type)) {
130 if (*current_cng_rtp_payload_type && 124 if (*current_cng_rtp_payload_type &&
131 **current_cng_rtp_payload_type != packet->payload_type) { 125 **current_cng_rtp_payload_type != packet.payload_type) {
132 // New CNG payload type implies new codec type. 126 // New CNG payload type implies new codec type.
133 *current_rtp_payload_type = rtc::Optional<uint8_t>(); 127 *current_rtp_payload_type = rtc::Optional<uint8_t>();
134 Flush(); 128 Flush();
135 flushed = true; 129 flushed = true;
136 } 130 }
137 *current_cng_rtp_payload_type = 131 *current_cng_rtp_payload_type =
138 rtc::Optional<uint8_t>(packet->payload_type); 132 rtc::Optional<uint8_t>(packet.payload_type);
139 } else if (!decoder_database.IsDtmf(packet->payload_type)) { 133 } else if (!decoder_database.IsDtmf(packet.payload_type)) {
140 // This must be speech. 134 // This must be speech.
141 if ((*current_rtp_payload_type && 135 if ((*current_rtp_payload_type &&
142 **current_rtp_payload_type != packet->payload_type) || 136 **current_rtp_payload_type != packet.payload_type) ||
143 (*current_cng_rtp_payload_type && 137 (*current_cng_rtp_payload_type &&
144 !EqualSampleRates(packet->payload_type, 138 !EqualSampleRates(packet.payload_type,
145 **current_cng_rtp_payload_type, 139 **current_cng_rtp_payload_type,
146 decoder_database))) { 140 decoder_database))) {
147 *current_cng_rtp_payload_type = rtc::Optional<uint8_t>(); 141 *current_cng_rtp_payload_type = rtc::Optional<uint8_t>();
148 Flush(); 142 Flush();
149 flushed = true; 143 flushed = true;
150 } 144 }
151 *current_rtp_payload_type = rtc::Optional<uint8_t>(packet->payload_type); 145 *current_rtp_payload_type = rtc::Optional<uint8_t>(packet.payload_type);
152 } 146 }
153 int return_val = InsertPacket(packet); 147 int return_val = InsertPacket(std::move(packet));
154 packet_list->pop_front();
155 if (return_val == kFlushed) { 148 if (return_val == kFlushed) {
156 // The buffer flushed, but this is not an error. We can still continue. 149 // The buffer flushed, but this is not an error. We can still continue.
157 flushed = true; 150 flushed = true;
158 } else if (return_val != kOK) { 151 } else if (return_val != kOK) {
159 // An error occurred. Delete remaining packets in list and return. 152 // An error occurred. Delete remaining packets in list and return.
160 DeleteAllPackets(packet_list); 153 packet_list->clear();
161 return return_val; 154 return return_val;
162 } 155 }
163 } 156 }
157 packet_list->clear();
164 return flushed ? kFlushed : kOK; 158 return flushed ? kFlushed : kOK;
165 } 159 }
166 160
167 int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const { 161 int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
168 if (Empty()) { 162 if (Empty()) {
169 return kBufferEmpty; 163 return kBufferEmpty;
170 } 164 }
171 if (!next_timestamp) { 165 if (!next_timestamp) {
172 return kInvalidPointer; 166 return kInvalidPointer;
173 } 167 }
174 *next_timestamp = buffer_.front()->timestamp; 168 *next_timestamp = buffer_.front().timestamp;
175 return kOK; 169 return kOK;
176 } 170 }
177 171
178 int PacketBuffer::NextHigherTimestamp(uint32_t timestamp, 172 int PacketBuffer::NextHigherTimestamp(uint32_t timestamp,
179 uint32_t* next_timestamp) const { 173 uint32_t* next_timestamp) const {
180 if (Empty()) { 174 if (Empty()) {
181 return kBufferEmpty; 175 return kBufferEmpty;
182 } 176 }
183 if (!next_timestamp) { 177 if (!next_timestamp) {
184 return kInvalidPointer; 178 return kInvalidPointer;
185 } 179 }
186 PacketList::const_iterator it; 180 PacketList::const_iterator it;
187 for (it = buffer_.begin(); it != buffer_.end(); ++it) { 181 for (it = buffer_.begin(); it != buffer_.end(); ++it) {
188 if ((*it)->timestamp >= timestamp) { 182 if (it->timestamp >= timestamp) {
189 // Found a packet matching the search. 183 // Found a packet matching the search.
190 *next_timestamp = (*it)->timestamp; 184 *next_timestamp = it->timestamp;
191 return kOK; 185 return kOK;
192 } 186 }
193 } 187 }
194 return kNotFound; 188 return kNotFound;
195 } 189 }
196 190
197 const Packet* PacketBuffer::PeekNextPacket() const { 191 const Packet* PacketBuffer::PeekNextPacket() const {
198 return buffer_.empty() ? nullptr : buffer_.front(); 192 return buffer_.empty() ? nullptr : &buffer_.front();
199 } 193 }
200 194
201 Packet* PacketBuffer::GetNextPacket(size_t* discard_count) { 195 rtc::Optional<Packet> PacketBuffer::GetNextPacket() {
202 if (Empty()) { 196 if (Empty()) {
203 // Buffer is empty. 197 // Buffer is empty.
204 return NULL; 198 return rtc::Optional<Packet>();
205 } 199 }
206 200
207 Packet* packet = buffer_.front(); 201 rtc::Optional<Packet> packet(std::move(buffer_.front()));
208 // Assert that the packet sanity checks in InsertPacket method works. 202 // Assert that the packet sanity checks in InsertPacket method works.
209 RTC_DCHECK(packet && !packet->empty()); 203 RTC_DCHECK(!packet->empty());
210 buffer_.pop_front(); 204 buffer_.pop_front();
211 205
212 // Discard other packets with the same timestamp. These are duplicates or
213 // redundant payloads that should not be used.
214 size_t discards = 0;
215
216 while (!Empty() && buffer_.front()->timestamp == packet->timestamp) {
217 if (DiscardNextPacket() != kOK) {
218 assert(false); // Must be ok by design.
219 }
220 ++discards;
221 }
222 // The way of inserting packet should not cause any packet discarding here.
223 // TODO(minyue): remove |discard_count|.
224 assert(discards == 0);
225 if (discard_count)
226 *discard_count = discards;
227
228 return packet; 206 return packet;
229 } 207 }
230 208
231 int PacketBuffer::DiscardNextPacket() { 209 int PacketBuffer::DiscardNextPacket() {
232 if (Empty()) { 210 if (Empty()) {
233 return kBufferEmpty; 211 return kBufferEmpty;
234 } 212 }
235 // Assert that the packet sanity checks in InsertPacket method works. 213 // Assert that the packet sanity checks in InsertPacket method works.
236 RTC_DCHECK(buffer_.front()); 214 RTC_DCHECK(!buffer_.front().empty());
237 RTC_DCHECK(!buffer_.front()->empty()); 215 buffer_.pop_front();
238 DeleteFirstPacket(&buffer_);
239 return kOK; 216 return kOK;
240 } 217 }
241 218
242 int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit, 219 int PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
243 uint32_t horizon_samples) { 220 uint32_t horizon_samples) {
244 while (!Empty() && timestamp_limit != buffer_.front()->timestamp && 221 while (!Empty() && timestamp_limit != buffer_.front().timestamp &&
245 IsObsoleteTimestamp(buffer_.front()->timestamp, timestamp_limit, 222 IsObsoleteTimestamp(buffer_.front().timestamp, timestamp_limit,
246 horizon_samples)) { 223 horizon_samples)) {
247 if (DiscardNextPacket() != kOK) { 224 if (DiscardNextPacket() != kOK) {
248 assert(false); // Must be ok by design. 225 assert(false); // Must be ok by design.
249 } 226 }
250 } 227 }
251 return 0; 228 return 0;
252 } 229 }
253 230
254 int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) { 231 int PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
255 return DiscardOldPackets(timestamp_limit, 0); 232 return DiscardOldPackets(timestamp_limit, 0);
256 } 233 }
257 234
258 void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) { 235 void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
259 for (auto it = buffer_.begin(); it != buffer_.end(); /* */) { 236 for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
260 Packet* packet = *it; 237 const Packet& packet = *it;
261 if (packet->payload_type == payload_type) { 238 if (packet.payload_type == payload_type) {
262 delete packet;
263 it = buffer_.erase(it); 239 it = buffer_.erase(it);
264 } else { 240 } else {
265 ++it; 241 ++it;
266 } 242 }
267 } 243 }
268 } 244 }
269 245
270 size_t PacketBuffer::NumPacketsInBuffer() const { 246 size_t PacketBuffer::NumPacketsInBuffer() const {
271 return buffer_.size(); 247 return buffer_.size();
272 } 248 }
273 249
274 size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const { 250 size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
275 size_t num_samples = 0; 251 size_t num_samples = 0;
276 size_t last_duration = last_decoded_length; 252 size_t last_duration = last_decoded_length;
277 for (Packet* packet : buffer_) { 253 for (const Packet& packet : buffer_) {
278 if (packet->frame) { 254 if (packet.frame) {
279 // TODO(hlundin): Verify that it's fine to count all packets and remove 255 // TODO(hlundin): Verify that it's fine to count all packets and remove
280 // this check. 256 // this check.
281 if (packet->priority != Packet::Priority(0, 0)) { 257 if (packet.priority != Packet::Priority(0, 0)) {
282 continue; 258 continue;
283 } 259 }
284 size_t duration = packet->frame->Duration(); 260 size_t duration = packet.frame->Duration();
285 if (duration > 0) { 261 if (duration > 0) {
286 last_duration = duration; // Save the most up-to-date (valid) duration. 262 last_duration = duration; // Save the most up-to-date (valid) duration.
287 } 263 }
288 } 264 }
289 num_samples += last_duration; 265 num_samples += last_duration;
290 } 266 }
291 return num_samples; 267 return num_samples;
292 } 268 }
293 269
294 bool PacketBuffer::DeleteFirstPacket(PacketList* packet_list) {
295 if (packet_list->empty()) {
296 return false;
297 }
298 Packet* first_packet = packet_list->front();
299 delete first_packet;
300 packet_list->pop_front();
301 return true;
302 }
303
304 void PacketBuffer::DeleteAllPackets(PacketList* packet_list) {
305 while (DeleteFirstPacket(packet_list)) {
306 // Continue while the list is not empty.
307 }
308 }
309
310 void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const { 270 void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
311 *num_packets = static_cast<int>(buffer_.size()); 271 *num_packets = static_cast<int>(buffer_.size());
312 *max_num_packets = static_cast<int>(max_number_of_packets_); 272 *max_num_packets = static_cast<int>(max_number_of_packets_);
313 } 273 }
314 274
315 } // namespace webrtc 275 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/audio_coding/neteq/packet_buffer.h ('k') | webrtc/modules/audio_coding/neteq/packet_buffer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698