OLD | NEW |
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 /* | 11 /* |
12 * Test application for core FEC algorithm. Calls encoding and decoding | 12 * Test application for core FEC algorithm. Calls encoding and decoding |
13 * functions in ForwardErrorCorrection directly. | 13 * functions in ForwardErrorCorrection directly. |
14 */ | 14 */ |
15 | 15 |
16 #include <assert.h> | 16 #include <assert.h> |
17 #include <stdio.h> | 17 #include <stdio.h> |
18 #include <stdlib.h> | 18 #include <stdlib.h> |
19 #include <string.h> | 19 #include <string.h> |
20 #include <time.h> | 20 #include <time.h> |
21 | 21 |
22 #include <list> | 22 #include <list> |
23 | 23 |
24 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
| 25 #include "webrtc/base/random.h" |
| 26 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
25 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" | 27 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" |
26 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" | 28 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" |
27 | |
28 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | |
29 #include "webrtc/test/testsupport/fileutils.h" | 29 #include "webrtc/test/testsupport/fileutils.h" |
30 | 30 |
31 // #define VERBOSE_OUTPUT | 31 // #define VERBOSE_OUTPUT |
32 | 32 |
33 namespace webrtc { | 33 namespace webrtc { |
34 namespace fec_private_tables { | 34 namespace fec_private_tables { |
35 extern const uint8_t** kPacketMaskBurstyTbl[12]; | 35 extern const uint8_t** kPacketMaskBurstyTbl[12]; |
36 } | 36 } |
37 namespace test { | 37 namespace test { |
38 using fec_private_tables::kPacketMaskBurstyTbl; | 38 using fec_private_tables::kPacketMaskBurstyTbl; |
39 | 39 |
40 void ReceivePackets( | 40 void ReceivePackets( |
41 ForwardErrorCorrection::ReceivedPacketList* toDecodeList, | 41 ForwardErrorCorrection::ReceivedPacketList* toDecodeList, |
42 ForwardErrorCorrection::ReceivedPacketList* receivedPacketList, | 42 ForwardErrorCorrection::ReceivedPacketList* receivedPacketList, |
43 uint32_t numPacketsToDecode, | 43 size_t numPacketsToDecode, |
44 float reorderRate, | 44 float reorderRate, |
45 float duplicateRate) { | 45 float duplicateRate, |
| 46 Random* random) { |
46 assert(toDecodeList->empty()); | 47 assert(toDecodeList->empty()); |
47 assert(numPacketsToDecode <= receivedPacketList->size()); | 48 assert(numPacketsToDecode <= receivedPacketList->size()); |
48 | 49 |
49 ForwardErrorCorrection::ReceivedPacketList::iterator it; | 50 ForwardErrorCorrection::ReceivedPacketList::iterator it; |
50 for (uint32_t i = 0; i < numPacketsToDecode; i++) { | 51 for (size_t i = 0; i < numPacketsToDecode; i++) { |
51 it = receivedPacketList->begin(); | 52 it = receivedPacketList->begin(); |
52 // Reorder packets. | 53 // Reorder packets. |
53 float randomVariable = static_cast<float>(rand()) / RAND_MAX; | 54 float randomVariable = random->Rand<float>(); |
54 while (randomVariable < reorderRate) { | 55 while (randomVariable < reorderRate) { |
55 ++it; | 56 ++it; |
56 if (it == receivedPacketList->end()) { | 57 if (it == receivedPacketList->end()) { |
57 --it; | 58 --it; |
58 break; | 59 break; |
59 } | 60 } |
60 randomVariable = static_cast<float>(rand()) / RAND_MAX; | 61 randomVariable = random->Rand<float>(); |
61 } | 62 } |
62 ForwardErrorCorrection::ReceivedPacket* receivedPacket = *it; | 63 ForwardErrorCorrection::ReceivedPacket* receivedPacket = *it; |
63 toDecodeList->push_back(receivedPacket); | 64 toDecodeList->push_back(receivedPacket); |
64 | 65 |
65 // Duplicate packets. | 66 // Duplicate packets. |
66 randomVariable = static_cast<float>(rand()) / RAND_MAX; | 67 randomVariable = random->Rand<float>(); |
67 while (randomVariable < duplicateRate) { | 68 while (randomVariable < duplicateRate) { |
68 ForwardErrorCorrection::ReceivedPacket* duplicatePacket = | 69 ForwardErrorCorrection::ReceivedPacket* duplicatePacket = |
69 new ForwardErrorCorrection::ReceivedPacket; | 70 new ForwardErrorCorrection::ReceivedPacket; |
70 *duplicatePacket = *receivedPacket; | 71 *duplicatePacket = *receivedPacket; |
71 duplicatePacket->pkt = new ForwardErrorCorrection::Packet; | 72 duplicatePacket->pkt = new ForwardErrorCorrection::Packet; |
72 memcpy(duplicatePacket->pkt->data, receivedPacket->pkt->data, | 73 memcpy(duplicatePacket->pkt->data, receivedPacket->pkt->data, |
73 receivedPacket->pkt->length); | 74 receivedPacket->pkt->length); |
74 duplicatePacket->pkt->length = receivedPacket->pkt->length; | 75 duplicatePacket->pkt->length = receivedPacket->pkt->length; |
75 | 76 |
76 toDecodeList->push_back(duplicatePacket); | 77 toDecodeList->push_back(duplicatePacket); |
77 randomVariable = static_cast<float>(rand()) / RAND_MAX; | 78 randomVariable = random->Rand<float>(); |
78 } | 79 } |
79 receivedPacketList->erase(it); | 80 receivedPacketList->erase(it); |
80 } | 81 } |
81 } | 82 } |
82 | 83 |
83 TEST(FecTest, FecTest) { | 84 TEST(FecTest, FecTest) { |
84 // TODO(marpan): Split this function into subroutines/helper functions. | 85 // TODO(marpan): Split this function into subroutines/helper functions. |
85 enum { kMaxNumberMediaPackets = 48 }; | 86 enum { kMaxNumberMediaPackets = 48 }; |
86 enum { kMaxNumberFecPackets = 48 }; | 87 enum { kMaxNumberFecPackets = 48 }; |
87 | 88 |
(...skipping 30 matching lines...) Expand all Loading... |
118 const float reorderRate = 0.1f; | 119 const float reorderRate = 0.1f; |
119 const float duplicateRate = 0.1f; | 120 const float duplicateRate = 0.1f; |
120 | 121 |
121 uint8_t mediaLossMask[kMaxNumberMediaPackets]; | 122 uint8_t mediaLossMask[kMaxNumberMediaPackets]; |
122 uint8_t fecLossMask[kMaxNumberFecPackets]; | 123 uint8_t fecLossMask[kMaxNumberFecPackets]; |
123 uint8_t fecPacketMasks[kMaxNumberFecPackets][kMaxNumberMediaPackets]; | 124 uint8_t fecPacketMasks[kMaxNumberFecPackets][kMaxNumberMediaPackets]; |
124 | 125 |
125 // Seed the random number generator, storing the seed to file in order to | 126 // Seed the random number generator, storing the seed to file in order to |
126 // reproduce past results. | 127 // reproduce past results. |
127 const unsigned int randomSeed = static_cast<unsigned int>(time(NULL)); | 128 const unsigned int randomSeed = static_cast<unsigned int>(time(NULL)); |
128 srand(randomSeed); | 129 Random random(randomSeed); |
129 std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt"; | 130 std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt"; |
130 FILE* randomSeedFile = fopen(filename.c_str(), "a"); | 131 FILE* randomSeedFile = fopen(filename.c_str(), "a"); |
131 fprintf(randomSeedFile, "%u\n", randomSeed); | 132 fprintf(randomSeedFile, "%u\n", randomSeed); |
132 fclose(randomSeedFile); | 133 fclose(randomSeedFile); |
133 randomSeedFile = NULL; | 134 randomSeedFile = NULL; |
134 | 135 |
135 uint16_t seqNum = 0; | 136 uint16_t seqNum = 0; |
136 uint32_t timeStamp = static_cast<uint32_t>(rand()); | 137 uint32_t timeStamp = random.Rand<uint32_t>(); |
137 const uint32_t ssrc = static_cast<uint32_t>(rand()); | 138 const uint32_t ssrc = random.Rand(1u, 0xfffffffe); |
138 | 139 |
139 // Loop over the mask types: random and bursty. | 140 // Loop over the mask types: random and bursty. |
140 for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes; | 141 for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes; |
141 ++mask_type_idx) { | 142 ++mask_type_idx) { |
142 for (uint32_t lossRateIdx = 0; lossRateIdx < lossRateSize; ++lossRateIdx) { | 143 for (uint32_t lossRateIdx = 0; lossRateIdx < lossRateSize; ++lossRateIdx) { |
143 printf("Loss rate: %.2f, Mask type %d \n", lossRate[lossRateIdx], | 144 printf("Loss rate: %.2f, Mask type %d \n", lossRate[lossRateIdx], |
144 mask_type_idx); | 145 mask_type_idx); |
145 | 146 |
146 const uint32_t packetMaskMax = kMaxMediaPackets[mask_type_idx]; | 147 const uint32_t packetMaskMax = kMaxMediaPackets[mask_type_idx]; |
147 uint8_t* packetMask = new uint8_t[packetMaskMax * kNumMaskBytesL1]; | 148 uint8_t* packetMask = new uint8_t[packetMaskMax * kNumMaskBytesL1]; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 | 221 |
221 // Construct media packets. | 222 // Construct media packets. |
222 // Reset the sequence number here for each FEC code/mask tested | 223 // Reset the sequence number here for each FEC code/mask tested |
223 // below, to avoid sequence number wrap-around. In actual decoding, | 224 // below, to avoid sequence number wrap-around. In actual decoding, |
224 // old FEC packets in list are dropped if sequence number wrap | 225 // old FEC packets in list are dropped if sequence number wrap |
225 // around is detected. This case is currently not handled below. | 226 // around is detected. This case is currently not handled below. |
226 seqNum = 0; | 227 seqNum = 0; |
227 for (uint32_t i = 0; i < numMediaPackets; ++i) { | 228 for (uint32_t i = 0; i < numMediaPackets; ++i) { |
228 mediaPacket = new ForwardErrorCorrection::Packet; | 229 mediaPacket = new ForwardErrorCorrection::Packet; |
229 mediaPacketList.push_back(mediaPacket); | 230 mediaPacketList.push_back(mediaPacket); |
230 mediaPacket->length = static_cast<size_t>( | 231 const uint32_t kMinPacketSize = 12; |
231 (static_cast<float>(rand()) / RAND_MAX) * | 232 const uint32_t kMaxPacketSize = static_cast<uint32_t>( |
232 (IP_PACKET_SIZE - 12 - 28 - | 233 IP_PACKET_SIZE - 12 - 28 - |
233 ForwardErrorCorrection::PacketOverhead())); | 234 ForwardErrorCorrection::PacketOverhead()); |
234 if (mediaPacket->length < 12) { | 235 mediaPacket->length = random.Rand(kMinPacketSize, kMaxPacketSize); |
235 mediaPacket->length = 12; | 236 |
236 } | |
237 // Generate random values for the first 2 bytes. | 237 // Generate random values for the first 2 bytes. |
238 mediaPacket->data[0] = static_cast<uint8_t>(rand() % 256); | 238 mediaPacket->data[0] = random.Rand<uint8_t>(); |
239 mediaPacket->data[1] = static_cast<uint8_t>(rand() % 256); | 239 mediaPacket->data[1] = random.Rand<uint8_t>(); |
240 | 240 |
241 // The first two bits are assumed to be 10 by the | 241 // The first two bits are assumed to be 10 by the |
242 // FEC encoder. In fact the FEC decoder will set the | 242 // FEC encoder. In fact the FEC decoder will set the |
243 // two first bits to 10 regardless of what they | 243 // two first bits to 10 regardless of what they |
244 // actually were. Set the first two bits to 10 | 244 // actually were. Set the first two bits to 10 |
245 // so that a memcmp can be performed for the | 245 // so that a memcmp can be performed for the |
246 // whole restored packet. | 246 // whole restored packet. |
247 mediaPacket->data[0] |= 0x80; | 247 mediaPacket->data[0] |= 0x80; |
248 mediaPacket->data[0] &= 0xbf; | 248 mediaPacket->data[0] &= 0xbf; |
249 | 249 |
250 // FEC is applied to a whole frame. | 250 // FEC is applied to a whole frame. |
251 // A frame is signaled by multiple packets without | 251 // A frame is signaled by multiple packets without |
252 // the marker bit set followed by the last packet of | 252 // the marker bit set followed by the last packet of |
253 // the frame for which the marker bit is set. | 253 // the frame for which the marker bit is set. |
254 // Only push one (fake) frame to the FEC. | 254 // Only push one (fake) frame to the FEC. |
255 mediaPacket->data[1] &= 0x7f; | 255 mediaPacket->data[1] &= 0x7f; |
256 | 256 |
257 ByteWriter<uint16_t>::WriteBigEndian(&mediaPacket->data[2], | 257 ByteWriter<uint16_t>::WriteBigEndian(&mediaPacket->data[2], |
258 seqNum); | 258 seqNum); |
259 ByteWriter<uint32_t>::WriteBigEndian(&mediaPacket->data[4], | 259 ByteWriter<uint32_t>::WriteBigEndian(&mediaPacket->data[4], |
260 timeStamp); | 260 timeStamp); |
261 ByteWriter<uint32_t>::WriteBigEndian(&mediaPacket->data[8], ssrc); | 261 ByteWriter<uint32_t>::WriteBigEndian(&mediaPacket->data[8], ssrc); |
262 // Generate random values for payload | 262 // Generate random values for payload |
263 for (size_t j = 12; j < mediaPacket->length; ++j) { | 263 for (size_t j = 12; j < mediaPacket->length; ++j) { |
264 mediaPacket->data[j] = static_cast<uint8_t>(rand() % 256); | 264 mediaPacket->data[j] = random.Rand<uint8_t>(); |
265 } | 265 } |
266 seqNum++; | 266 seqNum++; |
267 } | 267 } |
268 mediaPacket->data[1] |= 0x80; | 268 mediaPacket->data[1] |= 0x80; |
269 | 269 |
270 ASSERT_EQ(0, fec.GenerateFEC(mediaPacketList, protectionFactor, | 270 ASSERT_EQ(0, fec.GenerateFEC(mediaPacketList, protectionFactor, |
271 numImpPackets, kUseUnequalProtection, | 271 numImpPackets, kUseUnequalProtection, |
272 fec_mask_type, &fecPacketList)) | 272 fec_mask_type, &fecPacketList)) |
273 << "GenerateFEC() failed"; | 273 << "GenerateFEC() failed"; |
274 | 274 |
275 ASSERT_EQ(numFecPackets, fecPacketList.size()) | 275 ASSERT_EQ(numFecPackets, fecPacketList.size()) |
276 << "We requested " << numFecPackets << " FEC packets, but " | 276 << "We requested " << numFecPackets << " FEC packets, but " |
277 << "GenerateFEC() produced " << fecPacketList.size(); | 277 << "GenerateFEC() produced " << fecPacketList.size(); |
278 memset(mediaLossMask, 0, sizeof(mediaLossMask)); | 278 memset(mediaLossMask, 0, sizeof(mediaLossMask)); |
279 ForwardErrorCorrection::PacketList::iterator mediaPacketListItem = | 279 ForwardErrorCorrection::PacketList::iterator mediaPacketListItem = |
280 mediaPacketList.begin(); | 280 mediaPacketList.begin(); |
281 ForwardErrorCorrection::ReceivedPacket* receivedPacket; | 281 ForwardErrorCorrection::ReceivedPacket* receivedPacket; |
282 uint32_t mediaPacketIdx = 0; | 282 uint32_t mediaPacketIdx = 0; |
283 | 283 |
284 while (mediaPacketListItem != mediaPacketList.end()) { | 284 while (mediaPacketListItem != mediaPacketList.end()) { |
285 mediaPacket = *mediaPacketListItem; | 285 mediaPacket = *mediaPacketListItem; |
286 // We want a value between 0 and 1. | 286 // We want a value between 0 and 1. |
287 const float lossRandomVariable = | 287 const float lossRandomVariable = random.Rand<float>(); |
288 (static_cast<float>(rand()) / (RAND_MAX)); | |
289 | 288 |
290 if (lossRandomVariable >= lossRate[lossRateIdx]) { | 289 if (lossRandomVariable >= lossRate[lossRateIdx]) { |
291 mediaLossMask[mediaPacketIdx] = 1; | 290 mediaLossMask[mediaPacketIdx] = 1; |
292 receivedPacket = new ForwardErrorCorrection::ReceivedPacket; | 291 receivedPacket = new ForwardErrorCorrection::ReceivedPacket; |
293 receivedPacket->pkt = new ForwardErrorCorrection::Packet; | 292 receivedPacket->pkt = new ForwardErrorCorrection::Packet; |
294 receivedPacketList.push_back(receivedPacket); | 293 receivedPacketList.push_back(receivedPacket); |
295 | 294 |
296 receivedPacket->pkt->length = mediaPacket->length; | 295 receivedPacket->pkt->length = mediaPacket->length; |
297 memcpy(receivedPacket->pkt->data, mediaPacket->data, | 296 memcpy(receivedPacket->pkt->data, mediaPacket->data, |
298 mediaPacket->length); | 297 mediaPacket->length); |
299 receivedPacket->seq_num = | 298 receivedPacket->seq_num = |
300 ByteReader<uint16_t>::ReadBigEndian(&mediaPacket->data[2]); | 299 ByteReader<uint16_t>::ReadBigEndian(&mediaPacket->data[2]); |
301 receivedPacket->is_fec = false; | 300 receivedPacket->is_fec = false; |
302 } | 301 } |
303 mediaPacketIdx++; | 302 mediaPacketIdx++; |
304 ++mediaPacketListItem; | 303 ++mediaPacketListItem; |
305 } | 304 } |
306 memset(fecLossMask, 0, sizeof(fecLossMask)); | 305 memset(fecLossMask, 0, sizeof(fecLossMask)); |
307 ForwardErrorCorrection::PacketList::iterator fecPacketListItem = | 306 ForwardErrorCorrection::PacketList::iterator fecPacketListItem = |
308 fecPacketList.begin(); | 307 fecPacketList.begin(); |
309 ForwardErrorCorrection::Packet* fecPacket; | 308 ForwardErrorCorrection::Packet* fecPacket; |
310 uint32_t fecPacketIdx = 0; | 309 uint32_t fecPacketIdx = 0; |
311 while (fecPacketListItem != fecPacketList.end()) { | 310 while (fecPacketListItem != fecPacketList.end()) { |
312 fecPacket = *fecPacketListItem; | 311 fecPacket = *fecPacketListItem; |
313 const float lossRandomVariable = | 312 const float lossRandomVariable = random.Rand<float>(); |
314 (static_cast<float>(rand()) / (RAND_MAX)); | |
315 if (lossRandomVariable >= lossRate[lossRateIdx]) { | 313 if (lossRandomVariable >= lossRate[lossRateIdx]) { |
316 fecLossMask[fecPacketIdx] = 1; | 314 fecLossMask[fecPacketIdx] = 1; |
317 receivedPacket = new ForwardErrorCorrection::ReceivedPacket; | 315 receivedPacket = new ForwardErrorCorrection::ReceivedPacket; |
318 receivedPacket->pkt = new ForwardErrorCorrection::Packet; | 316 receivedPacket->pkt = new ForwardErrorCorrection::Packet; |
319 | 317 |
320 receivedPacketList.push_back(receivedPacket); | 318 receivedPacketList.push_back(receivedPacket); |
321 | 319 |
322 receivedPacket->pkt->length = fecPacket->length; | 320 receivedPacket->pkt->length = fecPacket->length; |
323 memcpy(receivedPacket->pkt->data, fecPacket->data, | 321 memcpy(receivedPacket->pkt->data, fecPacket->data, |
324 fecPacket->length); | 322 fecPacket->length); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 #ifdef VERBOSE_OUTPUT | 373 #ifdef VERBOSE_OUTPUT |
376 printf("Recovery mask:\n"); | 374 printf("Recovery mask:\n"); |
377 for (uint32_t i = 0; i < numMediaPackets; ++i) { | 375 for (uint32_t i = 0; i < numMediaPackets; ++i) { |
378 printf("%u ", mediaLossMask[i]); | 376 printf("%u ", mediaLossMask[i]); |
379 } | 377 } |
380 printf("\n\n"); | 378 printf("\n\n"); |
381 #endif | 379 #endif |
382 // For error-checking frame completion. | 380 // For error-checking frame completion. |
383 bool fecPacketReceived = false; | 381 bool fecPacketReceived = false; |
384 while (!receivedPacketList.empty()) { | 382 while (!receivedPacketList.empty()) { |
385 uint32_t numPacketsToDecode = static_cast<uint32_t>( | 383 size_t numPacketsToDecode = random.Rand( |
386 (static_cast<float>(rand()) / RAND_MAX) * | 384 1u, static_cast<uint32_t>(receivedPacketList.size())); |
387 receivedPacketList.size() + | |
388 0.5); | |
389 if (numPacketsToDecode < 1) { | |
390 numPacketsToDecode = 1; | |
391 } | |
392 ReceivePackets(&toDecodeList, &receivedPacketList, | 385 ReceivePackets(&toDecodeList, &receivedPacketList, |
393 numPacketsToDecode, reorderRate, duplicateRate); | 386 numPacketsToDecode, reorderRate, duplicateRate, |
| 387 &random); |
394 | 388 |
395 if (fecPacketReceived == false) { | 389 if (fecPacketReceived == false) { |
396 ForwardErrorCorrection::ReceivedPacketList::iterator | 390 ForwardErrorCorrection::ReceivedPacketList::iterator |
397 toDecodeIt = toDecodeList.begin(); | 391 toDecodeIt = toDecodeList.begin(); |
398 while (toDecodeIt != toDecodeList.end()) { | 392 while (toDecodeIt != toDecodeList.end()) { |
399 receivedPacket = *toDecodeIt; | 393 receivedPacket = *toDecodeIt; |
400 if (receivedPacket->is_fec) { | 394 if (receivedPacket->is_fec) { |
401 fecPacketReceived = true; | 395 fecPacketReceived = true; |
402 } | 396 } |
403 ++toDecodeIt; | 397 ++toDecodeIt; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 } // loop over mask types | 473 } // loop over mask types |
480 | 474 |
481 // Have DecodeFEC free allocated memory. | 475 // Have DecodeFEC free allocated memory. |
482 fec.ResetState(&recoveredPacketList); | 476 fec.ResetState(&recoveredPacketList); |
483 ASSERT_TRUE(recoveredPacketList.empty()) | 477 ASSERT_TRUE(recoveredPacketList.empty()) |
484 << "Recovered packet list is not empty"; | 478 << "Recovered packet list is not empty"; |
485 } | 479 } |
486 | 480 |
487 } // namespace test | 481 } // namespace test |
488 } // namespace webrtc | 482 } // namespace webrtc |
OLD | NEW |